PageRenderTime 59ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/web/paypal-wc/includes/abstracts/abstract-wc-order.php

https://gitlab.com/JoelSanchez/lampadario
PHP | 1602 lines | 803 code | 262 blank | 537 comment | 108 complexity | 812f1b72d747940e4e457ff572b1736d MD5 | raw file
  1. <?php
  2. /**
  3. * Abstract Order
  4. *
  5. * The WooCommerce order class handles order data.
  6. *
  7. * @class WC_Order
  8. * @version 2.2.0
  9. * @package WooCommerce/Classes
  10. * @category Class
  11. * @author WooThemes
  12. *
  13. * @property string $billing_first_name The billing address first name.
  14. * @property string $billing_last_name The billing address last name.
  15. * @property string $billing_company The billing address company.
  16. * @property string $billing_address_1 The first line of the billing address.
  17. * @property string $billing_address_2 The second line of the billing address.
  18. * @property string $billing_city The city of the billing address.
  19. * @property string $billing_state The state of the billing address.
  20. * @property string $billing_postcode The postcode of the billing address.
  21. * @property string $billing_country The country of the billing address.
  22. * @property string $billing_phone The billing phone number.
  23. * @property string $billing_email The billing email.
  24. * @property string $shipping_first_name The shipping address first name.
  25. * @property string $shipping_last_name The shipping address last name.
  26. * @property string $shipping_company The shipping address company.
  27. * @property string $shipping_address_1 The first line of the shipping address.
  28. * @property string $shipping_address_2 The second line of the shipping address.
  29. * @property string $shipping_city The city of the shipping address.
  30. * @property string $shipping_state The state of the shipping address.
  31. * @property string $shipping_postcode The postcode of the shipping address.
  32. * @property string $shipping_country The country of the shipping address.
  33. * @property string $cart_discount Total amount of discount.
  34. * @property string $cart_discount_tax Total amount of discount applied to taxes.
  35. * @property string $shipping_method_title < 2.1 was used for shipping method title. Now @deprecated.
  36. * @property int $customer_user User ID who the order belongs to. 0 for guests.
  37. * @property string $order_key Random key/password unqique to each order.
  38. * @property string $order_discount Stored after tax discounts pre-2.3. Now @deprecated.
  39. * @property string $order_tax Stores order tax total.
  40. * @property string $order_shipping_tax Stores shipping tax total.
  41. * @property string $order_shipping Stores shipping total.
  42. * @property string $order_total Stores order total.
  43. * @property string $order_currency Stores currency code used for the order.
  44. * @property string $payment_method method ID.
  45. * @property string $payment_method_title Name of the payment method used.
  46. * @property string $customer_ip_address Customer IP Address.
  47. * @property string $customer_user_agent Customer User agent.
  48. */
  49. abstract class WC_Abstract_Order {
  50. /** @public int Order (post) ID. */
  51. public $id = 0;
  52. /** @var $post WP_Post. */
  53. public $post = null;
  54. /** @public string Order type. */
  55. public $order_type = false;
  56. /** @public string Order Date. */
  57. public $order_date = '';
  58. /** @public string Order Modified Date. */
  59. public $modified_date = '';
  60. /** @public string Customer Message (excerpt). */
  61. public $customer_message = '';
  62. /** @public string Customer Note */
  63. public $customer_note = '';
  64. /** @public string Order Status. */
  65. public $post_status = '';
  66. /** @public bool Do prices include tax? */
  67. public $prices_include_tax = false;
  68. /** @public string Display mode for taxes in cart. */
  69. public $tax_display_cart = '';
  70. /** @public bool Do totals display ex tax? */
  71. public $display_totals_ex_tax = false;
  72. /** @public bool Do cart prices display ex tax? */
  73. public $display_cart_ex_tax = false;
  74. /** @protected string Formatted address. Accessed via get_formatted_billing_address(). */
  75. protected $formatted_billing_address = '';
  76. /** @protected string Formatted address. Accessed via get_formatted_shipping_address(). */
  77. protected $formatted_shipping_address = '';
  78. /**
  79. * Get the order if ID is passed, otherwise the order is new and empty.
  80. * This class should NOT be instantiated, but the get_order function or new WC_Order_Factory.
  81. * should be used. It is possible, but the aforementioned are preferred and are the only.
  82. * methods that will be maintained going forward.
  83. *
  84. * @param int|object|WC_Order $order Order to init.
  85. */
  86. public function __construct( $order = 0 ) {
  87. $this->prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false;
  88. $this->tax_display_cart = get_option( 'woocommerce_tax_display_cart' );
  89. $this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
  90. $this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
  91. $this->init( $order );
  92. }
  93. /**
  94. * Init/load the order object. Called from the constructor.
  95. *
  96. * @param int|object|WC_Order $order Order to init.
  97. */
  98. protected function init( $order ) {
  99. if ( is_numeric( $order ) ) {
  100. $this->id = absint( $order );
  101. $this->post = get_post( $order );
  102. $this->get_order( $this->id );
  103. } elseif ( $order instanceof WC_Order ) {
  104. $this->id = absint( $order->id );
  105. $this->post = $order->post;
  106. $this->get_order( $this->id );
  107. } elseif ( isset( $order->ID ) ) {
  108. $this->id = absint( $order->ID );
  109. $this->post = $order;
  110. $this->get_order( $this->id );
  111. }
  112. }
  113. /**
  114. * Remove all line items (products, coupons, shipping, taxes) from the order.
  115. *
  116. * @param string $type Order item type. Default null.
  117. */
  118. public function remove_order_items( $type = null ) {
  119. global $wpdb;
  120. if ( ! empty( $type ) ) {
  121. $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 ) );
  122. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $this->id, $type ) );
  123. } else {
  124. $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 ) );
  125. $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $this->id ) );
  126. }
  127. }
  128. /**
  129. * Set the payment method for the order.
  130. *
  131. * @param WC_Payment_Gateway $payment_method
  132. */
  133. public function set_payment_method( $payment_method ) {
  134. if ( is_object( $payment_method ) ) {
  135. update_post_meta( $this->id, '_payment_method', $payment_method->id );
  136. update_post_meta( $this->id, '_payment_method_title', $payment_method->get_title() );
  137. }
  138. }
  139. /**
  140. * Set the customer address.
  141. *
  142. * @param array $address Address data.
  143. * @param string $type billing or shipping.
  144. */
  145. public function set_address( $address, $type = 'billing' ) {
  146. foreach ( $address as $key => $value ) {
  147. update_post_meta( $this->id, "_{$type}_" . $key, $value );
  148. }
  149. }
  150. /**
  151. * Returns the requested address in raw, non-formatted way.
  152. * @since 2.4.0
  153. * @param string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
  154. * @return array The stored address after filter.
  155. */
  156. public function get_address( $type = 'billing' ) {
  157. if ( 'billing' === $type ) {
  158. $address = array(
  159. 'first_name' => $this->billing_first_name,
  160. 'last_name' => $this->billing_last_name,
  161. 'company' => $this->billing_company,
  162. 'address_1' => $this->billing_address_1,
  163. 'address_2' => $this->billing_address_2,
  164. 'city' => $this->billing_city,
  165. 'state' => $this->billing_state,
  166. 'postcode' => $this->billing_postcode,
  167. 'country' => $this->billing_country,
  168. 'email' => $this->billing_email,
  169. 'phone' => $this->billing_phone,
  170. );
  171. } else {
  172. $address = array(
  173. 'first_name' => $this->shipping_first_name,
  174. 'last_name' => $this->shipping_last_name,
  175. 'company' => $this->shipping_company,
  176. 'address_1' => $this->shipping_address_1,
  177. 'address_2' => $this->shipping_address_2,
  178. 'city' => $this->shipping_city,
  179. 'state' => $this->shipping_state,
  180. 'postcode' => $this->shipping_postcode,
  181. 'country' => $this->shipping_country,
  182. );
  183. }
  184. return apply_filters( 'woocommerce_get_order_address', $address, $type, $this );
  185. }
  186. /**
  187. * Add a product line item to the order.
  188. *
  189. * @since 2.2
  190. * @param \WC_Product $product
  191. * @param int $qty Line item quantity.
  192. * @param array $args
  193. * @return int|bool Item ID or false.
  194. */
  195. public function add_product( $product, $qty = 1, $args = array() ) {
  196. $default_args = array(
  197. 'variation' => array(),
  198. 'totals' => array()
  199. );
  200. $args = wp_parse_args( $args, $default_args );
  201. $item_id = wc_add_order_item( $this->id, array(
  202. 'order_item_name' => $product->get_title(),
  203. 'order_item_type' => 'line_item'
  204. ) );
  205. if ( ! $item_id ) {
  206. return false;
  207. }
  208. wc_add_order_item_meta( $item_id, '_qty', wc_stock_amount( $qty ) );
  209. wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() );
  210. wc_add_order_item_meta( $item_id, '_product_id', $product->id );
  211. wc_add_order_item_meta( $item_id, '_variation_id', isset( $product->variation_id ) ? $product->variation_id : 0 );
  212. // Set line item totals, either passed in or from the product
  213. 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 ) ) );
  214. 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 ) ) );
  215. wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) );
  216. wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) );
  217. // Save tax data - Since 2.2
  218. if ( isset( $args['totals']['tax_data'] ) ) {
  219. $tax_data = array();
  220. $tax_data['total'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['total'] );
  221. $tax_data['subtotal'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['subtotal'] );
  222. wc_add_order_item_meta( $item_id, '_line_tax_data', $tax_data );
  223. } else {
  224. wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) );
  225. }
  226. // Add variation meta
  227. if ( ! empty( $args['variation'] ) ) {
  228. foreach ( $args['variation'] as $key => $value ) {
  229. wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
  230. }
  231. }
  232. // Backorders
  233. if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) {
  234. wc_add_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $qty - max( 0, $product->get_total_stock() ) );
  235. }
  236. do_action( 'woocommerce_order_add_product', $this->id, $item_id, $product, $qty, $args );
  237. return $item_id;
  238. }
  239. /**
  240. * Update a line item for the order.
  241. *
  242. * Note this does not update order totals.
  243. *
  244. * @since 2.2
  245. * @param int $item_id order item ID.
  246. * @param array $args data to update.
  247. * @param WC_Product $product
  248. * @return bool
  249. */
  250. public function update_product( $item_id, $product, $args ) {
  251. if ( ! $item_id || ! is_object( $product ) ) {
  252. return false;
  253. }
  254. // quantity
  255. if ( isset( $args['qty'] ) ) {
  256. wc_update_order_item_meta( $item_id, '_qty', wc_stock_amount( $args['qty'] ) );
  257. }
  258. // tax class
  259. if ( isset( $args['tax_class'] ) ) {
  260. wc_update_order_item_meta( $item_id, '_tax_class', $args['tax_class'] );
  261. }
  262. // set item totals, either provided or from product
  263. if ( isset( $args['qty'] ) ) {
  264. 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'] ) ) );
  265. 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'] ) ) );
  266. }
  267. // set item tax totals
  268. wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) );
  269. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) );
  270. // variation meta
  271. if ( isset( $args['variation'] ) && is_array( $args['variation'] ) ) {
  272. foreach ( $args['variation'] as $key => $value ) {
  273. wc_update_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
  274. }
  275. }
  276. // backorders
  277. if ( isset( $args['qty'] ) && $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
  278. wc_update_order_item_meta( $item_id, apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ) ), $args['qty'] - max( 0, $product->get_total_stock() ) );
  279. }
  280. do_action( 'woocommerce_order_edit_product', $this->id, $item_id, $args, $product );
  281. return true;
  282. }
  283. /**
  284. * Add coupon code to the order.
  285. *
  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. if ( ! $item_id ) {
  297. return false;
  298. }
  299. wc_add_order_item_meta( $item_id, 'discount_amount', $discount_amount );
  300. wc_add_order_item_meta( $item_id, 'discount_amount_tax', $discount_amount_tax );
  301. do_action( 'woocommerce_order_add_coupon', $this->id, $item_id, $code, $discount_amount, $discount_amount_tax );
  302. return $item_id;
  303. }
  304. /**
  305. * Update coupon for order.
  306. *
  307. * Note this does not update order totals.
  308. *
  309. * @since 2.2
  310. * @param int $item_id
  311. * @param array $args
  312. * @return bool
  313. */
  314. public function update_coupon( $item_id, $args ) {
  315. if ( ! $item_id ) {
  316. return false;
  317. }
  318. // code
  319. if ( isset( $args['code'] ) ) {
  320. wc_update_order_item( $item_id, array( 'order_item_name' => $args['code'] ) );
  321. }
  322. // amount
  323. if ( isset( $args['discount_amount'] ) ) {
  324. wc_update_order_item_meta( $item_id, 'discount_amount', wc_format_decimal( $args['discount_amount'] ) );
  325. }
  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. return true;
  331. }
  332. /**
  333. * Add a tax row to the order.
  334. *
  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. $code = WC_Tax::get_rate_code( $tax_rate_id );
  341. if ( ! $code ) {
  342. return false;
  343. }
  344. $item_id = wc_add_order_item( $this->id, array(
  345. 'order_item_name' => $code,
  346. 'order_item_type' => 'tax'
  347. ) );
  348. if ( ! $item_id ) {
  349. return false;
  350. }
  351. wc_add_order_item_meta( $item_id, 'rate_id', $tax_rate_id );
  352. wc_add_order_item_meta( $item_id, 'label', WC_Tax::get_rate_label( $tax_rate_id ) );
  353. wc_add_order_item_meta( $item_id, 'compound', WC_Tax::is_compound( $tax_rate_id ) ? 1 : 0 );
  354. wc_add_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $tax_amount ) );
  355. wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $shipping_tax_amount ) );
  356. do_action( 'woocommerce_order_add_tax', $this->id, $item_id, $tax_rate_id, $tax_amount, $shipping_tax_amount );
  357. return $item_id;
  358. }
  359. /**
  360. * Add a shipping row to the order.
  361. *
  362. * @param WC_Shipping_Rate shipping_rate
  363. * @return int|bool Item ID or false.
  364. */
  365. public function add_shipping( $shipping_rate ) {
  366. $item_id = wc_add_order_item( $this->id, array(
  367. 'order_item_name' => $shipping_rate->label,
  368. 'order_item_type' => 'shipping'
  369. ) );
  370. if ( ! $item_id ) {
  371. return false;
  372. }
  373. wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id );
  374. wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) );
  375. // Save shipping taxes - Since 2.2
  376. $taxes = array_map( 'wc_format_decimal', $shipping_rate->taxes );
  377. wc_add_order_item_meta( $item_id, 'taxes', $taxes );
  378. do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate );
  379. // Update total
  380. $this->set_total( $this->order_shipping + wc_format_decimal( $shipping_rate->cost ), 'shipping' );
  381. return $item_id;
  382. }
  383. /**
  384. * Update shipping method for order.
  385. *
  386. * Note this does not update the order total.
  387. *
  388. * @since 2.2
  389. * @param int $item_id
  390. * @param array $args
  391. * @return bool
  392. */
  393. public function update_shipping( $item_id, $args ) {
  394. if ( ! $item_id ) {
  395. return false;
  396. }
  397. // method title
  398. if ( isset( $args['method_title'] ) ) {
  399. wc_update_order_item( $item_id, array( 'order_item_name' => $args['method_title'] ) );
  400. }
  401. // method ID
  402. if ( isset( $args['method_id'] ) ) {
  403. wc_update_order_item_meta( $item_id, 'method_id', $args['method_id'] );
  404. }
  405. // method cost
  406. if ( isset( $args['cost'] ) ) {
  407. // Get old cost before updating
  408. $old_cost = wc_get_order_item_meta( $item_id, 'cost' );
  409. // Update
  410. wc_update_order_item_meta( $item_id, 'cost', wc_format_decimal( $args['cost'] ) );
  411. // Update total
  412. $this->set_total( $this->order_shipping - wc_format_decimal( $old_cost ) + wc_format_decimal( $args['cost'] ), 'shipping' );
  413. }
  414. do_action( 'woocommerce_order_update_shipping', $this->id, $item_id, $args );
  415. return true;
  416. }
  417. /**
  418. * Add a fee to the order.
  419. *
  420. * @param object $fee
  421. * @return int|bool Item ID or false.
  422. */
  423. public function add_fee( $fee ) {
  424. $item_id = wc_add_order_item( $this->id, array(
  425. 'order_item_name' => $fee->name,
  426. 'order_item_type' => 'fee'
  427. ) );
  428. if ( ! $item_id ) {
  429. return false;
  430. }
  431. if ( $fee->taxable ) {
  432. wc_add_order_item_meta( $item_id, '_tax_class', $fee->tax_class );
  433. } else {
  434. wc_add_order_item_meta( $item_id, '_tax_class', '0' );
  435. }
  436. wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) );
  437. wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) );
  438. // Save tax data - Since 2.2
  439. $tax_data = array_map( 'wc_format_decimal', $fee->tax_data );
  440. wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $tax_data ) );
  441. do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee );
  442. return $item_id;
  443. }
  444. /**
  445. * Update fee for order.
  446. *
  447. * Note this does not update order totals.
  448. *
  449. * @since 2.2
  450. * @param int $item_id
  451. * @param array $args
  452. * @return bool
  453. */
  454. public function update_fee( $item_id, $args ) {
  455. if ( ! $item_id ) {
  456. return false;
  457. }
  458. // name
  459. if ( isset( $args['name'] ) ) {
  460. wc_update_order_item( $item_id, array( 'order_item_name' => $args['name'] ) );
  461. }
  462. // tax class
  463. if ( isset( $args['tax_class'] ) ) {
  464. wc_update_order_item_meta( $item_id, '_tax_class', $args['tax_class'] );
  465. }
  466. // total
  467. if ( isset( $args['line_total'] ) ) {
  468. wc_update_order_item_meta( $item_id, '_line_total', wc_format_decimal( $args['line_total'] ) );
  469. }
  470. // total tax
  471. if ( isset( $args['line_tax'] ) ) {
  472. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $args['line_tax'] ) );
  473. }
  474. do_action( 'woocommerce_order_update_fee', $this->id, $item_id, $args );
  475. return true;
  476. }
  477. /**
  478. * Set an order total.
  479. *
  480. * @param float $amount
  481. * @param string $total_type
  482. *
  483. * @return bool
  484. */
  485. public function set_total( $amount, $total_type = 'total' ) {
  486. if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
  487. return false;
  488. }
  489. switch ( $total_type ) {
  490. case 'total' :
  491. $key = '_order_total';
  492. $amount = wc_format_decimal( $amount, wc_get_price_decimals() );
  493. break;
  494. case 'cart_discount' :
  495. case 'cart_discount_tax' :
  496. $key = '_' . $total_type;
  497. $amount = wc_format_decimal( $amount );
  498. break;
  499. default :
  500. $key = '_order_' . $total_type;
  501. $amount = wc_format_decimal( $amount );
  502. break;
  503. }
  504. update_post_meta( $this->id, $key, $amount );
  505. return true;
  506. }
  507. /**
  508. * Calculate taxes for all line items and shipping, and store the totals and tax rows.
  509. *
  510. * Will use the base country unless customer addresses are set.
  511. *
  512. * @return bool success or fail.
  513. */
  514. public function calculate_taxes() {
  515. $tax_total = 0;
  516. $taxes = array();
  517. $tax_based_on = get_option( 'woocommerce_tax_based_on' );
  518. if ( 'billing' === $tax_based_on ) {
  519. $country = $this->billing_country;
  520. $state = $this->billing_state;
  521. $postcode = $this->billing_postcode;
  522. $city = $this->billing_city;
  523. } elseif ( 'shipping' === $tax_based_on ) {
  524. $country = $this->shipping_country;
  525. $state = $this->shipping_state;
  526. $postcode = $this->shipping_postcode;
  527. $city = $this->shipping_city;
  528. }
  529. // Default to base
  530. if ( 'base' === $tax_based_on || empty( $country ) ) {
  531. $default = wc_get_base_location();
  532. $country = $default['country'];
  533. $state = $default['state'];
  534. $postcode = '';
  535. $city = '';
  536. }
  537. // Get items
  538. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
  539. $product = $this->get_product_from_item( $item );
  540. $line_total = isset( $item['line_total'] ) ? $item['line_total'] : 0;
  541. $line_subtotal = isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0;
  542. $tax_class = $item['tax_class'];
  543. $item_tax_status = $product ? $product->get_tax_status() : 'taxable';
  544. if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
  545. $tax_rates = WC_Tax::find_rates( array(
  546. 'country' => $country,
  547. 'state' => $state,
  548. 'postcode' => $postcode,
  549. 'city' => $city,
  550. 'tax_class' => $tax_class
  551. ) );
  552. $line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false );
  553. $line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false );
  554. $line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) );
  555. $line_tax = max( 0, array_sum( $line_taxes ) );
  556. $tax_total += $line_tax;
  557. wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax ) );
  558. wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax ) );
  559. wc_update_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $line_taxes, 'subtotal' => $line_subtotal_taxes ) );
  560. // Sum the item taxes
  561. foreach ( array_keys( $taxes + $line_taxes ) as $key ) {
  562. $taxes[ $key ] = ( isset( $line_taxes[ $key ] ) ? $line_taxes[ $key ] : 0 ) + ( isset( $taxes[ $key ] ) ? $taxes[ $key ] : 0 );
  563. }
  564. }
  565. }
  566. // Now calculate shipping tax
  567. $shipping_methods = $this->get_shipping_methods();
  568. if ( ! empty( $shipping_methods ) ) {
  569. $matched_tax_rates = array();
  570. $tax_rates = WC_Tax::find_rates( array(
  571. 'country' => $country,
  572. 'state' => $state,
  573. 'postcode' => $postcode,
  574. 'city' => $city,
  575. 'tax_class' => ''
  576. ) );
  577. if ( ! empty( $tax_rates ) ) {
  578. foreach ( $tax_rates as $key => $rate ) {
  579. if ( isset( $rate['shipping'] ) && 'yes' === $rate['shipping'] ) {
  580. $matched_tax_rates[ $key ] = $rate;
  581. }
  582. }
  583. }
  584. $shipping_taxes = WC_Tax::calc_shipping_tax( $this->order_shipping, $matched_tax_rates );
  585. $shipping_tax_total = WC_Tax::round( array_sum( $shipping_taxes ) );
  586. } else {
  587. $shipping_taxes = array();
  588. $shipping_tax_total = 0;
  589. }
  590. // Save tax totals
  591. $this->set_total( $shipping_tax_total, 'shipping_tax' );
  592. $this->set_total( $tax_total, 'tax' );
  593. // Tax rows
  594. $this->remove_order_items( 'tax' );
  595. // Now merge to keep tax rows
  596. foreach ( array_keys( $taxes + $shipping_taxes ) as $tax_rate_id ) {
  597. $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 );
  598. }
  599. return true;
  600. }
  601. /**
  602. * Calculate shipping total.
  603. *
  604. * @since 2.2
  605. * @return float
  606. */
  607. public function calculate_shipping() {
  608. $shipping_total = 0;
  609. foreach ( $this->get_shipping_methods() as $shipping ) {
  610. $shipping_total += $shipping['cost'];
  611. }
  612. $this->set_total( $shipping_total, 'shipping' );
  613. return $this->get_total_shipping();
  614. }
  615. /**
  616. * Update tax lines at order level by looking at the line item taxes themselves.
  617. *
  618. * @return bool success or fail.
  619. */
  620. public function update_taxes() {
  621. $order_taxes = array();
  622. $order_shipping_taxes = array();
  623. foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
  624. $line_tax_data = maybe_unserialize( $item['line_tax_data'] );
  625. if ( isset( $line_tax_data['total'] ) ) {
  626. foreach ( $line_tax_data['total'] as $tax_rate_id => $tax ) {
  627. if ( ! isset( $order_taxes[ $tax_rate_id ] ) ) {
  628. $order_taxes[ $tax_rate_id ] = 0;
  629. }
  630. $order_taxes[ $tax_rate_id ] += $tax;
  631. }
  632. }
  633. }
  634. foreach ( $this->get_items( array( 'shipping' ) ) as $item_id => $item ) {
  635. $line_tax_data = maybe_unserialize( $item['taxes'] );
  636. if ( isset( $line_tax_data ) ) {
  637. foreach ( $line_tax_data as $tax_rate_id => $tax ) {
  638. if ( ! isset( $order_shipping_taxes[ $tax_rate_id ] ) ) {
  639. $order_shipping_taxes[ $tax_rate_id ] = 0;
  640. }
  641. $order_shipping_taxes[ $tax_rate_id ] += $tax;
  642. }
  643. }
  644. }
  645. // Remove old existing tax rows.
  646. $this->remove_order_items( 'tax' );
  647. // Now merge to keep tax rows.
  648. foreach ( array_keys( $order_taxes + $order_shipping_taxes ) as $tax_rate_id ) {
  649. $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 );
  650. }
  651. // Save tax totals
  652. $this->set_total( WC_Tax::round( array_sum( $order_shipping_taxes ) ), 'shipping_tax' );
  653. $this->set_total( WC_Tax::round( array_sum( $order_taxes ) ), 'tax' );
  654. return true;
  655. }
  656. /**
  657. * Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
  658. *
  659. * @since 2.2
  660. * @param bool $and_taxes Calc taxes if true.
  661. * @return float calculated grand total.
  662. */
  663. public function calculate_totals( $and_taxes = true ) {
  664. $cart_subtotal = 0;
  665. $cart_total = 0;
  666. $fee_total = 0;
  667. $cart_subtotal_tax = 0;
  668. $cart_total_tax = 0;
  669. if ( $and_taxes && wc_tax_enabled() ) {
  670. $this->calculate_taxes();
  671. }
  672. // line items
  673. foreach ( $this->get_items() as $item ) {
  674. $cart_subtotal += wc_format_decimal( isset( $item['line_subtotal'] ) ? $item['line_subtotal'] : 0 );
  675. $cart_total += wc_format_decimal( isset( $item['line_total'] ) ? $item['line_total'] : 0 );
  676. $cart_subtotal_tax += wc_format_decimal( isset( $item['line_subtotal_tax'] ) ? $item['line_subtotal_tax'] : 0 );
  677. $cart_total_tax += wc_format_decimal( isset( $item['line_tax'] ) ? $item['line_tax'] : 0 );
  678. }
  679. $this->calculate_shipping();
  680. foreach ( $this->get_fees() as $item ) {
  681. $fee_total += $item['line_total'];
  682. }
  683. $this->set_total( $cart_subtotal - $cart_total, 'cart_discount' );
  684. $this->set_total( $cart_subtotal_tax - $cart_total_tax, 'cart_discount_tax' );
  685. $grand_total = round( $cart_total + $fee_total + $this->get_total_shipping() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() );
  686. $this->set_total( $grand_total, 'total' );
  687. return $grand_total;
  688. }
  689. /**
  690. * Gets an order from the database.
  691. *
  692. * @param int $id (default: 0).
  693. * @return bool
  694. */
  695. public function get_order( $id = 0 ) {
  696. if ( ! $id ) {
  697. return false;
  698. }
  699. if ( $result = get_post( $id ) ) {
  700. $this->populate( $result );
  701. return true;
  702. }
  703. return false;
  704. }
  705. /**
  706. * Populates an order from the loaded post data.
  707. *
  708. * @param mixed $result
  709. */
  710. public function populate( $result ) {
  711. // Standard post data
  712. $this->id = $result->ID;
  713. $this->order_date = $result->post_date;
  714. $this->modified_date = $result->post_modified;
  715. $this->customer_message = $result->post_excerpt;
  716. $this->customer_note = $result->post_excerpt;
  717. $this->post_status = $result->post_status;
  718. // Billing email can default to user if set.
  719. if ( empty( $this->billing_email ) && ! empty( $this->customer_user ) && ( $user = get_user_by( 'id', $this->customer_user ) ) ) {
  720. $this->billing_email = $user->user_email;
  721. }
  722. // Orders store the state of prices including tax when created.
  723. $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;
  724. }
  725. /**
  726. * __isset function.
  727. *
  728. * @param mixed $key
  729. * @return bool
  730. */
  731. public function __isset( $key ) {
  732. if ( ! $this->id ) {
  733. return false;
  734. }
  735. return metadata_exists( 'post', $this->id, '_' . $key );
  736. }
  737. /**
  738. * __get function.
  739. *
  740. * @param mixed $key
  741. * @return mixed
  742. */
  743. public function __get( $key ) {
  744. // Get values or default if not set.
  745. if ( 'completed_date' === $key ) {
  746. $value = ( $value = get_post_meta( $this->id, '_completed_date', true ) ) ? $value : $this->modified_date;
  747. } elseif ( 'user_id' === $key ) {
  748. $value = ( $value = get_post_meta( $this->id, '_customer_user', true ) ) ? absint( $value ) : '';
  749. } elseif ( 'status' === $key ) {
  750. $value = $this->get_status();
  751. } else {
  752. $value = get_post_meta( $this->id, '_' . $key, true );
  753. }
  754. return $value;
  755. }
  756. /**
  757. * Return the order statuses without wc- internal prefix.
  758. *
  759. * Queries get_post_status() directly to avoid having out of date statuses, if updated elsewhere.
  760. *
  761. * @return string
  762. */
  763. public function get_status() {
  764. $this->post_status = get_post_status( $this->id );
  765. return apply_filters( 'woocommerce_order_get_status', 'wc-' === substr( $this->post_status, 0, 3 ) ? substr( $this->post_status, 3 ) : $this->post_status, $this );
  766. }
  767. /**
  768. * Checks the order status against a passed in status.
  769. *
  770. * @return bool
  771. */
  772. public function has_status( $status ) {
  773. return apply_filters( 'woocommerce_order_has_status', ( is_array( $status ) && in_array( $this->get_status(), $status ) ) || $this->get_status() === $status ? true : false, $this, $status );
  774. }
  775. /**
  776. * Gets the user ID associated with the order. Guests are 0.
  777. *
  778. * @since 2.2
  779. * @return int
  780. */
  781. public function get_user_id() {
  782. return $this->customer_user ? intval( $this->customer_user ) : 0;
  783. }
  784. /**
  785. * Get the user associated with the order. False for guests.
  786. *
  787. * @since 2.2
  788. * @return WP_User|false
  789. */
  790. public function get_user() {
  791. return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
  792. }
  793. /**
  794. * Get transaction id for the order.
  795. *
  796. * @return string
  797. */
  798. public function get_transaction_id() {
  799. return get_post_meta( $this->id, '_transaction_id', true );
  800. }
  801. /**
  802. * Check if an order key is valid.
  803. *
  804. * @param mixed $key
  805. * @return bool
  806. */
  807. public function key_is_valid( $key ) {
  808. if ( $key == $this->order_key ) {
  809. return true;
  810. }
  811. return false;
  812. }
  813. /**
  814. * get_order_number function.
  815. *
  816. * Gets the order number for display (by default, order ID).
  817. *
  818. * @return string
  819. */
  820. public function get_order_number() {
  821. return apply_filters( 'woocommerce_order_number', $this->id, $this );
  822. }
  823. /**
  824. * Get a formatted billing address for the order.
  825. *
  826. * @return string
  827. */
  828. public function get_formatted_billing_address() {
  829. if ( ! $this->formatted_billing_address ) {
  830. // Formatted Addresses.
  831. $address = apply_filters( 'woocommerce_order_formatted_billing_address', array(
  832. 'first_name' => $this->billing_first_name,
  833. 'last_name' => $this->billing_last_name,
  834. 'company' => $this->billing_company,
  835. 'address_1' => $this->billing_address_1,
  836. 'address_2' => $this->billing_address_2,
  837. 'city' => $this->billing_city,
  838. 'state' => $this->billing_state,
  839. 'postcode' => $this->billing_postcode,
  840. 'country' => $this->billing_country
  841. ), $this );
  842. $this->formatted_billing_address = WC()->countries->get_formatted_address( $address );
  843. }
  844. return $this->formatted_billing_address;
  845. }
  846. /**
  847. * Get a formatted shipping address for the order.
  848. *
  849. * @return string
  850. */
  851. public function get_formatted_shipping_address() {
  852. if ( ! $this->formatted_shipping_address ) {
  853. if ( $this->shipping_address_1 || $this->shipping_address_2 ) {
  854. // Formatted Addresses
  855. $address = apply_filters( 'woocommerce_order_formatted_shipping_address', array(
  856. 'first_name' => $this->shipping_first_name,
  857. 'last_name' => $this->shipping_last_name,
  858. 'company' => $this->shipping_company,
  859. 'address_1' => $this->shipping_address_1,
  860. 'address_2' => $this->shipping_address_2,
  861. 'city' => $this->shipping_city,
  862. 'state' => $this->shipping_state,
  863. 'postcode' => $this->shipping_postcode,
  864. 'country' => $this->shipping_country
  865. ), $this );
  866. $this->formatted_shipping_address = WC()->countries->get_formatted_address( $address );
  867. }
  868. }
  869. return $this->formatted_shipping_address;
  870. }
  871. /**
  872. * Get a formatted shipping address for the order.
  873. *
  874. * @return string
  875. */
  876. public function get_shipping_address_map_url() {
  877. $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', array(
  878. 'address_1' => $this->shipping_address_1,
  879. 'address_2' => $this->shipping_address_2,
  880. 'city' => $this->shipping_city,
  881. 'state' => $this->shipping_state,
  882. 'postcode' => $this->shipping_postcode,
  883. 'country' => $this->shipping_country
  884. ), $this );
  885. return apply_filters( 'woocommerce_shipping_address_map_url', 'http://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this );
  886. }
  887. /**
  888. * Get the billing address in an array.
  889. * @deprecated 2.3
  890. * @return string
  891. */
  892. public function get_billing_address() {
  893. _deprecated_function( 'get_billing_address', '2.3', 'get_formatted_billing_address' );
  894. return $this->get_formatted_billing_address();
  895. }
  896. /**
  897. * Get the shipping address in an array.
  898. * @deprecated 2.3
  899. * @return string
  900. */
  901. public function get_shipping_address() {
  902. _deprecated_function( 'get_shipping_address', '2.3', 'get_formatted_shipping_address' );
  903. return $this->get_formatted_shipping_address();
  904. }
  905. /**
  906. * Get a formatted billing full name.
  907. *
  908. * @since 2.4.0
  909. *
  910. * @return string
  911. */
  912. public function get_formatted_billing_full_name() {
  913. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->billing_first_name, $this->billing_last_name );
  914. }
  915. /**
  916. * Get a formatted shipping full name.
  917. *
  918. * @since 2.4.0
  919. *
  920. * @return string
  921. */
  922. public function get_formatted_shipping_full_name() {
  923. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->shipping_first_name, $this->shipping_last_name );
  924. }
  925. /**
  926. * Return an array of items/products within this order.
  927. *
  928. * @param string|array $type Types of line items to get (array or string).
  929. * @return array
  930. */
  931. public function get_items( $type = '' ) {
  932. global $wpdb;
  933. if ( empty( $type ) ) {
  934. $type = array( 'line_item' );
  935. }
  936. if ( ! is_array( $type ) ) {
  937. $type = array( $type );
  938. }
  939. $items = array();
  940. $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 );
  941. $get_items_sql .= "AND order_item_type IN ( '" . implode( "','", array_map( 'esc_sql', $type ) ) . "' ) ORDER BY order_item_id;";
  942. $line_items = $wpdb->get_results( $get_items_sql );
  943. // Loop items
  944. foreach ( $line_items as $item ) {
  945. $items[ $item->order_item_id ]['name'] = $item->order_item_name;
  946. $items[ $item->order_item_id ]['type'] = $item->order_item_type;
  947. $items[ $item->order_item_id ]['item_meta'] = $this->get_item_meta( $item->order_item_id );
  948. $items[ $item->order_item_id ]['item_meta_array'] = $this->get_item_meta_array( $item->order_item_id );
  949. $items[ $item->order_item_id ] = $this->expand_item_meta( $items[ $item->order_item_id ] );
  950. }
  951. return apply_filters( 'woocommerce_order_get_items', $items, $this );
  952. }
  953. /**
  954. * Expand item meta into the $item array.
  955. * @since 2.4.0
  956. * @param array $item before expansion.
  957. * @return array
  958. */
  959. public function expand_item_meta( $item ) {
  960. // Reserved meta keys
  961. $reserved_item_meta_keys = array(
  962. 'name',
  963. 'type',
  964. 'item_meta',
  965. 'item_meta_array',
  966. 'qty',
  967. 'tax_class',
  968. 'product_id',
  969. 'variation_id',
  970. 'line_subtotal',
  971. 'line_total',
  972. 'line_tax',
  973. 'line_subtotal_tax'
  974. );
  975. // Expand item meta if set.
  976. if ( ! empty( $item['item_meta'] ) ) {
  977. foreach ( $item['item_meta'] as $name => $value ) {
  978. if ( in_array( $name, $reserved_item_meta_keys ) ) {
  979. continue;
  980. }
  981. if ( '_' === substr( $name, 0, 1 ) ) {
  982. $item[ substr( $name, 1 ) ] = $value[0];
  983. } elseif ( ! in_array( $name, $reserved_item_meta_keys ) ) {
  984. $item[ $name ] = make_clickable( $value[0] );
  985. }
  986. }
  987. }
  988. return $item;
  989. }
  990. /**
  991. * Gets the count of order items of a certain type.
  992. *
  993. * @param string $item_type
  994. * @return string
  995. */
  996. public function get_item_count( $item_type = '' ) {
  997. if ( empty( $item_type ) ) {
  998. $item_type = array( 'line_item' );
  999. }
  1000. if ( ! is_array( $item_type ) ) {
  1001. $item_type = array( $item_type );
  1002. }
  1003. $items = $this->get_items( $item_type );
  1004. $count = 0;
  1005. foreach ( $items as $item ) {
  1006. $count += empty( $item['qty'] ) ? 1 : $item['qty'];
  1007. }
  1008. return apply_filters( 'woocommerce_get_item_count', $count, $item_type, $this );
  1009. }
  1010. /**
  1011. * Get refunds
  1012. * @return array
  1013. */
  1014. public function get_refunds() { return array(); }
  1015. /**
  1016. * Return an array of fees within this order.
  1017. *
  1018. * @return array
  1019. */
  1020. public function get_fees() {
  1021. return $this->get_items( 'fee' );
  1022. }
  1023. /**
  1024. * Return an array of taxes within this order.
  1025. *
  1026. * @return array
  1027. */
  1028. public function get_taxes() {
  1029. return $this->get_items( 'tax' );
  1030. }
  1031. /**
  1032. * Return an array of shipping costs within this order.
  1033. *
  1034. * @return array
  1035. */
  1036. public function get_shipping_methods() {
  1037. return $this->get_items( 'shipping' );
  1038. }
  1039. /**
  1040. * Check whether this order has a specific shipping method or not.
  1041. *
  1042. * @param string $method_id
  1043. *
  1044. * @return bool
  1045. */
  1046. public function has_shipping_method( $method_id ) {
  1047. $shipping_methods = $this->get_shipping_methods();
  1048. $has_method = false;
  1049. if ( empty( $shipping_methods ) ) {
  1050. return false;
  1051. }
  1052. foreach ( $shipping_methods as $shipping_method ) {
  1053. if ( $shipping_method['method_id'] == $method_id ) {
  1054. $has_method = true;
  1055. }
  1056. }
  1057. return $has_method;
  1058. }
  1059. /**
  1060. * Get taxes, merged by code, formatted ready for output.
  1061. *
  1062. * @return array
  1063. */
  1064. public function get_tax_totals() {
  1065. $taxes = $this->get_items( 'tax' );
  1066. $tax_totals = array();
  1067. foreach ( $taxes as $key => $tax ) {
  1068. $code = $tax[ 'name' ];
  1069. if ( ! isset( $tax_totals[ $code ] ) ) {
  1070. $tax_totals[ $code ] = new stdClass();
  1071. $tax_totals[ $code ]->amount = 0;
  1072. }
  1073. $tax_totals[ $code ]->id = $key;
  1074. $tax_totals[ $code ]->rate_id = $tax['rate_id'];
  1075. $tax_totals[ $code ]->is_compound = $tax[ 'compound' ];
  1076. $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
  1077. $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
  1078. $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) );
  1079. }
  1080. return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this );
  1081. }
  1082. /**
  1083. * has_meta function for order items.
  1084. *
  1085. * @param string $order_item_id
  1086. * @return array of meta data.
  1087. */
  1088. public function has_meta( $order_item_id ) {
  1089. global $wpdb;
  1090. return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
  1091. FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
  1092. ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
  1093. }
  1094. /**
  1095. * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
  1096. *
  1097. * @param mixed $order_item_id
  1098. * @return array of objects
  1099. */
  1100. public function get_item_meta_array( $order_item_id ) {
  1101. global $wpdb;
  1102. // Get cache key - uses get_cache_prefix to invalidate when needed
  1103. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'item_meta_array_' . $order_item_id;
  1104. $item_meta_array = wp_cache_get( $cache_key, 'orders' );
  1105. if ( false === $item_meta_array ) {
  1106. $item_meta_array = array();
  1107. $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 ) ) );
  1108. foreach ( $metadata as $metadata_row ) {
  1109. $item_meta_array[ $metadata_row->meta_id ] = (object) array( 'key' => $metadata_row->meta_key, 'value' => $metadata_row->meta_value );
  1110. }
  1111. wp_cache_set( $cache_key, $item_meta_array, 'orders' );
  1112. }
  1113. return $item_meta_array ;
  1114. }
  1115. /**
  1116. * Display meta data belonging to an item.
  1117. * @param array $item
  1118. */
  1119. public function display_item_meta( $item ) {
  1120. $product = $this->get_product_from_item( $item );
  1121. $item_meta = new WC_Order_Item_Meta( $item, $product );
  1122. $item_meta->display();
  1123. }
  1124. /**
  1125. * Get order item meta.
  1126. *
  1127. * @param mixed $order_item_id
  1128. * @param string $key (default: '')
  1129. * @param bool $single (default: false)
  1130. * @return array|string
  1131. */
  1132. public function get_item_meta( $order_item_id, $key = '', $single = false ) {
  1133. return get_metadata( 'order_item', $order_item_id, $key, $single );
  1134. }
  1135. /** Total Getters *******************************************************/
  1136. /**
  1137. * Gets the total discount amount.
  1138. * @param bool $ex_tax Show discount excl any tax.
  1139. * @return float
  1140. */
  1141. public function get_total_discount( $ex_tax = true ) {
  1142. if ( ! $this->order_version || version_compare( $this->order_version, '2.3.7', '<' ) ) {
  1143. // Backwards compatible total calculation - totals were not stored consistently in old versions.
  1144. if ( $ex_tax ) {
  1145. if ( $this->prices_include_tax ) {
  1146. $total_discount = (double) $this->cart_discount - (double) $this->cart_discount_tax;
  1147. } else {
  1148. $total_discount = (double) $this->cart_discount;
  1149. }
  1150. } else {
  1151. if ( $this->prices_include_tax ) {
  1152. $total_discount = (double) $this->cart_discount;
  1153. } else {
  1154. $total_discount = (double) $this->cart_discount + (double) $this->cart_discount_tax;
  1155. }
  1156. }
  1157. // New logic - totals are always stored exclusive of tax, tax total is stored in cart_discount_tax
  1158. } else {
  1159. if ( $ex_tax ) {
  1160. $total_discount = (double) $this->cart_discount;
  1161. } else {
  1162. $total_discount = (double) $this->cart_discount + (double) $this->cart_discount_tax;
  1163. }
  1164. }
  1165. return apply_filters( 'woocommerce_order_amount_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this );
  1166. }
  1167. /**
  1168. * Gets the discount amount.
  1169. * @deprecated in favour of get_total_discount() since we now only have one discount type.
  1170. * @return float
  1171. */
  1172. public function get_cart_discount() {
  1173. _deprecated_function( 'get_cart_discount', '2.3', 'get_total_discount' );
  1174. return apply_filters( 'woocommerce_order_amount_cart_discount', $this->get_total_discount(), $this );
  1175. }
  1176. /**
  1177. * Get cart discount (formatted).
  1178. *
  1179. * @deprecated order (after tax) discounts removed in 2.3.0.
  1180. * @return string
  1181. */
  1182. public function get_order_discount_to_display() {
  1183. _deprecated_function( 'get_order_discount_to_display', '2.3' );
  1184. }
  1185. /**
  1186. * Gets the total (order) discount amount - these are applied after tax.
  1187. *
  1188. * @deprecated order (after tax) discounts removed in 2.3.0.
  1189. * @return float
  1190. */
  1191. public function get_order_discount() {
  1192. _deprecated_function( 'get_order_discount', '2.3' );
  1193. return apply_filters( 'woocommerce_order_amount_order_discount', (double) $this->order_discount, $this );
  1194. }
  1195. /**
  1196. * Gets cart tax amount.
  1197. *
  1198. * @return float
  1199. */
  1200. public function get_cart_tax() {
  1201. return apply_filters( 'woocommerce_order_amount_cart_tax', (double) $this->order_tax, $this );
  1202. }
  1203. /**
  1204. * Gets shipping tax amount.
  1205. *
  1206. * @return float
  1207. */
  1208. public function get_shipping_tax() {
  1209. return apply_filters( 'woocommerce_order_amount_shipping_tax', (double) $this->order_shipping_tax, $this );
  1210. }
  1211. /**
  1212. * Gets shipping and product tax.
  1213. *
  1214. * @return float
  1215. */
  1216. public function get_total_tax() {
  1217. return apply_filters( 'woocommerce_order_amount_total_tax', wc_round_tax_total( $this->get_cart_tax() + $this->get_shipping_tax() ), $this );
  1218. }
  1219. /**
  1220. * Gets shipping total.
  1221. *
  1222. * @return float
  1223. */
  1224. public function get_total_shipping() {
  1225. return apply_filters( 'woocommerce_order_amount_total_shipping', (double) $this->order_shipping, $this );
  1226. }
  1227. /**
  1228. * Gets order total.
  1229. *
  1230. * @return float
  1231. */
  1232. public function get_total() {
  1233. return apply_filters( 'woocommerce_order_amount_total', (double) $this->order_total, $this );
  1234. }
  1235. /**
  1236. * Gets order subtotal.
  1237. *
  1238. * @return mixed|void
  1239. */
  1240. public function get_subtotal() {
  1241. $subtotal = 0;
  1242. foreach ( $this->get_items() as $item ) {
  1243. $subtotal += ( isset( $item['line_subtotal'] ) ) ? $item['line_subtotal'] : 0;
  1244. }
  1245. return apply_filters( 'woocommerce_order_amount_subtotal', (double) $subtotal, $this );
  1246. }
  1247. /**
  1248. * Get item subtotal - this is the cost before discount.
  1249. *
  1250. * @param mixed $item
  1251. * @param bool $inc_tax (default: false).
  1252. * @param bool $round (default: true).
  1253. * @return float
  1254. */
  1255. public function get_item_subtotal( $item, $inc_tax = false, $round = true ) {
  1256. if ( $inc_tax ) {
  1257. $price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / max( 1, $item['qty'] );
  1258. } else {
  1259. $price = ( $item['line_subtotal'] / max( 1, $item['qty'] ) );
  1260. }
  1261. $price = $round ? number_format( (float) $price, wc_get_price_decimals(), '.', '' ) : $price;
  1262. return apply_filters( 'woocommerce_order_amount_item_subtotal', $price, $this, $item, $inc_tax, $round );
  1263. }
  1264. /**
  1265. * Get line subtotal - this is the cost before discount.
  1266. *
  1267. * @param mixed $item
  1268. * @param bool $inc_tax (default: false).
  1269. * @param bool $round (default: true).
  1270. * @return float
  1271. */
  1272. public function get_line_subtotal( $item, $inc_tax = false, $round = true ) {
  1273. if ( $inc_tax ) {
  1274. $price = $item['line_subtotal'] + $item['line_subtotal_tax'];
  1275. } else {
  1276. $price = $item['line_subtotal'];
  1277. }
  1278. $price = $round ? round( $price, wc_get_price_decimals() ) : $price;
  1279. return apply_filters( 'woocommerce_order_amount_line_subtotal', $price, $this, $item, $inc_tax, $round );
  1280. }
  1281. /**
  1282. * Calculate item cost - useful for gateways.
  1283. *
  1284. * @param mixed $item
  1285. * @param bool $inc_tax (default: false).
  1286. * @param bool $round (default: true).
  1287. * @return float
  1288. */
  1289. public function get_item_total( $item, $inc_tax = false, $round = true ) {
  1290. $qty = ( ! empty( $item['qty'] ) ) ? $item['qty'] : 1;
  1291. if ( $inc_tax ) {
  1292. $price = ( $item['line_total'] + $item['line_tax'] ) / max( 1, $qty );
  1293. } else {
  1294. $price = $item['line_total'] / max( 1, $qty );
  1295. }
  1296. $price = $round ? round( $price, wc_get_price_decimals() ) : $price;
  1297. return apply_filters( 'woocommerce_order_amount_item_total', $price, $this, $item, $inc_tax, $round );
  1298. }
  1299. /**
  1300. * Calculate line total - useful for gateways.
  1301. *
  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_line_total( $item, $inc_tax = false, $round = true ) {
  1308. // Check if we need to add line tax to the line total.
  1309. $line_total = $inc_tax ? $item['line_total'] + $item['line_tax'] : $item['line_total'];
  1310. // Check if we need to round.
  1311. $line_total = $round ? round( $line_total, wc_get_price_decimals() ) : $line_total;
  1312. return apply_filters( 'woocommerce_order_amount_line_total', $line_total, $this, $item, $inc_tax, $round );
  1313. }
  1314. /**
  1315. * Calculate item tax - useful for gateways.
  1316. *
  1317. * @param mixed $item
  1318. * @param bool $round (default: true).
  1319. * @return float
  1320. */
  1321. public function get_item_tax( $item, $round = true ) {
  1322. $price = $item['line_tax'] / max( 1, $item['qty'] );
  1323. $price = $round ? wc_round_tax_total( $price ) : $price;
  1324. return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this );
  1325. }
  1326. /**
  1327. * Calculate line tax - useful for gateways.
  1328. *
  1329. * @param mixed $item
  1330. * @return float
  1331. */
  1332. public function get_line_tax( $item ) {
  1333. return apply_filters( 'woocommerce_order_amount_line_tax', wc_round_tax_total( $item['line_tax'] ), $item, $this );
  1334. }
  1335. /** End Total Getters *******************************************************/
  1336. /**
  1337. * Gets formatted shipping method title.
  1338. *
  1339. * @return string
  1340. *