Open Fayeakuzzamantonmoy opened 3 weeks ago
@getdokan/product @mrabbani
Regarding the question of which statuses should be whitelisted for updating suborders when an admin updates the parent order, I propose the following whitelist:
This whitelist aims to prevent issues like the one reported in #2341, where a canceled suborder was incorrectly marked as completed. By treating Canceled and Refunded as final states that can't be automatically changed, we ensure that vendor-canceled orders remain canceled regardless of parent order updates.
@Mohaiminulislam1989 vai, let me know what approach we should follow
@getdokan/product
CC: @mrabbani vai
@getdokan/product @mrabbani
Regarding the question of which statuses should be whitelisted for updating suborders when an admin updates the parent order, I propose the following whitelist:
- Pending Payment: Can be updated to any status
- On Hold: Can be updated to any status except Canceled and Refunded
- Processing: Can be updated to Completed, Failed, Canceled, or Refunded
- Completed: Can only be updated to Refunded
- Failed: Can be updated to any status except Completed
- Canceled: Cannot be automatically updated to any other status
- Refunded: Cannot be automatically updated to any other status
This whitelist aims to prevent issues like the one reported in #2341, where a canceled suborder was incorrectly marked as completed. By treating Canceled and Refunded as final states that can't be automatically changed, we ensure that vendor-canceled orders remain canceled regardless of parent order updates.
@Mohaiminulislam1989 vai, let me know what approach we should follow
@getdokan/product
CC: @mrabbani vai
Your whitelist is correct, alhamdulillah.
Update the on_order_status_change
method in the Dokan to handle sub-order status changes based on the main order status update, following a customizable whitelist and preventing incorrect status updates.
Create a new private method is_status_change_allowed
Modify the on_order_status_change
method
Add logging for skipped status updates
is_status_change_allowed
method:/**
* Check if a status change is allowed for a sub-order.
*
* @since x.x.x
*
* @param string $current_status The current status of the sub-order (should include 'wc-' prefix).
* @param string $new_status The new status to check (should include 'wc-' prefix).
*
* @return bool True if the status change is allowed, false otherwise.
*/
private function is_status_change_allowed( $current_status, $new_status ) {
// Ensure both statuses have 'wc-' prefix
$current_status = $this->maybe_add_wc_prefix( $current_status );
$new_status = $this->maybe_add_wc_prefix( $new_status );
// Define the default whitelist of allowed status transitions
$default_whitelist = [
'wc-pending' => ['any'],
'wc-on-hold' => ['wc-pending', 'wc-on-hold', 'wc-processing', 'wc-completed', 'wc-failed'],
'wc-processing' => ['wc-completed', 'wc-failed', 'wc-cancelled', 'wc-refunded'],
'wc-completed' => ['wc-refunded'],
'wc-failed' => ['wc-pending', 'wc-on-hold', 'wc-processing', 'wc-failed', 'wc-cancelled'],
'wc-cancelled' => [],
'wc-refunded' => []
];
/**
* Filter the whitelist of allowed status transitions for sub-orders.
*
* @since x.x.x
*
* @param array $default_whitelist The default whitelist of allowed status transitions.
*/
$whitelist = apply_filters( 'dokan_sub_order_status_update_whitelist', $default_whitelist );
// If the current status is not in the whitelist, status change is not allowed
if ( ! isset( $whitelist[ $current_status ] ) ) {
return false;
}
// If 'any' is allowed for the current status, all transitions are allowed
if ( in_array( 'any', $whitelist[ $current_status ], true ) ) {
return true;
}
// Check if the new status is in the list of allowed transitions
return in_array( $new_status, $whitelist[ $current_status ], true );
}
/**
* Ensure a status string has the 'wc-' prefix.
*
* @since x.x.x
*
* @param string $status The status string to check.
*
* @return string The status string with 'wc-' prefix added if it was missing.
*/
private function maybe_add_wc_prefix( $status ) {
return strpos( $status, 'wc-' ) === 0 ? $status : 'wc-' . $status;
}
on_order_status_change
method:/**
* Update the child order status when a parent order status is changed.
*
* @since x.x.x
*
* @param int $order_id
* @param string $old_status
* @param string $new_status
* @param WC_Order $order
*
* @return void
*/
public function on_order_status_change( $order_id, $old_status, $new_status, $order ) {
global $wpdb;
// Existing code for splitting orders remains unchanged
// Update status in dokan_orders table
$wpdb->update(
$wpdb->dokan_orders,
[ 'order_status' => $new_status ],
[ 'order_id' => $order_id ],
[ '%s' ],
[ '%d' ]
);
// Update sub-orders
$sub_orders = dokan()->order->get_child_orders( $order_id );
if ( $sub_orders ) {
foreach ( $sub_orders as $sub_order ) {
$sub_order_status = $sub_order->get_status();
if ( $this->is_status_change_allowed( $sub_order_status, $new_status ) ) {
$update_status = apply_filters( 'dokan_update_sub_order_status', $new_status, $sub_order, $order );
if ( $update_status !== $sub_order_status ) {
$sub_order->update_status( $update_status );
}
} else {
$this->log_skipped_status_update( $sub_order->get_id(), $sub_order_status, $new_status );
}
}
}
// Existing code for updating vendor balance remains unchanged
}
/**
* Log skipped status updates for sub-orders.
*
* @since x.x.x
*
* @param int $order_id The ID of the sub-order.
* @param string $current_status The current status of the sub-order.
* @param string $new_status The new status that was not applied.
*
* @return void
*/
private function log_skipped_status_update( $order_id, $current_status, $new_status ) {
dokan_log( sprintf( 'Skipped status update for sub-order %d from %s to %s', $order_id, $current_status, $new_status ) );
}
@mrabbani vai, would you kindly review it and share your feedback?
Problem:
When a customer completes a purchase involving at least two vendors within one order, a single order is generated in the admin panel, which contains two suborders. Each vendor can view and manage their respective suborder in their vendor dashboard.
Issue:
If a vendor marks their suborder as canceled from the vendor dashboard, the suborder is correctly marked as canceled in the admin panel. However, if the admin later marks the entire order as completed, the previously canceled suborder is incorrectly marked as completed as well.
Steps to Reproduce
Expected Behavior
Impact
Suggested Solution
Environment