From bf0e025b056aa6ee8689ec6a9504af88c4b285d7 Mon Sep 17 00:00:00 2001 From: Paul Sealock Date: Mon, 3 Dec 2018 15:05:25 +1300 Subject: [PATCH] REST API: isolate extened info in /reports/products --- .../client/analytics/report/products/table.js | 5 +- .../dashboard/top-selling-products/index.js | 2 +- .../top-selling-products/test/index.js | 2 +- ...admin-rest-reports-products-controller.php | 2 +- ...s-wc-admin-reports-products-data-store.php | 51 ++++++++-------- .../class-wc-tests-reports-products.php | 59 ++++++++++++++++++- 6 files changed, 92 insertions(+), 29 deletions(-) diff --git a/plugins/woocommerce-admin/client/analytics/report/products/table.js b/plugins/woocommerce-admin/client/analytics/report/products/table.js index 53bdd2bd697..9f2f7fffb4c 100644 --- a/plugins/woocommerce-admin/client/analytics/report/products/table.js +++ b/plugins/woocommerce-admin/client/analytics/report/products/table.js @@ -91,7 +91,7 @@ export default class ProductsReportTable extends Component { const { product_id, sku = '', // @TODO - name, + extended_info, items_sold, gross_revenue, orders_count, @@ -100,6 +100,7 @@ export default class ProductsReportTable extends Component { stock_status = 'outofstock', // @TODO stock_quantity = '0', // @TODO } = row; + const { name } = extended_info; const ordersLink = getNewPath( persistedQuery, 'orders', { filter: 'advanced', product_includes: product_id, @@ -209,7 +210,7 @@ export default class ProductsReportTable extends Component { tableQuery={ { orderby: query.orderby || 'items_sold', order: query.order || 'desc', - extended_product_info: true, + extended_info: true, } } title={ __( 'Products', 'wc-admin' ) } /> diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js b/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js index 9704576ea71..3399f7a9959 100644 --- a/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js +++ b/plugins/woocommerce-admin/client/dashboard/top-selling-products/index.js @@ -127,7 +127,7 @@ export default compose( const endpoint = NAMESPACE + 'reports/products'; // @TODO We will need to add the date parameters from the Date Picker // { after: '2018-04-22', before: '2018-05-06' } - const query = { orderby: 'items_sold', per_page: 5, extended_product_info: 1 }; + const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 }; const stats = getReportStats( endpoint, query ); const isRequesting = isReportStatsRequesting( endpoint, query ); diff --git a/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js b/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js index b368cc11079..e71be4c8c07 100644 --- a/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js +++ b/plugins/woocommerce-admin/client/dashboard/top-selling-products/test/index.js @@ -68,7 +68,7 @@ describe( 'TopSellingProducts', () => { const topSellingProducts = topSellingProductsWrapper.root.findByType( TopSellingProducts ); const endpoint = '/wc/v3/reports/products'; - const query = { orderby: 'items_sold', per_page: 5, extended_product_info: 1 }; + const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 }; expect( getReportStatsMock.mock.calls[ 0 ][ 1 ] ).toBe( endpoint ); expect( getReportStatsMock.mock.calls[ 0 ][ 2 ] ).toEqual( query ); diff --git a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php index b73dba30d1c..80e89366f96 100644 --- a/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php +++ b/plugins/woocommerce-admin/includes/api/class-wc-admin-rest-reports-products-controller.php @@ -243,7 +243,7 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll 'type' => 'integer', ), ); - $params['extended_product_info'] = array( + $params['extended_info'] = array( 'description' => __( 'Add additional piece of info about each product to the report.', 'wc-admin' ), 'type' => 'boolean', 'default' => false, 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 81e255abc2d..d6611058714 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 @@ -142,18 +142,24 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i * Enriches the product data with attributes specified by the extended_attributes. * * @param array $products_data Product data. + * @param array $query_args Query parameters. */ - protected function include_extended_product_info( &$products_data ) { + protected function include_extended_info( &$products_data, $query_args ) { foreach ( $products_data as $key => $product_data ) { - $product = wc_get_product( $product_data['product_id'] ); - $extended_attributes = apply_filters( 'woocommerce_rest_reports_products_extended_attributes', $this->extended_attributes, $product_data ); - foreach ( $extended_attributes as $extended_attribute ) { - $function = 'get_' . $extended_attribute; - if ( is_callable( array( $product, $function ) ) ) { - $value = $product->{$function}(); - $products_data[ $key ][ $extended_attribute ] = $value; + $extended_info = new ArrayObject(); + if ( $query_args['extended_info'] ) { + $product = wc_get_product( $product_data['product_id'] ); + $extended_attributes = apply_filters( 'woocommerce_rest_reports_products_extended_attributes', $this->extended_attributes, $product_data ); + foreach ( $extended_attributes as $extended_attribute ) { + $function = 'get_' . $extended_attribute; + if ( is_callable( array( $product, $function ) ) ) { + $value = $product->{$function}(); + $extended_info[ $extended_attribute ] = $value; + } } + $extended_info = $this->cast_numbers( $extended_info ); } + $products_data[ $key ]['extended_info'] = $extended_info; } } @@ -172,18 +178,18 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i // These defaults are only partially applied when used via REST API, as that has its own defaults. $defaults = array( - 'per_page' => get_option( 'posts_per_page' ), - 'page' => 1, - 'order' => 'DESC', - 'orderby' => 'date', - 'before' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $now ), - 'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ), - 'fields' => '*', - 'categories' => array(), - 'products' => array(), - 'extended_product_info' => false, + 'per_page' => get_option( 'posts_per_page' ), + 'page' => 1, + 'order' => 'DESC', + 'orderby' => 'date', + 'before' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $now ), + 'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ), + 'fields' => '*', + 'categories' => array(), + 'products' => array(), + 'extended_info' => false, // This is not a parameter for products reports per se, but we want to only take into account selected order types. - 'order_status' => parent::get_report_order_statuses(), + 'order_status' => parent::get_report_order_statuses(), ); $query_args = wp_parse_args( $query_args, $defaults ); @@ -192,7 +198,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i $data = wp_cache_get( $cache_key, $this->cache_group ); if ( false === $data ) { - $data = (object) array( + $data = (object) array( 'data' => array(), 'total' => 0, 'pages' => 0, @@ -244,9 +250,8 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i return $data; } - if ( $query_args['extended_product_info'] ) { - $this->include_extended_product_info( $product_data ); - } + $this->include_extended_info( $product_data, $query_args ); + $product_data = array_map( array( $this, 'cast_numbers' ), $product_data ); $data = (object) array( 'data' => $product_data, 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 da3eabd978a..b82e8d06085 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 @@ -52,6 +52,7 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { 'items_sold' => 4, 'gross_revenue' => 100.0, // $25 * 4. 'orders_count' => 1, + 'extended_info' => new ArrayObject(), ), ), ); @@ -76,7 +77,7 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { $product_2->set_regular_price( 20 ); $product_2->save(); - $date_created = time(); + $date_created = time(); $date_created_2 = $date_created + 5; $order = WC_Helper_Order::create_order( 1, $product ); @@ -121,12 +122,14 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { 'items_sold' => 4, 'gross_revenue' => 80.0, // $20 * 4. 'orders_count' => 1, + 'extended_info' => new ArrayObject(), ), 1 => array( 'product_id' => $product->get_id(), 'items_sold' => 4, 'gross_revenue' => 100.0, // $25 * 4. 'orders_count' => 1, + 'extended_info' => new ArrayObject(), ), ), ); @@ -151,12 +154,14 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { 'items_sold' => 4, 'gross_revenue' => 100.0, // $25 * 4. 'orders_count' => 1, + 'extended_info' => new ArrayObject(), ), 1 => array( 'product_id' => $product_2->get_id(), 'items_sold' => 4, 'gross_revenue' => 80.0, // $20 * 4. 'orders_count' => 1, + 'extended_info' => new ArrayObject(), ), ), ); @@ -167,4 +172,56 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case { $this->assertEquals( $expected_data, $query->get_data() ); } + /** + * Test the extended info. + * + * @since 3.5.0 + */ + public function test_extended_info() { + 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(); + $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, + 'extended_info' => 1, + ); + // 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' => 4, + 'gross_revenue' => 100.0, // $25 * 4. + 'orders_count' => 1, + 'extended_info' => array( + 'name' => $product->get_name(), + 'image' => $product->get_image(), + 'permalink' => $product->get_permalink(), + 'price' => (float) $product->get_price(), + ), + ), + ), + ); + $this->assertEquals( $expected_data, $data ); + } }