From d3230d8dae473ffc863e63b547e2ad66ec533fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Tue, 12 Mar 2019 10:50:53 +0100 Subject: [PATCH] Make categories endpoint return zero-value items (https://github.com/woocommerce/woocommerce-admin/pull/1755) * Make categories endpoint return zero-value items * Rename PHP variable to make it more specific * Remove uneeded lines * Remove second parameter from get_ids_table --- ...wc-admin-reports-categories-data-store.php | 67 ++++++++++++++----- .../tests/api/reports-categories.php | 63 +++++++++++++++++ 2 files changed, 113 insertions(+), 17 deletions(-) diff --git a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php index 37f5bd774a9..8dd511a6475 100644 --- a/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php +++ b/plugins/woocommerce-admin/includes/data-stores/class-wc-admin-reports-categories-data-store.php @@ -86,13 +86,15 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store $sql_query_params['from_clause'] .= " LEFT JOIN {$wpdb->prefix}term_relationships ON {$order_product_lookup_table}.product_id = {$wpdb->prefix}term_relationships.object_id"; $sql_query_params['from_clause'] .= " LEFT JOIN {$wpdb->prefix}term_taxonomy ON {$wpdb->prefix}term_relationships.term_taxonomy_id = {$wpdb->prefix}term_taxonomy.term_taxonomy_id"; - // Limit is left out here so that the grouping in code by PHP can be applied correctly. - // This also needs to be put after the term_taxonomy JOIN so that we can match the correct term name. - $sql_query_params = $this->get_order_by_params( $query_args, $sql_query_params ); - $included_categories = $this->get_included_categories( $query_args ); if ( $included_categories ) { $sql_query_params['where_clause'] .= " AND {$wpdb->prefix}term_taxonomy.term_id IN ({$included_categories})"; + + // Limit is left out here so that the grouping in code by PHP can be applied correctly. + // This also needs to be put after the term_taxonomy JOIN so that we can match the correct term name. + $sql_query_params = $this->get_order_by_params( $query_args, $sql_query_params, 'outer_from_clause', 'default_results.id' ); + } else { + $sql_query_params = $this->get_order_by_params( $query_args, $sql_query_params, 'from_clause', "{$wpdb->prefix}term_taxonomy.term_id" ); } // @todo Only products in the category C or orders with products from category C (and, possibly others?). @@ -115,11 +117,13 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store /** * Fills ORDER BY clause of SQL request based on user supplied parameters. * - * @param array $query_args Parameters supplied by the user. - * @param array $sql_query Current SQL query array. + * @param array $query_args Parameters supplied by the user. + * @param array $sql_query Current SQL query array. + * @param string $from_arg Name of the FROM sql param. + * @param string $id_cell ID cell identifier, like `table_name.id_column_name`. * @return array */ - protected function get_order_by_params( $query_args, $sql_query ) { + protected function get_order_by_params( $query_args, $sql_query, $from_arg, $id_cell ) { global $wpdb; $lookup_table = $wpdb->prefix . self::TABLE_NAME; @@ -128,8 +132,9 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store $sql_query['order_by_clause'] = $this->normalize_order_by( $query_args['orderby'] ); } + $sql_query['outer_from_clause'] = ''; if ( false !== strpos( $sql_query['order_by_clause'], '_terms' ) ) { - $sql_query['from_clause'] .= " JOIN {$wpdb->prefix}terms AS _terms ON {$wpdb->prefix}term_taxonomy.term_id = _terms.term_id"; + $sql_query[ $from_arg ] .= " JOIN {$wpdb->prefix}terms AS _terms ON {$id_cell} = _terms.term_id"; } if ( isset( $query_args['order'] ) ) { @@ -157,6 +162,18 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store return $order_by; } + /** + * Returns an array of ids of included categories, based on query arguments from the user. + * + * @param array $query_args Parameters supplied by the user. + * @return string + */ + protected function get_included_categories_array( $query_args ) { + if ( isset( $query_args['categories'] ) && is_array( $query_args['categories'] ) && count( $query_args['categories'] ) > 0 ) { + return $query_args['categories']; + } + return array(); + } /** * Returns comma separated ids of included categories, based on query arguments from the user. @@ -165,12 +182,8 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store * @return string */ protected function get_included_categories( $query_args ) { - $included_categories_str = ''; - - if ( isset( $query_args['categories'] ) && is_array( $query_args['categories'] ) && count( $query_args['categories'] ) > 0 ) { - $included_categories_str = implode( ',', $query_args['categories'] ); - } - return $included_categories_str; + $included_categories = $this->get_included_categories_array( $query_args ); + return implode( ',', $included_categories ); } /** @@ -239,11 +252,28 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store 'page_no' => 0, ); - $selections = $this->selected_columns( $query_args ); - $sql_query_params = $this->get_sql_query_params( $query_args ); + $selections = $this->selected_columns( $query_args ); + $sql_query_params = $this->get_sql_query_params( $query_args ); + $included_categories = $this->get_included_categories_array( $query_args ); + + if ( count( $included_categories ) > 0 ) { + $fields = $this->get_fields( $query_args ); + $join_selections = $this->format_join_selections( array_merge( array( 'category_id' ), $fields ), 'category_id' ); + $ids_table = $this->get_ids_table( $included_categories ); + + $prefix = "SELECT {$join_selections} FROM ("; + $suffix = ") AS {$table_name}"; + $right_join = "RIGHT JOIN ( {$ids_table} ) AS default_results + ON default_results.id = {$table_name}.category_id"; + } else { + $prefix = ''; + $suffix = ''; + $right_join = ''; + } $categories_data = $wpdb->get_results( - "SELECT + "${prefix} + SELECT {$wpdb->prefix}term_taxonomy.term_id as category_id, {$selections} FROM @@ -255,6 +285,9 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store {$sql_query_params['where_clause']} GROUP BY category_id + {$suffix} + {$right_join} + {$sql_query_params['outer_from_clause']} ORDER BY {$sql_query_params['order_by_clause']} ", diff --git a/plugins/woocommerce-admin/tests/api/reports-categories.php b/plugins/woocommerce-admin/tests/api/reports-categories.php index ac14cea7fac..0a629f90c1d 100644 --- a/plugins/woocommerce-admin/tests/api/reports-categories.php +++ b/plugins/woocommerce-admin/tests/api/reports-categories.php @@ -84,6 +84,69 @@ class WC_Tests_API_Reports_Categories extends WC_REST_Unit_Test_Case { $this->assertArrayHasKey( 'category', $category_report['_links'] ); } + /** + * Test getting reports with the `categories` param. + * + * @since 3.5.0 + */ + public function test_get_reports_categories_param() { + WC_Helper_Reports::reset_stats_dbs(); + wp_set_current_user( $this->user ); + + // 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_total( 100 ); // $25 x 4. + $order->save(); + + // Populate all of the data. + $product = new WC_Product_Simple(); + $product->set_name( 'Test Product 2' ); + $product->set_regular_price( 100 ); + $second_category_id = wp_create_category( 'Second Category' ); + $product->set_category_ids( array( $second_category_id ) ); + $product->save(); + + WC_Helper_Queue::run_all_pending(); + + $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' ); + + $request = new WP_REST_Request( 'GET', $this->endpoint ); + $request->set_query_params( + array( + 'categories' => $uncategorized_term->term_id . ',' . $second_category_id, + ) + ); + $response = $this->server->dispatch( $request ); + $reports = $response->get_data(); + + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 2, count( $reports ) ); + + $category_report = reset( $reports ); + + $this->assertEquals( $second_category_id, $category_report['category_id'] ); + $this->assertEquals( 0, $category_report['items_sold'] ); + $this->assertEquals( 0, $category_report['orders_count'] ); + $this->assertEquals( 0, $category_report['products_count'] ); + $this->assertArrayHasKey( '_links', $category_report ); + $this->assertArrayHasKey( 'category', $category_report['_links'] ); + + $category_report = next( $reports ); + + $this->assertEquals( $uncategorized_term->term_id, $category_report['category_id'] ); + $this->assertEquals( 4, $category_report['items_sold'] ); + $this->assertEquals( 1, $category_report['orders_count'] ); + $this->assertEquals( 1, $category_report['products_count'] ); + $this->assertArrayHasKey( '_links', $category_report ); + $this->assertArrayHasKey( 'category', $category_report['_links'] ); + } + /** * Test getting reports without valid permissions. *