Queue individual order syncing instead of handling immediately.

This commit is contained in:
Jeff Stieler 2019-01-29 14:37:59 -07:00
parent 9f3c95ae63
commit 11d18a8b5b
5 changed files with 80 additions and 51 deletions

View File

@ -37,6 +37,11 @@ class WC_Admin_Api_Init {
*/
const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init';
/**
* Action hook for processing a batch of orders.
*/
const SINGLE_ORDER_ACTION = 'wc-admin_process_order';
/**
* Queue instance.
*
@ -59,12 +64,8 @@ class WC_Admin_Api_Init {
add_filter( 'rest_endpoints', array( 'WC_Admin_Api_Init', 'filter_rest_endpoints' ), 10, 1 );
add_filter( 'woocommerce_debug_tools', array( 'WC_Admin_Api_Init', 'add_regenerate_tool' ) );
// Initialize Orders data store class's static vars.
add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'orders_data_store_init' ), 20 );
// Initialize Customers Report data store sync hooks.
// Note: we need to hook in before `wc_current_user_is_active`.
// See: https://github.com/woocommerce/woocommerce/blob/942615101ba00c939c107c3a4820c3d466864872/includes/wc-user-functions.php#L749.
add_action( 'wp_loaded', array( 'WC_Admin_Api_Init', 'customers_report_data_store_init' ) );
// Initialize syncing hooks.
add_action( 'wp_loaded', array( __CLASS__, 'orders_lookup_update_init' ) );
// Initialize scheduled action handlers.
add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 3 );
@ -72,6 +73,7 @@ class WC_Admin_Api_Init {
add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ) );
add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ) );
add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ) );
add_action( self::SINGLE_ORDER_ACTION, array( __CLASS__, 'orders_lookup_process_order' ) );
// Add currency symbol to orders endpoint response.
add_filter( 'woocommerce_rest_prepare_shop_order_object', array( __CLASS__, 'add_currency_symbol_to_order_response' ) );
@ -457,16 +459,58 @@ class WC_Admin_Api_Init {
}
/**
* Init orders data store.
* Schedule an action to process a single Order.
*
* @param int $order_id Order ID.
* @return void
*/
public static function orders_data_store_init() {
public static function schedule_single_order_process( $order_id ) {
if ( 'shop_order' !== get_post_type( $order_id ) ) {
return;
}
// This can get called multiple times for a single order, so we look
// for existing pending jobs for the same order to avoid duplicating efforts.
$existing_jobs = self::queue()->search(
array(
'status' => 'pending',
'per_page' => 1,
'claimed' => false,
'search' => "[{$order_id}]",
)
);
if ( $existing_jobs ) {
$existing_job = current( $existing_jobs );
// Bail out if there's a pending single order action, or a pending dependent action.
if (
( self::SINGLE_ORDER_ACTION === $existing_job->get_hook() ) ||
(
self::QUEUE_DEPEDENT_ACTION === $existing_job->get_hook() &&
in_array( self::SINGLE_ORDER_ACTION, $existing_job->get_args() )
)
) {
return;
}
}
// We want to ensure that customer lookup updates are scheduled before order updates.
self::queue_dependent_action( self::SINGLE_ORDER_ACTION, array( $order_id ), self::CUSTOMERS_BATCH_ACTION );
}
/**
* Attach order lookup update hooks.
*/
public static function orders_lookup_update_init() {
// Activate WC_Order extension.
WC_Admin_Order::add_filters();
// Initialize data stores.
add_action( 'save_post_shop_order', array( __CLASS__, 'schedule_single_order_process' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'schedule_single_order_process' ) );
WC_Admin_Reports_Orders_Stats_Data_Store::init();
WC_Admin_Reports_Products_Data_Store::init();
WC_Admin_Reports_Taxes_Data_Store::init();
WC_Admin_Reports_Coupons_Data_Store::init();
WC_Admin_Reports_Customers_Data_Store::init();
}
/**
@ -512,19 +556,35 @@ class WC_Admin_Api_Init {
$order_ids = $order_query->get_orders();
foreach ( $order_ids as $order_id ) {
// @todo: schedule single order update if this fails?
WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id );
WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id );
WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id );
WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id );
self::orders_lookup_process_order( $order_id );
}
}
/**
* Init customers report data store.
* Process a single order to update lookup tables for.
* If an error is encountered in one of the updates, a retry action is scheduled.
*
* @param int $order_id Order ID.
* @return void
*/
public static function customers_report_data_store_init() {
WC_Admin_Reports_Customers_Data_Store::init();
public static function orders_lookup_process_order( $order_id ) {
$result = array_sum(
array(
WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ),
WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ),
WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id ),
WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id ),
)
);
// If all updates were either skipped or successful, we're done.
// The update methods return -1 for skip, or a boolean success indicator.
if ( 4 === absint( $result ) ) {
return;
}
// Otherwise assume an error occurred and reschedule.
self::schedule_single_order_process( $order_id );
}
/**

View File

@ -51,15 +51,6 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
}
/**
* Set up all the hooks for maintaining and populating table data.
*/
public static function init() {
add_action( 'save_post', array( __CLASS__, 'sync_order_coupons' ) );
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_coupons' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_coupons' ) );
}
/**
* Returns comma separated ids of included coupons, based on query arguments from the user.
*

View File

@ -73,10 +73,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
* Set up all the hooks for maintaining and populating table data.
*/
public static function init() {
add_action( 'save_post', array( __CLASS__, 'sync_order' ) );
// @todo: this is required as order update skips save_post.
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order' ) );
add_action( 'woocommerce_refund_deleted', array( __CLASS__, 'sync_on_refund_delete' ), 10, 2 );
add_action( 'delete_post', array( __CLASS__, 'delete_order' ) );
}

View File

@ -82,15 +82,6 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
}
/**
* Set up all the hooks for maintaining and populating table data.
*/
public static function init() {
add_action( 'save_post', array( __CLASS__, 'sync_order_products' ) );
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_products' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_products' ) );
}
/**
* Fills ORDER BY clause of SQL request based on user supplied parameters.
*

View File

@ -66,15 +66,6 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
}
/**
* Set up all the hooks for maintaining and populating table data.
*/
public static function init() {
add_action( 'save_post', array( __CLASS__, 'sync_order_taxes' ) );
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_taxes' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_taxes' ) );
}
/**
* Updates the database query with parameters used for Taxes report: categories and order status.
*