WooCommerce_MyParcel_Export

The WooCommerce MyParcel WooCommerce MyParcel Export class.

Defined (1)

The class is defined in the following location(s).

/includes/class-wcmp-export.php  
  1. class WooCommerce_MyParcel_Export { 
  2. public $order_id; 
  3. public $success; 
  4. public $errors; 
  5.  
  6. /** 
  7. * Construct. 
  8. */ 
  9.  
  10. public function __construct() { 
  11. $this->success = array(); 
  12. $this->errors = array(); 
  13.  
  14. include( 'class-wcmp-rest.php' ); 
  15. include( 'class-wcmp-api.php' ); 
  16.  
  17. add_action( 'admin_notices', array( $this, 'admin_notices' ) ); 
  18. add_action( 'wp_ajax_wc_myparcel', array($this, 'export' )); 
  19. add_action( 'wp_ajax_wc_myparcel_frontend', array($this, 'frontend_api_request' )); 
  20. add_action( 'wp_ajax_nopriv_wc_myparcel_frontend', array($this, 'frontend_api_request' )); 
  21.  
  22. public function admin_notices () { 
  23. if ( isset($_GET['myparcel_done']) ) { // only do this when for the user that initiated this 
  24. $action_return = get_option( 'wcmyparcel_admin_notices' ); 
  25. $success_ids = get_option( 'wcmyparcel_print_queue', array() ); 
  26. if (!empty($action_return)) { 
  27. foreach ($action_return as $type => $message) { 
  28. if (in_array($type, array('success', 'error'))) { 
  29. if ( $type == 'success' && !empty($success_ids) ) { 
  30. $print_queue = sprintf('<input type="hidden" value="%s" id="wcmp_printqueue">', json_encode(array_keys($success_ids))); 
  31. // dequeue 
  32. delete_option( 'wcmyparcel_print_queue' ); 
  33. printf('<div class="myparcel_notice notice notice-%s"><p>%s</p>%s</div>', $type, $message, isset($print_queue)?$print_queue:''); 
  34. // destroy after reading 
  35. delete_option( 'wcmyparcel_admin_notices' ); 
  36.  
  37. if (isset($_GET['myparcel'])) { 
  38. switch ($_GET['myparcel']) { 
  39. case 'no_consignments': 
  40. $message = __('You have to export the orders to MyParcel before you can print the labels!', 'woocommerce-myparcel'); 
  41. printf('<div class="myparcel_notice notice notice-error"><p>%s</p></div>', $message); 
  42. break; 
  43. default: 
  44. break; 
  45.  
  46. /** 
  47. * Export selected orders 
  48. * @access public 
  49. * @return void 
  50. */ 
  51. public function export() { 
  52. // Check the nonce 
  53. check_ajax_referer( 'wc_myparcel', 'security' ); 
  54.  
  55. if( ! is_user_logged_in() ) { 
  56. wp_die( __( 'You do not have sufficient permissions to access this page.', 'woocommerce-myparcel' ) ); 
  57.  
  58. $return = array(); 
  59.  
  60. // Check the user privileges (maybe use order ids for filter?) 
  61. if( apply_filters( 'wc_myparcel_check_privs', !current_user_can( 'manage_woocommerce_orders' ) && !current_user_can( 'edit_shop_orders' ) ) ) { 
  62. $return['error'] = __( 'You do not have sufficient permissions to access this page.', 'woocommerce-myparcel' ); 
  63. $json = json_encode( $return ); 
  64. echo $json; 
  65. die(); 
  66.  
  67. extract($_REQUEST); // $request, $order_ids, ... 
  68. // make sure $order_ids is a proper array 
  69. $order_ids = !empty($order_ids) ? $this->sanitize_order_ids($order_ids) : array(); 
  70.  
  71. switch($request) { 
  72. case 'add_shipments': 
  73. if ( empty($order_ids) ) { 
  74. $this->errors[] = __( 'You have not selected any orders!', 'woocommerce-myparcel' ); 
  75. break; 
  76. $order_ids = $this->filter_eu_orders( $order_ids ); 
  77. // if we're going to print directly, we need to process the orders first, regardless of the settings 
  78. $process = (isset($print) && $print == 'yes') ? true : false; 
  79. $return = $this->add_shipments( $order_ids ); 
  80. break; 
  81. case 'add_return': 
  82. if ( empty($myparcel_options) ) { 
  83. $this->errors[] = __( 'You have not selected any orders!', 'woocommerce-myparcel' ); 
  84. break; 
  85. $return = $this->add_return( $myparcel_options ); 
  86. break; 
  87. case 'get_labels': 
  88. if ( empty($order_ids) ) { 
  89. $this->errors[] = __( 'You have not selected any orders!', 'woocommerce-myparcel' ); 
  90. break; 
  91. $order_ids = $this->filter_eu_orders( $order_ids ); 
  92. $label_response_type = isset($label_response_type) ? $label_response_type : NULL; 
  93. $return = $this->get_labels( $order_ids, $label_response_type ); 
  94. break; 
  95. case 'modal_dialog': 
  96. if ( empty($order_ids) ) { 
  97. $errors[] = __( 'You have not selected any orders!', 'woocommerce-myparcel' ); 
  98. break; 
  99. $order_ids = $this->filter_eu_orders( $order_ids ); 
  100. $this->modal_dialog( $order_ids, $dialog ); 
  101. break; 
  102.  
  103. // display errors directly if PDF requested or modal 
  104. if ( in_array($request, array('add_return', 'get_labels', 'modal_dialog')) && !empty($this->errors) ) { 
  105. echo $this->parse_errors( $this->errors ); 
  106. die(); 
  107. }  
  108.  
  109. // format errors for html output 
  110. if (!empty($this->errors)) { 
  111. $return['error'] = $this->parse_errors( $this->errors ); 
  112.  
  113. // When adding shipments, store $return for use in admin_notice 
  114. // This way we can refresh the page (JS) to show all new buttons 
  115. if ($request == 'add_shipments' && !empty($print) && ($print == 'no'|| $print == 'after_reload')) { 
  116. update_option( 'wcmyparcel_admin_notices', $return ); 
  117. if ($print == 'after_reload') { 
  118. update_option( 'wcmyparcel_print_queue', $return['success_ids'] ); 
  119.  
  120. // if we're directed here from modal, show proper result page 
  121. if (isset($modal)) { 
  122. $this->modal_success_page( $request, $return ); 
  123. } else { 
  124. // return JSON response 
  125. echo json_encode( $return ); 
  126.  
  127. die(); 
  128.  
  129. public function sanitize_order_ids($order_ids) { 
  130. // check for JSON 
  131. if (is_string($order_ids) && strpos($order_ids, '[') !== false ) { 
  132. $order_ids = json_decode(stripslashes($order_ids)); 
  133.  
  134. // cast as array for single exports 
  135. $order_ids = (array) $order_ids; 
  136.  
  137. return $order_ids; 
  138.  
  139. public function add_shipments( $order_ids, $process = false ) { 
  140. $return = array(); 
  141.  
  142. $this->log("*** Creating shipments started ***"); 
  143.  
  144. foreach ($order_ids as $order_id) { 
  145. $order = WCX::get_order( $order_id ); 
  146. $shipments = $this->get_order_shipment_data( (array) $order_id ); 
  147.  
  148. $this->log("Shipment data for order {$order_id}:\n".var_export($shipments, true)); 
  149.  
  150. // check colli amount 
  151. $extra_params = WCX_Order::get_meta( $order, '_myparcel_shipment_options_extra' ); 
  152. $colli_amount = isset($extra_params['colli_amount']) ? $extra_params['colli_amount'] : 1; 
  153.  
  154. for ($i=0; $i < intval($colli_amount); $i++) { 
  155. try { 
  156. $api = $this->init_api(); 
  157. $response = $api->add_shipments( $shipments ); 
  158. $this->log("API response (order {$order_id}):\n".var_export($response, true)); 
  159. // echo '<pre>';var_dump($response);echo '</pre>';die(); 
  160. if (isset($response['body']['data']['ids'])) { 
  161. $ids = array_shift($response['body']['data']['ids']); 
  162. $shipment_id = $ids['id']; 
  163. $this->success[$order_id] = $shipment_id; 
  164.  
  165. $shipment = array ( 
  166. 'shipment_id' => $shipment_id,  
  167. ); 
  168.  
  169. // save shipment data in order meta 
  170. $this->save_shipment_data( $order, $shipment ); 
  171.  
  172. // process directly setting 
  173. if ( isset(WooCommerce_MyParcel()->general_settings['process_directly']) || $process === true ) { 
  174. // flush cache until WC issue #13439 is fixed https://github.com/woocommerce/woocommerce/issues/13439 
  175. if (method_exists($order, 'save')) { 
  176. $order->save(); 
  177. $this->get_labels( (array) $order_id, 'url' ); 
  178. $this->get_shipment_data( $shipment_id, $order ); 
  179.  
  180. // status automation 
  181. if ( isset(WooCommerce_MyParcel()->general_settings['order_status_automation']) && !empty(WooCommerce_MyParcel()->general_settings['automatic_order_status']) ) { 
  182. $order->update_status( WooCommerce_MyParcel()->general_settings['automatic_order_status'], __( 'MyParcel shipment created:', 'woocommerce-myparcel' ) ); 
  183. } else { 
  184. $this->errors[$order_id] = __( 'Unknown error', 'woocommerce-myparcel' ); 
  185. } catch (Exception $e) { 
  186. $this->errors[$order_id] = $e->getMessage(); 
  187. }  
  188. // echo '<pre>';var_dump($this->success);echo '</pre>';die(); 
  189. if (!empty($this->success)) { 
  190. $return['success'] = sprintf(__( '%s shipments successfully exported to Myparcel', 'woocommerce-myparcel' ), count($this->success)); 
  191. $return['success_ids'] = $this->success; 
  192.  
  193. return $return; 
  194.  
  195. public function add_return( $myparcel_options ) { 
  196. $return = array(); 
  197.  
  198. $this->log("*** Creating return shipments started ***"); 
  199.  
  200. foreach ($myparcel_options as $order_id => $options) { 
  201. $return_shipments = array( $this->prepare_return_shipment_data( $order_id, $options ) ); 
  202. $this->log("Return shipment data for order {$order_id}:\n".var_export($return_shipments, true)); 
  203. // echo '<pre>';var_dump($return_shipment);echo '</pre>';die(); 
  204.  
  205. try { 
  206. $api = $this->init_api(); 
  207. $response = $api->add_shipments( $return_shipments, 'return' ); 
  208. $this->log("API response (order {$order_id}):\n".var_export($response, true)); 
  209. // echo '<pre>';var_dump($response);echo '</pre>';die(); 
  210. if (isset($response['body']['data']['ids'])) { 
  211. $order = WCX::get_order( $order_id ); 
  212. $ids = array_shift($response['body']['data']['ids']); 
  213. $shipment_id = $ids['id']; 
  214. $this->success[$order_id] = $shipment_id; 
  215.  
  216. $shipment = array ( 
  217. 'shipment_id' => $shipment_id,  
  218. ); 
  219.  
  220. // save shipment data in order meta 
  221. $this->save_shipment_data( $order, $shipment ); 
  222.  
  223. } else { 
  224. $this->errors[$order_id] = __( 'Unknown error', 'woocommerce-myparcel' ); 
  225. } catch (Exception $e) { 
  226. $this->errors[$order_id] = $e->getMessage(); 
  227.  
  228. // echo '<pre>';var_dump($success);echo '</pre>';die(); 
  229.  
  230. return $return; 
  231.  
  232. public function get_labels( $order_ids, $label_response_type = NULL ) { 
  233. $return = array(); 
  234.  
  235. $shipment_ids = $this->get_shipment_ids( $order_ids, array( 'only_last' => true ) ); 
  236.  
  237. if ( empty($shipment_ids) ) { 
  238. $this->log("*** Failed label request (not exported yet) ***"); 
  239. $this->errors[] = __( 'The selected orders have not been exported to MyParcel yet!', 'woocommerce-myparcel' ); 
  240. return $return; 
  241.  
  242. $this->log("*** Label request started ***"); 
  243. $this->log("Shipment ID's: ".implode(', ', $shipment_ids)); 
  244.  
  245. try { 
  246. $api = $this->init_api(); 
  247. $params = array(); 
  248.  
  249.  
  250. if (isset($label_response_type) && $label_response_type == 'url') { 
  251. $response = $api->get_shipment_labels( $shipment_ids, $params, 'link' ); 
  252. $this->log("API response:\n".var_export($response, true)); 
  253. // var_dump( $response ); 
  254. if (isset($response['body']['data']['pdfs']['url'])) { 
  255. $url = untrailingslashit( $api->APIURL ) . $response['body']['data']['pdfs']['url']; 
  256. $return['url'] = $url; 
  257. } else { 
  258. $this->errors[] = __( 'Unknown error', 'woocommerce-myparcel' ); 
  259. } else { 
  260. $response = $api->get_shipment_labels( $shipment_ids, $params, 'pdf' ); 
  261.  
  262. if (isset($response['body'])) { 
  263. $this->log("PDF data received"); 
  264. $pdf_data = $response['body']; 
  265. $output_mode = isset(WooCommerce_MyParcel()->general_settings['download_display'])?WooCommerce_MyParcel()->general_settings['download_display']:''; 
  266. if ( $output_mode == 'display' ) { 
  267. $this->stream_pdf( $pdf_data, $order_ids ); 
  268. } else { 
  269. $this->download_pdf( $pdf_data, $order_ids ); 
  270. } else { 
  271. $this->log("Unknown error, API response:\n".var_export($response, true)); 
  272. $this->errors[] = __( 'Unknown error', 'woocommerce-myparcel' ); 
  273.  
  274. // echo '<pre>';var_dump($response);echo '</pre>';die(); 
  275. } catch (Exception $e) { 
  276. $this->errors[] = $e->getMessage(); 
  277.  
  278. return $return; 
  279.  
  280. public function modal_dialog( $order_ids, $dialog ) { 
  281. // check for JSON 
  282. if (is_string($order_ids) && strpos($order_ids, '[') !== false ) { 
  283. $order_ids = json_decode(stripslashes($order_ids)); 
  284.  
  285. // cast as array for single exports 
  286. $order_ids = (array) $order_ids; 
  287.  
  288. include('views/wcmp-bulk-options-form.php'); 
  289. die(); 
  290.  
  291. public function modal_success_page( $request, $result ) { 
  292. include('views/wcmp-modal-result-page.php'); 
  293. die(); 
  294.  
  295. public function frontend_api_request() { 
  296. // TODO: check nonce 
  297. $params = $_REQUEST; 
  298.  
  299. // filter non API params 
  300. $api_params = array( 
  301. 'cc' => '',  
  302. 'postal_code' => '',  
  303. 'number' => '',  
  304. 'carrier' => '',  
  305. 'delivery_time' => '',  
  306. 'delivery_date' => '',  
  307. 'cutoff_time' => '',  
  308. 'dropoff_days' => '',  
  309. 'dropoff_delay' => '',  
  310. 'deliverydays_window' => '',  
  311. 'exclude_delivery_type' => '',  
  312. ); 
  313. $params = array_intersect_key($params, $api_params); 
  314.  
  315. $api = $this->init_api(); 
  316. $response = $api->get_delivery_options( $params, true ); 
  317.  
  318. @header('Content-type: application/json; charset=utf-8'); 
  319.  
  320. echo $response['body']; 
  321. die(); 
  322.  
  323. public function init_api () { 
  324. // $user = WooCommerce_MyParcel()->general_settings['api_username']; 
  325. if ( !isset(WooCommerce_MyParcel()->general_settings['api_key']) ) { 
  326. return false; 
  327.  
  328. $key = WooCommerce_MyParcel()->general_settings['api_key']; 
  329. $api = new WC_MyParcel_API( $key ); 
  330.  
  331. return $api; 
  332.  
  333. public function get_order_shipment_data( $order_ids, $type = 'standard' ) { 
  334. foreach( $order_ids as $order_id ) { 
  335. // get order 
  336. $order = WCX::get_order( $order_id ); 
  337.  
  338. $shipment = array( 
  339. 'recipient' => $this->get_recipient( $order ),  
  340. 'options' => $this->get_options( $order ),  
  341. 'carrier' => 1, // default to POSTNL for now 
  342. ); 
  343.  
  344. if ( $pickup = $this->is_pickup( $order ) ) { 
  345. // $pickup_time = array_shift($pickup['time']); // take first element in time array 
  346. $shipment['pickup'] = array( 
  347. 'postal_code' => $pickup['postal_code'],  
  348. 'street' => $pickup['street'],  
  349. 'city' => $pickup['city'],  
  350. 'number' => $pickup['number'],  
  351. 'location_name' => $pickup['location'],  
  352. ); 
  353.  
  354. /** disabled for now 
  355. $concept_shipments = $this->get_shipment_ids( (array) $order_id, array( 'only_concepts' => true, 'only_last' => true ) ); 
  356. if ( !empty($concept_shipments) ) { 
  357. $shipment['id'] = array_pop($concept_shipments); 
  358. */ 
  359.  
  360. $shipments[] = $shipment; 
  361.  
  362. return $shipments; 
  363.  
  364. public function prepare_return_shipment_data( $order_id, $options ) { 
  365. $order = WCX::get_order( $order_id ); 
  366.  
  367. $shipping_name = method_exists($order, 'get_formatted_shipping_full_name') ? $order->get_formatted_shipping_full_name() : trim( $order->shipping_first_name . ' ' . $order->shipping_last_name ); 
  368.  
  369. // set name & email 
  370. $return_shipment_data = array( 
  371. 'name' => $shipping_name,  
  372. 'email' => isset(WooCommerce_MyParcel()->export_defaults['connect_email']) ? WCX_Order::get_prop( $order, 'billing_email' ) : '',  
  373. 'carrier' => 1, // default to POSTNL for now 
  374. ); 
  375.  
  376. // add options if available 
  377. if (!empty($options)) { 
  378. // convert insurance option 
  379. if ( !isset($options['insurance']) && isset($options['insured_amount']) ) { 
  380. if ($options['insured_amount'] > 0) { 
  381. $options['insurance'] = array( 
  382. 'amount' => (int) $options['insured_amount'] * 100,  
  383. 'currency' => 'EUR',  
  384. ); 
  385.  
  386. unset($options['insured_amount']); 
  387. unset($options['insured']); 
  388.  
  389. // PREVENT ILLEGAL SETTINGS 
  390. // convert numeric strings to int 
  391. $int_options = array( 'package_type', 'delivery_type', 'only_recipient', 'signature', 'return', 'large_format' ); 
  392. foreach ($options as $key => &$value) { 
  393. if ( in_array($key, $int_options) ) { 
  394. $value = (int) $value; 
  395.  
  396. // remove frontend insurance option values 
  397. if (isset($options['insured_amount'])) { 
  398. unset($options['insured_amount']); 
  399. if (isset($options['insured'])) { 
  400. unset($options['insured']); 
  401.  
  402. $return_shipment_data['options'] = $options; 
  403.  
  404. // get parent 
  405. $shipment_ids = $this->get_shipment_ids( (array) $order_id, array( 'exclude_concepts' => true, 'only_last' => true ) ); 
  406. if ( !empty($shipment_ids) ) { 
  407. $return_shipment_data['parent'] = array_pop( $shipment_ids); 
  408.  
  409. return $return_shipment_data; 
  410.  
  411. public function get_recipient( $order ) { 
  412. $shipping_name = method_exists($order, 'get_formatted_shipping_full_name') ? $order->get_formatted_shipping_full_name() : trim( $order->shipping_first_name . ' ' . $order->shipping_last_name ); 
  413. $address = array( 
  414. 'cc' => (string) WCX_Order::get_prop( $order, 'shipping_country' ),  
  415. 'city' => (string) WCX_Order::get_prop( $order, 'shipping_city' ),  
  416. 'person' => $shipping_name,  
  417. 'company' => (string) WCX_Order::get_prop( $order, 'shipping_company' ),  
  418. 'email' => isset(WooCommerce_MyParcel()->export_defaults['connect_email']) ? WCX_Order::get_prop( $order, 'billing_email' ) : '',  
  419. 'phone' => isset(WooCommerce_MyParcel()->export_defaults['connect_phone']) ? WCX_Order::get_prop( $order, 'billing_phone' ) : '',  
  420. ); 
  421.  
  422.  
  423. $shipping_country = WCX_Order::get_prop( $order, 'shipping_country' ); 
  424. if ( $shipping_country == 'NL' ) { 
  425. // use billing address if old 'pakjegemak' (1.5.6 and older) 
  426. if ( $pgaddress = WCX_Order::get_meta( $order, '_myparcel_pgaddress' ) ) { 
  427. $billing_name = method_exists($order, 'get_formatted_billing_full_name') ? $order->get_formatted_billing_full_name() : trim( $order->billing_first_name . ' ' . $order->billing_last_name ); 
  428. $address_intl = array( 
  429. 'city' => (string) WCX_Order::get_prop( $order, 'billing_city' ),  
  430. 'person' => $billing_name,  
  431. 'company' => (string) WCX_Order::get_prop( $order, 'billing_company' ),  
  432. 'street' => (string) WCX_Order::get_meta( $order, '_billing_street_name' ),  
  433. 'number' => (string) WCX_Order::get_meta( $order, '_billing_house_number' ),  
  434. 'number_suffix' => (string) WCX_Order::get_meta( $order, '_billing_house_number_suffix' ),  
  435. 'postal_code' => (string) WCX_Order::get_prop( $order, 'billing_postcode' ),  
  436. ); 
  437. } else { 
  438. $address_intl = array( 
  439. 'street' => (string) WCX_Order::get_meta( $order, '_shipping_street_name' ),  
  440. 'number' => (string) WCX_Order::get_meta( $order, '_shipping_house_number' ),  
  441. 'number_suffix' => (string) WCX_Order::get_meta( $order, '_shipping_house_number_suffix' ),  
  442. 'postal_code' => (string) WCX_Order::get_prop( $order, 'shipping_postcode' ),  
  443. ); 
  444. } else { 
  445. $address_intl = array( 
  446. 'postal_code' => (string) WCX_Order::get_prop( $order, 'shipping_postcode' ),  
  447. 'street' => (string) WCX_Order::get_prop( $order, 'shipping_address_1' ),  
  448. 'street_additional_info' => (string) WCX_Order::get_prop( $order, 'shipping_address_2' ),  
  449. ); 
  450.  
  451. $address = array_merge( $address, $address_intl); 
  452.  
  453. return apply_filters( 'wc_myparcel_recipient', $address, $order ); 
  454.  
  455. public function get_options( $order ) { 
  456. // parse description 
  457. if (isset(WooCommerce_MyParcel()->export_defaults['label_description'])) { 
  458. $description = $this->replace_shortcodes( WooCommerce_MyParcel()->export_defaults['label_description'], $order ); 
  459. } else { 
  460. $description = ''; 
  461.  
  462. // determine appropriate package type for this order 
  463. if (isset(WooCommerce_MyParcel()->export_defaults['shipping_methods_package_types'])) { 
  464. // get shipping methods from order 
  465. $order_shipping_methods = $order->get_items('shipping'); 
  466.  
  467. if ( !empty( $order_shipping_methods ) ) { 
  468. // we're taking the first (we're not handling multiple shipping methods as of yet) 
  469. $order_shipping_method = array_shift($order_shipping_methods); 
  470. $order_shipping_method = $order_shipping_method['method_id']; 
  471. $order_shipping_class = WCX_Order::get_meta( $order, '_myparcel_highest_shipping_class' ); 
  472. if (empty($order_shipping_class)) { 
  473. $order_shipping_class = $this->get_order_shipping_class( $order, $order_shipping_method ); 
  474.  
  475. if ( strpos($order_shipping_method, ':') !== false ) { 
  476. // means we have method_id:instance_id 
  477. $order_shipping_method = explode(':', $order_shipping_method); 
  478. $order_shipping_method_id = $order_shipping_method[0]; 
  479. $order_shipping_method_instance = $order_shipping_method[1]; 
  480. } else { 
  481. $order_shipping_method_id = $order_shipping_method; 
  482.  
  483. // add class if we have one 
  484. if (!empty($order_shipping_class)) { 
  485. $order_shipping_method_id_class = "{$order_shipping_method_id}:{$order_shipping_class}"; 
  486.  
  487. foreach (WooCommerce_MyParcel()->export_defaults['shipping_methods_package_types'] as $package_type_key => $package_type_shipping_methods ) { 
  488. // check if we have a match with the predefined methods 
  489. // fallback to bare method (without class) (if bare method also defined in settings) 
  490. if (in_array($order_shipping_method_id, $package_type_shipping_methods) || (!empty($order_shipping_method_id_class) && in_array($order_shipping_method_id_class, $package_type_shipping_methods))) { 
  491. $package_type = $package_type_key; 
  492. break; 
  493. // fallbacks if no match from previous 
  494. if (!isset($package_type)) { 
  495. if ((isset(WooCommerce_MyParcel()->export_defaults['package_type']))) { 
  496. $package_type = WooCommerce_MyParcel()->export_defaults['package_type']; 
  497. } else { 
  498. $package_type = 1; // 1. package | 2. mailbox package | 3. letter 
  499.  
  500. // disable mailbox package outside NL 
  501. $shipping_country = WCX_Order::get_prop( $order, 'shipping_country' ); 
  502. if ($shipping_country != 'NL' && $package_type == 2 ) { 
  503. $package_type = 1; 
  504.  
  505. // always parcel for Pickup and Pickup express delivery types. 
  506. if ( $this->is_pickup( $order ) ) { 
  507. $package_type = 1; 
  508.  
  509. // use shipment options from order when available 
  510. $shipment_options = WCX_Order::get_meta( $order, '_myparcel_shipment_options' ); 
  511. if (!empty($shipment_options)) { 
  512. $emty_defaults = array( 
  513. 'package_type' => 1,  
  514. 'only_recipient' => 0,  
  515. 'signature' => 0,  
  516. 'return' => 0,  
  517. 'large_format' => 0,  
  518. 'label_description' => '',  
  519. 'insured_amount' => 0,  
  520. ); 
  521. $options = array_merge($emty_defaults, $shipment_options); 
  522. } else { 
  523. if (isset(WooCommerce_MyParcel()->export_defaults['insured']) && WooCommerce_MyParcel()->export_defaults['insured_amount'] == '' && isset(WooCommerce_MyParcel()->export_defaults['insured_amount_custom'])) { 
  524. $insured_amount = WooCommerce_MyParcel()->export_defaults['insured_amount_custom']; 
  525. } elseif (isset(WooCommerce_MyParcel()->export_defaults['insured']) && isset(WooCommerce_MyParcel()->export_defaults['insured_amount'])) { 
  526. $insured_amount = WooCommerce_MyParcel()->export_defaults['insured_amount']; 
  527. } else { 
  528. $insured_amount = 0; 
  529.  
  530. $options = array( 
  531. 'package_type' => $package_type,  
  532. 'only_recipient' => (isset(WooCommerce_MyParcel()->export_defaults['only_recipient'])) ? 1 : 0,  
  533. 'signature' => (isset(WooCommerce_MyParcel()->export_defaults['signature'])) ? 1 : 0,  
  534. 'return' => (isset(WooCommerce_MyParcel()->export_defaults['return'])) ? 1 : 0,  
  535. 'large_format' => (isset(WooCommerce_MyParcel()->export_defaults['large_format'])) ? 1 : 0,  
  536. 'label_description' => $description,  
  537. 'insured_amount' => $insured_amount,  
  538. ); 
  539.  
  540. // convert insurance option 
  541. if ( !isset($options['insurance']) && isset($options['insured_amount']) ) { 
  542. if ($options['insured_amount'] > 0) { 
  543. $options['insurance'] = array( 
  544. 'amount' => (int) $options['insured_amount'] * 100,  
  545. 'currency' => 'EUR',  
  546. ); 
  547.  
  548. unset($options['insured_amount']); 
  549. unset($options['insured']); 
  550.  
  551. // set insurance amount to int if already set 
  552. if (isset($options['insurance'])) { 
  553. $options['insurance']['amount'] = (int) $options['insurance']['amount']; 
  554.  
  555. // remove frontend insurance option values 
  556. if (isset($options['insured_amount'])) { 
  557. unset($options['insured_amount']); 
  558. if (isset($options['insured'])) { 
  559. unset($options['insured']); 
  560.  
  561. // load delivery options 
  562. $myparcel_delivery_options = WCX_Order::get_meta( $order, '_myparcel_delivery_options' ); 
  563.  
  564. // set delivery type 
  565. $options['delivery_type'] = $this->get_delivery_type( $order, $myparcel_delivery_options ); 
  566.  
  567. // Options for Pickup and Pickup express delivery types: 
  568. // always enable signature on receipt 
  569. if ( $this->is_pickup( $order, $myparcel_delivery_options ) ) { 
  570. $options['signature'] = 1; 
  571.  
  572. // delivery date (postponed delivery & pickup) 
  573. if ($delivery_date = $this->get_delivery_date( $order, $myparcel_delivery_options ) ) { 
  574. $date_time = explode(' ', $delivery_date); // split date and time 
  575. // only add if date is in the future 
  576. $timestamp = strtotime($date_time[0]); 
  577. if (time() < $timestamp) { 
  578. $options['delivery_date'] = $delivery_date; 
  579.  
  580. // options signed & recipient only 
  581. $myparcel_signed = WCX_Order::get_meta( $order, '_myparcel_signed' ); 
  582. if (!empty($myparcel_signed)) { 
  583. $options['signature'] = 1; 
  584. $myparcel_only_recipient = WCX_Order::get_meta( $order, '_myparcel_only_recipient' ); 
  585. if (!empty($myparcel_only_recipient)) { 
  586. $options['only_recipient'] = 1; 
  587.  
  588. // allow prefiltering consignment data 
  589. $options = apply_filters( 'wc_myparcel_order_shipment_options', $options, $order ); 
  590.  
  591. // PREVENT ILLEGAL SETTINGS 
  592. // convert numeric strings to int 
  593. $int_options = array( 'package_type', 'delivery_type', 'only_recipient', 'signature', 'return', 'large_format' ); 
  594. foreach ($options as $key => &$value) { 
  595. if ( in_array($key, $int_options) ) { 
  596. $value = (int) $value; 
  597.  
  598. // disable options for mailbox package and unpaid letter 
  599. // echo '<pre>';var_dump($package_type);echo '</pre>';die(); 
  600. if ( $options['package_type'] != 1 ) { 
  601. $illegal_options = array( 'delivery_type', 'only_recipient', 'signature', 'return', 'large_format', 'insurance', 'delivery_date' ); 
  602. foreach ($options as $key => $option) { 
  603. if (in_array($key, $illegal_options)) { 
  604. unset($options[$key]); 
  605.  
  606. return $options; 
  607.  
  608.  
  609. public function get_shipment_ids( $order_ids, $args ) { 
  610. $shipment_ids = array(); 
  611. foreach ($order_ids as $order_id) { 
  612. $order = WCX::get_order( $order_id ); 
  613. $order_shipments = WCX_Order::get_meta( $order, '_myparcel_shipments' ); 
  614. if (!empty($order_shipments)) { 
  615. $order_shipment_ids = array(); 
  616. // exclude concepts or only concepts 
  617. foreach ( $order_shipments as $key => $shipment) { 
  618. if (isset($args['exclude_concepts']) && empty($shipment['tracktrace'])) { 
  619. continue; 
  620. if (isset($args['only_concepts']) && !empty($shipment['tracktrace'])) { 
  621. continue; 
  622.  
  623. $order_shipment_ids[] = $shipment['shipment_id']; 
  624.  
  625. if (isset($args['only_last'])) { 
  626. $shipment_ids[] = array_pop( $order_shipment_ids ); 
  627. } else { 
  628. $shipment_ids[] = array_merge( $shipment_ids, $order_shipment_ids ); 
  629.  
  630. return $shipment_ids; 
  631.  
  632. public function save_shipment_data ( $order, $shipment ) { 
  633. if ( empty($shipment) ) { 
  634. return false; 
  635.  
  636. $shipments = array(); 
  637. $shipments[$shipment['shipment_id']] = $shipment; 
  638. // don't store full shipment data 
  639. // if (isset($shipment['shipment'])) { 
  640. // unset($shipment['shipment']); 
  641. // } 
  642.  
  643. if ( isset(WooCommerce_MyParcel()->general_settings['keep_shipments']) ) { 
  644. if ( $old_shipments = WCX_Order::get_meta( $order, '_myparcel_shipments' ) ) { 
  645. // merging the arrays with the union operator (+) preserves the left hand version 
  646. // when the key exists in both arrays, but we also want to preserve keys and put 
  647. // new shipments AFTER old shipments, so we remove doubles first 
  648. // More intelligent sorting (created/modified date) would be a better solution 
  649. foreach ($shipments as $shipment_id => $shipment) { 
  650. if (isset($old_shipments[$shipment_id])) { 
  651. unset($old_shipments[$shipment_id]); 
  652. $shipments = $old_shipments + $shipments; 
  653.  
  654. WCX_Order::update_meta_data( $order, '_myparcel_shipments', $shipments ); 
  655.  
  656. return; 
  657.  
  658. public function get_package_types( $shipment_type = 'shipment' ) { 
  659. $package_types = array( 
  660. 1 => __( 'Parcel' , 'woocommerce-myparcel' ),  
  661. 2 => __( 'Mailbox package' , 'woocommerce-myparcel' ),  
  662. 3 => __( 'Unpaid letter' , 'woocommerce-myparcel' ),  
  663. ); 
  664. if ( $shipment_type == 'return' ) { 
  665. unset($package_types[2]); 
  666. unset($package_types[3]); 
  667.  
  668. return $package_types; 
  669.  
  670. public function parse_errors( $errors ) { 
  671. $parsed_errors = array(); 
  672. foreach ($errors as $key => $error) { 
  673. // check if we have an order_id 
  674. if ($key > 10) { 
  675. $parsed_errors[] = sprintf("<strong>%s %s:</strong> %s", __( 'Order', 'woocommerce-myparcel' ), $key, $error ); 
  676. } else { 
  677. $parsed_errors[] = $error; 
  678.  
  679. if (count($parsed_errors) == 1) { 
  680. $html = array_shift($parsed_errors); 
  681. } else { 
  682. foreach ($parsed_errors as &$parsed_error) { 
  683. $parsed_error = "<li>{$parsed_error}</li>"; 
  684. $html = sprintf("<ul>%s</ul>", implode("\n", $parsed_errors)); 
  685.  
  686. return $html; 
  687.  
  688. public function stream_pdf ( $pdf_data, $order_ids ) { 
  689. header('Content-type: application/pdf'); 
  690. header('Content-Disposition: inline; filename="'.$this->get_filename( $order_ids ).'"'); 
  691. echo $pdf_data; 
  692. die(); 
  693. public function download_pdf ( $pdf_data, $order_ids ) { 
  694. header('Content-Description: File Transfer'); 
  695. header('Content-Type: application/octet-stream'); 
  696. header('Content-Disposition: attachment; filename="'.$this->get_filename( $order_ids ).'"');  
  697. header('Content-Transfer-Encoding: binary'); 
  698. header('Connection: Keep-Alive'); 
  699. header('Expires: 0'); 
  700. header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
  701. header('Pragma: public'); 
  702. echo $pdf_data; 
  703. die(); 
  704.  
  705. public function get_filename ( $order_ids ) { 
  706. $filename = 'MyParcel'; 
  707. $filename .= '-' . date('Y-m-d') . '.pdf'; 
  708.  
  709. return apply_filters( 'wcmyparcel_filename', $filename, $order_ids ); 
  710.  
  711. public function get_shipment_status_name( $status_code ) { 
  712. $shipment_statuses = array( 
  713. 1 => __('pending - concept', 'woocommerce-myparcel'),  
  714. 2 => __('pending - registered', 'woocommerce-myparcel'),  
  715. 3 => __('enroute - handed to carrier', 'woocommerce-myparcel'),  
  716. 4 => __('enroute - sorting', 'woocommerce-myparcel'),  
  717. 5 => __('enroute - distribution', 'woocommerce-myparcel'),  
  718. 6 => __('enroute - customs', 'woocommerce-myparcel'),  
  719. 7 => __('delivered - at recipient', 'woocommerce-myparcel'),  
  720. 8 => __('delivered - ready for pickup', 'woocommerce-myparcel'),  
  721. 9 => __('delivered - package picked up', 'woocommerce-myparcel'),  
  722. 30 => __('inactive - concept', 'woocommerce-myparcel'),  
  723. 31 => __('inactive - registered', 'woocommerce-myparcel'),  
  724. 32 => __('inactive - enroute - handed to carrier', 'woocommerce-myparcel'),  
  725. 33 => __('inactive - enroute - sorting', 'woocommerce-myparcel'),  
  726. 34 => __('inactive - enroute - distribution', 'woocommerce-myparcel'),  
  727. 35 => __('inactive - enroute - customs', 'woocommerce-myparcel'),  
  728. 36 => __('inactive - delivered - at recipient', 'woocommerce-myparcel'),  
  729. 37 => __('inactive - delivered - ready for pickup', 'woocommerce-myparcel'),  
  730. 38 => __('inactive - delivered - package picked up', 'woocommerce-myparcel'),  
  731. 99 => __('inactive - unknown', 'woocommerce-myparcel'),  
  732. ); 
  733.  
  734. if (isset($shipment_statuses[$status_code])) { 
  735. return $shipment_statuses[$status_code]; 
  736. } else { 
  737. return __('Unknown status', 'woocommerce-myparcel'); 
  738.  
  739. public function get_shipment_data( $id, $order ) { 
  740. try { 
  741. $api = $this->init_api(); 
  742. $response = $api->get_shipments( $id ); 
  743. // echo '<pre>';var_dump($response);echo '</pre>';die(); 
  744.  
  745. if (!empty($response['body']['data']['shipments'])) { 
  746. $shipments = $response['body']['data']['shipments']; 
  747. $shipment = array_shift($shipments); 
  748. // echo '<pre>';var_export($shipment);echo '</pre>';die(); 
  749.  
  750. // if shipment id matches and status is not concept, get tracktrace barcode and status name 
  751. if ( isset($shipment['id']) && $shipment['id'] == $id && $shipment['status'] >= 2 ) { 
  752. $status = $this->get_shipment_status_name( $shipment['status']); 
  753. $tracktrace = $shipment['barcode']; 
  754. $shipment_id = $id; 
  755. $shipment_data = compact( 'shipment_id', 'status', 'tracktrace', 'shipment'); 
  756. $this->save_shipment_data( $order, $shipment_data ); 
  757. return $shipment_data; 
  758. } else { 
  759. return false; 
  760.  
  761. } else { 
  762. // No shipments found with this ID 
  763. return false; 
  764.  
  765.  
  766. } catch (Exception $e) { 
  767. // echo $e->getMessage(); 
  768. return false; 
  769.  
  770. public function replace_shortcodes( $description, $order ) { 
  771. $myparcel_delivery_options = WCX_Order::get_meta( $order, '_myparcel_delivery_options' ); 
  772. $replacements = array( 
  773. '[ORDER_NR]' => $order->get_order_number(),  
  774. '[DELIVERY_DATE]' => isset($myparcel_delivery_options) && isset($myparcel_delivery_options['date']) ? $myparcel_delivery_options['date'] : '',  
  775. ); 
  776.  
  777. $description = str_replace(array_keys($replacements), array_values($replacements), $description); 
  778.  
  779. return $description; 
  780.  
  781. public function get_item_display_name ( $item, $order ) { 
  782. // set base name 
  783. $name = $item['name']; 
  784.  
  785. // add variation name if available 
  786. $product = $order->get_product_from_item( $item ); 
  787. if( $product && isset( $item['variation_id'] ) && $item['variation_id'] > 0 && method_exists($product, 'get_variation_attributes')) { 
  788. $name .= woocommerce_get_formatted_variation( $product->get_variation_attributes() ); 
  789.  
  790. return $name; 
  791.  
  792. public function get_parcel_weight ( $order ) { 
  793. $parcel_weight = (isset(WooCommerce_MyParcel()->general_settings['empty_parcel_weight'])) ? preg_replace("/\D/", "", WooCommerce_MyParcel()->general_settings['empty_parcel_weight'])/1000 : 0; 
  794.  
  795. $items = $order->get_items(); 
  796. foreach ( $items as $item_id => $item ) { 
  797. $parcel_weight += $this->get_item_weight_kg( $item, $order ); 
  798.  
  799. return $parcel_weight; 
  800.  
  801. public function get_item_weight_kg ( $item, $order ) { 
  802. $product = $order->get_product_from_item( $item ); 
  803.  
  804. if (empty($product)) { 
  805. return 0; 
  806.  
  807. $weight = $product->get_weight(); 
  808. $weight_unit = get_option( 'woocommerce_weight_unit' ); 
  809. switch ($weight_unit) { 
  810. case 'kg': 
  811. $product_weight = $weight; 
  812. break; 
  813. case 'g': 
  814. $product_weight = $weight / 1000; 
  815. break; 
  816. case 'lbs': 
  817. $product_weight = $weight * 0.45359237; 
  818. break; 
  819. case 'oz': 
  820. $product_weight = $weight * 0.0283495231; 
  821. break; 
  822. default: 
  823. $product_weight = $weight; 
  824. break; 
  825.  
  826. $item_weight = (float) $product_weight * (int) $item['qty']; 
  827.  
  828. return $item_weight; 
  829.  
  830. public function is_pickup( $order, $myparcel_delivery_options = '' ) { 
  831. if (empty($myparcel_delivery_options)) { 
  832. $myparcel_delivery_options = WCX_Order::get_meta( $order, '_myparcel_delivery_options' ); 
  833.  
  834. $pickup_types = array( 'retail', 'retailexpress' ); 
  835. if ( !empty($myparcel_delivery_options['price_comment']) && in_array($myparcel_delivery_options['price_comment'], $pickup_types) ) { 
  836. return $myparcel_delivery_options; 
  837.  
  838. // Backwards compatibility for pakjegemak data 
  839. $pgaddress = WCX_Order::get_meta( $order, '_myparcel_pgaddress' ); 
  840. if ( !empty( $pgaddress ) && !empty( $pgaddress['postcode'] ) ) { 
  841. $pickup = array( 
  842. 'postal_code' => $pgaddress['postcode'],  
  843. 'street' => $pgaddress['street'],  
  844. 'city' => $pgaddress['town'],  
  845. 'number' => $pgaddress['house_number'],  
  846. 'location' => $pgaddress['name'],  
  847. 'price_comment' => 'retail',  
  848. ); 
  849.  
  850. return $pickup; 
  851.  
  852. // no pickup 
  853. return false; 
  854.  
  855. public function get_delivery_type( $order, $myparcel_delivery_options = '' ) { 
  856. // delivery types 
  857. $delivery_types = array( 
  858. 'morning' => 1,  
  859. 'standard' => 2, // 'default in JS API' 
  860. 'night' => 3,  
  861. 'retail' => 4, // 'pickup' 
  862. 'retailexpress' => 5, // 'pickup_express' 
  863. ); 
  864.  
  865. if (empty($myparcel_delivery_options)) { 
  866. $myparcel_delivery_options = WCX_Order::get_meta( $order, '_myparcel_delivery_options' ); 
  867.  
  868. // standard = default, overwrite if otpions found 
  869. $delivery_type = 'standard'; 
  870. if (!empty($myparcel_delivery_options)) { 
  871. // pickup & pickupexpress store the delivery type in the delivery options,  
  872. // morning & night store it in the time data (...) 
  873. if ( empty($myparcel_delivery_options['price_comment']) && !empty($myparcel_delivery_options['time']) ) { 
  874. // check if we have a price_comment in the time option 
  875. $delivery_time = array_shift($myparcel_delivery_options['time']); // take first element in time array 
  876. if (isset($delivery_time['price_comment'])) { 
  877. $delivery_type = $delivery_time['price_comment']; 
  878. } else { 
  879. $delivery_type = $myparcel_delivery_options['price_comment']; 
  880.  
  881. // backwards compatibility for pakjegemak 
  882. if ( $pgaddress = WCX_Order::get_meta( $order, '_myparcel_pgaddress' ) ) { 
  883. $delivery_type = 'retail'; 
  884.  
  885. // convert to int (default to 2 = standard for unknown types) 
  886. $delivery_type = isset($delivery_types[$delivery_type]) ? $delivery_types[$delivery_type] : 2; 
  887.  
  888. return $delivery_type; 
  889.  
  890. public function get_delivery_date( $order, $myparcel_delivery_options = '' ) { 
  891. if (empty($myparcel_delivery_options)) { 
  892. $myparcel_delivery_options = WCX_Order::get_meta( $order, '_myparcel_delivery_options' ); 
  893.  
  894.  
  895. if ( !empty($myparcel_delivery_options) && !empty($myparcel_delivery_options['date']) ) { 
  896. $delivery_date = $myparcel_delivery_options['date']; 
  897.  
  898. $delivery_type = $this->get_delivery_type( $order, $myparcel_delivery_options ); 
  899. if ( in_array($delivery_type, array(1, 3)) && !empty($myparcel_delivery_options['time']) ) { 
  900. $delivery_time_options = array_shift($myparcel_delivery_options['time']); // take first element in time array 
  901. $delivery_time = $delivery_time_options['start']; 
  902. } else { 
  903. $delivery_time = '00:00:00'; 
  904. $delivery_date = "{$delivery_date} {$delivery_time}"; 
  905. return $delivery_date; 
  906. } else { 
  907. return false; 
  908.  
  909.  
  910. public function get_order_shipping_class($order, $shipping_method_id = '') { 
  911. if (empty($shipping_method_id)) { 
  912. $order_shipping_methods = $order->get_items('shipping'); 
  913.  
  914. if ( !empty( $order_shipping_methods ) ) { 
  915. // we're taking the first (we're not handling multiple shipping methods as of yet) 
  916. $order_shipping_method = array_shift($order_shipping_methods); 
  917. $shipping_method_id = $order_shipping_method['method_id']; 
  918. } else { 
  919. return false; 
  920.  
  921. $shipping_method = $this->get_shipping_method( $shipping_method_id ); 
  922. if (empty($shipping_method)) { 
  923. return false; 
  924.  
  925. // get shipping classes from order 
  926. $found_shipping_classes = $this->find_order_shipping_classes( $order ); 
  927.  
  928. $highest_class = $this->get_shipping_class( $shipping_method, $found_shipping_classes ); 
  929. return $highest_class; 
  930.  
  931.  
  932. public function get_shipping_method($chosen_method) { 
  933. if ( version_compare( WOOCOMMERCE_VERSION, '2.6', '>=' ) && $chosen_method !== 'legacy_flat_rate' ) { 
  934. $chosen_method = explode( ':', $chosen_method ); // slug:instance 
  935. // only for flat rate 
  936. if ( $chosen_method[0] !== 'flat_rate' ) { 
  937. return false; 
  938. if ( empty( $chosen_method[1] ) ) { 
  939. return false; // no instance known (=probably manual order) 
  940.  
  941. $method_slug = $chosen_method[0]; 
  942. $method_instance = $chosen_method[1]; 
  943.  
  944. $shipping_method = WC_Shipping_Zones::get_shipping_method( $method_instance ); 
  945. } else { 
  946. // only for flat rate or legacy flat rate 
  947. if ( !in_array($chosen_method, array('flat_rate', 'legacy_flat_rate') ) ) { 
  948. return false; 
  949. $shipping_methods = WC()->shipping->load_shipping_methods( $package ); 
  950.  
  951. if (!isset($shipping_methods[$chosen_method])) { 
  952. return false; 
  953. $shipping_method = $shipping_methods[$chosen_method]; 
  954.  
  955. return $shipping_method; 
  956.  
  957. public function get_shipping_class($shipping_method, $found_shipping_classes) { 
  958. // get most expensive class 
  959. // adapted from $shipping_method->calculate_shipping() 
  960. $highest_class_cost = 0; 
  961. $highest_class = false; 
  962. foreach ( $found_shipping_classes as $shipping_class => $products ) { 
  963. // Also handles BW compatibility when slugs were used instead of ids 
  964. $shipping_class_term = get_term_by( 'slug', $shipping_class, 'product_shipping_class' ); 
  965. $class_cost_string = $shipping_class_term && $shipping_class_term->term_id ? $shipping_method->get_option( 'class_cost_' . $shipping_class_term->term_id, $shipping_method->get_option( 'class_cost_' . $shipping_class, '' ) ) : $shipping_method->get_option( 'no_class_cost', '' ); 
  966.  
  967. if ( $class_cost_string === '' ) { 
  968. continue; 
  969.  
  970.  
  971. $has_costs = true; 
  972. $class_cost = $this->wc_flat_rate_evaluate_cost( $class_cost_string, array( 
  973. 'qty' => array_sum( wp_list_pluck( $products, 'quantity' ) ),  
  974. 'cost' => array_sum( wp_list_pluck( $products, 'line_total' ) ) 
  975. ), $shipping_method ); 
  976.  
  977. if ( $class_cost > $highest_class_cost && $shipping_class_term->term_id) { 
  978. $highest_class_cost = $class_cost; 
  979. $highest_class = $shipping_class_term->term_id; 
  980.  
  981. return $highest_class; 
  982.  
  983. public function find_order_shipping_classes($order) { 
  984. $found_shipping_classes = array(); 
  985. $order_items = $order->get_items(); 
  986. foreach ( $order_items as $item_id => $item ) { 
  987. $product = $order->get_product_from_item( $item ); 
  988. if ( $product && $product->needs_shipping() ) { 
  989. $found_class = $product->get_shipping_class(); 
  990.  
  991. if ( ! isset( $found_shipping_classes[ $found_class ] ) ) { 
  992. $found_shipping_classes[ $found_class ] = array(); 
  993.  
  994. $found_shipping_classes[ $found_class ][ $item_id ] = $product; 
  995.  
  996. return $found_shipping_classes; 
  997.  
  998. /** 
  999. * Adapted from WC_Shipping_Flat_Rate - Protected method 
  1000. * Evaluate a cost from a sum/string. 
  1001. * @param string $sum 
  1002. * @param array $args 
  1003. * @return string 
  1004. */ 
  1005. public function wc_flat_rate_evaluate_cost($sum, $args = array(), $flat_rate_method) { 
  1006. if ( version_compare( WOOCOMMERCE_VERSION, '2.6', '>=' ) ) { 
  1007. include_once( WC()->plugin_path() . '/includes/libraries/class-wc-eval-math.php' ); 
  1008. } else { 
  1009. include_once( WC()->plugin_path() . '/includes/shipping/flat-rate/includes/class-wc-eval-math.php' ); 
  1010.  
  1011. // Allow 3rd parties to process shipping cost arguments 
  1012. $args = apply_filters( 'woocommerce_evaluate_shipping_cost_args', $args, $sum, $flat_rate_method ); 
  1013. $locale = localeconv(); 
  1014. $decimals = array( wc_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'], ', ' ); 
  1015. $this->fee_cost = $args['cost']; 
  1016.  
  1017. // Expand shortcodes 
  1018. add_shortcode( 'fee', array( $this, 'wc_flat_rate_fee' ) ); 
  1019.  
  1020. $sum = do_shortcode( str_replace( 
  1021. array( 
  1022. '[qty]',  
  1023. '[cost]' 
  1024. ),  
  1025. array( 
  1026. $args['qty'],  
  1027. $args['cost'] 
  1028. ),  
  1029. $sum 
  1030. ) ); 
  1031.  
  1032. remove_shortcode( 'fee', array( $this, 'wc_flat_rate_fee' ) ); 
  1033.  
  1034. // Remove whitespace from string 
  1035. $sum = preg_replace( '/\s+/', '', $sum ); 
  1036.  
  1037. // Remove locale from string 
  1038. $sum = str_replace( $decimals, '.', $sum ); 
  1039.  
  1040. // Trim invalid start/end characters 
  1041. $sum = rtrim( ltrim( $sum, "\t\n\r\0\x0B+*/" ), "\t\n\r\0\x0B+-*/" ); 
  1042.  
  1043. // Do the math 
  1044. return $sum ? WC_Eval_Math::evaluate( $sum ) : 0; 
  1045.  
  1046. /** 
  1047. * Adapted from WC_Shipping_Flat_Rate - Protected method 
  1048. * Work out fee (shortcode). 
  1049. * @param array $atts 
  1050. * @return string 
  1051. */ 
  1052. public function wc_flat_rate_fee( $atts ) { 
  1053. $atts = shortcode_atts( array( 
  1054. 'percent' => '',  
  1055. 'min_fee' => '',  
  1056. 'max_fee' => '',  
  1057. ), $atts ); 
  1058.  
  1059. $calculated_fee = 0; 
  1060.  
  1061. if ( $atts['percent'] ) { 
  1062. $calculated_fee = $this->fee_cost * ( floatval( $atts['percent'] ) / 100 ); 
  1063.  
  1064. if ( $atts['min_fee'] && $calculated_fee < $atts['min_fee'] ) { 
  1065. $calculated_fee = $atts['min_fee']; 
  1066.  
  1067. if ( $atts['max_fee'] && $calculated_fee > $atts['max_fee'] ) { 
  1068. $calculated_fee = $atts['max_fee']; 
  1069.  
  1070. return $calculated_fee; 
  1071.  
  1072. public function filter_eu_orders( $order_ids ) { 
  1073. foreach ($order_ids as $key => $order_id) { 
  1074. $order = WCX::get_order( $order_id ); 
  1075. $shipping_country = WCX_Order::get_prop( $order, 'shipping_country' ); 
  1076. // skip non-eu orders 
  1077. if ( !$this->is_eu_country( $shipping_country ) ) { 
  1078. unset($order_ids[$key]); 
  1079. return $order_ids; 
  1080.  
  1081. public function is_eu_country($country_code) { 
  1082. $eu_countries = array( 'GB', 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE' ); 
  1083. return in_array( $country_code, $eu_countries); 
  1084.  
  1085. public function log( $message ) { 
  1086. if (isset(WooCommerce_MyParcel()->general_settings['error_logging'])) { 
  1087. // log file in upload folder - wp-content/uploads 
  1088. $upload_dir = wp_upload_dir(); 
  1089. $upload_base = trailingslashit( $upload_dir['basedir'] ); 
  1090. $log_file = $upload_base.'myparcel_log.txt'; 
  1091.  
  1092. $current_date_time = date("Y-m-d H:i:s"); 
  1093. $message = $current_date_time .' ' .$message ."\n"; 
  1094.  
  1095. file_put_contents($log_file, $message, FILE_APPEND);