WC_Abstract_Order

Abstract Order.

Defined (1)

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

/includes/abstracts/abstract-wc-order.php  
  1. abstract class WC_Abstract_Order { 
  2.  
  3. /** @public int Order (post) ID. */ 
  4. public $id = 0; 
  5.  
  6. /** @var $post WP_Post. */ 
  7. public $post = null; 
  8.  
  9. /** @public string Order type. */ 
  10. public $order_type = false; 
  11.  
  12. /** @public string Order Date. */ 
  13. public $order_date = ''; 
  14.  
  15. /** @public string Order Modified Date. */ 
  16. public $modified_date = ''; 
  17.  
  18. /** @public string Customer Message (excerpt). */ 
  19. public $customer_message = ''; 
  20.  
  21. /** @public string Customer Note */ 
  22. public $customer_note = ''; 
  23.  
  24. /** @public string Order Status. */ 
  25. public $post_status = ''; 
  26.  
  27. /** @public bool Do prices include tax? */ 
  28. public $prices_include_tax = false; 
  29.  
  30. /** @public string Display mode for taxes in cart. */ 
  31. public $tax_display_cart = ''; 
  32.  
  33. /** @public bool Do totals display ex tax? */ 
  34. public $display_totals_ex_tax = false; 
  35.  
  36. /** @public bool Do cart prices display ex tax? */ 
  37. public $display_cart_ex_tax = false; 
  38.  
  39. /** @protected string Formatted address. Accessed via get_formatted_billing_address(). */ 
  40. protected $formatted_billing_address = ''; 
  41.  
  42. /** @protected string Formatted address. Accessed via get_formatted_shipping_address(). */ 
  43. protected $formatted_shipping_address = ''; 
  44.  
  45. /** 
  46. * Get the order if ID is passed, otherwise the order is new and empty. 
  47. * This class should NOT be instantiated, but the get_order function or new WC_Order_Factory. 
  48. * should be used. It is possible, but the aforementioned are preferred and are the only. 
  49. * methods that will be maintained going forward. 
  50. * @param int|object|WC_Order $order Order to init. 
  51. */ 
  52. public function __construct( $order = 0 ) { 
  53. $this->prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false; 
  54. $this->tax_display_cart = get_option( 'woocommerce_tax_display_cart' ); 
  55. $this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false; 
  56. $this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false; 
  57. $this->init( $order ); 
  58.  
  59. /** 
  60. * Init/load the order object. Called from the constructor. 
  61. * @param int|object|WC_Order $order Order to init. 
  62. */ 
  63. protected function init( $order ) { 
  64. if ( is_numeric( $order ) ) { 
  65. $this->id = absint( $order ); 
  66. $this->post = get_post( $order ); 
  67. $this->get_order( $this->id ); 
  68. } elseif ( $order instanceof WC_Order ) { 
  69. $this->id = absint( $order->id ); 
  70. $this->post = $order->post; 
  71. $this->get_order( $this->id ); 
  72. } elseif ( isset( $order->ID ) ) { 
  73. $this->id = absint( $order->ID ); 
  74. $this->post = $order; 
  75. $this->get_order( $this->id ); 
  76.  
  77. /** 
  78. * Remove all line items (products, coupons, shipping, taxes) from the order. 
  79. * @param string $type Order item type. Default null. 
  80. */ 
  81. public function remove_order_items( $type = null ) { 
  82. global $wpdb; 
  83.  
  84. if ( ! empty( $type ) ) { 
  85. $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id AND items.order_id = %d AND items.order_item_type = %s", $this->id, $type ) ); 
  86. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->id, $type ) ); 
  87. } else { 
  88. $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id and items.order_id = %d", $this->id ) ); 
  89. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->id ) ); 
  90.  
  91. /** 
  92. * Returns a list of all payment tokens associated with the current order 
  93. * @since 2.6 
  94. * @return array An array of payment token objects 
  95. */ 
  96. public function get_payment_tokens() { 
  97. return WC_Payment_Tokens::get_order_tokens( $this->id ); 
  98.  
  99. /** 
  100. * Add a payment token to an order 
  101. * @since 2.6 
  102. * @param WC_Payment_Token $token Payment token object 
  103. * @return boolean True if the token was added, false if not 
  104. */ 
  105. public function add_payment_token( $token ) { 
  106. if ( empty( $token ) || ! ( $token instanceof WC_Payment_Token ) ) { 
  107. return false; 
  108.  
  109. $token_ids = get_post_meta( $this->id, '_payment_tokens', true ); 
  110. if ( empty ( $token_ids ) ) { 
  111. $token_ids = array(); 
  112. $token_ids[] = $token->get_id(); 
  113.  
  114. update_post_meta( $this->id, '_payment_tokens', $token_ids ); 
  115. do_action( 'woocommerce_payment_token_added_to_order', $this->id, $token->get_id(), $token, $token_ids ); 
  116. return true; 
  117.  
  118. /** 
  119. * Set the payment method for the order. 
  120. * @param WC_Payment_Gateway|string $payment_method 
  121. */ 
  122. public function set_payment_method( $payment_method = '' ) { 
  123. if ( is_object( $payment_method ) ) { 
  124. update_post_meta( $this->id, '_payment_method', $payment_method->id ); 
  125. update_post_meta( $this->id, '_payment_method_title', $payment_method->get_title() ); 
  126. } else { 
  127. update_post_meta( $this->id, '_payment_method', '' ); 
  128. update_post_meta( $this->id, '_payment_method_title', '' ); 
  129.  
  130. /** 
  131. * Set the customer address. 
  132. * @param array $address Address data. 
  133. * @param string $type billing or shipping. 
  134. */ 
  135. public function set_address( $address, $type = 'billing' ) { 
  136.  
  137. foreach ( $address as $key => $value ) { 
  138. update_post_meta( $this->id, "_{$type}_" . $key, $value ); 
  139.  
  140. /** 
  141. * Returns the requested address in raw, non-formatted way. 
  142. * @since 2.4.0 
  143. * @param string $type Billing or shipping. Anything else besides 'billing' will return shipping address. 
  144. * @return array The stored address after filter. 
  145. */ 
  146. public function get_address( $type = 'billing' ) { 
  147.  
  148. if ( 'billing' === $type ) { 
  149. $address = array( 
  150. 'first_name' => $this->billing_first_name,  
  151. 'last_name' => $this->billing_last_name,  
  152. 'company' => $this->billing_company,  
  153. 'address_1' => $this->billing_address_1,  
  154. 'address_2' => $this->billing_address_2,  
  155. 'city' => $this->billing_city,  
  156. 'state' => $this->billing_state,  
  157. 'postcode' => $this->billing_postcode,  
  158. 'country' => $this->billing_country,  
  159. 'email' => $this->billing_email,  
  160. 'phone' => $this->billing_phone,  
  161. ); 
  162. } else { 
  163. $address = array( 
  164. 'first_name' => $this->shipping_first_name,  
  165. 'last_name' => $this->shipping_last_name,  
  166. 'company' => $this->shipping_company,  
  167. 'address_1' => $this->shipping_address_1,  
  168. 'address_2' => $this->shipping_address_2,  
  169. 'city' => $this->shipping_city,  
  170. 'state' => $this->shipping_state,  
  171. 'postcode' => $this->shipping_postcode,  
  172. 'country' => $this->shipping_country,  
  173. ); 
  174.  
  175. return apply_filters( 'woocommerce_get_order_address', $address, $type, $this ); 
  176.  
  177. /** 
  178. * Add a product line item to the order. 
  179. * @since 2.2 
  180. * @param \WC_Product $product 
  181. * @param int $qty Line item quantity. 
  182. * @param array $args 
  183. * @return int|bool Item ID or false. 
  184. */ 
  185. public function add_product( $product, $qty = 1, $args = array() ) { 
  186. $args = wp_parse_args( $args, array( 
  187. 'variation' => array(),  
  188. 'totals' => array() 
  189. ) ); 
  190.  
  191. if ( ! $product ) { 
  192. return false; 
  193.  
  194. $item_id = wc_add_order_item( $this->id, array( 
  195. 'order_item_name' => $product->get_title(),  
  196. 'order_item_type' => 'line_item' 
  197. ) ); 
  198.  
  199. if ( ! $item_id ) { 
  200. return false; 
  201.  
  202. wc_add_order_item_meta( $item_id, '_qty', wc_stock_amount( $qty ) ); 
  203. wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() ); 
  204. wc_add_order_item_meta( $item_id, '_product_id', $product->id ); 
  205. wc_add_order_item_meta( $item_id, '_variation_id', isset( $product->variation_id ) ? $product->variation_id : 0 ); 
  206.  
  207. // Set line item totals, either passed in or from the product 
  208. wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( isset( $args['totals']['subtotal'] ) ? $args['totals']['subtotal'] : $product->get_price_excluding_tax( $qty ) ) ); 
  209. wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( isset( $args['totals']['total'] ) ? $args['totals']['total'] : $product->get_price_excluding_tax( $qty ) ) ); 
  210. wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) ); 
  211. wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) ); 
  212.  
  213. // Save tax data - Since 2.2 
  214. if ( isset( $args['totals']['tax_data'] ) ) { 
  215.  
  216. $tax_data = array(); 
  217. $tax_data['total'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['total'] ); 
  218. $tax_data['subtotal'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['subtotal'] ); 
  219.  
  220. wc_add_order_item_meta( $item_id, '_line_tax_data', $tax_data ); 
  221. } else { 
  222. wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) ); 
  223.  
  224. // Add variation meta 
  225. if ( ! empty( $args['variation'] ) ) { 
  226. foreach ( $args['variation'] as $key => $value ) { 
  227. wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value ); 
  228.  
  229. // Backorders 
  230. if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) { 
  231. wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $qty - max( 0, $product->get_total_stock() ) ); 
  232.  
  233. do_action( 'woocommerce_order_add_product', $this->id, $item_id, $product, $qty, $args ); 
  234.  
  235. return $item_id; 
  236.  
  237.  
  238. /** 
  239. * Update a line item for the order. 
  240. * Note this does not update order totals. 
  241. * @since 2.2 
  242. * @param int $item_id order item ID. 
  243. * @param array $args data to update. 
  244. * @param WC_Product $product 
  245. * @return bool 
  246. */ 
  247. public function update_product( $item_id, $product, $args ) { 
  248.  
  249. if ( ! $item_id || ! is_object( $product ) ) { 
  250. return false; 
  251.  
  252. // quantity 
  253. if ( isset( $args['qty'] ) ) { 
  254. wc_update_order_item_meta( $item_id, '_qty', wc_stock_amount( $args['qty'] ) ); 
  255.  
  256. // tax class 
  257. if ( isset( $args['tax_class'] ) ) { 
  258. wc_update_order_item_meta( $item_id, '_tax_class', $args['tax_class'] ); 
  259.  
  260. // set item totals, either provided or from product 
  261. if ( isset( $args['qty'] ) ) { 
  262. wc_update_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( isset( $args['totals']['subtotal'] ) ? $args['totals']['subtotal'] : $product->get_price_excluding_tax( $args['qty'] ) ) ); 
  263. wc_update_order_item_meta( $item_id, '_line_total', wc_format_decimal( isset( $args['totals']['total'] ) ? $args['totals']['total'] : $product->get_price_excluding_tax( $args['qty'] ) ) ); 
  264.  
  265. // set item tax totals 
  266. wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) ); 
  267. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) ); 
  268.  
  269. // variation meta 
  270. if ( isset( $args['variation'] ) && is_array( $args['variation'] ) ) { 
  271.  
  272. foreach ( $args['variation'] as $key => $value ) { 
  273. wc_update_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value ); 
  274.  
  275. // backorders 
  276. if ( isset( $args['qty'] ) && $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) { 
  277. wc_update_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ) ); 
  278.  
  279. do_action( 'woocommerce_order_edit_product', $this->id, $item_id, $args, $product ); 
  280.  
  281. return true; 
  282.  
  283.  
  284. /** 
  285. * Add coupon code to the order. 
  286. * @param string $code 
  287. * @param int $discount_amount 
  288. * @param int $discount_amount_tax "Discounted" tax - used for tax inclusive prices. 
  289. * @return int|bool Item ID or false. 
  290. */ 
  291. public function add_coupon( $code, $discount_amount = 0, $discount_amount_tax = 0 ) { 
  292. $item_id = wc_add_order_item( $this->id, array( 
  293. 'order_item_name' => $code,  
  294. 'order_item_type' => 'coupon' 
  295. ) ); 
  296.  
  297. if ( ! $item_id ) { 
  298. return false; 
  299.  
  300. wc_add_order_item_meta( $item_id, 'discount_amount', $discount_amount ); 
  301. wc_add_order_item_meta( $item_id, 'discount_amount_tax', $discount_amount_tax ); 
  302.  
  303. do_action( 'woocommerce_order_add_coupon', $this->id, $item_id, $code, $discount_amount, $discount_amount_tax ); 
  304.  
  305. return $item_id; 
  306.  
  307. /** 
  308. * Update coupon for order. 
  309. * Note this does not update order totals. 
  310. * @since 2.2 
  311. * @param int $item_id 
  312. * @param array $args 
  313. * @return bool 
  314. */ 
  315. public function update_coupon( $item_id, $args ) { 
  316. if ( ! $item_id ) { 
  317. return false; 
  318.  
  319. // code 
  320. if ( isset( $args['code'] ) ) { 
  321. wc_update_order_item( $item_id, array( 'order_item_name' => $args['code'] ) ); 
  322.  
  323. // amount 
  324. if ( isset( $args['discount_amount'] ) ) { 
  325. wc_update_order_item_meta( $item_id, 'discount_amount', wc_format_decimal( $args['discount_amount'] ) ); 
  326. if ( isset( $args['discount_amount_tax'] ) ) { 
  327. wc_add_order_item_meta( $item_id, 'discount_amount_tax', wc_format_decimal( $args['discount_amount_tax'] ) ); 
  328.  
  329. do_action( 'woocommerce_order_update_coupon', $this->id, $item_id, $args ); 
  330.  
  331. return true; 
  332.  
  333. /** 
  334. * Add a tax row to the order. 
  335. * @since 2.2 
  336. * @param int tax_rate_id 
  337. * @return int|bool Item ID or false. 
  338. */ 
  339. public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) { 
  340.  
  341. $code = WC_Tax::get_rate_code( $tax_rate_id ); 
  342.  
  343. if ( ! $code ) { 
  344. return false; 
  345.  
  346. $item_id = wc_add_order_item( $this->id, array( 
  347. 'order_item_name' => $code,  
  348. 'order_item_type' => 'tax' 
  349. ) ); 
  350.  
  351. if ( ! $item_id ) { 
  352. return false; 
  353.  
  354. wc_add_order_item_meta( $item_id, 'rate_id', $tax_rate_id ); 
  355. wc_add_order_item_meta( $item_id, 'label', WC_Tax::get_rate_label( $tax_rate_id ) ); 
  356. wc_add_order_item_meta( $item_id, 'compound', WC_Tax::is_compound( $tax_rate_id ) ? 1 : 0 ); 
  357. wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $tax_amount ) ); 
  358. wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $shipping_tax_amount ) ); 
  359.  
  360. do_action( 'woocommerce_order_add_tax', $this->id, $item_id, $tax_rate_id, $tax_amount, $shipping_tax_amount ); 
  361.  
  362. return $item_id; 
  363.  
  364. /** 
  365. * Add a shipping row to the order. 
  366. * @param WC_Shipping_Rate shipping_rate 
  367. * @return int|bool Item ID or false. 
  368. */ 
  369. public function add_shipping( $shipping_rate ) { 
  370.  
  371. $item_id = wc_add_order_item( $this->id, array( 
  372. 'order_item_name' => $shipping_rate->label,  
  373. 'order_item_type' => 'shipping' 
  374. ) ); 
  375.  
  376. if ( ! $item_id ) { 
  377. return false; 
  378.  
  379. wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id ); 
  380. wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) ); 
  381.  
  382. // Save shipping taxes - Since 2.2 
  383. $taxes = array_map( 'wc_format_decimal', $shipping_rate->taxes ); 
  384. wc_add_order_item_meta( $item_id, 'taxes', $taxes ); 
  385.  
  386. // Store meta 
  387. $shipping_meta = $shipping_rate->get_meta_data(); 
  388. if ( ! empty( $shipping_meta ) ) { 
  389. foreach ( $shipping_rate->get_meta_data() as $key => $value ) { 
  390. wc_add_order_item_meta( $item_id, $key, $value ); 
  391.  
  392. do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate ); 
  393.  
  394. // Update total 
  395. $this->set_total( $this->order_shipping + wc_format_decimal( $shipping_rate->cost ), 'shipping' ); 
  396.  
  397. return $item_id; 
  398.  
  399. /** 
  400. * Update shipping method for order. 
  401. * Note this does not update the order total. 
  402. * @since 2.2 
  403. * @param int $item_id 
  404. * @param array $args 
  405. * @return bool 
  406. */ 
  407. public function update_shipping( $item_id, $args ) { 
  408.  
  409. if ( ! $item_id ) { 
  410. return false; 
  411.  
  412. // method title 
  413. if ( isset( $args['method_title'] ) ) { 
  414. wc_update_order_item( $item_id, array( 'order_item_name' => $args['method_title'] ) ); 
  415.  
  416. // method ID 
  417. if ( isset( $args['method_id'] ) ) { 
  418. wc_update_order_item_meta( $item_id, 'method_id', $args['method_id'] ); 
  419.  
  420. // method cost 
  421. if ( isset( $args['cost'] ) ) { 
  422. // Get old cost before updating 
  423. $old_cost = wc_get_order_item_meta( $item_id, 'cost' ); 
  424.  
  425. // Update 
  426. wc_update_order_item_meta( $item_id, 'cost', wc_format_decimal( $args['cost'] ) ); 
  427.  
  428. // Update total 
  429. $this->set_total( $this->order_shipping - wc_format_decimal( $old_cost ) + wc_format_decimal( $args['cost'] ), 'shipping' ); 
  430.  
  431. do_action( 'woocommerce_order_update_shipping', $this->id, $item_id, $args ); 
  432.  
  433. return true; 
  434.  
  435. /** 
  436. * Add a fee to the order. 
  437. * @param object $fee 
  438. * @return int|bool Item ID or false. 
  439. */ 
  440. public function add_fee( $fee ) { 
  441.  
  442. $item_id = wc_add_order_item( $this->id, array( 
  443. 'order_item_name' => $fee->name,  
  444. 'order_item_type' => 'fee' 
  445. ) ); 
  446.  
  447. if ( ! $item_id ) { 
  448. return false; 
  449.  
  450. if ( $fee->taxable ) { 
  451. wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class ); 
  452. } else { 
  453. wc_add_order_item_meta( $item_id, '_tax_class', '0' ); 
  454.  
  455. wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) ); 
  456. wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) ); 
  457.  
  458. // Save tax data - Since 2.2 
  459. $tax_data = array_map( 'wc_format_decimal', $fee->tax_data ); 
  460. wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $tax_data ) ); 
  461.  
  462. do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee ); 
  463.  
  464. return $item_id; 
  465.  
  466. /** 
  467. * Update fee for order. 
  468. * Note this does not update order totals. 
  469. * @since 2.2 
  470. * @param int $item_id 
  471. * @param array $args 
  472. * @return bool 
  473. */ 
  474. public function update_fee( $item_id, $args ) { 
  475.  
  476. if ( ! $item_id ) { 
  477. return false; 
  478.  
  479. // name 
  480. if ( isset( $args['name'] ) ) { 
  481. wc_update_order_item( $item_id, array( 'order_item_name' => $args['name'] ) ); 
  482.  
  483. // tax class 
  484. if ( isset( $args['tax_class'] ) ) { 
  485. wc_update_order_item_meta( $item_id, '_tax_class', $args['tax_class'] ); 
  486.  
  487. // total 
  488. if ( isset( $args['line_total'] ) ) { 
  489. wc_update_order_item_meta( $item_id, '_line_total', wc_format_decimal( $args['line_total'] ) ); 
  490.  
  491. // total tax 
  492. if ( isset( $args['line_tax'] ) ) { 
  493. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $args['line_tax'] ) ); 
  494.  
  495. do_action( 'woocommerce_order_update_fee', $this->id, $item_id, $args ); 
  496.  
  497. return true; 
  498.  
  499. /** 
  500. * Set an order total. 
  501. * @param float $amount 
  502. * @param string $total_type 
  503. * @return bool 
  504. */ 
  505. public function set_total( $amount, $total_type = 'total' ) { 
  506.  
  507. if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) { 
  508. return false; 
  509.  
  510. switch ( $total_type ) { 
  511. case 'total' : 
  512. $key = '_order_total'; 
  513. $amount = wc_format_decimal( $amount, wc_get_price_decimals() ); 
  514. break; 
  515. case 'cart_discount' : 
  516. case 'cart_discount_tax' : 
  517. $key = '_' . $total_type; 
  518. $amount = wc_format_decimal( $amount ); 
  519. break; 
  520. default : 
  521. $key = '_order_' . $total_type; 
  522. $amount = wc_format_decimal( $amount ); 
  523. break; 
  524.  
  525. update_post_meta( $this->id, $key, $amount ); 
  526.  
  527. return true; 
  528.  
  529. /** 
  530. * Get all tax classes for items in the order. 
  531. * @since 2.6.3 
  532. * @return array 
  533. */ 
  534. public function get_items_tax_classes() { 
  535. $found_tax_classes = array(); 
  536.  
  537. foreach ( $this->get_items() as $item ) { 
  538. if ( $_product = $this->get_product_from_item( $item ) ) { 
  539. $found_tax_classes[] = $_product->get_tax_class(); 
  540.  
  541. return array_unique( $found_tax_classes ); 
  542.  
  543. /** 
  544. * Calculate taxes for all line items and shipping, and store the totals and tax rows. 
  545. * Will use the base country unless customer addresses are set. 
  546. * @return bool success or fail. 
  547. */ 
  548. public function calculate_taxes() { 
  549. $tax_total = 0; 
  550. $shipping_tax_total = 0; 
  551. $taxes = array(); 
  552. $shipping_taxes = array(); 
  553. $tax_based_on = get_option( 'woocommerce_tax_based_on' ); 
  554.  
  555. // If is_vat_exempt is 'yes', or wc_tax_enabled is false, return and do nothing. 
  556. if ( 'yes' === $this->is_vat_exempt || ! wc_tax_enabled() ) { 
  557. return false; 
  558.  
  559. if ( 'billing' === $tax_based_on ) { 
  560. $country = $this->billing_country; 
  561. $state = $this->billing_state; 
  562. $postcode = $this->billing_postcode; 
  563. $city = $this->billing_city; 
  564. } elseif ( 'shipping' === $tax_based_on ) { 
  565. $country = $this->shipping_country; 
  566. $state = $this->shipping_state; 
  567. $postcode = $this->shipping_postcode; 
  568. $city = $this->shipping_city; 
  569.  
  570. // Default to base 
  571. if ( 'base' === $tax_based_on || empty( $country ) ) { 
  572. $default = wc_get_base_location(); 
  573. $country = $default['country']; 
  574. $state = $default['state']; 
  575. $postcode = ''; 
  576. $city = ''; 
  577.  
  578. // Get items 
  579. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { 
  580.  
  581. $product = $this->get_product_from_item( $item ); 
  582. $line_total = isset( $item['line_total'] ) ? $item['line_total'] : 0; 
  583. $line_subtotal = isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0; 
  584. $tax_class = $item['tax_class']; 
  585. $item_tax_status = $product ? $product->get_tax_status() : 'taxable'; 
  586.  
  587. if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) { 
  588.  
  589. $tax_rates = WC_Tax::find_rates( array( 
  590. 'country' => $country,  
  591. 'state' => $state,  
  592. 'postcode' => $postcode,  
  593. 'city' => $city,  
  594. 'tax_class' => $tax_class 
  595. ) ); 
  596.  
  597. $line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false ); 
  598. $line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false ); 
  599. $line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) ); 
  600. $line_tax = max( 0, array_sum( $line_taxes ) ); 
  601. $tax_total += $line_tax; 
  602.  
  603. wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) ); 
  604. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) ); 
  605. wc_update_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $line_taxes, 'subtotal' => $line_subtotal_taxes ) ); 
  606.  
  607. // Sum the item taxes 
  608. foreach ( array_keys( $taxes + $line_taxes ) as $key ) { 
  609. $taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 ); 
  610.  
  611. // Calc taxes for shipping 
  612. foreach ( $this->get_shipping_methods() as $item_id => $item ) { 
  613. $shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' ); 
  614.  
  615. // Inherit tax class from items 
  616. if ( '' === $shipping_tax_class ) { 
  617. $tax_classes = WC_Tax::get_tax_classes(); 
  618. $found_tax_classes = $this->get_items_tax_classes(); 
  619.  
  620. foreach ( $tax_classes as $tax_class ) { 
  621. $tax_class = sanitize_title( $tax_class ); 
  622. if ( in_array( $tax_class, $found_tax_classes ) ) { 
  623. $tax_rates = WC_Tax::find_shipping_rates( array( 
  624. 'country' => $country,  
  625. 'state' => $state,  
  626. 'postcode' => $postcode,  
  627. 'city' => $city,  
  628. 'tax_class' => $tax_class,  
  629. ) ); 
  630. break; 
  631. } else { 
  632. $tax_rates = WC_Tax::find_shipping_rates( array( 
  633. 'country' => $country,  
  634. 'state' => $state,  
  635. 'postcode' => $postcode,  
  636. 'city' => $city,  
  637. 'tax_class' => 'standard' === $shipping_tax_class ? '' : $shipping_tax_class,  
  638. ) ); 
  639.  
  640. $line_taxes = WC_Tax::calc_tax( $item['cost'], $tax_rates, false ); 
  641. $line_tax = max( 0, array_sum( $line_taxes ) ); 
  642. $shipping_tax_total += $line_tax; 
  643.  
  644. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) ); 
  645. wc_update_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $line_taxes ) ); 
  646.  
  647. // Sum the item taxes 
  648. foreach ( array_keys( $shipping_taxes + $line_taxes ) as $key ) { 
  649. $shipping_taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $shipping_taxes[ $key ] ) ? $shipping_taxes[ $key ] : 0 ); 
  650.  
  651. // Save tax totals 
  652. $this->set_total( $shipping_tax_total, 'shipping_tax' ); 
  653. $this->set_total( $tax_total, 'tax' ); 
  654.  
  655. // Tax rows 
  656. $this->remove_order_items( 'tax' ); 
  657.  
  658. // Now merge to keep tax rows 
  659. foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) { 
  660. $this->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 ); 
  661.  
  662. return true; 
  663.  
  664.  
  665. /** 
  666. * Calculate shipping total. 
  667. * @since 2.2 
  668. * @return float 
  669. */ 
  670. public function calculate_shipping() { 
  671.  
  672. $shipping_total = 0; 
  673.  
  674. foreach ( $this->get_shipping_methods() as $shipping ) { 
  675. $shipping_total += $shipping['cost']; 
  676.  
  677. $this->set_total( $shipping_total, 'shipping' ); 
  678.  
  679. return $this->get_total_shipping(); 
  680.  
  681. /** 
  682. * Update tax lines at order level by looking at the line item taxes themselves. 
  683. * @return bool success or fail. 
  684. */ 
  685. public function update_taxes() { 
  686. $order_taxes = array(); 
  687. $order_shipping_taxes = array(); 
  688.  
  689. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { 
  690.  
  691. $line_tax_data = maybe_unserialize( $item['line_tax_data'] ); 
  692.  
  693. if ( isset( $line_tax_data['total'] ) ) { 
  694.  
  695. foreach ( $line_tax_data['total'] as $tax_rate_id => $tax ) { 
  696.  
  697. if ( ! isset( $order_taxes[ $tax_rate_id ] ) ) { 
  698. $order_taxes[ $tax_rate_id ] = 0; 
  699.  
  700. $order_taxes[ $tax_rate_id ] += $tax; 
  701.  
  702. foreach ( $this->get_items( array( 'shipping' ) ) as $item_id => $item ) { 
  703.  
  704. $line_tax_data = maybe_unserialize( $item['taxes'] ); 
  705.  
  706. if ( isset( $line_tax_data ) ) { 
  707. foreach ( $line_tax_data as $tax_rate_id => $tax ) { 
  708. if ( ! isset( $order_shipping_taxes[ $tax_rate_id ] ) ) { 
  709. $order_shipping_taxes[ $tax_rate_id ] = 0; 
  710.  
  711. $order_shipping_taxes[ $tax_rate_id ] += $tax; 
  712.  
  713. // Remove old existing tax rows. 
  714. $this->remove_order_items( 'tax' ); 
  715.  
  716. // Now merge to keep tax rows. 
  717. foreach ( array_keys( $order_taxes + $order_shipping_taxes ) as $tax_rate_id ) { 
  718. $this->add_tax( $tax_rate_id, isset( $order_taxes[ $tax_rate_id ] ) ? $order_taxes[ $tax_rate_id ] : 0, isset( $order_shipping_taxes[ $tax_rate_id ] ) ? $order_shipping_taxes[ $tax_rate_id ] : 0 ); 
  719.  
  720. // Save tax totals 
  721. $this->set_total( WC_Tax::round( array_sum( $order_shipping_taxes ) ), 'shipping_tax' ); 
  722. $this->set_total( WC_Tax::round( array_sum( $order_taxes ) ), 'tax' ); 
  723.  
  724. return true; 
  725.  
  726. /** 
  727. * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total. 
  728. * @since 2.2 
  729. * @param bool $and_taxes Calc taxes if true. 
  730. * @return float calculated grand total. 
  731. */ 
  732. public function calculate_totals( $and_taxes = true ) { 
  733. $cart_subtotal = 0; 
  734. $cart_total = 0; 
  735. $fee_total = 0; 
  736. $cart_subtotal_tax = 0; 
  737. $cart_total_tax = 0; 
  738.  
  739. if ( $and_taxes && wc_tax_enabled() ) { 
  740. $this->calculate_taxes(); 
  741.  
  742. // line items 
  743. foreach ( $this->get_items() as $item ) { 
  744. $cart_subtotal += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 ); 
  745. $cart_total += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 ); 
  746. $cart_subtotal_tax += wc_format_decimal( isset( $item['line_subtotal_tax'] ) ? $item['line_subtotal_tax'] : 0 ); 
  747. $cart_total_tax += wc_format_decimal( isset( $item['line_tax'] ) ? $item['line_tax'] : 0 ); 
  748.  
  749. $this->calculate_shipping(); 
  750.  
  751. foreach ( $this->get_fees() as $item ) { 
  752. $fee_total += $item['line_total']; 
  753.  
  754. $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' ); 
  755. $this->set_total( $cart_subtotal_tax - $cart_total_tax, 'cart_discount_tax' ); 
  756.  
  757. $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ); 
  758.  
  759. $this->set_total( $grand_total, 'total' ); 
  760.  
  761. return $grand_total; 
  762.  
  763. /** 
  764. * Gets an order from the database. 
  765. * @param int $id (default: 0). 
  766. * @return bool 
  767. */ 
  768. public function get_order( $id = 0 ) { 
  769.  
  770. if ( ! $id ) { 
  771. return false; 
  772.  
  773. if ( $result = get_post( $id ) ) { 
  774. $this->populate( $result ); 
  775. return true; 
  776.  
  777. return false; 
  778.  
  779. /** 
  780. * Populates an order from the loaded post data. 
  781. * @param mixed $result 
  782. */ 
  783. public function populate( $result ) { 
  784.  
  785. // Standard post data 
  786. $this->id = $result->ID; 
  787. $this->order_date = $result->post_date; 
  788. $this->modified_date = $result->post_modified; 
  789. $this->customer_message = $result->post_excerpt; 
  790. $this->customer_note = $result->post_excerpt; 
  791. $this->post_status = $result->post_status; 
  792.  
  793. // Billing email can default to user if set. 
  794. if ( empty( $this->billing_email ) && ! empty( $this->customer_user ) && ( $user = get_user_by( 'id', $this->customer_user ) ) ) { 
  795. $this->billing_email = $user->user_email; 
  796.  
  797. // Orders store the state of prices including tax when created. 
  798. $this->prices_include_tax = metadata_exists( 'post', $this->id, '_prices_include_tax' ) ? get_post_meta( $this->id, '_prices_include_tax', true ) === 'yes' : $this->prices_include_tax; 
  799.  
  800. /** 
  801. * __isset function. 
  802. * @param mixed $key 
  803. * @return bool 
  804. */ 
  805. public function __isset( $key ) { 
  806.  
  807. if ( ! $this->id ) { 
  808. return false; 
  809.  
  810. return metadata_exists( 'post', $this->id, '_' . $key ); 
  811.  
  812. /** 
  813. * __get function. 
  814. * @param mixed $key 
  815. * @return mixed 
  816. */ 
  817. public function __get( $key ) { 
  818. // Get values or default if not set. 
  819. if ( 'completed_date' === $key ) { 
  820. $value = ( $value = get_post_meta( $this->id, '_completed_date', true ) ) ? $value : $this->modified_date; 
  821. } elseif ( 'user_id' === $key ) { 
  822. $value = ( $value = get_post_meta( $this->id, '_customer_user', true ) ) ? absint( $value ) : ''; 
  823. } elseif ( 'status' === $key ) { 
  824. $value = $this->get_status(); 
  825. } else { 
  826. $value = get_post_meta( $this->id, '_' . $key, true ); 
  827.  
  828. return $value; 
  829.  
  830. /** 
  831. * Return the order statuses without wc- internal prefix. 
  832. * Queries get_post_status() directly to avoid having out of date statuses, if updated elsewhere. 
  833. * @return string 
  834. */ 
  835. public function get_status() { 
  836. $this->post_status = get_post_status( $this->id ); 
  837. return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->post_status, 0, 3 ) ? substr( $this->post_status, 3 ) : $this->post_status, $this ); 
  838.  
  839. /** 
  840. * Checks the order status against a passed in status. 
  841. * @return bool 
  842. */ 
  843. public function has_status( $status ) { 
  844. return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status ); 
  845.  
  846. /** 
  847. * Gets the user ID associated with the order. Guests are 0. 
  848. * @since 2.2 
  849. * @return int 
  850. */ 
  851. public function get_user_id() { 
  852. return $this->customer_user ? intval( $this->customer_user ) : 0; 
  853.  
  854. /** 
  855. * Get the user associated with the order. False for guests. 
  856. * @since 2.2 
  857. * @return WP_User|false 
  858. */ 
  859. public function get_user() { 
  860. return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false; 
  861.  
  862. /** 
  863. * Get transaction id for the order. 
  864. * @return string 
  865. */ 
  866. public function get_transaction_id() { 
  867. return get_post_meta( $this->id, '_transaction_id', true ); 
  868.  
  869. /** 
  870. * Check if an order key is valid. 
  871. * @param mixed $key 
  872. * @return bool 
  873. */ 
  874. public function key_is_valid( $key ) { 
  875.  
  876. if ( $key == $this->order_key ) { 
  877. return true; 
  878.  
  879. return false; 
  880.  
  881. /** 
  882. * get_order_number function. 
  883. * Gets the order number for display (by default, order ID). 
  884. * @return string 
  885. */ 
  886. public function get_order_number() { 
  887. return apply_filters( 'woocommerce_order_number', $this->id, $this ); 
  888.  
  889. /** 
  890. * Get a formatted billing address for the order. 
  891. * @return string 
  892. */ 
  893. public function get_formatted_billing_address() { 
  894. if ( ! $this->formatted_billing_address ) { 
  895.  
  896. // Formatted Addresses. 
  897. $address = apply_filters( 'woocommerce_order_formatted_billing_address', array( 
  898. 'first_name' => $this->billing_first_name,  
  899. 'last_name' => $this->billing_last_name,  
  900. 'company' => $this->billing_company,  
  901. 'address_1' => $this->billing_address_1,  
  902. 'address_2' => $this->billing_address_2,  
  903. 'city' => $this->billing_city,  
  904. 'state' => $this->billing_state,  
  905. 'postcode' => $this->billing_postcode,  
  906. 'country' => $this->billing_country 
  907. ), $this ); 
  908.  
  909. $this->formatted_billing_address = WC()->countries->get_formatted_address( $address ); 
  910.  
  911. return $this->formatted_billing_address; 
  912.  
  913. /** 
  914. * Get a formatted shipping address for the order. 
  915. * @return string 
  916. */ 
  917. public function get_formatted_shipping_address() { 
  918. if ( ! $this->formatted_shipping_address ) { 
  919.  
  920. if ( $this->shipping_address_1 || $this->shipping_address_2 ) { 
  921.  
  922. // Formatted Addresses 
  923. $address = apply_filters( 'woocommerce_order_formatted_shipping_address', array( 
  924. 'first_name' => $this->shipping_first_name,  
  925. 'last_name' => $this->shipping_last_name,  
  926. 'company' => $this->shipping_company,  
  927. 'address_1' => $this->shipping_address_1,  
  928. 'address_2' => $this->shipping_address_2,  
  929. 'city' => $this->shipping_city,  
  930. 'state' => $this->shipping_state,  
  931. 'postcode' => $this->shipping_postcode,  
  932. 'country' => $this->shipping_country 
  933. ), $this ); 
  934.  
  935. $this->formatted_shipping_address = WC()->countries->get_formatted_address( $address ); 
  936.  
  937. return $this->formatted_shipping_address; 
  938.  
  939. /** 
  940. * Get a formatted shipping address for the order. 
  941. * @return string 
  942. */ 
  943. public function get_shipping_address_map_url() { 
  944. $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', array( 
  945. 'address_1' => $this->shipping_address_1,  
  946. 'address_2' => $this->shipping_address_2,  
  947. 'city' => $this->shipping_city,  
  948. 'state' => $this->shipping_state,  
  949. 'postcode' => $this->shipping_postcode,  
  950. 'country' => $this->shipping_country 
  951. ), $this ); 
  952.  
  953. return apply_filters( 'woocommerce_shipping_address_map_url', 'https://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this ); 
  954.  
  955. /** 
  956. * Get the billing address in an array. 
  957. * @deprecated 2.3 
  958. * @return string 
  959. */ 
  960. public function get_billing_address() { 
  961. _deprecated_function( 'get_billing_address', '2.3', 'get_formatted_billing_address' ); 
  962. return $this->get_formatted_billing_address(); 
  963.  
  964. /** 
  965. * Get the shipping address in an array. 
  966. * @deprecated 2.3 
  967. * @return string 
  968. */ 
  969. public function get_shipping_address() { 
  970. _deprecated_function( 'get_shipping_address', '2.3', 'get_formatted_shipping_address' ); 
  971. return $this->get_formatted_shipping_address(); 
  972.  
  973. /** 
  974. * Get a formatted billing full name. 
  975. * @since 2.4.0 
  976. * @return string 
  977. */ 
  978. public function get_formatted_billing_full_name() { 
  979. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->billing_first_name, $this->billing_last_name ); 
  980.  
  981. /** 
  982. * Get a formatted shipping full name. 
  983. * @since 2.4.0 
  984. * @return string 
  985. */ 
  986. public function get_formatted_shipping_full_name() { 
  987. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->shipping_first_name, $this->shipping_last_name ); 
  988.  
  989. /** 
  990. * Return an array of items/products within this order. 
  991. * @param string|array $type Types of line items to get (array or string). 
  992. * @return array 
  993. */ 
  994. public function get_items( $type = '' ) { 
  995. global $wpdb; 
  996.  
  997. if ( empty( $type ) ) { 
  998. $type = array( 'line_item' ); 
  999.  
  1000. if ( ! is_array( $type ) ) { 
  1001. $type = array( $type ); 
  1002.  
  1003. $items = array(); 
  1004. $get_items_sql = $wpdb->prepare( "SELECT order_item_id, order_item_name, order_item_type FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d ", $this->id ); 
  1005. $get_items_sql .= "AND order_item_type IN ( '" . implode( "', '", array_map( 'esc_sql', $type ) ) . "' ) ORDER BY order_item_id;"; 
  1006. $line_items = $wpdb->get_results( $get_items_sql ); 
  1007.  
  1008. // Loop items 
  1009. foreach ( $line_items as $item ) { 
  1010. $items[ $item->order_item_id ]['name'] = $item->order_item_name; 
  1011. $items[ $item->order_item_id ]['type'] = $item->order_item_type; 
  1012. $items[ $item->order_item_id ]['item_meta'] = $this->get_item_meta( $item->order_item_id ); 
  1013. $items[ $item->order_item_id ]['item_meta_array'] = $this->get_item_meta_array( $item->order_item_id ); 
  1014. $items[ $item->order_item_id ] = $this->expand_item_meta( $items[ $item->order_item_id ] ); 
  1015.  
  1016. return apply_filters( 'woocommerce_order_get_items', $items, $this ); 
  1017.  
  1018. /** 
  1019. * Expand item meta into the $item array. 
  1020. * @since 2.4.0 
  1021. * @param array $item before expansion. 
  1022. * @return array 
  1023. */ 
  1024. public function expand_item_meta( $item ) { 
  1025. // Reserved meta keys 
  1026. $reserved_item_meta_keys = array( 
  1027. 'name',  
  1028. 'type',  
  1029. 'item_meta',  
  1030. 'item_meta_array',  
  1031. 'qty',  
  1032. 'tax_class',  
  1033. 'product_id',  
  1034. 'variation_id',  
  1035. 'line_subtotal',  
  1036. 'line_total',  
  1037. 'line_tax',  
  1038. 'line_subtotal_tax' 
  1039. ); 
  1040.  
  1041. // Expand item meta if set. 
  1042. if ( ! empty( $item['item_meta'] ) ) { 
  1043. foreach ( $item['item_meta'] as $name => $value ) { 
  1044. if ( in_array( $name, $reserved_item_meta_keys ) ) { 
  1045. continue; 
  1046. if ( '_' === substr( $name, 0, 1 ) ) { 
  1047. $item[ substr( $name, 1 ) ] = $value[0]; 
  1048. } elseif ( ! in_array( $name, $reserved_item_meta_keys ) ) { 
  1049. $item[ $name ] = make_clickable( $value[0] ); 
  1050. return $item; 
  1051.  
  1052. /** 
  1053. * Gets the count of order items of a certain type. 
  1054. * @param string $item_type 
  1055. * @return string 
  1056. */ 
  1057. public function get_item_count( $item_type = '' ) { 
  1058. if ( empty( $item_type ) ) { 
  1059. $item_type = array( 'line_item' ); 
  1060. if ( ! is_array( $item_type ) ) { 
  1061. $item_type = array( $item_type ); 
  1062.  
  1063. $items = $this->get_items( $item_type ); 
  1064. $count = 0; 
  1065.  
  1066. foreach ( $items as $item ) { 
  1067. $count += empty( $item['qty'] ) ? 1 : $item['qty']; 
  1068.  
  1069. return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this ); 
  1070.  
  1071. /** 
  1072. * Get refunds 
  1073. * @return array 
  1074. */ 
  1075. public function get_refunds() { return array(); } 
  1076.  
  1077. /** 
  1078. * Return an array of fees within this order. 
  1079. * @return array 
  1080. */ 
  1081. public function get_fees() { 
  1082. return $this->get_items( 'fee' ); 
  1083.  
  1084. /** 
  1085. * Return an array of taxes within this order. 
  1086. * @return array 
  1087. */ 
  1088. public function get_taxes() { 
  1089. return $this->get_items( 'tax' ); 
  1090.  
  1091. /** 
  1092. * Return an array of shipping costs within this order. 
  1093. * @return array 
  1094. */ 
  1095. public function get_shipping_methods() { 
  1096. return $this->get_items( 'shipping' ); 
  1097.  
  1098. /** 
  1099. * Check whether this order has a specific shipping method or not. 
  1100. * @param string $method_id 
  1101. * @return bool 
  1102. */ 
  1103. public function has_shipping_method( $method_id ) { 
  1104.  
  1105. $shipping_methods = $this->get_shipping_methods(); 
  1106. $has_method = false; 
  1107.  
  1108. if ( empty( $shipping_methods ) ) { 
  1109. return false; 
  1110.  
  1111. foreach ( $shipping_methods as $shipping_method ) { 
  1112. if ( $shipping_method['method_id'] == $method_id ) { 
  1113. $has_method = true; 
  1114.  
  1115. return $has_method; 
  1116.  
  1117. /** 
  1118. * Get taxes, merged by code, formatted ready for output. 
  1119. * @return array 
  1120. */ 
  1121. public function get_tax_totals() { 
  1122.  
  1123. $taxes = $this->get_items( 'tax' ); 
  1124. $tax_totals = array(); 
  1125.  
  1126. foreach ( $taxes as $key => $tax ) { 
  1127.  
  1128. $code = $tax[ 'name' ]; 
  1129.  
  1130. if ( ! isset( $tax_totals[ $code ] ) ) { 
  1131. $tax_totals[ $code ] = new stdClass(); 
  1132. $tax_totals[ $code ]->amount = 0; 
  1133.  
  1134. $tax_totals[ $code ]->id = $key; 
  1135. $tax_totals[ $code ]->rate_id = $tax['rate_id']; 
  1136. $tax_totals[ $code ]->is_compound = $tax[ 'compound' ]; 
  1137. $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ]; 
  1138. $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ]; 
  1139. $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) ); 
  1140.  
  1141. if ( apply_filters( 'woocommerce_order_hide_zero_taxes', true ) ) { 
  1142. $amounts = array_filter( wp_list_pluck( $tax_totals, 'amount' ) ); 
  1143. $tax_totals = array_intersect_key( $tax_totals, $amounts ); 
  1144.  
  1145. return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this ); 
  1146.  
  1147. /** 
  1148. * has_meta function for order items. 
  1149. * @param string $order_item_id 
  1150. * @return array of meta data. 
  1151. */ 
  1152. public function has_meta( $order_item_id ) { 
  1153. global $wpdb; 
  1154.  
  1155. return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id 
  1156. FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d 
  1157. ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A ); 
  1158.  
  1159. /** 
  1160. * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta(). 
  1161. * @param mixed $order_item_id 
  1162. * @return array of objects 
  1163. */ 
  1164. public function get_item_meta_array( $order_item_id ) { 
  1165. global $wpdb; 
  1166.  
  1167. // Get cache key - uses get_cache_prefix to invalidate when needed 
  1168. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'item_meta_array_' . $order_item_id; 
  1169. $item_meta_array = wp_cache_get( $cache_key, 'orders' ); 
  1170.  
  1171. if ( false === $item_meta_array ) { 
  1172. $item_meta_array = array(); 
  1173. $metadata = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d ORDER BY meta_id", absint( $order_item_id ) ) ); 
  1174. foreach ( $metadata as $metadata_row ) { 
  1175. $item_meta_array[ $metadata_row->meta_id ] = (object) array( 'key' => $metadata_row->meta_key, 'value' => $metadata_row->meta_value ); 
  1176. wp_cache_set( $cache_key, $item_meta_array, 'orders' ); 
  1177.  
  1178. return $item_meta_array ; 
  1179.  
  1180. /** 
  1181. * Display meta data belonging to an item. 
  1182. * @param array $item 
  1183. */ 
  1184. public function display_item_meta( $item ) { 
  1185. $product = $this->get_product_from_item( $item ); 
  1186. $item_meta = new WC_Order_Item_Meta( $item, $product ); 
  1187. $item_meta->display(); 
  1188.  
  1189. /** 
  1190. * Get order item meta. 
  1191. * @param mixed $order_item_id 
  1192. * @param string $key (default: '') 
  1193. * @param bool $single (default: false) 
  1194. * @return array|string 
  1195. */ 
  1196. public function get_item_meta( $order_item_id, $key = '', $single = false ) { 
  1197. return get_metadata( 'order_item', $order_item_id, $key, $single ); 
  1198.  
  1199. /** Total Getters *******************************************************/ 
  1200.  
  1201. /** 
  1202. * Gets the total discount amount. 
  1203. * @param bool $ex_tax Show discount excl any tax. 
  1204. * @return float 
  1205. */ 
  1206. public function get_total_discount( $ex_tax = true ) { 
  1207. if ( ! $this->order_version || version_compare( $this->order_version, '2.3.7', '<' ) ) { 
  1208. // Backwards compatible total calculation - totals were not stored consistently in old versions. 
  1209. if ( $ex_tax ) { 
  1210. if ( $this->prices_include_tax ) { 
  1211. $total_discount = (double) $this->cart_discount - (double) $this->cart_discount_tax; 
  1212. } else { 
  1213. $total_discount = (double) $this->cart_discount; 
  1214. } else { 
  1215. if ( $this->prices_include_tax ) { 
  1216. $total_discount = (double) $this->cart_discount; 
  1217. } else { 
  1218. $total_discount = (double) $this->cart_discount + (double) $this->cart_discount_tax; 
  1219. // New logic - totals are always stored exclusive of tax, tax total is stored in cart_discount_tax 
  1220. } else { 
  1221. if ( $ex_tax ) { 
  1222. $total_discount = (double) $this->cart_discount; 
  1223. } else { 
  1224. $total_discount = (double) $this->cart_discount + (double) $this->cart_discount_tax; 
  1225. return apply_filters( 'woocommerce_order_amount_total_discount', round( $total_discount, wc_get_rounding_precision() ), $this ); 
  1226.  
  1227. /** 
  1228. * Gets the discount amount. 
  1229. * @deprecated in favour of get_total_discount() since we now only have one discount type. 
  1230. * @return float 
  1231. */ 
  1232. public function get_cart_discount() { 
  1233. _deprecated_function( 'get_cart_discount', '2.3', 'get_total_discount' ); 
  1234. return apply_filters( 'woocommerce_order_amount_cart_discount', $this->get_total_discount(), $this ); 
  1235.  
  1236. /** 
  1237. * Get cart discount (formatted). 
  1238. * @deprecated order (after tax) discounts removed in 2.3.0. 
  1239. * @return string 
  1240. */ 
  1241. public function get_order_discount_to_display() { 
  1242. _deprecated_function( 'get_order_discount_to_display', '2.3' ); 
  1243.  
  1244. /** 
  1245. * Gets the total (order) discount amount - these are applied after tax. 
  1246. * @deprecated order (after tax) discounts removed in 2.3.0. 
  1247. * @return float 
  1248. */ 
  1249. public function get_order_discount() { 
  1250. _deprecated_function( 'get_order_discount', '2.3' ); 
  1251. return apply_filters( 'woocommerce_order_amount_order_discount', (double) $this->order_discount, $this ); 
  1252.  
  1253. /** 
  1254. * Gets cart tax amount. 
  1255. * @return float 
  1256. */ 
  1257. public function get_cart_tax() { 
  1258. return apply_filters( 'woocommerce_order_amount_cart_tax', (double) $this->order_tax, $this ); 
  1259.  
  1260. /** 
  1261. * Gets shipping tax amount. 
  1262. * @return float 
  1263. */ 
  1264. public function get_shipping_tax() { 
  1265. return apply_filters( 'woocommerce_order_amount_shipping_tax', (double) $this->order_shipping_tax, $this ); 
  1266.  
  1267. /** 
  1268. * Gets shipping and product tax. 
  1269. * @return float 
  1270. */ 
  1271. public function get_total_tax() { 
  1272. return apply_filters( 'woocommerce_order_amount_total_tax', wc_round_tax_total( $this->get_cart_tax() + $this->get_shipping_tax() ), $this ); 
  1273.  
  1274. /** 
  1275. * Gets shipping total. 
  1276. * @return float 
  1277. */ 
  1278. public function get_total_shipping() { 
  1279. return apply_filters( 'woocommerce_order_amount_total_shipping', (double) $this->order_shipping, $this ); 
  1280.  
  1281. /** 
  1282. * Gets order total. 
  1283. * @return float 
  1284. */ 
  1285. public function get_total() { 
  1286. return apply_filters( 'woocommerce_order_amount_total', (double) $this->order_total, $this ); 
  1287.  
  1288. /** 
  1289. * Gets order subtotal. 
  1290. * @return mixed|void 
  1291. */ 
  1292. public function get_subtotal() { 
  1293. $subtotal = 0; 
  1294.  
  1295. foreach ( $this->get_items() as $item ) { 
  1296. $subtotal += ( isset( $item['line_subtotal'] ) ) ? $item['line_subtotal'] : 0; 
  1297.  
  1298. return apply_filters( 'woocommerce_order_amount_subtotal', (double) $subtotal, $this ); 
  1299.  
  1300. /** 
  1301. * Get item subtotal - this is the cost before discount. 
  1302. * @param mixed $item 
  1303. * @param bool $inc_tax (default: false). 
  1304. * @param bool $round (default: true). 
  1305. * @return float 
  1306. */ 
  1307. public function get_item_subtotal( $item, $inc_tax = false, $round = true ) { 
  1308. if ( $inc_tax ) { 
  1309. $price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / max( 1, $item['qty'] ); 
  1310. } else { 
  1311. $price = ( $item['line_subtotal'] / max( 1, $item['qty'] ) ); 
  1312.  
  1313. $price = $round ? number_format( (float) $price, wc_get_price_decimals(), '.', '' ) : $price; 
  1314.  
  1315. return apply_filters( 'woocommerce_order_amount_item_subtotal', $price, $this, $item, $inc_tax, $round ); 
  1316.  
  1317. /** 
  1318. * Get line subtotal - this is the cost before discount. 
  1319. * @param mixed $item 
  1320. * @param bool $inc_tax (default: false). 
  1321. * @param bool $round (default: true). 
  1322. * @return float 
  1323. */ 
  1324. public function get_line_subtotal( $item, $inc_tax = false, $round = true ) { 
  1325. if ( $inc_tax ) { 
  1326. $price = $item['line_subtotal'] + $item['line_subtotal_tax']; 
  1327. } else { 
  1328. $price = $item['line_subtotal']; 
  1329.  
  1330. $price = $round ? round( $price, wc_get_price_decimals() ) : $price; 
  1331.  
  1332. return apply_filters( 'woocommerce_order_amount_line_subtotal', $price, $this, $item, $inc_tax, $round ); 
  1333.  
  1334. /** 
  1335. * Calculate item cost - useful for gateways. 
  1336. * @param mixed $item 
  1337. * @param bool $inc_tax (default: false). 
  1338. * @param bool $round (default: true). 
  1339. * @return float 
  1340. */ 
  1341. public function get_item_total( $item, $inc_tax = false, $round = true ) { 
  1342.  
  1343. $qty = ( ! empty( $item['qty'] ) ) ? $item['qty'] : 1; 
  1344.  
  1345. if ( $inc_tax ) { 
  1346. $price = ( $item['line_total'] + $item['line_tax'] ) / max( 1, $qty ); 
  1347. } else { 
  1348. $price = $item['line_total'] / max( 1, $qty ); 
  1349.  
  1350. $price = $round ? round( $price, wc_get_price_decimals() ) : $price; 
  1351.  
  1352. return apply_filters( 'woocommerce_order_amount_item_total', $price, $this, $item, $inc_tax, $round ); 
  1353.  
  1354. /** 
  1355. * Calculate line total - useful for gateways. 
  1356. * @param mixed $item 
  1357. * @param bool $inc_tax (default: false). 
  1358. * @param bool $round (default: true). 
  1359. * @return float 
  1360. */ 
  1361. public function get_line_total( $item, $inc_tax = false, $round = true ) { 
  1362.  
  1363. // Check if we need to add line tax to the line total. 
  1364. $line_total = $inc_tax ? $item['line_total'] + $item['line_tax'] : $item['line_total']; 
  1365.  
  1366. // Check if we need to round. 
  1367. $line_total = $round ? round( $line_total, wc_get_price_decimals() ) : $line_total; 
  1368.  
  1369. return apply_filters( 'woocommerce_order_amount_line_total', $line_total, $this, $item, $inc_tax, $round ); 
  1370.  
  1371. /** 
  1372. * Calculate item tax - useful for gateways. 
  1373. * @param mixed $item 
  1374. * @param bool $round (default: true). 
  1375. * @return float 
  1376. */ 
  1377. public function get_item_tax( $item, $round = true ) { 
  1378.  
  1379. $price = $item['line_tax'] / max( 1, $item['qty'] ); 
  1380. $price = $round ? wc_round_tax_total( $price ) : $price; 
  1381.  
  1382. return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this ); 
  1383.  
  1384. /** 
  1385. * Calculate line tax - useful for gateways. 
  1386. * @param mixed $item 
  1387. * @return float 
  1388. */ 
  1389. public function get_line_tax( $item ) { 
  1390. return apply_filters( 'woocommerce_order_amount_line_tax', wc_round_tax_total( $item['line_tax'] ), $item, $this ); 
  1391.  
  1392. /** End Total Getters *******************************************************/ 
  1393.  
  1394. /** 
  1395. * Gets formatted shipping method title. 
  1396. * @return string 
  1397. */ 
  1398. public function get_shipping_method() { 
  1399.  
  1400. $labels = array(); 
  1401.  
  1402. // Backwards compat < 2.1 - get shipping title stored in meta. 
  1403. if ( $this->shipping_method_title ) { 
  1404. $labels[] = $this->shipping_method_title; 
  1405. } else { 
  1406.  
  1407. // 2.1+ get line items for shipping. 
  1408. $shipping_methods = $this->get_shipping_methods(); 
  1409.  
  1410. foreach ( $shipping_methods as $shipping ) { 
  1411. $labels[] = $shipping['name'] ? $shipping['name'] : __( 'Shipping', 'woocommerce' ); 
  1412.  
  1413. return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $labels ), $this ); 
  1414.  
  1415. /** 
  1416. * Gets line subtotal - formatted for display. 
  1417. * @param array $item 
  1418. * @param string $tax_display 
  1419. * @return string 
  1420. */ 
  1421. public function get_formatted_line_subtotal( $item, $tax_display = '' ) { 
  1422.  
  1423. if ( ! $tax_display ) { 
  1424. $tax_display = $this->tax_display_cart; 
  1425.  
  1426. if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { 
  1427. return ''; 
  1428.  
  1429. if ( 'excl' == $tax_display ) { 
  1430. $ex_tax_label = $this->prices_include_tax ? 1 : 0; 
  1431.  
  1432. $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_order_currency() ) ); 
  1433. } else { 
  1434. $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array('currency' => $this->get_order_currency()) ); 
  1435.  
  1436. return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this ); 
  1437.  
  1438. /** 
  1439. * Gets order currency. 
  1440. * @return string 
  1441. */ 
  1442. public function get_order_currency() { 
  1443. return apply_filters( 'woocommerce_get_order_currency', $this->order_currency, $this ); 
  1444.  
  1445. /** 
  1446. * Gets order total - formatted for display. 
  1447. * @return string 
  1448. */ 
  1449. public function get_formatted_order_total() { 
  1450. $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_order_currency() ) ); 
  1451. return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this ); 
  1452.  
  1453. /** 
  1454. * Gets subtotal - subtotal is shown before discounts, but with localised taxes. 
  1455. * @param bool $compound (default: false). 
  1456. * @param string $tax_display (default: the tax_display_cart value). 
  1457. * @return string 
  1458. */ 
  1459. public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { 
  1460.  
  1461. if ( ! $tax_display ) { 
  1462. $tax_display = $this->tax_display_cart; 
  1463.  
  1464. $subtotal = 0; 
  1465.  
  1466. if ( ! $compound ) { 
  1467. foreach ( $this->get_items() as $item ) { 
  1468.  
  1469. if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) { 
  1470. return ''; 
  1471.  
  1472. $subtotal += $item['line_subtotal']; 
  1473.  
  1474. if ( 'incl' == $tax_display ) { 
  1475. $subtotal += $item['line_subtotal_tax']; 
  1476.  
  1477. $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); 
  1478.  
  1479. if ( $tax_display == 'excl' && $this->prices_include_tax ) { 
  1480. $subtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; 
  1481.  
  1482. } else { 
  1483.  
  1484. if ( 'incl' == $tax_display ) { 
  1485. return ''; 
  1486.  
  1487. foreach ( $this->get_items() as $item ) { 
  1488.  
  1489. $subtotal += $item['line_subtotal']; 
  1490.  
  1491.  
  1492. // Add Shipping Costs. 
  1493. $subtotal += $this->get_total_shipping(); 
  1494.  
  1495. // Remove non-compound taxes. 
  1496. foreach ( $this->get_taxes() as $tax ) { 
  1497.  
  1498. if ( ! empty( $tax['compound'] ) ) { 
  1499. continue; 
  1500.  
  1501. $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount']; 
  1502.  
  1503.  
  1504. // Remove discounts. 
  1505. $subtotal = $subtotal - $this->get_total_discount(); 
  1506.  
  1507. $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) ); 
  1508.  
  1509. return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this ); 
  1510.  
  1511.  
  1512. /** 
  1513. * Gets shipping (formatted). 
  1514. * @return string 
  1515. */ 
  1516. public function get_shipping_to_display( $tax_display = '' ) { 
  1517. if ( ! $tax_display ) { 
  1518. $tax_display = $this->tax_display_cart; 
  1519.  
  1520. if ( $this->order_shipping != 0 ) { 
  1521.  
  1522. if ( $tax_display == 'excl' ) { 
  1523.  
  1524. // Show shipping excluding tax. 
  1525. $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) ); 
  1526.  
  1527. if ( $this->order_shipping_tax != 0 && $this->prices_include_tax ) { 
  1528. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>', $this, $tax_display ); 
  1529.  
  1530. } else { 
  1531.  
  1532. // Show shipping including tax. 
  1533. $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) ); 
  1534.  
  1535. if ( $this->order_shipping_tax != 0 && ! $this->prices_include_tax ) { 
  1536. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>', $this, $tax_display ); 
  1537.  
  1538.  
  1539. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_shipped_via', ' <small class="shipped_via">' . sprintf( __( 'via %s', 'woocommerce' ), $this->get_shipping_method() ) . '</small>', $this ); 
  1540.  
  1541. } elseif ( $this->get_shipping_method() ) { 
  1542. $shipping = $this->get_shipping_method(); 
  1543. } else { 
  1544. $shipping = __( 'Free!', 'woocommerce' ); 
  1545.  
  1546. return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this ); 
  1547.  
  1548. /** 
  1549. * Get the discount amount (formatted). 
  1550. * @since 2.3.0 
  1551. * @return string 
  1552. */ 
  1553. public function get_discount_to_display( $tax_display = '' ) { 
  1554. if ( ! $tax_display ) { 
  1555. $tax_display = $this->tax_display_cart; 
  1556. return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_total_discount( $tax_display === 'excl' && $this->display_totals_ex_tax ), array( 'currency' => $this->get_order_currency() ) ), $this ); 
  1557.  
  1558. /** 
  1559. * Get cart discount (formatted). 
  1560. * @deprecated 
  1561. * @return string 
  1562. */ 
  1563. public function get_cart_discount_to_display( $tax_display = '' ) { 
  1564. _deprecated_function( 'get_cart_discount_to_display', '2.3', 'get_discount_to_display' ); 
  1565. return apply_filters( 'woocommerce_order_cart_discount_to_display', $this->get_discount_to_display( $tax_display ), $this ); 
  1566.  
  1567. /** 
  1568. * Get a product (either product or variation). 
  1569. * @param mixed $item 
  1570. * @return WC_Product 
  1571. */ 
  1572. public function get_product_from_item( $item ) { 
  1573.  
  1574. if ( ! empty( $item['variation_id'] ) && 'product_variation' === get_post_type( $item['variation_id'] ) ) { 
  1575. $_product = wc_get_product( $item['variation_id'] ); 
  1576. } elseif ( ! empty( $item['product_id'] ) ) { 
  1577. $_product = wc_get_product( $item['product_id'] ); 
  1578. } else { 
  1579. $_product = false; 
  1580.  
  1581. return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this ); 
  1582.  
  1583.  
  1584. /** 
  1585. * Get totals for display on pages and in emails. 
  1586. * @param mixed $tax_display 
  1587. * @return array 
  1588. */ 
  1589. public function get_order_item_totals( $tax_display = '' ) { 
  1590.  
  1591. if ( ! $tax_display ) { 
  1592. $tax_display = $this->tax_display_cart; 
  1593.  
  1594. $total_rows = array(); 
  1595.  
  1596. if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) { 
  1597. $total_rows['cart_subtotal'] = array( 
  1598. 'label' => __( 'Subtotal:', 'woocommerce' ),  
  1599. 'value' => $subtotal 
  1600. ); 
  1601.  
  1602. if ( $this->get_total_discount() > 0 ) { 
  1603. $total_rows['discount'] = array( 
  1604. 'label' => __( 'Discount:', 'woocommerce' ),  
  1605. 'value' => '-' . $this->get_discount_to_display( $tax_display ) 
  1606. ); 
  1607.  
  1608. if ( $this->get_shipping_method() ) { 
  1609. $total_rows['shipping'] = array( 
  1610. 'label' => __( 'Shipping:', 'woocommerce' ),  
  1611. 'value' => $this->get_shipping_to_display( $tax_display ) 
  1612. ); 
  1613.  
  1614. if ( $fees = $this->get_fees() ) { 
  1615. foreach ( $fees as $id => $fee ) { 
  1616.  
  1617. if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', $fee['line_total'] + $fee['line_tax'] == 0, $id ) ) { 
  1618. continue; 
  1619.  
  1620. if ( 'excl' == $tax_display ) { 
  1621.  
  1622. $total_rows[ 'fee_' . $id ] = array( 
  1623. 'label' => ( $fee['name'] ? $fee['name'] : __( 'Fee', 'woocommerce' ) ) . ':',  
  1624. 'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) ) 
  1625. ); 
  1626.  
  1627. } else { 
  1628.  
  1629. $total_rows[ 'fee_' . $id ] = array( 
  1630. 'label' => $fee['name'] . ':',  
  1631. 'value' => wc_price( $fee['line_total'] + $fee['line_tax'], array('currency' => $this->get_order_currency()) ) 
  1632. ); 
  1633.  
  1634. // Tax for tax exclusive prices. 
  1635. if ( 'excl' === $tax_display ) { 
  1636.  
  1637. if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) { 
  1638.  
  1639. foreach ( $this->get_tax_totals() as $code => $tax ) { 
  1640.  
  1641. $total_rows[ sanitize_title( $code ) ] = array( 
  1642. 'label' => $tax->label . ':',  
  1643. 'value' => $tax->formatted_amount 
  1644. ); 
  1645.  
  1646. } else { 
  1647.  
  1648. $total_rows['tax'] = array( 
  1649. 'label' => WC()->countries->tax_or_vat() . ':',  
  1650. 'value' => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_order_currency() ) ) 
  1651. ); 
  1652.  
  1653. if ( $this->get_total() > 0 && $this->payment_method_title ) { 
  1654. $total_rows['payment_method'] = array( 
  1655. 'label' => __( 'Payment Method:', 'woocommerce' ),  
  1656. 'value' => $this->payment_method_title 
  1657. ); 
  1658.  
  1659. if ( $refunds = $this->get_refunds() ) { 
  1660. foreach ( $refunds as $id => $refund ) { 
  1661. $total_rows[ 'refund_' . $id ] = array( 
  1662. 'label' => $refund->get_refund_reason() ? $refund->get_refund_reason() : __( 'Refund', 'woocommerce' ) . ':',  
  1663. 'value' => wc_price( '-' . $refund->get_refund_amount(), array( 'currency' => $this->get_order_currency() ) ) 
  1664. ); 
  1665.  
  1666. $total_rows['order_total'] = array( 
  1667. 'label' => __( 'Total:', 'woocommerce' ),  
  1668. 'value' => $this->get_formatted_order_total( $tax_display ) 
  1669. ); 
  1670.  
  1671. return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this ); 
  1672.  
  1673.  
  1674. /** 
  1675. * Output items for display in html emails. 
  1676. * @param array $args Items args. 
  1677. * @param null $deprecated1 Deprecated arg. 
  1678. * @param null $deprecated2 Deprecated arg. 
  1679. * @param null $deprecated3 Deprecated arg. 
  1680. * @param null $deprecated4 Deprecated arg. 
  1681. * @param null $deprecated5 Deprecated arg. 
  1682. * @return string 
  1683. */ 
  1684. public function email_order_items_table( $args = array(), $deprecated1 = null, $deprecated2 = null, $deprecated3 = null, $deprecated4 = null, $deprecated5 = null ) { 
  1685. ob_start(); 
  1686.  
  1687. if ( ! is_null( $deprecated1 ) || ! is_null( $deprecated2 ) || ! is_null( $deprecated3 ) || ! is_null( $deprecated4 ) || ! is_null( $deprecated5 ) ) { 
  1688. _deprecated_argument( __FUNCTION__, '2.5.0' ); 
  1689.  
  1690. $defaults = array( 
  1691. 'show_sku' => false,  
  1692. 'show_image' => false,  
  1693. 'image_size' => array( 32, 32 ),  
  1694. 'plain_text' => false,  
  1695. 'sent_to_admin' => false 
  1696. ); 
  1697.  
  1698. $args = wp_parse_args( $args, $defaults ); 
  1699. $template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; 
  1700.  
  1701. wc_get_template( $template, apply_filters( 'woocommerce_email_order_items_args', array( 
  1702. 'order' => $this,  
  1703. 'items' => $this->get_items(),  
  1704. 'show_download_links' => $this->is_download_permitted() && ! $args['sent_to_admin'],  
  1705. 'show_sku' => $args['show_sku'],  
  1706. 'show_purchase_note' => $this->is_paid() && ! $args['sent_to_admin'],  
  1707. 'show_image' => $args['show_image'],  
  1708. 'image_size' => $args['image_size'],  
  1709. 'plain_text' => $args['plain_text'],  
  1710. 'sent_to_admin' => $args['sent_to_admin'] 
  1711. ) ) ); 
  1712.  
  1713. return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $this ); 
  1714.  
  1715. /** 
  1716. * Returns if an order has been paid for based on the order status. 
  1717. * @since 2.5.0 
  1718. * @return bool 
  1719. */ 
  1720. public function is_paid() { 
  1721. return apply_filters( 'woocommerce_order_is_paid', $this->has_status( apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) ) ), $this ); 
  1722.  
  1723. /** 
  1724. * Checks if product download is permitted. 
  1725. * @return bool 
  1726. */ 
  1727. public function is_download_permitted() { 
  1728. return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'yes' && $this->has_status( 'processing' ) ), $this ); 
  1729.  
  1730. /** 
  1731. * Returns true if the order contains a downloadable product. 
  1732. * @return bool 
  1733. */ 
  1734. public function has_downloadable_item() { 
  1735. foreach ( $this->get_items() as $item ) { 
  1736. $_product = $this->get_product_from_item( $item ); 
  1737.  
  1738. if ( $_product && $_product->exists() && $_product->is_downloadable() && $_product->has_file() ) { 
  1739. return true; 
  1740. return false; 
  1741.  
  1742. /** 
  1743. * Returns true if the order contains a free product. 
  1744. * @since 2.5.0 
  1745. * @return bool 
  1746. */ 
  1747. public function has_free_item() { 
  1748. foreach ( $this->get_items() as $item ) { 
  1749. if ( ! $item['line_total'] ) { 
  1750. return true; 
  1751. return false; 
  1752.  
  1753. /** 
  1754. * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices. 
  1755. * @param bool $on_checkout 
  1756. * @return string 
  1757. */ 
  1758. public function get_checkout_payment_url( $on_checkout = false ) { 
  1759.  
  1760. $pay_url = wc_get_endpoint_url( 'order-pay', $this->id, wc_get_page_permalink( 'checkout' ) ); 
  1761.  
  1762. if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { 
  1763. $pay_url = str_replace( 'http:', 'https:', $pay_url ); 
  1764.  
  1765. if ( $on_checkout ) { 
  1766. $pay_url = add_query_arg( 'key', $this->order_key, $pay_url ); 
  1767. } else { 
  1768. $pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->order_key ), $pay_url ); 
  1769.  
  1770. return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this ); 
  1771.  
  1772. /** 
  1773. * Generates a URL for the thanks page (order received). 
  1774. * @return string 
  1775. */ 
  1776. public function get_checkout_order_received_url() { 
  1777.  
  1778. $order_received_url = wc_get_endpoint_url( 'order-received', $this->id, wc_get_page_permalink( 'checkout' ) ); 
  1779.  
  1780. if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { 
  1781. $order_received_url = str_replace( 'http:', 'https:', $order_received_url ); 
  1782.  
  1783. $order_received_url = add_query_arg( 'key', $this->order_key, $order_received_url ); 
  1784.  
  1785. return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this ); 
  1786.  
  1787. /** 
  1788. * Generates a URL so that a customer can cancel their (unpaid - pending) order. 
  1789. * @param string $redirect 
  1790. * @return string 
  1791. */ 
  1792. public function get_cancel_order_url( $redirect = '' ) { 
  1793.  
  1794. // Get cancel endpoint 
  1795. $cancel_endpoint = $this->get_cancel_endpoint(); 
  1796.  
  1797. return apply_filters( 'woocommerce_get_cancel_order_url', esc_url( add_query_arg( array( 
  1798. 'cancel_order' => 'true',  
  1799. 'order' => $this->order_key,  
  1800. 'order_id' => $this->id,  
  1801. 'redirect' => $redirect,  
  1802. ), $cancel_endpoint ) ) ); 
  1803.  
  1804. /** 
  1805. * Generates a raw (unescaped) cancel-order URL for use by payment gateways. 
  1806. * @param string $redirect 
  1807. * @return string The unescaped cancel-order URL. 
  1808. */ 
  1809. public function get_cancel_order_url_raw( $redirect = '' ) { 
  1810.  
  1811. // Get cancel endpoint 
  1812. $cancel_endpoint = $this->get_cancel_endpoint(); 
  1813.  
  1814. return apply_filters( 'woocommerce_get_cancel_order_url_raw', add_query_arg( array( 
  1815. 'cancel_order' => 'true',  
  1816. 'order' => $this->order_key,  
  1817. 'order_id' => $this->id,  
  1818. 'redirect' => $redirect,  
  1819. ), $cancel_endpoint ) ); 
  1820.  
  1821.  
  1822. /** 
  1823. * Helper method to return the cancel endpoint. 
  1824. * @return string the cancel endpoint; either the cart page or the home page. 
  1825. */ 
  1826. public function get_cancel_endpoint() { 
  1827.  
  1828. $cancel_endpoint = wc_get_page_permalink( 'cart' ); 
  1829. if ( ! $cancel_endpoint ) { 
  1830. $cancel_endpoint = home_url(); 
  1831.  
  1832. if ( false === strpos( $cancel_endpoint, '?' ) ) { 
  1833. $cancel_endpoint = trailingslashit( $cancel_endpoint ); 
  1834.  
  1835. return $cancel_endpoint; 
  1836.  
  1837.  
  1838. /** 
  1839. * Generates a URL to view an order from the my account page. 
  1840. * @return string 
  1841. */ 
  1842. public function get_view_order_url() { 
  1843.  
  1844. $view_order_url = wc_get_endpoint_url( 'view-order', $this->id, wc_get_page_permalink( 'myaccount' ) ); 
  1845.  
  1846. return apply_filters( 'woocommerce_get_view_order_url', $view_order_url, $this ); 
  1847.  
  1848. /** 
  1849. * Get the downloadable files for an item in this order. 
  1850. * @param array $item 
  1851. * @return array 
  1852. */ 
  1853. public function get_item_downloads( $item ) { 
  1854. global $wpdb; 
  1855.  
  1856. $product_id = $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id']; 
  1857. $product = wc_get_product( $product_id ); 
  1858. if ( ! $product ) { 
  1859. /** 
  1860. * $product can be `false`. Example: checking an old order, when a product or variation has been deleted. 
  1861. * @see \WC_Product_Factory::get_product 
  1862. */ 
  1863. return array(); 
  1864. $download_ids = $wpdb->get_col( $wpdb->prepare(" 
  1865. SELECT download_id 
  1866. FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions 
  1867. WHERE user_email = %s 
  1868. AND order_key = %s 
  1869. AND product_id = %s 
  1870. ORDER BY permission_id 
  1871. ", $this->billing_email, $this->order_key, $product_id ) ); 
  1872.  
  1873. $files = array(); 
  1874.  
  1875. foreach ( $download_ids as $download_id ) { 
  1876.  
  1877. if ( $product->has_file( $download_id ) ) { 
  1878. $files[ $download_id ] = $product->get_file( $download_id ); 
  1879. $files[ $download_id ]['download_url'] = $this->get_download_url( $product_id, $download_id ); 
  1880.  
  1881. return apply_filters( 'woocommerce_get_item_downloads', $files, $item, $this ); 
  1882.  
  1883. /** 
  1884. * Display download links for an order item. 
  1885. * @param array $item 
  1886. */ 
  1887. public function display_item_downloads( $item ) { 
  1888. $product = $this->get_product_from_item( $item ); 
  1889.  
  1890. if ( $product && $product->exists() && $product->is_downloadable() && $this->is_download_permitted() ) { 
  1891. $download_files = $this->get_item_downloads( $item ); 
  1892. $i = 0; 
  1893. $links = array(); 
  1894.  
  1895. foreach ( $download_files as $download_id => $file ) { 
  1896. $i++; 
  1897. $prefix = count( $download_files ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' ); 
  1898. $links[] = '<small class="download-url">' . $prefix . ': <a href="' . esc_url( $file['download_url'] ) . '" target="_blank">' . esc_html( $file['name'] ) . '</a></small>' . "\n"; 
  1899.  
  1900. echo '<br/>' . implode( '<br/>', $links ); 
  1901.  
  1902. /** 
  1903. * Get the Download URL. 
  1904. * @param int $product_id 
  1905. * @param int $download_id 
  1906. * @return string 
  1907. */ 
  1908. public function get_download_url( $product_id, $download_id ) { 
  1909. return add_query_arg( array( 
  1910. 'download_file' => $product_id,  
  1911. 'order' => $this->order_key,  
  1912. 'email' => urlencode( $this->billing_email ),  
  1913. 'key' => $download_id 
  1914. ), trailingslashit( home_url() ) ); 
  1915.  
  1916. /** 
  1917. * Adds a note (comment) to the order. 
  1918. * @param string $note Note to add. 
  1919. * @param int $is_customer_note (default: 0) Is this a note for the customer? 
  1920. * @param bool added_by_user Was the note added by a user? 
  1921. * @return int Comment ID. 
  1922. */ 
  1923. public function add_order_note( $note, $is_customer_note = 0, $added_by_user = false ) { 
  1924. if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->id ) && $added_by_user ) { 
  1925. $user = get_user_by( 'id', get_current_user_id() ); 
  1926. $comment_author = $user->display_name; 
  1927. $comment_author_email = $user->user_email; 
  1928. } else { 
  1929. $comment_author = __( 'WooCommerce', 'woocommerce' ); 
  1930. $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@'; 
  1931. $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com'; 
  1932. $comment_author_email = sanitize_email( $comment_author_email ); 
  1933.  
  1934. $comment_post_ID = $this->id; 
  1935. $comment_author_url = ''; 
  1936. $comment_content = $note; 
  1937. $comment_agent = 'WooCommerce'; 
  1938. $comment_type = 'order_note'; 
  1939. $comment_parent = 0; 
  1940. $comment_approved = 1; 
  1941. $commentdata = apply_filters( 'woocommerce_new_order_note_data', compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_agent', 'comment_type', 'comment_parent', 'comment_approved' ), array( 'order_id' => $this->id, 'is_customer_note' => $is_customer_note ) ); 
  1942.  
  1943. $comment_id = wp_insert_comment( $commentdata ); 
  1944.  
  1945. if ( $is_customer_note ) { 
  1946. add_comment_meta( $comment_id, 'is_customer_note', 1 ); 
  1947.  
  1948. do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->id, 'customer_note' => $commentdata['comment_content'] ) ); 
  1949.  
  1950. return $comment_id; 
  1951.  
  1952. /** 
  1953. * Updates status of order. 
  1954. * @param string $new_status Status to change the order to. No internal wc- prefix is required. 
  1955. * @param string $note (default: '') Optional note to add. 
  1956. * @param bool $manual is this a manual order status change? 
  1957. * @return bool Successful change or not 
  1958. */ 
  1959. public function update_status( $new_status, $note = '', $manual = false ) { 
  1960. if ( ! $this->id ) { 
  1961. return false; 
  1962.  
  1963. // Standardise status names. 
  1964. $new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status; 
  1965. $old_status = $this->get_status(); 
  1966.  
  1967. // If the old status is unknown (e.g. draft) assume its pending for action usage. 
  1968. if ( ! in_array( 'wc-' . $old_status, array_keys( wc_get_order_statuses() ) ) ) { 
  1969. $old_status = 'pending'; 
  1970.  
  1971. // If the statuses are the same there is no need to update, unless the post status is not a valid 'wc' status. 
  1972. if ( $new_status === $old_status && in_array( $this->post_status, array_keys( wc_get_order_statuses() ) ) ) { 
  1973. return false; 
  1974.  
  1975. $this->post_status = 'wc-' . $new_status; 
  1976. $update_post_data = array( 
  1977. 'ID' => $this->id,  
  1978. 'post_status' => $this->post_status,  
  1979. ); 
  1980.  
  1981. if ( 'pending' === $old_status && ! $manual ) { 
  1982. $update_post_data[ 'post_date' ] = current_time( 'mysql', 0 ); 
  1983. $update_post_data[ 'post_date_gmt' ] = current_time( 'mysql', 1 ); 
  1984.  
  1985. if ( ! wp_update_post( $update_post_data ) ) { 
  1986. $this->add_order_note( sprintf( __( 'Unable to update order from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $old_status ), wc_get_order_status_name( $new_status ) ), 0, $manual ); 
  1987. return false; 
  1988.  
  1989. // Status was set. 
  1990. do_action( 'woocommerce_order_status_' . $new_status, $this->id ); 
  1991.  
  1992. // Status was changed. 
  1993. if ( $new_status !== $old_status ) { 
  1994. $this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $old_status ), wc_get_order_status_name( $new_status ) ) ), 0, $manual ); 
  1995. do_action( 'woocommerce_order_status_' . $old_status . '_to_' . $new_status, $this->id ); 
  1996. do_action( 'woocommerce_order_status_changed', $this->id, $old_status, $new_status ); 
  1997. } else { 
  1998. $this->add_order_note( trim( $note . ' ' . sprintf( __( 'Order status changed to %s.', 'woocommerce' ), wc_get_order_status_name( $new_status ) ) ), 0, $manual ); 
  1999.  
  2000. switch ( $new_status ) { 
  2001.  
  2002. case 'completed' : 
  2003. // Record the sales. 
  2004. $this->record_product_sales(); 
  2005.  
  2006. // Increase coupon usage counts. 
  2007. $this->increase_coupon_usage_counts(); 
  2008.  
  2009. // Record the completed date of the order. 
  2010. update_post_meta( $this->id, '_completed_date', current_time('mysql') ); 
  2011.  
  2012. // Update reports. 
  2013. wc_delete_shop_order_transients( $this->id ); 
  2014. break; 
  2015.  
  2016. case 'processing' : 
  2017. case 'on-hold' : 
  2018. // Record the sales. 
  2019. $this->record_product_sales(); 
  2020.  
  2021. // Increase coupon usage counts. 
  2022. $this->increase_coupon_usage_counts(); 
  2023.  
  2024. // Update reports. 
  2025. wc_delete_shop_order_transients( $this->id ); 
  2026. break; 
  2027.  
  2028. case 'cancelled' : 
  2029. // If the order is cancelled, restore used coupons. 
  2030. $this->decrease_coupon_usage_counts(); 
  2031.  
  2032. // Update reports. 
  2033. wc_delete_shop_order_transients( $this->id ); 
  2034. break; 
  2035.  
  2036. return true; 
  2037.  
  2038.  
  2039. /** 
  2040. * Cancel the order and restore the cart (before payment). 
  2041. * @param string $note (default: '') Optional note to add. 
  2042. */ 
  2043. public function cancel_order( $note = '' ) { 
  2044. WC()->session->set( 'order_awaiting_payment', false ); 
  2045. $this->update_status( 'cancelled', $note ); 
  2046.  
  2047. /** 
  2048. * When a payment is complete this function is called. 
  2049. * Most of the time this should mark an order as 'processing' so that admin can process/post the items. 
  2050. * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action. 
  2051. * Stock levels are reduced at this point. 
  2052. * Sales are also recorded for products. 
  2053. * Finally, record the date of payment. 
  2054. * @param string $transaction_id Optional transaction id to store in post meta. 
  2055. */ 
  2056. public function payment_complete( $transaction_id = '' ) { 
  2057. do_action( 'woocommerce_pre_payment_complete', $this->id ); 
  2058.  
  2059. if ( null !== WC()->session ) { 
  2060. WC()->session->set( 'order_awaiting_payment', false ); 
  2061.  
  2062. $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed', 'cancelled' ), $this ); 
  2063.  
  2064. if ( $this->id && $this->has_status( $valid_order_statuses ) ) { 
  2065. $order_needs_processing = false; 
  2066.  
  2067. if ( sizeof( $this->get_items() ) > 0 ) { 
  2068. foreach ( $this->get_items() as $item ) { 
  2069. if ( $_product = $this->get_product_from_item( $item ) ) { 
  2070. $virtual_downloadable_item = $_product->is_downloadable() && $_product->is_virtual(); 
  2071.  
  2072. if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $_product, $this->id ) ) { 
  2073. $order_needs_processing = true; 
  2074. break; 
  2075. } else { 
  2076. $order_needs_processing = true; 
  2077. break; 
  2078.  
  2079. $this->update_status( apply_filters( 'woocommerce_payment_complete_order_status', $order_needs_processing ? 'processing' : 'completed', $this->id ) ); 
  2080.  
  2081. add_post_meta( $this->id, '_paid_date', current_time( 'mysql' ), true ); 
  2082.  
  2083. if ( ! empty( $transaction_id ) ) { 
  2084. update_post_meta( $this->id, '_transaction_id', $transaction_id ); 
  2085.  
  2086. // Payment is complete so reduce stock levels 
  2087. if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! get_post_meta( $this->id, '_order_stock_reduced', true ), $this->id ) ) { 
  2088. $this->reduce_order_stock(); 
  2089.  
  2090. do_action( 'woocommerce_payment_complete', $this->id ); 
  2091. } else { 
  2092. do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->id ); 
  2093.  
  2094.  
  2095. /** 
  2096. * Record sales. 
  2097. */ 
  2098. public function record_product_sales() { 
  2099. if ( 'yes' === get_post_meta( $this->id, '_recorded_sales', true ) ) { 
  2100. return; 
  2101.  
  2102. if ( sizeof( $this->get_items() ) > 0 ) { 
  2103.  
  2104. foreach ( $this->get_items() as $item ) { 
  2105.  
  2106. if ( $item['product_id'] > 0 ) { 
  2107. $sales = (int) get_post_meta( $item['product_id'], 'total_sales', true ); 
  2108. $sales += (int) $item['qty']; 
  2109.  
  2110. if ( $sales ) { 
  2111. update_post_meta( $item['product_id'], 'total_sales', $sales ); 
  2112.  
  2113. update_post_meta( $this->id, '_recorded_sales', 'yes' ); 
  2114.  
  2115. /** 
  2116. * Called when sales for an order are recorded 
  2117. * @param int $order_id order id 
  2118. */ 
  2119. do_action( 'woocommerce_recorded_sales', $this->id ); 
  2120.  
  2121.  
  2122. /** 
  2123. * Get coupon codes only. 
  2124. * @return array 
  2125. */ 
  2126. public function get_used_coupons() { 
  2127.  
  2128. $codes = array(); 
  2129. $coupons = $this->get_items( 'coupon' ); 
  2130.  
  2131. foreach ( $coupons as $item_id => $item ) { 
  2132. $codes[] = trim( $item['name'] ); 
  2133.  
  2134. return $codes; 
  2135.  
  2136.  
  2137. /** 
  2138. * Increase applied coupon counts. 
  2139. */ 
  2140. public function increase_coupon_usage_counts() { 
  2141. if ( 'yes' == get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { 
  2142. return; 
  2143.  
  2144. if ( sizeof( $this->get_used_coupons() ) > 0 ) { 
  2145.  
  2146. foreach ( $this->get_used_coupons() as $code ) { 
  2147. if ( ! $code ) { 
  2148. continue; 
  2149.  
  2150. $coupon = new WC_Coupon( $code ); 
  2151.  
  2152. $used_by = $this->get_user_id(); 
  2153.  
  2154. if ( ! $used_by ) { 
  2155. $used_by = $this->billing_email; 
  2156.  
  2157. $coupon->inc_usage_count( $used_by ); 
  2158.  
  2159. update_post_meta( $this->id, '_recorded_coupon_usage_counts', 'yes' ); 
  2160.  
  2161.  
  2162. /** 
  2163. * Decrease applied coupon counts. 
  2164. */ 
  2165. public function decrease_coupon_usage_counts() { 
  2166.  
  2167. if ( 'yes' != get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) { 
  2168. return; 
  2169.  
  2170. if ( sizeof( $this->get_used_coupons() ) > 0 ) { 
  2171.  
  2172. foreach ( $this->get_used_coupons() as $code ) { 
  2173.  
  2174. if ( ! $code ) { 
  2175. continue; 
  2176.  
  2177. $coupon = new WC_Coupon( $code ); 
  2178.  
  2179. $used_by = $this->get_user_id(); 
  2180. if ( ! $used_by ) { 
  2181. $used_by = $this->billing_email; 
  2182.  
  2183. $coupon->dcr_usage_count( $used_by ); 
  2184.  
  2185. delete_post_meta( $this->id, '_recorded_coupon_usage_counts' ); 
  2186.  
  2187. /** 
  2188. * Reduce stock levels for all line items in the order. 
  2189. * Runs if stock management is enabled, but can be disabled on per-order basis by extensions @since 2.4.0 via woocommerce_can_reduce_order_stock hook. 
  2190. */ 
  2191. public function reduce_order_stock() { 
  2192. if ( 'yes' === get_option( 'woocommerce_manage_stock' ) && apply_filters( 'woocommerce_can_reduce_order_stock', true, $this ) && sizeof( $this->get_items() ) > 0 ) { 
  2193. foreach ( $this->get_items() as $item ) { 
  2194. if ( $item['product_id'] > 0 ) { 
  2195. $_product = $this->get_product_from_item( $item ); 
  2196.  
  2197. if ( $_product && $_product->exists() && $_product->managing_stock() ) { 
  2198. $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item ); 
  2199. $new_stock = $_product->reduce_stock( $qty ); 
  2200. $item_name = $_product->get_sku() ? $_product->get_sku(): $item['product_id']; 
  2201.  
  2202. if ( isset( $item['variation_id'] ) && $item['variation_id'] ) { 
  2203. $this->add_order_note( sprintf( __( 'Item %1$s variation #%2$s stock reduced from %3$s to %4$s.', 'woocommerce' ), $item_name, $item['variation_id'], $new_stock + $qty, $new_stock) ); 
  2204. } else { 
  2205. $this->add_order_note( sprintf( __( 'Item %1$s stock reduced from %2$s to %3$s.', 'woocommerce' ), $item_name, $new_stock + $qty, $new_stock) ); 
  2206. $this->send_stock_notifications( $_product, $new_stock, $item['qty'] ); 
  2207.  
  2208. add_post_meta( $this->id, '_order_stock_reduced', '1', true ); 
  2209.  
  2210. do_action( 'woocommerce_reduce_order_stock', $this ); 
  2211.  
  2212. /** 
  2213. * Send the stock notifications. 
  2214. * @param WC_Product $product 
  2215. * @param int $new_stock 
  2216. * @param int $qty_ordered 
  2217. */ 
  2218. public function send_stock_notifications( $product, $new_stock, $qty_ordered ) { 
  2219.  
  2220. // Backorders 
  2221. if ( $new_stock < 0 ) { 
  2222. do_action( 'woocommerce_product_on_backorder', array( 'product' => $product, 'order_id' => $this->id, 'quantity' => $qty_ordered ) ); 
  2223.  
  2224. // stock status notifications 
  2225. $notification_sent = false; 
  2226.  
  2227. if ( 'yes' == get_option( 'woocommerce_notify_no_stock' ) && get_option( 'woocommerce_notify_no_stock_amount' ) >= $new_stock ) { 
  2228. do_action( 'woocommerce_no_stock', $product ); 
  2229. $notification_sent = true; 
  2230.  
  2231. if ( ! $notification_sent && 'yes' == get_option( 'woocommerce_notify_low_stock' ) && get_option( 'woocommerce_notify_low_stock_amount' ) >= $new_stock ) { 
  2232. do_action( 'woocommerce_low_stock', $product ); 
  2233.  
  2234. do_action( 'woocommerce_after_send_stock_notifications', $product, $new_stock, $qty_ordered ); 
  2235.  
  2236.  
  2237. /** 
  2238. * List order notes (public) for the customer. 
  2239. * @return array 
  2240. */ 
  2241. public function get_customer_order_notes() { 
  2242. $notes = array(); 
  2243. $args = array( 
  2244. 'post_id' => $this->id,  
  2245. 'approve' => 'approve',  
  2246. 'type' => '' 
  2247. ); 
  2248.  
  2249. remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); 
  2250.  
  2251. $comments = get_comments( $args ); 
  2252.  
  2253. foreach ( $comments as $comment ) { 
  2254. if ( ! get_comment_meta( $comment->comment_ID, 'is_customer_note', true ) ) { 
  2255. continue; 
  2256. $comment->comment_content = make_clickable( $comment->comment_content ); 
  2257. $notes[] = $comment; 
  2258.  
  2259. add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); 
  2260.  
  2261. return $notes; 
  2262.  
  2263. /** 
  2264. * Checks if an order needs payment, based on status and order total. 
  2265. * @return bool 
  2266. */ 
  2267. public function needs_payment() { 
  2268.  
  2269. $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ); 
  2270.  
  2271. if ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ) { 
  2272. $needs_payment = true; 
  2273. } else { 
  2274. $needs_payment = false; 
  2275.  
  2276. return apply_filters( 'woocommerce_order_needs_payment', $needs_payment, $this, $valid_order_statuses ); 
  2277.  
  2278. /** 
  2279. * Checks if an order needs display the shipping address, based on shipping method. 
  2280. * @return boolean 
  2281. */ 
  2282. public function needs_shipping_address() { 
  2283. if ( ! wc_shipping_enabled() ) { 
  2284. return false; 
  2285.  
  2286. $hide = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this ); 
  2287. $needs_address = false; 
  2288.  
  2289. foreach ( $this->get_shipping_methods() as $shipping_method ) { 
  2290. if ( ! in_array( $shipping_method['method_id'], $hide ) ) { 
  2291. $needs_address = true; 
  2292. break; 
  2293.  
  2294. return apply_filters( 'woocommerce_order_needs_shipping_address', $needs_address, $hide, $this ); 
  2295.  
  2296. /** 
  2297. * Checks if an order can be edited, specifically for use on the Edit Order screen. 
  2298. * @return bool 
  2299. */ 
  2300. public function is_editable() { 
  2301. return apply_filters( 'wc_order_is_editable', in_array( $this->get_status(), array( 'pending', 'on-hold', 'auto-draft', 'failed' ) ), $this );