Merge pull request woocommerce/woocommerce-admin#943 from woocommerce/fix/749

Adding support for advanced filters in orders reports.
This commit is contained in:
Peter Fabian 2018-12-04 12:19:51 +01:00 committed by GitHub
commit 22fa3f5b05
16 changed files with 3359 additions and 292 deletions

View File

@ -116,7 +116,7 @@ export const advancedFilters = {
} ) ), } ) ),
}, },
}, },
code: { coupon: {
labels: { labels: {
add: __( 'Coupon Codes', 'wc-admin' ), add: __( 'Coupon Codes', 'wc-admin' ),
placeholder: __( 'Search coupons', 'wc-admin' ), placeholder: __( 'Search coupons', 'wc-admin' ),

View File

@ -47,6 +47,8 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro
$args['orderby'] = $request['orderby']; $args['orderby'] = $request['orderby'];
$args['order'] = $request['order']; $args['order'] = $request['order'];
$args['categories'] = (array) $request['categories']; $args['categories'] = (array) $request['categories'];
$args['status_is'] = (array) $request['status_is'];
$args['status_is_not'] = (array) $request['status_is_not'];
return $args; return $args;
} }
@ -265,6 +267,26 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro
), ),
'validate_callback' => 'rest_validate_request_arg', 'validate_callback' => 'rest_validate_request_arg',
); );
$params['status_is'] = array(
'description' => __( 'Limit result set to items that have the specified order status.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_slug_list',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'enum' => $this->get_order_statuses(),
'type' => 'string',
),
);
$params['status_is_not'] = array(
'description' => __( 'Limit result set to items that don\'t have the specified order status.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_slug_list',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'enum' => $this->get_order_statuses(),
'type' => 'string',
),
);
$params['categories'] = array( $params['categories'] = array(
'description' => __( 'Limit result set to all items that have the specified term assigned in the categories taxonomy.', 'wc-admin' ), 'description' => __( 'Limit result set to all items that have the specified term assigned in the categories taxonomy.', 'wc-admin' ),
'type' => 'array', 'type' => 'array',
@ -277,4 +299,19 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro
return $params; return $params;
} }
/**
* Get order statuses without prefixes.
*
* @return array
*/
protected function get_order_statuses() {
$order_statuses = array();
foreach ( array_keys( wc_get_order_statuses() ) as $status ) {
$order_statuses[] = str_replace( 'wc-', '', $status );
}
return $order_statuses;
}
} }

View File

@ -46,10 +46,16 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
$args['per_page'] = $request['per_page']; $args['per_page'] = $request['per_page'];
$args['orderby'] = $request['orderby']; $args['orderby'] = $request['orderby'];
$args['order'] = $request['order']; $args['order'] = $request['order'];
$args['match'] = $request['match'];
$args['status_is'] = (array) $request['status_is'];
$args['status_is_not'] = (array) $request['status_is_not'];
$args['product_includes'] = (array) $request['product_includes'];
$args['product_excludes'] = (array) $request['product_excludes'];
$args['coupon_includes'] = (array) $request['coupon_includes'];
$args['coupon_excludes'] = (array) $request['coupon_excludes'];
$args['customer'] = $request['customer'];
$args['categories'] = (array) $request['categories']; $args['categories'] = (array) $request['categories'];
$args['coupons'] = (array) $request['coupons'];
$args['products'] = (array) $request['products'];
$args['order_status'] = (array) $request['order_status'];
return $args; return $args;
} }
@ -298,27 +304,18 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
), ),
'validate_callback' => 'rest_validate_request_arg', 'validate_callback' => 'rest_validate_request_arg',
); );
$params['categories'] = array( $params['match'] = array(
'description' => __( 'Limit result set to all items that have the specified term assigned in the categories taxonomy.', 'wc-admin' ), 'description' => __( 'Indicates whether all the conditions should be true for the resulting set, or if any one of them is sufficient. Match affects the following parameters: status_is, status_is_not, product_includes, product_excludes, coupon_includes, coupon_excludes, customer, categories', 'wc-admin' ),
'type' => 'string', 'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list', 'default' => 'all',
'enum' => array(
'all',
'any',
),
'validate_callback' => 'rest_validate_request_arg', 'validate_callback' => 'rest_validate_request_arg',
); );
$params['coupons'] = array( $params['status_is'] = array(
'description' => __( 'Limit result set to all items that have the specified coupon assigned.', 'wc-admin' ), 'description' => __( 'Limit result set to items that have the specified order status.', 'wc-admin' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['products'] = array(
'description' => __( 'Limit result set to all items that have the specified product assigned.', 'wc-admin' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order_status'] = array(
'default' => array( 'completed', 'processing', 'on-hold' ),
'description' => __( 'Limit result set to orders assigned one or more statuses', 'wc-admin' ),
'type' => 'array', 'type' => 'array',
'sanitize_callback' => 'wp_parse_slug_list', 'sanitize_callback' => 'wp_parse_slug_list',
'validate_callback' => 'rest_validate_request_arg', 'validate_callback' => 'rest_validate_request_arg',
@ -327,6 +324,62 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
'type' => 'string', 'type' => 'string',
), ),
); );
$params['status_is_not'] = array(
'description' => __( 'Limit result set to items that don\'t have the specified order status.', 'wc-admin' ),
'type' => 'array',
'sanitize_callback' => 'wp_parse_slug_list',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'enum' => $this->get_order_statuses(),
'type' => 'string',
),
);
$params['product_includes'] = array(
'description' => __( 'Limit result set to items that have the specified product(s) assigned.', 'wc-admin' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['product_excludes'] = array(
'description' => __( 'Limit result set to items that don\'t have the specified product(s) assigned.', 'wc-admin' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['coupon_includes'] = array(
'description' => __( 'Limit result set to items that have the specified coupon(s) assigned.', 'wc-admin' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['coupon_excludes'] = array(
'description' => __( 'Limit result set to items that don\'t have the specified coupon(s) assigned.', 'wc-admin' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
'default' => array(),
'sanitize_callback' => 'wp_parse_id_list',
);
$params['customer'] = array(
'description' => __( 'Limit result set to items that don\'t have the specified coupon(s) assigned.', 'wc-admin' ),
'type' => 'string',
'enum' => array(
'new',
'returning',
),
'validate_callback' => 'rest_validate_request_arg',
);
return $params; return $params;
} }

View File

@ -31,6 +31,15 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
*/ */
protected $rest_base = 'reports/products'; protected $rest_base = 'reports/products';
/**
* Mapping between external parameter name and name used in query class.
*
* @var array
*/
protected $param_mapping = array(
'products' => 'product_includes',
);
/** /**
* Get items. * Get items.
* *
@ -43,9 +52,13 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
$registered = array_keys( $this->get_collection_params() ); $registered = array_keys( $this->get_collection_params() );
foreach ( $registered as $param_name ) { foreach ( $registered as $param_name ) {
if ( isset( $request[ $param_name ] ) ) { if ( isset( $request[ $param_name ] ) ) {
if ( isset( $this->param_mapping[ $param_name ] ) ) {
$args[ $this->param_mapping[ $param_name ] ] = $request[ $param_name ];
} else {
$args[ $param_name ] = $request[ $param_name ]; $args[ $param_name ] = $request[ $param_name ];
} }
} }
}
$reports = new WC_Admin_Reports_Products_Query( $args ); $reports = new WC_Admin_Reports_Products_Query( $args );
$products_data = $reports->get_data(); $products_data = $reports->get_data();
@ -234,6 +247,16 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
'type' => 'integer', 'type' => 'integer',
), ),
); );
$params['match'] = array(
'description' => __( 'Indicates whether all the conditions should be true for the resulting set, or if any one of them is sufficient. Match affects the following parameters: status_is, status_is_not, product_includes, product_excludes, coupon_includes, coupon_excludes, customer, categories', 'wc-admin' ),
'type' => 'string',
'default' => 'all',
'enum' => array(
'all',
'any',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['products'] = array( $params['products'] = array(
'description' => __( 'Limit result to items with specified product ids.', 'wc-admin' ), 'description' => __( 'Limit result to items with specified product ids.', 'wc-admin' ),
'type' => 'array', 'type' => 'array',
@ -242,6 +265,7 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
'items' => array( 'items' => array(
'type' => 'integer', 'type' => 'integer',
), ),
); );
$params['extended_info'] = array( $params['extended_info'] = array(
'description' => __( 'Add additional piece of info about each product to the report.', 'wc-admin' ), 'description' => __( 'Add additional piece of info about each product to the report.', 'wc-admin' ),

View File

@ -31,6 +31,15 @@ class WC_Admin_REST_Reports_Products_Stats_Controller extends WC_REST_Reports_Co
*/ */
protected $rest_base = 'reports/products/stats'; protected $rest_base = 'reports/products/stats';
/**
* Mapping between external parameter name and name used in query class.
*
* @var array
*/
protected $param_mapping = array(
'products' => 'product_includes',
);
/** /**
* Constructor. * Constructor.
*/ */
@ -54,9 +63,14 @@ class WC_Admin_REST_Reports_Products_Stats_Controller extends WC_REST_Reports_Co
), ),
); );
foreach ( array_keys( $this->get_collection_params() ) as $arg ) { $registered = array_keys( $this->get_collection_params() );
if ( isset( $request[ $arg ] ) ) { foreach ( $registered as $param_name ) {
$query_args[ $arg ] = $request[ $arg ]; if ( isset( $request[ $param_name ] ) ) {
if ( isset( $this->param_mapping[ $param_name ] ) ) {
$query_args[ $this->param_mapping[ $param_name ] ] = $request[ $param_name ];
} else {
$query_args[ $param_name ] = $request[ $param_name ];
}
} }
} }

View File

@ -173,8 +173,23 @@ class WC_Admin_REST_Reports_Revenue_Stats_Controller extends WC_REST_Reports_Con
'context' => array( 'view', 'edit' ), 'context' => array( 'view', 'edit' ),
'readonly' => true, 'readonly' => true,
), ),
'num_items_sold' => array(
'description' => __( 'Amount of orders', 'wc-admin' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'products' => array(
'description' => __( 'Amount of orders', 'wc-admin' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
); );
$intervals = $totals;
unset( $intervals['products'] );
$schema = array( $schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#', '$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'report_revenue_stats', 'title' => 'report_revenue_stats',
@ -231,7 +246,7 @@ class WC_Admin_REST_Reports_Revenue_Stats_Controller extends WC_REST_Reports_Con
'type' => 'object', 'type' => 'object',
'context' => array( 'view', 'edit' ), 'context' => array( 'view', 'edit' ),
'readonly' => true, 'readonly' => true,
'properties' => $totals, 'properties' => $intervals,
), ),
), ),
), ),

View File

@ -350,7 +350,7 @@ class WC_Admin_Api_Init {
coupon_id BIGINT UNSIGNED NOT NULL, coupon_id BIGINT UNSIGNED NOT NULL,
date_created timestamp DEFAULT '0000-00-00 00:00:00' NOT NULL, date_created timestamp DEFAULT '0000-00-00 00:00:00' NOT NULL,
coupon_gross_discount double DEFAULT 0 NOT NULL, coupon_gross_discount double DEFAULT 0 NOT NULL,
KEY order_id (order_id), PRIMARY KEY (order_id, coupon_id),
KEY coupon_id (coupon_id), KEY coupon_id (coupon_id),
KEY date_created (date_created) KEY date_created (date_created)
) $collate; ) $collate;

View File

@ -67,25 +67,22 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store
*/ */
protected function get_sql_query_params( $query_args ) { protected function get_sql_query_params( $query_args ) {
global $wpdb; global $wpdb;
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
$sql_query_params = $this->get_time_period_sql_params( $query_args ); $sql_query_params = $this->get_time_period_sql_params( $query_args, $order_product_lookup_table );
// Limit is left out here so that the grouping in code by PHP can be applied correctly. // Limit is left out here so that the grouping in code by PHP can be applied correctly.
$sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) ); $sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) );
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME; // TODO: only products in the category C or orders with products from category C (and, possibly others?).
$included_products = $this->get_included_products( $query_args );
$allowed_products = $this->get_allowed_products( $query_args ); if ( $included_products ) {
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$included_products})";
if ( count( $allowed_products ) > 0 ) {
$allowed_products_str = implode( ',', $allowed_products );
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$allowed_products_str})";
} }
if ( is_array( $query_args['order_status'] ) && count( $query_args['order_status'] ) > 0 ) { $order_status_filter = $this->get_status_subquery( $query_args );
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] ); if ( $order_status_filter ) {
$sql_query_params['from_clause'] .= " JOIN {$wpdb->prefix}posts ON {$order_product_lookup_table}.order_id = {$wpdb->prefix}posts.ID"; $sql_query_params['from_clause'] .= " JOIN {$wpdb->prefix}posts ON {$order_product_lookup_table}.order_id = {$wpdb->prefix}posts.ID";
$sql_query_params['where_clause'] .= " AND {$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $statuses ) . "' ) "; $sql_query_params['where_clause'] .= " AND ( {$order_status_filter} )";
} }
return $sql_query_params; return $sql_query_params;
@ -204,6 +201,7 @@ class WC_Admin_Reports_Categories_Data_Store extends WC_Admin_Reports_Data_Store
{$sql_query_params['from_clause']} {$sql_query_params['from_clause']}
WHERE WHERE
1=1 1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']} {$sql_query_params['where_clause']}
GROUP BY GROUP BY
product_id product_id

View File

@ -121,6 +121,8 @@ class WC_Admin_Reports_Data_Store {
foreach ( $totals_arr as $key => $val ) { foreach ( $totals_arr as $key => $val ) {
$totals_arr[ $key ] = 0; $totals_arr[ $key ] = 0;
} }
// TODO: should 'products' be in intervals?
unset( $totals_arr['products'] );
while ( $datetime <= $end_datetime ) { while ( $datetime <= $end_datetime ) {
$next_start = WC_Admin_Reports_Interval::iterate( $datetime, $time_interval ); $next_start = WC_Admin_Reports_Interval::iterate( $datetime, $time_interval );
$time_id = WC_Admin_Reports_Interval::time_interval_id( $time_interval, $datetime ); $time_id = WC_Admin_Reports_Interval::time_interval_id( $time_interval, $datetime );
@ -260,9 +262,9 @@ class WC_Admin_Reports_Data_Store {
} }
$query_args['adj_after'] = $new_start_date->format( WC_Admin_Reports_Interval::$iso_datetime_format ); $query_args['adj_after'] = $new_start_date->format( WC_Admin_Reports_Interval::$iso_datetime_format );
$query_args['adj_before'] = $new_end_date->format( WC_Admin_Reports_Interval::$iso_datetime_format ); $query_args['adj_before'] = $new_end_date->format( WC_Admin_Reports_Interval::$iso_datetime_format );
$intervals_query['where_clause'] = ''; $intervals_query['where_time_clause'] = '';
$intervals_query['where_clause'] .= " AND date_created <= '{$query_args['adj_before']}'"; $intervals_query['where_time_clause'] .= " AND date_created <= '{$query_args['adj_before']}'";
$intervals_query['where_clause'] .= " AND date_created >= '{$query_args['adj_after']}'"; $intervals_query['where_time_clause'] .= " AND date_created >= '{$query_args['adj_after']}'";
$intervals_query['limit'] = 'LIMIT 0,' . $intervals_query['per_page']; $intervals_query['limit'] = 'LIMIT 0,' . $intervals_query['per_page'];
} else { } else {
if ( 'asc' === $query_args['order'] ) { if ( 'asc' === $query_args['order'] ) {
@ -425,28 +427,30 @@ class WC_Admin_Reports_Data_Store {
} }
/** /**
* Fills WHERE clause of SQL request for 'Totals' section of data response based on user supplied parameters. * Fills WHERE clause of SQL request with date-related constraints.
* *
* @param array $query_args Parameters supplied by the user. * @param array $query_args Parameters supplied by the user.
* @param string $table_name Name of the db table relevant for the date constraint.
* @return array * @return array
*/ */
protected function get_time_period_sql_params( $query_args ) { protected function get_time_period_sql_params( $query_args, $table_name ) {
$sql_query = array( $sql_query = array(
'from_clause' => '', 'from_clause' => '',
'where_time_clause' => '',
'where_clause' => '', 'where_clause' => '',
); );
if ( isset( $query_args['before'] ) && '' !== $query_args['before'] ) { if ( isset( $query_args['before'] ) && '' !== $query_args['before'] ) {
$datetime = new DateTime( $query_args['before'] ); $datetime = new DateTime( $query_args['before'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format ); $datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_clause'] .= " AND date_created <= '$datetime_str'"; $sql_query['where_time_clause'] .= " AND {$table_name}.date_created <= '$datetime_str'";
} }
if ( isset( $query_args['after'] ) && '' !== $query_args['after'] ) { if ( isset( $query_args['after'] ) && '' !== $query_args['after'] ) {
$datetime = new DateTime( $query_args['after'] ); $datetime = new DateTime( $query_args['after'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format ); $datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_clause'] .= " AND date_created >= '$datetime_str'"; $sql_query['where_time_clause'] .= " AND {$table_name}.date_created >= '$datetime_str'";
} }
return $sql_query; return $sql_query;
@ -498,15 +502,17 @@ class WC_Admin_Reports_Data_Store {
* Fills FROM and WHERE clauses of SQL request for 'Intervals' section of data response based on user supplied parameters. * Fills FROM and WHERE clauses of SQL request for 'Intervals' section of data response based on user supplied parameters.
* *
* @param array $query_args Parameters supplied by the user. * @param array $query_args Parameters supplied by the user.
* @param string $table_name Name of the db table relevant for the date constraint.
* @return array * @return array
*/ */
protected function get_intervals_sql_params( $query_args ) { protected function get_intervals_sql_params( $query_args, $table_name ) {
$intervals_query = array( $intervals_query = array(
'from_clause' => '', 'from_clause' => '',
'where_time_clause' => '',
'where_clause' => '', 'where_clause' => '',
); );
$intervals_query = array_merge( $intervals_query, $this->get_time_period_sql_params( $query_args ) ); $intervals_query = array_merge( $intervals_query, $this->get_time_period_sql_params( $query_args, $table_name ) );
if ( isset( $query_args['interval'] ) && '' !== $query_args['interval'] ) { if ( isset( $query_args['interval'] ) && '' !== $query_args['interval'] ) {
$interval = $query_args['interval']; $interval = $query_args['interval'];
@ -548,26 +554,151 @@ class WC_Admin_Reports_Data_Store {
} }
/** /**
* Returns ids of allowed products, based on query arguments from the user. * Returns comma separated ids of allowed products, based on query arguments from the user.
* *
* @param array $query_args Parameters supplied by the user. * @param array $query_args Parameters supplied by the user.
* @return array * @return string
*/ */
protected function get_allowed_products( $query_args ) { protected function get_included_products( $query_args ) {
$allowed_products = array(); $included_products = array();
$operator = $this->get_match_operator( $query_args );
if ( isset( $query_args['categories'] ) && is_array( $query_args['categories'] ) && count( $query_args['categories'] ) > 0 ) { if ( isset( $query_args['categories'] ) && is_array( $query_args['categories'] ) && count( $query_args['categories'] ) > 0 ) {
$allowed_products = $this->get_products_by_cat_ids( $query_args['categories'] ); $included_products = $this->get_products_by_cat_ids( $query_args['categories'] );
$allowed_products = wc_list_pluck( $allowed_products, 'get_id' ); $included_products = wc_list_pluck( $included_products, 'get_id' );
} }
if ( isset( $query_args['products'] ) && is_array( $query_args['products'] ) && count( $query_args['products'] ) > 0 ) { if ( isset( $query_args['product_includes'] ) && is_array( $query_args['product_includes'] ) && count( $query_args['product_includes'] ) > 0 ) {
if ( count( $allowed_products ) > 0 ) { if ( count( $included_products ) > 0 ) {
$allowed_products = array_intersect( $allowed_products, $query_args['products'] ); if ( 'AND' === $operator ) {
$included_products = array_intersect( $included_products, $query_args['product_includes'] );
} elseif ( 'OR' === $operator ) {
// Union of products from selected categories and manually included products.
$included_products = array_unique( array_merge( $included_products, $query_args['product_includes'] ) );
}
} else { } else {
$allowed_products = $query_args['products']; $included_products = $query_args['product_includes'];
} }
} }
return $allowed_products;
$included_products_str = implode( ',', $included_products );
return $included_products_str;
}
/**
* Returns comma separated ids of excluded products, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_excluded_products( $query_args ) {
$excluded_products_str = '';
if ( isset( $query_args['product_excludes'] ) && is_array( $query_args['product_excludes'] ) && count( $query_args['product_excludes'] ) > 0 ) {
$excluded_products_str = implode( ',', $query_args['product_excludes'] );
}
return $excluded_products_str;
}
/**
* Returns comma separated ids of included coupons, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_included_coupons( $query_args ) {
$included_coupons_str = '';
if ( isset( $query_args['coupon_includes'] ) && is_array( $query_args['coupon_includes'] ) && count( $query_args['coupon_includes'] ) > 0 ) {
$included_coupons_str = implode( ',', $query_args['coupon_includes'] );
}
return $included_coupons_str;
}
/**
* Returns comma separated ids of excluded coupons, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_excluded_coupons( $query_args ) {
$excluded_coupons_str = '';
if ( isset( $query_args['coupon_excludes'] ) && is_array( $query_args['coupon_excludes'] ) && count( $query_args['coupon_excludes'] ) > 0 ) {
$excluded_coupons_str = implode( ',', $query_args['coupon_excludes'] );
}
return $excluded_coupons_str;
}
/**
* Returns order status subquery to be used in WHERE SQL query, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @param string $operator AND or OR, based on match query argument.
* @return string
*/
protected function get_status_subquery( $query_args, $operator = 'AND' ) {
global $wpdb;
$subqueries = array();
if ( isset( $query_args['status_is'] ) && is_array( $query_args['status_is'] ) && count( $query_args['status_is'] ) > 0 ) {
$allowed_statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['status_is'] );
if ( $allowed_statuses ) {
$subqueries[] = "{$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $allowed_statuses ) . "' )";
}
}
if ( isset( $query_args['status_is_not'] ) && is_array( $query_args['status_is_not'] ) && count( $query_args['status_is_not'] ) > 0 ) {
$forbidden_statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['status_is_not'] );
if ( $forbidden_statuses ) {
$subqueries[] = "{$wpdb->prefix}posts.post_status NOT IN ( '" . implode( "','", $forbidden_statuses ) . "' )";
}
}
return implode( " $operator ", $subqueries );
}
/**
* Returns customer subquery to be used in WHERE SQL query, based on query arguments from the user.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_customer_subquery( $query_args ) {
global $wpdb;
$customer_filter = '';
if ( isset( $query_args['customer'] ) ) {
if ( 'new' === strtolower( $query_args['customer'] ) ) {
$customer_filter = " {$wpdb->prefix}wc_order_stats.returning_customer = 0";
} elseif ( 'returning' === strtolower( $query_args['customer'] ) ) {
$customer_filter = " {$wpdb->prefix}wc_order_stats.returning_customer = 1";
}
}
return $customer_filter;
}
/**
* Returns logic operator for WHERE subclause based on 'match' query argument.
*
* @param array $query_args Parameters supplied by the user.
* @return string
*/
protected function get_match_operator( $query_args ) {
$operator = 'AND';
if ( ! isset( $query_args['match'] ) ) {
return $operator;
}
if ( 'all' === strtolower( $query_args['match'] ) ) {
$operator = 'AND';
} elseif ( 'any' === strtolower( $query_args['match'] ) ) {
$operator = 'OR';
}
return $operator;
} }
} }

View File

@ -48,6 +48,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
'avg_order_value' => 'floatval', 'avg_order_value' => 'floatval',
'num_returning_customers' => 'intval', 'num_returning_customers' => 'intval',
'num_new_customers' => 'intval', 'num_new_customers' => 'intval',
'products' => 'intval',
); );
/** /**
@ -91,6 +92,8 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
*/ */
public static function init() { public static function init() {
add_action( 'save_post', array( __CLASS__, 'sync_order' ) ); 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' ) );
if ( ! self::$background_process ) { if ( ! self::$background_process ) {
self::$background_process = new WC_Admin_Order_Stats_Background_Process(); self::$background_process = new WC_Admin_Order_Stats_Background_Process();
@ -173,51 +176,85 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
// TODO: performance of all of this? // TODO: performance of all of this?
global $wpdb; global $wpdb;
$where_clause = '';
$from_clause = ''; $from_clause = '';
$orders_stats_table = $wpdb->prefix . self::TABLE_NAME; $orders_stats_table = $wpdb->prefix . self::TABLE_NAME;
$allowed_products = $this->get_allowed_products( $query_args ); $operator = $this->get_match_operator( $query_args );
if ( count( $allowed_products ) > 0 ) { $where_filters = array();
$allowed_products_str = implode( ',', $allowed_products );
$where_clause .= " AND {$orders_stats_table}.order_id IN ( // TODO: maybe move the sql inside the get_included/excluded functions?
// Products filters.
$included_products = $this->get_included_products( $query_args );
$excluded_products = $this->get_excluded_products( $query_args );
if ( $included_products ) {
$where_filters[] = " {$orders_stats_table}.order_id IN (
SELECT SELECT
DISTINCT {$wpdb->prefix}wc_order_product_lookup.order_id DISTINCT {$wpdb->prefix}wc_order_product_lookup.order_id
FROM FROM
{$wpdb->prefix}wc_order_product_lookup {$wpdb->prefix}wc_order_product_lookup
WHERE WHERE
{$wpdb->prefix}wc_order_product_lookup.product_id IN ({$allowed_products_str}) {$wpdb->prefix}wc_order_product_lookup.product_id IN ({$included_products})
)"; )";
} }
if ( is_array( $query_args['coupons'] ) && count( $query_args['coupons'] ) > 0 ) { if ( $excluded_products ) {
$allowed_coupons_str = implode( ', ', $query_args['coupons'] ); $where_filters[] = " {$orders_stats_table}.order_id NOT IN (
SELECT
DISTINCT {$wpdb->prefix}wc_order_product_lookup.order_id
FROM
{$wpdb->prefix}wc_order_product_lookup
WHERE
{$wpdb->prefix}wc_order_product_lookup.product_id IN ({$excluded_products})
)";
}
$where_clause .= " AND {$orders_stats_table}.order_id IN ( // Coupons filters.
$included_coupons = $this->get_included_coupons( $query_args );
$excluded_coupons = $this->get_excluded_coupons( $query_args );
if ( $included_coupons ) {
$where_filters[] = " {$orders_stats_table}.order_id IN (
SELECT SELECT
DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id
FROM FROM
{$wpdb->prefix}wc_order_coupon_lookup {$wpdb->prefix}wc_order_coupon_lookup
WHERE WHERE
{$wpdb->prefix}wc_order_coupon_lookup.coupon_id IN ({$allowed_coupons_str}) {$wpdb->prefix}wc_order_coupon_lookup.coupon_id IN ({$included_coupons})
)"; )";
} }
if ( is_array( $query_args['order_status'] ) && count( $query_args['order_status'] ) > 0 ) { if ( $excluded_coupons ) {
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] ); $where_filters[] = " {$orders_stats_table}.order_id NOT IN (
SELECT
$from_clause .= " JOIN {$wpdb->prefix}posts ON {$orders_stats_table}.order_id = {$wpdb->prefix}posts.ID"; DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id
$where_clause .= " AND {$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $statuses ) . "' ) "; FROM
{$wpdb->prefix}wc_order_coupon_lookup
WHERE
{$wpdb->prefix}wc_order_coupon_lookup.coupon_id IN ({$excluded_coupons})
)";
} }
// TODO: move order status to wc_order_stats so that JOIN is not necessary.
$order_status_filter = $this->get_status_subquery( $query_args, $operator );
if ( $order_status_filter ) {
$from_clause .= " JOIN {$wpdb->prefix}posts ON {$orders_stats_table}.order_id = {$wpdb->prefix}posts.ID";
$where_filters[] = $order_status_filter;
}
$customer_filter = $this->get_customer_subquery( $query_args );
if ( $customer_filter ) {
$where_filters[] = $customer_filter;
}
$where_subclause = implode( " $operator ", $where_filters );
// To avoid requesting the subqueries twice, the result is applied to all queries passed to the method. // To avoid requesting the subqueries twice, the result is applied to all queries passed to the method.
$totals_query['where_clause'] .= $where_clause; if ( $where_subclause ) {
$totals_query['where_clause'] .= " AND ( $where_subclause )";
$totals_query['from_clause'] .= $from_clause; $totals_query['from_clause'] .= $from_clause;
$intervals_query['where_clause'] .= $where_clause; $intervals_query['where_clause'] .= " AND ( $where_subclause )";
$intervals_query['from_clause'] .= $from_clause; $intervals_query['from_clause'] .= $from_clause;
} }
}
/** /**
* Returns the report data based on parameters supplied by the user. * Returns the report data based on parameters supplied by the user.
@ -243,10 +280,16 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ), 'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ),
'interval' => 'week', 'interval' => 'week',
'fields' => '*', 'fields' => '*',
'match' => 'all',
'status_is' => array(),
'status_is_not' => array(),
'product_includes' => array(),
'product_excludes' => array(),
'coupon_includes' => array(),
'coupon_excludes' => array(),
'customer' => '',
'categories' => array(), 'categories' => array(),
'coupons' => array(),
'order_status' => parent::get_report_order_statuses(),
'products' => array(),
); );
$query_args = wp_parse_args( $query_args, $defaults ); $query_args = wp_parse_args( $query_args, $defaults );
@ -263,8 +306,8 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
); );
$selections = $this->selected_columns( $query_args ); $selections = $this->selected_columns( $query_args );
$totals_query = $this->get_time_period_sql_params( $query_args ); $totals_query = $this->get_time_period_sql_params( $query_args, $table_name );
$intervals_query = $this->get_intervals_sql_params( $query_args ); $intervals_query = $this->get_intervals_sql_params( $query_args, $table_name );
// Additional filtering for Orders report. // Additional filtering for Orders report.
$this->orders_stats_sql_filter( $query_args, $totals_query, $intervals_query ); $this->orders_stats_sql_filter( $query_args, $totals_query, $intervals_query );
@ -277,6 +320,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
{$totals_query['from_clause']} {$totals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$totals_query['where_time_clause']}
{$totals_query['where_clause']}", {$totals_query['where_clause']}",
ARRAY_A ARRAY_A
); // WPCS: cache ok, DB call ok, unprepared SQL ok. ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
@ -284,13 +328,9 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
return new WP_Error( 'woocommerce_reports_revenue_result_failed', __( 'Sorry, fetching revenue data failed.', 'wc-admin' ) ); return new WP_Error( 'woocommerce_reports_revenue_result_failed', __( 'Sorry, fetching revenue data failed.', 'wc-admin' ) );
} }
$unique_products = $this->get_unique_products( $totals_query['where_clause'] ); $unique_products = $this->get_unique_product_count( $totals_query['from_clause'], $totals_query['where_time_clause'], $totals_query['where_clause'] );
$totals[0]['products'] = $unique_products; $totals[0]['products'] = $unique_products;
// Specification says these are not included in totals.
unset( $totals[0]['date_start'] );
unset( $totals[0]['date_end'] );
$totals = (object) $this->cast_numbers( $totals[0] ); $totals = (object) $this->cast_numbers( $totals[0] );
$db_intervals = $wpdb->get_col( $db_intervals = $wpdb->get_col(
@ -301,6 +341,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
{$intervals_query['from_clause']} {$intervals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']} {$intervals_query['where_clause']}
GROUP BY GROUP BY
time_interval" time_interval"
@ -330,6 +371,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
{$intervals_query['from_clause']} {$intervals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']} {$intervals_query['where_clause']}
GROUP BY GROUP BY
time_interval time_interval
@ -369,19 +411,25 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
/** /**
* Get unique products based on user time query * Get unique products based on user time query
* *
* @param string $from_clause From clause with date query.
* @param string $where_time_clause Where clause with date query.
* @param string $where_clause Where clause with date query. * @param string $where_clause Where clause with date query.
* @return integer Unique product count. * @return integer Unique product count.
*/ */
public function get_unique_products( $where_clause ) { public function get_unique_product_count( $from_clause, $where_time_clause, $where_clause ) {
global $wpdb; global $wpdb;
$table_name = $wpdb->prefix . self::TABLE_NAME;
return $wpdb->get_var( return $wpdb->get_var(
"SELECT "SELECT
COUNT( DISTINCT {$wpdb->prefix}wc_order_product_lookup.product_id ) COUNT( DISTINCT {$wpdb->prefix}wc_order_product_lookup.product_id )
FROM FROM
{$wpdb->prefix}wc_order_product_lookup JOIN {$wpdb->prefix}posts ON {$wpdb->prefix}wc_order_product_lookup.order_id = {$wpdb->prefix}posts.ID {$wpdb->prefix}wc_order_product_lookup JOIN {$table_name} ON {$wpdb->prefix}wc_order_product_lookup.order_id = {$table_name}.order_id
{$from_clause}
WHERE WHERE
1=1 1=1
{$where_time_clause}
{$where_clause}" {$where_clause}"
); // WPCS: cache ok, DB call ok, unprepared SQL ok. ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
} }

View File

@ -98,24 +98,21 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
*/ */
protected function get_sql_query_params( $query_args ) { protected function get_sql_query_params( $query_args ) {
global $wpdb; global $wpdb;
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
$sql_query_params = $this->get_time_period_sql_params( $query_args ); $sql_query_params = $this->get_time_period_sql_params( $query_args, $order_product_lookup_table );
$sql_query_params = array_merge( $sql_query_params, $this->get_limit_sql_params( $query_args ) ); $sql_query_params = array_merge( $sql_query_params, $this->get_limit_sql_params( $query_args ) );
$sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) ); $sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) );
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME; $included_products = $this->get_included_products( $query_args );
$allowed_products = $this->get_allowed_products( $query_args ); if ( $included_products ) {
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$included_products})";
if ( count( $allowed_products ) > 0 ) {
$allowed_products_str = implode( ',', $allowed_products );
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$allowed_products_str})";
} }
if ( is_array( $query_args['order_status'] ) && count( $query_args['order_status'] ) > 0 ) { $order_status_filter = $this->get_status_subquery( $query_args );
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] ); if ( $order_status_filter ) {
$sql_query_params['from_clause'] .= " JOIN {$wpdb->prefix}posts ON {$order_product_lookup_table}.order_id = {$wpdb->prefix}posts.ID";
$sql_query_params['from_clause'] .= " JOIN {$wpdb->prefix}posts AS _orders ON {$order_product_lookup_table}.order_id = _orders.ID"; $sql_query_params['where_clause'] .= " AND ( {$order_status_filter} )";
$sql_query_params['where_clause'] .= " AND _orders.post_status IN ( '" . implode( "','", $statuses ) . "' ) ";
} }
return $sql_query_params; return $sql_query_params;
@ -186,7 +183,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ), 'after' => date( WC_Admin_Reports_Interval::$iso_datetime_format, $week_back ),
'fields' => '*', 'fields' => '*',
'categories' => array(), 'categories' => array(),
'products' => array(), 'product_includes' => array(),
'extended_info' => false, 'extended_info' => false,
// This is not a parameter for products reports per se, but we want to only take into account selected order types. // 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(),
@ -217,6 +214,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
{$sql_query_params['from_clause']} {$sql_query_params['from_clause']}
WHERE WHERE
1=1 1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']} {$sql_query_params['where_clause']}
GROUP BY GROUP BY
product_id product_id
@ -236,6 +234,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
{$sql_query_params['from_clause']} {$sql_query_params['from_clause']}
WHERE WHERE
1=1 1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']} {$sql_query_params['where_clause']}
GROUP BY GROUP BY
product_id product_id

View File

@ -50,28 +50,27 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
protected function update_sql_query_params( $query_args, &$totals_params, &$intervals_params ) { protected function update_sql_query_params( $query_args, &$totals_params, &$intervals_params ) {
global $wpdb; global $wpdb;
$allowed_products = $this->get_allowed_products( $query_args );
$products_where_clause = ''; $products_where_clause = '';
$products_from_clause = ''; $products_from_clause = '';
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME; $order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
if ( count( $allowed_products ) > 0 ) {
$allowed_products_str = implode( ',', $allowed_products ); $included_products = $this->get_included_products( $query_args );
$products_where_clause .= " AND {$order_product_lookup_table}.product_id IN ({$allowed_products_str})"; if ( $included_products ) {
$products_where_clause .= " AND {$order_product_lookup_table}.product_id IN ({$included_products})";
} }
if ( is_array( $query_args['order_status'] ) && count( $query_args['order_status'] ) > 0 ) { $order_status_filter = $this->get_status_subquery( $query_args );
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] ); if ( $order_status_filter ) {
$products_from_clause .= " JOIN {$wpdb->prefix}posts ON {$order_product_lookup_table}.order_id = {$wpdb->prefix}posts.ID"; $products_from_clause .= " JOIN {$wpdb->prefix}posts ON {$order_product_lookup_table}.order_id = {$wpdb->prefix}posts.ID";
$products_where_clause .= " AND {$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $statuses ) . "' ) "; $products_where_clause .= " AND ( {$order_status_filter} )";
} }
$totals_params = array_merge( $totals_params, $this->get_time_period_sql_params( $query_args ) ); $totals_params = array_merge( $totals_params, $this->get_time_period_sql_params( $query_args, $order_product_lookup_table ) );
$totals_params['where_clause'] .= $products_where_clause; $totals_params['where_clause'] .= $products_where_clause;
$totals_params['from_clause'] .= $products_from_clause; $totals_params['from_clause'] .= $products_from_clause;
$intervals_params = array_merge( $intervals_params, $this->get_intervals_sql_params( $query_args ) ); $intervals_params = array_merge( $intervals_params, $this->get_intervals_sql_params( $query_args, $order_product_lookup_table ) );
$intervals_params['where_clause'] .= $products_where_clause; $intervals_params['where_clause'] .= $products_where_clause;
$intervals_params['from_clause'] .= $products_from_clause; $intervals_params['from_clause'] .= $products_from_clause;
} }
@ -101,7 +100,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
'fields' => '*', 'fields' => '*',
'categories' => array(), 'categories' => array(),
'interval' => 'week', 'interval' => 'week',
'products' => array(), 'product_includes' => array(),
// This is not a parameter for products reports per se, but we should probably restricts order statuses here, too. // This is not a parameter for products reports per se, but we should probably restricts order statuses here, too.
'order_status' => parent::get_report_order_statuses(), 'order_status' => parent::get_report_order_statuses(),
); );
@ -125,6 +124,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
{$intervals_query['from_clause']} {$intervals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']} {$intervals_query['where_clause']}
GROUP BY GROUP BY
time_interval time_interval
@ -144,6 +144,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
{$totals_query['from_clause']} {$totals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$totals_query['where_time_clause']}
{$totals_query['where_clause']}", {$totals_query['where_clause']}",
ARRAY_A ARRAY_A
); // WPCS: cache ok, DB call ok, unprepared SQL ok. ); // WPCS: cache ok, DB call ok, unprepared SQL ok.
@ -166,6 +167,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
{$intervals_query['from_clause']} {$intervals_query['from_clause']}
WHERE WHERE
1=1 1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']} {$intervals_query['where_clause']}
GROUP BY GROUP BY
time_interval time_interval

View File

@ -72,17 +72,15 @@ class WC_Admin_Reports_Variations_Data_Store extends WC_Admin_Reports_Data_Store
*/ */
protected function get_sql_query_params( $query_args ) { protected function get_sql_query_params( $query_args ) {
global $wpdb; global $wpdb;
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
$sql_query_params = $this->get_time_period_sql_params( $query_args ); $sql_query_params = $this->get_time_period_sql_params( $query_args, $order_product_lookup_table );
$sql_query_params = array_merge( $sql_query_params, $this->get_limit_sql_params( $query_args ) ); $sql_query_params = array_merge( $sql_query_params, $this->get_limit_sql_params( $query_args ) );
$sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) ); $sql_query_params = array_merge( $sql_query_params, $this->get_order_by_sql_params( $query_args ) );
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME; $included_products = $this->get_included_products( $query_args );
$allowed_products = $this->get_allowed_products( $query_args ); if ( $included_products ) {
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$included_products})";
if ( count( $allowed_products ) > 0 ) {
$allowed_products_str = implode( ',', $allowed_products );
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$allowed_products_str})";
} }
if ( count( $query_args['variations'] ) > 0 ) { if ( count( $query_args['variations'] ) > 0 ) {

View File

@ -46,7 +46,9 @@ function wc_admin_order_product_lookup_entry( $order_id ) {
); );
} }
} }
// TODO: maybe replace these with woocommerce_create_order, woocommerce_update_order, woocommerce_trash_order, woocommerce_delete_order, as clean_post_cache might be called in other circumstances and trigger too many updates?
add_action( 'save_post', 'wc_admin_order_product_lookup_entry', 10, 1 ); add_action( 'save_post', 'wc_admin_order_product_lookup_entry', 10, 1 );
add_action( 'clean_post_cache', 'wc_admin_order_product_lookup_entry', 10, 1 );
/** /**
* Make an entry in the wc_order_tax_lookup table for an order. * Make an entry in the wc_order_tax_lookup table for an order.
@ -84,6 +86,7 @@ function wc_order_tax_lookup_entry( $order_id ) {
} }
} }
add_action( 'save_post', 'wc_order_tax_lookup_entry', 10, 1 ); add_action( 'save_post', 'wc_order_tax_lookup_entry', 10, 1 );
add_action( 'clean_post_cache', 'wc_order_tax_lookup_entry', 10, 1 );
/** /**
* Make an entry in the wc_order_coupon_lookup table for an order. * Make an entry in the wc_order_coupon_lookup table for an order.
@ -106,7 +109,7 @@ function wc_order_coupon_lookup_entry( $order_id ) {
$wpdb->prefix . 'wc_order_coupon_lookup', $wpdb->prefix . 'wc_order_coupon_lookup',
array( array(
'order_id' => $order_id, 'order_id' => $order_id,
'coupon_id' => $coupon_item->get_id(), 'coupon_id' => wc_get_coupon_id_by_code( $coupon_item->get_code() ),
'coupon_gross_discount' => $coupon_item->get_discount(), 'coupon_gross_discount' => $coupon_item->get_discount(),
'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), 'date_created' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
), ),
@ -120,3 +123,4 @@ function wc_order_coupon_lookup_entry( $order_id ) {
} }
} }
add_action( 'save_post', 'wc_order_coupon_lookup_entry', 10, 1 ); add_action( 'save_post', 'wc_order_coupon_lookup_entry', 10, 1 );
add_action( 'clean_post_cache', 'wc_order_coupon_lookup_entry', 10, 1 );

View File

@ -88,7 +88,7 @@ class WC_Tests_API_Reports_Revenue_Stats extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'intervals', $properties ); $this->assertArrayHasKey( 'intervals', $properties );
$totals = $properties['totals']['properties']; $totals = $properties['totals']['properties'];
$this->assertEquals( 7, count( $totals ) ); $this->assertEquals( 9, count( $totals ) );
$this->assertArrayHasKey( 'gross_revenue', $totals ); $this->assertArrayHasKey( 'gross_revenue', $totals );
$this->assertArrayHasKey( 'net_revenue', $totals ); $this->assertArrayHasKey( 'net_revenue', $totals );
$this->assertArrayHasKey( 'coupons', $totals ); $this->assertArrayHasKey( 'coupons', $totals );
@ -96,6 +96,8 @@ class WC_Tests_API_Reports_Revenue_Stats extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'taxes', $totals ); $this->assertArrayHasKey( 'taxes', $totals );
$this->assertArrayHasKey( 'refunds', $totals ); $this->assertArrayHasKey( 'refunds', $totals );
$this->assertArrayHasKey( 'orders_count', $totals ); $this->assertArrayHasKey( 'orders_count', $totals );
$this->assertArrayHasKey( 'num_items_sold', $totals );
$this->assertArrayHasKey( 'products', $totals );
$intervals = $properties['intervals']['items']['properties']; $intervals = $properties['intervals']['items']['properties'];
$this->assertEquals( 6, count( $intervals ) ); $this->assertEquals( 6, count( $intervals ) );
@ -107,7 +109,7 @@ class WC_Tests_API_Reports_Revenue_Stats extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'subtotals', $intervals ); $this->assertArrayHasKey( 'subtotals', $intervals );
$subtotals = $properties['intervals']['items']['properties']['subtotals']['properties']; $subtotals = $properties['intervals']['items']['properties']['subtotals']['properties'];
$this->assertEquals( 7, count( $subtotals ) ); $this->assertEquals( 8, count( $subtotals ) );
$this->assertArrayHasKey( 'gross_revenue', $subtotals ); $this->assertArrayHasKey( 'gross_revenue', $subtotals );
$this->assertArrayHasKey( 'net_revenue', $subtotals ); $this->assertArrayHasKey( 'net_revenue', $subtotals );
$this->assertArrayHasKey( 'coupons', $subtotals ); $this->assertArrayHasKey( 'coupons', $subtotals );
@ -115,5 +117,6 @@ class WC_Tests_API_Reports_Revenue_Stats extends WC_REST_Unit_Test_Case {
$this->assertArrayHasKey( 'taxes', $subtotals ); $this->assertArrayHasKey( 'taxes', $subtotals );
$this->assertArrayHasKey( 'refunds', $subtotals ); $this->assertArrayHasKey( 'refunds', $subtotals );
$this->assertArrayHasKey( 'orders_count', $subtotals ); $this->assertArrayHasKey( 'orders_count', $subtotals );
$this->assertArrayHasKey( 'num_items_sold', $subtotals );
} }
} }