Merge pull request woocommerce/woocommerce-admin#943 from woocommerce/fix/749
Adding support for advanced filters in orders reports.
This commit is contained in:
commit
22fa3f5b05
|
@ -116,7 +116,7 @@ export const advancedFilters = {
|
|||
} ) ),
|
||||
},
|
||||
},
|
||||
code: {
|
||||
coupon: {
|
||||
labels: {
|
||||
add: __( 'Coupon Codes', 'wc-admin' ),
|
||||
placeholder: __( 'Search coupons', 'wc-admin' ),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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' ),
|
||||
|
|
|
@ -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 ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue