@@ -55,10 +55,10 @@ public function __construct() {
5555 add_action ( 'woocommerce_process_shop_order_meta ' , 'dokan_sync_insert_order ' , 60 );
5656 }
5757
58- // restore order stock if it's been reduced by twice
59- add_action ( 'woocommerce_reduce_order_stock ' , [ $ this , 'restore_reduced_order_stock ' ] );
58+ // prevent stock reduction for parent orders
59+ add_filter ( 'woocommerce_can_reduce_order_stock ' , [ $ this , 'prevent_stock_reduction_for_parent_order ' ], 10 , 2 );
6060
61- add_action ( 'woocommerce_reduce_order_stock ' , [ $ this , 'handle_order_notes_for_suborder ' ], 99 );
61+ add_action ( 'woocommerce_reduce_order_item_stock ' , [ $ this , 'sync_parent_order_item_stock ' ], 10 , 3 );
6262 }
6363
6464 /**
@@ -420,14 +420,14 @@ public function split_vendor_orders( $parent_order_id ) {
420420 * @throws Exception When the coupon is invalid for multiple vendors
421421 */
422422 public function ensure_coupon_is_valid ( bool $ valid , WC_Coupon $ coupon , WC_Discounts $ discounts ): bool {
423- $ available_vendors = [];
423+ $ available_vendors = [];
424424
425425 foreach ( $ discounts ->get_items () as $ item ) {
426426 if ( ! isset ( $ item ->product ) || ! $ item ->product instanceof WC_Product ) {
427427 continue ;
428428 }
429429
430- $ available_vendors [] = (int ) dokan_get_vendor_by_product ( $ item ->product ->get_id (), true );
430+ $ available_vendors [] = (int ) dokan_get_vendor_by_product ( $ item ->product ->get_id (), true );
431431 }
432432
433433 $ available_vendors = array_unique ( $ available_vendors );
@@ -449,86 +449,54 @@ public function ensure_coupon_is_valid( bool $valid, WC_Coupon $coupon, WC_Disco
449449 }
450450
451451 /**
452- * Restore order stock if it's been reduced by twice
452+ * Prevent stock reduction for parent orders
453453 *
454- * @param WC_Order $order
454+ * Parent orders should not have their stock reduced. Only sub-orders
455+ * should manage stock reductions.
455456 *
456- * @return void
457+ * @param bool $can_reduce Whether stock can be reduced.
458+ * @param WC_Order $order The order object.
459+ *
460+ * @return bool False if this is a parent order, true otherwise.
457461 */
458- public function restore_reduced_order_stock ( $ order ) {
459- // seems in rest request, there is no such issue like (stock reduced by twice ), so return early
460- if ( defined ( 'REST_REQUEST ' ) ) {
461- return ;
462+ public function prevent_stock_reduction_for_parent_order ( $ can_reduce , $ order ) {
463+ // If this is a parent order (has sub-orders ), prevent stock reduction
464+ if ( $ order -> get_meta ( 'has_sub_order ' ) ) {
465+ return false ;
462466 }
463467
464- // seems it's not a parent order so return early
465- if ( ! $ order ->get_meta ( 'has_sub_order ' ) ) {
466- return ;
467- }
468-
469- // Loop over all items.
470- foreach ( $ order ->get_items ( 'line_item ' ) as $ item ) {
471- // Only reduce stock once for each item.
472- $ product = $ item ->get_product ();
473- $ item_stock_reduced = $ item ->get_meta ( '_reduced_stock ' , true );
474-
475- if ( ! $ item_stock_reduced || ! $ product || ! $ product ->managing_stock () ) {
476- continue ;
477- }
478-
479- $ item_name = $ product ->get_formatted_name ();
480- $ new_stock = wc_update_product_stock ( $ product , $ item_stock_reduced , 'increase ' );
481-
482- if ( is_wp_error ( $ new_stock ) ) {
483- /* translators: %s item name. */
484- $ order ->add_order_note ( sprintf ( __ ( 'Unable to restore stock for item %s. ' , 'dokan-lite ' ), $ item_name ) );
485- continue ;
486- }
487-
488- $ item ->delete_meta_data ( '_reduced_stock ' );
489- $ item ->save ();
490- }
468+ return $ can_reduce ;
491469 }
492470
493471 /**
494- * Handle stock level wrong calculation in order notes for suborder
472+ * Sync parent order item stock metadata when sub- order item stock is reduced
495473 *
496- * @since 3.8.3
497- *
498- * @param WC_Order $order
474+ * When a sub-order item has its stock reduced, also update the parent order item's
475+ * _reduced_stock metadata to keep them in sync.
476+ * @param WC_Order_Item_Product $item The sub-order item.
477+ * @param array $change Change details (product, from, to).
478+ * @param WC_Order $order The sub-order.
499479 *
500480 * @return void
501481 */
502- public function handle_order_notes_for_suborder ( $ order ) {
503- //return if it has suborder. only continue if this is a suborder
504- if ( ! $ order ->get_meta ( ' has_sub_order ' ) ) {
482+ public function sync_parent_order_item_stock ( $ item , $ change , $ order ) {
483+ // Only process sub-orders (those with a parent)
484+ if ( ! $ order ->get_parent_id ( ) ) {
505485 return ;
506486 }
507487
508- $ notes = wc_get_order_notes ( [ 'order_id ' => $ order ->get_id () ] );
488+ // Get the parent order item ID from the sub-order item meta
489+ $ parent_item_id = $ item ->get_meta ( '_dokan_parent_order_item_id ' , true );
509490
510- //change stock level note status instead of deleting
511- foreach ( $ notes as $ note ) {
512- //here using the woocommerce as text domain because we are using woocommerce text for searching
513- if ( false !== strpos ( $ note ->content , __ ( 'Stock levels reduced: ' , 'woocommerce ' ) ) ) { //phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
514- //update notes status to `hold`, so that it will not show in order details page
515- wp_set_comment_status ( $ note ->id , 'hold ' );
516- }
491+ if ( ! $ parent_item_id ) {
492+ return ;
517493 }
518494
519- //adding stock level notes in order
520- foreach ( $ order ->get_items ( 'line_item ' ) as $ key => $ line_item ) {
521- $ product = $ line_item ->get_product ();
522-
523- if ( $ product ->get_manage_stock () ) {
524- $ stock_quantity = $ product ->get_stock_quantity ();
525- $ previous_quantity = (int ) $ stock_quantity + $ line_item ->get_quantity ();
526-
527- $ notes_content = $ product ->get_formatted_name () . ' ' . $ previous_quantity . '→ ' . $ stock_quantity ;
495+ $ reduced_qty = $ item ->get_meta ( '_reduced_stock ' , true );
528496
529- //here using the woocommerce as text domain because we are using woocommerce text for adding
530- $ order -> add_order_note ( __ ( ' Stock levels reduced: ' , ' woocommerce ' ) . ' ' . $ notes_content ); //phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
531- }
497+ // Update the parent item directly in the database
498+ if ( $ reduced_qty ) {
499+ wc_update_order_item_meta ( $ parent_item_id , ' _reduced_stock ' , $ reduced_qty );
532500 }
533- }
501+ }
534502}
0 commit comments