From a4f7fcdfe327dfebd2a5c3054b587042e99703c0 Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 4 Feb 2019 10:49:58 +0800 Subject: [PATCH 01/19] Fix variation search autocompleter invalid route (https://github.com/woocommerce/woocommerce-admin/pull/1448) --- ...min-rest-product-variations-controller.php | 25 +++++++++++++++++++ .../includes/class-wc-admin-api-init.php | 13 ++++++++++ 2 files changed, 38 insertions(+) create mode 100644 plugins/woocommerce-admin/includes/api/class-wc-admin-rest-product-variations-controller.php diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-product-variations-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-product-variations-controller.php new file mode 100644 index 00000000000..30657a6c411 --- /dev/null +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-product-variations-controller.php @@ -0,0 +1,25 @@ +[\d]+)/variations'] ) + && isset( $endpoints['products/(?P[\d]+)/variations'][3] ) + && isset( $endpoints['products/(?P[\d]+)/variations'][2] ) + && $endpoints['products/(?P[\d]+)/variations'][2]['callback'][0] instanceof WC_Admin_REST_Product_Variations_Controller + && $endpoints['products/(?P[\d]+)/variations'][3]['callback'][0] instanceof WC_Admin_REST_Product_Variations_Controller + ) { + $endpoints['products/(?P[\d]+)/variations'][0] = $endpoints['products/(?P[\d]+)/variations'][2]; + $endpoints['products/(?P[\d]+)/variations'][1] = $endpoints['products/(?P[\d]+)/variations'][3]; + } + // Override /wc/v4/taxes. if ( isset( $endpoints['/wc/v4/taxes'] ) && isset( $endpoints['/wc/v4/taxes'][3] ) From 2c1f8c17c7ae70ff83c6ee3cd06f23b9f9bacaa2 Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 4 Feb 2019 10:50:22 +0800 Subject: [PATCH 02/19] Fix incorrect label async request paths (https://github.com/woocommerce/woocommerce-admin/pull/1447) --- .../client/lib/async-requests/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce-admin/client/lib/async-requests/index.js b/plugins/woocommerce-admin/client/lib/async-requests/index.js index 1e4597ad8e4..ea4a015a974 100644 --- a/plugins/woocommerce-admin/client/lib/async-requests/index.js +++ b/plugins/woocommerce-admin/client/lib/async-requests/index.js @@ -39,30 +39,30 @@ export function getRequestByIdString( path, handleData = identity ) { } export const getCategoryLabels = getRequestByIdString( - NAMESPACE + 'products/categories', + NAMESPACE + '/products/categories', category => ( { id: category.id, label: category.name, } ) ); -export const getCouponLabels = getRequestByIdString( NAMESPACE + 'coupons', coupon => ( { +export const getCouponLabels = getRequestByIdString( NAMESPACE + '/coupons', coupon => ( { id: coupon.id, label: coupon.code, } ) ); -export const getCustomerLabels = getRequestByIdString( NAMESPACE + 'customers', customer => ( { +export const getCustomerLabels = getRequestByIdString( NAMESPACE + '/customers', customer => ( { id: customer.id, label: customer.username, } ) ); -export const getProductLabels = getRequestByIdString( NAMESPACE + 'products', product => ( { +export const getProductLabels = getRequestByIdString( NAMESPACE + '/products', product => ( { id: product.id, label: product.name, } ) ); export const getVariationLabels = getRequestByIdString( - query => NAMESPACE + `products/${ query.products }/variations`, + query => NAMESPACE + `/products/${ query.products }/variations`, variation => { return { id: variation.id, From 17179d41ffb8a05c004474e30e9bfa156d6d5c0b Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 4 Feb 2019 10:52:29 +0800 Subject: [PATCH 03/19] Add order status tests and refund tests (https://github.com/woocommerce/woocommerce-admin/pull/1443) * Add default order status tests * Test querying an excluded status * Add tests for product line item refunds * Update status test method comment * Drop @since versioning from doc blocks --- .../class-wc-tests-reports-orders-stats.php | 153 +++++++++++++++++- .../class-wc-tests-reports-products.php | 70 ++++++++ 2 files changed, 221 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php index 9a0edb16df8..c15da4e8169 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php @@ -36,8 +36,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $refund = wc_create_refund( array( - 'amount' => 12, - 'order_id' => $order->get_id(), + 'amount' => 12, + 'order_id' => $order->get_id(), ) ); @@ -142,6 +142,155 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $this->assertEquals( $expected_stats, json_decode( json_encode( $query->get_data() ), true ) ); } + /** + * Test that querying statuses includes the default or query-specific statuses. + */ + public function test_populate_and_query_statuses() { + WC_Helper_Reports::reset_stats_dbs(); + + // Populate all of the data. + $product = new WC_Product_Simple(); + $product->set_name( 'Test Product' ); + $product->set_regular_price( 25 ); + $product->save(); + + $order_types = array( + array( + 'status' => 'refunded', + 'total' => 50, + ), + array( + 'status' => 'completed', + 'total' => 100, + ), + array( + 'status' => 'failed', + 'total' => 75, + ), + ); + + foreach ( $order_types as $order_type ) { + $order = WC_Helper_Order::create_order( 1, $product ); + $order->set_status( $order_type['status'] ); + $order->set_total( $order_type['total'] ); + $order->set_shipping_total( 0 ); + $order->set_cart_tax( 0 ); + $order->save(); + // Wait one second to avoid potentially ambiguous new/returning customer. + sleep( 1 ); + } + + $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); + + $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); + $end_time = date( 'Y-m-d H:59:59', $order->get_date_created()->getOffsetTimestamp() ); + + // Query default statuses that should not include excluded or refunded order statuses. + $args = array( + 'interval' => 'hour', + 'after' => $start_time, + 'before' => $end_time, + ); + $expected_stats = array( + 'totals' => array( + 'orders_count' => 1, + 'num_items_sold' => 4, + 'avg_items_per_order' => 4, + 'avg_order_value' => 100, + 'gross_revenue' => 100, + 'coupons' => 0, + 'refunds' => 0, + 'taxes' => 0, + 'shipping' => 0, + 'net_revenue' => 100, + 'num_returning_customers' => 0, + 'num_new_customers' => 1, + 'products' => 1, + ), + 'intervals' => array( + array( + 'interval' => date( 'Y-m-d H', $order->get_date_created()->getOffsetTimestamp() ), + 'date_start' => $start_time, + 'date_start_gmt' => $start_time, + 'date_end' => $end_time, + 'date_end_gmt' => $end_time, + 'subtotals' => array( + 'gross_revenue' => 100, + 'net_revenue' => 100, + 'coupons' => 0, + 'shipping' => 0, + 'taxes' => 0, + 'refunds' => 0, + 'orders_count' => 1, + 'num_items_sold' => 4, + 'avg_items_per_order' => 4, + 'avg_order_value' => 100, + 'num_returning_customers' => 0, + 'num_new_customers' => 1, + ), + ), + ), + 'total' => 1, + 'pages' => 1, + 'page_no' => 1, + ); + + $this->assertEquals( $expected_stats, json_decode( json_encode( $data_store->get_data( $args ) ), true ) ); + + // Query an excluded status which should still return orders with the queried status. + $args = array( + 'interval' => 'hour', + 'after' => $start_time, + 'before' => $end_time, + 'status_is' => array( 'failed' ), + ); + $expected_stats = array( + 'totals' => array( + 'orders_count' => 1, + 'num_items_sold' => 4, + 'avg_items_per_order' => 4, + 'avg_order_value' => 75, + 'gross_revenue' => 75, + 'coupons' => 0, + 'refunds' => 0, + 'taxes' => 0, + 'shipping' => 0, + 'net_revenue' => 75, + 'num_returning_customers' => 1, + 'num_new_customers' => 0, + 'products' => 1, + ), + 'intervals' => array( + array( + 'interval' => date( 'Y-m-d H', $order->get_date_created()->getOffsetTimestamp() ), + 'date_start' => $start_time, + 'date_start_gmt' => $start_time, + 'date_end' => $end_time, + 'date_end_gmt' => $end_time, + 'subtotals' => array( + 'gross_revenue' => 75, + 'net_revenue' => 75, + 'coupons' => 0, + 'shipping' => 0, + 'taxes' => 0, + 'refunds' => 0, + 'orders_count' => 1, + 'num_items_sold' => 4, + 'avg_items_per_order' => 4, + 'avg_order_value' => 75, + 'num_returning_customers' => 1, + 'num_new_customers' => 0, + ), + ), + ), + 'total' => 1, + 'pages' => 1, + 'page_no' => 1, + ); + + $this->assertEquals( $expected_stats, json_decode( json_encode( $data_store->get_data( $args ) ), true ) ); + } + /** * Test the calculations and querying works correctly for the case of multiple orders. */ diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php index a6591c0330b..0b21cada12e 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php @@ -249,4 +249,74 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { ); $this->assertEquals( $expected_data, $data ); } + + /** + * Tests that line item refunds are reflected in product stats. + */ + public function test_populate_and_refund() { + WC_Helper_Reports::reset_stats_dbs(); + + // Populate all of the data. + $product = new WC_Product_Simple(); + $product->set_name( 'Test Product' ); + $product->set_regular_price( 25 ); + $product->save(); + + $order = WC_Helper_Order::create_order( 1, $product ); + $order->set_status( 'completed' ); + $order->set_shipping_total( 10 ); + $order->set_discount_total( 20 ); + $order->set_discount_tax( 0 ); + $order->set_cart_tax( 5 ); + $order->set_shipping_tax( 2 ); + $order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax. + $order->save(); + + foreach ( $order->get_items() as $item_key => $item_values ) { + $item_data = $item_values->get_data(); + $refund = wc_create_refund( + array( + 'amount' => 12, + 'order_id' => $order->get_id(), + 'line_items' => array( + $item_data['id'] => array( + 'qty' => 1, + 'refund_total' => 10, + ), + ), + ) + ); + break; + } + + $data_store = new WC_Admin_Reports_Products_Data_Store(); + $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); + $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); + $args = array( + 'after' => $start_time, + 'before' => $end_time, + ); + + // Test retrieving the stats through the data store. + $data = $data_store->get_data( $args ); + $expected_data = (object) array( + 'total' => 1, + 'pages' => 1, + 'page_no' => 1, + 'data' => array( + 0 => array( + 'product_id' => $product->get_id(), + 'items_sold' => 3, + 'net_revenue' => 90.0, // $25 * 4 - $10 refund. + 'orders_count' => 1, + 'extended_info' => new ArrayObject(), + ), + ), + ); + $this->assertEquals( $expected_data, $data ); + + // Test retrieving the stats through the query class. + $query = new WC_Admin_Reports_Products_Query( $args ); + $this->assertEquals( $expected_data, $query->get_data() ); + } } From fb0d71f11758cd11ca3b08d2d6267b45eb9fe108 Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 4 Feb 2019 10:55:06 +0800 Subject: [PATCH 04/19] Update page query to 1 when base query is changed (https://github.com/woocommerce/woocommerce-admin/pull/1444) * Update page query to 1 when base query is changed * Use history replace instead of updating query --- .../client/layout/controller.js | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce-admin/client/layout/controller.js b/plugins/woocommerce-admin/client/layout/controller.js index d9960efd0a8..728e5186622 100644 --- a/plugins/woocommerce-admin/client/layout/controller.js +++ b/plugins/woocommerce-admin/client/layout/controller.js @@ -4,12 +4,12 @@ */ import { Component, createElement } from '@wordpress/element'; import { parse } from 'qs'; -import { find, last } from 'lodash'; +import { find, last, isEqual } from 'lodash'; /** * WooCommerce dependencies */ -import { getPersistedQuery, stringifyQuery } from '@woocommerce/navigation'; +import { getNewPath, getPersistedQuery, history, stringifyQuery } from '@woocommerce/navigation'; /** * Internal dependencies @@ -64,11 +64,35 @@ const getPages = () => { }; class Controller extends Component { + componentDidUpdate( prevProps ) { + const prevQuery = this.getQuery( prevProps.location.search ); + const prevBaseQuery = this.getBaseQuery( prevProps.location.search ); + const baseQuery = this.getBaseQuery( this.props.location.search ); + + if ( prevQuery.page > 1 && ! isEqual( prevBaseQuery, baseQuery ) ) { + history.replace( getNewPath( { page: 1 } ) ); + } + } + + getQuery( searchString ) { + if ( ! searchString ) { + return {}; + } + + const search = searchString.substring( 1 ); + return parse( search ); + } + + getBaseQuery( searchString ) { + const query = this.getQuery( searchString ); + delete query.page; + return query; + } + render() { // Pass URL parameters (example :report -> params.report) and query string parameters const { path, url, params } = this.props.match; - const search = this.props.location.search.substring( 1 ); - const query = parse( search ); + const query = this.getQuery( this.props.location.search ); const page = find( getPages(), { path } ); window.wpNavMenuUrlUpdate( page, query ); window.wpNavMenuClassChange( page ); From 9dd4c10d7dc314329622c0444b0668fa8114e32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 4 Feb 2019 09:51:29 +0100 Subject: [PATCH 05/19] Fix autocompleters in customers and taxes report (https://github.com/woocommerce/woocommerce-admin/pull/1458) --- .../client/analytics/components/leaderboard/test/index.js | 2 +- .../client/analytics/report/customers/config.js | 4 ++-- .../woocommerce-admin/client/analytics/report/taxes/config.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce-admin/client/analytics/components/leaderboard/test/index.js b/plugins/woocommerce-admin/client/analytics/components/leaderboard/test/index.js index 1cfc9e5c699..49cda5b6c5b 100644 --- a/plugins/woocommerce-admin/client/analytics/components/leaderboard/test/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/leaderboard/test/index.js @@ -103,7 +103,7 @@ describe( 'Leaderboard', () => { ); const leaderboard = leaderboardWrapper.root.findByType( Leaderboard ); - const endpoint = NAMESPACE + 'reports/products'; + const endpoint = NAMESPACE + '/reports/products'; const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 }; expect( getReportStatsMock.mock.calls[ 0 ][ 1 ] ).toBe( endpoint ); diff --git a/plugins/woocommerce-admin/client/analytics/report/customers/config.js b/plugins/woocommerce-admin/client/analytics/report/customers/config.js index bdcd9827930..fe8bdc82b42 100644 --- a/plugins/woocommerce-admin/client/analytics/report/customers/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/customers/config.js @@ -57,7 +57,7 @@ export const advancedFilters = { input: { component: 'Search', type: 'customers', - getLabels: getRequestByIdString( NAMESPACE + 'customers', customer => ( { + getLabels: getRequestByIdString( NAMESPACE + '/customers', customer => ( { id: customer.id, label: [ customer.first_name, customer.last_name ].filter( Boolean ).join( ' ' ), } ) ), @@ -157,7 +157,7 @@ export const advancedFilters = { input: { component: 'Search', type: 'emails', - getLabels: getRequestByIdString( NAMESPACE + 'customers', customer => ( { + getLabels: getRequestByIdString( NAMESPACE + '/customers', customer => ( { id: customer.id, label: customer.email, } ) ), diff --git a/plugins/woocommerce-admin/client/analytics/report/taxes/config.js b/plugins/woocommerce-admin/client/analytics/report/taxes/config.js index 4eaf222afae..b9a978a6179 100644 --- a/plugins/woocommerce-admin/client/analytics/report/taxes/config.js +++ b/plugins/woocommerce-admin/client/analytics/report/taxes/config.js @@ -49,7 +49,7 @@ export const filters = [ settings: { type: 'taxes', param: 'taxes', - getLabels: getRequestByIdString( NAMESPACE + 'taxes', tax => ( { + getLabels: getRequestByIdString( NAMESPACE + '/taxes', tax => ( { id: tax.id, label: getTaxCode( tax ), } ) ), From 0d4e42def0df4deef7487dbc2800a1a2d63a45f8 Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Mon, 4 Feb 2019 18:39:33 +0800 Subject: [PATCH 06/19] Add segments to expected response in order stats (https://github.com/woocommerce/woocommerce-admin/pull/1466) --- .../tests/reports/class-wc-tests-reports-orders-stats.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php index c15da4e8169..91e6afbebc8 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php @@ -206,6 +206,7 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'num_returning_customers' => 0, 'num_new_customers' => 1, 'products' => 1, + 'segments' => array(), ), 'intervals' => array( array( @@ -227,6 +228,7 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'avg_order_value' => 100, 'num_returning_customers' => 0, 'num_new_customers' => 1, + 'segments' => array(), ), ), ), @@ -259,6 +261,7 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'num_returning_customers' => 1, 'num_new_customers' => 0, 'products' => 1, + 'segments' => array(), ), 'intervals' => array( array( @@ -280,6 +283,7 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'avg_order_value' => 75, 'num_returning_customers' => 1, 'num_new_customers' => 0, + 'segments' => array(), ), ), ), From 9b1f6999aa95ca2d3338a0c318ddc698484103bb Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Tue, 29 Jan 2019 14:34:42 -0700 Subject: [PATCH 07/19] Add action argument support when scheduling dependent actions. --- .../includes/class-wc-admin-api-init.php | 11 ++++++----- plugins/woocommerce-admin/tests/batch-queue.php | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php index 4ce7f57837a..f2d68e65ab4 100644 --- a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php +++ b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php @@ -68,7 +68,7 @@ class WC_Admin_Api_Init { // Initialize scheduled action handlers. add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 3 ); - add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 2 ); + add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 3 ); add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ) ); add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ) ); add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ) ); @@ -433,7 +433,7 @@ class WC_Admin_Api_Init { // so that the orders can be associated with the `customer_id` column. self::customer_lookup_batch_init(); // Queue orders lookup to occur after customers lookup generation is done. - self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, self::CUSTOMERS_BATCH_ACTION ); + self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, array(), self::CUSTOMERS_BATCH_ACTION ); } /** @@ -592,9 +592,10 @@ class WC_Admin_Api_Init { * Queue an action to run after another. * * @param string $action Action to run after prerequisite. + * @param array $action_args Action arguments. * @param string $prerequisite_action Prerequisite action. */ - public static function queue_dependent_action( $action, $prerequisite_action ) { + public static function queue_dependent_action( $action, $action_args, $prerequisite_action ) { $blocking_jobs = self::queue()->search( array( 'status' => 'pending', @@ -613,10 +614,10 @@ class WC_Admin_Api_Init { self::queue()->schedule_single( $after_blocking_job, self::QUEUE_DEPEDENT_ACTION, - array( $action, $prerequisite_action ) + array( $action, $action_args, $prerequisite_action ) ); } else { - self::queue()->schedule_single( time() + 5, $action ); + self::queue()->schedule_single( time() + 5, $action, $action_args ); } } diff --git a/plugins/woocommerce-admin/tests/batch-queue.php b/plugins/woocommerce-admin/tests/batch-queue.php index d8711afdc60..fba0fa4f294 100644 --- a/plugins/woocommerce-admin/tests/batch-queue.php +++ b/plugins/woocommerce-admin/tests/batch-queue.php @@ -136,7 +136,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case { // insert a blocking job. WC_Admin_Api_Init::queue()->schedule_single( time(), 'blocking_job', array( 'stuff' ) ); // queue an action that depends on blocking job. - WC_Admin_Api_Init::queue_dependent_action( 'dependent_action', 'blocking_job' ); + WC_Admin_Api_Init::queue_dependent_action( 'dependent_action', array(), 'blocking_job' ); // verify that the action was properly blocked. $this->assertEmpty( WC_Admin_Api_Init::queue()->search( @@ -157,7 +157,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case { ); // queue an action that isn't blocked. - WC_Admin_Api_Init::queue_dependent_action( 'another_dependent_action', 'nonexistant_blocking_job' ); + WC_Admin_Api_Init::queue_dependent_action( 'another_dependent_action', array(), 'nonexistant_blocking_job' ); // verify that the dependent action was queued. $this->assertCount( 1, From 9f3c95ae636382fef716e58631495689e612b98d Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Tue, 29 Jan 2019 14:36:02 -0700 Subject: [PATCH 08/19] Rework lookup table data store sync methods to return a meaningful status. --- ...lass-wc-admin-reports-coupons-data-store.php | 12 +++++++++--- ...wc-admin-reports-orders-stats-data-store.php | 15 +++++++++------ ...ass-wc-admin-reports-products-data-store.php | 17 ++++++++++++----- .../class-wc-admin-reports-taxes-data-store.php | 15 +++++++++++---- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php index 934ad18fcc6..39b11fcdb10 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php @@ -315,19 +315,21 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im * * @since 3.5.0 * @param int $order_id Order ID. - * @return void + * @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success. */ public static function sync_order_coupons( $order_id ) { global $wpdb; $order = wc_get_order( $order_id ); if ( ! $order ) { - return; + return -1; } $coupon_items = $order->get_items( 'coupon' ); + $num_updated = 0; + foreach ( $coupon_items as $coupon_item ) { - $wpdb->replace( + $result = $wpdb->replace( $wpdb->prefix . self::TABLE_NAME, array( 'order_id' => $order_id, @@ -342,7 +344,11 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im '%s', ) ); + + $num_updated += intval( $result ); } + + return ( count( $coupon_items ) === $num_updated ); } } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php index 5ea9cd13fe8..96c8350cfda 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php @@ -360,18 +360,19 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto * Add order information to the lookup table when orders are created or modified. * * @param int $post_id Post ID. + * @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success. */ public static function sync_order( $post_id ) { if ( 'shop_order' !== get_post_type( $post_id ) ) { - return; + return -1; } $order = wc_get_order( $post_id ); if ( ! $order ) { - return; + return -1; } - self::update( $order ); + return self::update( $order ); } /** @@ -388,14 +389,14 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto * Update the database with stats data. * * @param WC_Order $order Order to update row for. - * @return int|bool|null Number or rows modified or false on failure. + * @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success. */ public static function update( $order ) { global $wpdb; $table_name = $wpdb->prefix . self::TABLE_NAME; if ( ! $order->get_id() || ! $order->get_date_created() ) { - return false; + return -1; } $data = array( @@ -450,7 +451,9 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto } // Update or add the information to the DB. - return $wpdb->replace( $table_name, $data, $format ); + $result = $wpdb->replace( $table_name, $data, $format ); + + return ( 1 === $result ); } /** diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php index e1c0ce9d89e..6811a778d1e 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php @@ -319,7 +319,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i * * @since 3.5.0 * @param int $order_id Order ID. - * @return void + * @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success. */ public static function sync_order_products( $order_id ) { global $wpdb; @@ -328,10 +328,13 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i // This hook gets called on refunds as well, so return early to avoid errors. if ( ! $order || 'shop_order_refund' === $order->get_type() ) { - return; + return -1; } - foreach ( $order->get_items() as $order_item ) { + $order_items = $order->get_items(); + $num_updated = 0; + + foreach ( $order_items as $order_item ) { $order_item_id = $order_item->get_id(); $quantity_refunded = $order->get_item_quantity_refunded( $order_item ); $amount_refunded = $order->get_item_amount_refunded( $order_item ); @@ -355,13 +358,13 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i $net_revenue = $order_item->get_subtotal( 'edit' ) - $amount_refunded; if ( $quantity_refunded >= $order_item->get_quantity( 'edit' ) ) { - $wpdb->delete( + $result = $wpdb->delete( $wpdb->prefix . self::TABLE_NAME, array( 'order_item_id' => $order_item_id ), array( '%d' ) ); // WPCS: cache ok, DB call ok. } else { - $wpdb->replace( + $result = $wpdb->replace( $wpdb->prefix . self::TABLE_NAME, array( 'order_item_id' => $order_item_id, @@ -398,7 +401,11 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i ) ); // WPCS: cache ok, DB call ok, unprepared SQL ok. } + + $num_updated += intval( $result ); } + + return ( count( $order_items ) === $num_updated ); } } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php index f5323f7536d..6cd5379de53 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php @@ -255,17 +255,20 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl * Create or update an entry in the wc_order_tax_lookup table for an order. * * @param int $order_id Order ID. - * @return void + * @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success. */ public static function sync_order_taxes( $order_id ) { global $wpdb; $order = wc_get_order( $order_id ); if ( ! $order ) { - return; + return -1; } - foreach ( $order->get_items( 'tax' ) as $tax_item ) { - $wpdb->replace( + $tax_items = $order->get_items( 'tax' ); + $num_updated = 0; + + foreach ( $tax_items as $tax_item ) { + $result = $wpdb->replace( $wpdb->prefix . self::TABLE_NAME, array( 'order_id' => $order->get_id(), @@ -284,7 +287,11 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl '%f', ) ); + + $num_updated += intval( $result ); } + + return ( count( $tax_items ) === $num_updated ); } } From 11d18a8b5b60539fbe750c2797182fe465a04181 Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Tue, 29 Jan 2019 14:37:59 -0700 Subject: [PATCH 09/19] Queue individual order syncing instead of handling immediately. --- .../includes/class-wc-admin-api-init.php | 100 ++++++++++++++---- ...ss-wc-admin-reports-coupons-data-store.php | 9 -- ...-admin-reports-orders-stats-data-store.php | 4 - ...s-wc-admin-reports-products-data-store.php | 9 -- ...lass-wc-admin-reports-taxes-data-store.php | 9 -- 5 files changed, 80 insertions(+), 51 deletions(-) diff --git a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php index f2d68e65ab4..af4929c2ac3 100644 --- a/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php +++ b/plugins/woocommerce-admin/includes/class-wc-admin-api-init.php @@ -37,6 +37,11 @@ class WC_Admin_Api_Init { */ const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init'; + /** + * Action hook for processing a batch of orders. + */ + const SINGLE_ORDER_ACTION = 'wc-admin_process_order'; + /** * Queue instance. * @@ -59,12 +64,8 @@ class WC_Admin_Api_Init { add_filter( 'rest_endpoints', array( 'WC_Admin_Api_Init', 'filter_rest_endpoints' ), 10, 1 ); add_filter( 'woocommerce_debug_tools', array( 'WC_Admin_Api_Init', 'add_regenerate_tool' ) ); - // Initialize Orders data store class's static vars. - add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'orders_data_store_init' ), 20 ); - // Initialize Customers Report data store sync hooks. - // Note: we need to hook in before `wc_current_user_is_active`. - // See: https://github.com/woocommerce/woocommerce/blob/942615101ba00c939c107c3a4820c3d466864872/includes/wc-user-functions.php#L749. - add_action( 'wp_loaded', array( 'WC_Admin_Api_Init', 'customers_report_data_store_init' ) ); + // Initialize syncing hooks. + add_action( 'wp_loaded', array( __CLASS__, 'orders_lookup_update_init' ) ); // Initialize scheduled action handlers. add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 3 ); @@ -72,6 +73,7 @@ class WC_Admin_Api_Init { add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ) ); add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ) ); add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ) ); + add_action( self::SINGLE_ORDER_ACTION, array( __CLASS__, 'orders_lookup_process_order' ) ); // Add currency symbol to orders endpoint response. add_filter( 'woocommerce_rest_prepare_shop_order_object', array( __CLASS__, 'add_currency_symbol_to_order_response' ) ); @@ -457,16 +459,58 @@ class WC_Admin_Api_Init { } /** - * Init orders data store. + * Schedule an action to process a single Order. + * + * @param int $order_id Order ID. + * @return void */ - public static function orders_data_store_init() { + public static function schedule_single_order_process( $order_id ) { + if ( 'shop_order' !== get_post_type( $order_id ) ) { + return; + } + + // This can get called multiple times for a single order, so we look + // for existing pending jobs for the same order to avoid duplicating efforts. + $existing_jobs = self::queue()->search( + array( + 'status' => 'pending', + 'per_page' => 1, + 'claimed' => false, + 'search' => "[{$order_id}]", + ) + ); + + if ( $existing_jobs ) { + $existing_job = current( $existing_jobs ); + + // Bail out if there's a pending single order action, or a pending dependent action. + if ( + ( self::SINGLE_ORDER_ACTION === $existing_job->get_hook() ) || + ( + self::QUEUE_DEPEDENT_ACTION === $existing_job->get_hook() && + in_array( self::SINGLE_ORDER_ACTION, $existing_job->get_args() ) + ) + ) { + return; + } + } + + // We want to ensure that customer lookup updates are scheduled before order updates. + self::queue_dependent_action( self::SINGLE_ORDER_ACTION, array( $order_id ), self::CUSTOMERS_BATCH_ACTION ); + } + + /** + * Attach order lookup update hooks. + */ + public static function orders_lookup_update_init() { // Activate WC_Order extension. WC_Admin_Order::add_filters(); - // Initialize data stores. + + add_action( 'save_post_shop_order', array( __CLASS__, 'schedule_single_order_process' ) ); + add_action( 'woocommerce_order_refunded', array( __CLASS__, 'schedule_single_order_process' ) ); + WC_Admin_Reports_Orders_Stats_Data_Store::init(); - WC_Admin_Reports_Products_Data_Store::init(); - WC_Admin_Reports_Taxes_Data_Store::init(); - WC_Admin_Reports_Coupons_Data_Store::init(); + WC_Admin_Reports_Customers_Data_Store::init(); } /** @@ -512,19 +556,35 @@ class WC_Admin_Api_Init { $order_ids = $order_query->get_orders(); foreach ( $order_ids as $order_id ) { - // @todo: schedule single order update if this fails? - WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ); - WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ); - WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id ); - WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id ); + self::orders_lookup_process_order( $order_id ); } } /** - * Init customers report data store. + * Process a single order to update lookup tables for. + * If an error is encountered in one of the updates, a retry action is scheduled. + * + * @param int $order_id Order ID. + * @return void */ - public static function customers_report_data_store_init() { - WC_Admin_Reports_Customers_Data_Store::init(); + public static function orders_lookup_process_order( $order_id ) { + $result = array_sum( + array( + WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ), + WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ), + WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id ), + WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id ), + ) + ); + + // If all updates were either skipped or successful, we're done. + // The update methods return -1 for skip, or a boolean success indicator. + if ( 4 === absint( $result ) ) { + return; + } + + // Otherwise assume an error occurred and reschedule. + self::schedule_single_order_process( $order_id ); } /** diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php index 39b11fcdb10..337f12cdbc7 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-coupons-data-store.php @@ -51,15 +51,6 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im $this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] ); } - /** - * Set up all the hooks for maintaining and populating table data. - */ - public static function init() { - add_action( 'save_post', array( __CLASS__, 'sync_order_coupons' ) ); - add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_coupons' ) ); - add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_coupons' ) ); - } - /** * Returns comma separated ids of included coupons, based on query arguments from the user. * diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php index 96c8350cfda..e3efe7e9ef9 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-orders-stats-data-store.php @@ -73,10 +73,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto * Set up all the hooks for maintaining and populating table data. */ public static function init() { - add_action( 'save_post', array( __CLASS__, 'sync_order' ) ); - // @todo: this is required as order update skips save_post. - add_action( 'clean_post_cache', array( __CLASS__, 'sync_order' ) ); - add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order' ) ); add_action( 'woocommerce_refund_deleted', array( __CLASS__, 'sync_on_refund_delete' ), 10, 2 ); add_action( 'delete_post', array( __CLASS__, 'delete_order' ) ); } diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php index 6811a778d1e..0880d1a025c 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-products-data-store.php @@ -82,15 +82,6 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i $this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] ); } - /** - * Set up all the hooks for maintaining and populating table data. - */ - public static function init() { - add_action( 'save_post', array( __CLASS__, 'sync_order_products' ) ); - add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_products' ) ); - add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_products' ) ); - } - /** * Fills ORDER BY clause of SQL request based on user supplied parameters. * diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php index 6cd5379de53..86fa771bc01 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-taxes-data-store.php @@ -66,15 +66,6 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl $this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] ); } - /** - * Set up all the hooks for maintaining and populating table data. - */ - public static function init() { - add_action( 'save_post', array( __CLASS__, 'sync_order_taxes' ) ); - add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_taxes' ) ); - add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_taxes' ) ); - } - /** * Updates the database query with parameters used for Taxes report: categories and order status. * From 21572698d87d15897e07f2999b391fed476b4411 Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Wed, 30 Jan 2019 09:59:45 -0700 Subject: [PATCH 10/19] Fix unit tests that rely on queued data updates. --- .../tests/api/reports-categories.php | 2 ++ .../tests/api/reports-coupons-stats.php | 2 ++ .../tests/api/reports-coupons.php | 2 ++ .../tests/api/reports-customers-stats.php | 2 ++ .../tests/api/reports-customers.php | 2 ++ .../tests/api/reports-orders.php | 2 ++ .../api/reports-performance-indicators.php | 2 ++ .../tests/api/reports-products-stats.php | 2 ++ .../tests/api/reports-products.php | 2 ++ .../tests/api/reports-taxes.php | 2 ++ .../tests/api/reports-variations.php | 2 ++ .../woocommerce-admin/tests/batch-queue.php | 4 +-- plugins/woocommerce-admin/tests/bootstrap.php | 1 + .../helpers/class-wc-helper-queue.php | 32 +++++++++++++++++++ .../class-wc-tests-reports-coupons-stats.php | 2 ++ .../class-wc-tests-reports-coupons.php | 2 ++ .../class-wc-tests-reports-orders-stats.php | 6 ++++ .../class-wc-tests-reports-products.php | 7 ++++ .../class-wc-tests-reports-revenue-stats.php | 2 ++ .../class-wc-tests-reports-variations.php | 4 +++ 20 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 plugins/woocommerce-admin/tests/framework/helpers/class-wc-helper-queue.php diff --git a/plugins/woocommerce-admin/tests/api/reports-categories.php b/plugins/woocommerce-admin/tests/api/reports-categories.php index 13eb432ec33..ac14cea7fac 100644 --- a/plugins/woocommerce-admin/tests/api/reports-categories.php +++ b/plugins/woocommerce-admin/tests/api/reports-categories.php @@ -64,6 +64,8 @@ class WC_Tests_API_Reports_Categories extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); // $25 x 4. $order->save(); + WC_Helper_Queue::run_all_pending(); + $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' ); $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); diff --git a/plugins/woocommerce-admin/tests/api/reports-coupons-stats.php b/plugins/woocommerce-admin/tests/api/reports-coupons-stats.php index eb09fa697f6..a17f10a37db 100644 --- a/plugins/woocommerce-admin/tests/api/reports-coupons-stats.php +++ b/plugins/woocommerce-admin/tests/api/reports-coupons-stats.php @@ -87,6 +87,8 @@ class WC_Tests_API_Reports_Coupons_Stats extends WC_REST_Unit_Test_Case { $order_2c->set_date_created( $time ); $order_2c->save(); + WC_Helper_Queue::run_all_pending(); + $request = new WP_REST_Request( 'GET', $this->endpoint ); $request->set_query_params( array( diff --git a/plugins/woocommerce-admin/tests/api/reports-coupons.php b/plugins/woocommerce-admin/tests/api/reports-coupons.php index ad7d3b51aa4..36b1edda328 100644 --- a/plugins/woocommerce-admin/tests/api/reports-coupons.php +++ b/plugins/woocommerce-admin/tests/api/reports-coupons.php @@ -82,6 +82,8 @@ class WC_Tests_API_Reports_Coupons extends WC_REST_Unit_Test_Case { $order_2c->calculate_totals(); $order_2c->save(); + WC_Helper_Queue::run_all_pending(); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); $coupon_reports = $response->get_data(); diff --git a/plugins/woocommerce-admin/tests/api/reports-customers-stats.php b/plugins/woocommerce-admin/tests/api/reports-customers-stats.php index 316cf2613b8..367f5c642e4 100644 --- a/plugins/woocommerce-admin/tests/api/reports-customers-stats.php +++ b/plugins/woocommerce-admin/tests/api/reports-customers-stats.php @@ -126,6 +126,8 @@ class WC_Tests_API_Reports_Customers_Stats extends WC_REST_Unit_Test_Case { $order->set_total( 9.12 ); $order->save(); + WC_Helper_Queue::run_all_pending(); + $request = new WP_REST_Request( 'GET', $this->endpoint ); $response = $this->server->dispatch( $request ); $reports = $response->get_data(); diff --git a/plugins/woocommerce-admin/tests/api/reports-customers.php b/plugins/woocommerce-admin/tests/api/reports-customers.php index 781050fe3f1..f2386a45201 100644 --- a/plugins/woocommerce-admin/tests/api/reports-customers.php +++ b/plugins/woocommerce-admin/tests/api/reports-customers.php @@ -134,6 +134,8 @@ class WC_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); $order->save(); + WC_Helper_Queue::run_all_pending(); + $request = new WP_REST_Request( 'GET', $this->endpoint ); $request->set_query_params( array( diff --git a/plugins/woocommerce-admin/tests/api/reports-orders.php b/plugins/woocommerce-admin/tests/api/reports-orders.php index c625473eef4..114d368999f 100644 --- a/plugins/woocommerce-admin/tests/api/reports-orders.php +++ b/plugins/woocommerce-admin/tests/api/reports-orders.php @@ -67,6 +67,8 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); // $25 x 4. $order->save(); + WC_Helper_Queue::run_all_pending(); + $expected_customer_id = WC_Admin_Reports_Customers_Data_Store::get_customer_id_by_user_id( 1 ); $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); diff --git a/plugins/woocommerce-admin/tests/api/reports-performance-indicators.php b/plugins/woocommerce-admin/tests/api/reports-performance-indicators.php index 6821d615aba..119f8e7a015 100644 --- a/plugins/woocommerce-admin/tests/api/reports-performance-indicators.php +++ b/plugins/woocommerce-admin/tests/api/reports-performance-indicators.php @@ -84,6 +84,8 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case $object->set_user_ip_address( '1.2.3.4' ); $object->save(); + WC_Helper_Queue::run_all_pending(); + $time = time(); $request = new WP_REST_Request( 'GET', $this->endpoint ); $request->set_query_params( diff --git a/plugins/woocommerce-admin/tests/api/reports-products-stats.php b/plugins/woocommerce-admin/tests/api/reports-products-stats.php index 29825af677d..aab71f9c9df 100644 --- a/plugins/woocommerce-admin/tests/api/reports-products-stats.php +++ b/plugins/woocommerce-admin/tests/api/reports-products-stats.php @@ -71,6 +71,8 @@ class WC_Tests_API_Reports_Products_Stats extends WC_REST_Unit_Test_Case { $order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax. $order->save(); + WC_Helper_Queue::run_all_pending(); + $request = new WP_REST_Request( 'GET', $this->endpoint ); $request->set_query_params( array( diff --git a/plugins/woocommerce-admin/tests/api/reports-products.php b/plugins/woocommerce-admin/tests/api/reports-products.php index 9e7ada0f358..b8912503522 100644 --- a/plugins/woocommerce-admin/tests/api/reports-products.php +++ b/plugins/woocommerce-admin/tests/api/reports-products.php @@ -67,6 +67,8 @@ class WC_Tests_API_Reports_Products extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); // $25 x 4. $order->save(); + WC_Helper_Queue::run_all_pending(); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); $reports = $response->get_data(); diff --git a/plugins/woocommerce-admin/tests/api/reports-taxes.php b/plugins/woocommerce-admin/tests/api/reports-taxes.php index 31eda8216d9..217a2a4b77d 100644 --- a/plugins/woocommerce-admin/tests/api/reports-taxes.php +++ b/plugins/woocommerce-admin/tests/api/reports-taxes.php @@ -91,6 +91,8 @@ class WC_Tests_API_Reports_Taxes extends WC_REST_Unit_Test_Case { ) ); + WC_Helper_Queue::run_all_pending(); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); $reports = $response->get_data(); diff --git a/plugins/woocommerce-admin/tests/api/reports-variations.php b/plugins/woocommerce-admin/tests/api/reports-variations.php index 861e358e8c1..70e4f126591 100644 --- a/plugins/woocommerce-admin/tests/api/reports-variations.php +++ b/plugins/woocommerce-admin/tests/api/reports-variations.php @@ -65,6 +65,8 @@ class WC_Tests_API_Reports_Variations extends WC_REST_Unit_Test_Case { $order->set_total( 100 ); // $25 x 4. $order->save(); + WC_Helper_Queue::run_all_pending(); + $response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) ); $reports = $response->get_data(); diff --git a/plugins/woocommerce-admin/tests/batch-queue.php b/plugins/woocommerce-admin/tests/batch-queue.php index fba0fa4f294..afb3079ab4f 100644 --- a/plugins/woocommerce-admin/tests/batch-queue.php +++ b/plugins/woocommerce-admin/tests/batch-queue.php @@ -151,7 +151,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case { WC_Admin_Api_Init::queue()->search( array( 'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION, - 'args' => array( 'dependent_action', 'blocking_job' ), + 'args' => array( 'dependent_action', array(), 'blocking_job' ), ) ) ); @@ -172,7 +172,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case { WC_Admin_Api_Init::queue()->search( array( 'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION, - 'args' => array( 'another_dependent_action', 'nonexistant_blocking_job' ), + 'args' => array( 'another_dependent_action', array(), 'nonexistant_blocking_job' ), ) ) ); diff --git a/plugins/woocommerce-admin/tests/bootstrap.php b/plugins/woocommerce-admin/tests/bootstrap.php index 55caa41ce7d..0b2ebe86311 100755 --- a/plugins/woocommerce-admin/tests/bootstrap.php +++ b/plugins/woocommerce-admin/tests/bootstrap.php @@ -123,3 +123,4 @@ wc_test_includes(); require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-reports.php'; require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-admin-notes.php'; require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-test-action-queue.php'; +require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-queue.php'; diff --git a/plugins/woocommerce-admin/tests/framework/helpers/class-wc-helper-queue.php b/plugins/woocommerce-admin/tests/framework/helpers/class-wc-helper-queue.php new file mode 100644 index 00000000000..57b5c779c71 --- /dev/null +++ b/plugins/woocommerce-admin/tests/framework/helpers/class-wc-helper-queue.php @@ -0,0 +1,32 @@ +queue()->search( + array( + 'per_page' => -1, + 'status' => 'pending', + 'claimed' => false, + ) + ); + + foreach ( $jobs as $job ) { + $job->execute(); + } + } +} diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons-stats.php index e130bfb0c6a..2c6de71d4ae 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons-stats.php @@ -54,6 +54,8 @@ class WC_Tests_Reports_Coupons_Stats extends WC_Unit_Test_Case { $order_2c->calculate_totals(); $order_2c->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Coupons_Stats_Data_Store(); $start_time = date( 'Y-m-d 00:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d 23:59:59', $order->get_date_created()->getOffsetTimestamp() ); diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons.php index aeebb325518..58ac90c541d 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-coupons.php @@ -54,6 +54,8 @@ class WC_Tests_Reports_Coupons extends WC_Unit_Test_Case { $order_2c->calculate_totals(); $order_2c->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Coupons_Data_Store(); $start_time = date( 'Y-m-d 00:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d 23:59:59', $order->get_date_created()->getOffsetTimestamp() ); diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php index 91e6afbebc8..c48ef64cdb7 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php @@ -41,6 +41,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { ) ); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); @@ -483,6 +485,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { } } + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); // Tests for before & after set to current hour. @@ -1697,6 +1701,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $returning_order->set_date_created( $order_1_time + 1 ); // This is guaranteed to belong to the same hour by the adjustment to $order_1_time. $returning_order->save(); + WC_Helper_Queue::run_all_pending(); + $query_args = array( 'after' => $current_hour_start->format( WC_Admin_Reports_Interval::$sql_datetime_format ), // I don't think this makes sense.... date( 'Y-m-d H:i:s', $orders[0]->get_date_created()->getOffsetTimestamp() + 1 ), // Date after initial order to get a returning customer. 'before' => $current_hour_end->format( WC_Admin_Reports_Interval::$sql_datetime_format ), diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php index 0b21cada12e..95ab0d3dff1 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php @@ -38,6 +38,8 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { $order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax. $order->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Products_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); @@ -113,6 +115,8 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { $order_2->set_date_created( $date_created_2 ); $order_2->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Products_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order_2->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); @@ -211,6 +215,9 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { $order->set_shipping_tax( 2 ); $order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax. $order->save(); + + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Products_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-revenue-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-revenue-stats.php index fa74b3b9d22..a830010ab97 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-revenue-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-revenue-stats.php @@ -37,6 +37,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case { $order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax. $order->save(); + WC_Helper_Queue::run_all_pending(); + // /reports/revenue/stats is mapped to Orders_Data_Store. $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-variations.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-variations.php index 082e8d6e307..fd44d4e957f 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-variations.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-variations.php @@ -39,6 +39,8 @@ class WC_Tests_Reports_Variations extends WC_Unit_Test_Case { $order->set_status( 'completed' ); $order->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Variations_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); @@ -106,6 +108,8 @@ class WC_Tests_Reports_Variations extends WC_Unit_Test_Case { $order->set_status( 'completed' ); $order->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Variations_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); From bebe1bdead107e7ae5514c93d774b7c11fdaffed Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Thu, 31 Jan 2019 13:06:40 -0700 Subject: [PATCH 11/19] Add test for scheduling a retry job when order syncing fails. --- plugins/woocommerce-admin/tests/api-init.php | 85 ++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 plugins/woocommerce-admin/tests/api-init.php diff --git a/plugins/woocommerce-admin/tests/api-init.php b/plugins/woocommerce-admin/tests/api-init.php new file mode 100644 index 00000000000..5e196af6961 --- /dev/null +++ b/plugins/woocommerce-admin/tests/api-init.php @@ -0,0 +1,85 @@ +queue = new WC_Admin_Test_Action_Queue(); + WC_Admin_Api_Init::set_queue( $this->queue ); + } + + /** + * Tear down. + */ + public function tearDown() { + parent::tearDown(); + WC_Admin_Api_Init::set_queue( null ); + $this->queue->actions = array(); + } + + /** + * Cause a failure when updating order stats for the test order, without deleting it. + * + * @param string $query Query. + * @return string + */ + public function filter_order_query( $query ) { + if ( + 0 === strpos( $query, 'REPLACE INTO' ) && + false !== strpos( $query, WC_Admin_Reports_Orders_Stats_Data_Store::TABLE_NAME ) + ) { + remove_filter( 'query', array( $this, 'filter_order_query' ) ); + return 'THIS WONT MATCH'; + } + + return $query; + } + + /** + * Test that a retry job is scheduled for a failed sync. + * + * @return void + */ + public function test_order_sync_retries_on_failure() { + // Create a test Order. + $product = new WC_Product_Simple(); + $product->set_name( 'Test Product' ); + $product->set_regular_price( 25 ); + $product->save(); + + $order = WC_Helper_Order::create_order( 1, $product ); + $order->set_status( 'completed' ); + $order->set_total( 100 ); // $25 x 4. + $order->save(); + + // Clear the existing action queue (the above save adds an action). + $this->queue->actions = array(); + + // Force a failure by sabotaging the query run after retreiving order coupons. + add_filter( 'query', array( $this, 'filter_order_query' ) ); + + // Initiate sync. + WC_Admin_Api_Init::orders_lookup_process_order( $order->get_id() ); + + // Verify that a retry job was scheduled. + $this->assertCount( 1, $this->queue->actions ); + $this->assertArraySubset( + array( + 'hook' => WC_Admin_Api_Init::SINGLE_ORDER_ACTION, + 'args' => array( $order->get_id() ), + ), + $this->queue->actions[0] + ); + } +} From 7916100009f1a5671002cee3d14a0d6727edfc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 4 Feb 2019 18:32:27 +0100 Subject: [PATCH 12/19] Fix CSS Lint warning (https://github.com/woocommerce/woocommerce-admin/pull/1469) --- .../woocommerce-admin/packages/components/src/search/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/woocommerce-admin/packages/components/src/search/style.scss b/plugins/woocommerce-admin/packages/components/src/search/style.scss index 6ed6c70fd43..c7fce0f2bd6 100644 --- a/plugins/woocommerce-admin/packages/components/src/search/style.scss +++ b/plugins/woocommerce-admin/packages/components/src/search/style.scss @@ -131,7 +131,7 @@ .woocommerce-search__clear { position: absolute; right: 10px; - top: calc( 50% - 10px ); + top: calc(50% - 10px); & > .dashicon { color: #c9c9c9; From f938dd5708d953907a16a48d5f9730eef31acac9 Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Mon, 4 Feb 2019 11:46:46 -0700 Subject: [PATCH 13/19] Invoke queue test helper in new Order Stats and Products Report tests. --- .../tests/reports/class-wc-tests-reports-orders-stats.php | 6 ++++-- .../tests/reports/class-wc-tests-reports-products.php | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php index c48ef64cdb7..386f9d3bb27 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php @@ -178,8 +178,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $order->set_shipping_total( 0 ); $order->set_cart_tax( 0 ); $order->save(); - // Wait one second to avoid potentially ambiguous new/returning customer. - sleep( 1 ); + + WC_Helper_Queue::run_all_pending(); } $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); @@ -3330,6 +3330,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $order_2->calculate_totals(); $order_2->save(); + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); // Tests for before & after set to current hour. diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php index 95ab0d3dff1..7d6cf74074e 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-products.php @@ -296,6 +296,8 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { break; } + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Products_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); $end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS ); From 16ea4f60fc72a671b61a8da6a953a8e3f4447849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Mon, 4 Feb 2019 22:15:06 +0100 Subject: [PATCH 14/19] Fix hourly labels in bar charts X-axis (https://github.com/woocommerce/woocommerce-admin/pull/1468) * Fix hourly labels in bar charts X-axis * Add CHANGELOG comment * Remove unnecessary date object call --- plugins/woocommerce-admin/packages/components/CHANGELOG.md | 5 ++++- .../packages/components/src/chart/d3chart/utils/axis.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce-admin/packages/components/CHANGELOG.md b/plugins/woocommerce-admin/packages/components/CHANGELOG.md index 794b94f6e38..3c15838b004 100644 --- a/plugins/woocommerce-admin/packages/components/CHANGELOG.md +++ b/plugins/woocommerce-admin/packages/components/CHANGELOG.md @@ -1,3 +1,7 @@ +# 1.5.0 (unreleased) +- Fix X-axis labels in hourly bar charts. +- New `` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags. + # 1.4.2 - Add emoji-flags dependency @@ -5,7 +9,6 @@ - Chart component: format numbers and prices using store currency settings. - Make `href`/linking optional in SummaryNumber. - Fix SummaryNumber example code. -- New `` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags. # 1.4.0 - Add download log ip address autocompleter to search component diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js index 3e6a2417d23..e5483a7edc2 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js @@ -210,7 +210,7 @@ export const drawAxis = ( node, params, xOffset ) => { d3AxisBottom( xScale ) .tickValues( ticks ) .tickFormat( ( d, i ) => params.interval === 'hour' - ? params.xFormat( d ) + ? params.xFormat( d instanceof Date ? d : moment( d ).toDate() ) : removeDuplicateDates( d, i, ticks, params.xFormat ) ) ); From 7664612b57082895431f29ddb0ddcf4c477f2a3f Mon Sep 17 00:00:00 2001 From: Jeff Stieler Date: Mon, 4 Feb 2019 16:59:08 -0700 Subject: [PATCH 15/19] Fix order stats report status filtering test case (returning customer value incorrect). --- .../reports/class-wc-tests-reports-orders-stats.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php index 386f9d3bb27..7f0f69f1a5d 100644 --- a/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php +++ b/plugins/woocommerce-admin/tests/reports/class-wc-tests-reports-orders-stats.php @@ -179,9 +179,12 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { $order->set_cart_tax( 0 ); $order->save(); - WC_Helper_Queue::run_all_pending(); + // Wait one second to avoid potentially ambiguous new/returning customer. + sleep( 1 ); } + WC_Helper_Queue::run_all_pending(); + $data_store = new WC_Admin_Reports_Orders_Stats_Data_Store(); $start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() ); @@ -205,8 +208,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'taxes' => 0, 'shipping' => 0, 'net_revenue' => 100, - 'num_returning_customers' => 0, - 'num_new_customers' => 1, + 'num_returning_customers' => 1, + 'num_new_customers' => 0, 'products' => 1, 'segments' => array(), ), @@ -228,8 +231,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case { 'num_items_sold' => 4, 'avg_items_per_order' => 4, 'avg_order_value' => 100, - 'num_returning_customers' => 0, - 'num_new_customers' => 1, + 'num_returning_customers' => 1, + 'num_new_customers' => 0, 'segments' => array(), ), ), From fd3da36a2f82a646e4449b4ec801d453aa8146c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" Date: Tue, 5 Feb 2019 10:53:46 +0800 Subject: [PATCH 16/19] Lock file maintenance (https://github.com/woocommerce/woocommerce-admin/pull/1462) --- plugins/woocommerce-admin/package-lock.json | 244 +++++++++----------- 1 file changed, 113 insertions(+), 131 deletions(-) diff --git a/plugins/woocommerce-admin/package-lock.json b/plugins/woocommerce-admin/package-lock.json index eb6859c8e24..6a24370fd50 100644 --- a/plugins/woocommerce-admin/package-lock.json +++ b/plugins/woocommerce-admin/package-lock.json @@ -60,11 +60,11 @@ } }, "@babel/generator": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz", - "integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.2.tgz", + "integrity": "sha512-f3QCuPppXxtZOEm5GWPra/uYUjmNQlu9pbAD8D/9jze4pTY83rTtB1igTBSwvkeNlC5gR24zFFkz+2WHLFQhqQ==", "requires": { - "@babel/types": "^7.3.0", + "@babel/types": "^7.3.2", "jsesc": "^2.5.1", "lodash": "^4.17.10", "source-map": "^0.5.0", @@ -274,9 +274,9 @@ } }, "@babel/parser": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.1.tgz", - "integrity": "sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA==" + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.2.tgz", + "integrity": "sha512-QzNUC2RO1gadg+fs21fi0Uu0OuGNzRKEmgCxoLNzbCdoprLwjfmZwzUrpUNfJPaVRwBpDY47A17yYEGWyRelnQ==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.2.0", @@ -298,9 +298,9 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz", - "integrity": "sha512-Nmmv1+3LqxJu/V5jU9vJmxR/KIRWFk2qLHmbB56yRRRFhlaSuOVXscX3gUmhaKgUhzA3otOHVubbIEVYsZ0eZg==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz", + "integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==", "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-syntax-object-rest-spread": "^7.2.0" @@ -424,9 +424,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz", - "integrity": "sha512-coVO2Ayv7g0qdDbrNiadE4bU7lvCd9H539m2gMknyVjjMdwF/iCOM7R+E8PkntoqLkltO0rk+3axhpp/0v68VQ==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz", + "integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==", "requires": { "@babel/helper-plugin-utils": "^7.0.0" } @@ -730,9 +730,9 @@ } }, "@babel/types": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz", - "integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.2.tgz", + "integrity": "sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==", "requires": { "esutils": "^2.0.2", "lodash": "^4.17.10", @@ -1765,21 +1765,21 @@ } }, "inquirer": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", - "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", + "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^3.0.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^6.1.0", + "rxjs": "^6.4.0", "string-width": "^2.1.0", "strip-ansi": "^5.0.0", "through": "^2.3.6" @@ -2113,9 +2113,9 @@ "integrity": "sha512-y+h7tNlxDPDrH/TrSw1wCSm6FoEAY8FrbUxYng3BMSYBTUsX1utLooizk9v8J1yy6F9AioXNnPZ1qiu2vsa08Q==" }, "@types/node": { - "version": "10.12.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.19.tgz", - "integrity": "sha512-2NVovndCjJQj6fUUn9jCgpP4WSqr+u1SoUZMZyJkhGeBFsm6dE46l31S7lPUYt9uQ28XI+ibrJA1f5XyH5HNtA==" + "version": "10.12.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz", + "integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ==" }, "@webassemblyjs/ast": { "version": "1.7.11", @@ -2999,9 +2999,9 @@ }, "dependencies": { "acorn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz", - "integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA==" + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.7.tgz", + "integrity": "sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw==" } } }, @@ -3060,9 +3060,9 @@ } }, "ajv": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", - "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz", + "integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==", "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -4262,9 +4262,9 @@ } }, "binary-extensions": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", - "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", + "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", "dev": true }, "bindings": { @@ -4632,9 +4632,9 @@ } }, "caniuse-lite": { - "version": "1.0.30000932", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz", - "integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A==" + "version": "1.0.30000934", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000934.tgz", + "integrity": "sha512-o7yfZn0R9N+mWAuksDsdLsb1gu9o//XK0QSU0zSSReKNRsXsFc/n/psxi0YSPNiqlKxImp5h4DHnAPdwYJ8nNA==" }, "capture-exit": { "version": "1.2.0", @@ -6357,9 +6357,9 @@ "dev": true }, "cssom": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz", - "integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog==" + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==" }, "cssstyle": { "version": "1.1.1", @@ -6456,17 +6456,17 @@ "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg==" }, "d3-shape": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.3.tgz", - "integrity": "sha512-f7V9wHQCmv4s4N7EmD5i0mwJ5y09L8r1rWVrzH1Av0YfgBKJCnTJGho76rS4HNUIw6tTBbWfFcs4ntP/MKWF4A==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.4.tgz", + "integrity": "sha512-izaz4fOpOnY3CD17hkZWNxbaN70sIGagLR/5jb6RS96Y+6VqX+q1BQf1av6QSBRdfULi3Gb8Js4CzG4+KAPjMg==", "requires": { "d3-path": "1" } }, "d3-time": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.10.tgz", - "integrity": "sha512-hF+NTLCaJHF/JqHN5hE8HVGAXPStEq6/omumPE/SxyHVrR7/qQxusFDo0t0c/44+sCGHthC7yNGFZIEgju0P8g==" + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz", + "integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw==" }, "d3-time-format": { "version": "2.1.3", @@ -7234,9 +7234,9 @@ "dev": true }, "duplexify": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", - "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -7317,9 +7317,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.109", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.109.tgz", - "integrity": "sha512-1qhgVZD9KIULMyeBkbjU/dWmm30zpPUfdWZfVO3nPhbtqMHJqHr4Ua5wBcWtAymVFrUCuAJxjMF1OhG+bR21Ow==" + "version": "1.3.113", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", + "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==" }, "elliptic": { "version": "6.4.1", @@ -7422,9 +7422,9 @@ } }, "enzyme-adapter-react-16": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.8.0.tgz", - "integrity": "sha512-7cVHIKutqnesGeM3CjNFHSvktpypSWBokrBO8wIW+BVx+HGxWCF87W9TpkIIYJqgCtdw9FQGFrAbLg8kSwPRuQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.9.0.tgz", + "integrity": "sha512-tUqmeLi0Y3PxuiPSykjn8ZMqzCnaRIVywNx0i50+nhd4y/b3JtXRbsvIc8HKxn3heE4t969EI2461Kc9FYxjdw==", "requires": { "enzyme-adapter-utils": "^1.10.0", "function.prototype.name": "^1.1.0", @@ -7607,9 +7607,9 @@ }, "dependencies": { "acorn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz", - "integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.7.tgz", + "integrity": "sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw==", "dev": true }, "acorn-jsx": { @@ -7682,21 +7682,21 @@ "dev": true }, "inquirer": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz", - "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz", + "integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==", "dev": true, "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^3.0.0", + "external-editor": "^3.0.3", "figures": "^2.0.0", - "lodash": "^4.17.10", + "lodash": "^4.17.11", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rxjs": "^6.1.0", + "rxjs": "^6.4.0", "string-width": "^2.1.0", "strip-ansi": "^5.0.0", "through": "^2.3.6" @@ -8656,39 +8656,13 @@ "dev": true }, "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.0.tgz", + "integrity": "sha512-6MHED/cmsyux1G4/Cek2Z776y9t7WCNd3h2h/HW91vFeU7pzMhA8XvAlDhHcanG5IWuIh/xcC7JASY4WQpG6xg==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" } }, "for-in": { @@ -11339,8 +11313,7 @@ "is-wsl": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" }, "isarray": { "version": "1.0.0", @@ -13263,11 +13236,11 @@ } }, "magic-string": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz", - "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz", + "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==", "requires": { - "sourcemap-codec": "^1.4.1" + "sourcemap-codec": "^1.4.4" } }, "make-dir": { @@ -14163,20 +14136,21 @@ } }, "node-notifier": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz", - "integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", "requires": { "growly": "^1.3.0", + "is-wsl": "^1.1.0", "semver": "^5.5.0", "shellwords": "^0.1.1", "which": "^1.3.0" } }, "node-releases": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.6.tgz", - "integrity": "sha512-lODUVHEIZutZx+TDdOk47qLik8FJMXzJ+WnyUGci1MTvTOyzZrz5eVPIIpc5Hb3NfHZGeGHeuwrRYVI1PEITWg==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.7.tgz", + "integrity": "sha512-bKdrwaqJUPHqlCzDD7so/R+Nk0jGv9a11ZhLrD9f6i947qGLrGAhU3OxRENa19QQmwzGy/g6zCDEuLGDO8HPvA==", "requires": { "semver": "^5.3.0" } @@ -14457,13 +14431,14 @@ } }, "npm-package-json-lint": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-3.4.1.tgz", - "integrity": "sha512-W4xlmeFRAY34GQoHUywqoI3PxVZ0hugjbZLiGnVgFjgmvRRcmxKwwmubMe0lAD78vgOHgJZRGubdVXwkp9d3QA==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-3.5.0.tgz", + "integrity": "sha512-MELethOnZW5uVzP65oTQEH2fI6eS/BQEXjvOTyQkUQqGHP9si5pxCWcO+Q4dsahb+4yG7GMxFhpF42AjhCbgRA==", "requires": { - "ajv": "^6.5.4", - "chalk": "^2.4.1", + "ajv": "^6.7.0", + "chalk": "^2.4.2", "glob": "^7.1.3", + "ignore": "^5.0.5", "is-path-inside": "^2.0.0", "is-plain-obj": "^1.1.0", "is-resolvable": "^1.1.0", @@ -14472,7 +14447,14 @@ "plur": "^3.0.1", "semver": "^5.6.0", "strip-json-comments": "^2.0.1", - "validator": "^10.8.0" + "validator": "^10.11.0" + }, + "dependencies": { + "ignore": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.0.5.tgz", + "integrity": "sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA==" + } } }, "npm-packlist": { @@ -14561,9 +14543,9 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", - "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.0.tgz", + "integrity": "sha512-ZG3bLAvdHmhIjaQ/Db1qvBxsGvFMLIRpQszyqbg31VJ53UP++uZX1/gf3Ut96pdwN9AuDwlMqIYLm0UPCdUeHg==" }, "oauth-sign": { "version": "0.9.0", @@ -19717,9 +19699,9 @@ } }, "stylelint-scss": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.5.1.tgz", - "integrity": "sha512-XNWKTU1a2EUNWdauxHPTJlGNNQzIbg48OTTIdBs5xTXxpbYAGtX/J+jBqMPjxfdySXijc/mexubuZ+ZinUGGgw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.5.2.tgz", + "integrity": "sha512-HL95s8Q6wihbJe7c7z6rL9GHVHOF3H3tXkVmGutitwn14LYR52JYMwCkcifqlf4nRsvXrUDaoH6OHOdilifyjw==", "dev": true, "requires": { "lodash": "^4.17.11", @@ -19931,14 +19913,14 @@ } }, "terser": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.14.1.tgz", - "integrity": "sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw==", + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", + "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", "dev": true, "requires": { "commander": "~2.17.1", "source-map": "~0.6.1", - "source-map-support": "~0.5.6" + "source-map-support": "~0.5.9" }, "dependencies": { "commander": { @@ -19966,9 +19948,9 @@ } }, "terser-webpack-plugin": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz", - "integrity": "sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz", + "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==", "dev": true, "requires": { "cacache": "^11.0.2", @@ -19976,7 +19958,7 @@ "schema-utils": "^1.0.0", "serialize-javascript": "^1.4.0", "source-map": "^0.6.1", - "terser": "^3.8.1", + "terser": "^3.16.1", "webpack-sources": "^1.1.0", "worker-farm": "^1.5.2" }, From 3aaf3187796a3cead8ac5a2448c12a7bbceb0795 Mon Sep 17 00:00:00 2001 From: Joshua T Flowers Date: Tue, 5 Feb 2019 10:57:38 +0800 Subject: [PATCH 17/19] Exclude trashed orders from reports (https://github.com/woocommerce/woocommerce-admin/pull/1464) --- .../data-stores/class-wc-admin-reports-data-store.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php index 56e729736ca..2a57f934a88 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-data-store.php @@ -417,8 +417,8 @@ class WC_Admin_Reports_Data_Store { * @return array */ protected static function get_excluded_report_order_statuses() { - $excluded_statuses = WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) ); - $excluded_statuses[] = 'refunded'; + $excluded_statuses = WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) ); + $excluded_statuses = array_merge( array( 'refunded', 'trash' ), $excluded_statuses ); return apply_filters( 'woocommerce_reports_excluded_order_statuses', $excluded_statuses ); } From df97ac4d493cdc1a47d33d7c0fcc1abfd1185916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Tue, 5 Feb 2019 10:56:26 +0100 Subject: [PATCH 18/19] Improve display of 0-value charts (https://github.com/woocommerce/woocommerce-admin/pull/1470) * Improve display of 0-value charts * Add Changelog comment --- .../packages/components/CHANGELOG.md | 1 + .../components/src/chart/d3chart/utils/axis.js | 4 ++-- .../components/src/chart/d3chart/utils/scales.js | 4 ++-- .../src/chart/d3chart/utils/test/scales.js | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/plugins/woocommerce-admin/packages/components/CHANGELOG.md b/plugins/woocommerce-admin/packages/components/CHANGELOG.md index 3c15838b004..257be5e71be 100644 --- a/plugins/woocommerce-admin/packages/components/CHANGELOG.md +++ b/plugins/woocommerce-admin/packages/components/CHANGELOG.md @@ -1,4 +1,5 @@ # 1.5.0 (unreleased) +- Improves display of charts where all values are 0. - Fix X-axis labels in hourly bar charts. - New `` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags. diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js index e5483a7edc2..5ff1186accd 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/axis.js @@ -197,7 +197,7 @@ export const drawAxis = ( node, params, xOffset ) => { : compareStrings( formatter( prevMonth ), formatter( monthDate ) ).join( ' ' ); }; - const yGrids = getYGrids( params.yMax ); + const yGrids = getYGrids( params.yMax === 0 ? 1 : params.yMax ); const ticks = params.xTicks.map( d => ( params.type === 'line' ? moment( d ).toDate() : d ) ); @@ -257,7 +257,7 @@ export const drawAxis = ( node, params, xOffset ) => { .attr( 'text-anchor', 'start' ) .call( d3AxisLeft( params.yTickOffset ) - .tickValues( yGrids ) + .tickValues( params.yMax === 0 ? [ yGrids[ 0 ] ] : yGrids ) .tickFormat( d => params.yFormat( d !== 0 ? d : 0 ) ) ); diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/scales.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/scales.js index 122921209a4..38942f4e7b8 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/scales.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/scales.js @@ -72,7 +72,7 @@ export const getYMax = lineData => { */ export const getYScale = ( height, yMax ) => d3ScaleLinear() - .domain( [ 0, yMax ] ) + .domain( [ 0, yMax === 0 ? 1 : yMax ] ) .rangeRound( [ height, 0 ] ); /** @@ -83,5 +83,5 @@ export const getYScale = ( height, yMax ) => */ export const getYTickOffset = ( height, yMax ) => d3ScaleLinear() - .domain( [ 0, yMax ] ) + .domain( [ 0, yMax === 0 ? 1 : yMax ] ) .rangeRound( [ height + 12, 12 ] ); diff --git a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/scales.js b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/scales.js index 34867e4c3d8..39237d8b43f 100644 --- a/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/scales.js +++ b/plugins/woocommerce-admin/packages/components/src/chart/d3chart/utils/test/scales.js @@ -107,6 +107,14 @@ describe( 'Y scales', () => { expect( scaleLinear().domain ).toHaveBeenLastCalledWith( [ 0, 15000000 ] ); expect( scaleLinear().rangeRound ).toHaveBeenLastCalledWith( [ 100, 0 ] ); } ); + + it( 'avoids the domain starting and ending at the same point when yMax is 0', () => { + getYScale( 100, 0 ); + + const args = scaleLinear().domain.mock.calls; + const lastArgs = args[ args.length - 1 ][ 0 ]; + expect( lastArgs[ 0 ] ).toBeLessThan( lastArgs[ 1 ] ); + } ); } ); describe( 'getYTickOffset', () => { @@ -116,5 +124,13 @@ describe( 'Y scales', () => { expect( scaleLinear().domain ).toHaveBeenLastCalledWith( [ 0, 15000000 ] ); expect( scaleLinear().rangeRound ).toHaveBeenLastCalledWith( [ 112, 12 ] ); } ); + + it( 'avoids the domain starting and ending at the same point when yMax is 0', () => { + getYTickOffset( 100, 0 ); + + const args = scaleLinear().domain.mock.calls; + const lastArgs = args[ args.length - 1 ][ 0 ]; + expect( lastArgs[ 0 ] ).toBeLessThan( lastArgs[ 1 ] ); + } ); } ); } ); From 84ef5ffb8977d264640a07cabaf0b58e1a0b3548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Tue, 5 Feb 2019 13:00:37 +0100 Subject: [PATCH 19/19] Show empty table when search returns no results (https://github.com/woocommerce/woocommerce-admin/pull/1452) * Show empty table when search returns no results * Fix singular wrong string for 'orders' Co-Authored-By: Aljullu * Check if search returned 0 results inside table components instead of passing a prop --- .../components/report-table/index.js | 23 ++++++++--- .../analytics/report/categories/table.js | 24 ++++++------ .../client/analytics/report/coupons/table.js | 14 +++---- .../analytics/report/customers/table.js | 23 ++++++----- .../analytics/report/downloads/table.js | 8 ++-- .../client/analytics/report/index.js | 2 +- .../client/analytics/report/orders/table.js | 38 +++++++++++-------- .../report/products/table-variations.js | 18 ++++----- .../client/analytics/report/products/table.js | 25 ++++++------ .../client/analytics/report/revenue/table.js | 31 ++++++++------- .../client/analytics/report/stock/table.js | 20 +++++----- .../client/analytics/report/taxes/table.js | 24 +++++++----- .../client/wc-api/reports/utils.js | 3 +- 13 files changed, 140 insertions(+), 113 deletions(-) diff --git a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js index 55b664bebf7..6af282386be 100644 --- a/plugins/woocommerce-admin/client/analytics/components/report-table/index.js +++ b/plugins/woocommerce-admin/client/analytics/components/report-table/index.js @@ -20,6 +20,7 @@ import { onQueryChange } from '@woocommerce/navigation'; */ import ReportError from 'analytics/components/report-error'; import { getReportChartData, getReportTableData } from 'wc-api/reports/utils'; +import { QUERY_DEFAULTS } from 'wc-api/constants'; import withSelect from 'wc-api/with-select'; import { extendTableData } from './utils'; @@ -84,12 +85,12 @@ class ReportTable extends Component { } const isRequesting = tableData.isRequesting || primaryData.isRequesting; - const totals = get( primaryData, [ 'data', 'totals' ], null ); - const totalResults = items.totalResults || 0; + const totals = get( primaryData, [ 'data', 'totals' ], {} ); + const totalResults = items.totalResults; const { headers, ids, rows, summary } = applyFilters( TABLE_FILTER, { endpoint: endpoint, headers: getHeadersContent(), - ids: itemIdField ? items.data.map( item => item[ itemIdField ] ) : null, + ids: itemIdField ? items.data.map( item => item[ itemIdField ] ) : [], rows: getRowsContent( items.data ), totals: totals, summary: getSummary ? getSummary( totals, totalResults ) : null, @@ -107,7 +108,7 @@ class ReportTable extends Component { onQueryChange={ onQueryChange } onColumnsChange={ this.onColumnsChange } rows={ rows } - rowsPerPage={ parseInt( query.per_page ) } + rowsPerPage={ parseInt( query.per_page ) || QUERY_DEFAULTS.pageSize } summary={ summary } totalRows={ totalResults } { ...tableProps } @@ -159,7 +160,7 @@ ReportTable.propTypes = { * Primary data of that report. If it's not provided, it will be automatically * loaded via the provided `endpoint`. */ - primaryData: PropTypes.object.isRequired, + primaryData: PropTypes.object, /** * Table data of that report. If it's not provided, it will be automatically * loaded via the provided `endpoint`. @@ -176,13 +177,23 @@ ReportTable.propTypes = { }; ReportTable.defaultProps = { - tableData: {}, + primaryData: {}, + tableData: { + items: { + data: [], + totalResults: 0, + }, + query: {}, + }, tableQuery: {}, }; export default compose( withSelect( ( select, props ) => { const { endpoint, getSummary, query, tableData, tableQuery, columnPrefsKey } = props; + if ( query.search && ! ( query[ endpoint ] && query[ endpoint ].length ) ) { + return {}; + } const chartEndpoint = 'variations' === endpoint ? 'products' : endpoint; const primaryData = getSummary ? getReportChartData( chartEndpoint, 'primary', query, select ) diff --git a/plugins/woocommerce-admin/client/analytics/report/categories/table.js b/plugins/woocommerce-admin/client/analytics/report/categories/table.js index 95ad44e52c2..69918db5a21 100644 --- a/plugins/woocommerce-admin/client/analytics/report/categories/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/categories/table.js @@ -111,27 +111,24 @@ class CategoriesReportTable extends Component { } ); } - getSummary( totals, totalResults ) { - if ( ! totals ) { - return []; - } - + getSummary( totals, totalResults = 0 ) { + const { items_sold = 0, net_revenue = 0, orders_count = 0 } = totals; return [ { label: _n( 'category', 'categories', totalResults, 'wc-admin' ), value: numberFormat( totalResults ), }, { - label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ), - value: numberFormat( totals.items_sold ), + label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ), + value: numberFormat( items_sold ), }, { label: __( 'net revenue', 'wc-admin' ), - value: formatCurrency( totals.net_revenue ), + value: formatCurrency( net_revenue ), }, { - label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'order', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, ]; } @@ -168,7 +165,12 @@ class CategoriesReportTable extends Component { } export default compose( - withSelect( select => { + withSelect( ( select, props ) => { + const { query } = props; + if ( query.search && ! ( query.categories && query.categories.length ) ) { + return {}; + } + const { getItems, getItemsError, isGetItemsRequesting } = select( 'wc-api' ); const tableQuery = { per_page: -1, diff --git a/plugins/woocommerce-admin/client/analytics/report/coupons/table.js b/plugins/woocommerce-admin/client/analytics/report/coupons/table.js index 05bae64d70c..e9120933f79 100644 --- a/plugins/woocommerce-admin/client/analytics/report/coupons/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/coupons/table.js @@ -129,21 +129,19 @@ export default class CouponsReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { coupons_count = 0, orders_count = 0, amount = 0 } = totals; return [ { - label: _n( 'coupon', 'coupons', totals.coupons_count, 'wc-admin' ), - value: numberFormat( totals.coupons_count ), + label: _n( 'coupon', 'coupons', coupons_count, 'wc-admin' ), + value: numberFormat( coupons_count ), }, { - label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'order', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, { label: __( 'amount discounted', 'wc-admin' ), - value: formatCurrency( totals.amount ), + value: formatCurrency( amount ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/customers/table.js b/plugins/woocommerce-admin/client/analytics/report/customers/table.js index 63ba26dab1d..cfd5321ca38 100644 --- a/plugins/woocommerce-admin/client/analytics/report/customers/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/customers/table.js @@ -2,7 +2,7 @@ /** * External dependencies */ -import { __ } from '@wordpress/i18n'; +import { __, _n } from '@wordpress/i18n'; import { Component, Fragment } from '@wordpress/element'; import { Tooltip } from '@wordpress/components'; @@ -191,25 +191,28 @@ export default class CustomersReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { + customers_count = 0, + avg_orders_count = 0, + avg_total_spend = 0, + avg_avg_order_value = 0, + } = totals; return [ { - label: __( 'customers', 'wc-admin' ), - value: numberFormat( totals.customers_count ), + label: _n( 'customer', 'customers', customers_count, 'wc-admin' ), + value: numberFormat( customers_count ), }, { - label: __( 'average orders', 'wc-admin' ), - value: numberFormat( totals.avg_orders_count ), + label: _n( 'average order', 'average orders', avg_orders_count, 'wc-admin' ), + value: numberFormat( avg_orders_count ), }, { label: __( 'average lifetime spend', 'wc-admin' ), - value: formatCurrency( totals.avg_total_spend ), + value: formatCurrency( avg_total_spend ), }, { label: __( 'average order value', 'wc-admin' ), - value: formatCurrency( totals.avg_avg_order_value ), + value: formatCurrency( avg_avg_order_value ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/downloads/table.js b/plugins/woocommerce-admin/client/analytics/report/downloads/table.js index 9d2f403602d..9bb857e42d9 100644 --- a/plugins/woocommerce-admin/client/analytics/report/downloads/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/downloads/table.js @@ -121,9 +121,7 @@ export default class CouponsReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { download_count = 0 } = totals; const { query } = this.props; const dates = getCurrentDates( query ); const after = moment( dates.primary.after ); @@ -136,8 +134,8 @@ export default class CouponsReportTable extends Component { value: numberFormat( days ), }, { - label: _n( 'download', 'downloads', totals.download_count, 'wc-admin' ), - value: numberFormat( totals.download_count ), + label: _n( 'download', 'downloads', download_count, 'wc-admin' ), + value: numberFormat( download_count ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/index.js b/plugins/woocommerce-admin/client/analytics/report/index.js index 8b4b3c43df5..c9078b5269a 100644 --- a/plugins/woocommerce-admin/client/analytics/report/index.js +++ b/plugins/woocommerce-admin/client/analytics/report/index.js @@ -148,7 +148,7 @@ export default compose( const items = searchItemsByString( select, report, search ); const ids = Object.keys( items ); if ( ! ids.length ) { - return {}; // @TODO if no results were found, we should avoid making a server request. + return {}; } return { diff --git a/plugins/woocommerce-admin/client/analytics/report/orders/table.js b/plugins/woocommerce-admin/client/analytics/report/orders/table.js index cdd9db732ba..0885bafc28a 100644 --- a/plugins/woocommerce-admin/client/analytics/report/orders/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/orders/table.js @@ -182,42 +182,48 @@ export default class OrdersReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { + orders_count = 0, + num_new_customers = 0, + num_returning_customers = 0, + products = 0, + num_items_sold = 0, + coupons = 0, + net_revenue = 0, + } = totals; return [ { - label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'order', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, { - label: _n( 'new customer', 'new customers', totals.num_new_customers, 'wc-admin' ), - value: numberFormat( totals.num_new_customers ), + label: _n( 'new customer', 'new customers', num_new_customers, 'wc-admin' ), + value: numberFormat( num_new_customers ), }, { label: _n( 'returning customer', 'returning customers', - totals.num_returning_customers, + num_returning_customers, 'wc-admin' ), - value: numberFormat( totals.num_returning_customers ), + value: numberFormat( num_returning_customers ), }, { - label: _n( 'product', 'products', totals.products, 'wc-admin' ), - value: numberFormat( totals.products ), + label: _n( 'product', 'products', products, 'wc-admin' ), + value: numberFormat( products ), }, { - label: _n( 'item sold', 'items sold', totals.num_items_sold, 'wc-admin' ), - value: numberFormat( totals.num_items_sold ), + label: _n( 'item sold', 'items sold', num_items_sold, 'wc-admin' ), + value: numberFormat( num_items_sold ), }, { - label: _n( 'coupon', 'coupons', totals.coupons, 'wc-admin' ), - value: numberFormat( totals.coupons ), + label: _n( 'coupon', 'coupons', coupons, 'wc-admin' ), + value: numberFormat( coupons ), }, { label: __( 'net revenue', 'wc-admin' ), - value: formatCurrency( totals.net_revenue ), + value: formatCurrency( net_revenue ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/products/table-variations.js b/plugins/woocommerce-admin/client/analytics/report/products/table-variations.js index 320c2ac391d..bfcfbe5c37d 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/table-variations.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/table-variations.js @@ -139,26 +139,24 @@ export default class VariationsReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { products_count = 0, items_sold = 0, net_revenue = 0, orders_count = 0 } = totals; return [ { // @TODO: When primaryData is segmented, fix this to reflect variations, not products. - label: _n( 'variation sold', 'variations sold', totals.products_count, 'wc-admin' ), - value: numberFormat( totals.products_count ), + label: _n( 'variation sold', 'variations sold', products_count, 'wc-admin' ), + value: numberFormat( products_count ), }, { - label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ), - value: numberFormat( totals.items_sold ), + label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ), + value: numberFormat( items_sold ), }, { label: __( 'net revenue', 'wc-admin' ), - value: formatCurrency( totals.net_revenue ), + value: formatCurrency( net_revenue ), }, { - label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'orders', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/products/table.js b/plugins/woocommerce-admin/client/analytics/report/products/table.js index fcb24f0dac7..89111d1085d 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/table.js @@ -204,25 +204,23 @@ class ProductsReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { products_count = 0, items_sold = 0, net_revenue = 0, orders_count = 0 } = totals; return [ { - label: _n( 'product sold', 'products sold', totals.products_count, 'wc-admin' ), - value: numberFormat( totals.products_count ), + label: _n( 'product sold', 'products sold', products_count, 'wc-admin' ), + value: numberFormat( products_count ), }, { - label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ), - value: numberFormat( totals.items_sold ), + label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ), + value: numberFormat( items_sold ), }, { label: __( 'net revenue', 'wc-admin' ), - value: formatCurrency( totals.net_revenue ), + value: formatCurrency( net_revenue ), }, { - label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'orders', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, ]; } @@ -259,7 +257,12 @@ class ProductsReportTable extends Component { } export default compose( - withSelect( select => { + withSelect( ( select, props ) => { + const { query } = props; + if ( query.search && ! ( query.products && query.products.length ) ) { + return {}; + } + const { getItems, getItemsError, isGetItemsRequesting } = select( 'wc-api' ); const tableQuery = { per_page: -1, diff --git a/plugins/woocommerce-admin/client/analytics/report/revenue/table.js b/plugins/woocommerce-admin/client/analytics/report/revenue/table.js index 7a2230fb4e4..f1d5c5ec745 100644 --- a/plugins/woocommerce-admin/client/analytics/report/revenue/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/revenue/table.js @@ -153,43 +153,48 @@ class RevenueReportTable extends Component { } ); } - getSummary( totals, totalResults ) { - if ( ! totals ) { - return []; - } - + getSummary( totals, totalResults = 0 ) { + const { + orders_count = 0, + gross_revenue = 0, + refunds = 0, + coupons = 0, + taxes = 0, + shipping = 0, + net_revenue = 0, + } = totals; return [ { label: _n( 'day', 'days', totalResults, 'wc-admin' ), value: numberFormat( totalResults ), }, { - label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'order', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, { label: __( 'gross revenue', 'wc-admin' ), - value: formatCurrency( totals.gross_revenue ), + value: formatCurrency( gross_revenue ), }, { label: __( 'refunds', 'wc-admin' ), - value: formatCurrency( totals.refunds ), + value: formatCurrency( refunds ), }, { label: __( 'coupons', 'wc-admin' ), - value: formatCurrency( totals.coupons ), + value: formatCurrency( coupons ), }, { label: __( 'taxes', 'wc-admin' ), - value: formatCurrency( totals.taxes ), + value: formatCurrency( taxes ), }, { label: __( 'shipping', 'wc-admin' ), - value: formatCurrency( totals.shipping ), + value: formatCurrency( shipping ), }, { label: __( 'net revenue', 'wc-admin' ), - value: formatCurrency( totals.net_revenue ), + value: formatCurrency( net_revenue ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/stock/table.js b/plugins/woocommerce-admin/client/analytics/report/stock/table.js index ddabf01351c..05bab0e9960 100644 --- a/plugins/woocommerce-admin/client/analytics/report/stock/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/stock/table.js @@ -103,25 +103,23 @@ export default class StockReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { products = 0, out_of_stock = 0, low_stock = 0, in_stock = 0 } = totals; return [ { - label: _n( 'product', 'products', totals.products, 'wc-admin' ), - value: numberFormat( totals.products ), + label: _n( 'product', 'products', products, 'wc-admin' ), + value: numberFormat( products ), }, { - label: __( 'out of stock', totals.out_of_stock, 'wc-admin' ), - value: numberFormat( totals.out_of_stock ), + label: __( 'out of stock', out_of_stock, 'wc-admin' ), + value: numberFormat( out_of_stock ), }, { - label: __( 'low stock', totals.low_stock, 'wc-admin' ), - value: numberFormat( totals.low_stock ), + label: __( 'low stock', low_stock, 'wc-admin' ), + value: numberFormat( low_stock ), }, { - label: __( 'in stock', totals.in_stock, 'wc-admin' ), - value: numberFormat( totals.in_stock ), + label: __( 'in stock', in_stock, 'wc-admin' ), + value: numberFormat( in_stock ), }, ]; } diff --git a/plugins/woocommerce-admin/client/analytics/report/taxes/table.js b/plugins/woocommerce-admin/client/analytics/report/taxes/table.js index ab766745d7c..94dffb45873 100644 --- a/plugins/woocommerce-admin/client/analytics/report/taxes/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/taxes/table.js @@ -111,29 +111,33 @@ export default class TaxesReportTable extends Component { } getSummary( totals ) { - if ( ! totals ) { - return []; - } + const { + tax_codes = 0, + total_tax = 0, + order_tax = 0, + shipping_tax = 0, + orders_count = 0, + } = totals; return [ { - label: _n( 'tax code', 'tax codes', totals.tax_codes, 'wc-admin' ), - value: numberFormat( totals.tax_codes ), + label: _n( 'tax code', 'tax codes', tax_codes, 'wc-admin' ), + value: numberFormat( tax_codes ), }, { label: __( 'total tax', 'wc-admin' ), - value: formatCurrency( totals.total_tax ), + value: formatCurrency( total_tax ), }, { label: __( 'order tax', 'wc-admin' ), - value: formatCurrency( totals.order_tax ), + value: formatCurrency( order_tax ), }, { label: __( 'shipping tax', 'wc-admin' ), - value: formatCurrency( totals.shipping_tax ), + value: formatCurrency( shipping_tax ), }, { - label: _n( 'order', 'orders', totals.orders, 'wc-admin' ), - value: numberFormat( totals.orders_count ), + label: _n( 'order', 'orders', orders_count, 'wc-admin' ), + value: numberFormat( orders_count ), }, ]; } diff --git a/plugins/woocommerce-admin/client/wc-api/reports/utils.js b/plugins/woocommerce-admin/client/wc-api/reports/utils.js index 8a29cc9969d..4c97d42c5ee 100644 --- a/plugins/woocommerce-admin/client/wc-api/reports/utils.js +++ b/plugins/woocommerce-admin/client/wc-api/reports/utils.js @@ -239,7 +239,7 @@ export function getReportChartData( endpoint, dataType, query, select ) { isError: false, isRequesting: false, data: { - totals: null, + totals: {}, intervals: [], }, }; @@ -355,6 +355,7 @@ export function getReportTableData( endpoint, urlQuery, select, query = {} ) { isError: false, items: { data: [], + totalResults: 0, }, };