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: {
add: __( 'Coupon Codes', '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['order'] = $request['order'];
$args['categories'] = (array) $request['categories'];
$args['status_is'] = (array) $request['status_is'];
$args['status_is_not'] = (array) $request['status_is_not'];
return $args;
}
@ -265,6 +267,26 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro
),
'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(
'description' => __( 'Limit result set to all items that have the specified term assigned in the categories taxonomy.', 'wc-admin' ),
'type' => 'array',
@ -277,4 +299,19 @@ class WC_Admin_REST_Reports_Categories_Controller extends WC_REST_Reports_Contro
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

@ -38,18 +38,24 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
* @return array
*/
protected function prepare_reports_query( $request ) {
$args = array();
$args['before'] = $request['before'];
$args['after'] = $request['after'];
$args['interval'] = $request['interval'];
$args['page'] = $request['page'];
$args['per_page'] = $request['per_page'];
$args['orderby'] = $request['orderby'];
$args['order'] = $request['order'];
$args['categories'] = (array) $request['categories'];
$args['coupons'] = (array) $request['coupons'];
$args['products'] = (array) $request['products'];
$args['order_status'] = (array) $request['order_status'];
$args = array();
$args['before'] = $request['before'];
$args['after'] = $request['after'];
$args['interval'] = $request['interval'];
$args['page'] = $request['page'];
$args['per_page'] = $request['per_page'];
$args['orderby'] = $request['orderby'];
$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'];
return $args;
}
@ -234,9 +240,9 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
* @return array
*/
public function get_collection_params() {
$params = array();
$params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
$params['page'] = array(
$params = array();
$params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
$params['page'] = array(
'description' => __( 'Current page of the collection.', 'wc-admin' ),
'type' => 'integer',
'default' => 1,
@ -244,7 +250,7 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
'validate_callback' => 'rest_validate_request_arg',
'minimum' => 1,
);
$params['per_page'] = array(
$params['per_page'] = array(
'description' => __( 'Maximum number of items to be returned in result set.', 'wc-admin' ),
'type' => 'integer',
'default' => 10,
@ -253,26 +259,26 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
'sanitize_callback' => 'absint',
'validate_callback' => 'rest_validate_request_arg',
);
$params['after'] = array(
$params['after'] = array(
'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'wc-admin' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['before'] = array(
$params['before'] = array(
'description' => __( 'Limit response to resources published before a given ISO8601 compliant date.', 'wc-admin' ),
'type' => 'string',
'format' => 'date-time',
'validate_callback' => 'rest_validate_request_arg',
);
$params['order'] = array(
$params['order'] = array(
'description' => __( 'Order sort attribute ascending or descending.', 'wc-admin' ),
'type' => 'string',
'default' => 'desc',
'enum' => array( 'asc', 'desc' ),
'validate_callback' => 'rest_validate_request_arg',
);
$params['orderby'] = array(
$params['orderby'] = array(
'description' => __( 'Sort collection by object attribute.', 'wc-admin' ),
'type' => 'string',
'default' => 'date',
@ -284,7 +290,7 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['interval'] = array(
$params['interval'] = array(
'description' => __( 'Time interval to use for buckets in the returned data.', 'wc-admin' ),
'type' => 'string',
'default' => 'week',
@ -298,27 +304,18 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['categories'] = array(
'description' => __( 'Limit result set to all items that have the specified term assigned in the categories taxonomy.', 'wc-admin' ),
$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',
'sanitize_callback' => 'wp_parse_id_list',
'default' => 'all',
'enum' => array(
'all',
'any',
),
'validate_callback' => 'rest_validate_request_arg',
);
$params['coupons'] = array(
'description' => __( 'Limit result set to all items that have the specified coupon assigned.', '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' ),
$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',
@ -327,6 +324,62 @@ class WC_Admin_REST_Reports_Orders_Stats_Controller extends WC_REST_Reports_Cont
'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;
}

View File

@ -31,6 +31,15 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
*/
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.
*
@ -43,7 +52,11 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
$registered = array_keys( $this->get_collection_params() );
foreach ( $registered as $param_name ) {
if ( isset( $request[ $param_name ] ) ) {
$args[ $param_name ] = $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 ];
}
}
}
@ -234,6 +247,16 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
'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(
'description' => __( 'Limit result to items with specified product ids.', 'wc-admin' ),
'type' => 'array',
@ -242,6 +265,7 @@ class WC_Admin_REST_Reports_Products_Controller extends WC_REST_Reports_Controll
'items' => array(
'type' => 'integer',
),
);
$params['extended_info'] = array(
'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';
/**
* Mapping between external parameter name and name used in query class.
*
* @var array
*/
protected $param_mapping = array(
'products' => 'product_includes',
);
/**
* 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 ) {
if ( isset( $request[ $arg ] ) ) {
$query_args[ $arg ] = $request[ $arg ];
$registered = array_keys( $this->get_collection_params() );
foreach ( $registered as $param_name ) {
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

@ -131,43 +131,55 @@ class WC_Admin_REST_Reports_Revenue_Stats_Controller extends WC_REST_Reports_Con
*/
public function get_item_schema() {
$totals = array(
'gross_revenue' => array(
'gross_revenue' => array(
'description' => __( 'Gross revenue.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'net_revenue' => array(
'net_revenue' => array(
'description' => __( 'Net revenue.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'coupons' => array(
'coupons' => array(
'description' => __( 'Total of coupons.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'shipping' => array(
'shipping' => array(
'description' => __( 'Total of shipping.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'taxes' => array(
'taxes' => array(
'description' => __( 'Total of taxes.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'refunds' => array(
'refunds' => array(
'description' => __( 'Total of refunds.', 'wc-admin' ),
'type' => 'number',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
'orders_count' => array(
'orders_count' => array(
'description' => __( 'Amount of orders', 'wc-admin' ),
'type' => 'integer',
'context' => array( 'view', 'edit' ),
'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' ),
@ -175,6 +187,9 @@ class WC_Admin_REST_Reports_Revenue_Stats_Controller extends WC_REST_Reports_Con
),
);
$intervals = $totals;
unset( $intervals['products'] );
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'report_revenue_stats',
@ -231,7 +246,7 @@ class WC_Admin_REST_Reports_Revenue_Stats_Controller extends WC_REST_Reports_Con
'type' => 'object',
'context' => array( 'view', 'edit' ),
'readonly' => true,
'properties' => $totals,
'properties' => $intervals,
),
),
),

View File

@ -350,7 +350,7 @@ class WC_Admin_Api_Init {
coupon_id BIGINT UNSIGNED NOT NULL,
date_created timestamp DEFAULT '0000-00-00 00:00:00' 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 date_created (date_created)
) $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 ) {
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.
$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;
$allowed_products = $this->get_allowed_products( $query_args );
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})";
// 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 );
if ( $included_products ) {
$sql_query_params['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 ) {
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] );
$order_status_filter = $this->get_status_subquery( $query_args );
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['where_clause'] .= " AND {$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $statuses ) . "' ) ";
$sql_query_params['where_clause'] .= " AND ( {$order_status_filter} )";
}
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']}
WHERE
1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']}
GROUP BY
product_id

View File

@ -121,6 +121,8 @@ class WC_Admin_Reports_Data_Store {
foreach ( $totals_arr as $key => $val ) {
$totals_arr[ $key ] = 0;
}
// TODO: should 'products' be in intervals?
unset( $totals_arr['products'] );
while ( $datetime <= $end_datetime ) {
$next_start = WC_Admin_Reports_Interval::iterate( $datetime, $time_interval );
$time_id = WC_Admin_Reports_Interval::time_interval_id( $time_interval, $datetime );
@ -258,12 +260,12 @@ class WC_Admin_Reports_Data_Store {
$new_start_date->setTimestamp( $new_start_date_timestamp );
}
}
$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 );
$intervals_query['where_clause'] = '';
$intervals_query['where_clause'] .= " AND date_created <= '{$query_args['adj_before']}'";
$intervals_query['where_clause'] .= " AND date_created >= '{$query_args['adj_after']}'";
$intervals_query['limit'] = 'LIMIT 0,' . $intervals_query['per_page'];
$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 );
$intervals_query['where_time_clause'] = '';
$intervals_query['where_time_clause'] .= " AND date_created <= '{$query_args['adj_before']}'";
$intervals_query['where_time_clause'] .= " AND date_created >= '{$query_args['adj_after']}'";
$intervals_query['limit'] = 'LIMIT 0,' . $intervals_query['per_page'];
} else {
if ( 'asc' === $query_args['order'] ) {
$offset = ( ( $query_args['page'] - 1 ) * $intervals_query['per_page'] ) - ( $expected_interval_count - $db_interval_count );
@ -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
*/
protected function get_time_period_sql_params( $query_args ) {
protected function get_time_period_sql_params( $query_args, $table_name ) {
$sql_query = array(
'from_clause' => '',
'where_clause' => '',
'from_clause' => '',
'where_time_clause' => '',
'where_clause' => '',
);
if ( isset( $query_args['before'] ) && '' !== $query_args['before'] ) {
$datetime = new DateTime( $query_args['before'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_clause'] .= " AND date_created <= '$datetime_str'";
$datetime = new DateTime( $query_args['before'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_time_clause'] .= " AND {$table_name}.date_created <= '$datetime_str'";
}
if ( isset( $query_args['after'] ) && '' !== $query_args['after'] ) {
$datetime = new DateTime( $query_args['after'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_clause'] .= " AND date_created >= '$datetime_str'";
$datetime = new DateTime( $query_args['after'] );
$datetime_str = $datetime->format( WC_Admin_Reports_Interval::$sql_datetime_format );
$sql_query['where_time_clause'] .= " AND {$table_name}.date_created >= '$datetime_str'";
}
return $sql_query;
@ -497,16 +501,18 @@ 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.
*
* @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
*/
protected function get_intervals_sql_params( $query_args ) {
protected function get_intervals_sql_params( $query_args, $table_name ) {
$intervals_query = array(
'from_clause' => '',
'where_clause' => '',
'from_clause' => '',
'where_time_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'] ) {
$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.
* @return array
* @return string
*/
protected function get_allowed_products( $query_args ) {
$allowed_products = array();
protected function get_included_products( $query_args ) {
$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 ) {
$allowed_products = $this->get_products_by_cat_ids( $query_args['categories'] );
$allowed_products = wc_list_pluck( $allowed_products, 'get_id' );
$included_products = $this->get_products_by_cat_ids( $query_args['categories'] );
$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 ( count( $allowed_products ) > 0 ) {
$allowed_products = array_intersect( $allowed_products, $query_args['products'] );
if ( isset( $query_args['product_includes'] ) && is_array( $query_args['product_includes'] ) && count( $query_args['product_includes'] ) > 0 ) {
if ( count( $included_products ) > 0 ) {
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 {
$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',
'num_returning_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() {
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 ) {
self::$background_process = new WC_Admin_Order_Stats_Background_Process();
@ -173,50 +176,84 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
// TODO: performance of all of this?
global $wpdb;
$where_clause = '';
$from_clause = '';
$from_clause = '';
$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 ) {
$allowed_products_str = implode( ',', $allowed_products );
$where_filters = array();
$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
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 ({$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 ) {
$allowed_coupons_str = implode( ', ', $query_args['coupons'] );
$where_clause .= " AND {$orders_stats_table}.order_id IN (
if ( $excluded_products ) {
$where_filters[] = " {$orders_stats_table}.order_id NOT IN (
SELECT
DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id
DISTINCT {$wpdb->prefix}wc_order_product_lookup.order_id
FROM
{$wpdb->prefix}wc_order_coupon_lookup
{$wpdb->prefix}wc_order_product_lookup
WHERE
{$wpdb->prefix}wc_order_coupon_lookup.coupon_id IN ({$allowed_coupons_str})
{$wpdb->prefix}wc_order_product_lookup.product_id IN ({$excluded_products})
)";
}
if ( is_array( $query_args['order_status'] ) && count( $query_args['order_status'] ) > 0 ) {
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] );
$from_clause .= " JOIN {$wpdb->prefix}posts ON {$orders_stats_table}.order_id = {$wpdb->prefix}posts.ID";
$where_clause .= " AND {$wpdb->prefix}posts.post_status IN ( '" . implode( "','", $statuses ) . "' ) ";
// 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
DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id
FROM
{$wpdb->prefix}wc_order_coupon_lookup
WHERE
{$wpdb->prefix}wc_order_coupon_lookup.coupon_id IN ({$included_coupons})
)";
}
if ( $excluded_coupons ) {
$where_filters[] = " {$orders_stats_table}.order_id NOT IN (
SELECT
DISTINCT {$wpdb->prefix}wc_order_coupon_lookup.order_id
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.
$totals_query['where_clause'] .= $where_clause;
$totals_query['from_clause'] .= $from_clause;
$intervals_query['where_clause'] .= $where_clause;
$intervals_query['from_clause'] .= $from_clause;
if ( $where_subclause ) {
$totals_query['where_clause'] .= " AND ( $where_subclause )";
$totals_query['from_clause'] .= $from_clause;
$intervals_query['where_clause'] .= " AND ( $where_subclause )";
$intervals_query['from_clause'] .= $from_clause;
}
}
/**
@ -235,18 +272,24 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
// These defaults are only applied when not using REST API, as the API has its own defaults that overwrite these for most values (except before, after, etc).
$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 ),
'interval' => 'week',
'fields' => '*',
'categories' => array(),
'coupons' => array(),
'order_status' => parent::get_report_order_statuses(),
'products' => 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 ),
'interval' => 'week',
'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(),
);
$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 );
$totals_query = $this->get_time_period_sql_params( $query_args );
$intervals_query = $this->get_intervals_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, $table_name );
// Additional filtering for Orders report.
$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']}
WHERE
1=1
{$totals_query['where_time_clause']}
{$totals_query['where_clause']}",
ARRAY_A
); // 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' ) );
}
$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;
// 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] );
$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']}
WHERE
1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']}
GROUP BY
time_interval"
@ -330,6 +371,7 @@ class WC_Admin_Reports_Orders_Data_Store extends WC_Admin_Reports_Data_Store imp
{$intervals_query['from_clause']}
WHERE
1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']}
GROUP BY
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
*
* @param string $where_clause Where clause with date 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.
* @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;
$table_name = $wpdb->prefix . self::TABLE_NAME;
return $wpdb->get_var(
"SELECT
COUNT( DISTINCT {$wpdb->prefix}wc_order_product_lookup.product_id )
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
1=1
{$where_time_clause}
{$where_clause}"
); // 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 ) {
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_order_by_sql_params( $query_args ) );
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
$allowed_products = $this->get_allowed_products( $query_args );
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})";
$included_products = $this->get_included_products( $query_args );
if ( $included_products ) {
$sql_query_params['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 ) {
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] );
$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 _orders.post_status IN ( '" . implode( "','", $statuses ) . "' ) ";
$order_status_filter = $this->get_status_subquery( $query_args );
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['where_clause'] .= " AND ( {$order_status_filter} )";
}
return $sql_query_params;
@ -178,18 +175,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_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(),
'product_includes' => 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 );
@ -217,6 +214,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
{$sql_query_params['from_clause']}
WHERE
1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']}
GROUP BY
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']}
WHERE
1=1
{$sql_query_params['where_time_clause']}
{$sql_query_params['where_clause']}
GROUP BY
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 ) {
global $wpdb;
$allowed_products = $this->get_allowed_products( $query_args );
$products_where_clause = '';
$products_from_clause = '';
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
if ( count( $allowed_products ) > 0 ) {
$allowed_products_str = implode( ',', $allowed_products );
$products_where_clause .= " AND {$order_product_lookup_table}.product_id IN ({$allowed_products_str})";
$included_products = $this->get_included_products( $query_args );
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 ) {
$statuses = array_map( array( $this, 'normalize_order_status' ), $query_args['order_status'] );
$order_status_filter = $this->get_status_subquery( $query_args );
if ( $order_status_filter ) {
$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['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['from_clause'] .= $products_from_clause;
}
@ -91,19 +90,19 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
$week_back = $now - WEEK_IN_SECONDS;
// 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(),
'interval' => 'week',
'products' => array(),
$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(),
'interval' => 'week',
'product_includes' => array(),
// 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(),
);
$query_args = wp_parse_args( $query_args, $defaults );
@ -125,6 +124,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
{$intervals_query['from_clause']}
WHERE
1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']}
GROUP BY
time_interval
@ -144,6 +144,7 @@ class WC_Admin_Reports_Products_Stats_Data_Store extends WC_Admin_Reports_Produc
{$totals_query['from_clause']}
WHERE
1=1
{$totals_query['where_time_clause']}
{$totals_query['where_clause']}",
ARRAY_A
); // 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']}
WHERE
1=1
{$intervals_query['where_time_clause']}
{$intervals_query['where_clause']}
GROUP BY
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 ) {
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_order_by_sql_params( $query_args ) );
$order_product_lookup_table = $wpdb->prefix . self::TABLE_NAME;
$allowed_products = $this->get_allowed_products( $query_args );
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})";
$included_products = $this->get_included_products( $query_args );
if ( $included_products ) {
$sql_query_params['where_clause'] .= " AND {$order_product_lookup_table}.product_id IN ({$included_products})";
}
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( 'clean_post_cache', 'wc_admin_order_product_lookup_entry', 10, 1 );
/**
* 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( 'clean_post_cache', 'wc_order_tax_lookup_entry', 10, 1 );
/**
* 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',
array(
'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(),
'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( '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 );
$totals = $properties['totals']['properties'];
$this->assertEquals( 7, count( $totals ) );
$this->assertEquals( 9, count( $totals ) );
$this->assertArrayHasKey( 'gross_revenue', $totals );
$this->assertArrayHasKey( 'net_revenue', $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( 'refunds', $totals );
$this->assertArrayHasKey( 'orders_count', $totals );
$this->assertArrayHasKey( 'num_items_sold', $totals );
$this->assertArrayHasKey( 'products', $totals );
$intervals = $properties['intervals']['items']['properties'];
$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 );
$subtotals = $properties['intervals']['items']['properties']['subtotals']['properties'];
$this->assertEquals( 7, count( $subtotals ) );
$this->assertEquals( 8, count( $subtotals ) );
$this->assertArrayHasKey( 'gross_revenue', $subtotals );
$this->assertArrayHasKey( 'net_revenue', $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( 'refunds', $subtotals );
$this->assertArrayHasKey( 'orders_count', $subtotals );
$this->assertArrayHasKey( 'num_items_sold', $subtotals );
}
}