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 +297 -496 4.1.74.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,243 +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 - */
316 -function learn_press_add_transaction( $args = null ) {
317 - // _deprecated_function( 'learn_press_add_transaction', '1.0', 'learn_press_add_order' );
318 - return learn_press_add_order( $args );
319 -}
320 -
321 -/**
322 - * @param null $args
323 - *
324 - * @return mixed
325 - */
326 -function learn_press_add_order( $args = null ) {
327 - // $method, $method_id, $status = 'Pending', $customer_id = false, $transaction_object = false, $args = array()
328 - $default_args = array(
329 - 'method' => '',
330 - 'method_id' => '',
331 - 'status' => '',
332 - 'user_id' => null,
333 - 'order_id' => 0,
334 - 'parent' => 0,
335 - 'transaction_object' => false,
336 - );
337 -
338 - $args = wp_parse_args( $args, $default_args );
339 - $order_data = array();
340 -
341 - if ( $args['order_id'] > 0 && get_post( $args['order_id'] ) ) {
342 - $updating = true;
343 - $order_data['ID'] = $args['order_id'];
344 - } else {
345 - $updating = false;
346 - $order_data['post_type'] = LP_ORDER_CPT;
347 - $order_data['post_status'] = ! empty( $args['status'] ) ? 'publish' : 'lpr-draft';
348 - $order_data['ping_status'] = 'closed';
349 - $order_data['post_author'] = ( $order_owner_id = learn_press_cart_order_instructor() ) ? $order_owner_id : 1; // always is administrator
350 - $order_data['post_parent'] = absint( $args['parent'] );
351 - }
352 - $order_title = array();
353 - if ( $args['method'] ) {
354 - $order_title[] = $args['method'];
355 - }
356 - if ( $args['method_id'] ) {
357 - $order_title[] = $args['method_id'];
358 - }
359 - $order_title[] = date_i18n( 'Y-m-d-H:i:s' );
360 - $order_data['post_title'] = join( '-', $order_title );
361 -
362 - if ( empty( $args['user_id'] ) ) {
363 - $user = learn_press_get_current_user();
364 - $args['user_id'] = $user->get_id();
365 - }
366 -
367 - if ( ! $args['transaction_object'] ) {
368 - $args['transaction_object'] = learn_press_generate_transaction_object();
369 - }
370 -
371 - if ( ! $updating ) {
372 - if ( wp_insert_post( $order_data ) ) {
373 - $transaction_id = wp_insert_post( $order_data );
374 -
375 - update_post_meta( $transaction_id, '_learn_press_transaction_method', $args['method'] );
376 -
377 - // update_post_meta( $transaction_id, '_learn_press_transaction_status', $status );
378 - update_post_meta( $transaction_id, '_learn_press_customer_id', $args['user_id'] );
379 - update_post_meta( $transaction_id, '_learn_press_customer_ip', learn_press_get_ip() );
380 - update_post_meta( $transaction_id, '_learn_press_order_items', $args['transaction_object'] );
381 -
382 - add_user_meta( $args['user_id'], '_lpr_order_id', $transaction_id );
383 -
384 - }
385 - } else {
386 - $transaction_id = wp_update_post( $order_data );
387 - }
388 -
389 - if ( $transaction_id ) {
390 - if ( ! empty( $args['status'] ) ) {
391 - learn_press_update_order_status( $transaction_id, $args['status'] );
392 - }
393 - update_post_meta( $transaction_id, '_learn_press_transaction_method_id', $args['method_id'] );
394 -
395 - if ( $args['transaction_object'] ) {
396 - update_post_meta( $transaction_id, '_learn_press_order_items', $args['transaction_object'] );
397 - }
398 -
399 - if ( ! empty( $args['status'] ) ) {
400 - if ( $updating ) {
401 - return apply_filters( 'learn_press_update_transaction_success', $transaction_id, $args );
402 - } else {
403 - return apply_filters( 'learn_press_add_transaction_success', $transaction_id, $args );
404 - }
405 - }
406 -
407 - return $transaction_id;
408 - }
409 -
410 - return false;
411 -
412 - // do_action( 'learn_press_add_transaction_fail', $args );// $method, $method_id, $status, $customer_id, $transaction_object, $args );
413 -}
414 -
415 -function learn_press_payment_method_from_slug( $order_id ) {
416 - $slug = get_post_meta( $order_id, '_learn_press_transaction_method', true );
417 -
418 - return apply_filters( 'learn_press_payment_method_from_slug_' . $slug, $slug );
419 -}
420 -
421 -function learn_press_generate_transaction_object() {
422 - $cart = learn_press_get_cart();
423 - $products = $cart->get_items();
424 -
425 - if ( $products ) {
426 - foreach ( $products as $key => $product ) {
427 - $products[ $key ]['product_base_price'] = floatval( learn_press_get_course_price( $product['id'] ) );
428 - $products[ $key ]['product_subtotal'] = floatval( learn_press_get_course_price( $product['id'] ) * $product['quantity'] );
429 - $products[ $key ]['product_name'] = get_the_title( $product['id'] );
430 - $products = apply_filters( 'learn_press_generate_transaction_object_products', $products, $key, $product );
431 - }
432 - }
433 -
434 - $transaction_object = new stdClass();
435 - $transaction_object->cart_id = $cart->get_cart_id();
436 - $transaction_object->total = round( $cart->get_total(), 2 );
437 - $transaction_object->sub_total = $cart->get_sub_total();
438 - $transaction_object->currency = learn_press_get_currency();
439 - $transaction_object->description = learn_press_get_cart_description();
440 - $transaction_object->products = $products;
441 - $transaction_object->coupons = '';
442 - $transaction_object->coupons_total_discount = '';
443 -
444 - $transaction_object = apply_filters( 'learn_press_generate_transaction_object', $transaction_object );
445 -
446 - return $transaction_object;
447 -}
448 -
449 -/**
450 - * Get the author ID of course in the cart
451 - *
452 - * Currently, it only get the first item in cart
453 - *
454 - * @return int
455 - */
456 -function learn_press_cart_order_instructor() {
457 - $cart = learn_press_get_cart();
458 - $products = $cart->get_items();
459 -
460 - if ( $products ) {
461 - foreach ( $products as $key => $product ) {
462 - $post = get_post( $product['id'] );
463 -
464 - if ( $post && ! empty( $post->ID ) ) {
465 - return $post->post_author;
466 - }
467 - }
468 - }
469 -
470 - return 0;
471 -}
472 -
473 -function learn_press_get_orders( $args = array() ) {
474 - // _deprecated_function( __FUNCTION__, '3.0.0', 'get_posts' );
475 - $args['post_type'] = LP_ORDER_CPT;
476 - $orders = get_posts( $args );
477 -
478 - return apply_filters( 'learn_press_get_orders', $orders, $args );
479 -}
480 -
481 -/**
482 123 * Count orders by it's status
483 124 *
484 125 * @param array $args
485 - *
126 + * @Todo tungnx review to rewrite query
486 127 * @return array
487 128 */
488 129 function learn_press_count_orders( $args = array() ) {
489 130 if ( is_string( $args ) ) {
@@ -499,10 +140,9 @@
499 140 global $wpdb;
500 141 $statuses = $args['status'];
501 142
502 143 if ( ! $statuses ) {
503 - $statuses = learn_press_get_register_order_statuses();
504 - $statuses = array_keys( $statuses );
144 + $statuses = array_keys( LP_Order::get_order_statuses() );
505 145 }
506 146
507 147 settype( $statuses, 'array' );
508 148 $size_of_status = sizeof( $statuses );
@@ -539,9 +179,9 @@
539 179
540 180 /**
541 181 * Format price with currency and other settings.
542 182 *
543 - * @param float $price
183 + * @param float $price
544 184 * @param string $currency
545 185 *
546 186 * @return string
547 187 */
@@ -551,12 +191,16 @@
551 191 }
552 192
553 193 $before = $after = '';
554 194
555 - $currency = is_string( $currency ) && '' !== $currency ? $currency : learn_press_get_currency_symbol();
556 - $thousands_separator = LP_Settings::get_option( 'thousands_separator', ',' );
557 - $number_of_decimals = LP_Settings::get_option( 'number_of_decimals', 2 );
558 - $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', '.' ) );
559 203
560 204 switch ( LP_Settings::get_option( 'currency_pos' ) ) {
561 205 default:
562 206 $before = $currency;
@@ -629,62 +273,8 @@
629 273 return apply_filters( 'learn-press/order-number-formatted', $formatted_number, $order_number );
630 274 }
631 275
632 276 /**
633 - * Get label of an order's statues.
634 - *
635 - * @param int|string $order_id - Optional. ID of an order or status.
636 - *
637 - * @return string|bool
638 - */
639 -function learn_press_get_order_status_label( $order_id = 0 ) {
640 - $statuses = learn_press_get_order_statuses();
641 - if ( is_numeric( $order_id ) ) {
642 - $status = get_post_status( $order_id );
643 - } else {
644 - $status = $order_id;
645 - }
646 -
647 - return ! empty( $statuses[ $status ] ) ? $statuses[ $status ] : false;
648 -}
649 -
650 -/**
651 - * Get list of registered order's statuses and/or labels.
652 - *
653 - * @param bool $prefix
654 - * @param bool $status_only
655 - *
656 - * @since 2.1.7
657 - *
658 - * @return array
659 - */
660 -function learn_press_get_order_statuses( $prefix = true, $status_only = false ) {
661 - $register_statues = learn_press_get_register_order_statuses();
662 -
663 - if ( ! $prefix ) {
664 - $order_statuses = array();
665 - foreach ( $register_statues as $k => $v ) {
666 - $k = preg_replace( '~^lp-~', '', $k );
667 - $order_statuses[ $k ] = $v;
668 - }
669 - } else {
670 - $order_statuses = $register_statues;
671 - }
672 -
673 - $order_statuses = wp_list_pluck( $order_statuses, 'label' );
674 -
675 - if ( $status_only ) {
676 - $order_statuses = array_keys( $order_statuses );
677 - }
678 -
679 - // @deprecated
680 - $order_statuses = apply_filters( 'learn_press_order_statuses', $order_statuses );
681 -
682 - // @since 3.0.0
683 - return apply_filters( 'learn-press/order-statues', $order_statuses );
684 -}
685 -
686 -/**
687 277 * Get list of registered order's statues for registering with wp post's status.
688 278 *
689 279 * @since 2.0.0
690 280 *
@@ -692,8 +282,16 @@
692 282 */
693 283 function learn_press_get_register_order_statuses() {
694 284 $order_statues = array();
695 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 + );
696 294 $order_statues['lp-pending'] = array(
697 295 'label' => _x( 'Pending', 'Order status', 'learnpress' ),
698 296 'public' => false,
699 297 'exclude_from_search' => false,
@@ -708,16 +306,8 @@
708 306 'show_in_admin_all_list' => true,
709 307 'show_in_admin_status_list' => true,
710 308 'label_count' => _n_noop( 'Processing <span class="count">(%s)</span>', 'Processing <span class="count">(%s)</span>', 'learnpress' ),
711 309 );
712 - $order_statues['lp-completed'] = array(
713 - 'label' => _x( 'Completed', 'Order status', 'learnpress' ),
714 - 'public' => false,
715 - 'exclude_from_search' => false,
716 - 'show_in_admin_all_list' => true,
717 - 'show_in_admin_status_list' => true,
718 - 'label_count' => _n_noop( 'Completed <span class="count">(%s)</span>', 'Completed <span class="count">(%s)</span>', 'learnpress' ),
719 - );
720 310 $order_statues['lp-cancelled'] = array(
721 311 'label' => _x( 'Cancelled', 'Order status', 'learnpress' ),
722 312 'public' => false,
723 313 'exclude_from_search' => false,
@@ -732,24 +322,41 @@
732 322 'show_in_admin_all_list' => true,
733 323 'show_in_admin_status_list' => true,
734 324 'label_count' => _n_noop( 'Failed <span class="count">(%s)</span>', 'Failed <span class="count">(%s)</span>', 'learnpress' ),
735 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 + );
736 342
737 343 return $order_statues;
738 344 }
739 345
740 346 function _learn_press_get_order_status_description( $status ) {
741 - static $descriptions = null;
742 - $descriptions = array(
743 - 'pending' => __( 'Order received in case user buy a course but doesn\'t finalise the order.', 'learnpress' ),
347 +
348 + $status = str_replace( 'lp-', '', (string) $status );
349 + $descriptions = array(
350 + 'pending' => __( 'Order received in case a user purchases a course but doesn\'t finalize the order.', 'learnpress' ),
744 351 'processing' => __( 'Payment received and the order is awaiting fulfillment.', 'learnpress' ),
745 - 'completed' => __( 'Order fulfilled and complete.', 'learnpress' ),
352 + 'completed' => __( 'The order is fulfilled and completed.', 'learnpress' ),
746 353 'cancelled' => __( 'The order is cancelled by an admin or the customer.', 'learnpress' ),
354 + 'refunded' => __( 'Order was refunded to the customer.', 'learnpress' ),
747 355 );
748 356
749 357 return apply_filters( 'learn_press_order_status_description', ! empty( $descriptions[ $status ] ) ? $descriptions[ $status ] : '' );
750 358 }
751 -
752 359 /**
753 360 * Get status of an order by the ID.
754 361 *
755 362 * @param int $order_id
@@ -756,8 +363,9 @@
756 363 *
757 364 * @return bool|string
758 365 */
759 366 function learn_press_get_order_status( $order_id ) {
367 +
760 368 $order = learn_press_get_order( $order_id );
761 369
762 370 if ( $order ) {
763 371 return $order->get_status();
@@ -765,8 +373,74 @@
765 373
766 374 return false;
767 375 }
768 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 +
769 443 if ( ! function_exists( 'learn_press_cancel_order_process' ) ) {
770 444 /**
771 445 * Process action allows user to cancel an order is pending
772 446 * in their profile.
@@ -771,43 +445,209 @@
771 445 * Process action allows user to cancel an order is pending
772 446 * in their profile.
773 447 */
774 448 function learn_press_cancel_order_process() {
775 - if ( empty( $_REQUEST['cancel-order'] ) || empty( $_REQUEST['lp-nonce'] ) || ! wp_verify_nonce( $_REQUEST['lp-nonce'], 'cancel-order' ) || is_admin() ) {
449 +
450 + if ( empty( $_REQUEST['cancel-order'] ) || empty( $_REQUEST['lp-nonce'] ) ||
451 + ! wp_verify_nonce( $_REQUEST['lp-nonce'], 'cancel-order' ) || is_admin() ) {
776 452 return;
777 453 }
778 454
779 - $order_id = absint( $_REQUEST['cancel-order'] );
780 - $order = learn_press_get_order( $order_id );
781 - $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 + );
782 460
783 - if ( ! $order ) {
784 - learn_press_add_message( sprintf( __( 'Order number <strong>%s</strong> not found', 'learnpress' ), $order_id ), 'error' );
785 - } elseif ( $order->has_status( 'pending' ) ) {
786 - $order->update_status( 'cancelled' );
787 - $order->add_note( __( 'Order cancelled by customer', 'learnpress' ) );
461 + try {
462 + $message = array(
463 + 'status' => 'error',
464 + 'content' => '',
465 + );
788 466
789 - // set updated message
790 - learn_press_add_message( sprintf( __( 'Order number <strong>%s</strong> has been cancelled', 'learnpress' ), $order->get_order_number() ) );
791 - $url = $order->get_cancel_order_url( true );
792 - } else {
793 - learn_press_add_message( sprintf( __( '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();
794 495 }
795 - if ( ! $url ) {
796 - $url = learn_press_user_profile_link( $user->get_id(), LP_Settings::instance()->get( 'profile_endpoints.profile-orders', 'orders' ) );
797 - }
496 +
497 + learn_press_set_message( $message );
798 498 wp_safe_redirect( $url );
799 499 exit();
800 500 }
801 501 }
802 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 + }
803 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 + }
804 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 +}
805 571 /**
806 - * get total price order complete
572 + * Render pending refund request panel on order detail.
807 573 *
574 + * @since 4.3.4
575 + * @version 1.0.0
576 + * @param LP_Order $order
808 577 */
578 +function learn_press_admin_order_refund_request_panel( $order ) {
809 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 + */
810 650 function learn_press_get_total_price_order_complete() {
811 651 global $wpdb;
812 652
813 653 $query = $wpdb->prepare(
@@ -813,54 +653,15 @@
813 653 $query = $wpdb->prepare(
814 654 "SELECT SUM(meta_value) as order_total From `{$wpdb->prefix}postmeta` as mt
815 655 INNER JOIN `{$wpdb->prefix}posts` as p ON p.id = mt.post_id
816 656 WHERE p.post_type = %s AND mt.meta_key = %s
657 + AND p.post_status = %s
817 658 ",
818 659 LP_ORDER_CPT,
819 - '_order_total'
660 + '_order_total',
661 + 'lp-completed'
820 662 );
821 663
822 664 $total = $wpdb->get_results( $query )[0]->order_total;
823 665
824 666 return learn_press_format_price( $total, true );
825 -
826 667 }
827 -/**
828 - * Auto enroll course after user checkout
829 - *
830 - * @param $result
831 - * @param $order_id
832 - * @editor tungnx - comment - for not use
833 - */
834 -/*function _learn_press_checkout_auto_enroll_free_course( $result, $order_id ) {
835 - return;
836 - $enrolled = false;
837 - $order = learn_press_get_order( $order_id, true );
838 -
839 - if ( $order_id && $order ) {
840 - $user = learn_press_get_user( $order->user_id, true );
841 - $order_items = $order->get_items();
842 -
843 - if ( $order_items ) {
844 - foreach ( $order_items as $item ) {
845 - if ( $user->has_enrolled_course( $item['course_id'] ) ) {
846 - continue;
847 - }
848 - if ( $user->enroll( $item['course_id'] ) ) {
849 - $enrolled = $item['course_id'];
850 - }
851 - }
852 - if ( ! $enrolled ) {
853 - $item = reset( $order_items );
854 - $enrolled = $item['course_id'];
855 - }
856 - }
857 - }
858 - if ( $enrolled ) {
859 - learn_press_add_message( sprintf( __( 'You have enrolled in this course. <a href="%s">Order details</a>', 'learnpress' ), $result['redirect'] ) );
860 - $result['redirect'] = get_the_permalink( $enrolled );
861 - LP()->cart->empty_cart();
862 - }
863 -
864 - return $result;
865 -}*/
866 -