PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / order / class-lp-order.php

class-lp-order.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7, at inc/order/class-lp-order.php

1,408 lines 36.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Order
4 *
5 * @author ThimPress
6 * @package LearnPress/Classes
7 * @version 4.0.0
8 */
9
10 /**
11 * Prevent loading this file directly
12 */
13 defined( 'ABSPATH' ) || exit();
14
15 if ( ! class_exists( 'LP_Order' ) ) {
16
17 /**
18 * Class LP_Order
19 */
20 class LP_Order extends LP_Abstract_Post_Data {
21
22 /**
23 * @var string
24 */
25 protected $_post_type = LP_ORDER_CPT;
26
27 /**
28 * @var array
29 */
30 protected $_data = array(
31 'user_id' => '',
32 'order_date' => '',
33 'date_modified' => '',
34 'customer_message' => '',
35 'customer_note' => '',
36 'status' => '',
37 'order_key' => '',
38 'total' => 0,
39 'subtotal' => 0,
40 'created_via' => '',
41 'checkout_email' => '',
42 );
43
44 /**
45 * @var array
46 */
47 protected $_meta_keys = array(
48 '_user_id' => 'user',
49 '_order_currency' => 'currency',
50 '_order_subtotal' => 'subtotal',
51 '_order_total' => 'total',
52 '_payment_method' => 'payment_method',
53 '_payment_method_title' => 'payment_method_title',
54 '_order_version' => 'order_version',
55 '_edit_last' => '',
56 '_edit_lock' => '',
57 '_prices_include_tax' => '',
58 '_order_key' => '',
59 '_user_ip' => '',
60 '_checkout_email' => '',
61 );
62
63 /**
64 * Store order status in transactions.
65 *
66 * @var array
67 */
68 protected $_status = array();
69
70 /**
71 * LP_Order constructor.
72 *
73 * @param bool $order_id
74 *
75 * @throws Exception
76 */
77 public function __construct( $order_id = false ) {
78 $this->_curd = new LP_Order_CURD();
79 if ( is_numeric( $order_id ) && $order_id > 0 ) {
80 $this->set_id( $order_id );
81 } elseif ( $order_id instanceof self ) {
82 $this->set_id( absint( $order_id->get_id() ) );
83 } elseif ( ! empty( $order_id->ID ) ) {
84 $this->set_id( absint( $order_id->ID ) );
85 }
86
87 if ( $this->get_id() > 0 ) {
88 $this->load();
89 }
90 }
91
92 /**
93 * Load the order data.
94 * Check if the id is not zero but it's post type does not exists.
95 *
96 * @throws Exception
97 */
98 public function load() {
99 $this->_curd->load( $this );
100 }
101
102 /**
103 * Set order date.
104 *
105 * @param int|string $date
106 */
107 public function set_order_date( $date ) {
108 if ( is_numeric( $date ) ) {
109 $date = gmdate( 'Y-m-d H:i:s', $date );
110 }
111 $this->_set_data_date( 'order_date', $date );
112
113 }
114
115 /**
116 * Get date of this order.
117 *
118 * @param string $context
119 *
120 * @return string|LP_Datetime
121 */
122 public function get_order_date( $context = '' ) {
123 $date = $this->get_data( 'order_date' );
124
125 if ( 'edit' !== $context ) {
126
127 if ( $date instanceof LP_Datetime ) {
128 $strtime = strtotime( $date->toSql() );
129
130 switch ( $context ) {
131 case 'd':
132 $date = date_i18n( 'Y-m-d', $strtime );
133 break;
134 case 'h':
135 $date = date_i18n( 'H', $strtime );
136 break;
137 case 'm':
138 $date = date_i18n( 'i', $strtime );
139 break;
140 case 'timestamp':
141 $date = $strtime;
142 break;
143 default:
144 $post = get_post( $this->get_id() );
145 $m_time = $post->post_date;
146 $time = get_post_time( 'G', true, $post );
147 $time_diff = time() - $time;
148
149 if ( $time_diff > 0 && $time_diff < DAY_IN_SECONDS ) {
150 $date = sprintf( __( '%s ago', 'learnpress' ), human_time_diff( $time ) );
151 } else {
152 $date = mysql2date( get_option( 'date_format' ), $m_time );
153 }
154 }
155 }
156 } elseif ( ! $date instanceof LP_Datetime ) {
157 $date = new LP_Datetime( $date );
158 }
159
160 return $date;
161 }
162
163 /**
164 * Set order key
165 *
166 * @param string $order_key
167 */
168 public function set_order_key( $order_key ) {
169 $this->_set_data( 'order_key', $order_key );
170 }
171
172 /**
173 * Get order key.
174 *
175 * @return array|mixed
176 */
177 public function get_order_key() {
178 return $this->get_data( 'order_key', '' );
179 }
180
181 /**
182 * Get confirm received text
183 *
184 * @return string
185 * @since 3.0.0
186 */
187 public function get_confirm_order_received_text() {
188 return apply_filters( 'learn-press/confirm-order-received-text', __( 'Thank you. Your order has been received.', 'learnpress' ), $this->get_id() );
189 }
190
191 /**
192 * Get thank you message after the order is placed.
193 *
194 * @return mixed
195 * @since 3.0.0
196 */
197 public function get_thankyou_message() {
198 return apply_filters( 'learn-press/confirm-order-received-text', __( 'Thank you. Your order has been received.', 'learnpress' ), $this->get_id() );
199 }
200
201 /**
202 * Magic function for getting object property dynamic.
203 *
204 * @param string $prop
205 *
206 * @return int|mixed|null
207 * @deprecated
208 */
209 public function __get( $prop ) {
210 if ( $prop == 'post' ) {
211 // print_r( debug_backtrace() );
212 // die( '$post is deprecated' );
213 } elseif ( $prop == 'id' ) {
214 return $this->get_id();
215 }
216 $value = null;
217 if ( ! property_exists( $this, $prop ) ) {
218 $value = get_post_meta( $this->get_id(), '_' . $prop, true );
219 }
220
221 return $value;
222 }
223
224 /**
225 * Checks to see if current order has status as passed.
226 *
227 * @param string|array $status String or an array of statuses
228 *
229 * @return mixed
230 */
231 public function has_status( $status ) {
232 settype( $status, 'array' );
233 $has = in_array( $this->get_status(), $status );
234
235 return apply_filters( 'learn-press/has-order-status', $has, $status, $this->get_id() );
236 }
237
238 /**
239 * Check if order has a status as wp default.
240 *
241 * @return bool
242 */
243 public function has_invalid_status() {
244 return ! $this->has_status( learn_press_get_order_statuses( false, true ) );
245 }
246
247 /**
248 * Updates order to new status if needed
249 *
250 * @param mixed $new_status
251 * @param bool $manual Is this a manual order status change?.
252 *
253 * @return bool
254 * @throws Exception
255 */
256 public function update_status( $new_status = 'pending', $manual = false ) {
257 $old_status = $this->get_status();
258
259 do_action( 'learn-press/before-update-status-lp-order', $new_status, $old_status, $this, $manual );
260
261 $this->set_status( $new_status );
262 $result = $this->save();
263
264 do_action( 'learn-press/after-update-status-lp-order', $new_status, $old_status, $this, $manual );
265
266 return $result;
267 }
268
269 /**
270 * Set payment method for this order.
271 * If payment method is an instance of LP_Gateway_Abstract then
272 * update it to database.
273 *
274 * @param LP_Gateway_Abstract|string $payment_method
275 */
276 public function set_payment_method( $payment_method ) {
277 if ( $payment_method instanceof LP_Gateway_Abstract ) {
278 update_post_meta( $this->get_id(), '_payment_method', $payment_method->get_id() );
279 update_post_meta( $this->get_id(), '_payment_method_title', $payment_method->get_title() );
280 }
281
282 $this->payment_method = $payment_method;
283 }
284
285 /**
286 * Format order number id
287 *
288 * @return string
289 */
290 public function get_order_number(): string {
291 return learn_press_transaction_order_number( $this->get_id() );
292 }
293
294 /**
295 * Get status of the order
296 *
297 * @return mixed
298 */
299 public function get_order_status() {
300 return $this->get_status();
301 }
302
303 public function get_user_ip_address() {
304 return $this->get_data( 'user_ip_address' );
305 }
306
307 /**
308 * Get current status of order
309 *
310 * @return mixed
311 */
312 public function get_status() {
313 $status = $this->get_data( 'status', '' );
314 $status = apply_filters( 'learn_press_order_status', $status, $this );
315
316 apply_filters( 'learn-press/order/status', $status, $this->get_id() );
317
318 return $status;
319 }
320
321 /**
322 * Set order status.
323 *
324 * @param string $new_status
325 * @param string $note - Optional. Note for changing status.
326 */
327 public function set_status( string $new_status = '', string $note = '' ) {
328 $new_status = 'lp-' === substr( $new_status, 0, 3 ) ? substr( $new_status, 3 ) : $new_status;
329 $valid_statuses = learn_press_get_order_statuses( false, true );
330
331 if ( ! in_array( $new_status, $valid_statuses ) && 'trash' !== $new_status ) {
332 $new_status = 'pending';
333 }
334
335 $this->_set_data( 'status', $new_status );
336 }
337
338 public function get_order_status_html() {
339 $statuses = learn_press_get_order_statuses();
340 $order_status = $this->get_status();
341
342 if ( ! empty( $statuses[ $order_status ] ) ) {
343 $status = $statuses[ $order_status ];
344 } elseif ( ! empty( $statuses[ 'lp-' . $order_status ] ) ) {
345 $status = $statuses[ 'lp-' . $order_status ];
346 } elseif ( $order_status == 'trash' ) {
347 $status = __( 'Removed', 'learnpress' );
348 } else {
349 $status = ucfirst( $order_status );
350 }
351
352 $class = 'order-status order-status-' . sanitize_title( $status );
353 $html = sprintf( '<span class="%s">%s</span>', apply_filters( 'learn_press_order_status_class', $class, $status, $this ), $status );
354
355 return apply_filters( 'learn_press_order_status_html', $html, $this );
356 }
357
358 /**
359 * Mark order as complete
360 *
361 * @param string - transaction ID provided payment gateway
362 *
363 * @return bool
364 * @throws Exception
365 */
366 public function payment_complete( $transaction_id = '' ): bool {
367 do_action( 'learn-press/payment-pre-complete', $this->get_id() );
368
369 //TODO: tungnx - check to change code below - use LP()->session->set()
370 LP()->session->order_awaiting_payment = null;
371
372 $valid_order_statuses = apply_filters(
373 'learn-press/valid-order-statuses-for-payment-complete',
374 array(
375 'pending',
376 'processing',
377 ),
378 $this
379 );
380
381 if ( $this->get_id() && $this->has_status( $valid_order_statuses ) ) {
382
383 $this->update_status( 'completed' );
384
385 if ( ! empty( $transaction_id ) ) {
386 add_post_meta( $this->get_id(), '_transaction_id', $transaction_id, true );
387 }
388
389 do_action( 'learn-press/payment-complete', $this->get_id() );
390 } else {
391 do_action( 'learn-press/payment-complete-order-status-' . $this->get_status(), $this->get_id() );
392 }
393
394 return true;
395 }
396
397 /**
398 * Get checkout order successful url.
399 *
400 * @return string
401 */
402 public function get_checkout_order_received_url() {
403 $received_url = learn_press_get_endpoint_url( 'lp-order-received', $this->get_id(), learn_press_get_page_link( 'checkout' ) );
404
405 $received_url = add_query_arg( 'key', $this->get_order_key(), $received_url );
406
407 $received_url = apply_filters( 'learn_press_get_checkout_order_received_url', $received_url, $this );
408
409 /**
410 * @since 3.0.0
411 */
412 return apply_filters( 'learn-press/checkout-order-received-url', $received_url, $this );
413 }
414
415 /*********************************/
416
417 /**
418 * Get customer name of the order
419 */
420 public function get_customer_name() {
421 $customer_name = '';
422
423 if ( 'auto-draft' !== get_post_status( $this->get_id() ) ) {
424 $user_ids = $this->get_users();
425 if ( ! empty( $user_ids ) ) {
426 $customer_name = array();
427 foreach ( $user_ids as $uid ) {
428 $customer = learn_press_get_user( $uid );
429 if ( $customer && $customer->is_exists() ) {
430 if ( $customer->get_data( 'display_name' ) ) {
431 $customer_name[] = $customer->get_data( 'display_name' );
432 } elseif ( $customer->get_data( 'user_nicename' ) ) {
433 $customer_name[] = $customer->get_data( 'user_nicename' );
434 } elseif ( $customer->get_data( 'user_login' ) ) {
435 $customer_name[] = $customer->get_data( 'user_login' );
436 }
437 } else {
438 $customer_name[] = $this->get_guest_customer_name();
439 }
440 }
441
442 $customer_name = join( ', ', $customer_name );
443 }
444 }
445
446 if ( ! $customer_name ) {
447 $customer_name = $this->get_guest_customer_name();
448 }
449
450 return $customer_name;
451 }
452
453 public function get_guest_customer_name() {
454 $checkout_email = $this->get_checkout_email();
455 if ( $checkout_email ) {
456 $customer_name = sprintf( __( '%s (Guest)', 'learnpress' ), $checkout_email );
457 } else {
458 $customer_name = sprintf( __( '(Guest)', 'learnpress' ), $checkout_email );
459 }
460
461 return apply_filters( 'learn-press/order/guest-customer-name', $customer_name );
462 }
463
464 /*public function customer_exists() {
465 return false !== get_userdata( $this->get_data( 'user_id' ) );
466 }*/
467
468 public $order_items_loaded = false;
469
470 /**
471 * Get items of the order
472 *
473 * @return mixed
474 */
475 public function get_items() {
476 if ( $this->order_items_loaded ) {
477 return $this->order_items_loaded;
478 }
479
480 $items = $this->_curd->read_items( $this );
481
482 $this->order_items_loaded = $items;
483
484 return apply_filters( 'learn-press/order-items', $items );
485 }
486
487 /**
488 * Get items of the order by filter
489 *
490 * @param array $filter
491 *
492 * @return mixed
493 * @author tungnx
494 */
495 public function get_items_filter( $filter = array() ) {
496 $items = $this->_curd->read_items_filter( $this, $filter );
497
498 return apply_filters( 'learn-press/order-items', $items );
499 }
500
501 public function is_child() {
502 return $this->get_parent_id();
503 }
504
505 public function get_parent() {
506 return $this->get_parent_id() ? learn_press_get_order( $this->get_parent_id() ) : false;
507 }
508
509 /**
510 * Get list of course ids from order.
511 *
512 * @return array|bool
513 * @editor tungnx
514 */
515 public function get_item_ids() {
516 $items = $this->get_items();
517
518 if ( $items ) {
519 $course_ids = array();
520 foreach ( $items as $item ) {
521 if ( isset( $item['course_id'] ) ) {
522 $course_ids[] = $item['course_id'];
523 }
524 }
525
526 return $course_ids;
527 /**
528 * Comment by tungnx. Because it will error if item didn't have key 'course_id'.
529 * Ex: case buy certificate, will not have that key
530 */
531 //return @wp_list_pluck( $items, 'course_id' );
532 }
533
534 return false;
535 }
536
537 /**
538 * Check is order of Guest (user not login)
539 *
540 * @return bool
541 */
542 public function is_guest(): bool {
543 return ! get_user_by( 'ID', $this->get_user_id() );
544 }
545
546 public function get_item_meta( &$item ) {
547 $metas = get_metadata( 'learnpress_order_item', $item['id'] );
548 if ( $metas ) {
549 foreach ( $metas as $k => $v ) {
550 $item[ preg_replace( '!^_!', '', $k ) ] = LP_Helper::maybe_unserialize( $v[0] );
551 }
552 }
553 }
554
555 /**
556 * Remove all items from an order
557 */
558 public function remove_order_items() {
559 global $wpdb;
560 $wpdb->query(
561 $wpdb->prepare(
562 "
563 DELETE FROM itemmeta
564 USING $wpdb->learnpress_order_itemmeta itemmeta
565 INNER JOIN $wpdb->learnpress_order_items items
566 WHERE itemmeta.learnpress_order_item_id = items.order_item_id
567 AND items.order_id = %d",
568 $this->get_id()
569 )
570 );
571 $wpdb->query(
572 $wpdb->prepare(
573 "
574 DELETE FROM {$wpdb->learnpress_order_items}
575 WHERE order_id = %d",
576 $this->get_id()
577 )
578 );
579 $wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->learnpress_order_itemmeta} AUTO_INCREMENT = %d", 1 ) );
580 $wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->learnpress_order_items} AUTO_INCREMENT = %d", 1 ) );
581 }
582
583 /**
584 * Add a new item to order.
585 *
586 * @param array|int $item
587 *
588 * @return int
589 * @throws Exception
590 * @editor tungnx
591 * @modify 4.1.5
592 */
593 public function add_item( $item ): int {
594 global $wpdb;
595 $lp_user_items_db = LP_User_Items_DB::getInstance();
596
597 try {
598 if ( is_numeric( $item ) ) {
599 $item = array(
600 'item_id' => absint( $item ),
601 'order_item_name' => get_the_title( $item ),
602 );
603 }
604
605 $item_type = get_post_type( $item['item_id'] );
606 if ( ! in_array( $item_type, learn_press_get_item_types_can_purchase() ) ) {
607 return false;
608 }
609
610 $item = wp_parse_args(
611 $item,
612 array(
613 'item_id' => 0,
614 'item_type' => '',
615 'order_item_name' => '',
616 'quantity' => 1,
617 'subtotal' => 0,
618 'total' => 0,
619 'meta' => array(),
620 )
621 );
622
623 switch ( $item_type ) {
624 case LP_COURSE_CPT:
625 $course = learn_press_get_course( $item['item_id'] );
626 $item['subtotal'] = apply_filters( 'learnpress/order/item/subtotal', $course->get_price() * $item['quantity'], $course, $item );
627 $item['total'] = apply_filters( 'learnpress/order/item/total', $course->get_price() * $item['quantity'], $course, $item );
628 $item['order_item_name'] = apply_filters( 'learnpress/order/item/title', $course->get_title(), $course, $item );
629
630 if ( $this->check_can_delete_item_old( $course ) ) {
631 // Delete lp_user_items old
632 $user_ids = $this->get_users();
633 foreach ( $user_ids as $user_id ) {
634 $lp_user_items_db->delete_user_items_old( $user_id, $course->get_id() );
635 }
636 // End
637 }
638
639 //learn_press_add_order_item_meta( $order_item_id, '_course_id', $item['item_id'] );
640 $item['meta']['_course_id'] = $item['item_id'];
641 break;
642 default:
643 $item = apply_filters( 'learnpress/order/add-item/item_type_' . $item_type, $item );
644 break;
645 }
646
647 // Insert new order item
648 $wpdb->insert(
649 $wpdb->learnpress_order_items,
650 array(
651 'order_item_name' => $item['order_item_name'],
652 'order_id' => $this->get_id(),
653 'item_id' => $item['item_id'],
654 'item_type' => $item_type,
655 ),
656 array(
657 '%s',
658 '%d',
659 '%d',
660 '%s',
661 )
662 );
663 $order_item_id = absint( $wpdb->insert_id );
664 // End insert new order item
665
666 // Add learnpress_order_itemmeta
667 $item['meta']['_quantity'] = $item['quantity'];
668 $item['meta']['_subtotal'] = $item['subtotal'] ?? 0;
669 $item['meta']['_total'] = $item['total'] ?? 0;
670
671 if ( is_array( $item['meta'] ) ) {
672 foreach ( $item['meta'] as $k => $v ) {
673 learn_press_add_order_item_meta( $order_item_id, $k, $v );
674 }
675 }
676
677 do_action( 'learn-press/added-order-item-data', $order_item_id, $item, $this->get_id() );
678 } catch ( Throwable $e ) {
679 error_log( __FUNCTION__ . ': ' . $e->getMessage() );
680 }
681
682 return $order_item_id;
683 }
684
685 /**
686 * Set total
687 *
688 * @param int|float $total
689 */
690 public function set_total( $total = 0 ) {
691 $this->_set_data( 'total', $total );
692 }
693
694 /**
695 * Get total
696 *
697 * @return int|float
698 */
699 public function get_total() {
700 return $this->get_data( 'total' );
701 }
702
703 /**
704 * @param float|int $subtotal
705 */
706 public function set_subtotal( $subtotal = 0 ) {
707 $this->_set_data( 'subtotal', $subtotal );
708 }
709
710 /**
711 * Get subtotal
712 *
713 * @return float
714 */
715 public function get_subtotal() {
716 return $this->get_data( 'subtotal' );
717 }
718
719 public function cln() {
720 return $this->_curd->cln( $this );
721 }
722
723 public function cln_items( $to ) {
724 return $this->_curd->cln_items( $this->get_id(), $to );
725 }
726
727 /**
728 * Remove an item from database and it's data.
729 *
730 * @param int $item_id
731 *
732 * @return bool
733 */
734 public function remove_item( $item_id ) {
735 global $wpdb;
736
737 $item_id = absint( $item_id );
738
739 if ( ! $item_id ) {
740 return false;
741 }
742
743 do_action( 'learn_press_before_delete_order_item', $item_id );
744
745 /**
746 * @since 3.0.0
747 */
748 do_action( 'learn-press/before-delete-order-item', $item_id, $this->get_id() );
749
750 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}learnpress_order_items WHERE order_item_id = %d", $item_id ) );
751 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}learnpress_order_itemmeta WHERE learnpress_order_item_id = %d", $item_id ) );
752
753 /**
754 * @since 3.0.0
755 */
756 do_action( 'learn-press/deleted-order-item', $item_id, $this->get_id() );
757
758 do_action( 'learn_press_delete_order_item', $item_id );
759
760 return true;
761 }
762
763 /**
764 * Add multiple items.
765 *
766 * @param array $items
767 *
768 * @return array
769 */
770 public function add_items( $items ) {
771 settype( $items, 'array' );
772 $item_ids = array();
773 foreach ( $items as $item ) {
774 $item_id = $this->add_item( $item );
775 if ( $item_id ) {
776 $item_ids[] = $item_id;
777 }
778 }
779
780 return $item_ids;
781 }
782
783 /**
784 * @param string $field
785 *
786 * @return array|bool|int|LP_User|mixed
787 */
788 public function get_user( $field = '' ) {
789
790 $users = $this->get_users();
791 $uid = reset( $users );
792
793 $user = learn_press_get_user( $uid );
794 if ( false === $user ) {
795 return false;
796 }
797
798 if ( strtolower( $field ) == 'id' ) {
799 return $user->get_id();
800 }
801
802 if ( $field && $user ) {
803 return $user->get_data( $field );
804 }
805
806 return $user;
807 }
808
809 /**
810 * Get user id in array.
811 * user_id = 0 -> User type Guest
812 * @return int[]
813 * @editor tungnx
814 * @modify 4.1.4
815 * @version 1.0.1
816 */
817 public function get_users(): array {
818 $users = $this->get_user_id();
819 if ( $users !== -1 ) {
820 settype( $users, 'array' );
821 $users = array_unique( $users );
822 } else {
823 $users = array();
824 }
825
826 return $users;
827 }
828
829 public function dropdown_users() {
830 $order_users = $this->get_users();
831 $users = get_users( array() );
832 echo '<select name="order-customer[]" id="order-customer" multiple="multiple">';
833 foreach ( (array) $users as $user ) {
834 // $user->get_id() = (int) $user->get_id();
835 if ( in_array( $user->get_id(), $order_users ) ) {
836 $found_selected = true;
837 } else {
838 $found_selected = false;
839 }
840 echo sprintf( '<option value="%d" %s>%s</option>', esc_attr( $user->get_id() ), selected( $found_selected, true, false ), esc_html( $user->user_login ) );
841 }
842 echo '</select>';
843 }
844
845
846 public function get_checkout_payment_url() {
847
848 }
849
850 public function get_formatted_order_subtotal() {
851 $currency_symbol = learn_press_get_currency_symbol( $this->get_currency() );
852
853 return learn_press_format_price( $this->get_subtotal(), $currency_symbol );
854 }
855
856 public function get_formatted_order_total() {
857 $currency_symbol = learn_press_get_currency_symbol( $this->get_currency() );
858
859 return learn_press_format_price( $this->get_total(), $currency_symbol );
860 }
861
862 public function get_currency() {
863 return $this->get_data( 'currency' ) ? $this->get_data( 'currency' ) : learn_press_get_currency();
864 }
865
866 public function set_currency( $value ) {
867 $this->_set_data( 'currency', $value );
868 }
869
870 public function get_payment_method_title() {
871 if ( $this->order_total == 0 ) {
872 $title = '';
873 } else {
874 $title = $this->payment_method_title;
875 }
876
877 return $title;
878 }
879
880 public function get_view_order_url() {
881 global $wp_query;
882
883 $view_order_url = learn_press_get_endpoint_url( 'view-order', $this->get_id(), learn_press_get_page_link( 'profile' ) );
884 $user = learn_press_get_current_user();
885 $view_order_endpoint = LP_Settings::instance()->get( 'profile_endpoints.order-details' );
886
887 if ( ! $view_order_endpoint ) {
888 $view_order_endpoint = 'order-details';
889 }
890
891 $view_order_endpoint = urlencode( $view_order_endpoint );
892 if ( get_option( 'permalink_structure' ) ) {
893 $view_order_url = learn_press_get_page_link( 'profile' ) . $user->get_data( 'user_login' ) . '/' . $view_order_endpoint . '/' . $this->get_id() . '/';
894 } else {
895 $args = array(
896 'user' => $user->get_data( 'user_login' ),
897 );
898 $args['view'] = $view_order_endpoint;
899
900 if ( $view_order_endpoint ) {
901 $args['id'] = $this->get_id();
902 }
903 $view_order_url = add_query_arg(
904 $args,
905 learn_press_get_page_link( 'profile' )
906 );
907 }
908
909 return apply_filters( 'learn_press_view_order_url', $view_order_url, $this );
910 }
911
912 /**
913 * Get cancel url if it's status is pending.
914 *
915 * @param bool $force
916 *
917 * @return mixed
918 */
919 public function get_cancel_order_url( $force = false ) {
920
921 $url = false;
922 if ( $this->has_status( 'pending' ) ) {
923 $user = learn_press_get_current_user();
924 $url = learn_press_user_profile_link( $user->get_id(), LP_Settings::instance()->get( 'profile_endpoints.profile-orders' ) );
925 if ( ! $force ) {
926 $url = esc_url_raw( add_query_arg( 'cancel-order', $this->get_id(), $url ) );
927 } else {
928 $url = esc_url_raw( add_query_arg( 'cancelled-order', $this->get_id(), $url ) );
929 }
930
931 $url = wp_nonce_url( $url, 'cancel-order', 'lp-nonce' );
932 }
933
934 return apply_filters( 'learn-press/order-cancel-url', $url, $this->get_id() );
935 }
936
937 /**
938 * Get profile order's actions.
939 *
940 * @return array|mixed
941 */
942 public function get_profile_order_actions() {
943 $actions = array(
944 'view' => array(
945 'url' => $this->get_view_order_url(),
946 'text' => __( 'View', 'learnpress' ),
947 ),
948 );
949
950 $cancel_url = $this->get_cancel_order_url();
951 if ( $cancel_url ) {
952 $actions['cancel'] = array(
953 'url' => $this->get_cancel_order_url(),
954 'text' => __( 'Cancel', 'learnpress' ),
955 );
956 }
957 $actions = apply_filters( 'learn-press/profile-order-actions', $actions, $this->get_id() );
958
959 return $actions;
960 }
961
962 public function add_note( $note = null ) {
963 if ( is_user_logged_in() ) {
964 $user = get_user_by( 'id', get_current_user_id() );
965 $comment_author = $user->display_name;
966 $comment_author_email = $user->user_email;
967 $comment_post_ID = $this->get_id();
968 $comment_author_url = '';
969 $comment_content = $note;
970 $comment_agent = 'LearnPress';
971 $comment_type = 'lp_order_note';
972 $comment_parent = 0;
973 $comment_approved = 1;
974
975 $commentdata = apply_filters(
976 'learn_press_new_order_note_data',
977 compact( 'comment_post_ID', 'comment_author', 'comment_author_email', 'comment_author_url', 'comment_content', 'comment_agent', 'comment_type', 'comment_parent', 'comment_approved' ),
978 $this->get_id()
979 );
980
981 $comment_id = wp_insert_comment( $commentdata );
982
983 return $comment_id;
984 }
985
986 return false;
987 }
988
989 /**
990 * Get user_name
991 *
992 * @param int $user_id
993 * @return string
994 */
995 public function get_user_name( int $user_id = 0 ): string {
996 $user = learn_press_get_user( $user_id );
997
998 if ( $user && ! $user instanceof LP_User_Guest ) {
999 $user_name = $user->get_display_name();
1000 } else {
1001 $user_name = $this->get_checkout_email();
1002 }
1003
1004 return apply_filters( 'learn-press/order/user-name', sprintf( _x( '%1$s', 'full name', 'learnpress' ), $user_name ) );
1005 }
1006
1007 /**
1008 * Check to see if this order is for multi users
1009 *
1010 * @return bool
1011 * @since 2.1.5
1012 */
1013 public function is_multi_users(): bool {
1014 return is_array( $this->get_user_id() );
1015 }
1016
1017 /**
1018 * Print the list of all users has assigned to this order
1019 * in case this order is for multi users
1020 *
1021 * @since 2.1.5
1022 * @depecated 4.1.6.9
1023 */
1024 /*public function print_users() {
1025 $user_ids = get_post_meta( $this->get_id(), '_user_id' );
1026 if ( $user_ids ) {
1027 global $wpdb;
1028 if ( is_array( $user_ids[0] ) ) {
1029 $user_ids = reset( $user_ids );
1030 }
1031 $format_ids = array_fill( 0, sizeof( $user_ids ), '%d' );
1032 $sql = $wpdb->prepare( "SELECT user_login, user_email FROM {$wpdb->users} WHERE ID IN(" . join( ',', $format_ids ) . ')', $user_ids );
1033 $users = $wpdb->get_results( $sql );
1034 $size = sizeof( $users );
1035
1036 foreach ( $users as $i => $user ) {
1037 printf( '<strong>%s</strong> ( %s )', $user->user_login, $user->user_email );
1038 if ( $i < $size - 1 ) {
1039 echo ', ';
1040 }
1041 }
1042 } else {
1043 _e( 'No user assigned', 'learnpress' );
1044 }
1045 }*/
1046
1047 /**
1048 * Get email of user has bought this order.
1049 * In case this order is for multi users return an array with multi email addresses.
1050 *
1051 * @return array
1052 * @since 2.1.5
1053 */
1054 public function get_user_data(): array {
1055 $data = array();
1056
1057 $user_ids = $this->get_users();
1058 if ( ! empty( $user_ids ) ) {
1059 foreach ( $user_ids as $user_id ) {
1060 $user = learn_press_get_user( $user_id );
1061 if ( $user->is_exists() ) {
1062 $data[ $user_id ] = $user->get_data(
1063 array(
1064 'id',
1065 'email',
1066 'user_login',
1067 'description',
1068 'first_name',
1069 'last_name',
1070 'nickname',
1071 'display_name',
1072 )
1073 );
1074 }
1075 }
1076 }
1077
1078 return $data;
1079 }
1080
1081 /**
1082 * Get email's user by user_id
1083 *
1084 * @param int $user_id
1085 * @return string
1086 * @editor tungnx
1087 * @modify 4.1.3
1088 */
1089 public function get_user_email( int $user_id = 0 ): string {
1090 $user = learn_press_get_user( $user_id );
1091 if ( $user && ! $user instanceof LP_User_Guest ) {
1092 $email = $user->get_email();
1093 } else {
1094 $email = $this->get_checkout_email();
1095 }
1096
1097 return $email;
1098 }
1099
1100 public function get_child_orders( $force = false ) {
1101 if ( $force ) {
1102 wp_cache_delete( 'order-' . $this->get_id(), 'learn-press/child-orders' );
1103 }
1104
1105 return apply_filters( 'learn-press/child-orders', $this->_curd->get_child_orders( $this->get_id() ), $this->get_id() );
1106 }
1107
1108 /**
1109 * Order title
1110 *
1111 * @param string $context
1112 *
1113 * @return array|mixed
1114 */
1115 public function get_title( $context = '' ) {
1116 return $this->get_data( 'order_title', __( 'Order on', 'learnpress' ) . ' ' . current_time( 'l jS F Y h:i:s A' ) );
1117 }
1118
1119 public function get_parent_id() {
1120 return $this->get_data( 'parent_id', 0 );
1121 }
1122
1123 public function set_parent_id( $parent_id ) {
1124 $this->_set_data( 'parent_id', $parent_id );
1125 }
1126
1127 public function set_user_id( $user_id ) {
1128 $this->_set_data( 'user_id', $user_id );
1129 }
1130
1131 /**
1132 * Set 1 for is user guest
1133 *
1134 * @param int $user_type_guest
1135 */
1136 public function set_user_type_guest( int $user_type_guest ) {
1137 $this->_set_data( 'user_type_guest', $user_type_guest );
1138 }
1139
1140 /**
1141 * Get user's ids of order.
1142 *
1143 * @return array|int
1144 */
1145 public function get_user_id() {
1146 return $this->get_data( 'user_id', -1 );
1147 }
1148
1149 /**
1150 * Get date modified of order.
1151 *
1152 * @return LP_Datetime
1153 */
1154 public function get_date_modified() {
1155 return $this->get_data( 'date_modified' );
1156 }
1157
1158 /**
1159 * Set date modified of order.
1160 *
1161 * @param mixed $date
1162 */
1163 public function set_date_modified( $date ) {
1164 $this->_set_data( 'date_modified', $date );
1165 }
1166
1167 /**
1168 * Set method for creating the order, such as: checkout
1169 *
1170 * @param string $created_via
1171 */
1172 public function set_created_via( $created_via ) {
1173 $this->_set_data( 'created_via', $created_via );
1174 }
1175
1176 /**
1177 * Get method which order is created, such as: checkout
1178 *
1179 * @return string
1180 */
1181 public function get_created_via(): string {
1182 return $this->get_data( 'created_via', '' );
1183 }
1184
1185 /**
1186 * Update order status if changed and trigger actions.
1187 *
1188 * @return bool
1189 * @throws Exception
1190 *
1191 * @editor tungnx
1192 * @modify 4.1.3 - comment - not use
1193 */
1194 // public function _save_status(): bool {
1195 //
1196 // // Nothing changed
1197 // if ( ! $this->_status ) {
1198 // return false;
1199 // }
1200 //
1201 // $order_id = $this->get_id();
1202 // $old_status = $this->_status['from'] ?? '';
1203 // $new_status = $this->_status['to'] ?? '';
1204 //
1205 // // Only update if new status is difference with old status.
1206 // if ( $new_status !== $old_status ) {
1207 //
1208 // if ( ! $this->get_user_id() ) {
1209 // // $new_status = 'pending';
1210 // }
1211 //
1212 // if ( doing_action( 'save_post' ) ) {
1213 // // Update post's status using wpdb to preventing loop
1214 // global $wpdb;
1215 // $updated = $wpdb->update( $wpdb->posts, array( 'post_status' => 'lp-' . $new_status ), array( 'ID' => $order_id ), array( '%s' ) );
1216 // } else {
1217 // $updated = wp_update_post(
1218 // array(
1219 // 'post_status' => 'lp-' . $new_status,
1220 // 'ID' => $order_id,
1221 // )
1222 // );
1223 // }
1224 //
1225 // // Clear cache
1226 // wp_cache_delete( $order_id, 'posts' );
1227 //
1228 // /**
1229 // * Trigger actions after status was changed
1230 // *
1231 // * @deprecated
1232 // */
1233 // //do_action( 'learn_press_order_status_' . $new_status, $order_id );
1234 // //do_action( 'learn_press_order_status_' . $old_status . '_to_' . $new_status, $order_id );
1235 // //do_action( 'learn_press_order_status_changed', $order_id, $old_status, $new_status );
1236 // // backward compatible
1237 // do_action( 'learn_press_update_order_status', $new_status, $order_id );
1238 //
1239 // /**
1240 // * @since 3.0.0
1241 // */
1242 // do_action( 'learn-press/order/status-' . $new_status, $order_id, $old_status );
1243 // do_action( 'learn-press/order/status-' . $old_status . '-to-' . $new_status, $order_id );
1244 // do_action( 'learn-press/order/status-changed', $order_id, $old_status, $new_status );
1245 //
1246 // return true;
1247 // }
1248 //
1249 // return false;
1250 // }
1251
1252 /**
1253 * Save order data.
1254 *
1255 * @return mixed
1256 *
1257 * @throws Exception
1258 */
1259 public function save() {
1260 $old_status = '';
1261
1262 if ( $this->get_id() ) {
1263 $old_status = str_replace( 'lp-', '', get_post_status( $this->get_id() ) );
1264 $return = $this->_curd->update( $this );
1265 } else {
1266 $return = $this->_curd->create( $this );
1267 }
1268
1269 $new_status = str_replace( 'lp-', '', get_post_status( $this->get_id() ) );
1270
1271 $order_id = $this->get_id();
1272
1273 if ( $new_status !== $old_status ) {
1274 do_action( 'learn-press/order/status-' . $new_status, $order_id, $old_status );
1275 do_action( 'learn-press/order/status-' . $old_status . '-to-' . $new_status, $order_id );
1276 do_action( 'learn-press/order/status-changed', $order_id, $old_status, $new_status );
1277 //do_action( 'learn_press_update_order_status', $new_status, $order_id );
1278 }
1279
1280 //$this->_save_status();
1281
1282 return $return;
1283 }
1284
1285 /**
1286 * Get an instance of LP_Order by post ID or WP_Post object
1287 *
1288 * @param $order
1289 * @param $force
1290 *
1291 * @return LP_Order
1292 */
1293 public static function instance( $order, $force = true ) {
1294 // learn_press_deprecated_function( 'new LP_Order', '3.0', 'learn_press_get_order' );
1295
1296 return learn_press_get_order( $order );
1297 }
1298
1299 /** Getter/Setter **/
1300
1301 public function set_customer_message( $message ) {
1302 $this->_set_data( 'customer_message', $message );
1303 }
1304
1305 public function set_customer_note( $note ) {
1306 $this->_set_data( 'customer_note', $note );
1307 }
1308
1309 public function get_customer_note() {
1310 return $this->get_data( 'customer_note' ) . '';
1311 }
1312
1313 public function set_user_ip_address( $value ) {
1314 $this->_set_data( 'user_ip_address', $value );
1315 }
1316
1317 public function set_user_agent( $value ) {
1318 $this->_set_data( 'user_agent', $value );
1319 }
1320
1321 public function get_user_agent() {
1322 return $this->get_data( 'user_agent' );
1323 }
1324
1325 public function set_checkout_email( $email ) {
1326 $this->_set_data( 'checkout_email', $email );
1327 }
1328
1329 /**
1330 * Get email checkout for case Guest
1331 *
1332 * @return string
1333 */
1334 public function get_checkout_email(): string {
1335 return $this->get_data( 'checkout_email', '' );
1336 }
1337
1338 /**
1339 * Short function to check order is completed.
1340 *
1341 * @return bool
1342 */
1343 public function is_completed(): bool {
1344 return $this->get_order_status() === 'completed';
1345 }
1346
1347 /**
1348 * Check Order is created manual.
1349 *
1350 * @return bool
1351 * @since 4.1.3
1352 * @author tungnx
1353 * @version 1.0.0
1354 */
1355 public function is_manual(): bool {
1356 return $this->get_created_via() === 'manual';
1357 }
1358
1359 /**
1360 * Check can delete lp_user_items old
1361 *
1362 * @param LP_Course $course
1363 *
1364 * @return bool
1365 * @throws Exception
1366 * @author tungnx
1367 * @since 4.1.4
1368 * @version 1.0.0
1369 */
1370 public function check_can_delete_item_old( LP_Course $course ): bool {
1371 $can_delete = false;
1372
1373 $lp_user_items_db = LP_User_Items_DB::getInstance();
1374
1375 /**
1376 * For case user buy on frontend (not LP Order manual)
1377 * And course enable repurchase and repurchase_type is keep
1378 */
1379 $allow_repurchase_type = '';
1380
1381 $filter = new LP_User_Items_Filter();
1382 $filter->user_id = get_current_user_id();
1383 $filter->item_id = $course->get_id();
1384 $user_course = $lp_user_items_db->get_last_user_course( $filter );
1385
1386 if ( $user_course && isset( $user_course->user_item_id ) ) {
1387 $latest_user_item_id = $user_course->user_item_id;
1388
1389 /** Get allow_repurchase_type for reset or update. Add in: rest-api/v1/frontend/class-lp-courses-controller.php: purchase_course */
1390 $allow_repurchase_type = learn_press_get_user_item_meta( $latest_user_item_id, '_lp_allow_repurchase_type' );
1391 }
1392
1393 /**
1394 * Course is free
1395 * Or not allow repurchase
1396 * Or repurchase not type 'Keep'
1397 * And else
1398 * Will deleted lp_user_items old
1399 */
1400 if ( $course->is_free() || empty( $allow_repurchase_type ) || ! $course->allow_repurchase() || $allow_repurchase_type != 'keep' ) {
1401 $can_delete = true;
1402 }
1403
1404 return apply_filters( 'learnpress/order/can_delete_old_item', $can_delete, $course );
1405 }
1406 }
1407 }
1408