/includes/class-wc-order.php

  1. <?php 
  2.  
  3. if ( ! defined( 'ABSPATH' ) ) { 
  4. exit; 
  5.  
  6. /** 
  7. * Order Class. 
  8. * 
  9. * These are regular WooCommerce orders, which extend the abstract order class. 
  10. * 
  11. * @class WC_Order 
  12. * @version 2.2.0 
  13. * @package WooCommerce/Classes 
  14. * @category Class 
  15. * @author WooThemes 
  16. */ 
  17. class WC_Order extends WC_Abstract_Order { 
  18.  
  19. /** 
  20. * Stores data about status changes so relevant hooks can be fired. 
  21. * @var bool|array 
  22. */ 
  23. protected $status_transition = false; 
  24.  
  25. /** 
  26. * Order Data array. This is the core order data exposed in APIs since 3.0.0. 
  27. * @since 3.0.0 
  28. * @var array 
  29. */ 
  30. protected $data = array( 
  31. // Abstract order props 
  32. 'parent_id' => 0,  
  33. 'status' => '',  
  34. 'currency' => '',  
  35. 'version' => '',  
  36. 'prices_include_tax' => false,  
  37. 'date_created' => null,  
  38. 'date_modified' => null,  
  39. 'discount_total' => 0,  
  40. 'discount_tax' => 0,  
  41. 'shipping_total' => 0,  
  42. 'shipping_tax' => 0,  
  43. 'cart_tax' => 0,  
  44. 'total' => 0,  
  45. 'total_tax' => 0,  
  46.  
  47. // Order props 
  48. 'customer_id' => 0,  
  49. 'order_key' => '',  
  50. 'billing' => array( 
  51. 'first_name' => '',  
  52. 'last_name' => '',  
  53. 'company' => '',  
  54. 'address_1' => '',  
  55. 'address_2' => '',  
  56. 'city' => '',  
  57. 'state' => '',  
  58. 'postcode' => '',  
  59. 'country' => '',  
  60. 'email' => '',  
  61. 'phone' => '',  
  62. ),  
  63. 'shipping' => array( 
  64. 'first_name' => '',  
  65. 'last_name' => '',  
  66. 'company' => '',  
  67. 'address_1' => '',  
  68. 'address_2' => '',  
  69. 'city' => '',  
  70. 'state' => '',  
  71. 'postcode' => '',  
  72. 'country' => '',  
  73. ),  
  74. 'payment_method' => '',  
  75. 'payment_method_title' => '',  
  76. 'transaction_id' => '',  
  77. 'customer_ip_address' => '',  
  78. 'customer_user_agent' => '',  
  79. 'created_via' => '',  
  80. 'customer_note' => '',  
  81. 'date_completed' => null,  
  82. 'date_paid' => null,  
  83. 'cart_hash' => '',  
  84. ); 
  85.  
  86. /** 
  87. * When a payment is complete this function is called. 
  88. * 
  89. * Most of the time this should mark an order as 'processing' so that admin can process/post the items. 
  90. * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action. 
  91. * Stock levels are reduced at this point. 
  92. * Sales are also recorded for products. 
  93. * Finally, record the date of payment. 
  94. * 
  95. * Order must exist. 
  96. * 
  97. * @param string $transaction_id Optional transaction id to store in post meta. 
  98. * @return bool success 
  99. */ 
  100. public function payment_complete( $transaction_id = '' ) { 
  101. try { 
  102. if ( ! $this->get_id() ) { 
  103. return false; 
  104. do_action( 'woocommerce_pre_payment_complete', $this->get_id() ); 
  105.  
  106. if ( ! empty( WC()->session ) ) { 
  107. WC()->session->set( 'order_awaiting_payment', false ); 
  108.  
  109. if ( $this->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed', 'cancelled' ), $this ) ) ) { 
  110. if ( ! empty( $transaction_id ) ) { 
  111. $this->set_transaction_id( $transaction_id ); 
  112. if ( ! $this->get_date_paid( 'edit' ) ) { 
  113. $this->set_date_paid( current_time( 'timestamp', true ) ); 
  114. $this->set_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) ); 
  115. $this->save(); 
  116.  
  117. do_action( 'woocommerce_payment_complete', $this->get_id() ); 
  118. } else { 
  119. do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->get_id() ); 
  120. } catch ( Exception $e ) { 
  121. return false; 
  122. return true; 
  123.  
  124. /** 
  125. * Gets order total - formatted for display. 
  126. * 
  127. * @param string $tax_display Type of tax display. 
  128. * @param bool $display_refunded If should include refunded value. 
  129. * 
  130. * @return string 
  131. */ 
  132. public function get_formatted_order_total( $tax_display = '', $display_refunded = true ) { 
  133. $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_currency() ) ); 
  134. $order_total = $this->get_total(); 
  135. $total_refunded = $this->get_total_refunded(); 
  136. $tax_string = ''; 
  137.  
  138. // Tax for inclusive prices. 
  139. if ( wc_tax_enabled() && 'incl' == $tax_display ) { 
  140. $tax_string_array = array(); 
  141.  
  142. if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) { 
  143. foreach ( $this->get_tax_totals() as $code => $tax ) { 
  144. $tax_amount = ( $total_refunded && $display_refunded ) ? wc_price( WC_Tax::round( $tax->amount - $this->get_total_tax_refunded_by_rate_id( $tax->rate_id ) ), array( 'currency' => $this->get_currency() ) ) : $tax->formatted_amount; 
  145. $tax_string_array[] = sprintf( '%s %s', $tax_amount, $tax->label ); 
  146. } else { 
  147. $tax_amount = ( $total_refunded && $display_refunded ) ? $this->get_total_tax() - $this->get_total_tax_refunded() : $this->get_total_tax(); 
  148. $tax_string_array[] = sprintf( '%s %s', wc_price( $tax_amount, array( 'currency' => $this->get_currency() ) ), WC()->countries->tax_or_vat() ); 
  149. if ( ! empty( $tax_string_array ) ) { 
  150. $tax_string = ' <small class="includes_tax">' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) ) . '</small>'; 
  151.  
  152. if ( $total_refunded && $display_refunded ) { 
  153. $formatted_total = '<del>' . strip_tags( $formatted_total ) . '</del> <ins>' . wc_price( $order_total - $total_refunded, array( 'currency' => $this->get_currency() ) ) . $tax_string . '</ins>'; 
  154. } else { 
  155. $formatted_total .= $tax_string; 
  156.  
  157. /** 
  158. * Filter WooCommerce formatted order total. 
  159. * 
  160. * @param string $formatted_total Total to display. 
  161. * @param WC_Order $order Order data. 
  162. * @param string $tax_display Type of tax display. 
  163. * @param bool $display_refunded If should include refunded value. 
  164. */ 
  165. return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this, $tax_display, $display_refunded ); 
  166.  
  167. /** 
  168. |-------------------------------------------------------------------------- 
  169. | CRUD methods 
  170. |-------------------------------------------------------------------------- 
  171. | 
  172. | Methods which create, read, update and delete orders from the database. 
  173. | Written in abstract fashion so that the way orders are stored can be 
  174. | changed more easily in the future. 
  175. | 
  176. | A save method is included for convenience (chooses update or create based 
  177. | on if the order exists yet). 
  178. | 
  179. */ 
  180.  
  181. /** 
  182. * Save data to the database. 
  183. * 
  184. * @since 3.0.0 
  185. * @return int order ID 
  186. */ 
  187. public function save() { 
  188. $this->maybe_set_user_billing_email(); 
  189. if ( $this->data_store ) { 
  190. // Trigger action before saving to the DB. Allows you to adjust object props before save. 
  191. do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); 
  192.  
  193. if ( $this->get_id() ) { 
  194. $this->data_store->update( $this ); 
  195. } else { 
  196. $this->data_store->create( $this ); 
  197. $this->save_items(); 
  198. $this->status_transition(); 
  199. return $this->get_id(); 
  200.  
  201. /** 
  202. * Set order status. 
  203. * @since 3.0.0 
  204. * @param string $new_status Status to change the order to. No internal wc- prefix is required. 
  205. * @param string $note (default: '') Optional note to add. 
  206. * @param bool $manual_update is this a manual order status change? 
  207. * @param array details of change 
  208. */ 
  209. public function set_status( $new_status, $note = '', $manual_update = false ) { 
  210. $result = parent::set_status( $new_status ); 
  211.  
  212. if ( true === $this->object_read && ! empty( $result['from'] ) && $result['from'] !== $result['to'] ) { 
  213. $this->status_transition = array( 
  214. 'from' => ! empty( $this->status_transition['from'] ) ? $this->status_transition['from'] : $result['from'],  
  215. 'to' => $result['to'],  
  216. 'note' => $note,  
  217. 'manual' => (bool) $manual_update,  
  218. ); 
  219.  
  220. $this->maybe_set_date_paid(); 
  221. $this->maybe_set_date_completed(); 
  222.  
  223. return $result; 
  224.  
  225. /** 
  226. * Maybe set date paid. 
  227. * 
  228. * Sets the date paid variable when transitioning to the payment complete 
  229. * order status. This is either processing or completed. This is not filtered 
  230. * to avoid infinite loops e.g. if loading an order via the filter. 
  231. * 
  232. * Date paid is set once in this manner - only when it is not already set. 
  233. * This ensures the data exists even if a gateway does not use the 
  234. * `payment_complete` method. 
  235. * 
  236. * @since 3.0.0 
  237. */ 
  238. public function maybe_set_date_paid() { 
  239. if ( ! $this->get_date_paid( 'edit' ) && $this->has_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) ) ) { 
  240. $this->set_date_paid( current_time( 'timestamp' ) ); 
  241.  
  242. /** 
  243. * Maybe set date completed. 
  244. * 
  245. * Sets the date completed variable when transitioning to completed status. 
  246. * 
  247. * @since 3.0.0 
  248. */ 
  249. protected function maybe_set_date_completed() { 
  250. if ( $this->has_status( 'completed' ) ) { 
  251. $this->set_date_completed( current_time( 'timestamp', true ) ); 
  252.  
  253. /** 
  254. * Updates status of order immediately. Order must exist. 
  255. * @uses WC_Order::set_status() 
  256. * @return bool success 
  257. */ 
  258. public function update_status( $new_status, $note = '', $manual = false ) { 
  259. try { 
  260. if ( ! $this->get_id() ) { 
  261. return false; 
  262. $this->set_status( $new_status, $note, $manual ); 
  263. $this->save(); 
  264. } catch ( Exception $e ) { 
  265. return false; 
  266. return true; 
  267.  
  268. /** 
  269. * Handle the status transition. 
  270. */ 
  271. protected function status_transition() { 
  272. if ( $this->status_transition ) { 
  273. do_action( 'woocommerce_order_status_' . $this->status_transition['to'], $this->get_id(), $this ); 
  274.  
  275. if ( ! empty( $this->status_transition['from'] ) ) { 
  276. /** translators: 1: old order status 2: new order status */ 
  277. $transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $this->status_transition['from'] ), wc_get_order_status_name( $this->status_transition['to'] ) ); 
  278.  
  279. do_action( 'woocommerce_order_status_' . $this->status_transition['from'] . '_to_' . $this->status_transition['to'], $this->get_id(), $this ); 
  280. do_action( 'woocommerce_order_status_changed', $this->get_id(), $this->status_transition['from'], $this->status_transition['to'], $this ); 
  281. } else { 
  282. /** translators: %s: new order status */ 
  283. $transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $this->status_transition['to'] ) ); 
  284.  
  285. // Note the transition occurred 
  286. $this->add_order_note( trim( $this->status_transition['note'] . ' ' . $transition_note ), 0, $this->status_transition['manual'] ); 
  287.  
  288. // This has ran, so reset status transition variable 
  289. $this->status_transition = false; 
  290.  
  291. /** 
  292. |-------------------------------------------------------------------------- 
  293. | Getters 
  294. |-------------------------------------------------------------------------- 
  295. | 
  296. | Methods for getting data from the order object. 
  297. | 
  298. */ 
  299.  
  300. /** 
  301. * Get all class data in array format. 
  302. * @since 3.0.0 
  303. * @return array 
  304. */ 
  305. public function get_data() { 
  306. return array_merge( 
  307. array( 
  308. 'id' => $this->get_id(),  
  309. ),  
  310. $this->data,  
  311. array( 
  312. 'number' => $this->get_order_number(),  
  313. 'meta_data' => $this->get_meta_data(),  
  314. 'line_items' => $this->get_items( 'line_item' ),  
  315. 'tax_lines' => $this->get_items( 'tax' ),  
  316. 'shipping_lines' => $this->get_items( 'shipping' ),  
  317. 'fee_lines' => $this->get_items( 'fee' ),  
  318. 'coupon_lines' => $this->get_items( 'coupon' ),  
  319. ); 
  320.  
  321. /** 
  322. * Expands the shipping and billing information in the changes array. 
  323. */ 
  324. public function get_changes() { 
  325. $changed_props = parent::get_changes(); 
  326. $subs = array( 'shipping', 'billing' ); 
  327. foreach ( $subs as $sub ) { 
  328. if ( ! empty( $changed_props[ $sub ] ) ) { 
  329. foreach ( $changed_props[ $sub ] as $sub_prop => $value ) { 
  330. $changed_props[ $sub . '_' . $sub_prop ] = $value; 
  331. if ( isset( $changed_props['customer_note'] ) ) { 
  332. $changed_props['post_excerpt'] = $changed_props['customer_note']; 
  333. return $changed_props; 
  334.  
  335. /** 
  336. * get_order_number function. 
  337. * 
  338. * Gets the order number for display (by default, order ID). 
  339. * 
  340. * @return string 
  341. */ 
  342. public function get_order_number() { 
  343. return (string) apply_filters( 'woocommerce_order_number', $this->get_id(), $this ); 
  344.  
  345. /** 
  346. * Get order key. 
  347. * 
  348. * @since 3.0.0 
  349. * @param string $context 
  350. * @return string 
  351. */ 
  352. public function get_order_key( $context = 'view' ) { 
  353. return $this->get_prop( 'order_key', $context ); 
  354.  
  355. /** 
  356. * Get customer_id. 
  357. * 
  358. * @param string $context 
  359. * @return int 
  360. */ 
  361. public function get_customer_id( $context = 'view' ) { 
  362. return $this->get_prop( 'customer_id', $context ); 
  363.  
  364. /** 
  365. * Alias for get_customer_id(). 
  366. * 
  367. * @param string $context 
  368. * @return int 
  369. */ 
  370. public function get_user_id( $context = 'view' ) { 
  371. return $this->get_customer_id( $context ); 
  372.  
  373. /** 
  374. * Get the user associated with the order. False for guests. 
  375. * 
  376. * @return WP_User|false 
  377. */ 
  378. public function get_user() { 
  379. return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false; 
  380.  
  381. /** 
  382. * Gets a prop for a getter method. 
  383. * 
  384. * @since 3.0.0 
  385. * @param string $prop Name of prop to get. 
  386. * @param string $address billing or shipping. 
  387. * @param string $context What the value is for. Valid values are view and edit. 
  388. * @return mixed 
  389. */ 
  390. protected function get_address_prop( $prop, $address = 'billing', $context = 'view' ) { 
  391. $value = null; 
  392.  
  393. if ( array_key_exists( $prop, $this->data[ $address ] ) ) { 
  394. $value = isset( $this->changes[ $address ][ $prop ] ) ? $this->changes[ $address ][ $prop ] : $this->data[ $address ][ $prop ]; 
  395.  
  396. if ( 'view' === $context ) { 
  397. $value = apply_filters( $this->get_hook_prefix() . $address . '_' . $prop, $value, $this ); 
  398. return $value; 
  399.  
  400. /** 
  401. * Get billing_first_name. 
  402. * 
  403. * @param string $context 
  404. * @return string 
  405. */ 
  406. public function get_billing_first_name( $context = 'view' ) { 
  407. return $this->get_address_prop( 'first_name', 'billing', $context ); 
  408.  
  409. /** 
  410. * Get billing_last_name. 
  411. * 
  412. * @param string $context 
  413. * @return string 
  414. */ 
  415. public function get_billing_last_name( $context = 'view' ) { 
  416. return $this->get_address_prop( 'last_name', 'billing', $context ); 
  417.  
  418. /** 
  419. * Get billing_company. 
  420. * 
  421. * @param string $context 
  422. * @return string 
  423. */ 
  424. public function get_billing_company( $context = 'view' ) { 
  425. return $this->get_address_prop( 'company', 'billing', $context ); 
  426.  
  427. /** 
  428. * Get billing_address_1. 
  429. * 
  430. * @param string $context 
  431. * @return string 
  432. */ 
  433. public function get_billing_address_1( $context = 'view' ) { 
  434. return $this->get_address_prop( 'address_1', 'billing', $context ); 
  435.  
  436. /** 
  437. * Get billing_address_2. 
  438. * 
  439. * @param string $context 
  440. * @return string $value 
  441. */ 
  442. public function get_billing_address_2( $context = 'view' ) { 
  443. return $this->get_address_prop( 'address_2', 'billing', $context ); 
  444.  
  445. /** 
  446. * Get billing_city. 
  447. * 
  448. * @param string $context 
  449. * @return string $value 
  450. */ 
  451. public function get_billing_city( $context = 'view' ) { 
  452. return $this->get_address_prop( 'city', 'billing', $context ); 
  453.  
  454. /** 
  455. * Get billing_state. 
  456. * 
  457. * @param string $context 
  458. * @return string 
  459. */ 
  460. public function get_billing_state( $context = 'view' ) { 
  461. return $this->get_address_prop( 'state', 'billing', $context ); 
  462.  
  463. /** 
  464. * Get billing_postcode. 
  465. * 
  466. * @param string $context 
  467. * @return string 
  468. */ 
  469. public function get_billing_postcode( $context = 'view' ) { 
  470. return $this->get_address_prop( 'postcode', 'billing', $context ); 
  471.  
  472. /** 
  473. * Get billing_country. 
  474. * 
  475. * @param string $context 
  476. * @return string 
  477. */ 
  478. public function get_billing_country( $context = 'view' ) { 
  479. return $this->get_address_prop( 'country', 'billing', $context ); 
  480.  
  481. /** 
  482. * Get billing_email. 
  483. * 
  484. * @param string $context 
  485. * @return string 
  486. */ 
  487. public function get_billing_email( $context = 'view' ) { 
  488. return $this->get_address_prop( 'email', 'billing', $context ); 
  489.  
  490. /** 
  491. * Get billing_phone. 
  492. * 
  493. * @param string $context 
  494. * @return string 
  495. */ 
  496. public function get_billing_phone( $context = 'view' ) { 
  497. return $this->get_address_prop( 'phone', 'billing', $context ); 
  498.  
  499. /** 
  500. * Get shipping_first_name. 
  501. * 
  502. * @param string $context 
  503. * @return string 
  504. */ 
  505. public function get_shipping_first_name( $context = 'view' ) { 
  506. return $this->get_address_prop( 'first_name', 'shipping', $context ); 
  507.  
  508. /** 
  509. * Get shipping_last_name. 
  510. * 
  511. * @param string $context 
  512. * @return string 
  513. */ 
  514. public function get_shipping_last_name( $context = 'view' ) { 
  515. return $this->get_address_prop( 'last_name', 'shipping', $context ); 
  516.  
  517. /** 
  518. * Get shipping_company. 
  519. * 
  520. * @param string $context 
  521. * @return string 
  522. */ 
  523. public function get_shipping_company( $context = 'view' ) { 
  524. return $this->get_address_prop( 'company', 'shipping', $context ); 
  525.  
  526. /** 
  527. * Get shipping_address_1. 
  528. * 
  529. * @param string $context 
  530. * @return string 
  531. */ 
  532. public function get_shipping_address_1( $context = 'view' ) { 
  533. return $this->get_address_prop( 'address_1', 'shipping', $context ); 
  534.  
  535. /** 
  536. * Get shipping_address_2. 
  537. * 
  538. * @param string $context 
  539. * @return string 
  540. */ 
  541. public function get_shipping_address_2( $context = 'view' ) { 
  542. return $this->get_address_prop( 'address_2', 'shipping', $context ); 
  543.  
  544. /** 
  545. * Get shipping_city. 
  546. * 
  547. * @param string $context 
  548. * @return string 
  549. */ 
  550. public function get_shipping_city( $context = 'view' ) { 
  551. return $this->get_address_prop( 'city', 'shipping', $context ); 
  552.  
  553. /** 
  554. * Get shipping_state. 
  555. * 
  556. * @param string $context 
  557. * @return string 
  558. */ 
  559. public function get_shipping_state( $context = 'view' ) { 
  560. return $this->get_address_prop( 'state', 'shipping', $context ); 
  561.  
  562. /** 
  563. * Get shipping_postcode. 
  564. * 
  565. * @param string $context 
  566. * @return string 
  567. */ 
  568. public function get_shipping_postcode( $context = 'view' ) { 
  569. return $this->get_address_prop( 'postcode', 'shipping', $context ); 
  570.  
  571. /** 
  572. * Get shipping_country. 
  573. * 
  574. * @param string $context 
  575. * @return string 
  576. */ 
  577. public function get_shipping_country( $context = 'view' ) { 
  578. return $this->get_address_prop( 'country', 'shipping', $context ); 
  579.  
  580. /** 
  581. * Get the payment method. 
  582. * 
  583. * @param string $context 
  584. * @return string 
  585. */ 
  586. public function get_payment_method( $context = 'view' ) { 
  587. return $this->get_prop( 'payment_method', $context ); 
  588.  
  589. /** 
  590. * Get payment_method_title. 
  591. * 
  592. * @param string $context 
  593. * @return string 
  594. */ 
  595. public function get_payment_method_title( $context = 'view' ) { 
  596. return $this->get_prop( 'payment_method_title', $context ); 
  597.  
  598. /** 
  599. * Get transaction_id. 
  600. * 
  601. * @param string $context 
  602. * @return string 
  603. */ 
  604. public function get_transaction_id( $context = 'view' ) { 
  605. return $this->get_prop( 'transaction_id', $context ); 
  606.  
  607. /** 
  608. * Get customer_ip_address. 
  609. * 
  610. * @param string $context 
  611. * @return string 
  612. */ 
  613. public function get_customer_ip_address( $context = 'view' ) { 
  614. return $this->get_prop( 'customer_ip_address', $context ); 
  615.  
  616. /** 
  617. * Get customer_user_agent. 
  618. * 
  619. * @param string $context 
  620. * @return string 
  621. */ 
  622. public function get_customer_user_agent( $context = 'view' ) { 
  623. return $this->get_prop( 'customer_user_agent', $context ); 
  624.  
  625. /** 
  626. * Get created_via. 
  627. * 
  628. * @param string $context 
  629. * @return string 
  630. */ 
  631. public function get_created_via( $context = 'view' ) { 
  632. return $this->get_prop( 'created_via', $context ); 
  633.  
  634. /** 
  635. * Get customer_note. 
  636. * 
  637. * @param string $context 
  638. * @return string 
  639. */ 
  640. public function get_customer_note( $context = 'view' ) { 
  641. return $this->get_prop( 'customer_note', $context ); 
  642.  
  643. /** 
  644. * Get date_completed. 
  645. * 
  646. * @param string $context 
  647. * @return WC_DateTime|NULL object if the date is set or null if there is no date. 
  648. */ 
  649. public function get_date_completed( $context = 'view' ) { 
  650. return $this->get_prop( 'date_completed', $context ); 
  651.  
  652. /** 
  653. * Get date_paid. 
  654. * 
  655. * @param string $context 
  656. * @return WC_DateTime|NULL object if the date is set or null if there is no date. 
  657. */ 
  658. public function get_date_paid( $context = 'view' ) { 
  659. $date_paid = $this->get_prop( 'date_paid', $context ); 
  660.  
  661. if ( 'view' === $context && ! $date_paid && version_compare( $this->get_version( 'edit' ), '3.0', '<' ) && $this->has_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) ) ) { 
  662. // In view context, return a date if missing. 
  663. $date_paid = $this->get_date_created( 'edit' ); 
  664. return $date_paid; 
  665.  
  666. /** 
  667. * Get cart hash. 
  668. * 
  669. * @param string $context 
  670. * @return string 
  671. */ 
  672. public function get_cart_hash( $context = 'view' ) { 
  673. return $this->get_prop( 'cart_hash', $context ); 
  674.  
  675. /** 
  676. * Returns the requested address in raw, non-formatted way. 
  677. * Note: Merges raw data with get_prop data so changes are returned too. 
  678. * 
  679. * @since 2.4.0 
  680. * @param string $type Billing or shipping. Anything else besides 'billing' will return shipping address. 
  681. * @return array The stored address after filter. 
  682. */ 
  683. public function get_address( $type = 'billing' ) { 
  684. return apply_filters( 'woocommerce_get_order_address', array_merge( $this->data[ $type ], $this->get_prop( $type, 'view' ) ), $type, $this ); 
  685.  
  686. /** 
  687. * Get a formatted shipping address for the order. 
  688. * 
  689. * @return string 
  690. */ 
  691. public function get_shipping_address_map_url() { 
  692. $address = $this->get_address( 'shipping' ); 
  693.  
  694. // Remove name and company before generate the Google Maps URL. 
  695. unset( $address['first_name'], $address['last_name'], $address['company'] ); 
  696.  
  697. $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', $address, $this ); 
  698.  
  699. return apply_filters( 'woocommerce_shipping_address_map_url', 'https://maps.google.com/maps?&q=' . urlencode( implode( ', ', $address ) ) . '&z=16', $this ); 
  700.  
  701. /** 
  702. * Get a formatted billing full name. 
  703. * 
  704. * @return string 
  705. */ 
  706. public function get_formatted_billing_full_name() { 
  707. /** translators: 1: first name 2: last name */ 
  708. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_billing_first_name(), $this->get_billing_last_name() ); 
  709.  
  710. /** 
  711. * Get a formatted shipping full name. 
  712. * 
  713. * @return string 
  714. */ 
  715. public function get_formatted_shipping_full_name() { 
  716. /** translators: 1: first name 2: last name */ 
  717. return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_shipping_first_name(), $this->get_shipping_last_name() ); 
  718.  
  719. /** 
  720. * Get a formatted billing address for the order. 
  721. * 
  722. * @return string 
  723. */ 
  724. public function get_formatted_billing_address() { 
  725. return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this ) ); 
  726.  
  727. /** 
  728. * Get a formatted shipping address for the order. 
  729. * 
  730. * @return string 
  731. */ 
  732. public function get_formatted_shipping_address() { 
  733. if ( $this->has_shipping_address() ) { 
  734. return WC()->countries->get_formatted_address( apply_filters( 'woocommerce_order_formatted_shipping_address', $this->get_address( 'shipping' ), $this ) ); 
  735. } else { 
  736. return ''; 
  737.  
  738. /** 
  739. * Returns true if the order has a shipping address. 
  740. * 
  741. * @since 3.0.4 
  742. * @return boolean 
  743. */ 
  744. public function has_shipping_address() { 
  745. return $this->get_shipping_address_1() || $this->get_shipping_address_2(); 
  746.  
  747. /** 
  748. |-------------------------------------------------------------------------- 
  749. | Setters 
  750. |-------------------------------------------------------------------------- 
  751. | 
  752. | Functions for setting order data. These should not update anything in the 
  753. | database itself and should only change what is stored in the class 
  754. | object. However, for backwards compatibility pre 3.0.0 some of these 
  755. | setters may handle both. 
  756. | 
  757. */ 
  758.  
  759. /** 
  760. * Sets a prop for a setter method. 
  761. * 
  762. * @since 3.0.0 
  763. * @param string $prop Name of prop to set. 
  764. * @param string $address Name of address to set. billing or shipping. 
  765. * @param mixed $value Value of the prop. 
  766. */ 
  767. protected function set_address_prop( $prop, $address = 'billing', $value ) { 
  768. if ( array_key_exists( $prop, $this->data[ $address ] ) ) { 
  769. if ( true === $this->object_read ) { 
  770. if ( $value !== $this->data[ $address ][ $prop ] || ( isset( $this->changes[ $address ] ) && array_key_exists( $prop, $this->changes[ $address ] ) ) ) { 
  771. $this->changes[ $address ][ $prop ] = $value; 
  772. } else { 
  773. $this->data[ $address ][ $prop ] = $value; 
  774.  
  775. /** 
  776. * Set order_key. 
  777. * 
  778. * @param string $value Max length 22 chars. 
  779. * @throws WC_Data_Exception 
  780. */ 
  781. public function set_order_key( $value ) { 
  782. $this->set_prop( 'order_key', substr( $value, 0, 22 ) ); 
  783.  
  784. /** 
  785. * Set customer_id. 
  786. * 
  787. * @param int $value 
  788. * @throws WC_Data_Exception 
  789. */ 
  790. public function set_customer_id( $value ) { 
  791. $this->set_prop( 'customer_id', absint( $value ) ); 
  792.  
  793. /** 
  794. * Set billing_first_name. 
  795. * 
  796. * @param string $value 
  797. * @throws WC_Data_Exception 
  798. */ 
  799. public function set_billing_first_name( $value ) { 
  800. $this->set_address_prop( 'first_name', 'billing', $value ); 
  801.  
  802. /** 
  803. * Set billing_last_name. 
  804. * 
  805. * @param string $value 
  806. * @throws WC_Data_Exception 
  807. */ 
  808. public function set_billing_last_name( $value ) { 
  809. $this->set_address_prop( 'last_name', 'billing', $value ); 
  810.  
  811. /** 
  812. * Set billing_company. 
  813. * 
  814. * @param string $value 
  815. * @throws WC_Data_Exception 
  816. */ 
  817. public function set_billing_company( $value ) { 
  818. $this->set_address_prop( 'company', 'billing', $value ); 
  819.  
  820. /** 
  821. * Set billing_address_1. 
  822. * 
  823. * @param string $value 
  824. * @throws WC_Data_Exception 
  825. */ 
  826. public function set_billing_address_1( $value ) { 
  827. $this->set_address_prop( 'address_1', 'billing', $value ); 
  828.  
  829. /** 
  830. * Set billing_address_2. 
  831. * 
  832. * @param string $value 
  833. * @throws WC_Data_Exception 
  834. */ 
  835. public function set_billing_address_2( $value ) { 
  836. $this->set_address_prop( 'address_2', 'billing', $value ); 
  837.  
  838. /** 
  839. * Set billing_city. 
  840. * 
  841. * @param string $value 
  842. * @throws WC_Data_Exception 
  843. */ 
  844. public function set_billing_city( $value ) { 
  845. $this->set_address_prop( 'city', 'billing', $value ); 
  846.  
  847. /** 
  848. * Set billing_state. 
  849. * 
  850. * @param string $value 
  851. * @throws WC_Data_Exception 
  852. */ 
  853. public function set_billing_state( $value ) { 
  854. $this->set_address_prop( 'state', 'billing', $value ); 
  855.  
  856. /** 
  857. * Set billing_postcode. 
  858. * 
  859. * @param string $value 
  860. * @throws WC_Data_Exception 
  861. */ 
  862. public function set_billing_postcode( $value ) { 
  863. $this->set_address_prop( 'postcode', 'billing', $value ); 
  864.  
  865. /** 
  866. * Set billing_country. 
  867. * 
  868. * @param string $value 
  869. * @throws WC_Data_Exception 
  870. */ 
  871. public function set_billing_country( $value ) { 
  872. $this->set_address_prop( 'country', 'billing', $value ); 
  873.  
  874. /** 
  875. * Maybe set empty billing email to that of the user who owns the order. 
  876. */ 
  877. protected function maybe_set_user_billing_email() { 
  878. if ( ! $this->get_billing_email() && ( $user = $this->get_user() ) ) { 
  879. try { 
  880. $this->set_billing_email( $user->user_email ); 
  881. } catch( WC_Data_Exception $e ) { 
  882. unset( $e ); 
  883.  
  884. /** 
  885. * Set billing_email. 
  886. * 
  887. * @param string $value 
  888. * @throws WC_Data_Exception 
  889. */ 
  890. public function set_billing_email( $value ) { 
  891. if ( $value && ! is_email( $value ) ) { 
  892. $this->error( 'order_invalid_billing_email', __( 'Invalid billing email address', 'woocommerce' ) ); 
  893. $this->set_address_prop( 'email', 'billing', sanitize_email( $value ) ); 
  894.  
  895. /** 
  896. * Set billing_phone. 
  897. * 
  898. * @param string $value 
  899. * @throws WC_Data_Exception 
  900. */ 
  901. public function set_billing_phone( $value ) { 
  902. $this->set_address_prop( 'phone', 'billing', $value ); 
  903.  
  904. /** 
  905. * Set shipping_first_name. 
  906. * 
  907. * @param string $value 
  908. * @throws WC_Data_Exception 
  909. */ 
  910. public function set_shipping_first_name( $value ) { 
  911. $this->set_address_prop( 'first_name', 'shipping', $value ); 
  912.  
  913. /** 
  914. * Set shipping_last_name. 
  915. * 
  916. * @param string $value 
  917. * @throws WC_Data_Exception 
  918. */ 
  919. public function set_shipping_last_name( $value ) { 
  920. $this->set_address_prop( 'last_name', 'shipping', $value ); 
  921.  
  922. /** 
  923. * Set shipping_company. 
  924. * 
  925. * @param string $value 
  926. * @throws WC_Data_Exception 
  927. */ 
  928. public function set_shipping_company( $value ) { 
  929. $this->set_address_prop( 'company', 'shipping', $value ); 
  930.  
  931. /** 
  932. * Set shipping_address_1. 
  933. * 
  934. * @param string $value 
  935. * @throws WC_Data_Exception 
  936. */ 
  937. public function set_shipping_address_1( $value ) { 
  938. $this->set_address_prop( 'address_1', 'shipping', $value ); 
  939.  
  940. /** 
  941. * Set shipping_address_2. 
  942. * 
  943. * @param string $value 
  944. * @throws WC_Data_Exception 
  945. */ 
  946. public function set_shipping_address_2( $value ) { 
  947. $this->set_address_prop( 'address_2', 'shipping', $value ); 
  948.  
  949. /** 
  950. * Set shipping_city. 
  951. * 
  952. * @param string $value 
  953. * @throws WC_Data_Exception 
  954. */ 
  955. public function set_shipping_city( $value ) { 
  956. $this->set_address_prop( 'city', 'shipping', $value ); 
  957.  
  958. /** 
  959. * Set shipping_state. 
  960. * 
  961. * @param string $value 
  962. * @throws WC_Data_Exception 
  963. */ 
  964. public function set_shipping_state( $value ) { 
  965. $this->set_address_prop( 'state', 'shipping', $value ); 
  966.  
  967. /** 
  968. * Set shipping_postcode. 
  969. * 
  970. * @param string $value 
  971. * @throws WC_Data_Exception 
  972. */ 
  973. public function set_shipping_postcode( $value ) { 
  974. $this->set_address_prop( 'postcode', 'shipping', $value ); 
  975.  
  976. /** 
  977. * Set shipping_country. 
  978. * 
  979. * @param string $value 
  980. * @throws WC_Data_Exception 
  981. */ 
  982. public function set_shipping_country( $value ) { 
  983. $this->set_address_prop( 'country', 'shipping', $value ); 
  984.  
  985. /** 
  986. * Set the payment method. 
  987. * 
  988. * @param string $payment_method Supports WC_Payment_Gateway for bw compatibility with < 3.0 
  989. * @throws WC_Data_Exception 
  990. */ 
  991. public function set_payment_method( $payment_method = '' ) { 
  992. if ( is_object( $payment_method ) ) { 
  993. $this->set_payment_method( $payment_method->id ); 
  994. $this->set_payment_method_title( $payment_method->get_title() ); 
  995. } elseif ( '' === $payment_method ) { 
  996. $this->set_prop( 'payment_method', '' ); 
  997. $this->set_prop( 'payment_method_title', '' ); 
  998. } else { 
  999. $this->set_prop( 'payment_method', $payment_method ); 
  1000.  
  1001. /** 
  1002. * Set payment_method_title. 
  1003. * 
  1004. * @param string $value 
  1005. * @throws WC_Data_Exception 
  1006. */ 
  1007. public function set_payment_method_title( $value ) { 
  1008. $this->set_prop( 'payment_method_title', $value ); 
  1009.  
  1010. /** 
  1011. * Set transaction_id. 
  1012. * 
  1013. * @param string $value 
  1014. * @throws WC_Data_Exception 
  1015. */ 
  1016. public function set_transaction_id( $value ) { 
  1017. $this->set_prop( 'transaction_id', $value ); 
  1018.  
  1019. /** 
  1020. * Set customer_ip_address. 
  1021. * 
  1022. * @param string $value 
  1023. * @throws WC_Data_Exception 
  1024. */ 
  1025. public function set_customer_ip_address( $value ) { 
  1026. $this->set_prop( 'customer_ip_address', $value ); 
  1027.  
  1028. /** 
  1029. * Set customer_user_agent. 
  1030. * 
  1031. * @param string $value 
  1032. * @throws WC_Data_Exception 
  1033. */ 
  1034. public function set_customer_user_agent( $value ) { 
  1035. $this->set_prop( 'customer_user_agent', $value ); 
  1036.  
  1037. /** 
  1038. * Set created_via. 
  1039. * 
  1040. * @param string $value 
  1041. * @throws WC_Data_Exception 
  1042. */ 
  1043. public function set_created_via( $value ) { 
  1044. $this->set_prop( 'created_via', $value ); 
  1045.  
  1046. /** 
  1047. * Set customer_note. 
  1048. * 
  1049. * @param string $value 
  1050. * @throws WC_Data_Exception 
  1051. */ 
  1052. public function set_customer_note( $value ) { 
  1053. $this->set_prop( 'customer_note', $value ); 
  1054.  
  1055. /** 
  1056. * Set date_completed. 
  1057. * 
  1058. * @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. 
  1059. * @throws WC_Data_Exception 
  1060. */ 
  1061. public function set_date_completed( $date = null ) { 
  1062. $this->set_date_prop( 'date_completed', $date ); 
  1063.  
  1064. /** 
  1065. * Set date_paid. 
  1066. * 
  1067. * @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. 
  1068. * @throws WC_Data_Exception 
  1069. */ 
  1070. public function set_date_paid( $date = null ) { 
  1071. $this->set_date_prop( 'date_paid', $date ); 
  1072.  
  1073. /** 
  1074. * Set cart hash. 
  1075. * 
  1076. * @param string $value 
  1077. * @throws WC_Data_Exception 
  1078. */ 
  1079. public function set_cart_hash( $value ) { 
  1080. $this->set_prop( 'cart_hash', $value ); 
  1081.  
  1082. /** 
  1083. |-------------------------------------------------------------------------- 
  1084. | Conditionals 
  1085. |-------------------------------------------------------------------------- 
  1086. | 
  1087. | Checks if a condition is true or false. 
  1088. | 
  1089. */ 
  1090.  
  1091. /** 
  1092. * Check if an order key is valid. 
  1093. * 
  1094. * @param mixed $key 
  1095. * @return bool 
  1096. */ 
  1097. public function key_is_valid( $key ) { 
  1098. return $key === $this->get_order_key(); 
  1099.  
  1100. /** 
  1101. * See if order matches cart_hash. 
  1102. * @return bool 
  1103. */ 
  1104. public function has_cart_hash( $cart_hash = '' ) { 
  1105. return hash_equals( $this->get_cart_hash(), $cart_hash ); 
  1106.  
  1107. /** 
  1108. * Checks if an order can be edited, specifically for use on the Edit Order screen. 
  1109. * @return bool 
  1110. */ 
  1111. public function is_editable() { 
  1112. return apply_filters( 'wc_order_is_editable', in_array( $this->get_status(), array( 'pending', 'on-hold', 'auto-draft' ) ), $this ); 
  1113.  
  1114. /** 
  1115. * Returns if an order has been paid for based on the order status. 
  1116. * @since 2.5.0 
  1117. * @return bool 
  1118. */ 
  1119. public function is_paid() { 
  1120. return apply_filters( 'woocommerce_order_is_paid', $this->has_status( wc_get_is_paid_statuses() ), $this ); 
  1121.  
  1122. /** 
  1123. * Checks if product download is permitted. 
  1124. * 
  1125. * @return bool 
  1126. */ 
  1127. public function is_download_permitted() { 
  1128. return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( 'yes' === get_option( 'woocommerce_downloads_grant_access_after_payment' ) && $this->has_status( 'processing' ) ), $this ); 
  1129.  
  1130. /** 
  1131. * Checks if an order needs display the shipping address, based on shipping method. 
  1132. * @return bool 
  1133. */ 
  1134. public function needs_shipping_address() { 
  1135. if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) { 
  1136. return false; 
  1137.  
  1138. $hide = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this ); 
  1139. $needs_address = false; 
  1140.  
  1141. foreach ( $this->get_shipping_methods() as $shipping_method ) { 
  1142. // Remove any instance IDs after : 
  1143. $shipping_method_id = current( explode( ':', $shipping_method['method_id'] ) ); 
  1144.  
  1145. if ( ! in_array( $shipping_method_id, $hide ) ) { 
  1146. $needs_address = true; 
  1147. break; 
  1148.  
  1149. return apply_filters( 'woocommerce_order_needs_shipping_address', $needs_address, $hide, $this ); 
  1150.  
  1151. /** 
  1152. * Returns true if the order contains a downloadable product. 
  1153. * @return bool 
  1154. */ 
  1155. public function has_downloadable_item() { 
  1156. foreach ( $this->get_items() as $item ) { 
  1157. if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) && $product->is_downloadable() && $product->has_file() ) { 
  1158. return true; 
  1159. return false; 
  1160.  
  1161. /** 
  1162. * Checks if an order needs payment, based on status and order total. 
  1163. * 
  1164. * @return bool 
  1165. */ 
  1166. public function needs_payment() { 
  1167. $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ); 
  1168. return apply_filters( 'woocommerce_order_needs_payment', ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ), $this, $valid_order_statuses ); 
  1169.  
  1170. /** 
  1171. * See if the order needs processing before it can be completed. 
  1172. * 
  1173. * Orders which only contain virtual, downloadable items do not need admin 
  1174. * intervention. 
  1175. * 
  1176. * @since 3.0.0 
  1177. * @return bool 
  1178. */ 
  1179. public function needs_processing() { 
  1180. $needs_processing = false; 
  1181.  
  1182. if ( sizeof( $this->get_items() ) > 0 ) { 
  1183. foreach ( $this->get_items() as $item ) { 
  1184. if ( $item->is_type( 'line_item' ) && ( $product = $item->get_product() ) ) { 
  1185. $virtual_downloadable_item = $product->is_downloadable() && $product->is_virtual(); 
  1186.  
  1187. if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $product, $this->get_id() ) ) { 
  1188. $needs_processing = true; 
  1189. break; 
  1190.  
  1191. return $needs_processing; 
  1192.  
  1193. /** 
  1194. |-------------------------------------------------------------------------- 
  1195. | URLs and Endpoints 
  1196. |-------------------------------------------------------------------------- 
  1197. */ 
  1198.  
  1199. /** 
  1200. * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices. 
  1201. * 
  1202. * @param bool $on_checkout 
  1203. * @return string 
  1204. */ 
  1205. public function get_checkout_payment_url( $on_checkout = false ) { 
  1206. $pay_url = wc_get_endpoint_url( 'order-pay', $this->get_id(), wc_get_page_permalink( 'checkout' ) ); 
  1207.  
  1208. if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { 
  1209. $pay_url = str_replace( 'http:', 'https:', $pay_url ); 
  1210.  
  1211. if ( $on_checkout ) { 
  1212. $pay_url = add_query_arg( 'key', $this->get_order_key(), $pay_url ); 
  1213. } else { 
  1214. $pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->get_order_key() ), $pay_url ); 
  1215.  
  1216. return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this ); 
  1217.  
  1218. /** 
  1219. * Generates a URL for the thanks page (order received). 
  1220. * 
  1221. * @return string 
  1222. */ 
  1223. public function get_checkout_order_received_url() { 
  1224. $order_received_url = wc_get_endpoint_url( 'order-received', $this->get_id(), wc_get_page_permalink( 'checkout' ) ); 
  1225.  
  1226. if ( 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) { 
  1227. $order_received_url = str_replace( 'http:', 'https:', $order_received_url ); 
  1228.  
  1229. $order_received_url = add_query_arg( 'key', $this->get_order_key(), $order_received_url ); 
  1230.  
  1231. return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this ); 
  1232.  
  1233. /** 
  1234. * Generates a URL so that a customer can cancel their (unpaid - pending) order. 
  1235. * 
  1236. * @param string $redirect 
  1237. * 
  1238. * @return string 
  1239. */ 
  1240. public function get_cancel_order_url( $redirect = '' ) { 
  1241. return apply_filters( 'woocommerce_get_cancel_order_url', wp_nonce_url( add_query_arg( array( 
  1242. 'cancel_order' => 'true',  
  1243. 'order' => $this->get_order_key(),  
  1244. 'order_id' => $this->get_id(),  
  1245. 'redirect' => $redirect,  
  1246. ), $this->get_cancel_endpoint() ), 'woocommerce-cancel_order' ) ); 
  1247.  
  1248. /** 
  1249. * Generates a raw (unescaped) cancel-order URL for use by payment gateways. 
  1250. * 
  1251. * @param string $redirect 
  1252. * 
  1253. * @return string The unescaped cancel-order URL. 
  1254. */ 
  1255. public function get_cancel_order_url_raw( $redirect = '' ) { 
  1256. return apply_filters( 'woocommerce_get_cancel_order_url_raw', add_query_arg( array( 
  1257. 'cancel_order' => 'true',  
  1258. 'order' => $this->get_order_key(),  
  1259. 'order_id' => $this->get_id(),  
  1260. 'redirect' => $redirect,  
  1261. '_wpnonce' => wp_create_nonce( 'woocommerce-cancel_order' ),  
  1262. ), $this->get_cancel_endpoint() ) ); 
  1263.  
  1264. /** 
  1265. * Helper method to return the cancel endpoint. 
  1266. * 
  1267. * @return string the cancel endpoint; either the cart page or the home page. 
  1268. */ 
  1269. public function get_cancel_endpoint() { 
  1270. $cancel_endpoint = wc_get_page_permalink( 'cart' ); 
  1271. if ( ! $cancel_endpoint ) { 
  1272. $cancel_endpoint = home_url(); 
  1273.  
  1274. if ( false === strpos( $cancel_endpoint, '?' ) ) { 
  1275. $cancel_endpoint = trailingslashit( $cancel_endpoint ); 
  1276.  
  1277. return $cancel_endpoint; 
  1278.  
  1279. /** 
  1280. * Generates a URL to view an order from the my account page. 
  1281. * 
  1282. * @return string 
  1283. */ 
  1284. public function get_view_order_url() { 
  1285. return apply_filters( 'woocommerce_get_view_order_url', wc_get_endpoint_url( 'view-order', $this->get_id(), wc_get_page_permalink( 'myaccount' ) ), $this ); 
  1286.  
  1287. /** 
  1288. |-------------------------------------------------------------------------- 
  1289. | Order notes. 
  1290. |-------------------------------------------------------------------------- 
  1291. */ 
  1292.  
  1293. /** 
  1294. * Adds a note (comment) to the order. Order must exist. 
  1295. * 
  1296. * @param string $note Note to add. 
  1297. * @param int $is_customer_note (default: 0) Is this a note for the customer? 
  1298. * @param bool added_by_user Was the note added by a user? 
  1299. * @return int Comment ID. 
  1300. */ 
  1301. public function add_order_note( $note, $is_customer_note = 0, $added_by_user = false ) { 
  1302. if ( ! $this->get_id() ) { 
  1303. return 0; 
  1304.  
  1305. if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->get_id() ) && $added_by_user ) { 
  1306. $user = get_user_by( 'id', get_current_user_id() ); 
  1307. $comment_author = $user->display_name; 
  1308. $comment_author_email = $user->user_email; 
  1309. } else { 
  1310. $comment_author = __( 'WooCommerce', 'woocommerce' ); 
  1311. $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@'; 
  1312. $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com'; 
  1313. $comment_author_email = sanitize_email( $comment_author_email ); 
  1314. $commentdata = apply_filters( 'woocommerce_new_order_note_data', array( 
  1315. 'comment_post_ID' => $this->get_id(),  
  1316. 'comment_author' => $comment_author,  
  1317. 'comment_author_email' => $comment_author_email,  
  1318. 'comment_author_url' => '',  
  1319. 'comment_content' => $note,  
  1320. 'comment_agent' => 'WooCommerce',  
  1321. 'comment_type' => 'order_note',  
  1322. 'comment_parent' => 0,  
  1323. 'comment_approved' => 1,  
  1324. ), array( 'order_id' => $this->get_id(), 'is_customer_note' => $is_customer_note ) ); 
  1325.  
  1326. $comment_id = wp_insert_comment( $commentdata ); 
  1327.  
  1328. if ( $is_customer_note ) { 
  1329. add_comment_meta( $comment_id, 'is_customer_note', 1 ); 
  1330.  
  1331. do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->get_id(), 'customer_note' => $commentdata['comment_content'] ) ); 
  1332.  
  1333. return $comment_id; 
  1334.  
  1335. /** 
  1336. * List order notes (public) for the customer. 
  1337. * 
  1338. * @return array 
  1339. */ 
  1340. public function get_customer_order_notes() { 
  1341. $notes = array(); 
  1342. $args = array( 
  1343. 'post_id' => $this->get_id(),  
  1344. 'approve' => 'approve',  
  1345. 'type' => '',  
  1346. ); 
  1347.  
  1348. remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); 
  1349.  
  1350. $comments = get_comments( $args ); 
  1351.  
  1352. foreach ( $comments as $comment ) { 
  1353. if ( ! get_comment_meta( $comment->comment_ID, 'is_customer_note', true ) ) { 
  1354. continue; 
  1355. $comment->comment_content = make_clickable( $comment->comment_content ); 
  1356. $notes[] = $comment; 
  1357.  
  1358. add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) ); 
  1359.  
  1360. return $notes; 
  1361.  
  1362. /** 
  1363. |-------------------------------------------------------------------------- 
  1364. | Refunds 
  1365. |-------------------------------------------------------------------------- 
  1366. */ 
  1367.  
  1368. /** 
  1369. * Get order refunds. 
  1370. * 
  1371. * @since 2.2 
  1372. * @return array of WC_Order_Refund objects 
  1373. */ 
  1374. public function get_refunds() { 
  1375. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'refunds' . $this->get_id(); 
  1376. $cached_data = wp_cache_get( $cache_key, $this->cache_group ); 
  1377.  
  1378. if ( false !== $cached_data ) { 
  1379. return $cached_data; 
  1380.  
  1381. $this->refunds = wc_get_orders( array( 
  1382. 'type' => 'shop_order_refund',  
  1383. 'parent' => $this->get_id(),  
  1384. 'limit' => -1,  
  1385. ) ); 
  1386.  
  1387. wp_cache_set( $cache_key, $this->refunds, $this->cache_group ); 
  1388.  
  1389. return $this->refunds; 
  1390.  
  1391. /** 
  1392. * Get amount already refunded. 
  1393. * 
  1394. * @since 2.2 
  1395. * @return string 
  1396. */ 
  1397. public function get_total_refunded() { 
  1398. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_refunded' . $this->get_id(); 
  1399. $cached_data = wp_cache_get( $cache_key, $this->cache_group ); 
  1400.  
  1401. if ( false !== $cached_data ) { 
  1402. return $cached_data; 
  1403.  
  1404. $total_refunded = $this->data_store->get_total_refunded( $this ); 
  1405.  
  1406. wp_cache_set( $cache_key, $total_refunded, $this->cache_group ); 
  1407.  
  1408. return $total_refunded; 
  1409.  
  1410. /** 
  1411. * Get the total tax refunded. 
  1412. * 
  1413. * @since 2.3 
  1414. * @return float 
  1415. */ 
  1416. public function get_total_tax_refunded() { 
  1417. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_tax_refunded' . $this->get_id(); 
  1418. $cached_data = wp_cache_get( $cache_key, $this->cache_group ); 
  1419.  
  1420. if ( false !== $cached_data ) { 
  1421. return $cached_data; 
  1422.  
  1423. $total_refunded = $this->data_store->get_total_tax_refunded( $this ); 
  1424.  
  1425. wp_cache_set( $cache_key, $total_refunded, $this->cache_group ); 
  1426.  
  1427. return $total_refunded; 
  1428.  
  1429. /** 
  1430. * Get the total shipping refunded. 
  1431. * 
  1432. * @since 2.4 
  1433. * @return float 
  1434. */ 
  1435. public function get_total_shipping_refunded() { 
  1436. $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_shipping_refunded' . $this->get_id(); 
  1437. $cached_data = wp_cache_get( $cache_key, $this->cache_group ); 
  1438.  
  1439. if ( false !== $cached_data ) { 
  1440. return $cached_data; 
  1441.  
  1442. $total_refunded = $this->data_store->get_total_shipping_refunded( $this ); 
  1443.  
  1444. wp_cache_set( $cache_key, $total_refunded, $this->cache_group ); 
  1445.  
  1446. return $total_refunded; 
  1447.  
  1448. /** 
  1449. * Gets the count of order items of a certain type that have been refunded. 
  1450. * @since 2.4.0 
  1451. * @param string $item_type 
  1452. * @return string 
  1453. */ 
  1454. public function get_item_count_refunded( $item_type = '' ) { 
  1455. if ( empty( $item_type ) ) { 
  1456. $item_type = array( 'line_item' ); 
  1457. if ( ! is_array( $item_type ) ) { 
  1458. $item_type = array( $item_type ); 
  1459. $count = 0; 
  1460.  
  1461. foreach ( $this->get_refunds() as $refund ) { 
  1462. foreach ( $refund->get_items( $item_type ) as $refunded_item ) { 
  1463. $count += abs( $refunded_item->get_quantity() ); 
  1464.  
  1465. return apply_filters( 'woocommerce_get_item_count_refunded', $count, $item_type, $this ); 
  1466.  
  1467. /** 
  1468. * Get the total number of items refunded. 
  1469. * 
  1470. * @since 2.4.0 
  1471. * @param string $item_type type of the item we're checking, if not a line_item 
  1472. * @return integer 
  1473. */ 
  1474. public function get_total_qty_refunded( $item_type = 'line_item' ) { 
  1475. $qty = 0; 
  1476. foreach ( $this->get_refunds() as $refund ) { 
  1477. foreach ( $refund->get_items( $item_type ) as $refunded_item ) { 
  1478. $qty += $refunded_item->get_quantity(); 
  1479. return $qty; 
  1480.  
  1481. /** 
  1482. * Get the refunded amount for a line item. 
  1483. * 
  1484. * @param int $item_id ID of the item we're checking 
  1485. * @param string $item_type type of the item we're checking, if not a line_item 
  1486. * @return integer 
  1487. */ 
  1488. public function get_qty_refunded_for_item( $item_id, $item_type = 'line_item' ) { 
  1489. $qty = 0; 
  1490. foreach ( $this->get_refunds() as $refund ) { 
  1491. foreach ( $refund->get_items( $item_type ) as $refunded_item ) { 
  1492. if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) { 
  1493. $qty += $refunded_item->get_quantity(); 
  1494. return $qty; 
  1495.  
  1496. /** 
  1497. * Get the refunded amount for a line item. 
  1498. * 
  1499. * @param int $item_id ID of the item we're checking 
  1500. * @param string $item_type type of the item we're checking, if not a line_item 
  1501. * @return integer 
  1502. */ 
  1503. public function get_total_refunded_for_item( $item_id, $item_type = 'line_item' ) { 
  1504. $total = 0; 
  1505. foreach ( $this->get_refunds() as $refund ) { 
  1506. foreach ( $refund->get_items( $item_type ) as $refunded_item ) { 
  1507. if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) { 
  1508. $total += $refunded_item->get_total(); 
  1509. return $total * -1; 
  1510.  
  1511. /** 
  1512. * Get the refunded tax amount for a line item. 
  1513. * 
  1514. * @param int $item_id ID of the item we're checking 
  1515. * @param int $tax_id ID of the tax we're checking 
  1516. * @param string $item_type type of the item we're checking, if not a line_item 
  1517. * @return double 
  1518. */ 
  1519. public function get_tax_refunded_for_item( $item_id, $tax_id, $item_type = 'line_item' ) { 
  1520. $total = 0; 
  1521. foreach ( $this->get_refunds() as $refund ) { 
  1522. foreach ( $refund->get_items( $item_type ) as $refunded_item ) { 
  1523. $refunded_item_id = (int) $refunded_item->get_meta( '_refunded_item_id' ); 
  1524. if ( $refunded_item_id === $item_id ) { 
  1525. $taxes = $refunded_item->get_taxes(); 
  1526. $total += isset( $taxes['total'][ $tax_id ] ) ? $taxes['total'][ $tax_id ] : 0; 
  1527. break; 
  1528. return wc_round_tax_total( $total ) * -1; 
  1529.  
  1530. /** 
  1531. * Get total tax refunded by rate ID. 
  1532. * 
  1533. * @param int $rate_id 
  1534. * 
  1535. * @return float 
  1536. */ 
  1537. public function get_total_tax_refunded_by_rate_id( $rate_id ) { 
  1538. $total = 0; 
  1539. foreach ( $this->get_refunds() as $refund ) { 
  1540. foreach ( $refund->get_items( 'tax' ) as $refunded_item ) { 
  1541. if ( absint( $refunded_item->get_rate_id() ) === $rate_id ) { 
  1542. $total += abs( $refunded_item->get_tax_total() ) + abs( $refunded_item->get_shipping_tax_total() ); 
  1543.  
  1544. return $total; 
  1545.  
  1546. /** 
  1547. * How much money is left to refund? 
  1548. * @return string 
  1549. */ 
  1550. public function get_remaining_refund_amount() { 
  1551. return wc_format_decimal( $this->get_total() - $this->get_total_refunded(), wc_get_price_decimals() ); 
  1552.  
  1553. /** 
  1554. * How many items are left to refund? 
  1555. * @return int 
  1556. */ 
  1557. public function get_remaining_refund_items() { 
  1558. return absint( $this->get_item_count() - $this->get_item_count_refunded() ); 
  1559.  
  1560. /** 
  1561. * Add total row for the payment method. 
  1562. * 
  1563. * @param array $total_rows 
  1564. * @param string $tax_display 
  1565. */ 
  1566. protected function add_order_item_totals_payment_method_row( &$total_rows, $tax_display ) { 
  1567. if ( $this->get_total() > 0 && $this->get_payment_method_title() ) { 
  1568. $total_rows['payment_method'] = array( 
  1569. 'label' => __( 'Payment method:', 'woocommerce' ),  
  1570. 'value' => $this->get_payment_method_title(),  
  1571. ); 
  1572.  
  1573. /** 
  1574. * Add total row for refunds. 
  1575. * 
  1576. * @param array $total_rows 
  1577. * @param string $tax_display 
  1578. */ 
  1579. protected function add_order_item_totals_refund_rows( &$total_rows, $tax_display ) { 
  1580. if ( $refunds = $this->get_refunds() ) { 
  1581. foreach ( $refunds as $id => $refund ) { 
  1582. $total_rows[ 'refund_' . $id ] = array( 
  1583. 'label' => $refund->get_reason() ? $refund->get_reason() : __( 'Refund', 'woocommerce' ) . ':',  
  1584. 'value' => wc_price( '-' . $refund->get_amount(), array( 'currency' => $this->get_currency() ) ),  
  1585. ); 
  1586.  
  1587. /** 
  1588. * Get totals for display on pages and in emails. 
  1589. * 
  1590. * @param mixed $tax_display 
  1591. * @return array 
  1592. */ 
  1593. public function get_order_item_totals( $tax_display = '' ) { 
  1594. $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); 
  1595. $total_rows = array(); 
  1596.  
  1597. $this->add_order_item_totals_subtotal_row( $total_rows, $tax_display ); 
  1598. $this->add_order_item_totals_discount_row( $total_rows, $tax_display ); 
  1599. $this->add_order_item_totals_shipping_row( $total_rows, $tax_display ); 
  1600. $this->add_order_item_totals_fee_rows( $total_rows, $tax_display ); 
  1601. $this->add_order_item_totals_tax_rows( $total_rows, $tax_display ); 
  1602. $this->add_order_item_totals_payment_method_row( $total_rows, $tax_display ); 
  1603. $this->add_order_item_totals_refund_rows( $total_rows, $tax_display ); 
  1604. $this->add_order_item_totals_total_row( $total_rows, $tax_display ); 
  1605.  
  1606. return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this, $tax_display ); 
.