Correcting and clarifying analytics terms and calculations (https://github.com/woocommerce/woocommerce-admin/pull/3104)
* Relabel Net Revenue to Net Sales, revert previous refund work on Gross revenue and rename to total sales. Update the orer of all the things * Add gross sales calculation to revenue stats endpoint. * Restore coupon_total when updating order stats. * Wire up gross sales to revenue report. * Fix revenue report refunds calculation when there are no refunds. * update net sales labels and cases in order, product and category tables * Subtract refunded shipping and taxes from gross sales. * pluses to minuses to fix the gross revenue and refund totals when refunding * Add gross_sales to revenue stats orderby enum. * Change refund labels to Returns * Remove usage of defunct coupon_total column. * Store refunded amount in stats table. * Rename "gross_total" column to "total_sales". * Net total for refund orders can be used instead of a new column. * Rename gross_revenue to total_sales. * Coalesce coupons total in order stats query. SUM()ing all nulls gives null, not zero. * Use segmentation selections to backfill missing data. Fo when report columns and segmentation columns don't match. * Remove errant gross_sales from expected interval test data. * Fix gross sales tests for revenue/stats. * Move missing segment fills back to their original locations. * Fix remaining tests failing because of gross sales. * Fix db upgrade function rename of gross_total column. * Fix linter errors.
This commit is contained in:
parent
0db5cbb6a0
commit
52cb35f4de
|
@ -50,7 +50,7 @@ const headers = [
|
|||
label: 'Orders',
|
||||
},
|
||||
{
|
||||
label: 'Net Revenue',
|
||||
label: 'Net Sales',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ const data = {
|
|||
isRequesting: false,
|
||||
};
|
||||
const selectedChart = {
|
||||
key: 'gross_revenue',
|
||||
label: 'Gross Revenue',
|
||||
key: 'total_sales',
|
||||
label: 'Total Sales',
|
||||
type: 'currency',
|
||||
};
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ describe( 'ReportSummary', () => {
|
|||
props
|
||||
) {
|
||||
const selectedChart = {
|
||||
key: 'gross_revenue',
|
||||
label: 'Gross Revenue',
|
||||
key: 'total_sales',
|
||||
label: 'Total Sales',
|
||||
type,
|
||||
};
|
||||
const charts = [ selectedChart ];
|
||||
|
@ -29,10 +29,10 @@ describe( 'ReportSummary', () => {
|
|||
const summaryData = {
|
||||
totals: {
|
||||
primary: {
|
||||
gross_revenue: primaryValue,
|
||||
total_sales: primaryValue,
|
||||
},
|
||||
secondary: {
|
||||
gross_revenue: secondaryValue,
|
||||
total_sales: secondaryValue,
|
||||
},
|
||||
},
|
||||
isError,
|
||||
|
|
|
@ -47,7 +47,7 @@ class CategoriesReportTable extends Component {
|
|||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
key: 'net_revenue',
|
||||
isSortable: true,
|
||||
isNumeric: true,
|
||||
|
|
|
@ -23,7 +23,7 @@ export const charts = applyFilters( ORDERS_REPORT_CHARTS_FILTER, [
|
|||
},
|
||||
{
|
||||
key: 'net_revenue',
|
||||
label: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
order: 'desc',
|
||||
orderby: 'net_total',
|
||||
type: 'currency',
|
||||
|
|
|
@ -81,8 +81,8 @@ export default class OrdersReportTable extends Component {
|
|||
isSortable: false,
|
||||
},
|
||||
{
|
||||
label: __( 'N. Revenue', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
key: 'net_total',
|
||||
required: true,
|
||||
isSortable: true,
|
||||
|
@ -252,7 +252,7 @@ export default class OrdersReportTable extends Component {
|
|||
value: formatValue( 'number', coupons_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'woocommerce-admin' ),
|
||||
label: __( 'net sales', 'woocommerce-admin' ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
];
|
||||
|
|
|
@ -55,8 +55,8 @@ export default class VariationsReportTable extends Component {
|
|||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'N. Revenue', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
key: 'net_revenue',
|
||||
required: true,
|
||||
isSortable: true,
|
||||
|
@ -162,7 +162,7 @@ export default class VariationsReportTable extends Component {
|
|||
value: formatValue( 'number', items_sold ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'woocommerce-admin' ),
|
||||
label: __( 'net sales', 'woocommerce-admin' ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
{
|
||||
|
|
|
@ -60,8 +60,8 @@ class ProductsReportTable extends Component {
|
|||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'N. Revenue', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
screenReaderLabel: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
key: 'net_revenue',
|
||||
required: true,
|
||||
isSortable: true,
|
||||
|
|
|
@ -11,15 +11,15 @@ const REVENUE_REPORT_ADVANCED_FILTERS_FILTER = 'woocommerce_admin_revenue_report
|
|||
|
||||
export const charts = applyFilters( REVENUE_REPORT_CHARTS_FILTER, [
|
||||
{
|
||||
key: 'gross_revenue',
|
||||
label: __( 'Gross Revenue', 'woocommerce-admin' ),
|
||||
key: 'gross_sales',
|
||||
label: __( 'Gross Sales', 'woocommerce-admin' ),
|
||||
order: 'desc',
|
||||
orderby: 'gross_revenue',
|
||||
orderby: 'gross_sales',
|
||||
type: 'currency',
|
||||
},
|
||||
{
|
||||
key: 'refunds',
|
||||
label: __( 'Refunds', 'woocommerce-admin' ),
|
||||
label: __( 'Returns', 'woocommerce-admin' ),
|
||||
order: 'desc',
|
||||
orderby: 'refunds',
|
||||
type: 'currency',
|
||||
|
@ -31,6 +31,12 @@ export const charts = applyFilters( REVENUE_REPORT_CHARTS_FILTER, [
|
|||
orderby: 'coupons',
|
||||
type: 'currency',
|
||||
},
|
||||
{
|
||||
key: 'net_revenue',
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
orderby: 'net_revenue',
|
||||
type: 'currency',
|
||||
},
|
||||
{
|
||||
key: 'taxes',
|
||||
label: __( 'Taxes', 'woocommerce-admin' ),
|
||||
|
@ -45,9 +51,10 @@ export const charts = applyFilters( REVENUE_REPORT_CHARTS_FILTER, [
|
|||
type: 'currency',
|
||||
},
|
||||
{
|
||||
key: 'net_revenue',
|
||||
label: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
orderby: 'net_revenue',
|
||||
key: 'total_sales',
|
||||
label: __( 'Total Sales', 'woocommerce-admin' ),
|
||||
order: 'desc',
|
||||
orderby: 'total_sales',
|
||||
type: 'currency',
|
||||
},
|
||||
] );
|
||||
|
|
|
@ -50,14 +50,14 @@ class RevenueReportTable extends Component {
|
|||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Gross Revenue', 'woocommerce-admin' ),
|
||||
key: 'gross_revenue',
|
||||
required: true,
|
||||
label: __( 'Gross Sales', 'woocommerce-admin' ),
|
||||
key: 'gross_sales',
|
||||
required: false,
|
||||
isSortable: true,
|
||||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Refunds', 'woocommerce-admin' ),
|
||||
label: __( 'Returns', 'woocommerce-admin' ),
|
||||
key: 'refunds',
|
||||
required: false,
|
||||
isSortable: true,
|
||||
|
@ -70,6 +70,13 @@ class RevenueReportTable extends Component {
|
|||
isSortable: true,
|
||||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
key: 'net_revenue',
|
||||
required: false,
|
||||
isSortable: true,
|
||||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Taxes', 'woocommerce-admin' ),
|
||||
key: 'taxes',
|
||||
|
@ -85,9 +92,9 @@ class RevenueReportTable extends Component {
|
|||
isNumeric: true,
|
||||
},
|
||||
{
|
||||
label: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
key: 'net_revenue',
|
||||
required: false,
|
||||
label: __( 'Total Sales', 'woocommerce-admin' ),
|
||||
key: 'total_sales',
|
||||
required: true,
|
||||
isSortable: true,
|
||||
isNumeric: true,
|
||||
},
|
||||
|
@ -98,7 +105,8 @@ class RevenueReportTable extends Component {
|
|||
return data.map( row => {
|
||||
const {
|
||||
coupons,
|
||||
gross_revenue,
|
||||
gross_sales,
|
||||
total_sales,
|
||||
net_revenue,
|
||||
orders_count,
|
||||
refunds,
|
||||
|
@ -126,8 +134,8 @@ class RevenueReportTable extends Component {
|
|||
value: Number( orders_count ),
|
||||
},
|
||||
{
|
||||
display: renderCurrency( gross_revenue ),
|
||||
value: getCurrencyFormatDecimal( gross_revenue ),
|
||||
display: renderCurrency( gross_sales ),
|
||||
value: getCurrencyFormatDecimal( gross_sales ),
|
||||
},
|
||||
{
|
||||
display: formatCurrency( refunds ),
|
||||
|
@ -137,6 +145,10 @@ class RevenueReportTable extends Component {
|
|||
display: formatCurrency( coupons ),
|
||||
value: getCurrencyFormatDecimal( coupons ),
|
||||
},
|
||||
{
|
||||
display: renderCurrency( net_revenue ),
|
||||
value: getCurrencyFormatDecimal( net_revenue ),
|
||||
},
|
||||
{
|
||||
display: renderCurrency( taxes ),
|
||||
value: getCurrencyFormatDecimal( taxes ),
|
||||
|
@ -146,8 +158,8 @@ class RevenueReportTable extends Component {
|
|||
value: getCurrencyFormatDecimal( shipping ),
|
||||
},
|
||||
{
|
||||
display: renderCurrency( net_revenue ),
|
||||
value: getCurrencyFormatDecimal( net_revenue ),
|
||||
display: renderCurrency( total_sales ),
|
||||
value: getCurrencyFormatDecimal( total_sales ),
|
||||
},
|
||||
];
|
||||
} );
|
||||
|
@ -156,7 +168,8 @@ class RevenueReportTable extends Component {
|
|||
getSummary( totals, totalResults = 0 ) {
|
||||
const {
|
||||
orders_count = 0,
|
||||
gross_revenue = 0,
|
||||
gross_sales = 0,
|
||||
total_sales = 0,
|
||||
refunds = 0,
|
||||
coupons = 0,
|
||||
taxes = 0,
|
||||
|
@ -173,17 +186,21 @@ class RevenueReportTable extends Component {
|
|||
value: formatValue( 'number', orders_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'gross revenue', 'woocommerce-admin' ),
|
||||
value: formatCurrency( gross_revenue ),
|
||||
label: __( 'gross sales', 'woocommerce-admin' ),
|
||||
value: formatCurrency( gross_sales ),
|
||||
},
|
||||
{
|
||||
label: __( 'refunds', 'woocommerce-admin' ),
|
||||
label: __( 'returns', 'woocommerce-admin' ),
|
||||
value: formatCurrency( refunds ),
|
||||
},
|
||||
{
|
||||
label: __( 'coupons', 'woocommerce-admin' ),
|
||||
value: formatCurrency( coupons ),
|
||||
},
|
||||
{
|
||||
label: __( 'net sales', 'woocommerce-admin' ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
{
|
||||
label: __( 'taxes', 'woocommerce-admin' ),
|
||||
value: formatCurrency( taxes ),
|
||||
|
@ -193,8 +210,8 @@ class RevenueReportTable extends Component {
|
|||
value: formatCurrency( shipping ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'woocommerce-admin' ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
label: __( 'total sales', 'woocommerce-admin' ),
|
||||
value: formatCurrency( total_sales ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ const charts = {
|
|||
|
||||
const defaultCharts = [
|
||||
{
|
||||
label: __( 'Gross Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Total Sales', 'woocommerce-admin' ),
|
||||
report: 'revenue',
|
||||
key: 'gross_revenue',
|
||||
key: 'total_sales',
|
||||
},
|
||||
{
|
||||
label: __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
label: __( 'Net Sales', 'woocommerce-admin' ),
|
||||
report: 'revenue',
|
||||
key: 'net_revenue',
|
||||
},
|
||||
|
|
|
@ -41,7 +41,7 @@ export default applyFilters( DEFAULT_SECTIONS_FILTER, [
|
|||
'avg_order_value',
|
||||
'avg_items_per_order',
|
||||
'items_sold',
|
||||
'gross_revenue',
|
||||
'total_sales',
|
||||
'refunds',
|
||||
'coupons',
|
||||
'taxes',
|
||||
|
|
|
@ -136,7 +136,7 @@ class OrdersPanel extends Component {
|
|||
const productsCount =
|
||||
extended_info && extended_info.products ? extended_info.products.length : 0;
|
||||
|
||||
const total = order.gross_total;
|
||||
const total = order.total_sales;
|
||||
|
||||
cards.push(
|
||||
<ActivityCard
|
||||
|
|
|
@ -41,3 +41,23 @@ function wc_admin_update_0201_order_status_index() {
|
|||
function wc_admin_update_0201_db_version() {
|
||||
Installer::update_db_version( '0.20.1' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename "gross_total" to "total_sales".
|
||||
* See: https://github.com/woocommerce/woocommerce-admin/issues/3175
|
||||
*/
|
||||
function wc_admin_update_0230_rename_gross_total() {
|
||||
global $wpdb;
|
||||
|
||||
// We first need to drop the new `total_sales` column, since dbDelta() will have created it.
|
||||
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats DROP COLUMN `total_sales`" );
|
||||
// Then we can rename the existing `gross_total` column.
|
||||
$wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_order_stats CHANGE COLUMN `gross_total` `total_sales` double DEFAULT 0 NOT NULL" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update DB Version.
|
||||
*/
|
||||
function wc_admin_update_0230_db_version() {
|
||||
Installer::update_db_version( '0.23.0' );
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ A container element for a list of SummaryNumbers. This component handles detecti
|
|||
<SummaryNumber
|
||||
key="revenue"
|
||||
value={ '$829.40' }
|
||||
label="Gross Revenue"
|
||||
label="Total Sales"
|
||||
delta={ 29 }
|
||||
href="/analytics/report"
|
||||
/>,
|
||||
|
|
|
@ -11,7 +11,7 @@ export default () => (
|
|||
<SummaryNumber
|
||||
key="revenue"
|
||||
value={ '$829.40' }
|
||||
label="Gross Revenue"
|
||||
label="Total Sales"
|
||||
delta={ 29 }
|
||||
href="/analytics/report"
|
||||
/>,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/** @format */
|
||||
|
||||
export default `Date,Orders,Gross Revenue,Refunds,Taxes,Shipping,Net Revenue
|
||||
export default `Date,Orders,Total Sales,Refunds,Taxes,Shipping,Net Sales
|
||||
2018-10-01 00:00:00,1,411,0,0,0,411
|
||||
2018-10-02 00:00:00,0,0,,0,0,0`;
|
||||
|
|
|
@ -12,8 +12,8 @@ export default [
|
|||
required: false,
|
||||
},
|
||||
{
|
||||
label: 'Gross Revenue',
|
||||
key: 'gross_revenue',
|
||||
label: 'Total Sales',
|
||||
key: 'total_sales',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ export default [
|
|||
key: 'shipping',
|
||||
},
|
||||
{
|
||||
label: 'Net Revenue',
|
||||
label: 'Net Sales',
|
||||
key: 'net_revenue',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** @format */
|
||||
|
||||
export default `Date,Orders,Description,"Gross Revenue",Refunds,Coupons,Taxes,Shipping,"Net Revenue","Negative Number"
|
||||
export default `Date,Orders,Description,"Total Sales",Refunds,Coupons,Taxes,Shipping,"Net Sales","Negative Number"
|
||||
2018-04-29T00:00:00,30,"Lorem, ""ipsum""",200,19,19,100,19,200,'-123`;
|
||||
|
|
|
@ -14,8 +14,8 @@ export default [
|
|||
key: 'description',
|
||||
},
|
||||
{
|
||||
label: 'Gross Revenue',
|
||||
key: 'gross_revenue',
|
||||
label: 'Total Sales',
|
||||
key: 'total_sales',
|
||||
},
|
||||
{
|
||||
label: 'Refunds',
|
||||
|
@ -34,7 +34,7 @@ export default [
|
|||
key: 'shipping',
|
||||
},
|
||||
{
|
||||
label: 'Net Revenue',
|
||||
label: 'Net Sales',
|
||||
key: 'net_revenue',
|
||||
},
|
||||
{
|
||||
|
|
|
@ -194,7 +194,7 @@ class Leaderboards extends \WC_REST_Data_Controller {
|
|||
'label' => __( 'Items Sold', 'woocommerce-admin' ),
|
||||
),
|
||||
array(
|
||||
'label' => __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
'label' => __( 'Net Sales', 'woocommerce-admin' ),
|
||||
),
|
||||
),
|
||||
'rows' => $rows,
|
||||
|
@ -324,7 +324,7 @@ class Leaderboards extends \WC_REST_Data_Controller {
|
|||
'label' => __( 'Items Sold', 'woocommerce-admin' ),
|
||||
),
|
||||
array(
|
||||
'label' => __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
'label' => __( 'Net Sales', 'woocommerce-admin' ),
|
||||
),
|
||||
),
|
||||
'rows' => $rows,
|
||||
|
|
|
@ -179,7 +179,7 @@ class Controller extends ReportsController implements ExportableInterface {
|
|||
'readonly' => true,
|
||||
),
|
||||
'net_revenue' => array(
|
||||
'description' => __( 'Gross revenue.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Total Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
|
|
|
@ -18,26 +18,28 @@ use \Automattic\WooCommerce\Admin\API\Reports\ParameterException;
|
|||
class Segmenter extends ReportsSegmenter {
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for product-related product-level segmenting query (e.g. coupon discount amount for product X when segmenting by product id or category).
|
||||
* Returns column => query mapping to be used for product-related product-level segmenting query
|
||||
* (e.g. coupon discount amount for product X when segmenting by product id or category).
|
||||
*
|
||||
* @param string $products_table Name of SQL table containing the product-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_product_level( $products_table ) {
|
||||
$columns_mapping = array(
|
||||
'amount' => "SUM($products_table.coupon_amount) as amount",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for order-related product-level segmenting query (e.g. orders_count when segmented by category).
|
||||
* Returns column => query mapping to be used for order-related product-level segmenting query
|
||||
* (e.g. orders_count when segmented by category).
|
||||
*
|
||||
* @param string $coupons_lookup_table Name of SQL table containing the order-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_order_level( $coupons_lookup_table ) {
|
||||
$columns_mapping = array(
|
||||
|
@ -45,16 +47,17 @@ class Segmenter extends ReportsSegmenter {
|
|||
'orders_count' => "COUNT(DISTINCT $coupons_lookup_table.order_id) as orders_count",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for order-level segmenting query (e.g. discount amount when segmented by coupons).
|
||||
* Returns column => query mapping to be used for order-level segmenting query
|
||||
* (e.g. discount amount when segmented by coupons).
|
||||
*
|
||||
* @param string $coupons_lookup_table Name of SQL table containing the order-level info.
|
||||
* @param array $overrides Array of overrides for default column calculations.
|
||||
*
|
||||
* @return string
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function segment_selections_orders( $coupons_lookup_table, $overrides = array() ) {
|
||||
$columns_mapping = array(
|
||||
|
@ -67,7 +70,7 @@ class Segmenter extends ReportsSegmenter {
|
|||
$columns_mapping = array_merge( $columns_mapping, $overrides );
|
||||
}
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -265,10 +268,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
// while coupon and customer are bound to order, so we don't need the extra JOIN for those.
|
||||
// This also means that segment selections need to be calculated differently.
|
||||
if ( 'product' === $this->query_args['segmentby'] ) {
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $table_name );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $table_name ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from = "INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)";
|
||||
$segmenting_groupby = $product_segmenting_table . '.product_id';
|
||||
$segmenting_dimension_name = 'product_id';
|
||||
|
@ -279,10 +285,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
throw new ParameterException( 'wc_admin_reports_invalid_segmenting_variation', __( 'product_includes parameter need to specify exactly one product when segmenting by variation.', 'woocommerce-admin' ) );
|
||||
}
|
||||
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $table_name );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $table_name ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from = "INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)";
|
||||
$segmenting_where = "AND $product_segmenting_table.product_id = {$this->query_args['product_includes'][0]}";
|
||||
$segmenting_groupby = $product_segmenting_table . '.variation_id';
|
||||
|
@ -290,10 +299,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
|
||||
$segments = $this->get_product_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $query_params, $unique_orders_table );
|
||||
} elseif ( 'category' === $this->query_args['segmentby'] ) {
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $table_name );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $table_name ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from = "
|
||||
INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)
|
||||
LEFT JOIN {$wpdb->prefix}term_relationships ON {$product_segmenting_table}.product_id = {$wpdb->prefix}term_relationships.object_id
|
||||
|
@ -305,7 +317,9 @@ class Segmenter extends ReportsSegmenter {
|
|||
|
||||
$segments = $this->get_product_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $query_params, $unique_orders_table );
|
||||
} elseif ( 'coupon' === $this->query_args['segmentby'] ) {
|
||||
$segmenting_selections = $this->segment_selections_orders( $table_name );
|
||||
$coupon_level_columns = $this->segment_selections_orders( $table_name );
|
||||
$segmenting_selections = $this->prepare_selections( $coupon_level_columns );
|
||||
$this->report_columns = $coupon_level_columns;
|
||||
$segmenting_from = '';
|
||||
$segmenting_groupby = "$table_name.coupon_id";
|
||||
|
||||
|
|
|
@ -74,8 +74,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'date_last_active' => 'IF( date_last_active <= "0000-00-00 00:00:00", NULL, date_last_active ) AS date_last_active',
|
||||
'date_last_order' => "MAX( {$wpdb->prefix}wc_order_stats.date_created ) as date_last_order",
|
||||
'orders_count' => 'SUM( CASE WHEN parent_id = 0 THEN 1 ELSE 0 END ) as orders_count',
|
||||
'total_spend' => 'SUM( gross_total ) as total_spend',
|
||||
'avg_order_value' => '( SUM( gross_total ) / COUNT( order_id ) ) as avg_order_value',
|
||||
'total_spend' => 'SUM( total_sales ) as total_spend',
|
||||
'avg_order_value' => '( SUM( total_sales ) / COUNT( order_id ) ) as avg_order_value',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -259,11 +259,11 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'format' => '%d',
|
||||
),
|
||||
'total_spend' => array(
|
||||
'column' => 'SUM( gross_total )',
|
||||
'column' => 'SUM( total_sales )',
|
||||
'format' => '%f',
|
||||
),
|
||||
'avg_order_value' => array(
|
||||
'column' => '( SUM( gross_total ) / COUNT( order_id ) )',
|
||||
'column' => '( SUM( total_sales ) / COUNT( order_id ) )',
|
||||
'format' => '%f',
|
||||
),
|
||||
);
|
||||
|
@ -464,7 +464,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'state' => $order->get_billing_state( 'edit' ),
|
||||
'postcode' => $order->get_billing_postcode( 'edit' ),
|
||||
'country' => $order->get_billing_country( 'edit' ),
|
||||
'date_last_active' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
|
||||
'date_last_active' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
|
||||
);
|
||||
$format = array(
|
||||
'%s',
|
||||
|
@ -603,7 +603,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'postcode' => $customer->get_billing_postcode( 'edit' ),
|
||||
'country' => $customer->get_billing_country( 'edit' ),
|
||||
'date_registered' => $customer->get_date_created( 'edit' )->date( TimeInterval::$sql_datetime_format ),
|
||||
'date_last_active' => $last_active ? date( 'Y-m-d H:i:s', $last_active ) : null,
|
||||
'date_last_active' => $last_active ? gmdate( 'Y-m-d H:i:s', $last_active ) : null,
|
||||
);
|
||||
$format = array(
|
||||
'%d',
|
||||
|
|
|
@ -97,14 +97,14 @@ class DataStore extends CustomersDataStore implements DataStoreInterface {
|
|||
$this->add_sql_query_params( $query_args );
|
||||
// Clear SQL clauses set for parent class queries that are different here.
|
||||
$this->subquery->clear_sql_clause( 'select' );
|
||||
$this->subquery->add_sql_clause( 'select', 'SUM( gross_total ) AS total_spend,' );
|
||||
$this->subquery->add_sql_clause( 'select', 'SUM( total_sales ) AS total_spend,' );
|
||||
$this->subquery->add_sql_clause(
|
||||
'select',
|
||||
'CASE WHEN COUNT( order_id ) = 0 THEN NULL ELSE COUNT( order_id ) END AS orders_count,'
|
||||
);
|
||||
$this->subquery->add_sql_clause(
|
||||
'select',
|
||||
'CASE WHEN COUNT( order_id ) = 0 THEN NULL ELSE SUM( gross_total ) / COUNT( order_id ) END AS avg_order_value'
|
||||
'CASE WHEN COUNT( order_id ) = 0 THEN NULL ELSE SUM( total_sales ) / COUNT( order_id ) END AS avg_order_value'
|
||||
);
|
||||
|
||||
$this->clear_sql_clause( array( 'order_by', 'limit' ) );
|
||||
|
|
|
@ -45,7 +45,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'status' => 'strval',
|
||||
'customer_id' => 'intval',
|
||||
'net_total' => 'floatval',
|
||||
'gross_total' => 'floatval',
|
||||
'total_sales' => 'floatval',
|
||||
'num_items_sold' => 'intval',
|
||||
'customer_type' => 'strval',
|
||||
);
|
||||
|
@ -71,7 +71,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'status' => "REPLACE({$table_name}.status, 'wc-', '') as status",
|
||||
'customer_id' => "{$table_name}.customer_id",
|
||||
'net_total' => "{$table_name}.net_total",
|
||||
'gross_total' => "{$table_name}.gross_total",
|
||||
'total_sales' => "{$table_name}.total_sales",
|
||||
'num_items_sold' => "{$table_name}.num_items_sold",
|
||||
'customer_type' => "(CASE WHEN {$table_name}.returning_customer = 1 THEN 'returning' WHEN {$table_name}.returning_customer = 0 THEN 'new' ELSE '' END) as customer_type",
|
||||
);
|
||||
|
|
|
@ -154,7 +154,7 @@ class Controller extends \Automattic\WooCommerce\Admin\API\Reports\Controller {
|
|||
public function get_item_schema() {
|
||||
$data_values = array(
|
||||
'net_revenue' => array(
|
||||
'description' => __( 'Net revenue.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Net Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
|
|
|
@ -47,7 +47,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
protected $column_types = array(
|
||||
'orders_count' => 'intval',
|
||||
'num_items_sold' => 'intval',
|
||||
'gross_revenue' => 'floatval',
|
||||
'gross_sales' => 'floatval',
|
||||
'total_sales' => 'floatval',
|
||||
'coupons' => 'floatval',
|
||||
'coupons_count' => 'intval',
|
||||
'refunds' => 'floatval',
|
||||
|
@ -75,13 +76,23 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
protected function assign_report_columns() {
|
||||
$table_name = self::get_db_table_name();
|
||||
// Avoid ambigious columns in SQL query.
|
||||
$refunds = "ABS( SUM( CASE WHEN {$table_name}.net_total < 0 THEN {$table_name}.net_total ELSE 0 END ) )";
|
||||
$gross_sales =
|
||||
"( SUM({$table_name}.total_sales)" .
|
||||
' + COALESCE( SUM(discount_amount), 0 )' . // SUM() all nulls gives null.
|
||||
" - SUM({$table_name}.tax_total)" .
|
||||
" - SUM({$table_name}.shipping_total)" .
|
||||
" + {$refunds}" .
|
||||
' ) as gross_sales';
|
||||
|
||||
$this->report_columns = array(
|
||||
'orders_count' => "SUM( CASE WHEN {$table_name}.parent_id = 0 THEN 1 ELSE 0 END ) as orders_count",
|
||||
'num_items_sold' => "SUM({$table_name}.num_items_sold) as num_items_sold",
|
||||
'gross_revenue' => "SUM( CASE WHEN {$table_name}.gross_total > 0 THEN {$table_name}.gross_total END ) AS gross_revenue",
|
||||
'coupons' => 'SUM(discount_amount) AS coupons',
|
||||
'coupons_count' => 'coupons_count',
|
||||
'refunds' => "ABS( SUM( CASE WHEN {$table_name}.gross_total < 0 THEN {$table_name}.gross_total END ) ) AS refunds",
|
||||
'gross_sales' => $gross_sales,
|
||||
'total_sales' => "SUM({$table_name}.total_sales) AS total_sales",
|
||||
'coupons' => 'COALESCE( SUM(discount_amount), 0 ) AS coupons', // SUM() all nulls gives null.
|
||||
'coupons_count' => 'COALESCE( coupons_count, 0 ) as coupons_count',
|
||||
'refunds' => "{$refunds} AS refunds",
|
||||
'taxes' => "SUM({$table_name}.tax_total) AS taxes",
|
||||
'shipping' => "SUM({$table_name}.shipping_total) AS shipping",
|
||||
'net_revenue' => "SUM({$table_name}.net_total) AS net_revenue",
|
||||
|
@ -458,7 +469,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
'date_created' => $order->get_date_created()->date( 'Y-m-d H:i:s' ),
|
||||
'date_created_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created()->getTimestamp() ),
|
||||
'num_items_sold' => self::get_num_items_sold( $order ),
|
||||
'gross_total' => $order->get_total(),
|
||||
'total_sales' => $order->get_total(),
|
||||
'tax_total' => $order->get_total_tax(),
|
||||
'shipping_total' => $order->get_shipping_total(),
|
||||
'net_total' => self::get_net_total( $order ),
|
||||
|
|
|
@ -18,16 +18,17 @@ use \Automattic\WooCommerce\Admin\API\Reports\ParameterException;
|
|||
class Segmenter extends ReportsSegmenter {
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for product-related product-level segmenting query (e.g. products sold, revenue from product X when segmenting by category).
|
||||
* Returns column => query mapping to be used for product-related product-level segmenting query
|
||||
* (e.g. products sold, revenue from product X when segmenting by category).
|
||||
*
|
||||
* @param string $products_table Name of SQL table containing the product-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_product_level( $products_table ) {
|
||||
$columns_mapping = array(
|
||||
'num_items_sold' => "SUM($products_table.product_qty) as num_items_sold",
|
||||
'gross_revenue' => "SUM($products_table.product_gross_revenue) AS gross_revenue",
|
||||
'total_sales' => "SUM($products_table.product_gross_revenue) AS total_sales",
|
||||
'coupons' => 'SUM( coupon_lookup_left_join.discount_amount ) AS coupons',
|
||||
'coupons_count' => 'COUNT( DISTINCT( coupon_lookup_left_join.coupon_id ) ) AS coupons_count',
|
||||
'refunds' => "SUM( CASE WHEN $products_table.product_gross_revenue < 0 THEN $products_table.product_gross_revenue ELSE 0 END ) AS refunds",
|
||||
|
@ -36,15 +37,16 @@ class Segmenter extends ReportsSegmenter {
|
|||
'net_revenue' => "SUM($products_table.product_net_revenue) AS net_revenue",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for order-related product-level segmenting query (e.g. avg items per order when segmented by category).
|
||||
* Returns column => query mapping to be used for order-related product-level segmenting query
|
||||
* (e.g. avg items per order when segmented by category).
|
||||
*
|
||||
* @param string $unique_orders_table Name of SQL table containing the order-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_order_level( $unique_orders_table ) {
|
||||
$columns_mapping = array(
|
||||
|
@ -55,24 +57,25 @@ class Segmenter extends ReportsSegmenter {
|
|||
'num_new_customers' => "COUNT($unique_orders_table.returning_customer) - SUM($unique_orders_table.returning_customer) AS num_new_customers",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for order-level segmenting query (e.g. avg items per order or net revenue when segmented by coupons).
|
||||
* Returns column => query mapping to be used for order-level segmenting query
|
||||
* (e.g. avg items per order or Net Sales when segmented by coupons).
|
||||
*
|
||||
* @param string $order_stats_table Name of SQL table containing the order-level info.
|
||||
* @param array $overrides Array of overrides for default column calculations.
|
||||
*
|
||||
* @return string
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function segment_selections_orders( $order_stats_table, $overrides = array() ) {
|
||||
$columns_mapping = array(
|
||||
'num_items_sold' => "SUM($order_stats_table.num_items_sold) as num_items_sold",
|
||||
'gross_revenue' => "SUM($order_stats_table.gross_total) AS gross_revenue",
|
||||
'total_sales' => "SUM($order_stats_table.total_sales) AS total_sales",
|
||||
'coupons' => "SUM($order_stats_table.discount_amount) AS coupons",
|
||||
'coupons_count' => 'COUNT( DISTINCT(coupon_lookup_left_join.coupon_id) ) AS coupons_count',
|
||||
'refunds' => "SUM( CASE WHEN $order_stats_table.parent_id != 0 THEN $order_stats_table.gross_total END ) AS refunds",
|
||||
'refunds' => "SUM( CASE WHEN $order_stats_table.parent_id != 0 THEN $order_stats_table.total_sales END ) AS refunds",
|
||||
'taxes' => "SUM($order_stats_table.tax_total) AS taxes",
|
||||
'shipping' => "SUM($order_stats_table.shipping_total) AS shipping",
|
||||
'net_revenue' => "SUM($order_stats_table.net_total) AS net_revenue",
|
||||
|
@ -87,7 +90,7 @@ class Segmenter extends ReportsSegmenter {
|
|||
$columns_mapping = array_merge( $columns_mapping, $overrides );
|
||||
}
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,10 +363,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
// This also means that segment selections need to be calculated differently.
|
||||
if ( 'product' === $this->query_args['segmentby'] ) {
|
||||
// @todo How to handle shipping taxes when grouped by product?
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $unique_orders_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $unique_orders_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from .= "INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)";
|
||||
$segmenting_groupby = $product_segmenting_table . '.product_id';
|
||||
$segmenting_dimension_name = 'product_id';
|
||||
|
@ -374,10 +380,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
throw new ParameterException( 'wc_admin_reports_invalid_segmenting_variation', __( 'product_includes parameter need to specify exactly one product when segmenting by variation.', 'woocommerce-admin' ) );
|
||||
}
|
||||
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $unique_orders_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $unique_orders_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from .= "INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)";
|
||||
$segmenting_where = "AND $product_segmenting_table.product_id = {$this->query_args['product_includes'][0]}";
|
||||
$segmenting_groupby = $product_segmenting_table . '.variation_id';
|
||||
|
@ -385,10 +394,13 @@ class Segmenter extends ReportsSegmenter {
|
|||
|
||||
$segments = $this->get_product_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $query_params, $unique_orders_table );
|
||||
} elseif ( 'category' === $this->query_args['segmentby'] ) {
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$order_level_columns = $this->get_segment_selections_order_level( $unique_orders_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'order_level' => $this->get_segment_selections_order_level( $unique_orders_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
'order_level' => $this->prepare_selections( $order_level_columns ),
|
||||
);
|
||||
$this->report_columns = array_merge( $product_level_columns, $order_level_columns );
|
||||
$segmenting_from .= "
|
||||
INNER JOIN $product_segmenting_table ON ($table_name.order_id = $product_segmenting_table.order_id)
|
||||
LEFT JOIN {$wpdb->term_relationships} ON {$product_segmenting_table}.product_id = {$wpdb->term_relationships}.object_id
|
||||
|
@ -404,7 +416,9 @@ class Segmenter extends ReportsSegmenter {
|
|||
$coupon_override = array(
|
||||
'coupons' => 'SUM(coupon_lookup.discount_amount) AS coupons',
|
||||
);
|
||||
$segmenting_selections = $this->segment_selections_orders( $table_name, $coupon_override );
|
||||
$coupon_level_columns = $this->segment_selections_orders( $table_name, $coupon_override );
|
||||
$segmenting_selections = $this->prepare_selections( $coupon_level_columns );
|
||||
$this->report_columns = $coupon_level_columns;
|
||||
$segmenting_from .= "
|
||||
INNER JOIN {$wpdb->prefix}wc_order_coupon_lookup AS coupon_lookup ON ($table_name.order_id = coupon_lookup.order_id)
|
||||
";
|
||||
|
@ -412,8 +426,10 @@ class Segmenter extends ReportsSegmenter {
|
|||
|
||||
$segments = $this->get_order_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $query_params );
|
||||
} elseif ( 'customer_type' === $this->query_args['segmentby'] ) {
|
||||
$segmenting_selections = $this->segment_selections_orders( $table_name );
|
||||
$segmenting_groupby = "$table_name.returning_customer";
|
||||
$customer_level_columns = $this->segment_selections_orders( $table_name );
|
||||
$segmenting_selections = $this->prepare_selections( $customer_level_columns );
|
||||
$this->report_columns = $customer_level_columns;
|
||||
$segmenting_groupby = "$table_name.returning_customer";
|
||||
|
||||
$segments = $this->get_order_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $query_params );
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$stat_order = apply_filters(
|
||||
'woocommerce_rest_report_sort_performance_indicators',
|
||||
array(
|
||||
'revenue/gross_revenue',
|
||||
'revenue/total_sales',
|
||||
'revenue/net_revenue',
|
||||
'orders/orders_count',
|
||||
'orders/avg_order_value',
|
||||
|
|
|
@ -171,7 +171,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'type' => 'number',
|
||||
'readonly' => true,
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'description' => __( 'Total net revenue of all items sold.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Total Net Sales of all items sold.', 'woocommerce-admin' ),
|
||||
),
|
||||
'orders_count' => array(
|
||||
'type' => 'integer',
|
||||
|
|
|
@ -165,7 +165,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
'indicator' => true,
|
||||
),
|
||||
'net_revenue' => array(
|
||||
'description' => __( 'Net revenue.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Net Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
|
|
|
@ -18,11 +18,12 @@ use \Automattic\WooCommerce\Admin\API\Reports\ParameterException;
|
|||
class Segmenter extends ReportsSegmenter {
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for product-related product-level segmenting query (e.g. products sold, revenue from product X when segmenting by category).
|
||||
* Returns column => query mapping to be used for product-related product-level segmenting query
|
||||
* (e.g. products sold, revenue from product X when segmenting by category).
|
||||
*
|
||||
* @param string $products_table Name of SQL table containing the product-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_product_level( $products_table ) {
|
||||
$columns_mapping = array(
|
||||
|
@ -33,7 +34,7 @@ class Segmenter extends ReportsSegmenter {
|
|||
'variations_count' => "COUNT( DISTINCT $products_table.variation_id ) AS variations_count",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,9 +156,11 @@ class Segmenter extends ReportsSegmenter {
|
|||
// while coupon and customer are bound to order, so we don't need the extra JOIN for those.
|
||||
// This also means that segment selections need to be calculated differently.
|
||||
if ( 'product' === $this->query_args['segmentby'] ) {
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
);
|
||||
$this->report_columns = $product_level_columns;
|
||||
$segmenting_from = '';
|
||||
$segmenting_groupby = $product_segmenting_table . '.product_id';
|
||||
$segmenting_dimension_name = 'product_id';
|
||||
|
@ -168,9 +171,11 @@ class Segmenter extends ReportsSegmenter {
|
|||
throw new ParameterException( 'wc_admin_reports_invalid_segmenting_variation', __( 'product_includes parameter need to specify exactly one product when segmenting by variation.', 'woocommerce-admin' ) );
|
||||
}
|
||||
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
);
|
||||
$this->report_columns = $product_level_columns;
|
||||
$segmenting_from = '';
|
||||
$segmenting_where = "AND $product_segmenting_table.product_id = {$this->query_args['product_includes'][0]}";
|
||||
$segmenting_groupby = $product_segmenting_table . '.variation_id';
|
||||
|
@ -178,9 +183,11 @@ class Segmenter extends ReportsSegmenter {
|
|||
|
||||
$segments = $this->get_product_related_segments( $type, $segmenting_selections, $segmenting_from, $segmenting_where, $segmenting_groupby, $segmenting_dimension_name, $table_name, $query_params, $unique_orders_table );
|
||||
} elseif ( 'category' === $this->query_args['segmentby'] ) {
|
||||
$product_level_columns = $this->get_segment_selections_product_level( $product_segmenting_table );
|
||||
$segmenting_selections = array(
|
||||
'product_level' => $this->get_segment_selections_product_level( $product_segmenting_table ),
|
||||
'product_level' => $this->prepare_selections( $product_level_columns ),
|
||||
);
|
||||
$this->report_columns = $product_level_columns;
|
||||
$segmenting_from = "
|
||||
LEFT JOIN {$wpdb->term_relationships} ON {$product_segmenting_table}.product_id = {$wpdb->term_relationships}.object_id
|
||||
LEFT JOIN {$wpdb->wc_category_lookup} ON {$wpdb->term_relationships}.term_taxonomy_id = {$wpdb->wc_category_lookup}.category_id
|
||||
|
|
|
@ -42,13 +42,14 @@ class Query extends ReportsQuery {
|
|||
'fields' => array(
|
||||
'orders_count',
|
||||
'num_items_sold',
|
||||
'gross_revenue',
|
||||
'total_sales',
|
||||
'coupons',
|
||||
'coupons_count',
|
||||
'refunds',
|
||||
'taxes',
|
||||
'shipping',
|
||||
'net_revenue',
|
||||
'gross_sales',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -165,8 +165,8 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
*/
|
||||
public function get_item_schema() {
|
||||
$data_values = array(
|
||||
'gross_revenue' => array(
|
||||
'description' => __( 'Gross revenue.', 'woocommerce-admin' ),
|
||||
'total_sales' => array(
|
||||
'description' => __( 'Total Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
|
@ -174,7 +174,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'format' => 'currency',
|
||||
),
|
||||
'net_revenue' => array(
|
||||
'description' => __( 'Net revenue.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Net Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
|
@ -237,6 +237,14 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'gross_sales' => array(
|
||||
'description' => __( 'Gross Sales.', 'woocommerce-admin' ),
|
||||
'type' => 'number',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
'indicator' => true,
|
||||
'format' => 'currency',
|
||||
),
|
||||
);
|
||||
|
||||
$segments = array(
|
||||
|
@ -390,7 +398,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'default' => 'date',
|
||||
'enum' => array(
|
||||
'date',
|
||||
'gross_revenue',
|
||||
'total_sales',
|
||||
'coupons',
|
||||
'refunds',
|
||||
'shipping',
|
||||
|
@ -398,6 +406,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'net_revenue',
|
||||
'orders_count',
|
||||
'items_sold',
|
||||
'gross_sales',
|
||||
),
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
@ -438,14 +447,14 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
*/
|
||||
public function get_export_columns() {
|
||||
return array(
|
||||
'date' => __( 'Date', 'woocommerce-admin' ),
|
||||
'orders_count' => __( 'Orders', 'woocommerce-admin' ),
|
||||
'gross_revenue' => __( 'Gross Revenue', 'woocommerce-admin' ),
|
||||
'refunds' => __( 'Refunds', 'woocommerce-admin' ),
|
||||
'coupons' => __( 'Coupons', 'woocommerce-admin' ),
|
||||
'taxes' => __( 'Taxes', 'woocommerce-admin' ),
|
||||
'shipping' => __( 'Shipping', 'woocommerce-admin' ),
|
||||
'net_revenue' => __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
'date' => __( 'Date', 'woocommerce-admin' ),
|
||||
'orders_count' => __( 'Orders', 'woocommerce-admin' ),
|
||||
'total_sales' => __( 'Total Sales', 'woocommerce-admin' ),
|
||||
'refunds' => __( 'Refunds', 'woocommerce-admin' ),
|
||||
'coupons' => __( 'Coupons', 'woocommerce-admin' ),
|
||||
'taxes' => __( 'Taxes', 'woocommerce-admin' ),
|
||||
'shipping' => __( 'Shipping', 'woocommerce-admin' ),
|
||||
'net_revenue' => __( 'Net Revenue', 'woocommerce-admin' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -459,14 +468,14 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
$subtotals = (array) $item['subtotals'];
|
||||
|
||||
return array(
|
||||
'date' => $item['date_start'],
|
||||
'orders_count' => $subtotals['orders_count'],
|
||||
'gross_revenue' => self::csv_number_format( $subtotals['gross_revenue'] ),
|
||||
'refunds' => self::csv_number_format( $subtotals['refunds'] ),
|
||||
'coupons' => self::csv_number_format( $subtotals['coupons'] ),
|
||||
'taxes' => self::csv_number_format( $subtotals['taxes'] ),
|
||||
'shipping' => self::csv_number_format( $subtotals['shipping'] ),
|
||||
'net_revenue' => self::csv_number_format( $subtotals['net_revenue'] ),
|
||||
'date' => $item['date_start'],
|
||||
'orders_count' => $subtotals['orders_count'],
|
||||
'total_sales' => self::csv_number_format( $subtotals['total_sales'] ),
|
||||
'refunds' => self::csv_number_format( $subtotals['refunds'] ),
|
||||
'coupons' => self::csv_number_format( $subtotals['coupons'] ),
|
||||
'taxes' => self::csv_number_format( $subtotals['taxes'] ),
|
||||
'shipping' => self::csv_number_format( $subtotals['shipping'] ),
|
||||
'net_revenue' => self::csv_number_format( $subtotals['net_revenue'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ class Segmenter {
|
|||
}
|
||||
|
||||
unset( $segment_data[ $segment_dimension ] );
|
||||
$segment_datum = array(
|
||||
$segment_datum = array(
|
||||
'segment_id' => $segment_id,
|
||||
'segment_label' => $segment_labels[ $segment_id ],
|
||||
'subtotals' => $segment_data,
|
||||
|
@ -391,7 +391,7 @@ class Segmenter {
|
|||
// This is to catch simple products with prior sales converted into variable products.
|
||||
// See: https://github.com/woocommerce/woocommerce-admin/issues/2719.
|
||||
if ( empty( $this->query_args['variations'] ) ) {
|
||||
$parent_object = wc_get_product( $this->query_args['product_includes'][0] );
|
||||
$parent_object = wc_get_product( $this->query_args['product_includes'][0] );
|
||||
$segments[] = 0;
|
||||
$segment_labels[0] = $parent_object->get_name();
|
||||
}
|
||||
|
@ -496,7 +496,6 @@ class Segmenter {
|
|||
* @return array
|
||||
*/
|
||||
protected function fill_in_missing_segments( $segments ) {
|
||||
|
||||
$segment_subtotals = array();
|
||||
if ( isset( $this->query_args['fields'] ) && is_array( $this->query_args['fields'] ) ) {
|
||||
foreach ( $this->query_args['fields'] as $field ) {
|
||||
|
@ -620,7 +619,9 @@ class Segmenter {
|
|||
*/
|
||||
public function get_totals_segments( $query_params, $table_name ) {
|
||||
$segments = $this->get_segments( 'totals', $query_params, $table_name );
|
||||
return $this->fill_in_missing_segments( $segments );
|
||||
$segments = $this->fill_in_missing_segments( $segments );
|
||||
|
||||
return $segments;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,6 +633,7 @@ class Segmenter {
|
|||
*/
|
||||
public function add_intervals_segments( &$data, $intervals_query, $table_name ) {
|
||||
$intervals_segments = $this->get_segments( 'intervals', $intervals_query, $table_name );
|
||||
|
||||
$this->assign_segments_to_intervals( $data->intervals, $intervals_segments );
|
||||
$this->fill_in_missing_interval_segments( $data );
|
||||
}
|
||||
|
|
|
@ -350,7 +350,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
'enum' => array(
|
||||
'date',
|
||||
'items_sold',
|
||||
'gross_revenue',
|
||||
'total_sales',
|
||||
'orders_count',
|
||||
'products_count',
|
||||
),
|
||||
|
|
|
@ -17,11 +17,11 @@ use \Automattic\WooCommerce\Admin\API\Reports\Segmenter as ReportsSegmenter;
|
|||
class Segmenter extends ReportsSegmenter {
|
||||
|
||||
/**
|
||||
* Returns SELECT clause statements to be used for order-related order-level segmenting query (e.g. tax_rate_id).
|
||||
* Returns column => query mapping to be used for order-related order-level segmenting query (e.g. tax_rate_id).
|
||||
*
|
||||
* @param string $lookup_table Name of SQL table containing the order-level segmenting info.
|
||||
*
|
||||
* @return string SELECT clause statements.
|
||||
* @return array Column => SELECT query mapping.
|
||||
*/
|
||||
protected function get_segment_selections_order_level( $lookup_table ) {
|
||||
$columns_mapping = array(
|
||||
|
@ -32,7 +32,7 @@ class Segmenter extends ReportsSegmenter {
|
|||
'orders_count' => "COUNT(DISTINCT $lookup_table.order_id) as orders_count",
|
||||
);
|
||||
|
||||
return $this->prepare_selections( $columns_mapping );
|
||||
return $columns_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,8 +140,10 @@ class Segmenter extends ReportsSegmenter {
|
|||
$segments = array();
|
||||
|
||||
if ( 'tax_rate_id' === $this->query_args['segmentby'] ) {
|
||||
$segmenting_select = $this->get_segment_selections_order_level( $table_name );
|
||||
$segmenting_groupby = $table_name . '.tax_rate_id';
|
||||
$tax_rate_level_columns = $this->get_segment_selections_order_level( $table_name );
|
||||
$segmenting_select = $this->prepare_selections( $tax_rate_level_columns );
|
||||
$this->report_columns = $tax_rate_level_columns;
|
||||
$segmenting_groupby = $table_name . '.tax_rate_id';
|
||||
|
||||
$segments = $this->get_order_related_segments( $type, $segmenting_select, $segmenting_from, $segmenting_where, $segmenting_groupby, $table_name, $query_params );
|
||||
}
|
||||
|
|
|
@ -185,7 +185,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
'type' => 'number',
|
||||
'readonly' => true,
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'description' => __( 'Total net revenue of all items sold.', 'woocommerce-admin' ),
|
||||
'description' => __( 'Total Net Sales of all items sold.', 'woocommerce-admin' ),
|
||||
),
|
||||
'orders_count' => array(
|
||||
'type' => 'integer',
|
||||
|
|
|
@ -31,6 +31,10 @@ class Install {
|
|||
'wc_admin_update_0201_order_status_index',
|
||||
'wc_admin_update_0201_db_version',
|
||||
),
|
||||
'0.23.0' => array(
|
||||
'wc_admin_update_0230_rename_gross_total',
|
||||
'wc_admin_update_0230_db_version',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -128,7 +132,7 @@ class Install {
|
|||
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
|
||||
date_created_gmt datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
|
||||
num_items_sold int(11) DEFAULT 0 NOT NULL,
|
||||
gross_total double DEFAULT 0 NOT NULL,
|
||||
total_sales double DEFAULT 0 NOT NULL,
|
||||
tax_total double DEFAULT 0 NOT NULL,
|
||||
shipping_total double DEFAULT 0 NOT NULL,
|
||||
net_total double DEFAULT 0 NOT NULL,
|
||||
|
|
|
@ -54,7 +54,7 @@ class WC_Admin_Notes_New_Sales_Record {
|
|||
return;
|
||||
}
|
||||
|
||||
$yesterday = date( 'Y-m-d', current_time( 'timestamp', 0 ) - DAY_IN_SECONDS );
|
||||
$yesterday = gmdate( 'Y-m-d', current_time( 'timestamp', 0 ) - DAY_IN_SECONDS );
|
||||
$total = self::sum_sales_for_date( $yesterday );
|
||||
|
||||
// No sales yesterday? Bail.
|
||||
|
@ -77,14 +77,14 @@ class WC_Admin_Notes_New_Sales_Record {
|
|||
update_option( self::RECORD_DATE_OPTION_KEY, $yesterday );
|
||||
update_option( self::RECORD_AMOUNT_OPTION_KEY, $total );
|
||||
|
||||
$formatted_yesterday = date( 'F jS', strtotime( $yesterday ) );
|
||||
$formatted_yesterday = gmdate( 'F jS', strtotime( $yesterday ) );
|
||||
$formatted_total = html_entity_decode( wp_strip_all_tags( wc_price( $total ) ) );
|
||||
$formatted_record_date = date( 'F jS', strtotime( $record_date ) );
|
||||
$formatted_record_date = gmdate( 'F jS', strtotime( $record_date ) );
|
||||
$formatted_record_amt = html_entity_decode( wp_strip_all_tags( wc_price( $record_amt ) ) );
|
||||
|
||||
$content = sprintf(
|
||||
/* translators: 1 and 4: Date (e.g. October 16th), 2 and 3: Amount (e.g. $160.00) */
|
||||
__( 'Woohoo, %1$s was your record day for sales! Net revenue was %2$s beating the previous record of %3$s set on %4$s.', 'woocommerce-admin' ),
|
||||
__( 'Woohoo, %1$s was your record day for sales! Net Sales was %2$s beating the previous record of %3$s set on %4$s.', 'woocommerce-admin' ),
|
||||
$formatted_yesterday,
|
||||
$formatted_total,
|
||||
$formatted_record_amt,
|
||||
|
|
|
@ -97,8 +97,9 @@ class WC_Tests_API_Reports_Revenue_Stats extends WC_REST_Unit_Test_Case {
|
|||
$this->assertArrayHasKey( 'intervals', $properties );
|
||||
|
||||
$totals = $properties['totals']['properties'];
|
||||
$this->assertEquals( 11, count( $totals ) );
|
||||
$this->assertArrayHasKey( 'gross_revenue', $totals );
|
||||
$this->assertEquals( 12, count( $totals ) );
|
||||
$this->assertArrayHasKey( 'gross_sales', $totals );
|
||||
$this->assertArrayHasKey( 'total_sales', $totals );
|
||||
$this->assertArrayHasKey( 'net_revenue', $totals );
|
||||
$this->assertArrayHasKey( 'coupons', $totals );
|
||||
$this->assertArrayHasKey( 'coupons_count', $totals );
|
||||
|
@ -120,8 +121,9 @@ 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( 10, count( $subtotals ) );
|
||||
$this->assertArrayHasKey( 'gross_revenue', $subtotals );
|
||||
$this->assertEquals( 11, count( $subtotals ) );
|
||||
$this->assertArrayHasKey( 'gross_sales', $subtotals );
|
||||
$this->assertArrayHasKey( 'total_sales', $subtotals );
|
||||
$this->assertArrayHasKey( 'net_revenue', $subtotals );
|
||||
$this->assertArrayHasKey( 'coupons', $subtotals );
|
||||
$this->assertArrayHasKey( 'coupons_count', $subtotals );
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -48,8 +48,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
// /reports/revenue/stats is mapped to Orders_Data_Store.
|
||||
$data_store = new OrdersStatsDataStore();
|
||||
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:59:59', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$start_time = gmdate( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = gmdate( 'Y-m-d H:59:59', $order->get_date_created()->getOffsetTimestamp() );
|
||||
|
||||
$args = array(
|
||||
'interval' => 'hour',
|
||||
|
@ -60,7 +60,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
'totals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'gross_revenue' => 97,
|
||||
'total_sales' => 97,
|
||||
'gross_sales' => 100,
|
||||
'coupons' => 20,
|
||||
'coupons_count' => 1,
|
||||
'refunds' => 0,
|
||||
|
@ -76,7 +77,7 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
),
|
||||
'intervals' => array(
|
||||
array(
|
||||
'interval' => date( 'Y-m-d H', $order->get_date_created()->getTimestamp() ),
|
||||
'interval' => gmdate( 'Y-m-d H', $order->get_date_created()->getTimestamp() ),
|
||||
'date_start' => $start_time,
|
||||
'date_start_gmt' => $start_time,
|
||||
'date_end' => $end_time,
|
||||
|
@ -84,7 +85,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
'subtotals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'gross_revenue' => 97,
|
||||
'total_sales' => 97,
|
||||
'gross_sales' => 100,
|
||||
'coupons' => 20,
|
||||
'coupons_count' => 1,
|
||||
'refunds' => 0,
|
||||
|
@ -112,7 +114,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
'totals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'gross_revenue' => 97,
|
||||
'total_sales' => 97,
|
||||
'gross_sales' => 100,
|
||||
'coupons' => 20,
|
||||
'coupons_count' => 1,
|
||||
'refunds' => 0,
|
||||
|
@ -124,7 +127,7 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
),
|
||||
'intervals' => array(
|
||||
array(
|
||||
'interval' => date( 'Y-m-d H', $order->get_date_created()->getTimestamp() ),
|
||||
'interval' => gmdate( 'Y-m-d H', $order->get_date_created()->getTimestamp() ),
|
||||
'date_start' => $start_time,
|
||||
'date_start_gmt' => $start_time,
|
||||
'date_end' => $end_time,
|
||||
|
@ -132,7 +135,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
'subtotals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'gross_revenue' => 97,
|
||||
'total_sales' => 97,
|
||||
'gross_sales' => 100,
|
||||
'coupons' => 20,
|
||||
'coupons_count' => 1,
|
||||
'refunds' => 0,
|
||||
|
|
Loading…
Reference in New Issue