Also support syncing for HPOS with stats table. (#35118)
* Also support syncing for HPOS with stats table. * Add changelog. * Fixup. * More fixup. * test commit by disabling importing admin test orders. * Update get_items to work with HPOS. * Modify tests to assert against invalid result. * test commit for ci. * Remove seperate test as its quite slow. * Applied coding standards. * Coding standards, part 2.
This commit is contained in:
parent
2c5d3d2acc
commit
6c551b0cd6
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Sync orders for stats table.
|
|
@ -12,6 +12,7 @@ use \Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
|
|||
use \Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* Admin\API\Reports\Customers\DataStore.
|
||||
|
@ -64,7 +65,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'id' => "{$table_name}.customer_id as id",
|
||||
'user_id' => 'user_id',
|
||||
'username' => 'username',
|
||||
'name' => "CONCAT_WS( ' ', first_name, last_name ) as name", // @todo What does this mean for RTL?
|
||||
'name' => "CONCAT_WS( ' ', first_name, last_name ) as name", // @xxx: What does this mean for RTL?
|
||||
'email' => 'email',
|
||||
'country' => 'country',
|
||||
'city' => 'city',
|
||||
|
@ -122,7 +123,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
public static function sync_order_customer( $post_id ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( 'shop_order' !== get_post_type( $post_id ) && 'shop_order_refund' !== get_post_type( $post_id ) ) {
|
||||
if ( ! OrderUtil::is_order( $post_id, array( 'shop_order', 'shop_order_refund' ) ) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use \Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
|||
use \Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* API\Reports\Orders\Stats\DataStore.
|
||||
|
@ -113,6 +114,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
* @param array $query_args Query arguments supplied by the user.
|
||||
*/
|
||||
protected function orders_stats_sql_filter( $query_args ) {
|
||||
// phpcs:ignore Generic.Commenting.Todo.TaskFound
|
||||
// @todo Performance of all of this?
|
||||
global $wpdb;
|
||||
|
||||
|
@ -335,6 +337,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
return new \WP_Error( 'woocommerce_analytics_revenue_result_failed', __( 'Sorry, fetching revenue data failed.', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
// phpcs:ignore Generic.Commenting.Todo.TaskFound
|
||||
// @todo Remove these assignements when refactoring segmenter classes to use query objects.
|
||||
$totals_query = array(
|
||||
'from_clause' => $this->total_query->get_sql_clause( 'join' ),
|
||||
|
@ -474,7 +477,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function sync_order( $post_id ) {
|
||||
if ( 'shop_order' !== get_post_type( $post_id ) && 'shop_order_refund' !== get_post_type( $post_id ) ) {
|
||||
if ( ! OrderUtil::is_order( $post_id, array( 'shop_order', 'shop_order_refund' ) ) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -505,6 +508,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
*
|
||||
* @param array $data Data written to order stats lookup table.
|
||||
* @param WC_Order $order Order object.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
$data = apply_filters(
|
||||
'woocommerce_analytics_update_order_stats_data',
|
||||
|
@ -555,6 +560,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
* Fires when order's stats reports are updated.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
*
|
||||
* @since 4.0.0.
|
||||
*/
|
||||
do_action( 'woocommerce_analytics_update_order_stats', $order->get_id() );
|
||||
|
||||
|
@ -571,7 +578,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
global $wpdb;
|
||||
$order_id = (int) $post_id;
|
||||
|
||||
if ( 'shop_order' !== get_post_type( $order_id ) && 'shop_order_refund' !== get_post_type( $order_id ) ) {
|
||||
if ( ! OrderUtil::is_order( $post_id, array( 'shop_order', 'shop_order_refund' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -586,6 +593,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param int $customer_id Customer ID.
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
do_action( 'woocommerce_analytics_delete_order_stats', $order_id, $customer_id );
|
||||
|
||||
|
|
|
@ -13,6 +13,9 @@ use \Automattic\WooCommerce\Admin\API\Reports\Products\DataStore as ProductsData
|
|||
use \Automattic\WooCommerce\Admin\API\Reports\Taxes\DataStore as TaxesDataStore;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
|
||||
use Automattic\WooCommerce\Admin\Overrides\Order;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* OrdersScheduler Class.
|
||||
|
@ -36,7 +39,8 @@ class OrdersScheduler extends ImportScheduler {
|
|||
\Automattic\WooCommerce\Admin\Overrides\OrderRefund::add_filters();
|
||||
|
||||
// Order and refund data must be run on these hooks to ensure meta data is set.
|
||||
add_action( 'save_post', array( __CLASS__, 'possibly_schedule_import' ) );
|
||||
add_action( 'woocommerce_update_order', array( __CLASS__, 'possibly_schedule_import' ) );
|
||||
add_action( 'woocommerce_create_order', array( __CLASS__, 'possibly_schedule_import' ) );
|
||||
add_action( 'woocommerce_refund_created', array( __CLASS__, 'possibly_schedule_import' ) );
|
||||
|
||||
OrdersStatsDataStore::init();
|
||||
|
@ -69,6 +73,25 @@ class OrdersScheduler extends ImportScheduler {
|
|||
* @param bool $skip_existing Skip already imported orders.
|
||||
*/
|
||||
public static function get_items( $limit = 10, $page = 1, $days = false, $skip_existing = false ) {
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
return self::get_items_from_orders_table( $limit, $page, $days, $skip_existing );
|
||||
} else {
|
||||
return self::get_items_from_posts_table( $limit, $page, $days, $skip_existing );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to ger order/refund IDS and total count that needs to be synced.
|
||||
*
|
||||
* @internal
|
||||
* @param int $limit Number of records to retrieve.
|
||||
* @param int $page Page number.
|
||||
* @param int|bool $days Number of days prior to current date to limit search results.
|
||||
* @param bool $skip_existing Skip already imported orders.
|
||||
*
|
||||
* @return object Total counts.
|
||||
*/
|
||||
private static function get_items_from_posts_table( $limit, $page, $days, $skip_existing ) {
|
||||
global $wpdb;
|
||||
$where_clause = '';
|
||||
$offset = $page > 1 ? ( $page - 1 ) * $limit : 0;
|
||||
|
@ -112,6 +135,65 @@ class OrdersScheduler extends ImportScheduler {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to ger order/refund IDS and total count that needs to be synced from HPOS.
|
||||
*
|
||||
* @internal
|
||||
* @param int $limit Number of records to retrieve.
|
||||
* @param int $page Page number.
|
||||
* @param int|bool $days Number of days prior to current date to limit search results.
|
||||
* @param bool $skip_existing Skip already imported orders.
|
||||
*
|
||||
* @return object Total counts.
|
||||
*/
|
||||
private static function get_items_from_orders_table( $limit, $page, $days, $skip_existing ) {
|
||||
global $wpdb;
|
||||
$where_clause = '';
|
||||
$offset = $page > 1 ? ( $page - 1 ) * $limit : 0;
|
||||
$order_table = OrdersTableDataStore::get_orders_table_name();
|
||||
|
||||
if ( is_int( $days ) ) {
|
||||
$days_ago = gmdate( 'Y-m-d 00:00:00', time() - ( DAY_IN_SECONDS * $days ) );
|
||||
$where_clause .= " AND orders.date_created_gmt >= '{$days_ago}'";
|
||||
}
|
||||
|
||||
if ( $skip_existing ) {
|
||||
$where_clause .= "AND NOT EXiSTS (
|
||||
SELECT 1 FROM {$wpdb->prefix}wc_order_stats
|
||||
WHERE {$wpdb->prefix}wc_order_stats.order_id = orders.id
|
||||
)
|
||||
";
|
||||
}
|
||||
|
||||
$count = $wpdb->get_var(
|
||||
"
|
||||
SELECT COUNT(*) FROM {$order_table} AS orders
|
||||
WHERE type in ( 'shop_order', 'shop_order_refund' )
|
||||
AND status NOT IN ( 'wc-auto-draft', 'trash', 'auto-draft' )
|
||||
{$where_clause}
|
||||
"
|
||||
); // phpcs:ignore unprepared SQL ok.
|
||||
|
||||
$order_ids = absint( $count ) > 0 ? $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT id FROM {$order_table} AS orders
|
||||
WHERE type IN ( 'shop_order', 'shop_order_refund' )
|
||||
AND status NOT IN ( 'wc-auto-draft', 'auto-draft', 'trash' )
|
||||
{$where_clause}
|
||||
ORDER BY date_created_gmt ASC
|
||||
LIMIT %d
|
||||
OFFSET %d",
|
||||
$limit,
|
||||
$offset
|
||||
)
|
||||
) : array(); // phpcs:ignore unprepared SQL ok.
|
||||
|
||||
return (object) array(
|
||||
'total' => absint( $count ),
|
||||
'ids' => $order_ids,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total number of rows imported.
|
||||
*
|
||||
|
@ -125,15 +207,16 @@ class OrdersScheduler extends ImportScheduler {
|
|||
/**
|
||||
* Schedule this import if the post is an order or refund.
|
||||
*
|
||||
* @param int $order_id Post ID.
|
||||
*
|
||||
* @internal
|
||||
* @param int $post_id Post ID.
|
||||
*/
|
||||
public static function possibly_schedule_import( $post_id ) {
|
||||
if ( 'shop_order' !== get_post_type( $post_id ) && 'woocommerce_refund_created' !== current_filter() ) {
|
||||
public static function possibly_schedule_import( $order_id ) {
|
||||
if ( ! OrderUtil::is_order( $order_id, array( 'shop_order' ) ) && 'woocommerce_refund_created' !== current_filter() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::schedule_action( 'import', array( $post_id ) );
|
||||
self::schedule_action( 'import', array( $order_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -122,15 +122,15 @@ class COTMigrationUtil {
|
|||
}
|
||||
|
||||
/**
|
||||
* Helper function to id from an post or order object.
|
||||
* Helper function to get ID from a post or order object.
|
||||
*
|
||||
* @param WP_Post/WC_Order $post_or_order_object WP_Post/WC_Order object to get ID for.
|
||||
*
|
||||
* @return int Order or post ID.
|
||||
*/
|
||||
public function get_post_or_order_id( $post_or_order_object ) : int {
|
||||
if ( is_int( $post_or_order_object ) ) {
|
||||
return $post_or_order_object;
|
||||
if ( is_numeric( $post_or_order_object ) ) {
|
||||
return (int) $post_or_order_object;
|
||||
} elseif ( $post_or_order_object instanceof WC_Order ) {
|
||||
return $post_or_order_object->get_id();
|
||||
} elseif ( $post_or_order_object instanceof WP_Post ) {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @since 3.5.0
|
||||
*/
|
||||
|
||||
// phpcs:disable Squiz.Classes.ClassFileName.NoMatch, Squiz.Classes.ValidClassName.NotCamelCaps
|
||||
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
|
||||
|
||||
/**
|
||||
|
@ -503,7 +505,8 @@ class WC_Admin_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case {
|
|||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$this->assertTrue( $result );
|
||||
$this->assertNotEquals( -1, $result );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
@ -599,7 +602,7 @@ class WC_Admin_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case {
|
|||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
// Didn't update anything.
|
||||
$this->assertTrue( $result );
|
||||
$this->assertNotEquals( -1, $result );
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
|
Loading…
Reference in New Issue