Add delete batch actions for orders and customers

This commit is contained in:
Joshua Flowers 2019-04-15 16:07:43 +08:00 committed by Jeff Stieler
parent a4d1256292
commit 0a229e3654
2 changed files with 170 additions and 50 deletions

View File

@ -47,10 +47,10 @@ class WC_Admin_ActionScheduler_WPPostStore extends ActionScheduler_wpPostStore {
$action_types = array(
WC_Admin_Reports_Sync::QUEUE_BATCH_ACTION,
WC_Admin_Reports_Sync::QUEUE_DEPEDENT_ACTION,
WC_Admin_Reports_Sync::CUSTOMERS_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_LOOKUP_BATCH_INIT,
WC_Admin_Reports_Sync::SINGLE_ORDER_ACTION,
WC_Admin_Reports_Sync::CUSTOMERS_IMPORT_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_IMPORT_BATCH_ACTION,
WC_Admin_Reports_Sync::ORDERS_IMPORT_BATCH_INIT,
WC_Admin_Reports_Sync::SINGLE_ORDER_IMPORT_ACTION,
);
foreach ( $action_types as $action_type ) {

View File

@ -22,24 +22,44 @@ class WC_Admin_Reports_Sync {
const QUEUE_DEPEDENT_ACTION = 'wc-admin_queue_dependent_action';
/**
* Action hook for processing a batch of customers.
* Action hook for importing a batch of customers.
*/
const CUSTOMERS_BATCH_ACTION = 'wc-admin_process_customers_batch';
/**
* Action hook for processing a batch of orders.
*/
const ORDERS_BATCH_ACTION = 'wc-admin_process_orders_batch';
const CUSTOMERS_IMPORT_BATCH_ACTION = 'wc-admin_import_customers_batch';
/**
* Action hook for initializing the orders lookup batch creation.
*/
const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init';
const CUSTOMERS_DELETE_BATCH_INIT = 'wc-admin_delete_customers_batch_init';
/**
* Action hook for processing a batch of orders.
* Action hook for importing a batch of customers.
*/
const SINGLE_ORDER_ACTION = 'wc-admin_process_order';
const CUSTOMERS_DELETE_BATCH_ACTION = 'wc-admin_delete_customers_batch';
/**
* Action hook for importing a batch of orders.
*/
const ORDERS_IMPORT_BATCH_ACTION = 'wc-admin_import_orders_batch';
/**
* Action hook for initializing the orders lookup batch creation.
*/
const ORDERS_IMPORT_BATCH_INIT = 'wc-admin_orders_lookup_import_batch_init';
/**
* Action hook for initializing the orders lookup batch deletion.
*/
const ORDERS_DELETE_BATCH_INIT = 'wc-admin_orders_lookup_delete_batch_init';
/**
* Action hook for deleting a batch of orders.
*/
const ORDERS_DELETE_BATCH_ACTION = 'wc-admin_delete_orders_batch';
/**
* Action hook for importing a batch of orders.
*/
const SINGLE_ORDER_IMPORT_ACTION = 'wc-admin_import_order';
/**
* Action scheduler group.
@ -85,22 +105,26 @@ class WC_Admin_Reports_Sync {
// Initialize scheduled action handlers.
add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 4 );
add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 3 );
add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ), 10, 3 );
add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ), 10, 3 );
add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ), 10, 2 );
add_action( self::SINGLE_ORDER_ACTION, array( __CLASS__, 'orders_lookup_process_order' ) );
add_action( self::CUSTOMERS_IMPORT_BATCH_ACTION, array( __CLASS__, 'customer_lookup_import_batch' ), 10, 3 );
add_action( self::CUSTOMERS_DELETE_BATCH_INIT, array( __CLASS__, 'customer_lookup_delete_batch_init' ) );
add_action( self::CUSTOMERS_DELETE_BATCH_ACTION, array( __CLASS__, 'customer_lookup_delete_batch' ) );
add_action( self::ORDERS_IMPORT_BATCH_ACTION, array( __CLASS__, 'orders_lookup_import_batch' ), 10, 4 );
add_action( self::ORDERS_IMPORT_BATCH_INIT, array( __CLASS__, 'orders_lookup_import_batch_init' ), 10, 3 );
add_action( self::ORDERS_DELETE_BATCH_ACTION, array( __CLASS__, 'orders_lookup_delete_batch' ), 10, 4 );
add_action( self::ORDERS_DELETE_BATCH_INIT, array( __CLASS__, 'orders_lookup_delete_batch_init' ), 10, 3 );
add_action( self::SINGLE_ORDER_IMPORT_ACTION, array( __CLASS__, 'orders_lookup_import_order' ) );
}
/**
* Regenerate data for reports.
*
* @param int|bool $days Number of days to process.
* @param int|bool $days Number of days to import.
* @param bool $skip_existing Skip exisiting records.
* @return string
*/
public static function regenerate_report_data( $days, $skip_existing ) {
self::customer_lookup_batch_init( $days, $skip_existing );
self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, array( $days, $skip_existing ), self::CUSTOMERS_BATCH_ACTION );
self::customer_lookup_import_batch_init( $days, $skip_existing );
self::queue_dependent_action( self::ORDERS_IMPORT_BATCH_INIT, array( $days, $skip_existing ), self::CUSTOMERS_IMPORT_BATCH_ACTION );
return __( 'Report table data is being rebuilt. Please allow some time for data to fully populate.', 'woocommerce-admin' );
}
@ -120,18 +144,36 @@ class WC_Admin_Reports_Sync {
}
/**
* Schedule an action to process a single Order.
* Delete all data for reports.
*
* @return string
*/
public static function delete_report_data() {
// Cancel all pending import jobs.
self::clear_queued_actions();
// Delete orders in batches.
self::queue()->schedule_single( time() + 5, self::ORDERS_DELETE_BATCH_INIT, array(), self::QUEUE_GROUP );
// Delete customers after order data is deleted.
self::queue_dependent_action( self::CUSTOMERS_DELETE_BATCH_INIT, array(), self::ORDERS_DELETE_BATCH_INIT );
return __( 'Report table data is being deleted.', 'woocommerce-admin' );
}
/**
* Schedule an action to import a single Order.
*
* @param int $order_id Order ID.
* @return void
*/
public static function schedule_single_order_process( $order_id ) {
public static function schedule_single_order_import( $order_id ) {
if ( 'shop_order' !== get_post_type( $order_id ) ) {
return;
}
if ( apply_filters( 'woocommerce_disable_order_scheduling', false ) ) {
self::orders_lookup_process_order( $order_id );
self::orders_lookup_import_order( $order_id );
return;
}
@ -152,10 +194,10 @@ class WC_Admin_Reports_Sync {
// 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::SINGLE_ORDER_IMPORT_ACTION === $existing_job->get_hook() ) ||
(
self::QUEUE_DEPEDENT_ACTION === $existing_job->get_hook() &&
in_array( self::SINGLE_ORDER_ACTION, $existing_job->get_args() )
in_array( self::SINGLE_ORDER_IMPORT_ACTION, $existing_job->get_args() )
)
) {
return;
@ -163,7 +205,7 @@ class WC_Admin_Reports_Sync {
}
// 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 );
self::queue_dependent_action( self::SINGLE_ORDER_IMPORT_ACTION, array( $order_id ), self::CUSTOMERS_IMPORT_BATCH_ACTION );
}
/**
@ -173,8 +215,8 @@ class WC_Admin_Reports_Sync {
// Activate WC_Order extension.
WC_Admin_Order::add_filters();
add_action( 'save_post', array( __CLASS__, 'schedule_single_order_process' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'schedule_single_order_process' ) );
add_action( 'save_post', array( __CLASS__, 'schedule_single_order_import' ) );
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'schedule_single_order_import' ) );
WC_Admin_Reports_Orders_Stats_Data_Store::init();
WC_Admin_Reports_Customers_Data_Store::init();
@ -186,11 +228,11 @@ class WC_Admin_Reports_Sync {
/**
* Init order/product lookup tables update (in batches).
*
* @param integer|boolean $days Number of days to process.
* @param integer|boolean $days Number of days to import.
* @param boolean $skip_existing Skip exisiting records.
*/
public static function orders_lookup_batch_init( $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::ORDERS_BATCH_ACTION );
public static function orders_lookup_import_batch_init( $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::ORDERS_IMPORT_BATCH_ACTION );
$orders = self::get_orders( 1, 1, $days, $skip_existing );
if ( 0 === $orders->total ) {
@ -199,7 +241,7 @@ class WC_Admin_Reports_Sync {
$num_batches = ceil( $orders->total / $batch_size );
self::queue_batches( 1, $num_batches, self::ORDERS_BATCH_ACTION, array( $days, $skip_existing ) );
self::queue_batches( 1, $num_batches, self::ORDERS_IMPORT_BATCH_ACTION, array( $days, $skip_existing ) );
}
/**
@ -253,30 +295,30 @@ class WC_Admin_Reports_Sync {
}
/**
* Process a batch of orders to update (stats and products).
* Imports a batch of orders to update (stats and products).
*
* @param int $batch_number Batch number to process (essentially a query page number).
* @param int|bool $days Number of days to process.
* @param int $batch_number Batch number to import (essentially a query page number).
* @param int|bool $days Number of days to import.
* @param bool $skip_existing Skip exisiting records.
* @return void
*/
public static function orders_lookup_process_batch( $batch_number, $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::ORDERS_BATCH_ACTION );
public static function orders_lookup_import_batch( $batch_number, $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::ORDERS_IMPORT_BATCH_ACTION );
$orders = self::get_orders( $batch_size, $batch_number, $days, $skip_existing );
foreach ( $orders->order_ids as $order_id ) {
self::orders_lookup_process_order( $order_id );
self::orders_lookup_import_order( $order_id );
}
}
/**
* Process a single order to update lookup tables for.
* Imports 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 orders_lookup_process_order( $order_id ) {
public static function orders_lookup_import_order( $order_id ) {
$result = array_sum(
array(
WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ),
@ -293,7 +335,7 @@ class WC_Admin_Reports_Sync {
}
// Otherwise assume an error occurred and reschedule.
self::schedule_single_order_process( $order_id );
self::schedule_single_order_import( $order_id );
}
/**
@ -305,9 +347,11 @@ class WC_Admin_Reports_Sync {
*/
public static function get_batch_size( $action ) {
$batch_sizes = array(
self::QUEUE_BATCH_ACTION => 100,
self::CUSTOMERS_BATCH_ACTION => 25,
self::ORDERS_BATCH_ACTION => 10,
self::QUEUE_BATCH_ACTION => 100,
self::CUSTOMERS_IMPORT_BATCH_ACTION => 25,
self::CUSTOMERS_DELETE_BATCH_ACTION => 25,
self::ORDERS_IMPORT_BATCH_ACTION => 10,
self::ORDERS_DELETE_BATCH_ACTION => 10,
);
$batch_size = isset( $batch_sizes[ $action ] ) ? $batch_sizes[ $action ] : 25;
@ -461,8 +505,8 @@ class WC_Admin_Reports_Sync {
* @param int|bool $days Number of days to process.
* @param bool $skip_existing Skip exisiting records.
*/
public static function customer_lookup_batch_init( $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::CUSTOMERS_BATCH_ACTION );
public static function customer_lookup_import_batch_init( $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::CUSTOMERS_IMPORT_BATCH_ACTION );
$customer_query = self::get_user_ids_for_batch(
$days,
$skip_existing,
@ -479,7 +523,7 @@ class WC_Admin_Reports_Sync {
$num_batches = ceil( $total_customers / $batch_size );
self::queue_batches( 1, $num_batches, self::CUSTOMERS_BATCH_ACTION, array( $days, $skip_existing ) );
self::queue_batches( 1, $num_batches, self::CUSTOMERS_IMPORT_BATCH_ACTION, array( $days, $skip_existing ) );
}
/**
@ -490,8 +534,8 @@ class WC_Admin_Reports_Sync {
* @param bool $skip_existing Skip exisiting records.
* @return void
*/
public static function customer_lookup_process_batch( $batch_number, $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::CUSTOMERS_BATCH_ACTION );
public static function customer_lookup_import_batch( $batch_number, $days, $skip_existing ) {
$batch_size = self::get_batch_size( self::CUSTOMERS_IMPORT_BATCH_ACTION );
$customer_query = self::get_user_ids_for_batch(
$days,
$skip_existing,
@ -511,6 +555,82 @@ class WC_Admin_Reports_Sync {
WC_Admin_Reports_Customers_Data_Store::update_registered_customer( $customer_id );
}
}
/**
* Delete customer lookup table rows (in batches).
*/
public static function customer_lookup_delete_batch_init() {
global $wpdb;
$batch_size = self::get_batch_size( self::CUSTOMERS_DELETE_BATCH_ACTION );
$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_customer_lookup" );
if ( 0 === $count ) {
return;
}
$num_batches = ceil( $count / $batch_size );
self::queue_batches( 1, $num_batches, self::CUSTOMERS_DELETE_BATCH_ACTION );
}
/**
* Delete a batch of customers.
*
* @param int $batch_number Batch number to import (essentially a query page number).
* @return void
*/
public static function customer_lookup_delete_batch( $batch_number ) {
global $wpdb;
$batch_size = self::get_batch_size( self::CUSTOMERS_DELETE_BATCH_ACTION );
$customer_ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT customer_id FROM {$wpdb->prefix}wc_customer_lookup ORDER BY customer_id ASC LIMIT %d",
$batch_size
)
);
foreach ( $customer_ids as $customer_id ) {
WC_Admin_Reports_Customers_Data_Store::delete_customer( $customer_id );
}
}
/**
* Delete orders lookup table rows (in batches).
*/
public static function orders_lookup_delete_batch_init() {
global $wpdb;
$batch_size = self::get_batch_size( self::ORDERS_DELETE_BATCH_ACTION );
$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}wc_order_stats" );
if ( 0 === $count ) {
return;
}
$num_batches = ceil( $count / $batch_size );
self::queue_batches( 1, $num_batches, self::ORDERS_DELETE_BATCH_ACTION );
}
/**
* Delete a batch of orders.
*
* @return void
*/
public static function orders_lookup_delete_batch() {
global $wpdb;
$batch_size = self::get_batch_size( self::ORDERS_DELETE_BATCH_ACTION );
$order_ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT order_id FROM {$wpdb->prefix}wc_order_stats ORDER BY order_id ASC LIMIT %d",
$batch_size
)
);
foreach ( $order_ids as $order_id ) {
WC_Admin_Reports_Orders_Stats_Data_Store::delete_order( $order_id );
}
}
}
WC_Admin_Reports_Sync::init();