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 extends WC_Abstract_Legacy_Order { 
  2.  
  3. /** 
  4. * Order Data array. This is the core order data exposed in APIs since 3.0.0. 
  5. * Notes: cart_tax = cart_tax is the new name for the legacy 'order_tax' 
  6. * which is the tax for items only, not shipping. 
  7. * @since 3.0.0 
  8. * @var array 
  9. */ 
  10. protected $data = array( 
  11. 'parent_id' => 0,  
  12. 'status' => '',  
  13. 'currency' => '',  
  14. 'version' => '',  
  15. 'prices_include_tax' => false,  
  16. 'date_created' => null,  
  17. 'date_modified' => null,  
  18. 'discount_total' => 0,  
  19. 'discount_tax' => 0,  
  20. 'shipping_total' => 0,  
  21. 'shipping_tax' => 0,  
  22. 'cart_tax' => 0,  
  23. 'total' => 0,  
  24. 'total_tax' => 0,  
  25. ); 
  26.  
  27. /** 
  28. * Order items will be stored here, sometimes before they persist in the DB. 
  29. * @since 3.0.0 
  30. * @var array 
  31. */ 
  32. protected $items = array(); 
  33.  
  34. /** 
  35. * Order items that need deleting are stored here. 
  36. * @since 3.0.0 
  37. * @var array 
  38. */ 
  39. protected $items_to_delete = array(); 
  40.  
  41. /** 
  42. * Stores meta in cache for future reads. 
  43. * A group must be set to to enable caching. 
  44. * @var string 
  45. */ 
  46. protected $cache_group = 'orders'; 
  47.  
  48. /** 
  49. * Which data store to load. 
  50. * @var string 
  51. */ 
  52. protected $data_store_name = 'order'; 
  53.  
  54. /** 
  55. * This is the name of this object type. 
  56. * @var string 
  57. */ 
  58. protected $object_type = 'order'; 
  59.  
  60. /** 
  61. * Get the order if ID is passed, otherwise the order is new and empty. 
  62. * This class should NOT be instantiated, but the get_order function or new WC_Order_Factory. 
  63. * should be used. It is possible, but the aforementioned are preferred and are the only. 
  64. * methods that will be maintained going forward. 
  65. * @param int|object|WC_Order $order Order to read. 
  66. */ 
  67. public function __construct( $order = 0 ) { 
  68. parent::__construct( $order ); 
  69.  
  70. if ( is_numeric( $order ) && $order > 0 ) { 
  71. $this->set_id( $order ); 
  72. } elseif ( $order instanceof self ) { 
  73. $this->set_id( $order->get_id() ); 
  74. } elseif ( ! empty( $order->ID ) ) { 
  75. $this->set_id( $order->ID ); 
  76. } else { 
  77. $this->set_object_read( true ); 
  78.  
  79. $this->data_store = WC_Data_Store::load( $this->data_store_name ); 
  80.  
  81. if ( $this->get_id() > 0 ) { 
  82. $this->data_store->read( $this ); 
  83.  
  84. /** 
  85. * Get internal type. 
  86. * @return string 
  87. */ 
  88. public function get_type() { 
  89. return 'shop_order'; 
  90.  
  91. /** 
  92. * Get all class data in array format. 
  93. * @since 3.0.0 
  94. * @return array 
  95. */ 
  96. public function get_data() { 
  97. return array_merge( 
  98. array( 
  99. 'id' => $this->get_id(),  
  100. ),  
  101. $this->data,  
  102. array( 
  103. 'meta_data' => $this->get_meta_data(),  
  104. 'line_items' => $this->get_items( 'line_item' ),  
  105. 'tax_lines' => $this->get_items( 'tax' ),  
  106. 'shipping_lines' => $this->get_items( 'shipping' ),  
  107. 'fee_lines' => $this->get_items( 'fee' ),  
  108. 'coupon_lines' => $this->get_items( 'coupon' ),  
  109. ); 
  110.  
  111. /** 
  112. |-------------------------------------------------------------------------- 
  113. | CRUD methods 
  114. |-------------------------------------------------------------------------- 
  115. | Methods which create, read, update and delete orders from the database. 
  116. | Written in abstract fashion so that the way orders are stored can be 
  117. | changed more easily in the future. 
  118. | A save method is included for convenience (chooses update or create based 
  119. | on if the order exists yet). 
  120. */ 
  121.  
  122. /** 
  123. * Save data to the database. 
  124. * @since 3.0.0 
  125. * @return int order ID 
  126. */ 
  127. public function save() { 
  128. if ( $this->data_store ) { 
  129. // Trigger action before saving to the DB. Allows you to adjust object props before save. 
  130. do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); 
  131.  
  132. if ( $this->get_id() ) { 
  133. $this->data_store->update( $this ); 
  134. } else { 
  135. $this->data_store->create( $this ); 
  136. $this->save_items(); 
  137. return $this->get_id(); 
  138.  
  139. /** 
  140. * Save all order items which are part of this order. 
  141. */ 
  142. protected function save_items() { 
  143. foreach ( $this->items_to_delete as $item ) { 
  144. $item->delete(); 
  145. $this->items_to_delete = array(); 
  146.  
  147. // Add/save items. 
  148. foreach ( $this->items as $item_group => $items ) { 
  149. if ( is_array( $items ) ) { 
  150. foreach ( array_filter( $items ) as $item_key => $item ) { 
  151. $item->set_order_id( $this->get_id() ); 
  152. $item_id = $item->save(); 
  153.  
  154. // If ID changed (new item saved to DB)... 
  155. if ( $item_id !== $item_key ) { 
  156. $this->items[ $item_group ][ $item_id ] = $item; 
  157.  
  158. unset( $this->items[ $item_group ][ $item_key ] ); 
  159.  
  160. /** 
  161. |-------------------------------------------------------------------------- 
  162. | Getters 
  163. |-------------------------------------------------------------------------- 
  164. */ 
  165.  
  166. /** 
  167. * Get parent order ID. 
  168. * @since 3.0.0 
  169. * @param string $context 
  170. * @return integer 
  171. */ 
  172. public function get_parent_id( $context = 'view' ) { 
  173. return $this->get_prop( 'parent_id', $context ); 
  174.  
  175. /** 
  176. * Gets order currency. 
  177. * @param string $context 
  178. * @return string 
  179. */ 
  180. public function get_currency( $context = 'view' ) { 
  181. return $this->get_prop( 'currency', $context ); 
  182.  
  183. /** 
  184. * Get order_version. 
  185. * @param string $context 
  186. * @return string 
  187. */ 
  188. public function get_version( $context = 'view' ) { 
  189. return $this->get_prop( 'version', $context ); 
  190.  
  191. /** 
  192. * Get prices_include_tax. 
  193. * @param string $context 
  194. * @return bool 
  195. */ 
  196. public function get_prices_include_tax( $context = 'view' ) { 
  197. return $this->get_prop( 'prices_include_tax', $context ); 
  198.  
  199. /** 
  200. * Get date_created. 
  201. * @param string $context 
  202. * @return WC_DateTime|NULL object if the date is set or null if there is no date. 
  203. */ 
  204. public function get_date_created( $context = 'view' ) { 
  205. return $this->get_prop( 'date_created', $context ); 
  206.  
  207. /** 
  208. * Get date_modified. 
  209. * @param string $context 
  210. * @return WC_DateTime|NULL object if the date is set or null if there is no date. 
  211. */ 
  212. public function get_date_modified( $context = 'view' ) { 
  213. return $this->get_prop( 'date_modified', $context ); 
  214.  
  215. /** 
  216. * Return the order statuses without wc- internal prefix. 
  217. * @param string $context 
  218. * @return string 
  219. */ 
  220. public function get_status( $context = 'view' ) { 
  221. $status = $this->get_prop( 'status', $context ); 
  222.  
  223. if ( empty( $status ) && 'view' === $context ) { 
  224. // In view context, return the default status if no status has been set. 
  225. $status = apply_filters( 'woocommerce_default_order_status', 'pending' ); 
  226. return $status; 
  227.  
  228. /** 
  229. * Get discount_total. 
  230. * @param string $context 
  231. * @return string 
  232. */ 
  233. public function get_discount_total( $context = 'view' ) { 
  234. return $this->get_prop( 'discount_total', $context ); 
  235.  
  236. /** 
  237. * Get discount_tax. 
  238. * @param string $context 
  239. * @return string 
  240. */ 
  241. public function get_discount_tax( $context = 'view' ) { 
  242. return $this->get_prop( 'discount_tax', $context ); 
  243.  
  244. /** 
  245. * Get shipping_total. 
  246. * @param string $context 
  247. * @return string 
  248. */ 
  249. public function get_shipping_total( $context = 'view' ) { 
  250. return $this->get_prop( 'shipping_total', $context ); 
  251.  
  252. /** 
  253. * Get shipping_tax. 
  254. * @param string $context 
  255. * @return string 
  256. */ 
  257. public function get_shipping_tax( $context = 'view' ) { 
  258. return $this->get_prop( 'shipping_tax', $context ); 
  259.  
  260. /** 
  261. * Gets cart tax amount. 
  262. * @param string $context 
  263. * @return float 
  264. */ 
  265. public function get_cart_tax( $context = 'view' ) { 
  266. return $this->get_prop( 'cart_tax', $context ); 
  267.  
  268. /** 
  269. * Gets order grand total. incl. taxes. Used in gateways. 
  270. * @param string $context 
  271. * @return float 
  272. */ 
  273. public function get_total( $context = 'view' ) { 
  274. return $this->get_prop( 'total', $context ); 
  275.  
  276. /** 
  277. * Get total tax amount. Alias for get_order_tax(). 
  278. * @param string $context 
  279. * @return float 
  280. */ 
  281. public function get_total_tax( $context = 'view' ) { 
  282. return $this->get_prop( 'total_tax', $context ); 
  283.  
  284. /** 
  285. |-------------------------------------------------------------------------- 
  286. | Non-CRUD Getters 
  287. |-------------------------------------------------------------------------- 
  288. */ 
  289.  
  290. /** 
  291. * Gets the total discount amount. 
  292. * @param bool $ex_tax Show discount excl any tax. 
  293. * @return float 
  294. */ 
  295. public function get_total_discount( $ex_tax = true ) { 
  296. if ( $ex_tax ) { 
  297. $total_discount = $this->get_discount_total(); 
  298. } else { 
  299. $total_discount = $this->get_discount_total() + $this->get_discount_tax(); 
  300. return apply_filters( 'woocommerce_order_get_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this ); 
  301.  
  302. /** 
  303. * Gets order subtotal. 
  304. * @return float 
  305. */ 
  306. public function get_subtotal() { 
  307. $subtotal = 0; 
  308.  
  309. foreach ( $this->get_items() as $item ) { 
  310. $subtotal += $item->get_subtotal(); 
  311.  
  312. return apply_filters( 'woocommerce_order_get_subtotal', (double) $subtotal, $this ); 
  313.  
  314. /** 
  315. * Get taxes, merged by code, formatted ready for output. 
  316. * @return array 
  317. */ 
  318. public function get_tax_totals() { 
  319. $tax_totals = array(); 
  320.  
  321. foreach ( $this->get_items( 'tax' ) as $key => $tax ) { 
  322. $code = $tax->get_rate_code(); 
  323.  
  324. if ( ! isset( $tax_totals[ $code ] ) ) { 
  325. $tax_totals[ $code ] = new stdClass(); 
  326. $tax_totals[ $code ]->amount = 0; 
  327.  
  328. $tax_totals[ $code ]->id = $key; 
  329. $tax_totals[ $code ]->rate_id = $tax->get_rate_id(); 
  330. $tax_totals[ $code ]->is_compound = $tax->is_compound(); 
  331. $tax_totals[ $code ]->label = $tax->get_label(); 
  332. $tax_totals[ $code ]->amount += (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total(); 
  333. $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array( 'currency' => $this->get_currency() ) ); 
  334.  
  335. if ( apply_filters( 'woocommerce_order_hide_zero_taxes', true ) ) { 
  336. $amounts = array_filter( wp_list_pluck( $tax_totals, 'amount' ) ); 
  337. $tax_totals = array_intersect_key( $tax_totals, $amounts ); 
  338.  
  339. return apply_filters( 'woocommerce_order_get_tax_totals', $tax_totals, $this ); 
  340.  
  341. /** 
  342. * Get all valid statuses for this order 
  343. * @since 3.0.0 
  344. * @return array Internal status keys e.g. 'wc-processing' 
  345. */ 
  346. protected function get_valid_statuses() { 
  347. return array_keys( wc_get_order_statuses() ); 
  348.  
  349. /** 
  350. * Get user ID. Used by orders, not other order types like refunds. 
  351. * @param string $context 
  352. * @return int 
  353. */ 
  354. public function get_user_id( $context = 'view' ) { 
  355. return 0; 
  356.  
  357. /** 
  358. * Get user. Used by orders, not other order types like refunds. 
  359. * @return WP_User|false 
  360. */ 
  361. public function get_user() { 
  362. return false; 
  363.  
  364. /** 
  365. |-------------------------------------------------------------------------- 
  366. | Setters 
  367. |-------------------------------------------------------------------------- 
  368. | Functions for setting order data. These should not update anything in the 
  369. | database itself and should only change what is stored in the class 
  370. | object. However, for backwards compatibility pre 3.0.0 some of these 
  371. | setters may handle both. 
  372. */ 
  373.  
  374. /** 
  375. * Set parent order ID. 
  376. * @since 3.0.0 
  377. * @param int $value 
  378. * @throws WC_Data_Exception 
  379. */ 
  380. public function set_parent_id( $value ) { 
  381. if ( $value && ( $value === $this->get_id() || ! wc_get_order( $value ) ) ) { 
  382. $this->error( 'order_invalid_parent_id', __( 'Invalid parent ID', 'woocommerce' ) ); 
  383. $this->set_prop( 'parent_id', absint( $value ) ); 
  384.  
  385. /** 
  386. * Set order status. 
  387. * @since 3.0.0 
  388. * @param string $new_status Status to change the order to. No internal wc- prefix is required. 
  389. * @return array details of change 
  390. */ 
  391. public function set_status( $new_status ) { 
  392. $old_status = $this->get_status(); 
  393. $new_status = 'wc-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status; 
  394.  
  395. // If setting the status, ensure it's set to a valid status. 
  396. if ( true === $this->object_read ) { 
  397. // Only allow valid new status 
  398. if ( ! in_array( 'wc-' . $new_status, $this->get_valid_statuses() ) && 'trash' !== $new_status ) { 
  399. $new_status = 'pending'; 
  400.  
  401. // If the old status is set but unknown (e.g. draft) assume its pending for action usage. 
  402. if ( $old_status && ! in_array( 'wc-' . $old_status, $this->get_valid_statuses() ) && 'trash' !== $old_status ) { 
  403. $old_status = 'pending'; 
  404.  
  405. $this->set_prop( 'status', $new_status ); 
  406.  
  407. return array( 
  408. 'from' => $old_status,  
  409. 'to' => $new_status,  
  410. ); 
  411.  
  412. /** 
  413. * Set order_version. 
  414. * @param string $value 
  415. * @throws WC_Data_Exception 
  416. */ 
  417. public function set_version( $value ) { 
  418. $this->set_prop( 'version', $value ); 
  419.  
  420. /** 
  421. * Set order_currency. 
  422. * @param string $value 
  423. * @throws WC_Data_Exception 
  424. */ 
  425. public function set_currency( $value ) { 
  426. if ( $value && ! in_array( $value, array_keys( get_woocommerce_currencies() ) ) ) { 
  427. $this->error( 'order_invalid_currency', __( 'Invalid currency code', 'woocommerce' ) ); 
  428. $this->set_prop( 'currency', $value ? $value : get_woocommerce_currency() ); 
  429.  
  430. /** 
  431. * Set prices_include_tax. 
  432. * @param bool $value 
  433. * @throws WC_Data_Exception 
  434. */ 
  435. public function set_prices_include_tax( $value ) { 
  436. $this->set_prop( 'prices_include_tax', (bool) $value ); 
  437.  
  438. /** 
  439. * Set date_created. 
  440. * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. 
  441. * @throws WC_Data_Exception 
  442. */ 
  443. public function set_date_created( $date = null ) { 
  444. $this->set_date_prop( 'date_created', $date ); 
  445.  
  446. /** 
  447. * Set date_modified. 
  448. * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date. 
  449. * @throws WC_Data_Exception 
  450. */ 
  451. public function set_date_modified( $date = null ) { 
  452. $this->set_date_prop( 'date_modified', $date ); 
  453.  
  454. /** 
  455. * Set discount_total. 
  456. * @param string $value 
  457. * @throws WC_Data_Exception 
  458. */ 
  459. public function set_discount_total( $value ) { 
  460. $this->set_prop( 'discount_total', wc_format_decimal( $value ) ); 
  461.  
  462. /** 
  463. * Set discount_tax. 
  464. * @param string $value 
  465. * @throws WC_Data_Exception 
  466. */ 
  467. public function set_discount_tax( $value ) { 
  468. $this->set_prop( 'discount_tax', wc_format_decimal( $value ) ); 
  469.  
  470. /** 
  471. * Set shipping_total. 
  472. * @param string $value 
  473. * @throws WC_Data_Exception 
  474. */ 
  475. public function set_shipping_total( $value ) { 
  476. $this->set_prop( 'shipping_total', wc_format_decimal( $value ) ); 
  477.  
  478. /** 
  479. * Set shipping_tax. 
  480. * @param string $value 
  481. * @throws WC_Data_Exception 
  482. */ 
  483. public function set_shipping_tax( $value ) { 
  484. $this->set_prop( 'shipping_tax', wc_format_decimal( $value ) ); 
  485. $this->set_total_tax( (float) $this->get_cart_tax() + (float) $this->get_shipping_tax() ); 
  486.  
  487. /** 
  488. * Set cart tax. 
  489. * @param string $value 
  490. * @throws WC_Data_Exception 
  491. */ 
  492. public function set_cart_tax( $value ) { 
  493. $this->set_prop( 'cart_tax', wc_format_decimal( $value ) ); 
  494. $this->set_total_tax( (float) $this->get_cart_tax() + (float) $this->get_shipping_tax() ); 
  495.  
  496. /** 
  497. * Sets order tax (sum of cart and shipping tax). Used internaly only. 
  498. * @param string $value 
  499. * @throws WC_Data_Exception 
  500. */ 
  501. protected function set_total_tax( $value ) { 
  502. $this->set_prop( 'total_tax', wc_format_decimal( $value ) ); 
  503.  
  504. /** 
  505. * Set total. 
  506. * @param string $value 
  507. * @param string $deprecated Function used to set different totals based on this. 
  508. * @throws WC_Data_Exception 
  509. */ 
  510. public function set_total( $value, $deprecated = '' ) { 
  511. if ( $deprecated ) { 
  512. wc_deprecated_argument( 'total_type', '3.0', 'Use dedicated total setter methods instead.' ); 
  513. return $this->legacy_set_total( $value, $deprecated ); 
  514. $this->set_prop( 'total', wc_format_decimal( $value, wc_get_price_decimals() ) ); 
  515.  
  516. /** 
  517. |-------------------------------------------------------------------------- 
  518. | Order Item Handling 
  519. |-------------------------------------------------------------------------- 
  520. | Order items are used for products, taxes, shipping, and fees within 
  521. | each order. 
  522. */ 
  523.  
  524. /** 
  525. * Remove all line items (products, coupons, shipping, taxes) from the order. 
  526. * @param string $type Order item type. Default null. 
  527. */ 
  528. public function remove_order_items( $type = null ) { 
  529. if ( ! empty( $type ) ) { 
  530. $this->data_store->delete_items( $this, $type ); 
  531.  
  532. if ( $group = $this->type_to_group( $type ) ) { 
  533. unset( $this->items[ $group ] ); 
  534. } else { 
  535. $this->data_store->delete_items( $this ); 
  536. $this->items = array(); 
  537.  
  538. /** 
  539. * Convert a type to a types group. 
  540. * @param string $type 
  541. * @return string group 
  542. */ 
  543. protected function type_to_group( $type ) { 
  544. $type_to_group = apply_filters( 'woocommerce_order_type_to_group', array( 
  545. 'line_item' => 'line_items',  
  546. 'tax' => 'tax_lines',  
  547. 'shipping' => 'shipping_lines',  
  548. 'fee' => 'fee_lines',  
  549. 'coupon' => 'coupon_lines',  
  550. ) ); 
  551. return isset( $type_to_group[ $type ] ) ? $type_to_group[ $type ] : ''; 
  552.  
  553. /** 
  554. * Return an array of items/products within this order. 
  555. * @param string|array $types Types of line items to get (array or string). 
  556. * @return Array of WC_Order_item 
  557. */ 
  558. public function get_items( $types = 'line_item' ) { 
  559. $items = array(); 
  560. $types = array_filter( (array) $types ); 
  561.  
  562. foreach ( $types as $type ) { 
  563. if ( $group = $this->type_to_group( $type ) ) { 
  564. if ( ! isset( $this->items[ $group ] ) ) { 
  565. $this->items[ $group ] = $this->data_store->read_items( $this, $type ); 
  566. // Don't use array_merge here because keys are numeric 
  567. $items = array_filter( $items + $this->items[ $group ] ); 
  568.  
  569. return apply_filters( 'woocommerce_order_get_items', $items, $this ); 
  570.  
  571. /** 
  572. * Return an array of fees within this order. 
  573. * @return array 
  574. */ 
  575. public function get_fees() { 
  576. return $this->get_items( 'fee' ); 
  577.  
  578. /** 
  579. * Return an array of taxes within this order. 
  580. * @return array 
  581. */ 
  582. public function get_taxes() { 
  583. return $this->get_items( 'tax' ); 
  584.  
  585. /** 
  586. * Return an array of shipping costs within this order. 
  587. * @return array 
  588. */ 
  589. public function get_shipping_methods() { 
  590. return $this->get_items( 'shipping' ); 
  591.  
  592. /** 
  593. * Gets formatted shipping method title. 
  594. * @return string 
  595. */ 
  596. public function get_shipping_method() { 
  597. $names = array(); 
  598. foreach ( $this->get_shipping_methods() as $shipping_method ) { 
  599. $names[] = $shipping_method->get_name(); 
  600. return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $names ), $this ); 
  601.  
  602. /** 
  603. * Get coupon codes only. 
  604. * @return array 
  605. */ 
  606. public function get_used_coupons() { 
  607. $coupon_codes = array(); 
  608. if ( $coupons = $this->get_items( 'coupon' ) ) { 
  609. foreach ( $coupons as $coupon ) { 
  610. $coupon_codes[] = $coupon->get_code(); 
  611. return $coupon_codes; 
  612.  
  613. /** 
  614. * Gets the count of order items of a certain type. 
  615. * @param string $item_type 
  616. * @return string 
  617. */ 
  618. public function get_item_count( $item_type = '' ) { 
  619. $items = $this->get_items( empty( $item_type ) ? 'line_item' : $item_type ); 
  620. $count = 0; 
  621.  
  622. foreach ( $items as $item ) { 
  623. $count += $item->get_quantity(); 
  624.  
  625. return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this ); 
  626.  
  627. /** 
  628. * Get an order item object, based on it's type. 
  629. * @since 3.0.0 
  630. * @param int $item_id 
  631. * @return WC_Order_Item 
  632. */ 
  633. public function get_item( $item_id ) { 
  634. return WC_Order_Factory::get_order_item( $item_id ); 
  635.  
  636. /** 
  637. * Get key for where a certain item type is stored in _items. 
  638. * @since 3.0.0 
  639. * @param $item object Order item (product, shipping, fee, coupon, tax) 
  640. * @return string 
  641. */ 
  642. protected function get_items_key( $item ) { 
  643. if ( is_a( $item, 'WC_Order_Item_Product' ) ) { 
  644. return 'line_items'; 
  645. } elseif ( is_a( $item, 'WC_Order_Item_Fee' ) ) { 
  646. return 'fee_lines'; 
  647. } elseif ( is_a( $item, 'WC_Order_Item_Shipping' ) ) { 
  648. return 'shipping_lines'; 
  649. } elseif ( is_a( $item, 'WC_Order_Item_Tax' ) ) { 
  650. return 'tax_lines'; 
  651. } elseif ( is_a( $item, 'WC_Order_Item_Coupon' ) ) { 
  652. return 'coupon_lines'; 
  653. } else { 
  654. return ''; 
  655.  
  656. /** 
  657. * Remove item from the order. 
  658. * @param int $item_id 
  659. */ 
  660. public function remove_item( $item_id ) { 
  661. $item = $this->get_item( $item_id ); 
  662.  
  663. if ( ! $item || ! ( $items_key = $this->get_items_key( $item ) ) ) { 
  664. return false; 
  665.  
  666. // Unset and remove later 
  667. $this->items_to_delete[] = $item; 
  668. unset( $this->items[ $items_key ][ $item->get_id() ] ); 
  669.  
  670. /** 
  671. * Adds an order item to this order. The order item will not persist until save. 
  672. * @since 3.0.0 
  673. * @param WC_Order_Item Order item object (product, shipping, fee, coupon, tax) 
  674. */ 
  675. public function add_item( $item ) { 
  676. if ( ! $items_key = $this->get_items_key( $item ) ) { 
  677. return false; 
  678.  
  679. // Make sure existing items are loaded so we can append this new one. 
  680. if ( ! isset( $this->items[ $items_key ] ) ) { 
  681. $this->items[ $items_key ] = $this->get_items( $item->get_type() ); 
  682.  
  683. // Set parent. 
  684. $item->set_order_id( $this->get_id() ); 
  685.  
  686. // Append new row with generated temporary ID 
  687. if ( $item_id = $item->get_id() ) { 
  688. $this->items[ $items_key ][ $item_id ] = $item; 
  689. } else { 
  690. $this->items[ $items_key ][ 'new:' . $items_key . sizeof( $this->items[ $items_key ] ) ] = $item; 
  691.  
  692. /** 
  693. * Add a product line item to the order. This is the only line item type with 
  694. * it's own method because it saves looking up order amounts (costs are added up for you). 
  695. * @param \WC_Product $product 
  696. * @param int $qty 
  697. * @param array $args 
  698. * @return int order item ID 
  699. * @throws WC_Data_Exception 
  700. */ 
  701. public function add_product( $product, $qty = 1, $args = array() ) { 
  702. if ( $product ) { 
  703. $default_args = array( 
  704. 'name' => $product->get_name(),  
  705. 'tax_class' => $product->get_tax_class(),  
  706. 'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(),  
  707. 'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0,  
  708. 'variation' => $product->is_type( 'variation' ) ? $product->get_attributes() : array(),  
  709. 'subtotal' => wc_get_price_excluding_tax( $product, array( 'qty' => $qty ) ),  
  710. 'total' => wc_get_price_excluding_tax( $product, array( 'qty' => $qty ) ),  
  711. 'quantity' => $qty,  
  712. ); 
  713. } else { 
  714. $default_args = array( 
  715. 'quantity' => $qty,  
  716. ); 
  717.  
  718. $args = wp_parse_args( $args, $default_args ); 
  719.  
  720. // BW compatibility with old args 
  721. if ( isset( $args['totals'] ) ) { 
  722. foreach ( $args['totals'] as $key => $value ) { 
  723. if ( 'tax' === $key ) { 
  724. $args['total_tax'] = $value; 
  725. } elseif ( 'tax_data' === $key ) { 
  726. $args['taxes'] = $value; 
  727. } else { 
  728. $args[ $key ] = $value; 
  729.  
  730. $item = new WC_Order_Item_Product(); 
  731. $item->set_props( $args ); 
  732. $item->set_backorder_meta(); 
  733. $item->set_order_id( $this->get_id() ); 
  734. $item->save(); 
  735. $this->add_item( $item ); 
  736. wc_do_deprecated_action( 'woocommerce_order_add_product', array( $this->get_id(), $item->get_id(), $product, $qty, $args ), '3.0', 'woocommerce_new_order_item action instead' ); 
  737. return $item->get_id(); 
  738.  
  739. /** 
  740. |-------------------------------------------------------------------------- 
  741. | Payment Token Handling 
  742. |-------------------------------------------------------------------------- 
  743. | Payment tokens are hashes used to take payments by certain gateways. 
  744. */ 
  745.  
  746. /** 
  747. * Add a payment token to an order 
  748. * @since 2.6 
  749. * @param WC_Payment_Token $token Payment token object 
  750. * @return boolean|int The new token ID or false if it failed. 
  751. */ 
  752. public function add_payment_token( $token ) { 
  753. if ( empty( $token ) || ! ( $token instanceof WC_Payment_Token ) ) { 
  754. return false; 
  755.  
  756. $token_ids = $this->data_store->get_payment_token_ids( $this ); 
  757. $token_ids[] = $token->get_id(); 
  758. $this->data_store->update_payment_token_ids( $this, $token_ids ); 
  759.  
  760. do_action( 'woocommerce_payment_token_added_to_order', $this->get_id(), $token->get_id(), $token, $token_ids ); 
  761. return $token->get_id(); 
  762.  
  763. /** 
  764. * Returns a list of all payment tokens associated with the current order 
  765. * @since 2.6 
  766. * @return array An array of payment token objects 
  767. */ 
  768. public function get_payment_tokens() { 
  769. return $this->data_store->get_payment_token_ids( $this ); 
  770.  
  771. /** 
  772. |-------------------------------------------------------------------------- 
  773. | Calculations. 
  774. |-------------------------------------------------------------------------- 
  775. | These methods calculate order totals and taxes based on the current data. 
  776. */ 
  777.  
  778. /** 
  779. * Calculate shipping total. 
  780. * @since 2.2 
  781. * @return float 
  782. */ 
  783. public function calculate_shipping() { 
  784. $shipping_total = 0; 
  785.  
  786. foreach ( $this->get_shipping_methods() as $shipping ) { 
  787. $shipping_total += $shipping->get_total(); 
  788.  
  789. $this->set_shipping_total( $shipping_total ); 
  790. $this->save(); 
  791.  
  792. return $this->get_shipping_total(); 
  793.  
  794. /** 
  795. * Get all tax classes for items in the order. 
  796. * @since 2.6.3 
  797. * @return array 
  798. */ 
  799. public function get_items_tax_classes() { 
  800. $found_tax_classes = array(); 
  801.  
  802. foreach ( $this->get_items() as $item ) { 
  803. if ( $_product = $item->get_product() ) { 
  804. $found_tax_classes[] = $_product->get_tax_class(); 
  805.  
  806. return array_unique( $found_tax_classes ); 
  807.  
  808. /** 
  809. * Calculate taxes for all line items and shipping, and store the totals and tax rows. 
  810. * Will use the base country unless customer addresses are set. 
  811. * @param $args array Added in 3.0.0 to pass things like location. 
  812. */ 
  813. public function calculate_taxes( $args = array() ) { 
  814. $tax_based_on = get_option( 'woocommerce_tax_based_on' ); 
  815. $args = wp_parse_args( $args, array( 
  816. 'country' => 'billing' === $tax_based_on ? $this->get_billing_country() : $this->get_shipping_country(),  
  817. 'state' => 'billing' === $tax_based_on ? $this->get_billing_state() : $this->get_shipping_state(),  
  818. 'postcode' => 'billing' === $tax_based_on ? $this->get_billing_postcode() : $this->get_shipping_postcode(),  
  819. 'city' => 'billing' === $tax_based_on ? $this->get_billing_city() : $this->get_shipping_city(),  
  820. ) ); 
  821.  
  822. // Default to base 
  823. if ( 'base' === $tax_based_on || empty( $args['country'] ) ) { 
  824. $default = wc_get_base_location(); 
  825. $args['country'] = $default['country']; 
  826. $args['state'] = $default['state']; 
  827. $args['postcode'] = ''; 
  828. $args['city'] = ''; 
  829.  
  830. // Calc taxes for line items 
  831. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { 
  832. $tax_class = $item->get_tax_class(); 
  833. $tax_status = $item->get_tax_status(); 
  834.  
  835. if ( '0' !== $tax_class && 'taxable' === $tax_status ) { 
  836. $tax_rates = WC_Tax::find_rates( array( 
  837. 'country' => $args['country'],  
  838. 'state' => $args['state'],  
  839. 'postcode' => $args['postcode'],  
  840. 'city' => $args['city'],  
  841. 'tax_class' => $tax_class,  
  842. ) ); 
  843.  
  844. $total = $item->get_total(); 
  845. $taxes = WC_Tax::calc_tax( $total, $tax_rates, false ); 
  846.  
  847. if ( $item->is_type( 'line_item' ) ) { 
  848. $subtotal = $item->get_subtotal(); 
  849. $subtotal_taxes = WC_Tax::calc_tax( $subtotal, $tax_rates, false ); 
  850. $item->set_taxes( array( 'total' => $taxes, 'subtotal' => $subtotal_taxes ) ); 
  851. } else { 
  852. $item->set_taxes( array( 'total' => $taxes ) ); 
  853. $item->save(); 
  854.  
  855. // Calc taxes for shipping 
  856. foreach ( $this->get_shipping_methods() as $item_id => $item ) { 
  857. $shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' ); 
  858.  
  859. // Inherit tax class from items 
  860. if ( 'inherit' === $shipping_tax_class ) { 
  861. $tax_rates = array(); 
  862. $tax_classes = array_merge( array( '' ), WC_Tax::get_tax_class_slugs() ); 
  863. $found_tax_classes = $this->get_items_tax_classes(); 
  864.  
  865. foreach ( $tax_classes as $tax_class ) { 
  866. if ( in_array( $tax_class, $found_tax_classes ) ) { 
  867. $tax_rates = WC_Tax::find_shipping_rates( array( 
  868. 'country' => $args['country'],  
  869. 'state' => $args['state'],  
  870. 'postcode' => $args['postcode'],  
  871. 'city' => $args['city'],  
  872. 'tax_class' => $tax_class,  
  873. ) ); 
  874. break; 
  875. } else { 
  876. $tax_rates = WC_Tax::find_shipping_rates( array( 
  877. 'country' => $args['country'],  
  878. 'state' => $args['state'],  
  879. 'postcode' => $args['postcode'],  
  880. 'city' => $args['city'],  
  881. 'tax_class' => $shipping_tax_class,  
  882. ) ); 
  883.  
  884. $item->set_taxes( array( 'total' => WC_Tax::calc_tax( $item->get_total(), $tax_rates, false ) ) ); 
  885. $item->save(); 
  886. $this->update_taxes(); 
  887.  
  888. /** 
  889. * Update tax lines for the order based on the line item taxes themselves. 
  890. */ 
  891. public function update_taxes() { 
  892. $cart_taxes = array(); 
  893. $shipping_taxes = array(); 
  894. $existing_taxes = $this->get_taxes(); 
  895. $saved_rate_ids = array(); 
  896.  
  897. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) { 
  898. $taxes = $item->get_taxes(); 
  899. foreach ( $taxes['total'] as $tax_rate_id => $tax ) { 
  900. $cart_taxes[ $tax_rate_id ] = isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] + (float) $tax : (float) $tax; 
  901.  
  902. foreach ( $this->get_shipping_methods() as $item_id => $item ) { 
  903. $taxes = $item->get_taxes(); 
  904. foreach ( $taxes['total'] as $tax_rate_id => $tax ) { 
  905. $shipping_taxes[ $tax_rate_id ] = isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] + (float) $tax : (float) $tax; 
  906.  
  907. foreach ( $existing_taxes as $tax ) { 
  908. // Remove taxes which no longer exist for cart/shipping. 
  909. if ( ( ! array_key_exists( $tax->get_rate_id(), $cart_taxes ) && ! array_key_exists( $tax->get_rate_id(), $shipping_taxes ) ) || in_array( $tax->get_rate_id(), $saved_rate_ids ) ) { 
  910. $this->remove_item( $tax->get_id() ); 
  911. continue; 
  912. $saved_rate_ids[] = $tax->get_rate_id(); 
  913. $tax->set_tax_total( isset( $cart_taxes[ $tax->get_rate_id() ] ) ? $cart_taxes[ $tax->get_rate_id() ] : 0 ); 
  914. $tax->set_shipping_tax_total( ! empty( $shipping_taxes[ $tax->get_rate_id() ] ) ? $shipping_taxes[ $tax->get_rate_id() ] : 0 ); 
  915. $tax->save(); 
  916.  
  917. $new_rate_ids = wp_parse_id_list( array_diff( array_keys( $cart_taxes + $shipping_taxes ), $saved_rate_ids ) ); 
  918.  
  919. // New taxes. 
  920. foreach ( $new_rate_ids as $tax_rate_id ) { 
  921. $item = new WC_Order_Item_Tax(); 
  922. $item->set_rate( $tax_rate_id ); 
  923. $item->set_tax_total( isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] : 0 ); 
  924. $item->set_shipping_tax_total( ! empty( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 ); 
  925. $this->add_item( $item ); 
  926.  
  927. // Save tax totals 
  928. $this->set_shipping_tax( WC_Tax::round( array_sum( $shipping_taxes ) ) ); 
  929. $this->set_cart_tax( WC_Tax::round( array_sum( $cart_taxes ) ) ); 
  930. $this->save(); 
  931.  
  932. /** 
  933. * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total. 
  934. * @since 2.2 
  935. * @param bool $and_taxes Calc taxes if true. 
  936. * @return float calculated grand total. 
  937. */ 
  938. public function calculate_totals( $and_taxes = true ) { 
  939. $cart_subtotal = 0; 
  940. $cart_total = 0; 
  941. $fee_total = 0; 
  942. $cart_subtotal_tax = 0; 
  943. $cart_total_tax = 0; 
  944.  
  945. if ( $and_taxes && wc_tax_enabled() ) { 
  946. $this->calculate_taxes(); 
  947.  
  948. // line items 
  949. foreach ( $this->get_items() as $item ) { 
  950. $cart_subtotal += $item->get_subtotal(); 
  951. $cart_total += $item->get_total(); 
  952. $cart_subtotal_tax += $item->get_subtotal_tax(); 
  953. $cart_total_tax += $item->get_total_tax(); 
  954.  
  955. $this->calculate_shipping(); 
  956.  
  957. foreach ( $this->get_fees() as $item ) { 
  958. $fee_total += $item->get_total(); 
  959.  
  960. $grand_total = round( $cart_total + $fee_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ); 
  961.  
  962. $this->set_discount_total( $cart_subtotal - $cart_total ); 
  963. $this->set_discount_tax( $cart_subtotal_tax - $cart_total_tax ); 
  964. $this->set_total( $grand_total ); 
  965. $this->save(); 
  966.  
  967. return $grand_total; 
  968.  
  969. /** 
  970. * Get item subtotal - this is the cost before discount. 
  971. * @param object $item 
  972. * @param bool $inc_tax (default: false). 
  973. * @param bool $round (default: true). 
  974. * @return float 
  975. */ 
  976. public function get_item_subtotal( $item, $inc_tax = false, $round = true ) { 
  977. $subtotal = 0; 
  978.  
  979. if ( is_callable( array( $item, 'get_subtotal' ) ) ) { 
  980. if ( $inc_tax ) { 
  981. $subtotal = ( $item->get_subtotal() + $item->get_subtotal_tax() ) / max( 1, $item->get_quantity() ); 
  982. } else { 
  983. $subtotal = ( floatval( $item->get_subtotal() ) / max( 1, $item->get_quantity() ) ); 
  984.  
  985. $subtotal = $round ? number_format( (float) $subtotal, wc_get_price_decimals(), '.', '' ) : $subtotal; 
  986.  
  987. return apply_filters( 'woocommerce_order_amount_item_subtotal', $subtotal, $this, $item, $inc_tax, $round ); 
  988.  
  989. /** 
  990. * Get line subtotal - this is the cost before discount. 
  991. * @param object $item 
  992. * @param bool $inc_tax (default: false). 
  993. * @param bool $round (default: true). 
  994. * @return float 
  995. */ 
  996. public function get_line_subtotal( $item, $inc_tax = false, $round = true ) { 
  997. $subtotal = 0; 
  998.  
  999. if ( is_callable( array( $item, 'get_subtotal' ) ) ) { 
  1000. if ( $inc_tax ) { 
  1001. $subtotal = $item->get_subtotal() + $item->get_subtotal_tax(); 
  1002. } else { 
  1003. $subtotal = $item->get_subtotal(); 
  1004.  
  1005. $subtotal = $round ? round( $subtotal, wc_get_price_decimals() ) : $subtotal; 
  1006.  
  1007. return apply_filters( 'woocommerce_order_amount_line_subtotal', $subtotal, $this, $item, $inc_tax, $round ); 
  1008.  
  1009. /** 
  1010. * Calculate item cost - useful for gateways. 
  1011. * @param object $item 
  1012. * @param bool $inc_tax (default: false). 
  1013. * @param bool $round (default: true). 
  1014. * @return float 
  1015. */ 
  1016. public function get_item_total( $item, $inc_tax = false, $round = true ) { 
  1017. $total = 0; 
  1018.  
  1019. if ( is_callable( array( $item, 'get_total' ) ) ) { 
  1020. if ( $inc_tax ) { 
  1021. $total = ( $item->get_total() + $item->get_total_tax() ) / max( 1, $item->get_quantity() ); 
  1022. } else { 
  1023. $total = floatval( $item->get_total() ) / max( 1, $item->get_quantity() ); 
  1024.  
  1025. $total = $round ? round( $total, wc_get_price_decimals() ) : $total; 
  1026.  
  1027. return apply_filters( 'woocommerce_order_amount_item_total', $total, $this, $item, $inc_tax, $round ); 
  1028.  
  1029. /** 
  1030. * Calculate line total - useful for gateways. 
  1031. * @param object $item 
  1032. * @param bool $inc_tax (default: false). 
  1033. * @param bool $round (default: true). 
  1034. * @return float 
  1035. */ 
  1036. public function get_line_total( $item, $inc_tax = false, $round = true ) { 
  1037. $total = 0; 
  1038.  
  1039. if ( is_callable( array( $item, 'get_total' ) ) ) { 
  1040. // Check if we need to add line tax to the line total. 
  1041. $total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total(); 
  1042.  
  1043. // Check if we need to round. 
  1044. $total = $round ? round( $total, wc_get_price_decimals() ) : $total; 
  1045.  
  1046. return apply_filters( 'woocommerce_order_amount_line_total', $total, $this, $item, $inc_tax, $round ); 
  1047.  
  1048. /** 
  1049. * Get item tax - useful for gateways. 
  1050. * @param mixed $item 
  1051. * @param bool $round (default: true). 
  1052. * @return float 
  1053. */ 
  1054. public function get_item_tax( $item, $round = true ) { 
  1055. $tax = 0; 
  1056.  
  1057. if ( is_callable( array( $item, 'get_total_tax' ) ) ) { 
  1058. $tax = $item->get_total_tax() / max( 1, $item->get_quantity() ); 
  1059. $tax = $round ? wc_round_tax_total( $tax ) : $tax; 
  1060.  
  1061. return apply_filters( 'woocommerce_order_amount_item_tax', $tax, $item, $round, $this ); 
  1062.  
  1063. /** 
  1064. * Get line tax - useful for gateways. 
  1065. * @param mixed $item 
  1066. * @return float 
  1067. */ 
  1068. public function get_line_tax( $item ) { 
  1069. return apply_filters( 'woocommerce_order_amount_line_tax', is_callable( array( $item, 'get_total_tax' ) ) ? wc_round_tax_total( $item->get_total_tax() ) : 0, $item, $this ); 
  1070.  
  1071. /** 
  1072. * Gets line subtotal - formatted for display. 
  1073. * @param array $item 
  1074. * @param string $tax_display 
  1075. * @return string 
  1076. */ 
  1077. public function get_formatted_line_subtotal( $item, $tax_display = '' ) { 
  1078. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1079.  
  1080. if ( 'excl' == $tax_display ) { 
  1081. $ex_tax_label = $this->get_prices_include_tax() ? 1 : 0; 
  1082.  
  1083. $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_currency() ) ); 
  1084. } else { 
  1085. $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array( 'currency' => $this->get_currency() ) ); 
  1086.  
  1087. return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this ); 
  1088.  
  1089. /** 
  1090. * Gets order total - formatted for display. 
  1091. * @return string 
  1092. */ 
  1093. public function get_formatted_order_total() { 
  1094. $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_currency() ) ); 
  1095. return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this ); 
  1096.  
  1097. /** 
  1098. * Gets subtotal - subtotal is shown before discounts, but with localised taxes. 
  1099. * @param bool $compound (default: false). 
  1100. * @param string $tax_display (default: the tax_display_cart value). 
  1101. * @return string 
  1102. */ 
  1103. public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { 
  1104. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1105. $subtotal = 0; 
  1106.  
  1107. if ( ! $compound ) { 
  1108. foreach ( $this->get_items() as $item ) { 
  1109. $subtotal += $item->get_subtotal(); 
  1110.  
  1111. if ( 'incl' === $tax_display ) { 
  1112. $subtotal += $item->get_subtotal_tax(); 
  1113.  
  1114. $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) ); 
  1115.  
  1116. if ( 'excl' === $tax_display && $this->get_prices_include_tax() ) { 
  1117. $subtotal .= ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>'; 
  1118. } else { 
  1119. if ( 'incl' === $tax_display ) { 
  1120. return ''; 
  1121.  
  1122. foreach ( $this->get_items() as $item ) { 
  1123. $subtotal += $item->get_subtotal(); 
  1124.  
  1125. // Add Shipping Costs. 
  1126. $subtotal += $this->get_shipping_total(); 
  1127.  
  1128. // Remove non-compound taxes. 
  1129. foreach ( $this->get_taxes() as $tax ) { 
  1130. if ( $tax->is_compound() ) { 
  1131. continue; 
  1132. $subtotal = $subtotal + $tax->get_tax_total() + $tax->get_shipping_tax_total(); 
  1133.  
  1134. // Remove discounts. 
  1135. $subtotal = $subtotal - $this->get_total_discount(); 
  1136. $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) ); 
  1137.  
  1138. return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this ); 
  1139.  
  1140. /** 
  1141. * Gets shipping (formatted). 
  1142. * @return string 
  1143. */ 
  1144. public function get_shipping_to_display( $tax_display = '' ) { 
  1145. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1146.  
  1147. if ( $this->get_shipping_total() != 0 ) { 
  1148.  
  1149. if ( 'excl' === $tax_display ) { 
  1150.  
  1151. // Show shipping excluding tax. 
  1152. $shipping = wc_price( $this->get_shipping_total(), array( 'currency' => $this->get_currency() ) ); 
  1153.  
  1154. if ( $this->get_shipping_tax() != 0 && $this->get_prices_include_tax() ) { 
  1155. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->ex_tax_or_vat() . '</small>', $this, $tax_display ); 
  1156. } else { 
  1157.  
  1158. // Show shipping including tax. 
  1159. $shipping = wc_price( $this->get_shipping_total() + $this->get_shipping_tax(), array( 'currency' => $this->get_currency() ) ); 
  1160.  
  1161. if ( $this->get_shipping_tax() != 0 && ! $this->get_prices_include_tax() ) { 
  1162. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_tax_label', ' <small class="tax_label">' . WC()->countries->inc_tax_or_vat() . '</small>', $this, $tax_display ); 
  1163.  
  1164. /** translators: %s: shipping method */ 
  1165. $shipping .= apply_filters( 'woocommerce_order_shipping_to_display_shipped_via', ' <small class="shipped_via">' . sprintf( __( 'via %s', 'woocommerce' ), $this->get_shipping_method() ) . '</small>', $this ); 
  1166.  
  1167. } elseif ( $this->get_shipping_method() ) { 
  1168. $shipping = $this->get_shipping_method(); 
  1169. } else { 
  1170. $shipping = __( 'Free!', 'woocommerce' ); 
  1171.  
  1172. return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this ); 
  1173.  
  1174. /** 
  1175. * Get the discount amount (formatted). 
  1176. * @since 2.3.0 
  1177. * @return string 
  1178. */ 
  1179. public function get_discount_to_display( $tax_display = '' ) { 
  1180. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1181. return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_total_discount( 'excl' === $tax_display && 'excl' === get_option( 'woocommerce_tax_display_cart' ) ), array( 'currency' => $this->get_currency() ) ), $this ); 
  1182.  
  1183. /** 
  1184. * Add total row for subtotal. 
  1185. * @param array $total_rows 
  1186. * @param string $tax_display 
  1187. */ 
  1188. protected function add_order_item_totals_subtotal_row( &$total_rows, $tax_display ) { 
  1189. if ( $subtotal = $this->get_subtotal_to_display( false, $tax_display ) ) { 
  1190. $total_rows['cart_subtotal'] = array( 
  1191. 'label' => __( 'Subtotal:', 'woocommerce' ),  
  1192. 'value' => $subtotal,  
  1193. ); 
  1194.  
  1195. /** 
  1196. * Add total row for discounts. 
  1197. * @param array $total_rows 
  1198. * @param string $tax_display 
  1199. */ 
  1200. protected function add_order_item_totals_discount_row( &$total_rows, $tax_display ) { 
  1201. if ( $this->get_total_discount() > 0 ) { 
  1202. $total_rows['discount'] = array( 
  1203. 'label' => __( 'Discount:', 'woocommerce' ),  
  1204. 'value' => '-' . $this->get_discount_to_display( $tax_display ),  
  1205. ); 
  1206.  
  1207. /** 
  1208. * Add total row for shipping. 
  1209. * @param array $total_rows 
  1210. * @param string $tax_display 
  1211. */ 
  1212. protected function add_order_item_totals_shipping_row( &$total_rows, $tax_display ) { 
  1213. if ( $this->get_shipping_method() ) { 
  1214. $total_rows['shipping'] = array( 
  1215. 'label' => __( 'Shipping:', 'woocommerce' ),  
  1216. 'value' => $this->get_shipping_to_display( $tax_display ),  
  1217. ); 
  1218.  
  1219. /** 
  1220. * Add total row for fees. 
  1221. * @param array $total_rows 
  1222. * @param string $tax_display 
  1223. */ 
  1224. protected function add_order_item_totals_fee_rows( &$total_rows, $tax_display ) { 
  1225. if ( $fees = $this->get_fees() ) { 
  1226. foreach ( $fees as $id => $fee ) { 
  1227. if ( apply_filters( 'woocommerce_get_order_item_totals_excl_free_fees', empty( $fee['line_total'] ) && empty( $fee['line_tax'] ), $id ) ) { 
  1228. continue; 
  1229. $total_rows[ 'fee_' . $fee->get_id() ] = array( 
  1230. 'label' => $fee->get_name() . ':',  
  1231. 'value' => wc_price( 'excl' === $tax_display ? $fee->get_total() : $fee->get_total() + $fee->get_total_tax(), array( 'currency' => $this->get_currency() ) ),  
  1232. ); 
  1233.  
  1234. /** 
  1235. * Add total row for taxes. 
  1236. * @param array $total_rows 
  1237. * @param string $tax_display 
  1238. */ 
  1239. protected function add_order_item_totals_tax_rows( &$total_rows, $tax_display ) { 
  1240. // Tax for tax exclusive prices. 
  1241. if ( 'excl' === $tax_display ) { 
  1242. if ( 'itemized' === get_option( 'woocommerce_tax_total_display' ) ) { 
  1243. foreach ( $this->get_tax_totals() as $code => $tax ) { 
  1244. $total_rows[ sanitize_title( $code ) ] = array( 
  1245. 'label' => $tax->label . ':',  
  1246. 'value' => $tax->formatted_amount,  
  1247. ); 
  1248. } else { 
  1249. $total_rows['tax'] = array( 
  1250. 'label' => WC()->countries->tax_or_vat() . ':',  
  1251. 'value' => wc_price( $this->get_total_tax(), array( 'currency' => $this->get_currency() ) ),  
  1252. ); 
  1253.  
  1254. /** 
  1255. * Add total row for grand total. 
  1256. * @param array $total_rows 
  1257. * @param string $tax_display 
  1258. */ 
  1259. protected function add_order_item_totals_total_row( &$total_rows, $tax_display ) { 
  1260. $total_rows['order_total'] = array( 
  1261. 'label' => __( 'Total:', 'woocommerce' ),  
  1262. 'value' => $this->get_formatted_order_total( $tax_display ),  
  1263. ); 
  1264.  
  1265. /** 
  1266. * Get totals for display on pages and in emails. 
  1267. * @param mixed $tax_display 
  1268. * @return array 
  1269. */ 
  1270. public function get_order_item_totals( $tax_display = '' ) { 
  1271. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1272. $total_rows = array(); 
  1273.  
  1274. $this->add_order_item_totals_subtotal_row( $total_rows, $tax_display ); 
  1275. $this->add_order_item_totals_discount_row( $total_rows, $tax_display ); 
  1276. $this->add_order_item_totals_shipping_row( $total_rows, $tax_display ); 
  1277. $this->add_order_item_totals_fee_rows( $total_rows, $tax_display ); 
  1278. $this->add_order_item_totals_tax_rows( $total_rows, $tax_display ); 
  1279. $this->add_order_item_totals_total_row( $total_rows, $tax_display ); 
  1280.  
  1281. return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this, $tax_display ); 
  1282.  
  1283. /** 
  1284. |-------------------------------------------------------------------------- 
  1285. | Conditionals 
  1286. |-------------------------------------------------------------------------- 
  1287. | Checks if a condition is true or false. 
  1288. */ 
  1289.  
  1290. /** 
  1291. * Checks the order status against a passed in status. 
  1292. * @return bool 
  1293. */ 
  1294. public function has_status( $status ) { 
  1295. return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status ); 
  1296.  
  1297. /** 
  1298. * Check whether this order has a specific shipping method or not. 
  1299. * @param string $method_id 
  1300. * @return bool 
  1301. */ 
  1302. public function has_shipping_method( $method_id ) { 
  1303. foreach ( $this->get_shipping_methods() as $shipping_method ) { 
  1304. if ( strpos( $shipping_method->get_method_id(), $method_id ) === 0 ) { 
  1305. return true; 
  1306. return false; 
  1307.  
  1308. /** 
  1309. * Returns true if the order contains a free product. 
  1310. * @since 2.5.0 
  1311. * @return bool 
  1312. */ 
  1313. public function has_free_item() { 
  1314. foreach ( $this->get_items() as $item ) { 
  1315. if ( ! $item->get_total() ) { 
  1316. return true; 
  1317. return false;