/includes/api/class-wc-pos-orders.php

  1. <?php 
  2.  
  3. /** 
  4. * POS Orders Class 
  5. * duck punches the WC REST API 
  6. * 
  7. * @class WC_POS_API_Orders 
  8. * @package WooCommerce POS 
  9. * @author Paul Kilmurray <paul@kilbot.com.au> 
  10. * @link http://www.woopos.com.au 
  11. */ 
  12.  
  13. class WC_POS_API_Orders extends WC_POS_API_Abstract { 
  14.  
  15. /** @var array Contains the raw order data */ 
  16. private $data = array(); 
  17. private $flag = false; 
  18.  
  19. /** 
  20. * Constructor 
  21. */ 
  22. public function __construct() { 
  23.  
  24. // order data 
  25. add_filter( 'woocommerce_api_create_order_data', array( $this, 'create_order_data') ); 
  26. add_filter( 'woocommerce_api_edit_order_data', array( $this, 'edit_order_data'), 10, 2 ); 
  27. add_action( 'woocommerce_api_create_order', array( $this, 'create_order') ); 
  28. add_action( 'woocommerce_api_edit_order', array( $this, 'edit_order') ); 
  29.  
  30. // payment 
  31. add_action( 'woocommerce_pos_process_payment', array( $this, 'process_payment' ), 10, 2 ); 
  32. add_action( 'woocommerce_payment_complete', array( $this, 'payment_complete' ), 10, 1 ); 
  33.  
  34. // order response 
  35. add_filter( 'woocommerce_api_order_response', array( $this, 'order_response' ), 10, 4 ); 
  36.  
  37. // order emails 
  38. add_filter( 'woocommerce_email', array( $this, 'woocommerce_email' ), 99 ); 
  39.  
  40. /** 
  41. * Create order data 
  42. * 
  43. * @param array $data 
  44. * @return array 
  45. */ 
  46. public function create_order_data(array $data) { 
  47.  
  48. // store raw http data 
  49. $this->data = $data; 
  50.  
  51. // add filters & actions for create order 
  52. add_filter( 'woocommerce_product_tax_class', array( $this, 'product_tax_class' ), 10, 2 ); 
  53. add_filter( 'woocommerce_get_product_from_item', array( $this, 'get_product_from_item' ), 10, 3 ); 
  54. add_filter( 'pre_option_woocommerce_tax_based_on', array( $this, 'woocommerce_tax_based_on' ) ); 
  55. add_filter( 'woocommerce_find_rates', array( $this, 'find_rates'), 10, 2 ); 
  56. add_action( 'woocommerce_order_add_product', array( $this, 'order_add_product'), 10, 5 ); 
  57. add_action( 'updated_order_item_meta', array( $this, 'updated_order_item_meta'), 10, 4 ); 
  58.  
  59. // WC API < 2.4 has a bug if $fee['taxable'] = false 
  60. // set $fee['taxable'] = true and use random tax_class so not tax is calculated 
  61. if( version_compare( WC()->version, '2.4', '<' ) && isset($this->data['fee_lines']) ) { 
  62. foreach( $this->data['fee_lines'] as &$fee ) { 
  63. if( !isset($fee['taxable']) || $fee['taxable'] == false ) { 
  64. $fee['taxable'] = true; 
  65. $fee['tax_class'] = 'upgrade-woocommerce-' . time(); 
  66.  
  67. // WC handling of shipping is FUBAR 
  68. // if order has shipping line, we'll have to calc the tax ourselves 
  69. // also recalc total tax for negative fee lines 
  70. $has_fee = isset($this->data['fee_lines']) && !empty($this->data['fee_lines']); 
  71. $has_shipping = isset($this->data['shipping_lines']) && !empty($this->data['shipping_lines']); 
  72.  
  73. if( $has_shipping ) { 
  74. add_filter( 'pre_option_woocommerce_shipping_tax_class', array( $this, 'woocommerce_shipping_tax_class' ) ); 
  75. add_action( 'woocommerce_order_add_shipping', array( $this, 'order_add_shipping'), 10, 3 ); 
  76.  
  77. if( $has_fee || $has_shipping ) 
  78. add_filter( 'update_post_metadata', array( $this, 'update_post_metadata'), 10, 5 ); 
  79.  
  80. // POS UI uses Fee 'name' for WC 3 compat 
  81. if( $has_fee ) { 
  82. foreach($this->data['fee_lines'] as &$fee) { 
  83. if( !isset($fee['title']) && isset( $fee['name'] ) ) { 
  84. $fee['title'] = $fee['name']; 
  85.  
  86. // populate customer data 
  87. $customer_id = isset( $data['customer_id'] ) ? $data['customer_id'] : 0 ; 
  88. if($customer_id) { 
  89. $this->data['billing_address'] = $this->get_customer_details($customer_id, 'billing'); 
  90. $this->data['shipping_address'] = $this->get_customer_details($customer_id, 'shipping'); 
  91.  
  92. return $this->data; 
  93.  
  94. /** 
  95. * Edit order data 
  96. * 
  97. * @param $data 
  98. * @param $order_id 
  99. * @return array 
  100. */ 
  101. public function edit_order_data(array $data, $order_id) { 
  102. // $this->delete_order_items($order_id); 
  103. return $this->create_order_data($data); 
  104.  
  105. /** 
  106. * Change the product tax_class 
  107. * @param $tax_class 
  108. * @param $product 
  109. * @return string 
  110. */ 
  111. public function product_tax_class($tax_class, $product) { 
  112.  
  113. $id = isset($product->id) ? $product->id: false; 
  114. $id = isset($product->variation_id) ? $product->variation_id: $id; 
  115.  
  116. if($id) { 
  117. $item = $this->get_line_item($id); 
  118. if( isset( $item['tax_class'] ) ) { 
  119. $tax_class = sanitize_text_field( $item['tax_class'] ); 
  120.  
  121. return $tax_class; 
  122.  
  123. /** 
  124. * Set taxable 
  125. * @param $product 
  126. * @param $item 
  127. * @param $WC_Product 
  128. * @return mixed 
  129. */ 
  130. public function get_product_from_item($product, $item, $WC_Product) { 
  131.  
  132. $id = isset($product->id) ? $product->id: false; 
  133. $id = isset($product->variation_id) ? $product->variation_id: $id; 
  134.  
  135. if($id) { 
  136. $data = $this->get_line_item($id); 
  137. if( isset( $data['taxable'] ) ) { 
  138. // api has options true/false 
  139. // tax_status has options taxable/shipping/none 
  140. $product->tax_status = $data['taxable'] ? 'taxable' : 'none'; 
  141.  
  142. return $product; 
  143.  
  144.  
  145. /** 
  146. * Opportunity to change title and add line_item meta 
  147. * @param $order_id 
  148. * @param $item_id 
  149. * @param $product 
  150. * @param $qty 
  151. * @param $args 
  152. */ 
  153. public function order_add_product($order_id, $item_id, $product, $qty, $args) { 
  154.  
  155. $id = isset($product->id) ? $product->id: false; 
  156. $id = isset($product->variation_id) ? $product->variation_id: $id; 
  157.  
  158. if($id) { 
  159. $data = $this->get_line_item($id); 
  160.  
  161. // update title 
  162. if( isset( $data['name'] ) ) { 
  163. wc_update_order_item( $item_id,  
  164. array( 
  165. 'order_item_name' => sanitize_text_field( $data['name'] ) 
  166. ); 
  167.  
  168. // update meta 
  169. if( isset( $data['meta'] ) && !empty( $data['meta'] ) ) { 
  170. $this->add_product_meta( $item_id, $data['meta'] ); 
  171.  
  172.  
  173.  
  174. /** 
  175. * Add product meta 
  176. * @param $item_id 
  177. * @param array $meta 
  178. */ 
  179. private function add_product_meta($item_id, array $meta) { 
  180.  
  181. // line meta 
  182. foreach($meta as $m) { 
  183. $label = isset($m['label']) ? $m['label'] : ''; 
  184. $value = isset($m['value']) ? $m['value'] : ''; 
  185. wc_add_order_item_meta( $item_id, $label, $value ); 
  186.  
  187.  
  188. /** 
  189. * 
  190. * @param $order_id 
  191. * @param $item_id 
  192. * @param $rate 
  193. */ 
  194. public function order_add_shipping($order_id, $item_id, $rate) { 
  195. $shipping_line = $this->get_shipping_line($rate, $item_id); 
  196.  
  197. if($shipping_line && isset($shipping_line['tax'])) { 
  198. $taxes = array(); 
  199. foreach($shipping_line['tax'] as $k => $tax) { 
  200. if( !empty($tax) ) { 
  201. $taxes[$k] = isset($tax['total']) ? wc_format_decimal( $tax['total'] ) : 0 ; 
  202. wc_update_order_item_meta( $item_id, 'taxes', $taxes ); 
  203.  
  204. /** 
  205. * Short circuit get_option('woocommerce_tax_based_on') as shop base 
  206. * @return string 
  207. */ 
  208. public function woocommerce_tax_based_on() { 
  209. return 'base'; 
  210.  
  211. /** 
  212. * Short circuit get_option('woocommerce_shipping_tax_class') as standard 
  213. * @return string 
  214. */ 
  215. public function woocommerce_shipping_tax_class() { 
  216. return 'standard'; 
  217.  
  218. /** 
  219. * Remove calc_shipping_tax 
  220. * @param $matched_tax_rates 
  221. * @param $args 
  222. * @return array 
  223. */ 
  224. public function find_rates( $matched_tax_rates, $args ) { 
  225. if ( $matched_tax_rates ) { 
  226. foreach ( $matched_tax_rates as &$rate ) { 
  227. $rate['shipping'] = 'no'; 
  228. return $matched_tax_rates; 
  229.  
  230. /** 
  231. * Retrieve line_item from raw data 
  232. * @param $product_id 
  233. */ 
  234. private function get_line_item($product_id) { 
  235. if(!isset($this->data['line_items'])) 
  236. return; 
  237.  
  238. foreach($this->data['line_items'] as $item) { 
  239. if( isset($item['product_id']) && $item['product_id'] == $product_id ) 
  240. return $item; 
  241.  
  242. /** 
  243. * Match $rate properties to raw data 
  244. * - there's no id to match so do best guess match id, title & cost 
  245. * @param $rate 
  246. * @param $item_id 
  247. */ 
  248. private function get_shipping_line($rate, $item_id) { 
  249. if(!isset($this->data['shipping_lines'])) 
  250. return; 
  251.  
  252. $lines = $this->data['shipping_lines']; 
  253. foreach($lines as $key => &$line) { 
  254. if( 
  255. $line['method_id'] == $rate->method_id && 
  256. $line['method_title'] == $rate->label && 
  257. $line['total'] == $rate->cost && 
  258. !isset( $line['id'] ) 
  259. $line['id'] = $item_id; 
  260. return $line; 
  261.  
  262. /** 
  263. * Fix item meta for negative product/fee values 
  264. * @param $meta_id 
  265. * @param $order_id 
  266. * @param $meta_key 
  267. * @param $meta_value 
  268. */ 
  269. public function updated_order_item_meta($meta_id, $order_id, $meta_key, $meta_value) { 
  270.  
  271. if($meta_key == '_line_tax_data') { 
  272. $line_subtotal_taxes = isset($meta_value['subtotal']) ? $meta_value['subtotal'] : array(); 
  273. $line_taxes = isset($meta_value['total']) ? $meta_value['total'] : array(); 
  274. $line_subtotal_tax = array_sum( $line_subtotal_taxes ); 
  275. $line_tax = array_sum( $line_taxes ); 
  276.  
  277. wc_update_order_item_meta( $order_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) ); 
  278. wc_update_order_item_meta( $order_id, '_line_tax', wc_format_decimal( $line_tax ) ); 
  279.  
  280.  
  281. /** 
  282. * Apply shipping tax, fix order_tax 
  283. * - 
  284. * - filter has already passed $this->data['shipping_tax'] test 
  285. * @param $null 
  286. * @param $order_id 
  287. * @param $meta_key 
  288. * @param $meta_value 
  289. * @param $prev_value 
  290. * @return null 
  291. */ 
  292. public function update_post_metadata($null, $order_id, $meta_key, $meta_value, $prev_value) { 
  293.  
  294. // we want last update to _order_shipping after $order->calculate_taxes() 
  295. // set flag true on first pass 
  296. if( $meta_key == '_order_shipping_tax' ) 
  297. $this->flag = true; 
  298.  
  299. if( $meta_key != '_order_shipping' || ! $this->flag ) 
  300. return $null; 
  301.  
  302. // update order meta 
  303. $shipping_tax_total = isset($this->data['shipping_tax']) ? $this->data['shipping_tax'] : 0 ; 
  304. update_post_meta( $order_id, '_order_shipping_tax', wc_format_decimal( $shipping_tax_total ) ); 
  305.  
  306. // check each shipping tax line 
  307. // if order item meta already exists, update the shipping_tax_amount 
  308. // if order item meta not present, add the new tax 
  309. // ... nasty :( 
  310.  
  311. // first get an assoc array of $rate_id => $item_id 
  312. $tax_items = array(); 
  313. $order_tax = 0; 
  314. $order = wc_get_order( $order_id ); 
  315. foreach ( $order->get_tax_totals() as $code => $tax ) { 
  316. $tax_items[$tax->rate_id] = $tax->id; 
  317. $order_tax += $tax->amount; 
  318.  
  319. // fix total_tax calc 
  320. update_post_meta($order_id, '_order_tax', $order_tax); 
  321.  
  322. // now loop through the shipping_lines 
  323. if( isset( $shipping['shipping_lines'] ) ) : 
  324. foreach($this->data['shipping_lines'] as $shipping) : 
  325. if( isset( $shipping['tax'] ) ) : 
  326. foreach( $shipping['tax'] as $rate_id => $tax ) : 
  327. if( isset( $tax['total'] ) ) : 
  328.  
  329. if( array_key_exists( $rate_id, $tax_items ) ) { 
  330. wc_update_order_item_meta( $tax_items[$rate_id], 'shipping_tax_amount', wc_format_decimal( $tax['total'] ) ); 
  331. } else { 
  332. $order->add_tax( $rate_id, 0, $tax['total'] ); 
  333.  
  334. endif; 
  335. endforeach; 
  336. endif; 
  337. endforeach; 
  338. endif; 
  339.  
  340. return $null; 
  341.  
  342. /** 
  343. * Create order complete 
  344. * @param $order_id 
  345. */ 
  346. public function create_order( $order_id ) { 
  347. // pos meta 
  348. $current_user = wp_get_current_user(); 
  349.  
  350. update_post_meta( $order_id, '_pos', 1 ); 
  351. update_post_meta( $order_id, '_pos_user', $current_user->ID ); 
  352. update_post_meta( $order_id, '_pos_user_name', $current_user->user_firstname . ' ' . $current_user->user_lastname ); 
  353.  
  354. // check _order_tax and _order_shipping_tax for reports 
  355. if( ! get_post_meta( $order_id, '_order_tax', true ) ) { 
  356. update_post_meta( $order_id, '_order_tax', 0 ); 
  357.  
  358. if( ! get_post_meta( $order_id, '_order_shipping_tax', true ) ) { 
  359. update_post_meta( $order_id, '_order_shipping_tax', 0 ); 
  360.  
  361. // payment 
  362. do_action( 'woocommerce_pos_process_payment', $order_id, $this->data); 
  363.  
  364. /** 
  365. * Edit order complete 
  366. * @param $order_id 
  367. */ 
  368. public function edit_order( $order_id ) { 
  369. // payment 
  370. do_action( 'woocommerce_pos_process_payment', $order_id, $this->data); 
  371.  
  372. /** 
  373. * Process payment 
  374. * @param $order_id 
  375. * @param $data 
  376. */ 
  377. public function process_payment( $order_id, $data ) { 
  378.  
  379. if( !isset($data['payment_details']) ) { 
  380. return; 
  381.  
  382. // some gateways check if a user is signed in, so let's switch to customer 
  383. $logged_in_user = get_current_user_id(); 
  384. $customer_id = isset( $data['customer_id'] ) ? $data['customer_id'] : 0 ; 
  385. wp_set_current_user( $customer_id ); 
  386.  
  387. // load the gateways & process payment 
  388. $gateway_id = $data['payment_details']['method_id']; 
  389. add_filter('option_woocommerce_'. $gateway_id .'_settings', array($this, 'force_enable_gateway')); 
  390. $settings = WC_POS_Admin_Settings_Checkout::get_instance(); 
  391. $gateways = $settings->load_enabled_gateways(); 
  392. $response = $gateways[ $gateway_id ]->process_payment( $order_id ); 
  393.  
  394. if(isset($response['result']) && $response['result'] == 'success') { 
  395. $this->payment_success($gateway_id, $order_id, $response); 
  396. } else { 
  397. $this->payment_failure($gateway_id, $order_id, $response); 
  398.  
  399. // switch back to logged in user 
  400. wp_set_current_user( $logged_in_user ); 
  401.  
  402. // clear any payment gateway messages 
  403. wc_clear_notices(); 
  404.  
  405. /** 
  406. * Some gateways will check if enabled 
  407. * @param $data 
  408. * @return mixed 
  409. */ 
  410. public function force_enable_gateway($data) { 
  411. if(isset($data['enabled'])) { 
  412. $data['enabled'] = 'yes'; 
  413. return $data; 
  414.  
  415. /** 
  416. * @param $gateway_id 
  417. * @param $order_id 
  418. * @param $response 
  419. */ 
  420. private function payment_success($gateway_id, $order_id, $response) { 
  421.  
  422. // capture any instructions 
  423. ob_start(); 
  424. do_action( 'woocommerce_thankyou_' . $gateway_id, $order_id ); 
  425. $response['messages'] = ob_get_contents(); 
  426. ob_end_clean(); 
  427.  
  428. // redirect 
  429. if( isset($response['redirect']) ) { 
  430. $response['messages'] = $this->payment_redirect($gateway_id, $order_id, $response); 
  431.  
  432. update_post_meta( $order_id, '_pos_payment_result', 'success' ); 
  433. update_post_meta( $order_id, '_pos_payment_message', $response['messages'] ); 
  434.  
  435. /** 
  436. * @param $gateway_id 
  437. * @param $order_id 
  438. * @param $response 
  439. */ 
  440. private function payment_failure($gateway_id, $order_id, $response) { 
  441. $message = isset($response['messages']) ? $response['messages'] : wc_get_notices( 'error' ); 
  442.  
  443. // if messages empty give generic response 
  444. if(empty($message)) { 
  445. $message = __( 'There was an error processing the payment', 'woocommerce-pos'); 
  446.  
  447. update_post_meta( $order_id, '_pos_payment_result', 'failure' ); 
  448. update_post_meta( $order_id, '_pos_payment_message', $message ); 
  449.  
  450. /** 
  451. * @param $gateway_id 
  452. * @param $order_id 
  453. * @param $response 
  454. * @return string 
  455. */ 
  456. private function payment_redirect($gateway_id, $order_id, $response) { 
  457. $message = $response['messages']; 
  458.  
  459. // compare url fragments 
  460. $success_url = wc_get_endpoint_url( 'order-received', $order_id, get_permalink( wc_get_page_id( 'checkout' ) ) ); 
  461. $success = wp_parse_args( parse_url( $success_url ), array( 'host' => '', 'path' => '' )); 
  462. $redirect = wp_parse_args( parse_url( $response['redirect'] ), array( 'host' => '', 'path' => '' )); 
  463.  
  464. $offsite = $success['host'] !== $redirect['host']; 
  465. $reload = !$offsite && $success['path'] !== $redirect['path'] && $response['messages'] == ''; 
  466.  
  467. if($offsite || $reload) { 
  468. update_post_meta( $order_id, '_pos_payment_redirect', $response['redirect'] ); 
  469. $message = __('You are now being redirected offsite to complete the payment. ', 'woocommerce-pos'); 
  470. $message .= sprintf( __('<a href="%s">Click here</a> if you are not redirected automatically. ', 'woocommerce-pos'), $response['redirect'] ); 
  471.  
  472. return $message; 
  473.  
  474. /** 
  475. * @param $order_id 
  476. */ 
  477. public function payment_complete( $order_id ) { 
  478.  
  479. // update order status 
  480. $order = new WC_Order( $order_id ); 
  481. if( $order->status == 'processing' ) { 
  482. $message = __('POS Transaction completed.', 'woocommerce-pos'); 
  483. $order->update_status( wc_pos_get_option( 'checkout', 'order_status' ), $message ); 
  484.  
  485.  
  486. /** 
  487. * Add any payment messages to API response 
  488. * Also add subtotal_tax to receipt which is not included for some reason 
  489. * @param array $order_data 
  490. * @param $order 
  491. * @param $fields 
  492. * @param $server 
  493. * @return array 
  494. */ 
  495. public function order_response( $order_data, $order, $fields, $server ) { 
  496.  
  497. // add cashier data 
  498. $cashier_details = isset( $order_data['cashier'] ) ? $order_data['cashier'] : array(); 
  499. $order_data['cashier'] = $this->add_cashier_details( $order, $cashier_details ); 
  500.  
  501. // add pos payment info 
  502. $payment_details = isset( $order_data['payment_details'] ) ? $order_data['payment_details'] : array(); 
  503. $order_data['payment_details'] = $this->add_payment_details( $order, $payment_details ); 
  504.  
  505. // addresses 
  506. // $order_data['billing_address'] = $this->filter_address($order_data['billing_address'], $order); 
  507. // $order_data['shipping_address'] = $this->filter_address($order_data['shipping_address'], $order, 'shipping'); 
  508.  
  509. // allow decimal quantity 
  510. // fixed in WC 2.4+ 
  511. if( version_compare( WC()->version, '2.4', '<' ) && wc_pos_get_option( 'general', 'decimal_qty' ) ) { 
  512. $order_data['line_items'] = $this->filter_qty($order_data['line_items']); 
  513.  
  514. // add subtotal_tax 
  515. $subtotal_tax = 0; 
  516. foreach( $order_data['line_items'] as $item ) { 
  517. if(isset( $item['subtotal_tax'] )) { 
  518. $subtotal_tax += wc_format_decimal( $item['subtotal_tax'] ); 
  519. $order_data['subtotal_tax'] = wc_format_decimal( $subtotal_tax ); 
  520.  
  521. // add shipping tax 
  522. foreach( $order_data['shipping_lines'] as &$item ) { 
  523. if(isset( $item['id'] )) { 
  524. $taxes = wc_get_order_item_meta( $item['id'], 'taxes' ); 
  525. $item['total_tax'] = wc_format_decimal( array_sum($taxes) ); 
  526.  
  527. // compatibility for templates 
  528. foreach( $order_data['fee_lines'] as &$item ) { 
  529. if( !isset($item['name']) && isset($item['title'] ) ) { 
  530. $item['name'] = $item['title']; 
  531.  
  532. // add cart discount tax 
  533. $order_data['cart_discount_tax'] = get_post_meta($order->id, '_cart_discount_tax', true); 
  534.  
  535. // Backwards compatibility for WC legacy API 
  536. $order_data['discount_total'] = $order_data['total_discount']; 
  537.  
  538. return $order_data; 
  539.  
  540. /** 
  541. * @param $order 
  542. * @param array $cashier 
  543. * @return array 
  544. */ 
  545. private function add_cashier_details( $order ) { 
  546. if ( !$cashier_id = get_post_meta( $order->id, '_pos_user', true ) ) { 
  547. return; 
  548. $first_name = get_post_meta( $order->id, '_pos_user_first_name', true ); 
  549. $last_name = get_post_meta( $order->id, '_pos_user_last_name', true ); 
  550. if ( !$first_name && !$last_name && $user_info = get_userdata( $cashier_id ) ) { 
  551. $first_name = $user_info->first_name; 
  552. $last_name = $user_info->last_name; 
  553. $cashier = array( 
  554. 'id' => $cashier_id,  
  555. 'first_name' => $first_name,  
  556. 'last_name' => $last_name 
  557. ); 
  558. return apply_filters( 'woocommerce_pos_order_response_cashier', $cashier, $order ); 
  559.  
  560. /** 
  561. * @param $order 
  562. * @param array $payment 
  563. * @return array 
  564. */ 
  565. private function add_payment_details( $order, array $payment = array() ) { 
  566. $payment['result'] = get_post_meta( $order->id, '_pos_payment_result', true ); 
  567. $payment['message'] = get_post_meta( $order->id, '_pos_payment_message', true ); 
  568. $payment['redirect'] = get_post_meta( $order->id, '_pos_payment_redirect', true ); 
  569. if( isset( $payment['method_id'] ) && $payment['method_id'] == 'pos_cash' ) { 
  570. $payment = WC_POS_Gateways_Cash::payment_details( $payment, $order ); 
  571. return apply_filters( 'woocommerce_pos_order_response_payment_details', $payment, $order ); 
  572.  
  573. /** 
  574. * Adds support for custom address fields 
  575. * @param $address 
  576. * @param $order 
  577. * @param string $type 
  578. * @return array 
  579. */ 
  580. private function filter_address( $address, $order, $type = 'billing' ) { 
  581. $fields = apply_filters('woocommerce_admin_'.$type.'_fields', false); 
  582. if( $fields ) { 
  583. $address = array(); 
  584. foreach($fields as $key => $value) { 
  585. $address[$key] = $order->{$type.'_'.$key}; 
  586. return $address; 
  587.  
  588. /** 
  589. * Get customer details 
  590. * - mirrors woocommerce/includes/class-wc-ajax.php->get_customer_details() 
  591. * @param $user_id 
  592. * @param $type_to_load 
  593. * @return mixed|void 
  594. */ 
  595. private function get_customer_details( $user_id, $type_to_load ) { 
  596. $customer_data = array( 
  597. $type_to_load . '_first_name' => get_user_meta( $user_id, $type_to_load . '_first_name', true ),  
  598. $type_to_load . '_last_name' => get_user_meta( $user_id, $type_to_load . '_last_name', true ),  
  599. $type_to_load . '_company' => get_user_meta( $user_id, $type_to_load . '_company', true ),  
  600. $type_to_load . '_address_1' => get_user_meta( $user_id, $type_to_load . '_address_1', true ),  
  601. $type_to_load . '_address_2' => get_user_meta( $user_id, $type_to_load . '_address_2', true ),  
  602. $type_to_load . '_city' => get_user_meta( $user_id, $type_to_load . '_city', true ),  
  603. $type_to_load . '_postcode' => get_user_meta( $user_id, $type_to_load . '_postcode', true ),  
  604. $type_to_load . '_country' => get_user_meta( $user_id, $type_to_load . '_country', true ),  
  605. $type_to_load . '_state' => get_user_meta( $user_id, $type_to_load . '_state', true ),  
  606. $type_to_load . '_email' => get_user_meta( $user_id, $type_to_load . '_email', true ),  
  607. $type_to_load . '_phone' => get_user_meta( $user_id, $type_to_load . '_phone', true ),  
  608. ); 
  609. $customer_data = apply_filters( 'woocommerce_found_customer_details', $customer_data, $user_id, $type_to_load ); 
  610.  
  611. // remove billing_ or shipping_ prefix for WC REST API 
  612. $data = array(); 
  613. foreach( $customer_data as $key => $value ): if($value): 
  614. $key = str_replace( $type_to_load.'_', '', $key ); 
  615. $data[$key] = $value; 
  616. endif; endforeach; 
  617. return $data; 
  618.  
  619. /** 
  620. * @param $line_items 
  621. * @return mixed 
  622. */ 
  623. private function filter_qty($line_items) { 
  624. foreach( $line_items as &$item ) { 
  625. $qty = wc_get_order_item_meta( $item['id'], '_qty' ); 
  626. $item['quantity'] = wc_stock_amount( $qty ); 
  627. return $line_items; 
  628.  
  629. /** 
  630. * Returns array of all order ids 
  631. * optionally return ids updated_at_min 
  632. * @param $updated_at_min 
  633. * @return array 
  634. */ 
  635. public function get_ids($updated_at_min) { 
  636. $args = array( 
  637. 'post_type' => array('shop_order'),  
  638. 'post_status' => array('any'),  
  639. 'posts_per_page'=> -1,  
  640. 'fields' => 'ids' 
  641. ); 
  642.  
  643. if($updated_at_min) { 
  644. $args['date_query'][] = array( 
  645. 'column' => 'post_modified_gmt',  
  646. 'after' => $updated_at_min,  
  647. 'inclusive' => false 
  648. ); 
  649.  
  650. $query = new WP_Query( $args ); 
  651. return array_map( 'intval', $query->posts ); 
  652.  
  653. /** 
  654. * Delete all order items 
  655. * @param $order_id 
  656. */ 
  657. private function delete_order_items($order_id) { 
  658. global $wpdb; 
  659. $order_item_ids = $wpdb->get_col( $wpdb->prepare( " 
  660. SELECT order_item_id 
  661. FROM {$wpdb->prefix}woocommerce_order_items 
  662. WHERE order_id = %d 
  663. ", $order_id ) ); 
  664.  
  665. foreach($order_item_ids as $item_id) { 
  666. wc_delete_order_item($item_id); 
  667.  
  668. /** 
  669. * WC email notifications 
  670. * @param WC_Emails $wc_emails 
  671. */ 
  672. public function woocommerce_email(WC_Emails $wc_emails) { 
  673.  
  674. if( ! wc_pos_get_option( 'checkout', 'customer_emails' ) ) { 
  675. $this->remove_customer_emails($wc_emails); 
  676.  
  677. if( ! wc_pos_get_option( 'checkout', 'admin_emails' ) ) { 
  678. $this->remove_admin_emails($wc_emails); 
  679.  
  680. /** 
  681. * @param WC_Emails $wc_emails 
  682. */ 
  683. private function remove_customer_emails(WC_Emails $wc_emails) { 
  684. remove_action( 
  685. 'woocommerce_order_status_pending_to_processing_notification',  
  686. array( 
  687. $wc_emails->emails['WC_Email_Customer_Processing_Order'],  
  688. 'trigger' 
  689. ); 
  690. remove_action( 
  691. 'woocommerce_order_status_pending_to_on-hold_notification',  
  692. array( 
  693. $wc_emails->emails['WC_Email_Customer_Processing_Order'],  
  694. 'trigger' 
  695. ); 
  696. remove_action( 
  697. 'woocommerce_order_status_completed_notification',  
  698. array( 
  699. $wc_emails->emails['WC_Email_Customer_Completed_Order'],  
  700. 'trigger' 
  701. ); 
  702.  
  703. /** 
  704. * @param WC_Emails $wc_emails 
  705. */ 
  706. private function remove_admin_emails(WC_Emails $wc_emails) { 
  707. // send 'woocommerce_low_stock_notification' 
  708. // send 'woocommerce_no_stock_notification' 
  709. // send 'woocommerce_product_on_backorder_notification' 
  710. remove_action( 
  711. 'woocommerce_order_status_pending_to_processing_notification',  
  712. array( 
  713. $wc_emails->emails['WC_Email_New_Order'],  
  714. 'trigger' 
  715. ); 
  716. remove_action( 
  717. 'woocommerce_order_status_pending_to_completed_notification',  
  718. array( 
  719. $wc_emails->emails['WC_Email_New_Order'],  
  720. 'trigger' 
  721. ); 
  722. remove_action( 
  723. 'woocommerce_order_status_pending_to_on-hold_notification',  
  724. array( 
  725. $wc_emails->emails['WC_Email_New_Order'],  
  726. 'trigger' 
  727. ); 
  728. remove_action( 
  729. 'woocommerce_order_status_failed_to_processing_notification',  
  730. array( 
  731. $wc_emails->emails['WC_Email_New_Order'],  
  732. 'trigger' 
  733. ); 
  734. remove_action( 
  735. 'woocommerce_order_status_failed_to_completed_notification',  
  736. array( 
  737. $wc_emails->emails['WC_Email_New_Order'],  
  738. 'trigger' 
  739. ); 
  740. remove_action( 
  741. 'woocommerce_order_status_failed_to_on-hold_notification',  
  742. array( 
  743. $wc_emails->emails['WC_Email_New_Order'],  
  744. 'trigger' 
  745. ); 
  746.  
  747.  
.