1 <?php
2 3 4 5 6 7 8 9 10 11 12
13 class WC_Order {
14
15
16 public $id;
17
18 19 20 21 22 23 24
25 public function __construct( $id = '' ) {
26 $this->prices_include_tax = get_option('woocommerce_prices_include_tax') == 'yes' ? true : false;
27 $this->tax_display_cart = get_option( 'woocommerce_tax_display_cart' );
28
29 $this->display_totals_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
30 $this->display_cart_ex_tax = $this->tax_display_cart == 'excl' ? true : false;
31
32 if ( $id > 0 ) {
33 $this->get_order( $id );
34 }
35 }
36
37
38 39 40 41 42 43 44
45 public function get_order( $id = 0 ) {
46 if ( ! $id ) {
47 return false;
48 }
49 if ( $result = get_post( $id ) ) {
50 $this->populate( $result );
51 return true;
52 }
53 return false;
54 }
55
56
57 58 59 60 61 62 63
64 public function populate( $result ) {
65
66 $this->id = $result->ID;
67 $this->order_date = $result->post_date;
68 $this->modified_date = $result->post_modified;
69 $this->customer_message = $result->post_excerpt;
70 $this->customer_note = $result->post_excerpt;
71 $this->post_status = $result->post_status;
72
73
74 if ( empty( $this->billing_email ) && ! empty( $this->customer_user ) ) {
75 $user = get_user_by( 'id', $this->customer_user );
76 $this->billing_email = $user->user_email;
77 }
78
79
80 $terms = wp_get_object_terms( $this->id, 'shop_order_status', array( 'fields' => 'slugs' ) );
81 $this->status = isset( $terms[0] ) ? $terms[0] : apply_filters( 'woocommerce_default_order_status', 'pending' );
82 }
83
84 85 86 87 88 89 90
91 public function __isset( $key ) {
92 if ( ! $this->id ) {
93 return false;
94 }
95 return metadata_exists( 'post', $this->id, '_' . $key );
96 }
97
98 99 100 101 102 103 104
105 public function __get( $key ) {
106
107 if ( 'completed_date' == $key ) {
108 $value = ( $value = get_post_meta( $this->id, '_completed_date', true ) ) ? $value : $this->modified_date;
109 } elseif ( 'user_id' == $key ) {
110 $value = ( $value = get_post_meta( $this->id, '_customer_user', true ) ) ? absint( $value ) : '';
111 } else {
112 $value = get_post_meta( $this->id, '_' . $key, true );
113 }
114
115 return $value;
116 }
117
118 119 120 121 122 123 124
125 public function key_is_valid( $key ) {
126 if ( $key == $this->order_key ) {
127 return true;
128 }
129
130 return false;
131 }
132
133 134 135 136 137 138 139 140
141 public function get_order_number() {
142 return apply_filters( 'woocommerce_order_number', _x( '#', 'hash before order number', 'woocommerce' ) . $this->id, $this );
143 }
144
145 146 147 148 149 150
151 public function get_formatted_billing_address() {
152 if ( ! $this->formatted_billing_address ) {
153
154
155 $address = apply_filters( 'woocommerce_order_formatted_billing_address', array(
156 'first_name' => $this->billing_first_name,
157 'last_name' => $this->billing_last_name,
158 'company' => $this->billing_company,
159 'address_1' => $this->billing_address_1,
160 'address_2' => $this->billing_address_2,
161 'city' => $this->billing_city,
162 'state' => $this->billing_state,
163 'postcode' => $this->billing_postcode,
164 'country' => $this->billing_country
165 ), $this );
166
167 $this->formatted_billing_address = WC()->countries->get_formatted_address( $address );
168 }
169 return $this->formatted_billing_address;
170 }
171
172 173 174 175 176 177
178 public function get_billing_address() {
179 if ( ! $this->billing_address ) {
180
181 $address = array(
182 'address_1' => $this->billing_address_1,
183 'address_2' => $this->billing_address_2,
184 'city' => $this->billing_city,
185 'state' => $this->billing_state,
186 'postcode' => $this->billing_postcode,
187 'country' => $this->billing_country
188 );
189 $joined_address = array();
190 foreach ( $address as $part ) {
191 if ( ! empty( $part ) ) {
192 $joined_address[] = $part;
193 }
194 }
195 $this->billing_address = implode( ', ', $joined_address );
196 }
197 return $this->billing_address;
198 }
199
200 201 202 203 204 205
206 public function get_formatted_shipping_address() {
207 if ( ! $this->formatted_shipping_address ) {
208 if ( $this->shipping_address_1 ) {
209
210
211 $address = apply_filters( 'woocommerce_order_formatted_shipping_address', array(
212 'first_name' => $this->shipping_first_name,
213 'last_name' => $this->shipping_last_name,
214 'company' => $this->shipping_company,
215 'address_1' => $this->shipping_address_1,
216 'address_2' => $this->shipping_address_2,
217 'city' => $this->shipping_city,
218 'state' => $this->shipping_state,
219 'postcode' => $this->shipping_postcode,
220 'country' => $this->shipping_country
221 ), $this );
222
223 $this->formatted_shipping_address = WC()->countries->get_formatted_address( $address );
224 }
225 }
226 return $this->formatted_shipping_address;
227 }
228
229
230 231 232 233 234 235
236 public function get_shipping_address() {
237 if ( ! $this->shipping_address ) {
238 if ( $this->shipping_address_1 ) {
239
240 $address = array(
241 'address_1' => $this->shipping_address_1,
242 'address_2' => $this->shipping_address_2,
243 'city' => $this->shipping_city,
244 'state' => $this->shipping_state,
245 'postcode' => $this->shipping_postcode,
246 'country' => $this->shipping_country
247 );
248 $joined_address = array();
249 foreach ( $address as $part ) {
250 if ( ! empty( $part ) ) {
251 $joined_address[] = $part;
252 }
253 }
254 $this->shipping_address = implode( ', ', $joined_address );
255 }
256 }
257 return $this->shipping_address;
258 }
259
260 261 262 263 264 265 266
267 public function get_items( $type = '' ) {
268 global $wpdb;
269
270 if ( empty( $type ) ) {
271 $type = array( 'line_item' );
272 }
273
274 if ( ! is_array( $type ) ) {
275 $type = array( $type );
276 }
277
278 $type = array_map( 'esc_attr', $type );
279
280 $line_items = $wpdb->get_results( $wpdb->prepare( "
281 SELECT order_item_id, order_item_name, order_item_type
282 FROM {$wpdb->prefix}woocommerce_order_items
283 WHERE order_id = %d
284 AND order_item_type IN ( '" . implode( "','", $type ) . "' )
285 ORDER BY order_item_id
286 ", $this->id ) );
287
288 $items = array();
289
290
291 $reserved_item_meta_keys = array(
292 'name',
293 'type',
294 'item_meta',
295 'qty',
296 'tax_class',
297 'product_id',
298 'variation_id',
299 'line_subtotal',
300 'line_total',
301 'line_tax',
302 'line_subtotal_tax'
303 );
304
305
306 foreach ( $line_items as $item ) {
307
308 $items[ $item->order_item_id ]['name'] = $item->order_item_name;
309 $items[ $item->order_item_id ]['type'] = $item->order_item_type;
310 $items[ $item->order_item_id ]['item_meta'] = $this->get_item_meta( $item->order_item_id );
311
312
313 foreach ( $items[ $item->order_item_id ]['item_meta'] as $name => $value ) {
314 if ( in_array( $name, $reserved_item_meta_keys ) ) {
315 continue;
316 }
317 if ( '_' === substr( $name, 0, 1 ) ) {
318 $items[ $item->order_item_id ][ substr( $name, 1 ) ] = $value[0];
319 } elseif ( ! in_array( $name, $reserved_item_meta_keys ) ) {
320 $items[ $item->order_item_id ][ $name ] = $value[0];
321 }
322 }
323 }
324
325 return apply_filters( 'woocommerce_order_get_items', $items, $this );
326 }
327
328 329 330 331 332 333
334 public function get_item_count( $type = '' ) {
335 global $wpdb;
336
337 if ( empty( $type ) ) {
338 $type = array( 'line_item' );
339 }
340
341 if ( ! is_array( $type ) ) {
342 $type = array( $type );
343 }
344
345 $items = $this->get_items( $type );
346
347 $count = 0;
348
349 foreach ( $items as $item ) {
350 if ( ! empty( $item['qty'] ) ) {
351 $count += $item['qty'];
352 } else {
353 $count ++;
354 }
355 }
356
357 return apply_filters( 'woocommerce_get_item_count', $count, $type, $this );
358 }
359
360 361 362 363 364 365
366 public function get_fees() {
367 return $this->get_items( 'fee' );
368 }
369
370 371 372 373 374 375
376 public function get_taxes() {
377 return $this->get_items( 'tax' );
378 }
379
380 381 382 383 384
385 public function get_shipping_methods() {
386 return $this->get_items( 'shipping' );
387 }
388
389 390 391 392 393
394 public function has_shipping_method( $method_id ) {
395 $shipping_methods = $this->get_shipping_methods();
396 $has_method = false;
397
398 if ( ! $shipping_methods ) {
399 return false;
400 }
401
402 foreach ( $shipping_methods as $shipping_method ) {
403 if ( $shipping_method['method_id'] == $method_id ) {
404 $has_method = true;
405 }
406 }
407
408 return $has_method;
409 }
410
411 412 413 414 415 416
417 public function get_tax_totals() {
418 $taxes = $this->get_items( 'tax' );
419 $tax_totals = array();
420
421 foreach ( $taxes as $key => $tax ) {
422
423 $code = $tax[ 'name' ];
424
425 if ( ! isset( $tax_totals[ $code ] ) ) {
426 $tax_totals[ $code ] = new stdClass();
427 $tax_totals[ $code ]->amount = 0;
428 }
429
430 $tax_totals[ $code ]->is_compound = $tax[ 'compound' ];
431 $tax_totals[ $code ]->label = isset( $tax[ 'label' ] ) ? $tax[ 'label' ] : $tax[ 'name' ];
432 $tax_totals[ $code ]->amount += $tax[ 'tax_amount' ] + $tax[ 'shipping_tax_amount' ];
433 $tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array('currency' => $this->get_order_currency()) );
434 }
435
436 return apply_filters( 'woocommerce_order_tax_totals', $tax_totals, $this );
437 }
438
439 440 441 442 443 444
445 public function has_meta( $order_item_id ) {
446 global $wpdb;
447
448 return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
449 FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
450 ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
451 }
452
453 454 455 456 457 458 459 460 461
462 public function get_item_meta( $order_item_id, $key = '', $single = false ) {
463 return get_metadata( 'order_item', $order_item_id, $key, $single );
464 }
465
466
467
468 469 470 471 472 473
474 public function get_cart_discount() {
475 return apply_filters( 'woocommerce_order_amount_cart_discount', (double) $this->cart_discount, $this );
476 }
477
478 479 480 481 482 483
484 public function get_order_discount() {
485 return apply_filters( 'woocommerce_order_amount_order_discount', (double) $this->order_discount, $this );
486 }
487
488 489 490 491 492 493
494 public function get_total_discount() {
495 return apply_filters( 'woocommerce_order_amount_total_discount', $this->get_cart_discount() + $this->get_order_discount(), $this );
496 }
497
498 499 500 501 502 503
504 public function get_cart_tax() {
505 return apply_filters( 'woocommerce_order_amount_cart_tax', (double) $this->order_tax, $this );
506 }
507
508 509 510 511 512 513
514 public function get_shipping_tax() {
515 return apply_filters( 'woocommerce_order_amount_shipping_tax', (double) $this->order_shipping_tax, $this );
516 }
517
518 519 520 521 522 523
524 public function get_total_tax() {
525 return apply_filters( 'woocommerce_order_amount_total_tax', wc_round_tax_total( $this->get_cart_tax() + $this->get_shipping_tax() ), $this );
526 }
527
528 529 530 531 532 533
534 public function get_total_shipping() {
535 return apply_filters( 'woocommerce_order_amount_total_shipping', (double) $this->order_shipping, $this );
536 }
537
538 539 540 541 542 543
544 public function get_total() {
545 return apply_filters( 'woocommerce_order_amount_total', (double) $this->order_total, $this );
546 }
547
548 549 550 551 552 553 554 555 556
557 public function get_item_subtotal( $item, $inc_tax = false, $round = true ) {
558 if ( $inc_tax ) {
559 $price = ( $item['line_subtotal'] + $item['line_subtotal_tax'] ) / $item['qty'];
560 } else {
561 $price = ( $item['line_subtotal'] / $item['qty'] );
562 }
563
564 $price = $round ? round( $price, 2 ) : $price;
565
566 return apply_filters( 'woocommerce_order_amount_item_subtotal', $price, $this );
567 }
568
569 570 571 572 573 574 575 576 577
578 public function get_line_subtotal( $item, $inc_tax = false, $round = true ) {
579 if ( $inc_tax ) {
580 $price = $item['line_subtotal'] + $item['line_subtotal_tax'];
581 } else {
582 $price = $item['line_subtotal'];
583 }
584
585 $price = $round ? round( $price, 2 ) : $price;
586
587 return apply_filters( 'woocommerce_order_amount_line_subtotal', $price, $this );
588 }
589
590 591 592 593 594 595 596 597 598
599 public function get_item_total( $item, $inc_tax = false, $round = true ) {
600 if ( $inc_tax ) {
601 $price = ( $item['line_total'] + $item['line_tax'] ) / $item['qty'];
602 } else {
603 $price = $item['line_total'] / $item['qty'];
604 }
605
606 $price = $round ? round( $price, 2 ) : $price;
607
608 return apply_filters( 'woocommerce_order_amount_item_total', $price, $this );
609 }
610
611 612 613 614 615 616 617 618
619 public function get_line_total( $item, $inc_tax = false ) {
620 $line_total = $inc_tax ? round( $item['line_total'] + $item['line_tax'], 2 ) : round( $item['line_total'], 2 );
621 return apply_filters( 'woocommerce_order_amount_line_total', $line_total, $this );
622 }
623
624 625 626 627 628 629 630 631
632 public function get_item_tax( $item, $round = true ) {
633 $price = $item['line_tax'] / $item['qty'];
634 $price = $round ? wc_round_tax_total( $price ) : $price;
635 return apply_filters( 'woocommerce_order_amount_item_tax', $price, $item, $round, $this );
636 }
637
638 639 640 641 642 643 644
645 public function get_line_tax( $item ) {
646 return apply_filters( 'woocommerce_order_amount_line_tax', wc_round_tax_total( $item['line_tax'] ), $item, $this );
647 }
648
649 650 651 652 653 654 655
656 public function get_shipping() {
657 _deprecated_function( 'get_shipping', '2.1', 'get_total_shipping' );
658 return $this->get_total_shipping();
659 }
660
661 662 663 664 665 666 667
668 public function get_order_total() {
669 _deprecated_function( 'get_order_total', '2.1', 'get_total' );
670 return $this->get_total();
671 }
672
673
674
675 676 677 678 679
680 public function get_shipping_method() {
681 $labels = array();
682
683
684 if ( $this->shipping_method_title ) {
685 $labels[] = $this->shipping_method_title;
686 } else {
687
688 $shipping_methods = $this->get_shipping_methods();
689
690 foreach ( $shipping_methods as $shipping ) {
691 $labels[] = $shipping['name'];
692 }
693 }
694
695 return apply_filters( 'woocommerce_order_shipping_method', implode( ', ', $labels ), $this );
696 }
697
698 699 700 701 702 703 704 705
706 public function get_formatted_line_subtotal( $item, $tax_display = '' ) {
707 if ( ! $tax_display ) {
708 $tax_display = $this->tax_display_cart;
709 }
710
711 if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) {
712 return '';
713 }
714
715 if ( 'excl' == $tax_display ) {
716 $ex_tax_label = $this->prices_include_tax ? 1 : 0;
717
718 $subtotal = wc_price( $this->get_line_subtotal( $item ), array( 'ex_tax_label' => $ex_tax_label, 'currency' => $this->get_order_currency() ) );
719 } else {
720 $subtotal = wc_price( $this->get_line_subtotal( $item, true ), array('currency' => $this->get_order_currency()) );
721 }
722
723 return apply_filters( 'woocommerce_order_formatted_line_subtotal', $subtotal, $item, $this );
724 }
725
726 727 728 729 730 731
732 public function get_order_currency() {
733
734 $currency = $this->order_currency;
735
736 return apply_filters( 'woocommerce_get_order_currency', $currency, $this );
737 }
738
739 740 741 742 743 744
745 public function get_formatted_order_total() {
746
747 $formatted_total = wc_price( $this->order_total , array('currency' => $this->get_order_currency()));
748
749 return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this );
750 }
751
752
753 754 755 756 757 758 759 760
761 public function get_subtotal_to_display( $compound = false, $tax_display = '' ) {
762 if ( ! $tax_display ) {
763 $tax_display = $this->tax_display_cart;
764 }
765
766 $subtotal = 0;
767
768 if ( ! $compound ) {
769 foreach ( $this->get_items() as $item ) {
770
771 if ( ! isset( $item['line_subtotal'] ) || ! isset( $item['line_subtotal_tax'] ) ) {
772 return '';
773 }
774
775 $subtotal += $item['line_subtotal'];
776
777 if ( 'incl' == $tax_display ) {
778 $subtotal += $item['line_subtotal_tax'];
779 }
780 }
781
782 $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) );
783
784 if ( $tax_display == 'excl' && $this->prices_include_tax ) {
785 $subtotal .= ' <small>' . WC()->countries->ex_tax_or_vat() . '</small>';
786 }
787
788 } else {
789
790 if ( 'incl' == $tax_display ) {
791 return '';
792 }
793
794 foreach ( $this->get_items() as $item ) {
795
796 $subtotal += $item['line_subtotal'];
797
798 }
799
800
801 $subtotal += $this->get_total_shipping();
802
803
804 foreach ( $this->get_taxes() as $tax ) {
805
806 if ( ! empty( $tax['compound'] ) ) {
807 continue;
808 }
809
810 $subtotal = $subtotal + $tax['tax_amount'] + $tax['shipping_tax_amount'];
811
812 }
813
814
815 $subtotal = $subtotal - $this->get_cart_discount();
816
817 $subtotal = wc_price( $subtotal, array('currency' => $this->get_order_currency()) );
818 }
819
820 return apply_filters( 'woocommerce_order_subtotal_to_display', $subtotal, $compound, $this );
821 }
822
823
824 825 826 827 828 829
830 public function get_shipping_to_display( $tax_display = '' ) {
831 if ( ! $tax_display ) {
832 $tax_display = $this->tax_display_cart;
833 }
834
835 if ( $this->order_shipping > 0 ) {
836
837 $tax_text = '';
838
839 if ( $tax_display == 'excl' ) {
840
841
842 $shipping = wc_price( $this->order_shipping, array('currency' => $this->get_order_currency()) );
843
844 if ( $this->order_shipping_tax > 0 && $this->prices_include_tax ) {
845 $tax_text = WC()->countries->ex_tax_or_vat() . ' ';
846 }
847
848 } else {
849
850
851 $shipping = wc_price( $this->order_shipping + $this->order_shipping_tax, array('currency' => $this->get_order_currency()) );
852
853 if ( $this->order_shipping_tax > 0 && ! $this->prices_include_tax ) {
854 $tax_text = WC()->countries->inc_tax_or_vat() . ' ';
855 }
856
857 }
858
859 $shipping .= sprintf( __( ' <small>%svia %s</small>', 'woocommerce' ), $tax_text, $this->get_shipping_method() );
860
861 } elseif ( $this->get_shipping_method() ) {
862 $shipping = $this->get_shipping_method();
863 } else {
864 $shipping = __( 'Free!', 'woocommerce' );
865 }
866
867 return apply_filters( 'woocommerce_order_shipping_to_display', $shipping, $this );
868 }
869
870
871 872 873 874 875 876
877 public function get_cart_discount_to_display() {
878 return apply_filters( 'woocommerce_order_cart_discount_to_display', wc_price( $this->get_cart_discount(), array( 'currency' => $this->get_order_currency() ) ), $this );
879 }
880
881
882 883 884 885 886 887
888 public function get_order_discount_to_display() {
889 return apply_filters( 'woocommerce_order_discount_to_display', wc_price( $this->get_order_discount(), array( 'currency' => $this->get_order_currency() ) ), $this );
890 }
891
892
893 894 895 896 897 898 899
900 public function get_product_from_item( $item ) {
901 $_product = get_product( $item['variation_id'] ? $item['variation_id'] : $item['product_id'] );
902
903 return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this );
904 }
905
906
907 908 909 910 911 912
913 public function get_order_item_totals( $tax_display = '' ) {
914 if ( ! $tax_display ) {
915 $tax_display = $this->tax_display_cart;
916 }
917
918 $total_rows = array();
919
920 if ( $subtotal = $this->get_subtotal_to_display() ) {
921 $total_rows['cart_subtotal'] = array(
922 'label' => __( 'Cart Subtotal:', 'woocommerce' ),
923 'value' => $subtotal
924 );
925 }
926
927 if ( $this->get_cart_discount() > 0 ) {
928 $total_rows['cart_discount'] = array(
929 'label' => __( 'Cart Discount:', 'woocommerce' ),
930 'value' => '-' . $this->get_cart_discount_to_display()
931 );
932 }
933
934 if ( $this->get_shipping_method() ) {
935 $total_rows['shipping'] = array(
936 'label' => __( 'Shipping:', 'woocommerce' ),
937 'value' => $this->get_shipping_to_display()
938 );
939 }
940
941 if ( $fees = $this->get_fees() )
942 foreach( $fees as $id => $fee ) {
943 if ( $fee['line_total'] + $fee['line_tax'] == 0 ) {
944 continue;
945 }
946
947 if ( 'excl' == $tax_display ) {
948
949 $total_rows[ 'fee_' . $id ] = array(
950 'label' => $fee['name'],
951 'value' => wc_price( $fee['line_total'], array('currency' => $this->get_order_currency()) )
952 );
953
954 } else {
955
956 $total_rows[ 'fee_' . $id ] = array(
957 'label' => $fee['name'],
958 'value' => wc_price( $fee['line_total'] + $fee['line_tax'], array('currency' => $this->get_order_currency()) )
959 );
960
961 }
962 }
963
964
965 if ( 'excl' == $tax_display ) {
966 if ( get_option( 'woocommerce_tax_total_display' ) == 'itemized' ) {
967 foreach ( $this->get_tax_totals() as $code => $tax ) {
968 $total_rows[ sanitize_title( $code ) ] = array(
969 'label' => $tax->label . ':',
970 'value' => $tax->formatted_amount
971 );
972 }
973 } else {
974 $total_rows['tax'] = array(
975 'label' => WC()->countries->tax_or_vat() . ':',
976 'value' => wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) )
977 );
978 }
979 }
980
981 if ( $this->get_order_discount() > 0 ) {
982 $total_rows['order_discount'] = array(
983 'label' => __( 'Order Discount:', 'woocommerce' ),
984 'value' => '-' . $this->get_order_discount_to_display()
985 );
986 }
987
988 $total_rows['order_total'] = array(
989 'label' => __( 'Order Total:', 'woocommerce' ),
990 'value' => $this->get_formatted_order_total()
991 );
992
993
994 if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) && 'incl' == $tax_display ) {
995
996 $tax_string_array = array();
997
998 if ( 'itemized' == get_option( 'woocommerce_tax_total_display' ) ) {
999 foreach ( $this->get_tax_totals() as $code => $tax ) {
1000 $tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label );
1001 }
1002 } else {
1003 $tax_string_array[] = sprintf( '%s %s', wc_price( $this->get_total_tax(), array('currency' => $this->get_order_currency()) ), WC()->countries->tax_or_vat() );
1004 }
1005
1006 if ( ! empty( $tax_string_array ) ) {
1007 $total_rows['order_total']['value'] .= ' ' . sprintf( __( '(Includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) );
1008 }
1009 }
1010
1011 return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this );
1012 }
1013
1014
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
1027 public function email_order_items_table( $show_download_links = false, $show_sku = false, $show_purchase_note = false, $show_image = false, $image_size = array( 32, 32 ), $plain_text = false ) {
1028
1029 ob_start();
1030
1031 $template = $plain_text ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php';
1032
1033 wc_get_template( $template, array(
1034 'order' => $this,
1035 'items' => $this->get_items(),
1036 'show_download_links' => $show_download_links,
1037 'show_sku' => $show_sku,
1038 'show_purchase_note' => $show_purchase_note,
1039 'show_image' => $show_image,
1040 'image_size' => $image_size
1041 ) );
1042
1043 $return = apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $this );
1044
1045 return $return;
1046 }
1047
1048 1049 1050 1051 1052 1053
1054 public function is_download_permitted() {
1055 return apply_filters( 'woocommerce_order_is_download_permitted', $this->status == 'completed' || ( get_option( 'woocommerce_downloads_grant_access_after_payment' ) == 'yes' && $this->status == 'processing' ), $this );
1056 }
1057
1058 1059 1060 1061 1062 1063
1064 public function has_downloadable_item() {
1065 $has_downloadable_item = false;
1066
1067 foreach ( $this->get_items() as $item ) {
1068
1069 $_product = $this->get_product_from_item( $item );
1070
1071 if ( $_product && $_product->exists() && $_product->is_downloadable() && $_product->has_file() ) {
1072 $has_downloadable_item = true;
1073 }
1074
1075 }
1076
1077 return $has_downloadable_item;
1078 }
1079
1080
1081 1082 1083 1084 1085 1086 1087
1088 public function get_checkout_payment_url( $on_checkout = false ) {
1089
1090 $pay_url = wc_get_endpoint_url( 'order-pay', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) );
1091
1092 if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
1093 $pay_url = str_replace( 'http:', 'https:', $pay_url );
1094 }
1095
1096 if ( $on_checkout ) {
1097 $pay_url = add_query_arg( 'key', $this->order_key, $pay_url );
1098 } else {
1099 $pay_url = add_query_arg( array( 'pay_for_order' => 'true', 'key' => $this->order_key ), $pay_url );
1100 }
1101
1102 return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this );
1103 }
1104
1105
1106 1107 1108 1109 1110 1111
1112 public function get_checkout_order_received_url() {
1113
1114 $order_received_url = wc_get_endpoint_url( 'order-received', $this->id, get_permalink( wc_get_page_id( 'checkout' ) ) );
1115
1116 if ( 'yes' == get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
1117 $order_received_url = str_replace( 'http:', 'https:', $order_received_url );
1118 }
1119
1120 $order_received_url = add_query_arg( 'key', $this->order_key, $order_received_url );
1121
1122 return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this );
1123 }
1124
1125
1126 1127 1128 1129 1130 1131
1132 public function get_cancel_order_url( $redirect = '' ) {
1133 $cancel_endpoint = get_permalink( wc_get_page_id( 'cart' ) );
1134 if ( ! $cancel_endpoint ) {
1135 $cancel_endpoint = home_url();
1136 }
1137
1138 if ( false === strpos( $cancel_endpoint, '?' ) ) {
1139 $cancel_endpoint = trailingslashit( $cancel_endpoint );
1140 }
1141
1142 return apply_filters('woocommerce_get_cancel_order_url', wp_nonce_url( add_query_arg( array( 'cancel_order' => 'true', 'order' => $this->order_key, 'order_id' => $this->id, 'redirect' => $redirect ), $cancel_endpoint ), 'woocommerce-cancel_order' ) );
1143 }
1144
1145 1146 1147 1148 1149
1150 public function get_view_order_url() {
1151 $view_order_url = wc_get_endpoint_url( 'view-order', $this->id, get_permalink( wc_get_page_id( 'myaccount' ) ) );
1152
1153 return apply_filters( 'woocommerce_get_view_order_url', $view_order_url, $this );
1154 }
1155
1156 1157 1158 1159 1160 1161 1162 1163 1164
1165 public function get_downloadable_file_urls( $product_id, $variation_id, $item ) {
1166 global $wpdb;
1167
1168 _deprecated_function( 'get_downloadable_file_urls', '2.1', 'get_item_downloads' );
1169
1170 $download_file = $variation_id > 0 ? $variation_id : $product_id;
1171 $_product = get_product( $download_file );
1172
1173 $user_email = $this->billing_email;
1174
1175 $results = $wpdb->get_results( $wpdb->prepare("
1176 SELECT download_id
1177 FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
1178 WHERE user_email = %s
1179 AND order_key = %s
1180 AND product_id = %s
1181 ", $user_email, $this->order_key, $download_file ) );
1182
1183 $file_urls = array();
1184 foreach ( $results as $result ) {
1185 if ( $_product->has_file( $result->download_id ) ) {
1186 $file_urls[ $_product->get_file_download_path( $result->download_id ) ] = $this->get_download_url( $download_file, $result->download_id );
1187 }
1188 }
1189
1190 return apply_filters( 'woocommerce_get_downloadable_file_urls', $file_urls, $product_id, $variation_id, $item );
1191 }
1192
1193 1194 1195 1196 1197
1198 public function get_item_downloads( $item ) {
1199 global $wpdb;
1200
1201 $product_id = $item['variation_id'] > 0 ? $item['variation_id'] : $item['product_id'];
1202 $product = get_product( $product_id );
1203 $download_ids = $wpdb->get_col( $wpdb->prepare("
1204 SELECT download_id
1205 FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
1206 WHERE user_email = %s
1207 AND order_key = %s
1208 AND product_id = %s
1209 ORDER BY permission_id
1210 ", $this->billing_email, $this->order_key, $product_id ) );
1211
1212 $files = array();
1213
1214 foreach ( $download_ids as $download_id ) {
1215 if ( $product->has_file( $download_id ) ) {
1216 $files[ $download_id ] = $product->get_file( $download_id );
1217 $files[ $download_id ]['download_url'] = $this->get_download_url( $product_id, $download_id );
1218 }
1219 }
1220
1221 return apply_filters( 'woocommerce_get_item_downloads', $files, $item, $this );
1222 }
1223
1224 1225 1226 1227 1228 1229
1230 public function get_download_url( $product_id, $download_id ) {
1231 return add_query_arg( array(
1232 'download_file' => $product_id,
1233 'order' => $this->order_key,
1234 'email' => urlencode( $this->billing_email ),
1235 'key' => $download_id
1236 ), trailingslashit( home_url() ) );
1237 }
1238
1239 1240 1241 1242 1243 1244 1245 1246
1247 public function add_order_note( $note, $is_customer_note = 0 ) {
1248
1249 $is_customer_note = intval( $is_customer_note );
1250
1251 if ( is_user_logged_in() && current_user_can( 'edit_shop_order', $this->id ) ) {
1252 $user = get_user_by( 'id', get_current_user_id() );
1253 $comment_author = $user->display_name;
1254 $comment_author_email = $user->user_email;
1255 } else {
1256 $comment_author = __( 'WooCommerce', 'woocommerce' );
1257 $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@';
1258 $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ) : 'noreply.com';
1259 $comment_author_email = sanitize_email( $comment_author_email );
1260 }
1261
1262 $comment_post_ID = $this->id;
1263 $comment_author_url = '';
1264 $comment_content = $note;
1265 $comment_agent = 'WooCommerce';
1266 $comment_type = 'order_note';
1267 $comment_parent = 0;
1268 $comment_approved = 1;
1269 $commentdata = apply_filters( 'woocommerce_new_order_note_data', compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_agent', 'comment_type', 'comment_parent', 'comment_approved' ), array( 'order_id' => $this->id, 'is_customer_note' => $is_customer_note ) );
1270
1271 $comment_id = wp_insert_comment( $commentdata );
1272
1273 add_comment_meta( $comment_id, 'is_customer_note', $is_customer_note );
1274
1275 if ( $is_customer_note ) {
1276 do_action( 'woocommerce_new_customer_note', array( 'order_id' => $this->id, 'customer_note' => $note ) );
1277 }
1278
1279 return $comment_id;
1280 }
1281
1282
1283 1284 1285 1286 1287 1288 1289 1290
1291 public function update_status( $new_status_slug, $note = '' ) {
1292
1293 if ( $note ) {
1294 $note .= ' ';
1295 }
1296
1297 $old_status = get_term_by( 'slug', sanitize_title( $this->status ), 'shop_order_status' );
1298 $new_status = get_term_by( 'slug', sanitize_title( $new_status_slug ), 'shop_order_status' );
1299
1300 if ( $new_status ) {
1301
1302 wp_set_object_terms( $this->id, array( $new_status->slug ), 'shop_order_status', false );
1303
1304 if ( $this->id && $this->status != $new_status->slug ) {
1305
1306
1307 do_action( 'woocommerce_order_status_' . $new_status->slug, $this->id );
1308 do_action( 'woocommerce_order_status_' . $this->status . '_to_' . $new_status->slug, $this->id );
1309 do_action( 'woocommerce_order_status_changed', $this->id, $this->status, $new_status->slug );
1310
1311 if ( $old_status ) {
1312 $this->add_order_note( $note . sprintf( __( 'Order status changed from %s to %s.', 'woocommerce' ), __( $old_status->name, 'woocommerce' ), __( $new_status->name, 'woocommerce' ) ) );
1313 }
1314
1315
1316 if ( 'completed' == $new_status->slug ) {
1317 update_post_meta( $this->id, '_completed_date', current_time('mysql') );
1318 }
1319
1320 if ( 'processing' == $new_status->slug || 'completed' == $new_status->slug || 'on-hold' == $new_status->slug ) {
1321
1322
1323 $this->record_product_sales();
1324
1325
1326 $this->increase_coupon_usage_counts();
1327 }
1328
1329
1330 if ( 'cancelled' == $new_status->slug ) {
1331 $this->decrease_coupon_usage_counts();
1332 }
1333
1334
1335 wp_update_post( array( 'ID' => $this->id ) );
1336
1337 $this->status = $new_status->slug;
1338 }
1339
1340 }
1341
1342 wc_delete_shop_order_transients( $this->id );
1343 }
1344
1345
1346 1347 1348 1349 1350 1351 1352
1353 public function cancel_order( $note = '' ) {
1354 unset( WC()->session->order_awaiting_payment );
1355
1356 $this->update_status( 'cancelled', $note );
1357
1358 }
1359
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
1372 public function payment_complete() {
1373
1374 do_action( 'woocommerce_pre_payment_complete', $this->id );
1375
1376 if ( ! empty( WC()->session->order_awaiting_payment ) ) {
1377 unset( WC()->session->order_awaiting_payment );
1378 }
1379
1380 if ( $this->id && ( 'on-hold' == $this->status || 'pending' == $this->status || 'failed' == $this->status ) ) {
1381
1382 $order_needs_processing = true;
1383
1384 if ( sizeof( $this->get_items() ) > 0 ) {
1385
1386 foreach( $this->get_items() as $item ) {
1387
1388 if ( $item['product_id'] > 0 ) {
1389
1390 $_product = $this->get_product_from_item( $item );
1391
1392 if ( false !== $_product && ( $_product->is_downloadable() && $_product->is_virtual() ) || ! apply_filters( 'woocommerce_order_item_needs_processing', true, $_product, $this->id ) ) {
1393 $order_needs_processing = false;
1394 continue;
1395 }
1396
1397 }
1398 $order_needs_processing = true;
1399 break;
1400 }
1401 }
1402
1403 $new_order_status = $order_needs_processing ? 'processing' : 'completed';
1404
1405 $new_order_status = apply_filters( 'woocommerce_payment_complete_order_status', $new_order_status, $this->id );
1406
1407 $this->update_status( $new_order_status );
1408
1409 add_post_meta( $this->id, '_paid_date', current_time('mysql'), true );
1410
1411 $this_order = array(
1412 'ID' => $this->id,
1413 'post_date' => current_time( 'mysql', 0 ),
1414 'post_date_gmt' => current_time( 'mysql', 1 )
1415 );
1416 wp_update_post( $this_order );
1417
1418 if ( apply_filters( 'woocommerce_payment_complete_reduce_order_stock', true, $this->id ) ) {
1419 $this->reduce_order_stock();
1420 }
1421
1422 do_action( 'woocommerce_payment_complete', $this->id );
1423
1424 } else {
1425
1426 do_action( 'woocommerce_payment_complete_order_status_' . $this->status, $this->id );
1427
1428 }
1429 }
1430
1431
1432 1433 1434 1435 1436 1437
1438 public function record_product_sales() {
1439
1440 if ( 'yes' == get_post_meta( $this->id, '_recorded_sales', true ) ) {
1441 return;
1442 }
1443
1444 if ( sizeof( $this->get_items() ) > 0 ) {
1445 foreach ( $this->get_items() as $item ) {
1446 if ( $item['product_id'] > 0 ) {
1447 $sales = (int) get_post_meta( $item['product_id'], 'total_sales', true );
1448 $sales += (int) $item['qty'];
1449 if ( $sales ) {
1450 update_post_meta( $item['product_id'], 'total_sales', $sales );
1451 }
1452 }
1453 }
1454 }
1455
1456 update_post_meta( $this->id, '_recorded_sales', 'yes' );
1457 }
1458
1459
1460 1461 1462 1463 1464 1465
1466 public function get_used_coupons() {
1467
1468 $codes = array();
1469 $coupons = $this->get_items( 'coupon' );
1470
1471 foreach ( $coupons as $item_id => $item ) {
1472 $codes[] = trim( $item['name'] );
1473 }
1474
1475 return $codes;
1476 }
1477
1478
1479 1480 1481 1482 1483 1484
1485 public function increase_coupon_usage_counts() {
1486
1487 if ( 'yes' == get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) {
1488 return;
1489 }
1490
1491 if ( sizeof( $this->get_used_coupons() ) > 0 ) {
1492 foreach ( $this->get_used_coupons() as $code ) {
1493 if ( ! $code ) {
1494 continue;
1495 }
1496
1497 $coupon = new WC_Coupon( $code );
1498
1499 $used_by = $this->user_id;
1500 if ( ! $used_by ) {
1501 $used_by = $this->billing_email;
1502 }
1503
1504 $coupon->inc_usage_count( $used_by );
1505 }
1506 }
1507
1508 update_post_meta( $this->id, '_recorded_coupon_usage_counts', 'yes' );
1509 }
1510
1511
1512 1513 1514 1515 1516 1517
1518 public function decrease_coupon_usage_counts() {
1519
1520 if ( 'yes' != get_post_meta( $this->id, '_recorded_coupon_usage_counts', true ) ) {
1521 return;
1522 }
1523
1524 if ( sizeof( $this->get_used_coupons() ) > 0 ) {
1525 foreach ( $this->get_used_coupons() as $code ) {
1526 if ( ! $code ) {
1527 continue;
1528 }
1529
1530 $coupon = new WC_Coupon( $code );
1531
1532 $used_by = $this->user_id;
1533 if ( ! $used_by ) {
1534 $used_by = $this->billing_email;
1535 }
1536
1537 $coupon->dcr_usage_count( $used_by );
1538 }
1539 }
1540
1541 delete_post_meta( $this->id, '_recorded_coupon_usage_counts' );
1542 }
1543
1544
1545 1546 1547 1548 1549 1550
1551 public function reduce_order_stock() {
1552
1553 if ( 'yes' == get_option('woocommerce_manage_stock') && sizeof( $this->get_items() ) > 0 ) {
1554
1555
1556 foreach ( $this->get_items() as $item ) {
1557
1558 if ( $item['product_id'] > 0 ) {
1559 $_product = $this->get_product_from_item( $item );
1560
1561 if ( $_product && $_product->exists() && $_product->managing_stock() ) {
1562
1563 $old_stock = $_product->stock;
1564
1565 $qty = apply_filters( 'woocommerce_order_item_quantity', $item['qty'], $this, $item );
1566
1567 $new_quantity = $_product->reduce_stock( $qty );
1568
1569 $this->add_order_note( sprintf( __( 'Item #%s stock reduced from %s to %s.', 'woocommerce' ), $item['product_id'], $old_stock, $new_quantity) );
1570
1571 $this->send_stock_notifications( $_product, $new_quantity, $item['qty'] );
1572
1573 }
1574
1575 }
1576
1577 }
1578
1579 do_action( 'woocommerce_reduce_order_stock', $this );
1580
1581 $this->add_order_note( __( 'Order item stock reduced successfully.', 'woocommerce' ) );
1582 }
1583
1584 }
1585
1586
1587 1588 1589 1590 1591 1592 1593 1594 1595
1596 public function send_stock_notifications( $product, $new_stock, $qty_ordered ) {
1597
1598
1599 if ( $new_stock < 0 ) {
1600 do_action( 'woocommerce_product_on_backorder', array( 'product' => $product, 'order_id' => $this->id, 'quantity' => $qty_ordered ) );
1601 }
1602
1603
1604 $notification_sent = false;
1605
1606 if ( 'yes' == get_option( 'woocommerce_notify_no_stock' ) && get_option('woocommerce_notify_no_stock_amount') >= $new_stock ) {
1607 do_action( 'woocommerce_no_stock', $product );
1608 $notification_sent = true;
1609 }
1610 if ( ! $notification_sent && 'yes' == get_option( 'woocommerce_notify_low_stock' ) && get_option('woocommerce_notify_low_stock_amount') >= $new_stock ) {
1611 do_action( 'woocommerce_low_stock', $product );
1612 $notification_sent = true;
1613 }
1614
1615 }
1616
1617
1618 1619 1620 1621 1622 1623
1624 public function get_customer_order_notes() {
1625
1626 $notes = array();
1627
1628 $args = array(
1629 'post_id' => $this->id,
1630 'approve' => 'approve',
1631 'type' => ''
1632 );
1633
1634 remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
1635
1636 $comments = get_comments( $args );
1637
1638 foreach ( $comments as $comment ) {
1639 $is_customer_note = get_comment_meta( $comment->comment_ID, 'is_customer_note', true );
1640 $comment->comment_content = make_clickable( $comment->comment_content );
1641 if ( $is_customer_note ) {
1642 $notes[] = $comment;
1643 }
1644 }
1645
1646 add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
1647
1648 return (array) $notes;
1649
1650 }
1651
1652 1653 1654 1655 1656 1657
1658 public function needs_payment() {
1659 $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this );
1660
1661 if ( in_array( $this->status, $valid_order_statuses ) && $this->get_total() > 0 ) {
1662 $needs_payment = true;
1663 } else {
1664 $needs_payment = false;
1665 }
1666
1667 return apply_filters( 'woocommerce_order_needs_payment', $needs_payment, $this, $valid_order_statuses );
1668 }
1669 }
1670