PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 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 All 139 releases
← All changes | inc/order/lp-order-functions.php +291 -503 4.2.04.4.8 View file →
@@ -5,8 +5,10 @@
5 5 * @author ThimPress
6 6 * @package LearnPress/Functions
7 7 * @version 1.0
8 8 */
9 +use LearnPress\Models\UserItems\UserCourseModel;
10 +use LearnPress\Models\UserModel;
9 11
10 12 defined( 'ABSPATH' ) || exit;
11 13
12 14 /**
@@ -18,61 +20,8 @@
18 20 return apply_filters( 'learn-press/order-key', strtoupper( uniqid( 'ORDER' ) ) );
19 21 }
20 22
21 23 /**
22 - * Return default order status when creating new.
23 - *
24 - * @param string $prefix . Optional
25 - *
26 - * @return string
27 - */
28 -function learn_press_default_order_status( $prefix = '' ) {
29 - return apply_filters( 'learn-press/default-order-status', $prefix . 'pending' );
30 -}
31 -
32 -/**
33 - * Create or update an order.
34 - * If an 'ID' is passed throught $order_data, then update the existing order
35 - *
36 - * @param array $order_data {
37 - * Array of options to add or update an order
38 - *
39 - * @type int ID The order ID
40 - * @type
41 - * }
42 - *
43 - * @return LP_Order|WP_Error
44 - * @editor tungnx
45 - * @modify 4.1.4 - comment - not use
46 - */
47 -/*function learn_press_create_order( $order_data ) {
48 -
49 - $order = new LP_Order();
50 - $order->save();
51 -
52 - return $order;
53 -}*/
54 -
55 -/**
56 - * Create a new order or update an existing
57 - *
58 - * @param array $order_data
59 - *
60 - * @return LP_Order|WP_Error
61 - *
62 - * @throws Exception
63 - */
64 -
65 -/*function learn_press_update_order( $order_data ) {
66 - if ( empty( $order_data['order_id'] ) ) {
67 - throw new Exception( __( 'Invalid order ID when updating.', 'learnpress' ) );
68 - }
69 -
70 - return learn_press_create_order( $order_data );
71 -}*/
72 -
73 -/**************************/
74 -/**
75 24 * Update Order status
76 25 *
77 26 * @param int
78 27 * @param string
@@ -88,85 +37,8 @@
88 37 return false;
89 38 }
90 39
91 40 /**
92 - * Add an order item into order.
93 - *
94 - * @param int $order_id
95 - * @param mixed $item - Array of item data or ID
96 - *
97 - * @return bool
98 - * @editor tungnx
99 - * @modify 4.1.4 - comment - not use
100 - */
101 -/*function learn_press_add_order_item( $order_id, $item ) {
102 - $item_id = false;
103 - $order = learn_press_get_order( $order_id );
104 -
105 - if ( $order ) {
106 - $item_id = $order->add_item( $item );
107 - }
108 -
109 - return $item_id;
110 -}*/
111 -
112 -/**
113 - * Remove an order item by order_item_id.
114 - *
115 - * @param int $order_id
116 - * @param int $item_id
117 - *
118 - * @return bool
119 - */
120 -function learn_press_remove_order_item( $order_id, $item_id ) {
121 - $order = learn_press_get_order( $order_id );
122 -
123 - if ( $order ) {
124 - return $order->remove_item( $item_id );
125 - }
126 -
127 - return false;
128 -}
129 -
130 -function _learn_press_before_delete_order_item( $item_id, $order_id ) {
131 - global $wpdb;
132 - $order = learn_press_get_order_by_item_id( $item_id );
133 -
134 - if ( $order ) {
135 - $course_id = learn_press_get_order_item_meta( $item_id, '_course_id' );
136 - learn_press_delete_user_data( $order->user_id, $course_id );
137 - }
138 -}
139 -
140 -// add_action( 'learn-press/before-delete-order-item', '_learn_press_before_delete_order_item', 10, 2 );
141 -
142 -function _learn_press_ajax_add_order_item_meta( $item ) {
143 - $item_id = $item['id'];
144 - $order = learn_press_get_order_by_item_id( $item_id );
145 -
146 - if ( $order ) {
147 - if ( $order->get_status() == 'completed' ) {
148 - learn_press_auto_enroll_user_to_courses( $order->id );
149 - }
150 - }
151 -}
152 -
153 -add_action( 'learn_press_ajax_add_order_item_meta', '_learn_press_ajax_add_order_item_meta' );
154 -
155 -function learn_press_get_order_by_item_id( $item_id ) {
156 - global $wpdb;
157 -
158 - $order_id = $wpdb->get_var( $wpdb->prepare( "SELECT order_id FROM {$wpdb->prefix}learnpress_order_items WHERE order_item_id = %d", $item_id ) );
159 - $order = learn_press_get_order( $order_id );
160 -
161 - if ( $order_id && $order ) {
162 - return $order;
163 - }
164 -
165 - return false;
166 -}
167 -
168 -/**
169 41 * Add order item meta data.
170 42 *
171 43 * @param int $item_id
172 44 * @param string $meta_key
@@ -247,250 +119,12 @@
247 119 return new LP_Order( $the_id );
248 120 }
249 121
250 122 /**
251 - * get confirm order URL
252 - *
253 - * @param int $order_id
254 - *
255 - * @return string
256 - */
257 -function learn_press_get_order_confirm_url( $order_id = 0 ) {
258 - $url = '';
259 - $confirm_page_id = learn_press_get_page_id( 'taken_course_confirm' );
260 -
261 - if ( $confirm_page_id && get_post( $confirm_page_id ) ) {
262 - $url = get_permalink( $confirm_page_id );
263 -
264 - if ( $order_id ) {
265 - $url = join( preg_match( '!\?!', $url ) ? '&' : '?', array( $url, "order_id={$order_id}" ) );
266 - }
267 - } else {
268 - $order = new LP_Order( $order_id );
269 - $items = $order->get_items();
270 -
271 - if ( $items && ! empty( $items->products ) ) {
272 - $course = reset( $items->products );
273 - $url = get_permalink( $course['id'] );
274 - } else {
275 - $url = get_home_url();
276 - }
277 - }
278 -
279 - return $url;
280 -}
281 -
282 -
283 -function learn_press_do_transaction( $method, $transaction = false ) {
284 - LP_Gateways::instance()->get_available_payment_gateways();
285 -
286 - do_action( 'learn_press_do_transaction_' . $method, $transaction );
287 -}
288 -
289 -function learn_press_set_transient_transaction( $method, $temp_id, $user_id, $transaction ) {
290 - set_transient(
291 - $method . '-' . $temp_id,
292 - array(
293 - 'user_id' => $user_id,
294 - 'transaction_object' => $transaction,
295 - ),
296 - 60 * 60 * 24
297 - );
298 -}
299 -
300 -function learn_press_get_transient_transaction( $method, $temp_id ) {
301 - return get_transient( $method . '-' . $temp_id );
302 -}
303 -
304 -function learn_press_delete_transient_transaction( $method, $temp_id ) {
305 - return delete_transient( $method . '-' . $temp_id );
306 -}
307 -
308 -
309 -/**
310 - * Deprecated function
311 - *
312 - * @param array $args
313 - *
314 - * @return int
315 - * @deprecated 4.2.0
316 - */
317 -function learn_press_add_transaction( $args = null ) {
318 - // _deprecated_function( 'learn_press_add_transaction', '1.0', 'learn_press_add_order' );
319 - return learn_press_add_order( $args );
320 -}
321 -
322 -/**
323 - * @param null $args
324 - *
325 - * @return mixed
326 - * @deprecated 4.2.0
327 - */
328 -function learn_press_add_order( $args = null ) {
329 - _deprecated_function( __FUNCTION__, '4.2.0' );
330 - // $method, $method_id, $status = 'Pending', $customer_id = false, $transaction_object = false, $args = array()
331 - /*$default_args = array(
332 - 'method' => '',
333 - 'method_id' => '',
334 - 'status' => '',
335 - 'user_id' => null,
336 - 'order_id' => 0,
337 - 'parent' => 0,
338 - 'transaction_object' => false,
339 - );
340 -
341 - $args = wp_parse_args( $args, $default_args );
342 - $order_data = array();
343 -
344 - if ( $args['order_id'] > 0 && get_post( $args['order_id'] ) ) {
345 - $updating = true;
346 - $order_data['ID'] = $args['order_id'];
347 - } else {
348 - $updating = false;
349 - $order_data['post_type'] = LP_ORDER_CPT;
350 - $order_data['post_status'] = ! empty( $args['status'] ) ? 'publish' : 'lpr-draft';
351 - $order_data['ping_status'] = 'closed';
352 - $order_data['post_author'] = ( $order_owner_id = learn_press_cart_order_instructor() ) ? $order_owner_id : 1; // always is administrator
353 - $order_data['post_parent'] = absint( $args['parent'] );
354 - }
355 - $order_title = array();
356 - if ( $args['method'] ) {
357 - $order_title[] = $args['method'];
358 - }
359 - if ( $args['method_id'] ) {
360 - $order_title[] = $args['method_id'];
361 - }
362 - $order_title[] = date_i18n( 'Y-m-d-H:i:s' );
363 - $order_data['post_title'] = join( '-', $order_title );
364 -
365 - if ( empty( $args['user_id'] ) ) {
366 - $user = learn_press_get_current_user();
367 - $args['user_id'] = $user->get_id();
368 - }
369 -
370 - if ( ! $args['transaction_object'] ) {
371 - $args['transaction_object'] = learn_press_generate_transaction_object();
372 - }
373 -
374 - if ( ! $updating ) {
375 - if ( wp_insert_post( $order_data ) ) {
376 - $transaction_id = wp_insert_post( $order_data );
377 -
378 - update_post_meta( $transaction_id, '_learn_press_transaction_method', $args['method'] );
379 -
380 - // update_post_meta( $transaction_id, '_learn_press_transaction_status', $status );
381 - update_post_meta( $transaction_id, '_learn_press_customer_id', $args['user_id'] );
382 - update_post_meta( $transaction_id, '_learn_press_customer_ip', learn_press_get_ip() );
383 - update_post_meta( $transaction_id, '_learn_press_order_items', $args['transaction_object'] );
384 -
385 - add_user_meta( $args['user_id'], '_lpr_order_id', $transaction_id );
386 -
387 - }
388 - } else {
389 - $transaction_id = wp_update_post( $order_data );
390 - }
391 -
392 - if ( $transaction_id ) {
393 - if ( ! empty( $args['status'] ) ) {
394 - learn_press_update_order_status( $transaction_id, $args['status'] );
395 - }
396 - update_post_meta( $transaction_id, '_learn_press_transaction_method_id', $args['method_id'] );
397 -
398 - if ( $args['transaction_object'] ) {
399 - update_post_meta( $transaction_id, '_learn_press_order_items', $args['transaction_object'] );
400 - }
401 -
402 - if ( ! empty( $args['status'] ) ) {
403 - if ( $updating ) {
404 - return apply_filters( 'learn_press_update_transaction_success', $transaction_id, $args );
405 - } else {
406 - return apply_filters( 'learn_press_add_transaction_success', $transaction_id, $args );
407 - }
408 - }
409 -
410 - return $transaction_id;
411 - }
412 -
413 - return false;*/
414 -
415 - // do_action( 'learn_press_add_transaction_fail', $args );// $method, $method_id, $status, $customer_id, $transaction_object, $args );
416 -}
417 -
418 -function learn_press_payment_method_from_slug( $order_id ) {
419 - $slug = get_post_meta( $order_id, '_learn_press_transaction_method', true );
420 -
421 - return apply_filters( 'learn_press_payment_method_from_slug_' . $slug, $slug );
422 -}
423 -
424 -/**
425 - * @deprecated 4.2.0
426 - */
427 -function learn_press_generate_transaction_object() {
428 - _deprecated_function( __FUNCTION__, '4.2.0' );
429 - /*$cart = learn_press_get_cart();
430 - $products = $cart->get_items();
431 -
432 - if ( $products ) {
433 - foreach ( $products as $key => $product ) {
434 - $products[ $key ]['product_base_price'] = floatval( learn_press_get_course_price( $product['id'] ) );
435 - $products[ $key ]['product_subtotal'] = floatval( learn_press_get_course_price( $product['id'] ) * $product['quantity'] );
436 - $products[ $key ]['product_name'] = get_the_title( $product['id'] );
437 - $products = apply_filters( 'learn_press_generate_transaction_object_products', $products, $key, $product );
438 - }
439 - }
440 -
441 - $transaction_object = new stdClass();
442 - $transaction_object->cart_id = $cart->get_cart_id();
443 - $transaction_object->total = round( $cart->get_total(), 2 );
444 - $transaction_object->sub_total = $cart->get_sub_total();
445 - $transaction_object->currency = learn_press_get_currency();
446 - $transaction_object->description = learn_press_get_cart_description();
447 - $transaction_object->products = $products;
448 - $transaction_object->coupons = '';
449 - $transaction_object->coupons_total_discount = '';
450 -
451 - $transaction_object = apply_filters( 'learn_press_generate_transaction_object', $transaction_object );
452 -
453 - return $transaction_object;*/
454 -}
455 -
456 -/**
457 - * Get the author ID of course in the cart
458 - *
459 - * Currently, it only get the first item in cart
460 - *
461 - * @return int
462 - */
463 -function learn_press_cart_order_instructor() {
464 - $cart = learn_press_get_cart();
465 - $products = $cart->get_items();
466 -
467 - if ( $products ) {
468 - foreach ( $products as $key => $product ) {
469 - $post = get_post( $product['id'] );
470 -
471 - if ( $post && ! empty( $post->ID ) ) {
472 - return $post->post_author;
473 - }
474 - }
475 - }
476 -
477 - return 0;
478 -}
479 -
480 -function learn_press_get_orders( $args = array() ) {
481 - // _deprecated_function( __FUNCTION__, '3.0.0', 'get_posts' );
482 - $args['post_type'] = LP_ORDER_CPT;
483 - $orders = get_posts( $args );
484 -
485 - return apply_filters( 'learn_press_get_orders', $orders, $args );
486 -}
487 -
488 -/**
489 123 * Count orders by it's status
490 124 *
491 125 * @param array $args
492 - *
126 + * @Todo tungnx review to rewrite query
493 127 * @return array
494 128 */
495 129 function learn_press_count_orders( $args = array() ) {
496 130 if ( is_string( $args ) ) {
@@ -545,9 +179,9 @@
545 179
546 180 /**
547 181 * Format price with currency and other settings.
548 182 *
549 - * @param float $price
183 + * @param float $price
550 184 * @param string $currency
551 185 *
552 186 * @return string
553 187 */
@@ -557,12 +191,16 @@
557 191 }
558 192
559 193 $before = $after = '';
560 194
561 - $currency = is_string( $currency ) && '' !== $currency ? $currency : learn_press_get_currency_symbol();
562 - $thousands_separator = LP_Settings::get_option( 'thousands_separator', ',' );
563 - $number_of_decimals = LP_Settings::get_option( 'number_of_decimals', 2 );
564 - $decimals_separator = LP_Settings::get_option( 'decimals_separator', '.' );
195 + $currency = esc_html(
196 + is_string( $currency ) && '' !== $currency
197 + ? $currency
198 + : learn_press_get_currency_symbol()
199 + );
200 + $thousands_separator = esc_html( LP_Settings::get_option( 'thousands_separator', ',' ) );
201 + $number_of_decimals = esc_html( LP_Settings::get_option( 'number_of_decimals', 2 ) );
202 + $decimals_separator = esc_html( LP_Settings::get_option( 'decimals_separator', '.' ) );
565 203
566 204 switch ( LP_Settings::get_option( 'currency_pos' ) ) {
567 205 default:
568 206 $before = $currency;
@@ -635,66 +273,8 @@
635 273 return apply_filters( 'learn-press/order-number-formatted', $formatted_number, $order_number );
636 274 }
637 275
638 276 /**
639 - * Get label of an order's statues.
640 - *
641 - * @param int|string $order_id - Optional. ID of an order or status.
642 - *
643 - * @return string|bool
644 - * @deprecated 4.2.0
645 - */
646 -function learn_press_get_order_status_label( $order_id = 0 ) {
647 - _deprecated_function( __FUNCTION__, '4.2.0' );
648 - $statuses = learn_press_get_order_statuses();
649 - if ( is_numeric( $order_id ) ) {
650 - $status = get_post_status( $order_id );
651 - } else {
652 - $status = $order_id;
653 - }
654 -
655 - return ! empty( $statuses[ $status ] ) ? $statuses[ $status ] : false;
656 -}
657 -
658 -/**
659 - * Get list of registered order's statuses and/or labels.
660 - *
661 - * @param bool $prefix
662 - * @param bool $status_only
663 - *
664 - * @since 2.1.7
665 - *
666 - * @return array
667 - * @deprecated 4.2.0
668 - */
669 -function learn_press_get_order_statuses( $prefix = true, $status_only = false ) {
670 - _deprecated_function( __FUNCTION__, '4.2.0' );
671 - $register_statues = learn_press_get_register_order_statuses();
672 -
673 - if ( ! $prefix ) {
674 - $order_statuses = array();
675 - foreach ( $register_statues as $k => $v ) {
676 - $k = preg_replace( '~^lp-~', '', $k );
677 - $order_statuses[ $k ] = $v;
678 - }
679 - } else {
680 - $order_statuses = $register_statues;
681 - }
682 -
683 - $order_statuses = wp_list_pluck( $order_statuses, 'label' );
684 -
685 - if ( $status_only ) {
686 - $order_statuses = array_keys( $order_statuses );
687 - }
688 -
689 - // @deprecated
690 - $order_statuses = apply_filters( 'learn_press_order_statuses', $order_statuses );
691 -
692 - // @since 3.0.0
693 - return apply_filters( 'learn-press/order-statues', $order_statuses );
694 -}
695 -
696 -/**
697 277 * Get list of registered order's statues for registering with wp post's status.
698 278 *
699 279 * @since 2.0.0
700 280 *
@@ -702,8 +282,16 @@
702 282 */
703 283 function learn_press_get_register_order_statuses() {
704 284 $order_statues = array();
705 285
286 + $order_statues['lp-completed'] = array(
287 + 'label' => _x( 'Completed', 'Order status', 'learnpress' ),
288 + 'public' => false,
289 + 'exclude_from_search' => false,
290 + 'show_in_admin_all_list' => true,
291 + 'show_in_admin_status_list' => true,
292 + 'label_count' => _n_noop( 'Completed <span class="count">(%s)</span>', 'Completed <span class="count">(%s)</span>', 'learnpress' ),
293 + );
706 294 $order_statues['lp-pending'] = array(
707 295 'label' => _x( 'Pending', 'Order status', 'learnpress' ),
708 296 'public' => false,
709 297 'exclude_from_search' => false,
@@ -718,16 +306,8 @@
718 306 'show_in_admin_all_list' => true,
719 307 'show_in_admin_status_list' => true,
720 308 'label_count' => _n_noop( 'Processing <span class="count">(%s)</span>', 'Processing <span class="count">(%s)</span>', 'learnpress' ),
721 309 );
722 - $order_statues['lp-completed'] = array(
723 - 'label' => _x( 'Completed', 'Order status', 'learnpress' ),
724 - 'public' => false,
725 - 'exclude_from_search' => false,
726 - 'show_in_admin_all_list' => true,
727 - 'show_in_admin_status_list' => true,
728 - 'label_count' => _n_noop( 'Completed <span class="count">(%s)</span>', 'Completed <span class="count">(%s)</span>', 'learnpress' ),
729 - );
730 310 $order_statues['lp-cancelled'] = array(
731 311 'label' => _x( 'Cancelled', 'Order status', 'learnpress' ),
732 312 'public' => false,
733 313 'exclude_from_search' => false,
@@ -742,24 +322,41 @@
742 322 'show_in_admin_all_list' => true,
743 323 'show_in_admin_status_list' => true,
744 324 'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'learnpress' ),
745 325 );
326 + $order_statues['lp-refunded'] = array(
327 + 'label' => _x( 'Refunded', 'Order status', 'learnpress' ),
328 + 'public' => false,
329 + 'exclude_from_search' => false,
330 + 'show_in_admin_all_list' => true,
331 + 'show_in_admin_status_list' => true,
332 + 'label_count' => _n_noop( 'Refunded <span class="count">(%s)</span>', 'Refunded <span class="count">(%s)</span>', 'learnpress' ),
333 + );
334 + $order_statues['trash'] = array(
335 + 'label' => _x( 'Trash', 'Order status', 'learnpress' ),
336 + 'public' => false,
337 + 'exclude_from_search' => false,
338 + 'show_in_admin_all_list' => true,
339 + 'show_in_admin_status_list' => true,
340 + 'label_count' => _n_noop( 'Trash <span class="count">(%s)</span>', 'Trash <span class="count">(%s)</span>', 'learnpress' ),
341 + );
746 342
747 343 return $order_statues;
748 344 }
749 345
750 346 function _learn_press_get_order_status_description( $status ) {
751 - static $descriptions = null;
752 - $descriptions = array(
347 +
348 + $status = str_replace( 'lp-', '', (string) $status );
349 + $descriptions = array(
753 350 'pending' => __( 'Order received in case a user purchases a course but doesn\'t finalize the order.', 'learnpress' ),
754 351 'processing' => __( 'Payment received and the order is awaiting fulfillment.', 'learnpress' ),
755 352 'completed' => __( 'The order is fulfilled and completed.', 'learnpress' ),
756 353 'cancelled' => __( 'The order is cancelled by an admin or the customer.', 'learnpress' ),
354 + 'refunded' => __( 'Order was refunded to the customer.', 'learnpress' ),
757 355 );
758 356
759 357 return apply_filters( 'learn_press_order_status_description', ! empty( $descriptions[ $status ] ) ? $descriptions[ $status ] : '' );
760 358 }
761 -
762 359 /**
763 360 * Get status of an order by the ID.
764 361 *
765 362 * @param int $order_id
@@ -766,8 +363,9 @@
766 363 *
767 364 * @return bool|string
768 365 */
769 366 function learn_press_get_order_status( $order_id ) {
367 +
770 368 $order = learn_press_get_order( $order_id );
771 369
772 370 if ( $order ) {
773 371 return $order->get_status();
@@ -775,8 +373,74 @@
775 373
776 374 return false;
777 375 }
778 376
377 +if ( ! function_exists( 'learn_press_get_refund_setting' ) ) {
378 + /**
379 + * Get refund setting value with safe defaults.
380 + *
381 + * @param string $key
382 + * @param mixed $default
383 + *
384 + * @since 4.3.4
385 + * @version 1.0.0
386 + * @return mixed
387 + */
388 + function learn_press_get_refund_setting( string $key, $default = null ) {
389 + $defaults = array(
390 + 'enable_refund_requests' => 'no',
391 + 'auto_refund' => 'no',
392 + 'refund_time_limit' => 30,
393 + 'require_refund_reason' => 'no',
394 + 'allow_resend_after_rejected' => 'no',
395 + 'refund_max_completion' => 0,
396 + );
397 +
398 + if ( null === $default && array_key_exists( $key, $defaults ) ) {
399 + $default = $defaults[ $key ];
400 + }
401 +
402 + return LP_Settings::get_option( $key, $default );
403 + }
404 +}
405 +
406 +if ( ! function_exists( 'learn_press_get_order_refund_supported_gateways' ) ) {
407 + /**
408 + * Get list gateways that support refund.
409 + *
410 + * @since 4.3.4
411 + * @version 1.1.0
412 + * @return array
413 + */
414 + function learn_press_get_order_refund_supported_gateways(): array {
415 + if ( ! class_exists( 'LP_Gateways' ) ) {
416 + return array();
417 + }
418 +
419 + $gateways_instance = LP_Gateways::instance();
420 + if ( ! $gateways_instance || ! method_exists( $gateways_instance, 'get_gateways' ) ) {
421 + return array();
422 + }
423 +
424 + $supported_gateways = array();
425 + $all_gateways = (array) $gateways_instance->get_gateways();
426 + foreach ( $all_gateways as $gateway_id => $gateway ) {
427 + $gateway_id = sanitize_key( (string) $gateway_id );
428 + if ( empty( $gateway_id ) ) {
429 + continue;
430 + }
431 +
432 + if ( ! is_object( $gateway ) || ! is_callable( array( $gateway, 'refund' ) ) ) {
433 + continue;
434 + }
435 +
436 + $supported_gateways[] = $gateway_id;
437 + }
438 +
439 + return array_values( array_unique( $supported_gateways ) );
440 + }
441 +}
442 +
779 443 if ( ! function_exists( 'learn_press_cancel_order_process' ) ) {
780 444 /**
781 445 * Process action allows user to cancel an order is pending
782 446 * in their profile.
@@ -781,46 +445,209 @@
781 445 * Process action allows user to cancel an order is pending
782 446 * in their profile.
783 447 */
784 448 function learn_press_cancel_order_process() {
449 +
785 450 if ( empty( $_REQUEST['cancel-order'] ) || empty( $_REQUEST['lp-nonce'] ) ||
786 451 ! wp_verify_nonce( $_REQUEST['lp-nonce'], 'cancel-order' ) || is_admin() ) {
787 452 return;
788 453 }
789 454
790 - $url = '';
791 - $order_id = absint( $_REQUEST['cancel-order'] );
792 - $order = learn_press_get_order( $order_id );
793 - $user = learn_press_get_current_user();
455 + $user_id = get_current_user_id();
456 + $profile = LP_Profile::instance( $user_id );
457 + $url = $profile->get_tab_link(
458 + LP_Settings::instance()->get( 'profile_endpoints.orders', 'orders' )
459 + );
794 460
795 - if ( ! $order ) {
796 - learn_press_add_message( sprintf( __( 'Order number <strong>%s</strong> not found', 'learnpress' ), $order_id ), 'error' );
797 - } elseif ( $order->has_status( 'pending' ) ) {
798 - $order->update_status( LP_ORDER_CANCELLED );
799 - $order->add_note( __( 'The order is cancelled by the customer', 'learnpress' ) );
461 + try {
462 + $message = array(
463 + 'status' => 'error',
464 + 'content' => '',
465 + );
800 466
801 - // set updated message
802 - learn_press_add_message( sprintf( __( 'Order number <strong>%s</strong> has been cancelled', 'learnpress' ), $order->get_order_number() ) );
803 - $url = $order->get_cancel_order_url( true );
804 - } else {
805 - learn_press_add_message( sprintf( __( 'The order number <strong>%s</strong> can not be cancelled.', 'learnpress' ), $order->get_order_number() ), 'error' );
467 + $order_id = absint( $_REQUEST['cancel-order'] );
468 + $order = learn_press_get_order( $order_id );
469 +
470 + if ( ! $order ) {
471 + throw new Exception( sprintf( __( 'Order number <strong>%s</strong> not found', 'learnpress' ), $order_id ) );
472 + }
473 +
474 + $user_ids = (array) $order->get_user_id();
475 + if ( ! in_array( $user_id, $user_ids ) ) {
476 + throw new Exception( __( 'You do not have permission to cancel this order.', 'learnpress' ) );
477 + }
478 +
479 + if ( $order->has_status( LP_ORDER_PENDING ) ) {
480 + $order->update_status( LP_ORDER_CANCELLED );
481 + $order->add_note( __( 'The order is cancelled by the customer', 'learnpress' ) );
482 +
483 + $message['status'] = 'success';
484 + $message['content'] = sprintf( __( 'Order number <strong>%s</strong> has been cancelled', 'learnpress' ), $order->get_order_number() );
485 + } else {
486 + throw new Exception(
487 + sprintf(
488 + __( 'The order number <strong>%s</strong> can not be cancelled.', 'learnpress' ),
489 + $order->get_order_number()
490 + )
491 + );
492 + }
493 + } catch ( Throwable $e ) {
494 + $message['content'] = $e->getMessage();
806 495 }
807 496
808 - if ( ! $url ) {
809 - $url = learn_press_user_profile_link( $user->get_id(), LP_Settings::instance()->get( 'profile_endpoints.profile-orders', 'orders' ) );
810 - }
497 + learn_press_set_message( $message );
811 498 wp_safe_redirect( $url );
812 499 exit();
813 500 }
814 501 }
815 502 add_action( 'init', 'learn_press_cancel_order_process' );
503 +if ( ! function_exists( 'learn_press_get_order_refund_event_data' ) ) {
504 + /**
505 + * Build normalized refund event payload.
506 + *
507 + * @since 4.3.5
508 + * @version 1.0.1
509 + *
510 + * @param LP_Order $order
511 + * @param array $overrides
512 + *
513 + * @return array
514 + */
515 + function learn_press_get_order_refund_event_data( LP_Order $order, array $overrides = array() ): array {
516 + $order_id = $order->get_id();
517 + $requested_at = get_post_meta( $order_id, '_lp_refund_requested_at', true );
518 + if ( ! empty( $requested_at ) ) {
519 + $requested_at = new LP_Datetime( $requested_at );
520 + $requested_at = sprintf(
521 + esc_html__( '%1$s %2$s', 'learnpress' ),
522 + $requested_at->format( LP_Datetime::I18N_FORMAT_HAS_TIME ),
523 + LP_Datetime::get_timezone_string()
524 + );
525 + }
816 526
527 + $user_id = (int) $order->get_user_id();
528 + $userOrderModel = UserModel::find( $user_id, true );
529 + if ( $userOrderModel instanceof UserModel ) {
530 + $requested_by = $userOrderModel->get_display_name();
531 + } else {
532 + $requested_by = $order->get_checkout_email();
533 + }
817 534
535 + $data = array(
536 + 'order_id' => $order_id,
537 + 'order_number' => $order->get_order_number(),
538 + 'order_key' => $order->get_order_key(),
539 + 'order_status' => $order->get_status(),
540 + 'request_status' => $order->get_refund_request(),
541 + 'requested_by' => $requested_by,
542 + 'requested_at' => $requested_at,
543 + 'reviewed_by' => absint( get_post_meta( $order_id, '_lp_refund_reviewed_by', true ) ),
544 + 'reviewed_at' => (string) get_post_meta( $order_id, '_lp_refund_reviewed_at', true ),
545 + 'reason' => (string) get_post_meta( $order_id, LP_Order::META_KEY_REFUND_REQUEST_REASON, true ),
546 + 'requester_email' => '',
547 + 'admin_order_edit_url' => add_query_arg(
548 + array(
549 + 'post' => $order_id,
550 + 'action' => 'edit',
551 + ),
552 + admin_url( 'post.php' )
553 + ),
554 + );
555 +
556 + $requested_user_id = absint( $data['requested_by'] );
557 + if ( ! empty( $requested_user_id ) ) {
558 + $requested_user = get_user_by( 'id', $requested_user_id );
559 + if ( $requested_user instanceof WP_User ) {
560 + $data['requester_email'] = $requested_user->user_email;
561 + }
562 + }
563 +
564 + if ( ! empty( $overrides ) ) {
565 + $data = array_merge( $data, $overrides );
566 + }
567 +
568 + return $data;
569 + }
570 +}
818 571 /**
819 - * get total price order complete
572 + * Render pending refund request panel on order detail.
820 573 *
574 + * @since 4.3.4
575 + * @version 1.0.0
576 + * @param LP_Order $order
821 577 */
578 +function learn_press_admin_order_refund_request_panel( $order ) {
822 579
580 + if ( ! $order instanceof LP_Order ) {
581 + return;
582 + }
583 +
584 + $order_id = $order->get_id();
585 + if ( ! current_user_can( 'edit_post', $order_id ) ) {
586 + return;
587 + }
588 +
589 + $refund_event_data = learn_press_get_order_refund_event_data( $order );
590 + $refund_request_status = sanitize_key( (string) ( $refund_event_data['request_status'] ?? '' ) );
591 + $requested_by = $refund_event_data['requested_by'] ?? '';
592 + $requested_at = $refund_event_data['requested_at'] ?? '';
593 + $refund_reason = $refund_event_data['reason'] ?? '';
594 + $requester_email = '';
595 +
596 + $status_labels = array(
597 + 'pending' => __( 'Pending review', 'learnpress' ),
598 + 'approved' => __( 'Approved', 'learnpress' ),
599 + 'auto-approved' => __( 'Auto approved', 'learnpress' ),
600 + 'rejected' => __( 'Rejected', 'learnpress' ),
601 + );
602 + $status_label = $status_labels[ $refund_request_status ] ?? '';
603 + if ( empty( $status_label ) && ! empty( $refund_request_status ) ) {
604 + $status_label = ucwords( str_replace( '-', ' ', $refund_request_status ) );
605 + }
606 +
607 + $render_statuses = array( 'pending', 'approved', 'auto-approved' );
608 + if ( ! in_array( $refund_request_status, $render_statuses, true ) ) {
609 + return;
610 + }
611 +
612 + $is_pending = ( 'pending' === $refund_request_status );
613 + $currency_symbol = learn_press_get_currency_symbol( $order->get_currency() );
614 +
615 + $order_total = round( max( 0, floatval( $order->get_total() ) ), 2 );
616 + $order_total_formatted = learn_press_format_price( $order_total, $currency_symbol );
617 +
618 + // Refund amount is only meaningful once the refund has been executed
619 + // (approved/auto-approved), when _lp_refund_amount has been written.
620 + $refund_amount_formatted = '';
621 + if ( ! $is_pending ) {
622 + $refund_amount = get_post_meta( $order_id, LP_Order::META_KEY_REFUNDED_AMOUNT, true );
623 + if ( '' === $refund_amount || null === $refund_amount ) {
624 + $refund_amount = $order_total; // Fallback for full refunds without a stored amount.
625 + }
626 + $refund_amount = round( max( 0, floatval( $refund_amount ) ), 2 );
627 + $refund_amount_formatted = learn_press_format_price( $refund_amount, $currency_symbol );
628 + }
629 +
630 + learn_press_admin_view(
631 + 'meta-boxes/order/refund-request-panel',
632 + compact(
633 + 'order_id',
634 + 'is_pending',
635 + 'order_total',
636 + 'order_total_formatted',
637 + 'refund_amount_formatted',
638 + 'requested_by',
639 + 'requested_at',
640 + 'requester_email',
641 + 'refund_reason',
642 + 'status_label'
643 + )
644 + );
645 +}
646 +
647 +/**
648 + * get total price order complete
649 + */
823 650 function learn_press_get_total_price_order_complete() {
824 651 global $wpdb;
825 652
826 653 $query = $wpdb->prepare(
@@ -826,54 +653,15 @@
826 653 $query = $wpdb->prepare(
827 654 "SELECT SUM(meta_value) as order_total From `{$wpdb->prefix}postmeta` as mt
828 655 INNER JOIN `{$wpdb->prefix}posts` as p ON p.id = mt.post_id
829 656 WHERE p.post_type = %s AND mt.meta_key = %s
657 + AND p.post_status = %s
830 658 ",
831 659 LP_ORDER_CPT,
832 - '_order_total'
660 + '_order_total',
661 + 'lp-completed'
833 662 );
834 663
835 664 $total = $wpdb->get_results( $query )[0]->order_total;
836 665
837 666 return learn_press_format_price( $total, true );
838 -
839 667 }
840 -/**
841 - * Auto enroll course after user checkout
842 - *
843 - * @param $result
844 - * @param $order_id
845 - * @editor tungnx - comment - for not use
846 - */
847 -/*function _learn_press_checkout_auto_enroll_free_course( $result, $order_id ) {
848 - return;
849 - $enrolled = false;
850 - $order = learn_press_get_order( $order_id, true );
851 -
852 - if ( $order_id && $order ) {
853 - $user = learn_press_get_user( $order->user_id, true );
854 - $order_items = $order->get_items();
855 -
856 - if ( $order_items ) {
857 - foreach ( $order_items as $item ) {
858 - if ( $user->has_enrolled_course( $item['course_id'] ) ) {
859 - continue;
860 - }
861 - if ( $user->enroll( $item['course_id'] ) ) {
862 - $enrolled = $item['course_id'];
863 - }
864 - }
865 - if ( ! $enrolled ) {
866 - $item = reset( $order_items );
867 - $enrolled = $item['course_id'];
868 - }
869 - }
870 - }
871 - if ( $enrolled ) {
872 - learn_press_add_message( sprintf( __( 'You have enrolled in this course. <a href="%s">Order details</a>', 'learnpress' ), $result['redirect'] ) );
873 - $result['redirect'] = get_the_permalink( $enrolled );
874 - LearnPress::instance()->cart->empty_cart();
875 - }
876 -
877 - return $result;
878 -}*/
879 -