From 7d26cc819c0710bd5e1517a58952a8f43a19cc83 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 14 Feb 2023 17:39:33 +0530 Subject: [PATCH 01/49] Handle data query params by converting to appropriate timezone. Additionally, there is not need to map params from same key to value name, otherwise it causes issues and gets unset the in for loop below. --- .../DataStores/Orders/OrdersTableQuery.php | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index b6ff8f91be6..62e08f2f53e 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -202,13 +202,13 @@ class OrdersTableQuery { private function maybe_remap_args(): void { $mapping = array( // WP_Query legacy. - 'post_date' => 'date_created_gmt', + 'post_date' => 'date_created', 'post_date_gmt' => 'date_created_gmt', - 'post_modified' => 'date_modified_gmt', + 'post_modified' => 'date_modified', 'post_modified_gmt' => 'date_updated_gmt', 'post_status' => 'status', - '_date_completed' => 'date_completed_gmt', - '_date_paid' => 'date_paid_gmt', + '_date_completed' => 'date_completed', + '_date_paid' => 'date_paid', 'paged' => 'page', 'post_parent' => 'parent_order_id', 'post_parent__in' => 'parent_order_id', @@ -231,12 +231,8 @@ class OrdersTableQuery { // Translate from WC_Order_Query to table structure. 'version' => 'woocommerce_version', - 'date_created' => 'date_created_gmt', - 'date_modified' => 'date_updated_gmt', + 'date_modified' => 'date_updated', 'date_modified_gmt' => 'date_updated_gmt', - 'date_completed' => 'date_completed_gmt', - 'date_completed_gmt' => 'date_completed_gmt', - 'date_paid' => 'date_paid_gmt', 'discount_total' => 'discount_total_amount', 'discount_tax' => 'discount_tax_amount', 'shipping_total' => 'shipping_total_amount', @@ -282,10 +278,11 @@ class OrdersTableQuery { * Generates a `WP_Date_Query` compatible query from a given date. * YYYY-MM-DD queries have 'day' precision for backwards compatibility. * - * @param mixed $date The date. Can be a {@see \WC_DateTime}, a timestamp or a string. + * @param mixed $date The date. Can be a {@see \WC_DateTime}, a timestamp or a string. + * @param string $timezone The timezone to use for the date. * @return array An array with keys 'year', 'month', 'day' and possibly 'hour', 'minute' and 'second'. */ - private function date_to_date_query_arg( $date ): array { + private function date_to_date_query_arg( $date, $timezone ): array { $result = array( 'year' => '', 'month' => '', @@ -294,7 +291,7 @@ class OrdersTableQuery { $precision = 'second'; if ( is_numeric( $date ) ) { - $date = new \WC_DateTime( "@{$date}", new \DateTimeZone( 'UTC' ) ); + $date = new \WC_DateTime( "@{$date}", new \DateTimeZone( $timezone ) ); } elseif ( ! is_a( $date, 'WC_DateTime' ) ) { // YYYY-MM-DD queries have 'day' precision for backwards compat. $date = wc_string_to_datetime( $date ); @@ -321,30 +318,33 @@ class OrdersTableQuery { * @throws \Exception When date args are invalid. */ private function process_date_args(): void { - $valid_operators = array( '>', '>=', '=', '<=', '<', '...' ); - $date_queries = array(); - $gmt_date_keys = array( - 'date_created_gmt', - 'date_updated_gmt', - 'date_paid_gmt', - 'date_completed_gmt', + $valid_operators = array( '>', '>=', '=', '<=', '<', '...' ); + $date_queries = array(); + $local_to_gmt_date_keys = array( + 'date_created' => 'date_created_gmt', + 'date_updated' => 'date_updated_gmt', + 'date_paid' => 'date_paid_gmt', + 'date_completed' => 'date_completed_gmt', ); + $gmt_date_keys = array_values( $local_to_gmt_date_keys ); + $local_date_keys = array_keys( $local_to_gmt_date_keys ); - foreach ( array_filter( $gmt_date_keys, array( $this, 'arg_isset' ) ) as $date_key ) { + foreach ( array_filter( array_merge( $gmt_date_keys, $local_date_keys ), array( $this, 'arg_isset' ) ) as $date_key ) { $date_value = $this->args[ $date_key ]; $operator = '='; $dates = array(); + $timezone = in_array( $date_key, $gmt_date_keys, true ) ? '+0000' : wc_timezone_string(); if ( is_string( $date_value ) && preg_match( self::REGEX_SHORTHAND_DATES, $date_value, $matches ) ) { $operator = in_array( $matches[2], $valid_operators, true ) ? $matches[2] : ''; if ( ! empty( $matches[1] ) ) { - $dates[] = $this->date_to_date_query_arg( $matches[1] ); + $dates[] = $this->date_to_date_query_arg( $matches[1], $timezone ); } - $dates[] = $this->date_to_date_query_arg( $matches[3] ); + $dates[] = $this->date_to_date_query_arg( $matches[3], $timezone ); } else { - $dates[] = $this->date_to_date_query_arg( $date_value ); + $dates[] = $this->date_to_date_query_arg( $date_value, $timezone ); } if ( empty( $dates ) || ! $operator || ( '...' === $operator && count( $dates ) < 2 ) ) { @@ -361,6 +361,7 @@ class OrdersTableQuery { $operator_to_keys[] = 'before'; } + $date_key = in_array( $date_key, $local_date_keys, true ) ? $local_to_gmt_date_keys[ $date_key ] : $date_key; $date_queries[] = array_merge( array( 'column' => $date_key, From 9bdc7f349560af77a479d518898f4c59509a7d31 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 14 Feb 2023 17:40:49 +0530 Subject: [PATCH 02/49] Add changelog. --- plugins/woocommerce/changelog/fix-36685 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36685 diff --git a/plugins/woocommerce/changelog/fix-36685 b/plugins/woocommerce/changelog/fix-36685 new file mode 100644 index 00000000000..6aba52e9087 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36685 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Handle date arguments in OrderTableQuery correctly by adjusting their timezones before running. From ae7d827f221556eef5be6b31faad7eeecfdd621e Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 15 Feb 2023 17:23:43 +0530 Subject: [PATCH 03/49] Directly fetch order prop from DB for compatibility with CPT store. --- plugins/woocommerce/changelog/fix-36685-2 | 4 ++ .../Orders/OrdersTableDataStore.php | 66 +++++++++++++++---- .../DataStores/Orders/OrdersTableQuery.php | 26 ++++---- 3 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-36685-2 diff --git a/plugins/woocommerce/changelog/fix-36685-2 b/plugins/woocommerce/changelog/fix-36685-2 new file mode 100644 index 00000000000..6a89ac8e78f --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36685-2 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Directly fetch order prop from DB for compatibility with CPT store. diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php index 0fd369cf83c..2d4038adbed 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php @@ -180,6 +180,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements /** * Get the names of all the tables involved in the custom orders table feature. * + * See also : get_all_table_names_with_id. + * * @return string[] */ public function get_all_table_names() { @@ -191,6 +193,22 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements ); } + /** + * Similar to get_all_table_names, but also returns the table name along with the items table. + * + * @return array Names of the tables. + */ + public static function get_all_table_names_with_id() { + global $wpdb; + return array( + 'orders' => self::get_orders_table_name(), + 'addresses' => self::get_addresses_table_name(), + 'operational_data' => self::get_operational_data_table_name(), + 'meta' => self::get_meta_table_name(), + 'items' => $wpdb->prefix . 'woocommerce_order_items', + ); + } + /** * Table column to WC_Order mapping for wc_orders table. * @@ -554,8 +572,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether permissions are granted. */ public function get_download_permissions_granted( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_download_permissions_granted(); + $order_id = is_int( $order ) ? $order : $order->get_id(); + return $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ); } /** @@ -580,8 +598,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether sales are recorded. */ public function get_recorded_sales( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_recorded_sales(); + $order_id = is_int( $order ) ? $order : $order->get_id(); + return $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ); } /** @@ -606,8 +624,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether coupon counts were updated. */ public function get_recorded_coupon_usage_counts( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_recorded_coupon_usage_counts(); + $order_id = is_int( $order ) ? $order : $order->get_id(); + return $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ); } /** @@ -632,8 +650,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether email is sent. */ public function get_email_sent( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_new_order_email_sent(); + $order_id = is_int( $order ) ? $order : $order->get_id(); + return $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ); } /** @@ -658,8 +676,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether email was sent. */ public function get_new_order_email_sent( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_new_order_email_sent(); + return $this->get_email_sent( $order ); } /** @@ -684,8 +701,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements * @return bool Whether stock was reduced. */ public function get_stock_reduced( $order ) { - $order = is_int( $order ) ? wc_get_order( $order ) : $order; - return $order->get_order_stock_reduced(); + $order_id = is_int( $order ) ? $order : $order->get_id(); + return $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ); } /** @@ -882,6 +899,31 @@ WHERE // phpcs:enable } + /** + * Returns field value for an order directly from the database, skipping the value stored in order prop. + * Useful when you are not sure if the order prop is manipulated by a callee function without having to refresh the order. + * + * @param int $order_id Order ID. + * @param string $column_name Name of the column to fetch value from. + * @param string $table_name Name of the table to fetch value from. + * + * @return string|null Field value or null if not found. + */ + public function get_field_value( $order_id, $column_name, $table_name ) { + global $wpdb; + $where_clause = ' WHERE 1=1 '; + if ( self::get_addresses_table_name() === $table_name ) { + $address_type = explode( '_', $column_name )[0]; + $column_name = str_replace( $address_type . '_', '', $column_name ); + $where_clause .= $wpdb->prepare( ' AND type = %s', $address_type ); + } + $select_clause = 'SELECT `' . esc_sql( $column_name ) . '` FROM `' . esc_sql( $table_name ) . '` '; + $where_clause .= $wpdb->prepare( ' AND order_id = %d', $order_id ); + + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Both select_clause and where_clause are escaped. + return $wpdb->get_var( "$select_clause $where_clause LIMIT 1" ); + } + /** * Search order data for a term and return matching order IDs. * diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index 62e08f2f53e..444e4f7eca8 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -164,6 +164,12 @@ class OrdersTableQuery { */ private $date_query = null; + /** + * Instance of the OrdersTableDataStore class. + * + * @var OrdersTableDataStore + */ + private $order_datastore = null; /** * Sets up and runs the query after processing arguments. @@ -171,19 +177,11 @@ class OrdersTableQuery { * @param array $args Array of query vars. */ public function __construct( $args = array() ) { - global $wpdb; + // Note that ideally we would inject this dependency via constructor, but that's not possible since this class needs to be backward compatible with WC_Order_Query class. + $this->order_datastore = wc_get_container()->get( OrdersTableDataStore::class ); - $datastore = wc_get_container()->get( OrdersTableDataStore::class ); - - // TODO: maybe OrdersTableDataStore::get_all_table_names() could return these keys/indices instead. - $this->tables = array( - 'orders' => $datastore::get_orders_table_name(), - 'addresses' => $datastore::get_addresses_table_name(), - 'operational_data' => $datastore::get_operational_data_table_name(), - 'meta' => $datastore::get_meta_table_name(), - 'items' => $wpdb->prefix . 'woocommerce_order_items', - ); - $this->mappings = $datastore->get_all_order_column_mappings(); + $this->tables = $this->order_datastore::get_all_table_names_with_id(); + $this->mappings = $this->order_datastore->get_all_order_column_mappings(); $this->args = $args; @@ -333,7 +331,7 @@ class OrdersTableQuery { $date_value = $this->args[ $date_key ]; $operator = '='; $dates = array(); - $timezone = in_array( $date_key, $gmt_date_keys, true ) ? '+0000' : wc_timezone_string(); + $timezone = in_array( $date_key, $gmt_date_keys, true ) ? '+0000' : wc_timezone_string(); if ( is_string( $date_value ) && preg_match( self::REGEX_SHORTHAND_DATES, $date_value, $matches ) ) { $operator = in_array( $matches[2], $valid_operators, true ) ? $matches[2] : ''; @@ -361,7 +359,7 @@ class OrdersTableQuery { $operator_to_keys[] = 'before'; } - $date_key = in_array( $date_key, $local_date_keys, true ) ? $local_to_gmt_date_keys[ $date_key ] : $date_key; + $date_key = in_array( $date_key, $local_date_keys, true ) ? $local_to_gmt_date_keys[ $date_key ] : $date_key; $date_queries[] = array_merge( array( 'column' => $date_key, From 95f141826130cea060a8aefb0bd49581d3097033 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 20 Feb 2023 18:30:18 +0530 Subject: [PATCH 04/49] Enable post data store before running post data store order tests. --- .../rest-api/Helpers/OrderHelper.php | 5 +++ .../class-wc-order-data-store-cpt-test.php | 33 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Helpers/OrderHelper.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Helpers/OrderHelper.php index 1dfed4fe425..8955f0368ae 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Helpers/OrderHelper.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Helpers/OrderHelper.php @@ -14,6 +14,7 @@ use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableControlle use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer; use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore; use Automattic\WooCommerce\Internal\Features\FeaturesController; +use Automattic\WooCommerce\Utilities\OrderUtil; use WC_Data_Store; use WC_Mock_Payment_Gateway; use WC_Order; @@ -187,6 +188,8 @@ class OrderHelper { * @return int Order ID */ public static function create_complex_wp_post_order() { + $current_cot_state = OrderUtil::custom_orders_table_usage_is_enabled(); + self::toggle_cot( false ); update_option( 'woocommerce_prices_include_tax', 'yes' ); update_option( 'woocommerce_calc_taxes', 'yes' ); $uniq_cust_id = wp_generate_password( 10, false ); @@ -256,6 +259,8 @@ class OrderHelper { $order->save(); $order->save_meta_data(); + self::toggle_cot( $current_cot_state ); + return $order->get_id(); } diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php index 011a0bdf776..4fb6bd7132c 100644 --- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php +++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-order-data-store-cpt-test.php @@ -1,9 +1,40 @@ prev_cot_state = OrderUtil::custom_orders_table_usage_is_enabled(); + OrderHelper::toggle_cot( false ); + } + + /** + * Restore the COT state after the test. + * + * @return void + */ + public function tearDown(): void { + OrderHelper::toggle_cot( $this->prev_cot_state ); + parent::tearDown(); + } /** * Test that refund cache are invalidated correctly when refund is deleted. @@ -131,7 +162,7 @@ class WC_Order_Data_Store_CPT_Test extends WC_Unit_Test_Case { * Legacy getters and setters for props migrated from data stores should be set/reset properly. */ public function test_legacy_getters_setters() { - $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_wp_post_order(); + $order_id = OrderHelper::create_complex_wp_post_order(); $order = wc_get_order( $order_id ); $bool_props = array( '_download_permissions_granted' => 'download_permissions_granted', From 69e4df6786fb93c0eae1da17ae8dc469222fd6a0 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 13:56:33 +0530 Subject: [PATCH 05/49] Treat invalid query to not return any result for backward compatibility. --- .../src/Internal/DataStores/Orders/OrdersTableQuery.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index 444e4f7eca8..cba6c094d4a 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -873,6 +873,9 @@ class OrdersTableQuery { $ids[] = absint( $value ); } elseif ( is_string( $value ) && is_email( $value ) ) { $emails[] = sanitize_email( $value ); + } else { + // Invalid query. + $pieces[] = '1=0'; } } From 0b513107b0b77e18a366198bba05aae95f4b8d44 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Wed, 25 Jan 2023 15:28:41 +0100 Subject: [PATCH 06/49] Proper deletion of order data from wc_order_tax_lookup and wc_order_stats When the orders table is authoritative, deleting an order was not deleting the records in wc_order_tax_lookup and wc_order_stats for the order. --- .../woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php b/plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php index b2ef6217df0..a7dc05948a7 100644 --- a/plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php +++ b/plugins/woocommerce/src/Admin/API/Reports/Orders/Stats/DataStore.php @@ -105,6 +105,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface { * Set up all the hooks for maintaining and populating table data. */ public static function init() { + add_action( 'woocommerce_before_delete_order', array( __CLASS__, 'delete_order' ) ); add_action( 'delete_post', array( __CLASS__, 'delete_order' ) ); } From a1ebcedea789e5d3c5c46d8203269c0fdcea1425 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 14:05:48 +0530 Subject: [PATCH 07/49] Modify to use WC hook instead of post for HPOS compat. --- plugins/woocommerce/includes/class-wc-post-data.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/includes/class-wc-post-data.php b/plugins/woocommerce/includes/class-wc-post-data.php index b27cfe47db8..e35de400ef1 100644 --- a/plugins/woocommerce/includes/class-wc-post-data.php +++ b/plugins/woocommerce/includes/class-wc-post-data.php @@ -53,7 +53,7 @@ class WC_Post_Data { add_action( 'delete_post', array( __CLASS__, 'delete_post' ) ); add_action( 'wp_trash_post', array( __CLASS__, 'trash_post' ) ); add_action( 'untrashed_post', array( __CLASS__, 'untrash_post' ) ); - add_action( 'before_delete_post', array( __CLASS__, 'before_delete_order' ) ); + add_action( 'woocommerce_before_delete_order', array( __CLASS__, 'before_delete_order' ) ); // Meta cache flushing. add_action( 'updated_post_meta', array( __CLASS__, 'flush_object_meta_cache' ), 10, 4 ); From 2ee7306a80bb1cca64a8681595f6d16442992573 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 14:22:33 +0530 Subject: [PATCH 08/49] Add HPOS compat for resetting order on user deletion. --- .../includes/wc-user-functions.php | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/plugins/woocommerce/includes/wc-user-functions.php b/plugins/woocommerce/includes/wc-user-functions.php index 6b98a8a8df0..f1c2c43706a 100644 --- a/plugins/woocommerce/includes/wc-user-functions.php +++ b/plugins/woocommerce/includes/wc-user-functions.php @@ -714,16 +714,40 @@ function wc_get_customer_order_count( $user_id ) { function wc_reset_order_customer_id_on_deleted_user( $user_id ) { global $wpdb; - $wpdb->update( - $wpdb->postmeta, - array( - 'meta_value' => 0, - ), - array( - 'meta_key' => '_customer_user', - 'meta_value' => $user_id, - ) - ); // WPCS: slow query ok. + if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { + $order_table_ds = wc_get_container()->get( OrdersTableDataStore::class ); + $order_table = $order_table_ds::get_orders_table_name(); + $wpdb->update( + $order_table, + array( + 'customer_id' => 0, + 'date_updated_gmt' => current_time( 'mysql', true ), + ), + array( + 'customer_id' => $user_id, + ), + array( + '%d', + '%s', + ), + array( + '%d', + ) + ); + } + + if ( ! OrderUtil::custom_orders_table_usage_is_enabled() || OrderUtil::is_custom_order_tables_in_sync() ) { + $wpdb->update( + $wpdb->postmeta, + array( + 'meta_value' => 0, + ), + array( + 'meta_key' => '_customer_user', + 'meta_value' => $user_id, + ) + ); // WPCS: slow query ok. + } } add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' ); From 035ab94e5a25cf9d90d8b1aaa34004d3e70cd4a8 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 15:24:44 +0530 Subject: [PATCH 09/49] Add HPOS compatibility to order function tests. --- .../unit-tests/order/class-wc-tests-order-functions.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php index 4df224a5e58..6ba56763594 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php @@ -115,9 +115,13 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case { $add_mock_order_type = function( $order_types ) use ( $mock_datastores ) { return array( 'shop_order', 'order-fake-type' ); }; + $return_mock_order_data_store = function ( $stores ) use ( $mock_datastores ) { + return $mock_datastores['order']; + }; add_filter( 'woocommerce_data_stores', $add_mock_datastores ); add_filter( 'wc_order_types', $add_mock_order_type ); + add_filter( 'woocommerce_order_data_store', $return_mock_order_data_store, 1000, 2 ); // Check counts for specific order types. $this->assertEquals( 2, wc_orders_count( 'on-hold', 'shop_order' ) ); @@ -131,6 +135,7 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case { remove_filter( 'woocommerce_data_stores', $add_mock_datastores ); remove_filter( 'wc_order_types', $add_mock_order_type ); + remove_filter( 'woocommerce_order_data_store', $return_mock_order_data_store, 1000 ); // Confirm that everything's back to normal. wp_cache_flush(); @@ -190,7 +195,8 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case { // Assert the return when $the_order args is false. $this->assertFalse( wc_get_order( false ) ); - $post = get_post( $order->get_id() ); + $post = get_post( $order->get_id() ); + $theorder = $order; $this->assertInstanceOf( 'WC_Order', wc_get_order(), From fe273c955611dd2aa884e490dfd907d41c020d51 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 15:34:52 +0530 Subject: [PATCH 10/49] Add HPOS compat for meta unit tests. --- .../tests/legacy/unit-tests/crud/meta.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php b/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php index 3bcc8da38d8..427739ca95e 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php @@ -1,4 +1,7 @@ assertCount( 1, $order->get_meta_data() ); $this->assertTrue( in_array( 'random', wp_list_pluck( $order->get_meta_data(), 'key' ) ) ); - // The new $order should have 3 items of meta since it's freshly loaded. - $this->assertCount( 3, $new_order->get_meta_data() ); + $expected_count = OrderUtil::custom_orders_table_usage_is_enabled() ? 2 : 3; + // The new $order should have 3 items (or 2 in case of HPOS since direct post updates are not read) of meta since it's freshly loaded. + $this->assertCount( $expected_count, $new_order->get_meta_data() ); $this->assertTrue( in_array( 'random', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); $this->assertTrue( in_array( 'random_other', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); - $this->assertTrue( in_array( 'random_other_pre_crud', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); + if ( ! OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->assertTrue( in_array( 'random_other_pre_crud', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); + } } /** From a76a4154876085f06e1d4ccf1c9b8b64ebf70f63 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 15:38:24 +0530 Subject: [PATCH 11/49] Add HPOS compat for crud unit tests. --- .../legacy/unit-tests/order/class-wc-tests-crud-orders.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php index 1d6a917bc02..b0f8897821a 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php @@ -884,8 +884,8 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { // Save + create. $save_id = $object->save(); $post = get_post( $save_id ); - $this->assertEquals( 'shop_order', $post->post_type ); - $this->assertEquals( 'shop_order', $post->post_type ); + $expected_post_type = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ? 'shop_order_placehold' : 'shop_order'; + $this->assertEquals( $expected_post_type, $post->post_type ); // Update. $update_id = $object->save(); From c06ee8f794cd7c0d8c118d432795381b268de0e1 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 15:57:00 +0530 Subject: [PATCH 12/49] Skip unsupported tests with HPOS. --- .../unit-tests/admin/class-wc-tests-admin-dashboard.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php index 56b0e4cd6ca..46d3d9972f2 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php @@ -5,6 +5,8 @@ * @package WooCommerce\Tests\Admin */ +use Automattic\WooCommerce\Utilities\OrderUtil; + /** * Tests for the WC_Admin_Report class. */ @@ -37,6 +39,9 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case { * Test: get_status_widget */ public function test_status_widget() { + if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->markTestSkipped( 'We don\'t support legacy reports in HPOS.' ); + } wp_set_current_user( $this->user ); $order = WC_Helper_Order::create_order(); $order->set_status( 'completed' ); @@ -58,6 +63,9 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case { * Test: get_status_widget with woo admin disabled. */ public function test_status_widget_with_woo_admin_disabled() { + if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->markTestSkipped( 'We don\'t support legacy reports in HPOS.' ); + } wp_set_current_user( $this->user ); $order = WC_Helper_Order::create_order(); $order->set_status( 'completed' ); From 8be7f763e201ec5d01992ccfe149e781bf6dddf7 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 16:01:38 +0530 Subject: [PATCH 13/49] Update PayPal tests for HPOS compat. --- .../gateways/paypal/class-wc-gateway-paypal-test.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php b/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php index 7f319dc4181..4f26bdfad79 100644 --- a/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php +++ b/plugins/woocommerce/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php @@ -29,8 +29,8 @@ class WC_Gateway_Paypal_Test extends \WC_Unit_Test_Case { $order = WC_Helper_Order::create_order(); $order->save(); - update_post_meta( $order->get_id(), '_paypal_status', 'pending' ); - update_post_meta( $order->get_id(), '_transaction_id', $this->transaction_id_26960 ); + $order->update_meta_data( '_paypal_status', 'pending' ); + $order->set_transaction_id( $this->transaction_id_26960 ); $order->set_payment_method( 'paypal' ); $order->save(); @@ -56,8 +56,8 @@ class WC_Gateway_Paypal_Test extends \WC_Unit_Test_Case { $order = WC_Helper_Order::create_order(); $order->save(); - update_post_meta( $order->get_id(), '_paypal_status', 'pending' ); - update_post_meta( $order->get_id(), '_transaction_id', $this->transaction_id_26960 ); + $order->update_meta_data( '_paypal_status', 'pending' ); + $order->set_transaction_id( $this->transaction_id_26960 ); $order->set_payment_method( 'paypal' ); $order->save(); From be82dae74a6b4e875adf723f1d7bb6350bdeec17 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 16:18:48 +0530 Subject: [PATCH 14/49] Restore indexes incase any meta key is filtered out. --- .../Controllers/Version3/class-wc-rest-orders-controller.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index b594de2284f..0ebbeb9473c 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -253,10 +253,11 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { if ( ! empty( $item_data['meta_data'] ) ) { $item_data['meta_data'] = array_filter( $item_data['meta_data'], - function( $meta ) use ( $cpt_hidden_keys ) { + function ( $meta ) use ( $cpt_hidden_keys ) { return ! in_array( $meta->key, $cpt_hidden_keys, true ); } ); + $item_data['meta_data'] = array_values( $item_data['meta_data'] ); } return $item_data; From 993efa0de27dd4df3a166706a2335ecc5bd3aede Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 16:54:41 +0530 Subject: [PATCH 15/49] Move more generic methods to their parent class for better reusability. --- .../abstract-wc-order-data-store-cpt.php | 83 +++++++++++++++++++ .../class-wc-order-data-store-cpt.php | 83 ------------------- .../class-wc-rest-orders-controller.php | 2 +- 3 files changed, 84 insertions(+), 84 deletions(-) diff --git a/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php index fad3a54eca4..b26a0875462 100644 --- a/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php +++ b/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php @@ -413,6 +413,89 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme return $items; } + /** + * Return the order type of a given item which belongs to WC_Order. + * + * @since 3.2.0 + * @param WC_Order $order Order Object. + * @param int $order_item_id Order item id. + * @return string Order Item type + */ + public function get_order_item_type( $order, $order_item_id ) { + global $wpdb; + return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT order_item_type FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d and order_item_id = %d;", $order->get_id(), $order_item_id ) ); + } + + /** + * Prime following caches: + * 1. item-$order_item_id For individual items. + * 2. order-items-$order-id For fetching items associated with an order. + * 3. order-item meta. + * + * @param array $order_ids Order Ids to prime cache for. + * @param array $query_vars Query vars for the query. + */ + protected function prime_order_item_caches_for_orders( $order_ids, $query_vars ) { + global $wpdb; + if ( isset( $query_vars['fields'] ) && 'all' !== $query_vars['fields'] ) { + $line_items = array( + 'line_items', + 'shipping_lines', + 'fee_lines', + 'coupon_lines', + ); + + if ( is_array( $query_vars['fields'] ) && 0 === count( array_intersect( $line_items, $query_vars['fields'] ) ) ) { + return; + } + } + $cache_keys = array_map( + function ( $order_id ) { + return 'order-items-' . $order_id; + }, + $order_ids + ); + $cache_values = wc_cache_get_multiple( $cache_keys, 'orders' ); + $non_cached_ids = array(); + foreach ( $order_ids as $order_id ) { + if ( false === $cache_values[ 'order-items-' . $order_id ] ) { + $non_cached_ids[] = $order_id; + } + } + if ( empty( $non_cached_ids ) ) { + return; + } + + $non_cached_ids = esc_sql( $non_cached_ids ); + $non_cached_ids_string = implode( ',', $non_cached_ids ); + $order_items = $wpdb->get_results( + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + "SELECT order_item_type, order_item_id, order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id in ( $non_cached_ids_string ) ORDER BY order_item_id;" + ); + if ( empty( $order_items ) ) { + return; + } + + $order_items_for_all_orders = array_reduce( + $order_items, + function ( $order_items_collection, $order_item ) { + if ( ! isset( $order_items_collection[ $order_item->order_id ] ) ) { + $order_items_collection[ $order_item->order_id ] = array(); + } + $order_items_collection[ $order_item->order_id ][] = $order_item; + return $order_items_collection; + } + ); + foreach ( $order_items_for_all_orders as $order_id => $items ) { + wp_cache_set( 'order-items-' . $order_id, $items, 'orders' ); + } + foreach ( $order_items as $item ) { + wp_cache_set( 'item-' . $item->order_item_id, $item, 'order-items' ); + } + $order_item_ids = wp_list_pluck( $order_items, 'order_item_id' ); + update_meta_cache( 'order_item', $order_item_ids ); + } + /** * Remove all line items (products, coupons, shipping, taxes) from the order. * diff --git a/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php b/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php index b8e26142e44..a8982de92ee 100644 --- a/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php +++ b/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php @@ -1118,76 +1118,6 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement } } - /** - * Prime following caches: - * 1. item-$order_item_id For individual items. - * 2. order-items-$order-id For fetching items associated with an order. - * 3. order-item meta. - * - * @param array $order_ids Order Ids to prime cache for. - * @param array $query_vars Query vars for the query. - */ - private function prime_order_item_caches_for_orders( $order_ids, $query_vars ) { - global $wpdb; - if ( isset( $query_vars['fields'] ) && 'all' !== $query_vars['fields'] ) { - $line_items = array( - 'line_items', - 'shipping_lines', - 'fee_lines', - 'coupon_lines', - ); - - if ( is_array( $query_vars['fields'] ) && 0 === count( array_intersect( $line_items, $query_vars['fields'] ) ) ) { - return; - } - } - $cache_keys = array_map( - function ( $order_id ) { - return 'order-items-' . $order_id; - }, - $order_ids - ); - $cache_values = wc_cache_get_multiple( $cache_keys, 'orders' ); - $non_cached_ids = array(); - foreach ( $order_ids as $order_id ) { - if ( false === $cache_values[ 'order-items-' . $order_id ] ) { - $non_cached_ids[] = $order_id; - } - } - if ( empty( $non_cached_ids ) ) { - return; - } - - $non_cached_ids = esc_sql( $non_cached_ids ); - $non_cached_ids_string = implode( ',', $non_cached_ids ); - $order_items = $wpdb->get_results( - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared - "SELECT order_item_type, order_item_id, order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id in ( $non_cached_ids_string ) ORDER BY order_item_id;" - ); - if ( empty( $order_items ) ) { - return; - } - - $order_items_for_all_orders = array_reduce( - $order_items, - function ( $order_items_collection, $order_item ) { - if ( ! isset( $order_items_collection[ $order_item->order_id ] ) ) { - $order_items_collection[ $order_item->order_id ] = array(); - } - $order_items_collection[ $order_item->order_id ][] = $order_item; - return $order_items_collection; - } - ); - foreach ( $order_items_for_all_orders as $order_id => $items ) { - wp_cache_set( 'order-items-' . $order_id, $items, 'orders' ); - } - foreach ( $order_items as $item ) { - wp_cache_set( 'item-' . $item->order_item_id, $item, 'order-items' ); - } - $order_item_ids = wp_list_pluck( $order_items, 'order_item_id' ); - update_meta_cache( 'order_item', $order_item_ids ); - } - /** * Prime cache for raw meta data for orders in bulk. Difference between this and WP built-in metadata is that this method also fetches `meta_id` field which we use and cache it. * @@ -1240,17 +1170,4 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement ); WC_Order::prime_raw_meta_data_cache( $raw_meta_data_collection, 'orders' ); } - - /** - * Return the order type of a given item which belongs to WC_Order. - * - * @since 3.2.0 - * @param WC_Order $order Order Object. - * @param int $order_item_id Order item id. - * @return string Order Item type - */ - public function get_order_item_type( $order, $order_item_id ) { - global $wpdb; - return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT order_item_type FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d and order_item_id = %d;", $order->get_id(), $order_item_id ) ); - } } diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 0ebbeb9473c..ca488ebdde9 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -103,7 +103,7 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { */ protected function prepare_object_for_database( $request, $creating = false ) { $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $order = new WC_Order( $id ); + $order = wc_get_order( $id ); $schema = $this->get_item_schema(); $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); From 263758aa83a1de5bd8b130bfcc03f0a41bee8b2e Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Tue, 21 Feb 2023 19:21:34 +0530 Subject: [PATCH 16/49] Handle local date filters when passed via after/before params. --- .../DataStores/Orders/OrdersTableQuery.php | 32 ++++++++++++++++++- .../Tests/Version3/date-filtering.php | 32 +++++++++++++++---- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index cba6c094d4a..357b9808430 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -270,6 +270,15 @@ class OrdersTableQuery { $this->args['meta_query'] = array( $shortcut_meta_query ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query } } + + // Date query. + if ( isset( $this->args['date_query'] ) && is_array( $this->args['date_query'] ) ) { + foreach ( $this->args['date_query'] as $index => $query ) { + if ( isset( $query['column'] ) && isset( $mapping[ $query['column'] ] ) ) { + $this->args['date_query'][ $index ]['column'] = $mapping[ $query['column'] ]; + } + } + } } /** @@ -327,7 +336,28 @@ class OrdersTableQuery { $gmt_date_keys = array_values( $local_to_gmt_date_keys ); $local_date_keys = array_keys( $local_to_gmt_date_keys ); - foreach ( array_filter( array_merge( $gmt_date_keys, $local_date_keys ), array( $this, 'arg_isset' ) ) as $date_key ) { + $valid_date_keys = array_merge( $gmt_date_keys, $local_date_keys ); + $date_keys = array_filter( $valid_date_keys, array( $this, 'arg_isset' ) ); + + // Process already passed date queries args. + if ( $this->arg_isset( 'date_query' ) && is_array( $this->args['date_query'] ) ) { + foreach ( $this->args['date_query'] as $index => $query ) { + if ( ! isset( $query['column' ] ) || ! in_array( $query['column'], $valid_date_keys, true ) ) { + unset( $this->args['date_query'][ $index ] ); + continue; + } + // Convert any local dates to GMT. + if ( isset( $local_to_gmt_date_keys[ $query['column'] ] ) ) { + $this->args['date_query'][ $index ]['column'] = $local_to_gmt_date_keys[ $query['column'] ]; + $op = $query['after'] ? 'after' : 'before'; + $date_value_local = $query[ $op ]; + $date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) ); + $this->args['date_query'][ $index ][ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' ); + } + } + } + + foreach ( $date_keys as $date_key ) { $date_value = $this->args[ $date_key ]; $operator = '='; $dates = array(); diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php index 2a513e41dc4..cfa7a7dcf3e 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php @@ -10,6 +10,9 @@ * @package WooCommerce\Tests\API */ +use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore; +use Automattic\WooCommerce\Utilities\OrderUtil; + /** * Trait for testing the date filtering on controllers that inherit from WC_REST_CRUD_Controller. */ @@ -31,21 +34,37 @@ trait DateFilteringForCrudControllers { * @param bool $filter_by_gmt Whether the dates to filter by are GMT or not. * @param bool $expected_to_be_returned True if the created item is expected to be included in the response, false otherwise. */ - public function test_filter_by_creation_or_modification_date( $param_name, $filter_by_gmt, $expected_to_be_returned ) { + public function test_filter_by_creation_or_modification_date_sign1( $param_name, $filter_by_gmt, $expected_to_be_returned ) { global $wpdb; + $timezone_string_option = get_option( 'timezone_string' ); + update_option( 'timezone_string', 'Africa/Blantyre', true ); // +02:00 wp_set_current_user( $this->user ); - $item_id = $this->get_item_for_date_filtering_tests()->get_id(); + $item = $this->get_item_for_date_filtering_tests(); + $item_id = $item->get_id(); - // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared - $wpdb->query( - 'UPDATE ' . $wpdb->prefix . "posts SET + if ( $item instanceof WC_Abstract_Order && OrderUtil::custom_orders_table_usage_is_enabled() ) { + $wpdb->update( + OrdersTableDataStore::get_orders_table_name(), + array( + 'date_created_gmt' => '2000-01-01T10:00:00', + 'date_updated_gmt' => '2000-02-01T10:00:00', + ), + array( + 'id' => $item->get_id(), + ) + ); + } else { + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( + 'UPDATE ' . $wpdb->prefix . "posts SET post_date = '2000-01-01T12:00:00', post_date_gmt = '2000-01-01T10:00:00', post_modified = '2000-02-01T12:00:00', post_modified_gmt = '2000-02-01T10:00:00' WHERE ID = " . $item_id - ); + ); + } // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared $request = new WP_REST_Request( 'GET', $this->get_endpoint_for_date_filtering_tests() ); @@ -60,6 +79,7 @@ trait DateFilteringForCrudControllers { $this->assertEquals( 200, $response->get_status() ); $this->assertEquals( $expected_to_be_returned ? 1 : 0, count( $response_items ) ); + update_option( 'timezone_string', $timezone_string_option ); } /** From 61b6daae27c6c09098c23a3540e78b3a7a41201f Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 22 Feb 2023 17:51:59 +0530 Subject: [PATCH 17/49] Use correct column name for date_updated. --- .../src/Internal/DataStores/Orders/OrdersTableQuery.php | 2 +- .../unit-tests/rest-api/Tests/Version3/date-filtering.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index 357b9808430..9120aca1dbe 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -202,7 +202,7 @@ class OrdersTableQuery { // WP_Query legacy. 'post_date' => 'date_created', 'post_date_gmt' => 'date_created_gmt', - 'post_modified' => 'date_modified', + 'post_modified' => 'date_updated', 'post_modified_gmt' => 'date_updated_gmt', 'post_status' => 'status', '_date_completed' => 'date_completed', diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php index cfa7a7dcf3e..82c88c6878d 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php @@ -34,7 +34,7 @@ trait DateFilteringForCrudControllers { * @param bool $filter_by_gmt Whether the dates to filter by are GMT or not. * @param bool $expected_to_be_returned True if the created item is expected to be included in the response, false otherwise. */ - public function test_filter_by_creation_or_modification_date_sign1( $param_name, $filter_by_gmt, $expected_to_be_returned ) { + public function test_filter_by_creation_or_modification_date( $param_name, $filter_by_gmt, $expected_to_be_returned ) { global $wpdb; $timezone_string_option = get_option( 'timezone_string' ); From aaf45d59710298967e144d56431ba003e92f8e94 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 22 Feb 2023 19:12:15 +0530 Subject: [PATCH 18/49] Use isset to support other params. --- .../src/Internal/DataStores/Orders/OrdersTableQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index 9120aca1dbe..df85dba80ba 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -349,7 +349,7 @@ class OrdersTableQuery { // Convert any local dates to GMT. if ( isset( $local_to_gmt_date_keys[ $query['column'] ] ) ) { $this->args['date_query'][ $index ]['column'] = $local_to_gmt_date_keys[ $query['column'] ]; - $op = $query['after'] ? 'after' : 'before'; + $op = isset( $query['after'] ) ? 'after' : 'before'; $date_value_local = $query[ $op ]; $date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) ); $this->args['date_query'][ $index ][ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' ); From 0b689ed8bdcfe1acbe62c395dc8b5551399ab32b Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 22 Feb 2023 19:12:53 +0530 Subject: [PATCH 19/49] Modify test to support HPOS. --- .../Tests/Version3/date-filtering.php | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php index 82c88c6878d..a4eea18677a 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php @@ -100,19 +100,35 @@ trait DateFilteringForCrudControllers { public function test_can_filter_by_more_than_one_date( $first_param_name, $first_param_value, $second_param_name, $second_param_value, $filter_by_gmt, $expected_to_be_returned ) { global $wpdb; + $timezone_string_option = get_option( 'timezone_string' ); + update_option( 'timezone_string', 'Africa/Blantyre', true ); // +02:00 wp_set_current_user( $this->user ); - $item_id = $this->get_item_for_date_filtering_tests()->get_id(); + $item = $this->get_item_for_date_filtering_tests(); + $item_id = $item->get_id(); - // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared - $wpdb->query( - 'UPDATE ' . $wpdb->prefix . "posts SET + if ( $item instanceof WC_Abstract_Order && OrderUtil::custom_orders_table_usage_is_enabled() ) { + $wpdb->update( + OrdersTableDataStore::get_orders_table_name(), + array( + 'date_created_gmt' => '2000-01-01T10:00:00', + 'date_updated_gmt' => '2000-02-01T10:00:00', + ), + array( + 'id' => $item->get_id(), + ) + ); + } else { + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( + 'UPDATE ' . $wpdb->prefix . "posts SET post_date = '2000-01-01T12:00:00', post_date_gmt = '2000-01-01T10:00:00', post_modified = '2000-02-01T12:00:00', post_modified_gmt = '2000-02-01T10:00:00' WHERE ID = " . $item_id - ); - // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared + ); + // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared + } $request = new WP_REST_Request( 'GET', $this->get_endpoint_for_date_filtering_tests() ); $request->set_query_params( @@ -127,5 +143,6 @@ trait DateFilteringForCrudControllers { $this->assertEquals( 200, $response->get_status() ); $this->assertEquals( $expected_to_be_returned ? 1 : 0, count( $response_items ) ); + update_option( 'timezone_string', $timezone_string_option ); } } From 6d162a99500b08275f28832a68c6a2013614c0a0 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 22 Feb 2023 19:13:06 +0530 Subject: [PATCH 20/49] Undo regression in previous commit. --- .../Controllers/Version3/class-wc-rest-orders-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index ca488ebdde9..0ebbeb9473c 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -103,7 +103,7 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { */ protected function prepare_object_for_database( $request, $creating = false ) { $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0; - $order = wc_get_order( $id ); + $order = new WC_Order( $id ); $schema = $this->get_item_schema(); $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) ); From f3cb5424d7d520d1f39290ef9d6f92d9702351cc Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 22 Feb 2023 19:42:47 +0530 Subject: [PATCH 21/49] Move generic method to parent class for reusability. --- .../class-wc-rest-orders-v2-controller.php | 24 ++++++++++++++++ .../class-wc-rest-orders-controller.php | 28 ------------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 9f49bb546c9..89b90fb657b 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -325,6 +325,29 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { return $result; } + /** + * With HPOS, few internal meta keys such as _billing_address_index, _shipping_address_index are not considered internal anymore (since most internal keys were flattened into dedicated columns). + * + * This function helps in filtering out any remaining internal meta keys with HPOS is enabled. + * + * @param array $meta_data Order meta data. + * + * @return array Filtered order meta data. + */ + private function filter_internal_meta_keys( $meta_data ) { + if ( ! OrderUtil::custom_orders_table_usage_is_enabled() ) { + return $meta_data; + } + $cpt_hidden_keys = ( new \WC_Order_Data_Store_CPT() )->get_internal_meta_keys(); + $meta_data = array_filter( + $meta_data, + function ( $meta ) use ( $cpt_hidden_keys ) { + return ! in_array( $meta->key, $cpt_hidden_keys, true ); + } + ); + return array_values( $meta_data ); + } + /** * Get formatted item data. * @@ -369,6 +392,7 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { case 'meta_data': $meta_data = $order->get_meta_data(); $data['meta_data'] = $this->get_meta_data_for_response( $this->request, $meta_data ); + $data['meta_data'] = $this->filter_internal_meta_keys( $data['meta_data'] ); break; case 'line_items': $data['line_items'] = $order->get_items( 'line_item' ); diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php index 0ebbeb9473c..ab11869e49e 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-orders-controller.php @@ -235,34 +235,6 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller { } } - /** - * Get formatted item data. - * - * @param WC_Order $order WC_Data instance. - * @return array - */ - protected function get_formatted_item_data( $order ) { - $item_data = parent::get_formatted_item_data( $order ); - $cpt_hidden_keys = array(); - - if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { - $cpt_hidden_keys = ( new \WC_Order_Data_Store_CPT() )->get_internal_meta_keys(); - } - - // XXX: This might be removed once we finalize the design for internal keys vs meta vs props in COT. - if ( ! empty( $item_data['meta_data'] ) ) { - $item_data['meta_data'] = array_filter( - $item_data['meta_data'], - function ( $meta ) use ( $cpt_hidden_keys ) { - return ! in_array( $meta->key, $cpt_hidden_keys, true ); - } - ); - $item_data['meta_data'] = array_values( $item_data['meta_data'] ); - } - - return $item_data; - } - /** * Prepare objects query. * From 5c6392dc7ca0893c15a3cf79462b7b08e94b59f8 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 13:04:01 +0530 Subject: [PATCH 22/49] Use closure instead of returning DB object to prevent interference in other tests. PHPUnit will evaluate all data providers before starting anyh test (to count the number of tests to be executed). Which means that any data provider inserting data into DB is going to interfere with other tests. Using closure instead helps PHP in counting the data, yet not having to actual DB calls. --- ...ss-wc-customer-data-store-session-test.php | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php index 75ef103b8e0..64952afdab2 100644 --- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php +++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php @@ -11,11 +11,12 @@ class WC_Customer_Data_Store_Session_Test extends WC_Unit_Test_Case { * @see https://github.com/woocommerce/woocommerce/issues/28759 * @dataProvider provide_customers_with_different_addresses * - * @param WC_Customer $customer The customer object being tested. + * @param Closure $customer_closure The customer object being tested. * @param bool $states_should_match If the billing and shipping states should match. * @param bool $countries_should_match If the billing and shipping countries should match. */ - public function test_setting_default_address_fields( WC_Customer $customer, bool $states_should_match, bool $countries_should_match ) { + public function test_setting_default_address_fields( Closure $customer_closure, bool $states_should_match, bool $countries_should_match ) { + $customer = $customer_closure(); $session_data = new WC_Customer_Data_Store_Session(); $session_data->read( $customer ); @@ -46,66 +47,78 @@ class WC_Customer_Data_Store_Session_Test extends WC_Unit_Test_Case { * @return array[] */ public function provide_customers_with_different_addresses() { - $has_billing_address_only = new WC_Customer(); - $has_billing_address_only->set_email( 'wc-customer-test-01@test.user' ); - $has_billing_address_only->set_billing_address( '1234 Quality Lane' ); - $has_billing_address_only->set_billing_city( 'Testville' ); - $has_billing_address_only->set_billing_country( 'US' ); - $has_billing_address_only->set_billing_state( 'CA' ); - $has_billing_address_only->set_billing_postcode( '90123' ); - $has_billing_address_only->save(); + $cust1_closure = function () { + $has_billing_address_only = new WC_Customer(); + $has_billing_address_only->set_email( 'wc-customer-test-01@test.user' ); + $has_billing_address_only->set_billing_address( '1234 Quality Lane' ); + $has_billing_address_only->set_billing_city( 'Testville' ); + $has_billing_address_only->set_billing_country( 'US' ); + $has_billing_address_only->set_billing_state( 'CA' ); + $has_billing_address_only->set_billing_postcode( '90123' ); + $has_billing_address_only->save(); + return $has_billing_address_only; + }; - $separate_billing_and_shipping_state_and_country = new WC_Customer(); - $separate_billing_and_shipping_state_and_country->set_email( 'wc-customer-test-02@test.user' ); - $separate_billing_and_shipping_state_and_country->set_billing_address( '4567 Scenario Street' ); - $separate_billing_and_shipping_state_and_country->set_billing_city( 'Unitly' ); - $separate_billing_and_shipping_state_and_country->set_billing_country( 'UK' ); - $separate_billing_and_shipping_state_and_country->set_billing_state( 'Computershire' ); - $separate_billing_and_shipping_state_and_country->set_billing_postcode( 'ZX1 2PQ' ); - $separate_billing_and_shipping_state_and_country->set_shipping_address( '8901 Situation Court' ); - $separate_billing_and_shipping_state_and_country->set_shipping_city( 'Endtoendly' ); - $separate_billing_and_shipping_state_and_country->set_shipping_country( 'CA' ); - $separate_billing_and_shipping_state_and_country->set_shipping_state( 'BC' ); - $separate_billing_and_shipping_state_and_country->set_shipping_postcode( 'A1B 2C3' ); - $separate_billing_and_shipping_state_and_country->save(); + $cust2_closure = function () { + $separate_billing_and_shipping_state_and_country = new WC_Customer(); + $separate_billing_and_shipping_state_and_country->set_email( 'wc-customer-test-02@test.user' ); + $separate_billing_and_shipping_state_and_country->set_billing_address( '4567 Scenario Street' ); + $separate_billing_and_shipping_state_and_country->set_billing_city( 'Unitly' ); + $separate_billing_and_shipping_state_and_country->set_billing_country( 'UK' ); + $separate_billing_and_shipping_state_and_country->set_billing_state( 'Computershire' ); + $separate_billing_and_shipping_state_and_country->set_billing_postcode( 'ZX1 2PQ' ); + $separate_billing_and_shipping_state_and_country->set_shipping_address( '8901 Situation Court' ); + $separate_billing_and_shipping_state_and_country->set_shipping_city( 'Endtoendly' ); + $separate_billing_and_shipping_state_and_country->set_shipping_country( 'CA' ); + $separate_billing_and_shipping_state_and_country->set_shipping_state( 'BC' ); + $separate_billing_and_shipping_state_and_country->set_shipping_postcode( 'A1B 2C3' ); + $separate_billing_and_shipping_state_and_country->save(); + return $separate_billing_and_shipping_state_and_country; + }; - $separate_billing_state_same_country = new WC_Customer(); - $separate_billing_state_same_country->set_email( 'wc-customer-test-03@test.user' ); - $separate_billing_state_same_country->set_billing_address( '4567 Scenario Street' ); - $separate_billing_state_same_country->set_billing_city( 'Unitly' ); - $separate_billing_state_same_country->set_billing_country( 'UK' ); - $separate_billing_state_same_country->set_billing_state( 'Computershire' ); - $separate_billing_state_same_country->set_billing_postcode( 'ZX1 2PQ' ); - $separate_billing_state_same_country->set_shipping_address( '8901 Situation Court' ); - $separate_billing_state_same_country->set_shipping_city( 'Endtoendly' ); - $separate_billing_state_same_country->set_shipping_country( 'UK' ); - $separate_billing_state_same_country->set_shipping_state( 'Byteshire' ); - $separate_billing_state_same_country->set_shipping_postcode( 'RS1 2TU' ); - $separate_billing_state_same_country->save(); + $cust3_closure = function () { + $separate_billing_state_same_country = new WC_Customer(); + $separate_billing_state_same_country->set_email( 'wc-customer-test-03@test.user' ); + $separate_billing_state_same_country->set_billing_address( '4567 Scenario Street' ); + $separate_billing_state_same_country->set_billing_city( 'Unitly' ); + $separate_billing_state_same_country->set_billing_country( 'UK' ); + $separate_billing_state_same_country->set_billing_state( 'Computershire' ); + $separate_billing_state_same_country->set_billing_postcode( 'ZX1 2PQ' ); + $separate_billing_state_same_country->set_shipping_address( '8901 Situation Court' ); + $separate_billing_state_same_country->set_shipping_city( 'Endtoendly' ); + $separate_billing_state_same_country->set_shipping_country( 'UK' ); + $separate_billing_state_same_country->set_shipping_state( 'Byteshire' ); + $separate_billing_state_same_country->set_shipping_postcode( 'RS1 2TU' ); + $separate_billing_state_same_country->save(); + return $separate_billing_state_same_country; + }; - $shipping_address_is_effectively_empty = new WC_Customer(); - $shipping_address_is_effectively_empty->set_email( 'wc-customer-test-04@test.user' ); - $shipping_address_is_effectively_empty->set_shipping_address( ' ' ); - $shipping_address_is_effectively_empty->save(); + $cust4_closure = function () { + $shipping_address_is_effectively_empty = new WC_Customer(); + $shipping_address_is_effectively_empty->set_email( 'wc-customer-test-04@test.user' ); + $shipping_address_is_effectively_empty->set_shipping_address( ' ' ); + $shipping_address_is_effectively_empty->save(); + return $shipping_address_is_effectively_empty; + }; return array( 'has_billing_address_only' => array( - $has_billing_address_only, + $cust1_closure, true, true, ), 'separate_billing_and_shipping_state_and_country' => array( - $separate_billing_and_shipping_state_and_country, + $cust2_closure, false, false, ), 'separate_billing_state_same_country' => array( - $separate_billing_state_same_country, + $cust3_closure, false, true, ), 'shipping_address_is_effectively_empty' => array( - $shipping_address_is_effectively_empty, + $cust4_closure, true, true, ), From d54e141aaf4ff36fe826d58c15b810ad464b8b81 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 13:06:04 +0530 Subject: [PATCH 23/49] Use CRUD instead of direct post access for HPOS compat. --- .../unit-tests/woocommerce-admin/api/reports-import.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-import.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-import.php index b4a78652004..18e00664fd4 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-import.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/api/reports-import.php @@ -323,13 +323,8 @@ class WC_Admin_Tests_API_Reports_Import extends WC_REST_Unit_Test_Case { // Create 1 draft order - to be excluded from totals. $order = WC_Helper_Order::create_order( $this->customer, $product ); $order->set_date_created( time() - ( 5 * DAY_IN_SECONDS ) ); + $order->set_status( 'auto-draft' ); $order->save(); - wp_update_post( - array( - 'ID' => $order->get_id(), - 'post_status' => 'auto-draft', - ) - ); // Test totals and total params. $request = new WP_REST_Request( 'GET', $this->endpoint . '/totals' ); From f20d619c30ec1c33cabca676d7f144c578faf66b Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 13:11:28 +0530 Subject: [PATCH 24/49] Skip legacy tests. --- .../admin/reports/class-wc-tests-admin-report.php | 10 ++++++++++ .../reports/class-wc-tests-report-sales-by-date.php | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-admin-report.php b/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-admin-report.php index 480af399bdc..4b21d058eb3 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-admin-report.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-admin-report.php @@ -18,6 +18,16 @@ class WC_Tests_Admin_Report extends WC_Unit_Test_Case { include_once WC_Unit_Tests_Bootstrap::instance()->plugin_dir . '/includes/admin/reports/class-wc-admin-report.php'; } + /** + * Set up the test. + */ + public function setUp(): void { + parent::setUp(); + if ( \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->markTestSkipped( 'This test is not compatible with the custom orders table.' ); + } + } + /** * Clear cached report data. * diff --git a/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-report-sales-by-date.php b/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-report-sales-by-date.php index 8f3364deb11..b7e602e0c56 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-report-sales-by-date.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/admin/reports/class-wc-tests-report-sales-by-date.php @@ -18,6 +18,16 @@ class WC_Tests_Report_Sales_By_Date extends WC_Unit_Test_Case { include_once WC_Unit_Tests_Bootstrap::instance()->plugin_dir . '/includes/admin/reports/class-wc-report-sales-by-date.php'; } + /** + * Set up the test. + */ + public function setUp(): void { + parent::setUp(); + if ( \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->markTestSkipped( 'This test is not compatible with the custom orders table.' ); + } + } + /** * Clear cached report data. * From a3c646fe552cf9e6df8ef8816d2364ec69e0ff76 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 13:18:52 +0530 Subject: [PATCH 25/49] Apply coding standards. --- .../class-wc-customer-data-store-session-test.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php index 64952afdab2..126d1b055a5 100644 --- a/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php +++ b/plugins/woocommerce/tests/php/includes/data-stores/class-wc-customer-data-store-session-test.php @@ -11,12 +11,12 @@ class WC_Customer_Data_Store_Session_Test extends WC_Unit_Test_Case { * @see https://github.com/woocommerce/woocommerce/issues/28759 * @dataProvider provide_customers_with_different_addresses * - * @param Closure $customer_closure The customer object being tested. - * @param bool $states_should_match If the billing and shipping states should match. - * @param bool $countries_should_match If the billing and shipping countries should match. + * @param Closure $customer_closure The customer object being tested. + * @param bool $states_should_match If the billing and shipping states should match. + * @param bool $countries_should_match If the billing and shipping countries should match. */ public function test_setting_default_address_fields( Closure $customer_closure, bool $states_should_match, bool $countries_should_match ) { - $customer = $customer_closure(); + $customer = $customer_closure(); $session_data = new WC_Customer_Data_Store_Session(); $session_data->read( $customer ); From 2362d7785a1a5c7add8cc31649b18a256096a930 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 14:04:35 +0530 Subject: [PATCH 26/49] Add HPOS support to admin orders API. --- plugins/woocommerce/src/Admin/API/Orders.php | 56 +++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/plugins/woocommerce/src/Admin/API/Orders.php b/plugins/woocommerce/src/Admin/API/Orders.php index e85bec04c10..303ec5d5a33 100644 --- a/plugins/woocommerce/src/Admin/API/Orders.php +++ b/plugins/woocommerce/src/Admin/API/Orders.php @@ -10,6 +10,8 @@ namespace Automattic\WooCommerce\Admin\API; defined( 'ABSPATH' ) || exit; use Automattic\WooCommerce\Admin\API\Reports\Controller as ReportsController; +use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore; +use Automattic\WooCommerce\Utilities\OrderUtil; /** * Orders controller. @@ -54,30 +56,58 @@ class Orders extends \WC_REST_Orders_Controller { * @return array */ protected function prepare_objects_query( $request ) { - global $wpdb; $args = parent::prepare_objects_query( $request ); - // Search by partial order number. if ( ! empty( $request['number'] ) ) { - $partial_number = trim( $request['number'] ); - $limit = intval( $args['posts_per_page'] ); - $order_ids = $wpdb->get_col( + $args = $this->search_partial_order_number( $request['number'], $args ); + } + + return $args; + } + + /** + * Helper method to allow searching by partial order number. + * @param int $number Partial order number match + * @param array $args List of arguments for the request. + * + * @return array Modified args with partial order search included. + */ + private function search_partial_order_number( $number, $args ) { + global $wpdb; + + $partial_number = trim( $number ); + $limit = intval( $args['posts_per_page'] ); + if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { + $order_table_name = OrdersTableDataStore::get_orders_table_name(); + $order_ids = $wpdb->get_col( $wpdb->prepare( - "SELECT ID - FROM {$wpdb->prefix}posts - WHERE post_type = 'shop_order' - AND ID LIKE %s + "SELECT id + FROM $order_table_name + WHERE type = 'shop_order' + AND id LIKE %s LIMIT %d", $wpdb->esc_like( absint( $partial_number ) ) . '%', $limit ) ); - - // Force WP_Query return empty if don't found any order. - $order_ids = empty( $order_ids ) ? array( 0 ) : $order_ids; - $args['post__in'] = $order_ids; + } else { + $order_ids = $wpdb->get_col( + $wpdb->prepare( + "SELECT ID + FROM {$wpdb->prefix}posts + WHERE post_type = 'shop_order' + AND ID LIKE %s + LIMIT %d", + $wpdb->esc_like( absint( $partial_number ) ) . '%', + $limit + ) + ); } + // Force WP_Query return empty if don't found any order. + $order_ids = empty( $order_ids ) ? array( 0 ) : $order_ids; + $args['post__in'] = $order_ids; + return $args; } From 2d3f38851c29784dcd850160f95a5b55029014bb Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 14:37:35 +0530 Subject: [PATCH 27/49] Set correct datastore for tests. --- .../includes/class-wc-order-factory-test.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php index e3af7d32052..34e8e2a7dc9 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php @@ -5,6 +5,35 @@ */ class WC_Order_Factory_Test extends WC_Unit_Test_Case { + /** + * Store COT state at the start of the test so we can restore it later. + * + * @var bool + */ + private $cot_state; + + /** + * Disable COT before the test. + * + * @return void + */ + public function setUp(): void { + parent::setUp(); + $this->cot_state = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); + \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( false ); + } + + /** + * Restore COT state after the test. + *= + * @return void + */ + public function tearDown(): void { + parent::tearDown(); + wp_cache_flush(); + \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( $this->cot_state ); + } + /** * @testDox get_orders should be able to return multiple orders of different types. */ From 7fbd73651762ff203cbb042780dfff4b4a2c5ff4 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 15:01:38 +0530 Subject: [PATCH 28/49] Sanitize value before returning. --- .../DataStores/Orders/OrdersTableDataStore.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php index 2d4038adbed..d15cebcf241 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php @@ -573,7 +573,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_download_permissions_granted( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ) ); } /** @@ -599,7 +599,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_sales( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ) ); } /** @@ -625,7 +625,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_coupon_usage_counts( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ) ); } /** @@ -651,7 +651,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_email_sent( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ) ); } /** @@ -702,7 +702,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_stock_reduced( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ) ); } /** From 5e7052b03d5fa2102f3421209b80da308d05ab54 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 15:02:01 +0530 Subject: [PATCH 29/49] Use correct data store for getter/setters. --- .../Internal/DataStores/Orders/OrdersTableDataStoreTests.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php index 2d7b5685c55..88b557e5ca1 100644 --- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php +++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php @@ -1855,7 +1855,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { * @testDox Legacy getters and setters for props migrated from data stores should be set/reset properly. */ public function test_legacy_getters_setters() { - $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_wp_post_order(); + $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_data_store_order( $this->sut ); $order = wc_get_order( $order_id ); $this->switch_data_store( $order, $this->sut ); $bool_props = array( From f8b6258c92b5b4b29ecfe5a7a581797164e3aa5e Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 14:37:35 +0530 Subject: [PATCH 30/49] Set correct datastore for tests. --- .../includes/class-wc-order-factory-test.php | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php index e3af7d32052..34e8e2a7dc9 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php @@ -5,6 +5,35 @@ */ class WC_Order_Factory_Test extends WC_Unit_Test_Case { + /** + * Store COT state at the start of the test so we can restore it later. + * + * @var bool + */ + private $cot_state; + + /** + * Disable COT before the test. + * + * @return void + */ + public function setUp(): void { + parent::setUp(); + $this->cot_state = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); + \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( false ); + } + + /** + * Restore COT state after the test. + *= + * @return void + */ + public function tearDown(): void { + parent::tearDown(); + wp_cache_flush(); + \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( $this->cot_state ); + } + /** * @testDox get_orders should be able to return multiple orders of different types. */ From a3a41356eed46de80769617d9342ddd8d45bdcd6 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 15:01:38 +0530 Subject: [PATCH 31/49] Sanitize value before returning. --- .../DataStores/Orders/OrdersTableDataStore.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php index 2d4038adbed..d15cebcf241 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php @@ -573,7 +573,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_download_permissions_granted( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ) ); } /** @@ -599,7 +599,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_sales( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ) ); } /** @@ -625,7 +625,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_coupon_usage_counts( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ) ); } /** @@ -651,7 +651,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_email_sent( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ) ); } /** @@ -702,7 +702,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_stock_reduced( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ); + return wc_string_to_bool( $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ) ); } /** From 87da68c377f224315cfcbb5a8fe79ff294a023c9 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Fri, 24 Feb 2023 15:02:01 +0530 Subject: [PATCH 32/49] Use correct data store for getter/setters. --- .../Internal/DataStores/Orders/OrdersTableDataStoreTests.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php index 2d7b5685c55..88b557e5ca1 100644 --- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php +++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php @@ -1855,7 +1855,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { * @testDox Legacy getters and setters for props migrated from data stores should be set/reset properly. */ public function test_legacy_getters_setters() { - $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_wp_post_order(); + $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_data_store_order( $this->sut ); $order = wc_get_order( $order_id ); $this->switch_data_store( $order, $this->sut ); $bool_props = array( From 8da07f73e71194aedbfc4474a882e3d436a4bc83 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 13:48:59 +0530 Subject: [PATCH 33/49] Fetch order first to refresh cache before returning prop. --- plugins/woocommerce/changelog/fix-36685-2 | 2 +- .../Orders/OrdersTableDataStore.php | 40 +++++-------------- 2 files changed, 11 insertions(+), 31 deletions(-) diff --git a/plugins/woocommerce/changelog/fix-36685-2 b/plugins/woocommerce/changelog/fix-36685-2 index 6a89ac8e78f..9a8084aeee3 100644 --- a/plugins/woocommerce/changelog/fix-36685-2 +++ b/plugins/woocommerce/changelog/fix-36685-2 @@ -1,4 +1,4 @@ Significance: patch Type: fix -Directly fetch order prop from DB for compatibility with CPT store. +Fetch order first to refresh cache before returning prop. diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php index d15cebcf241..92612709cab 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php @@ -573,7 +573,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_download_permissions_granted( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return wc_string_to_bool( $this->get_field_value( $order_id, 'download_permission_granted', self::get_operational_data_table_name() ) ); + $order = wc_get_order( $order_id ); + return $order->get_download_permissions_granted(); } /** @@ -599,7 +600,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_sales( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return wc_string_to_bool( $this->get_field_value( $order_id, 'recorded_sales', self::get_operational_data_table_name() ) ); + $order = wc_get_order( $order_id ); + return $order->get_recorded_sales(); } /** @@ -625,7 +627,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_coupon_usage_counts( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return wc_string_to_bool( $this->get_field_value( $order_id, 'coupon_usages_are_counted', self::get_operational_data_table_name() ) ); + $order = wc_get_order( $order_id ); + return $order->get_recorded_coupon_usage_counts(); } /** @@ -651,7 +654,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_email_sent( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return wc_string_to_bool( $this->get_field_value( $order_id, 'new_order_email_sent', self::get_operational_data_table_name() ) ); + $order = wc_get_order( $order_id ); + return $order->get_new_order_email_sent(); } /** @@ -702,7 +706,8 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_stock_reduced( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - return wc_string_to_bool( $this->get_field_value( $order_id, 'order_stock_reduced', self::get_operational_data_table_name() ) ); + $order = wc_get_order( $order_id ); + return $order->get_order_stock_reduced(); } /** @@ -899,31 +904,6 @@ WHERE // phpcs:enable } - /** - * Returns field value for an order directly from the database, skipping the value stored in order prop. - * Useful when you are not sure if the order prop is manipulated by a callee function without having to refresh the order. - * - * @param int $order_id Order ID. - * @param string $column_name Name of the column to fetch value from. - * @param string $table_name Name of the table to fetch value from. - * - * @return string|null Field value or null if not found. - */ - public function get_field_value( $order_id, $column_name, $table_name ) { - global $wpdb; - $where_clause = ' WHERE 1=1 '; - if ( self::get_addresses_table_name() === $table_name ) { - $address_type = explode( '_', $column_name )[0]; - $column_name = str_replace( $address_type . '_', '', $column_name ); - $where_clause .= $wpdb->prepare( ' AND type = %s', $address_type ); - } - $select_clause = 'SELECT `' . esc_sql( $column_name ) . '` FROM `' . esc_sql( $table_name ) . '` '; - $where_clause .= $wpdb->prepare( ' AND order_id = %d', $order_id ); - - // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Both select_clause and where_clause are escaped. - return $wpdb->get_var( "$select_clause $where_clause LIMIT 1" ); - } - /** * Search order data for a term and return matching order IDs. * From 01114fc5d95b943b6e59fffc826e37d59cd2bcc5 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 14:50:14 +0530 Subject: [PATCH 34/49] Toggle COT appropriately for COT tests. --- .../Orders/OrdersTableDataStore.php | 2 +- .../Orders/OrdersTableDataStoreTests.php | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php index 92612709cab..8683d1c366e 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php @@ -627,7 +627,7 @@ class OrdersTableDataStore extends \Abstract_WC_Order_Data_Store_CPT implements */ public function get_recorded_coupon_usage_counts( $order ) { $order_id = is_int( $order ) ? $order : $order->get_id(); - $order = wc_get_order( $order_id ); + $order = wc_get_order( $order_id ); return $order->get_recorded_coupon_usage_counts(); } diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php index 88b557e5ca1..04e70cc9c90 100644 --- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php +++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php @@ -7,6 +7,7 @@ use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore; use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableQuery; use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper; use Automattic\WooCommerce\RestApi\UnitTests\HPOSToggleTrait; +use Automattic\WooCommerce\Utilities\OrderUtil; /** * Class OrdersTableDataStoreTests. @@ -37,6 +38,12 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { */ private $cpt_data_store; + /** + * Whether COT was enabled before the test. + * @var bool + */ + private $cot_state; + /** * Initializes system under test. */ @@ -47,6 +54,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { parent::setUp(); // Remove the Test Suiteā€™s use of temporary tables https://wordpress.stackexchange.com/a/220308. $this->setup_cot(); + $this->cot_state = OrderUtil::custom_orders_table_usage_is_enabled(); $this->toggle_cot( false ); $this->sut = wc_get_container()->get( OrdersTableDataStore::class ); $this->migrator = wc_get_container()->get( PostsToOrdersMigrationController::class ); @@ -59,6 +67,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { public function tearDown(): void { //phpcs:ignore WordPress.DateTime.RestrictedFunctions.timezone_change_date_default_timezone_set -- We need to change the timezone to test the date sync fields. update_option( 'timezone_string', $this->original_time_zone ); + $this->toggle_cot( $this->cot_state ); $this->clean_up_cot_setup(); parent::tearDown(); } @@ -205,6 +214,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { wp_cache_flush(); $order = new WC_Order(); $order->set_id( $post_order->get_id() ); + $this->toggle_cot( true ); $this->switch_data_store( $order, $this->sut ); $this->sut->read( $order ); @@ -239,6 +249,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { foreach ( $datastore_updates as $prop => $value ) { $this->assertEquals( $value, $this->sut->{"get_$prop"}( $order ), "Unable to match prop $prop" ); } + $this->toggle_cot( false ); } /** @@ -1767,6 +1778,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { * Ideally, this should be possible only from getters and setters for objects, but for backward compatibility, earlier ways are also supported. */ public function test_internal_ds_getters_and_setters() { + $this->toggle_cot( true ); $props_to_test = array( '_download_permissions_granted', '_recorded_sales', @@ -1813,6 +1825,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { $order->save(); } $this->assert_get_prop_via_ds_object_and_metadata( $props_to_test, $order, false, $ds_getter_setter_names ); + $this->toggle_cot( false ); } /** @@ -1855,6 +1868,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { * @testDox Legacy getters and setters for props migrated from data stores should be set/reset properly. */ public function test_legacy_getters_setters() { + $this->toggle_cot( true ); $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_data_store_order( $this->sut ); $order = wc_get_order( $order_id ); $this->switch_data_store( $order, $this->sut ); @@ -1887,7 +1901,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { $this->assert_props_value_via_data_store( $order, $bool_props, true ); $this->assert_props_value_via_order_object( $order, $bool_props, true ); - + $this->toggle_cot( false ); } /** @@ -1984,8 +1998,9 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { */ public function test_read_multiple_dont_sync_again_for_same_order() { $this->toggle_cot( true ); - $this->enable_cot_sync(); $order = $this->create_complex_cot_order(); + $this->sut->backfill_post_record( $order ); + $this->enable_cot_sync(); $order_id = $order->get_id(); @@ -1999,6 +2014,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { $this->assertTrue( $should_sync_callable->call( $this->sut, $order ) ); $this->sut->read_multiple( $orders ); $this->assertFalse( $should_sync_callable->call( $this->sut, $order ) ); + $this->toggle_cot( false ); } /** From 46f6eb3d5f78727ebf16a8a9db5d46e8c6d0587f Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 14:56:43 +0530 Subject: [PATCH 35/49] Removed typo. --- .../tests/php/includes/class-wc-order-factory-test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php index 34e8e2a7dc9..56cda5d51c8 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php @@ -25,7 +25,7 @@ class WC_Order_Factory_Test extends WC_Unit_Test_Case { /** * Restore COT state after the test. - *= + * * @return void */ public function tearDown(): void { From 83694878477cb8a787da603b196eb1048597cd41 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 16:43:25 +0530 Subject: [PATCH 36/49] Apply coding standards. --- plugins/woocommerce/includes/wc-user-functions.php | 6 +++--- .../unit-tests/order/class-wc-tests-order-functions.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/includes/wc-user-functions.php b/plugins/woocommerce/includes/wc-user-functions.php index f1c2c43706a..868dc539451 100644 --- a/plugins/woocommerce/includes/wc-user-functions.php +++ b/plugins/woocommerce/includes/wc-user-functions.php @@ -716,11 +716,11 @@ function wc_reset_order_customer_id_on_deleted_user( $user_id ) { if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { $order_table_ds = wc_get_container()->get( OrdersTableDataStore::class ); - $order_table = $order_table_ds::get_orders_table_name(); + $order_table = $order_table_ds::get_orders_table_name(); $wpdb->update( $order_table, array( - 'customer_id' => 0, + 'customer_id' => 0, 'date_updated_gmt' => current_time( 'mysql', true ), ), array( @@ -746,7 +746,7 @@ function wc_reset_order_customer_id_on_deleted_user( $user_id ) { 'meta_key' => '_customer_user', 'meta_value' => $user_id, ) - ); // WPCS: slow query ok. + ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query } } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php index 6ba56763594..696668decd9 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-order-functions.php @@ -109,10 +109,10 @@ class WC_Tests_Order_Functions extends WC_Unit_Test_Case { ->will( $this->returnValueMap( $test_counts[ $order_type ] ) ); } - $add_mock_datastores = function( $stores ) use ( $mock_datastores ) { + $add_mock_datastores = function ( $stores ) use ( $mock_datastores ) { return array_merge( $stores, $mock_datastores ); }; - $add_mock_order_type = function( $order_types ) use ( $mock_datastores ) { + $add_mock_order_type = function ( $order_types ) use ( $mock_datastores ) { return array( 'shop_order', 'order-fake-type' ); }; $return_mock_order_data_store = function ( $stores ) use ( $mock_datastores ) { From ef74ccd496a21ae3b90ebecfaaa675d40ceae22f Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 17:07:59 +0530 Subject: [PATCH 37/49] Use posts before delete hook along with HPOS one. --- plugins/woocommerce/includes/class-wc-post-data.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/woocommerce/includes/class-wc-post-data.php b/plugins/woocommerce/includes/class-wc-post-data.php index e35de400ef1..c1e3aa6b5f0 100644 --- a/plugins/woocommerce/includes/class-wc-post-data.php +++ b/plugins/woocommerce/includes/class-wc-post-data.php @@ -53,6 +53,7 @@ class WC_Post_Data { add_action( 'delete_post', array( __CLASS__, 'delete_post' ) ); add_action( 'wp_trash_post', array( __CLASS__, 'trash_post' ) ); add_action( 'untrashed_post', array( __CLASS__, 'untrash_post' ) ); + add_action( 'before_delete_post', array( __CLASS__, 'before_delete_order' ) ); add_action( 'woocommerce_before_delete_order', array( __CLASS__, 'before_delete_order' ) ); // Meta cache flushing. From 648d801da2b6b95ab04e6ad63a02b8e2ebdebf6f Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 17:08:38 +0530 Subject: [PATCH 38/49] Added changelog. --- plugins/woocommerce/changelog/fix-36684 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36684 diff --git a/plugins/woocommerce/changelog/fix-36684 b/plugins/woocommerce/changelog/fix-36684 new file mode 100644 index 00000000000..46751fa0216 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36684 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Add HPOS compat for wc-user-functions.php. From 04642b8bd403ff2cbe8ee238d7e9b6e87f5944fc Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 17:22:44 +0530 Subject: [PATCH 39/49] Apply coding standards --- plugins/woocommerce/includes/wc-user-functions.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/includes/wc-user-functions.php b/plugins/woocommerce/includes/wc-user-functions.php index 868dc539451..7b53871b454 100644 --- a/plugins/woocommerce/includes/wc-user-functions.php +++ b/plugins/woocommerce/includes/wc-user-functions.php @@ -740,13 +740,13 @@ function wc_reset_order_customer_id_on_deleted_user( $user_id ) { $wpdb->update( $wpdb->postmeta, array( - 'meta_value' => 0, + 'meta_value' => 0, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ), array( - 'meta_key' => '_customer_user', - 'meta_value' => $user_id, + 'meta_key' => '_customer_user', //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + 'meta_value' => $user_id, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value ) - ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + ); } } From f5ac18f11c70cb34a853dd6cbe0878ba178efd79 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 17:27:32 +0530 Subject: [PATCH 40/49] Add changelog. --- plugins/woocommerce/changelog/fix-36682 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36682 diff --git a/plugins/woocommerce/changelog/fix-36682 b/plugins/woocommerce/changelog/fix-36682 new file mode 100644 index 00000000000..57e3e2c4011 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36682 @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Changes are only in unit tests, no functionality is affected. + + From 1736911bfa866dcc81583e24c66141e63d61c67d Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 17:42:47 +0530 Subject: [PATCH 41/49] Applied coding standards. --- plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php | 2 +- .../unit-tests/order/class-wc-tests-crud-orders.php | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php b/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php index 427739ca95e..00c34fd5eac 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/crud/meta.php @@ -115,7 +115,7 @@ class WC_Tests_CRUD_Meta_Data extends WC_Unit_Test_Case { $this->assertTrue( in_array( 'random', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); $this->assertTrue( in_array( 'random_other', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); if ( ! OrderUtil::custom_orders_table_usage_is_enabled() ) { - $this->assertTrue( in_array( 'random_other_pre_crud', wp_list_pluck( $new_order->get_meta_data(), 'key' ) ) ); + $this->assertTrue( in_array( 'random_other_pre_crud', wp_list_pluck( $new_order->get_meta_data(), 'key' ), true ) ); } } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php index b0f8897821a..e85e8f0fe50 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php @@ -5,6 +5,8 @@ * @package WooCommerce\Tests\CRUD */ +use Automattic\WooCommerce\Utilities\OrderUtil; + /** * Meta * @@ -882,9 +884,9 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $object = new WC_Order(); // Save + create. - $save_id = $object->save(); - $post = get_post( $save_id ); - $expected_post_type = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ? 'shop_order_placehold' : 'shop_order'; + $save_id = $object->save(); + $post = get_post( $save_id ); + $expected_post_type = OrderUtil::custom_orders_table_usage_is_enabled() ? 'shop_order_placehold' : 'shop_order'; $this->assertEquals( $expected_post_type, $post->post_type ); // Update. From 5c1d1d78d256188c4925f1ee7ca485a3f4081b67 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 18:25:01 +0530 Subject: [PATCH 42/49] Add changelog. --- plugins/woocommerce/changelog/fix-36681 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36681 diff --git a/plugins/woocommerce/changelog/fix-36681 b/plugins/woocommerce/changelog/fix-36681 new file mode 100644 index 00000000000..861800cd5f3 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36681 @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Skipping unit test for legacy widgets when in HPOS context. + + From 4f4d42b9efc538364f5013eed2b781a56cbaac9c Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 18:47:54 +0530 Subject: [PATCH 43/49] Add changelog. --- plugins/woocommerce/changelog/fix-36680 | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36680 diff --git a/plugins/woocommerce/changelog/fix-36680 b/plugins/woocommerce/changelog/fix-36680 new file mode 100644 index 00000000000..1f0244c8d51 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36680 @@ -0,0 +1,5 @@ +Significance: patch +Type: fix +Comment: Changes are only in unit tests (for HPOS compat). + + From 1e700b90af95e8299d065162a7827a6a62547691 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 19:11:37 +0530 Subject: [PATCH 44/49] Add changelog. --- plugins/woocommerce/changelog/fix-36679 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36679 diff --git a/plugins/woocommerce/changelog/fix-36679 b/plugins/woocommerce/changelog/fix-36679 new file mode 100644 index 00000000000..ba4a88ad52d --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36679 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Add support for `after`, `before`, `modified_after` and `modified_before` params in local timezone. From 33d41206fcbe7fc43c7c3779b88a4a4627162edf Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 19:18:23 +0530 Subject: [PATCH 45/49] Add changelog. --- plugins/woocommerce/changelog/fix-36678 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 plugins/woocommerce/changelog/fix-36678 diff --git a/plugins/woocommerce/changelog/fix-36678 b/plugins/woocommerce/changelog/fix-36678 new file mode 100644 index 00000000000..c784cf1db18 --- /dev/null +++ b/plugins/woocommerce/changelog/fix-36678 @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Add HPOS compat for admin report functions. From f12be6e673e3c14d0f89ae1b5ebbad066b3aa186 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 19:29:21 +0530 Subject: [PATCH 46/49] Applied coding standards. --- .../Version2/class-wc-rest-orders-v2-controller.php | 2 +- .../Internal/DataStores/Orders/OrdersTableQuery.php | 10 +++++----- .../rest-api/Tests/Version3/date-filtering.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php index 89b90fb657b..b646c36a2e3 100644 --- a/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php +++ b/plugins/woocommerce/includes/rest-api/Controllers/Version2/class-wc-rest-orders-v2-controller.php @@ -339,7 +339,7 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller { return $meta_data; } $cpt_hidden_keys = ( new \WC_Order_Data_Store_CPT() )->get_internal_meta_keys(); - $meta_data = array_filter( + $meta_data = array_filter( $meta_data, function ( $meta ) use ( $cpt_hidden_keys ) { return ! in_array( $meta->key, $cpt_hidden_keys, true ); diff --git a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php index df85dba80ba..92148b218c6 100644 --- a/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php +++ b/plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableQuery.php @@ -342,17 +342,17 @@ class OrdersTableQuery { // Process already passed date queries args. if ( $this->arg_isset( 'date_query' ) && is_array( $this->args['date_query'] ) ) { foreach ( $this->args['date_query'] as $index => $query ) { - if ( ! isset( $query['column' ] ) || ! in_array( $query['column'], $valid_date_keys, true ) ) { + if ( ! isset( $query['column'] ) || ! in_array( $query['column'], $valid_date_keys, true ) ) { unset( $this->args['date_query'][ $index ] ); continue; } // Convert any local dates to GMT. if ( isset( $local_to_gmt_date_keys[ $query['column'] ] ) ) { $this->args['date_query'][ $index ]['column'] = $local_to_gmt_date_keys[ $query['column'] ]; - $op = isset( $query['after'] ) ? 'after' : 'before'; - $date_value_local = $query[ $op ]; - $date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) ); - $this->args['date_query'][ $index ][ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' ); + $op = isset( $query['after'] ) ? 'after' : 'before'; + $date_value_local = $query[ $op ]; + $date_value_gmt = wc_string_to_timestamp( get_gmt_from_date( wc_string_to_datetime( $date_value_local ) ) ); + $this->args['date_query'][ $index ][ $op ] = $this->date_to_date_query_arg( $date_value_gmt, 'UTC' ); } } } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php index a4eea18677a..b18c201cb44 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/date-filtering.php @@ -40,7 +40,7 @@ trait DateFilteringForCrudControllers { $timezone_string_option = get_option( 'timezone_string' ); update_option( 'timezone_string', 'Africa/Blantyre', true ); // +02:00 wp_set_current_user( $this->user ); - $item = $this->get_item_for_date_filtering_tests(); + $item = $this->get_item_for_date_filtering_tests(); $item_id = $item->get_id(); if ( $item instanceof WC_Abstract_Order && OrderUtil::custom_orders_table_usage_is_enabled() ) { From 4c75a3600311fb1fcb058128db12536b470834cc Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 27 Feb 2023 20:06:51 +0530 Subject: [PATCH 47/49] Applied coding standards. --- plugins/woocommerce/src/Admin/API/Orders.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/woocommerce/src/Admin/API/Orders.php b/plugins/woocommerce/src/Admin/API/Orders.php index 303ec5d5a33..64138466a65 100644 --- a/plugins/woocommerce/src/Admin/API/Orders.php +++ b/plugins/woocommerce/src/Admin/API/Orders.php @@ -67,7 +67,8 @@ class Orders extends \WC_REST_Orders_Controller { /** * Helper method to allow searching by partial order number. - * @param int $number Partial order number match + * + * @param int $number Partial order number match. * @param array $args List of arguments for the request. * * @return array Modified args with partial order search included. @@ -79,6 +80,7 @@ class Orders extends \WC_REST_Orders_Controller { $limit = intval( $args['posts_per_page'] ); if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { $order_table_name = OrdersTableDataStore::get_orders_table_name(); + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orders_table_name is hardcoded. $order_ids = $wpdb->get_col( $wpdb->prepare( "SELECT id @@ -90,6 +92,7 @@ class Orders extends \WC_REST_Orders_Controller { $limit ) ); + // phpcs:enable } else { $order_ids = $wpdb->get_col( $wpdb->prepare( From 185b8ae252344f52eefec104dbcfa2b274f02c2b Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Wed, 1 Mar 2023 17:43:36 +0530 Subject: [PATCH 48/49] Use common method to mark HPOS tests as skipped. --- .../legacy/framework/class-wc-unit-test-case.php | 12 ++++++++++++ .../admin/class-wc-tests-admin-dashboard.php | 10 ++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php b/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php index a7f00cb42e7..488cea9e120 100644 --- a/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php +++ b/plugins/woocommerce/tests/legacy/framework/class-wc-unit-test-case.php @@ -7,6 +7,7 @@ use Automattic\WooCommerce\Proxies\LegacyProxy; use Automattic\WooCommerce\Testing\Tools\CodeHacking\CodeHacker; +use Automattic\WooCommerce\Utilities\OrderUtil; use PHPUnit\Framework\Constraint\IsType; /** @@ -388,4 +389,15 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase { $events = self::get_tracks_events( $event_name ); $this->assertEmpty( $events ); } + + /** + * Mark test skipped when HPOS is enabled. + * + * @param string $message Message to display when test is skipped. + */ + protected function skip_if_hpos_enabled( $message ) { + if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { + $this->markTestSkipped( $message ); + } + } } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php index 46d3d9972f2..535869c41b0 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/admin/class-wc-tests-admin-dashboard.php @@ -5,8 +5,6 @@ * @package WooCommerce\Tests\Admin */ -use Automattic\WooCommerce\Utilities\OrderUtil; - /** * Tests for the WC_Admin_Report class. */ @@ -39,9 +37,7 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case { * Test: get_status_widget */ public function test_status_widget() { - if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { - $this->markTestSkipped( 'We don\'t support legacy reports in HPOS.' ); - } + $this->skip_if_hpos_enabled( 'We don\'t support legacy reports on HPOS' ); wp_set_current_user( $this->user ); $order = WC_Helper_Order::create_order(); $order->set_status( 'completed' ); @@ -63,9 +59,7 @@ class WC_Tests_Admin_Dashboard extends WC_Unit_Test_Case { * Test: get_status_widget with woo admin disabled. */ public function test_status_widget_with_woo_admin_disabled() { - if ( OrderUtil::custom_orders_table_usage_is_enabled() ) { - $this->markTestSkipped( 'We don\'t support legacy reports in HPOS.' ); - } + $this->skip_if_hpos_enabled( 'We don\'t support legacy reports on HPOS' ); wp_set_current_user( $this->user ); $order = WC_Helper_Order::create_order(); $order->set_status( 'completed' ); From fb356b686e10f779fb7e6a50908eefe9b7dea045 Mon Sep 17 00:00:00 2001 From: Vedanshu Jain Date: Mon, 6 Mar 2023 17:21:23 +0530 Subject: [PATCH 49/49] Use simplified name for readibility. --- .../tests/php/includes/class-wc-order-factory-test.php | 10 ++++++---- .../DataStores/Orders/OrdersTableDataStoreTests.php | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php index 56cda5d51c8..22f4839dfa0 100644 --- a/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php +++ b/plugins/woocommerce/tests/php/includes/class-wc-order-factory-test.php @@ -1,5 +1,7 @@ cot_state = \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); - \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( false ); + OrderHelper::toggle_cot( false ); } /** @@ -31,15 +33,15 @@ class WC_Order_Factory_Test extends WC_Unit_Test_Case { public function tearDown(): void { parent::tearDown(); wp_cache_flush(); - \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::toggle_cot( $this->cot_state ); + OrderHelper::toggle_cot( $this->cot_state ); } /** * @testDox get_orders should be able to return multiple orders of different types. */ public function test_get_orders_with_multiple_order_type() { - $order1 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_wp_post_order(); - $order2 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_wp_post_order(); + $order1 = OrderHelper::create_complex_wp_post_order(); + $order2 = OrderHelper::create_complex_wp_post_order(); assert( $order1 > 0 ); assert( $order2 > 0 ); diff --git a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php index 04e70cc9c90..db284beec3e 100644 --- a/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php +++ b/plugins/woocommerce/tests/php/src/Internal/DataStores/Orders/OrdersTableDataStoreTests.php @@ -1869,7 +1869,7 @@ class OrdersTableDataStoreTests extends WC_Unit_Test_Case { */ public function test_legacy_getters_setters() { $this->toggle_cot( true ); - $order_id = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_complex_data_store_order( $this->sut ); + $order_id = OrderHelper::create_complex_data_store_order( $this->sut ); $order = wc_get_order( $order_id ); $this->switch_data_store( $order, $this->sut ); $bool_props = array(