Merge branch 'master' into feature/754
This commit is contained in:
commit
e0004eb461
|
@ -103,7 +103,7 @@ describe( 'Leaderboard', () => {
|
|||
);
|
||||
const leaderboard = leaderboardWrapper.root.findByType( Leaderboard );
|
||||
|
||||
const endpoint = NAMESPACE + 'reports/products';
|
||||
const endpoint = NAMESPACE + '/reports/products';
|
||||
const query = { orderby: 'items_sold', per_page: 5, extended_info: 1 };
|
||||
|
||||
expect( getReportStatsMock.mock.calls[ 0 ][ 1 ] ).toBe( endpoint );
|
||||
|
|
|
@ -20,6 +20,7 @@ import { onQueryChange } from '@woocommerce/navigation';
|
|||
*/
|
||||
import ReportError from 'analytics/components/report-error';
|
||||
import { getReportChartData, getReportTableData } from 'wc-api/reports/utils';
|
||||
import { QUERY_DEFAULTS } from 'wc-api/constants';
|
||||
import withSelect from 'wc-api/with-select';
|
||||
import { extendTableData } from './utils';
|
||||
|
||||
|
@ -84,12 +85,12 @@ class ReportTable extends Component {
|
|||
}
|
||||
|
||||
const isRequesting = tableData.isRequesting || primaryData.isRequesting;
|
||||
const totals = get( primaryData, [ 'data', 'totals' ], null );
|
||||
const totalResults = items.totalResults || 0;
|
||||
const totals = get( primaryData, [ 'data', 'totals' ], {} );
|
||||
const totalResults = items.totalResults;
|
||||
const { headers, ids, rows, summary } = applyFilters( TABLE_FILTER, {
|
||||
endpoint: endpoint,
|
||||
headers: getHeadersContent(),
|
||||
ids: itemIdField ? items.data.map( item => item[ itemIdField ] ) : null,
|
||||
ids: itemIdField ? items.data.map( item => item[ itemIdField ] ) : [],
|
||||
rows: getRowsContent( items.data ),
|
||||
totals: totals,
|
||||
summary: getSummary ? getSummary( totals, totalResults ) : null,
|
||||
|
@ -107,7 +108,7 @@ class ReportTable extends Component {
|
|||
onQueryChange={ onQueryChange }
|
||||
onColumnsChange={ this.onColumnsChange }
|
||||
rows={ rows }
|
||||
rowsPerPage={ parseInt( query.per_page ) }
|
||||
rowsPerPage={ parseInt( query.per_page ) || QUERY_DEFAULTS.pageSize }
|
||||
summary={ summary }
|
||||
totalRows={ totalResults }
|
||||
{ ...tableProps }
|
||||
|
@ -159,7 +160,7 @@ ReportTable.propTypes = {
|
|||
* Primary data of that report. If it's not provided, it will be automatically
|
||||
* loaded via the provided `endpoint`.
|
||||
*/
|
||||
primaryData: PropTypes.object.isRequired,
|
||||
primaryData: PropTypes.object,
|
||||
/**
|
||||
* Table data of that report. If it's not provided, it will be automatically
|
||||
* loaded via the provided `endpoint`.
|
||||
|
@ -176,13 +177,23 @@ ReportTable.propTypes = {
|
|||
};
|
||||
|
||||
ReportTable.defaultProps = {
|
||||
tableData: {},
|
||||
primaryData: {},
|
||||
tableData: {
|
||||
items: {
|
||||
data: [],
|
||||
totalResults: 0,
|
||||
},
|
||||
query: {},
|
||||
},
|
||||
tableQuery: {},
|
||||
};
|
||||
|
||||
export default compose(
|
||||
withSelect( ( select, props ) => {
|
||||
const { endpoint, getSummary, query, tableData, tableQuery, columnPrefsKey } = props;
|
||||
if ( query.search && ! ( query[ endpoint ] && query[ endpoint ].length ) ) {
|
||||
return {};
|
||||
}
|
||||
const chartEndpoint = 'variations' === endpoint ? 'products' : endpoint;
|
||||
const primaryData = getSummary
|
||||
? getReportChartData( chartEndpoint, 'primary', query, select )
|
||||
|
|
|
@ -111,27 +111,24 @@ class CategoriesReportTable extends Component {
|
|||
} );
|
||||
}
|
||||
|
||||
getSummary( totals, totalResults ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
getSummary( totals, totalResults = 0 ) {
|
||||
const { items_sold = 0, net_revenue = 0, orders_count = 0 } = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'category', 'categories', totalResults, 'wc-admin' ),
|
||||
value: numberFormat( totalResults ),
|
||||
},
|
||||
{
|
||||
label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ),
|
||||
value: numberFormat( totals.items_sold ),
|
||||
label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ),
|
||||
value: numberFormat( items_sold ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.net_revenue ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
{
|
||||
label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'order', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -168,7 +165,12 @@ class CategoriesReportTable extends Component {
|
|||
}
|
||||
|
||||
export default compose(
|
||||
withSelect( select => {
|
||||
withSelect( ( select, props ) => {
|
||||
const { query } = props;
|
||||
if ( query.search && ! ( query.categories && query.categories.length ) ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { getItems, getItemsError, isGetItemsRequesting } = select( 'wc-api' );
|
||||
const tableQuery = {
|
||||
per_page: -1,
|
||||
|
|
|
@ -129,21 +129,19 @@ export default class CouponsReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const { coupons_count = 0, orders_count = 0, amount = 0 } = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'coupon', 'coupons', totals.coupons_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.coupons_count ),
|
||||
label: _n( 'coupon', 'coupons', coupons_count, 'wc-admin' ),
|
||||
value: numberFormat( coupons_count ),
|
||||
},
|
||||
{
|
||||
label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'order', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'amount discounted', 'wc-admin' ),
|
||||
value: formatCurrency( totals.amount ),
|
||||
value: formatCurrency( amount ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ export const advancedFilters = {
|
|||
input: {
|
||||
component: 'Search',
|
||||
type: 'customers',
|
||||
getLabels: getRequestByIdString( NAMESPACE + 'customers', customer => ( {
|
||||
getLabels: getRequestByIdString( NAMESPACE + '/customers', customer => ( {
|
||||
id: customer.id,
|
||||
label: [ customer.first_name, customer.last_name ].filter( Boolean ).join( ' ' ),
|
||||
} ) ),
|
||||
|
@ -157,7 +157,7 @@ export const advancedFilters = {
|
|||
input: {
|
||||
component: 'Search',
|
||||
type: 'emails',
|
||||
getLabels: getRequestByIdString( NAMESPACE + 'customers', customer => ( {
|
||||
getLabels: getRequestByIdString( NAMESPACE + '/customers', customer => ( {
|
||||
id: customer.id,
|
||||
label: customer.email,
|
||||
} ) ),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { __, _n } from '@wordpress/i18n';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { Tooltip } from '@wordpress/components';
|
||||
|
||||
|
@ -191,25 +191,28 @@ export default class CustomersReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const {
|
||||
customers_count = 0,
|
||||
avg_orders_count = 0,
|
||||
avg_total_spend = 0,
|
||||
avg_avg_order_value = 0,
|
||||
} = totals;
|
||||
return [
|
||||
{
|
||||
label: __( 'customers', 'wc-admin' ),
|
||||
value: numberFormat( totals.customers_count ),
|
||||
label: _n( 'customer', 'customers', customers_count, 'wc-admin' ),
|
||||
value: numberFormat( customers_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'average orders', 'wc-admin' ),
|
||||
value: numberFormat( totals.avg_orders_count ),
|
||||
label: _n( 'average order', 'average orders', avg_orders_count, 'wc-admin' ),
|
||||
value: numberFormat( avg_orders_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'average lifetime spend', 'wc-admin' ),
|
||||
value: formatCurrency( totals.avg_total_spend ),
|
||||
value: formatCurrency( avg_total_spend ),
|
||||
},
|
||||
{
|
||||
label: __( 'average order value', 'wc-admin' ),
|
||||
value: formatCurrency( totals.avg_avg_order_value ),
|
||||
value: formatCurrency( avg_avg_order_value ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -121,9 +121,7 @@ export default class CouponsReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const { download_count = 0 } = totals;
|
||||
const { query } = this.props;
|
||||
const dates = getCurrentDates( query );
|
||||
const after = moment( dates.primary.after );
|
||||
|
@ -136,8 +134,8 @@ export default class CouponsReportTable extends Component {
|
|||
value: numberFormat( days ),
|
||||
},
|
||||
{
|
||||
label: _n( 'download', 'downloads', totals.download_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.download_count ),
|
||||
label: _n( 'download', 'downloads', download_count, 'wc-admin' ),
|
||||
value: numberFormat( download_count ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ export default compose(
|
|||
const items = searchItemsByString( select, report, search );
|
||||
const ids = Object.keys( items );
|
||||
if ( ! ids.length ) {
|
||||
return {}; // @TODO if no results were found, we should avoid making a server request.
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -182,42 +182,48 @@ export default class OrdersReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const {
|
||||
orders_count = 0,
|
||||
num_new_customers = 0,
|
||||
num_returning_customers = 0,
|
||||
products = 0,
|
||||
num_items_sold = 0,
|
||||
coupons = 0,
|
||||
net_revenue = 0,
|
||||
} = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'order', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
{
|
||||
label: _n( 'new customer', 'new customers', totals.num_new_customers, 'wc-admin' ),
|
||||
value: numberFormat( totals.num_new_customers ),
|
||||
label: _n( 'new customer', 'new customers', num_new_customers, 'wc-admin' ),
|
||||
value: numberFormat( num_new_customers ),
|
||||
},
|
||||
{
|
||||
label: _n(
|
||||
'returning customer',
|
||||
'returning customers',
|
||||
totals.num_returning_customers,
|
||||
num_returning_customers,
|
||||
'wc-admin'
|
||||
),
|
||||
value: numberFormat( totals.num_returning_customers ),
|
||||
value: numberFormat( num_returning_customers ),
|
||||
},
|
||||
{
|
||||
label: _n( 'product', 'products', totals.products, 'wc-admin' ),
|
||||
value: numberFormat( totals.products ),
|
||||
label: _n( 'product', 'products', products, 'wc-admin' ),
|
||||
value: numberFormat( products ),
|
||||
},
|
||||
{
|
||||
label: _n( 'item sold', 'items sold', totals.num_items_sold, 'wc-admin' ),
|
||||
value: numberFormat( totals.num_items_sold ),
|
||||
label: _n( 'item sold', 'items sold', num_items_sold, 'wc-admin' ),
|
||||
value: numberFormat( num_items_sold ),
|
||||
},
|
||||
{
|
||||
label: _n( 'coupon', 'coupons', totals.coupons, 'wc-admin' ),
|
||||
value: numberFormat( totals.coupons ),
|
||||
label: _n( 'coupon', 'coupons', coupons, 'wc-admin' ),
|
||||
value: numberFormat( coupons ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.net_revenue ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -139,26 +139,24 @@ export default class VariationsReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const { products_count = 0, items_sold = 0, net_revenue = 0, orders_count = 0 } = totals;
|
||||
return [
|
||||
{
|
||||
// @TODO: When primaryData is segmented, fix this to reflect variations, not products.
|
||||
label: _n( 'variation sold', 'variations sold', totals.products_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.products_count ),
|
||||
label: _n( 'variation sold', 'variations sold', products_count, 'wc-admin' ),
|
||||
value: numberFormat( products_count ),
|
||||
},
|
||||
{
|
||||
label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ),
|
||||
value: numberFormat( totals.items_sold ),
|
||||
label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ),
|
||||
value: numberFormat( items_sold ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.net_revenue ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
{
|
||||
label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'orders', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -204,25 +204,23 @@ class ProductsReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const { products_count = 0, items_sold = 0, net_revenue = 0, orders_count = 0 } = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'product sold', 'products sold', totals.products_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.products_count ),
|
||||
label: _n( 'product sold', 'products sold', products_count, 'wc-admin' ),
|
||||
value: numberFormat( products_count ),
|
||||
},
|
||||
{
|
||||
label: _n( 'item sold', 'items sold', totals.items_sold, 'wc-admin' ),
|
||||
value: numberFormat( totals.items_sold ),
|
||||
label: _n( 'item sold', 'items sold', items_sold, 'wc-admin' ),
|
||||
value: numberFormat( items_sold ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.net_revenue ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
{
|
||||
label: _n( 'orders', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'orders', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -259,7 +257,12 @@ class ProductsReportTable extends Component {
|
|||
}
|
||||
|
||||
export default compose(
|
||||
withSelect( select => {
|
||||
withSelect( ( select, props ) => {
|
||||
const { query } = props;
|
||||
if ( query.search && ! ( query.products && query.products.length ) ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { getItems, getItemsError, isGetItemsRequesting } = select( 'wc-api' );
|
||||
const tableQuery = {
|
||||
per_page: -1,
|
||||
|
|
|
@ -153,43 +153,48 @@ class RevenueReportTable extends Component {
|
|||
} );
|
||||
}
|
||||
|
||||
getSummary( totals, totalResults ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
getSummary( totals, totalResults = 0 ) {
|
||||
const {
|
||||
orders_count = 0,
|
||||
gross_revenue = 0,
|
||||
refunds = 0,
|
||||
coupons = 0,
|
||||
taxes = 0,
|
||||
shipping = 0,
|
||||
net_revenue = 0,
|
||||
} = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'day', 'days', totalResults, 'wc-admin' ),
|
||||
value: numberFormat( totalResults ),
|
||||
},
|
||||
{
|
||||
label: _n( 'order', 'orders', totals.orders_count, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'order', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
{
|
||||
label: __( 'gross revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.gross_revenue ),
|
||||
value: formatCurrency( gross_revenue ),
|
||||
},
|
||||
{
|
||||
label: __( 'refunds', 'wc-admin' ),
|
||||
value: formatCurrency( totals.refunds ),
|
||||
value: formatCurrency( refunds ),
|
||||
},
|
||||
{
|
||||
label: __( 'coupons', 'wc-admin' ),
|
||||
value: formatCurrency( totals.coupons ),
|
||||
value: formatCurrency( coupons ),
|
||||
},
|
||||
{
|
||||
label: __( 'taxes', 'wc-admin' ),
|
||||
value: formatCurrency( totals.taxes ),
|
||||
value: formatCurrency( taxes ),
|
||||
},
|
||||
{
|
||||
label: __( 'shipping', 'wc-admin' ),
|
||||
value: formatCurrency( totals.shipping ),
|
||||
value: formatCurrency( shipping ),
|
||||
},
|
||||
{
|
||||
label: __( 'net revenue', 'wc-admin' ),
|
||||
value: formatCurrency( totals.net_revenue ),
|
||||
value: formatCurrency( net_revenue ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -103,25 +103,23 @@ export default class StockReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const { products = 0, out_of_stock = 0, low_stock = 0, in_stock = 0 } = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'product', 'products', totals.products, 'wc-admin' ),
|
||||
value: numberFormat( totals.products ),
|
||||
label: _n( 'product', 'products', products, 'wc-admin' ),
|
||||
value: numberFormat( products ),
|
||||
},
|
||||
{
|
||||
label: __( 'out of stock', totals.out_of_stock, 'wc-admin' ),
|
||||
value: numberFormat( totals.out_of_stock ),
|
||||
label: __( 'out of stock', out_of_stock, 'wc-admin' ),
|
||||
value: numberFormat( out_of_stock ),
|
||||
},
|
||||
{
|
||||
label: __( 'low stock', totals.low_stock, 'wc-admin' ),
|
||||
value: numberFormat( totals.low_stock ),
|
||||
label: __( 'low stock', low_stock, 'wc-admin' ),
|
||||
value: numberFormat( low_stock ),
|
||||
},
|
||||
{
|
||||
label: __( 'in stock', totals.in_stock, 'wc-admin' ),
|
||||
value: numberFormat( totals.in_stock ),
|
||||
label: __( 'in stock', in_stock, 'wc-admin' ),
|
||||
value: numberFormat( in_stock ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ export const filters = [
|
|||
settings: {
|
||||
type: 'taxes',
|
||||
param: 'taxes',
|
||||
getLabels: getRequestByIdString( NAMESPACE + 'taxes', tax => ( {
|
||||
getLabels: getRequestByIdString( NAMESPACE + '/taxes', tax => ( {
|
||||
id: tax.id,
|
||||
label: getTaxCode( tax ),
|
||||
} ) ),
|
||||
|
|
|
@ -111,29 +111,33 @@ export default class TaxesReportTable extends Component {
|
|||
}
|
||||
|
||||
getSummary( totals ) {
|
||||
if ( ! totals ) {
|
||||
return [];
|
||||
}
|
||||
const {
|
||||
tax_codes = 0,
|
||||
total_tax = 0,
|
||||
order_tax = 0,
|
||||
shipping_tax = 0,
|
||||
orders_count = 0,
|
||||
} = totals;
|
||||
return [
|
||||
{
|
||||
label: _n( 'tax code', 'tax codes', totals.tax_codes, 'wc-admin' ),
|
||||
value: numberFormat( totals.tax_codes ),
|
||||
label: _n( 'tax code', 'tax codes', tax_codes, 'wc-admin' ),
|
||||
value: numberFormat( tax_codes ),
|
||||
},
|
||||
{
|
||||
label: __( 'total tax', 'wc-admin' ),
|
||||
value: formatCurrency( totals.total_tax ),
|
||||
value: formatCurrency( total_tax ),
|
||||
},
|
||||
{
|
||||
label: __( 'order tax', 'wc-admin' ),
|
||||
value: formatCurrency( totals.order_tax ),
|
||||
value: formatCurrency( order_tax ),
|
||||
},
|
||||
{
|
||||
label: __( 'shipping tax', 'wc-admin' ),
|
||||
value: formatCurrency( totals.shipping_tax ),
|
||||
value: formatCurrency( shipping_tax ),
|
||||
},
|
||||
{
|
||||
label: _n( 'order', 'orders', totals.orders, 'wc-admin' ),
|
||||
value: numberFormat( totals.orders_count ),
|
||||
label: _n( 'order', 'orders', orders_count, 'wc-admin' ),
|
||||
value: numberFormat( orders_count ),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
*/
|
||||
import { Component, createElement } from '@wordpress/element';
|
||||
import { parse } from 'qs';
|
||||
import { find, last } from 'lodash';
|
||||
import { find, last, isEqual } from 'lodash';
|
||||
|
||||
/**
|
||||
* WooCommerce dependencies
|
||||
*/
|
||||
import { getPersistedQuery, stringifyQuery } from '@woocommerce/navigation';
|
||||
import { getNewPath, getPersistedQuery, history, stringifyQuery } from '@woocommerce/navigation';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -64,11 +64,35 @@ const getPages = () => {
|
|||
};
|
||||
|
||||
class Controller extends Component {
|
||||
componentDidUpdate( prevProps ) {
|
||||
const prevQuery = this.getQuery( prevProps.location.search );
|
||||
const prevBaseQuery = this.getBaseQuery( prevProps.location.search );
|
||||
const baseQuery = this.getBaseQuery( this.props.location.search );
|
||||
|
||||
if ( prevQuery.page > 1 && ! isEqual( prevBaseQuery, baseQuery ) ) {
|
||||
history.replace( getNewPath( { page: 1 } ) );
|
||||
}
|
||||
}
|
||||
|
||||
getQuery( searchString ) {
|
||||
if ( ! searchString ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const search = searchString.substring( 1 );
|
||||
return parse( search );
|
||||
}
|
||||
|
||||
getBaseQuery( searchString ) {
|
||||
const query = this.getQuery( searchString );
|
||||
delete query.page;
|
||||
return query;
|
||||
}
|
||||
|
||||
render() {
|
||||
// Pass URL parameters (example :report -> params.report) and query string parameters
|
||||
const { path, url, params } = this.props.match;
|
||||
const search = this.props.location.search.substring( 1 );
|
||||
const query = parse( search );
|
||||
const query = this.getQuery( this.props.location.search );
|
||||
const page = find( getPages(), { path } );
|
||||
window.wpNavMenuUrlUpdate( page, query );
|
||||
window.wpNavMenuClassChange( page );
|
||||
|
|
|
@ -39,30 +39,30 @@ export function getRequestByIdString( path, handleData = identity ) {
|
|||
}
|
||||
|
||||
export const getCategoryLabels = getRequestByIdString(
|
||||
NAMESPACE + 'products/categories',
|
||||
NAMESPACE + '/products/categories',
|
||||
category => ( {
|
||||
id: category.id,
|
||||
label: category.name,
|
||||
} )
|
||||
);
|
||||
|
||||
export const getCouponLabels = getRequestByIdString( NAMESPACE + 'coupons', coupon => ( {
|
||||
export const getCouponLabels = getRequestByIdString( NAMESPACE + '/coupons', coupon => ( {
|
||||
id: coupon.id,
|
||||
label: coupon.code,
|
||||
} ) );
|
||||
|
||||
export const getCustomerLabels = getRequestByIdString( NAMESPACE + 'customers', customer => ( {
|
||||
export const getCustomerLabels = getRequestByIdString( NAMESPACE + '/customers', customer => ( {
|
||||
id: customer.id,
|
||||
label: customer.username,
|
||||
} ) );
|
||||
|
||||
export const getProductLabels = getRequestByIdString( NAMESPACE + 'products', product => ( {
|
||||
export const getProductLabels = getRequestByIdString( NAMESPACE + '/products', product => ( {
|
||||
id: product.id,
|
||||
label: product.name,
|
||||
} ) );
|
||||
|
||||
export const getVariationLabels = getRequestByIdString(
|
||||
query => NAMESPACE + `products/${ query.products }/variations`,
|
||||
query => NAMESPACE + `/products/${ query.products }/variations`,
|
||||
variation => {
|
||||
return {
|
||||
id: variation.id,
|
||||
|
|
|
@ -239,7 +239,7 @@ export function getReportChartData( endpoint, dataType, query, select ) {
|
|||
isError: false,
|
||||
isRequesting: false,
|
||||
data: {
|
||||
totals: null,
|
||||
totals: {},
|
||||
intervals: [],
|
||||
},
|
||||
};
|
||||
|
@ -355,6 +355,7 @@ export function getReportTableData( endpoint, urlQuery, select, query = {} ) {
|
|||
isError: false,
|
||||
items: {
|
||||
data: [],
|
||||
totalResults: 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
/**
|
||||
* REST API Product Variations Controller
|
||||
*
|
||||
* Handles requests to /products/variations.
|
||||
*
|
||||
* @package WooCommerce Admin/API
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Product variations controller.
|
||||
*
|
||||
* @package WooCommerce Admin/API
|
||||
* @extends WC_REST_Product_Variations_Controller
|
||||
*/
|
||||
class WC_Admin_REST_Product_Variations_Controller extends WC_REST_Product_Variations_Controller {
|
||||
/**
|
||||
* Endpoint namespace.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'wc/v4';
|
||||
}
|
|
@ -37,6 +37,11 @@ class WC_Admin_Api_Init {
|
|||
*/
|
||||
const ORDERS_LOOKUP_BATCH_INIT = 'wc-admin_orders_lookup_batch_init';
|
||||
|
||||
/**
|
||||
* Action hook for processing a batch of orders.
|
||||
*/
|
||||
const SINGLE_ORDER_ACTION = 'wc-admin_process_order';
|
||||
|
||||
/**
|
||||
* Queue instance.
|
||||
*
|
||||
|
@ -59,19 +64,16 @@ class WC_Admin_Api_Init {
|
|||
add_filter( 'rest_endpoints', array( 'WC_Admin_Api_Init', 'filter_rest_endpoints' ), 10, 1 );
|
||||
add_filter( 'woocommerce_debug_tools', array( 'WC_Admin_Api_Init', 'add_regenerate_tool' ) );
|
||||
|
||||
// Initialize Orders data store class's static vars.
|
||||
add_action( 'woocommerce_after_register_post_type', array( 'WC_Admin_Api_Init', 'orders_data_store_init' ), 20 );
|
||||
// Initialize Customers Report data store sync hooks.
|
||||
// Note: we need to hook in before `wc_current_user_is_active`.
|
||||
// See: https://github.com/woocommerce/woocommerce/blob/942615101ba00c939c107c3a4820c3d466864872/includes/wc-user-functions.php#L749.
|
||||
add_action( 'wp_loaded', array( 'WC_Admin_Api_Init', 'customers_report_data_store_init' ) );
|
||||
// Initialize syncing hooks.
|
||||
add_action( 'wp_loaded', array( __CLASS__, 'orders_lookup_update_init' ) );
|
||||
|
||||
// Initialize scheduled action handlers.
|
||||
add_action( self::QUEUE_BATCH_ACTION, array( __CLASS__, 'queue_batches' ), 10, 3 );
|
||||
add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 2 );
|
||||
add_action( self::QUEUE_DEPEDENT_ACTION, array( __CLASS__, 'queue_dependent_action' ), 10, 3 );
|
||||
add_action( self::CUSTOMERS_BATCH_ACTION, array( __CLASS__, 'customer_lookup_process_batch' ) );
|
||||
add_action( self::ORDERS_BATCH_ACTION, array( __CLASS__, 'orders_lookup_process_batch' ) );
|
||||
add_action( self::ORDERS_LOOKUP_BATCH_INIT, array( __CLASS__, 'orders_lookup_batch_init' ) );
|
||||
add_action( self::SINGLE_ORDER_ACTION, array( __CLASS__, 'orders_lookup_process_order' ) );
|
||||
|
||||
// Add currency symbol to orders endpoint response.
|
||||
add_filter( 'woocommerce_rest_prepare_shop_order_object', array( __CLASS__, 'add_currency_symbol_to_order_response' ) );
|
||||
|
@ -179,6 +181,7 @@ class WC_Admin_Api_Init {
|
|||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-products-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-product-categories-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-product-reviews-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-product-variations-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-reports-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-setting-options-controller.php';
|
||||
require_once dirname( __FILE__ ) . '/api/class-wc-admin-rest-system-status-tools-controller.php';
|
||||
|
@ -215,6 +218,7 @@ class WC_Admin_Api_Init {
|
|||
'WC_Admin_REST_Products_Controller',
|
||||
'WC_Admin_REST_Product_Categories_Controller',
|
||||
'WC_Admin_REST_Product_Reviews_Controller',
|
||||
'WC_Admin_REST_Product_Variations_Controller',
|
||||
'WC_Admin_REST_Reports_Controller',
|
||||
'WC_Admin_REST_Setting_Options_Controller',
|
||||
'WC_Admin_REST_System_Status_Tools_Controller',
|
||||
|
@ -384,6 +388,17 @@ class WC_Admin_Api_Init {
|
|||
$endpoints['/wc/v4/products/reviews'][1] = $endpoints['/wc/v4/products/reviews'][3];
|
||||
}
|
||||
|
||||
// Override /wc/v4/products/$product_id/variations.
|
||||
if ( isset( $endpoints['products/(?P<product_id>[\d]+)/variations'] )
|
||||
&& isset( $endpoints['products/(?P<product_id>[\d]+)/variations'][3] )
|
||||
&& isset( $endpoints['products/(?P<product_id>[\d]+)/variations'][2] )
|
||||
&& $endpoints['products/(?P<product_id>[\d]+)/variations'][2]['callback'][0] instanceof WC_Admin_REST_Product_Variations_Controller
|
||||
&& $endpoints['products/(?P<product_id>[\d]+)/variations'][3]['callback'][0] instanceof WC_Admin_REST_Product_Variations_Controller
|
||||
) {
|
||||
$endpoints['products/(?P<product_id>[\d]+)/variations'][0] = $endpoints['products/(?P<product_id>[\d]+)/variations'][2];
|
||||
$endpoints['products/(?P<product_id>[\d]+)/variations'][1] = $endpoints['products/(?P<product_id>[\d]+)/variations'][3];
|
||||
}
|
||||
|
||||
// Override /wc/v4/taxes.
|
||||
if ( isset( $endpoints['/wc/v4/taxes'] )
|
||||
&& isset( $endpoints['/wc/v4/taxes'][3] )
|
||||
|
@ -420,7 +435,7 @@ class WC_Admin_Api_Init {
|
|||
// so that the orders can be associated with the `customer_id` column.
|
||||
self::customer_lookup_batch_init();
|
||||
// Queue orders lookup to occur after customers lookup generation is done.
|
||||
self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, self::CUSTOMERS_BATCH_ACTION );
|
||||
self::queue_dependent_action( self::ORDERS_LOOKUP_BATCH_INIT, array(), self::CUSTOMERS_BATCH_ACTION );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,16 +459,58 @@ class WC_Admin_Api_Init {
|
|||
}
|
||||
|
||||
/**
|
||||
* Init orders data store.
|
||||
* Schedule an action to process a single Order.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function orders_data_store_init() {
|
||||
public static function schedule_single_order_process( $order_id ) {
|
||||
if ( 'shop_order' !== get_post_type( $order_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This can get called multiple times for a single order, so we look
|
||||
// for existing pending jobs for the same order to avoid duplicating efforts.
|
||||
$existing_jobs = self::queue()->search(
|
||||
array(
|
||||
'status' => 'pending',
|
||||
'per_page' => 1,
|
||||
'claimed' => false,
|
||||
'search' => "[{$order_id}]",
|
||||
)
|
||||
);
|
||||
|
||||
if ( $existing_jobs ) {
|
||||
$existing_job = current( $existing_jobs );
|
||||
|
||||
// Bail out if there's a pending single order action, or a pending dependent action.
|
||||
if (
|
||||
( self::SINGLE_ORDER_ACTION === $existing_job->get_hook() ) ||
|
||||
(
|
||||
self::QUEUE_DEPEDENT_ACTION === $existing_job->get_hook() &&
|
||||
in_array( self::SINGLE_ORDER_ACTION, $existing_job->get_args() )
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We want to ensure that customer lookup updates are scheduled before order updates.
|
||||
self::queue_dependent_action( self::SINGLE_ORDER_ACTION, array( $order_id ), self::CUSTOMERS_BATCH_ACTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach order lookup update hooks.
|
||||
*/
|
||||
public static function orders_lookup_update_init() {
|
||||
// Activate WC_Order extension.
|
||||
WC_Admin_Order::add_filters();
|
||||
// Initialize data stores.
|
||||
|
||||
add_action( 'save_post_shop_order', array( __CLASS__, 'schedule_single_order_process' ) );
|
||||
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'schedule_single_order_process' ) );
|
||||
|
||||
WC_Admin_Reports_Orders_Stats_Data_Store::init();
|
||||
WC_Admin_Reports_Products_Data_Store::init();
|
||||
WC_Admin_Reports_Taxes_Data_Store::init();
|
||||
WC_Admin_Reports_Coupons_Data_Store::init();
|
||||
WC_Admin_Reports_Customers_Data_Store::init();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -499,19 +556,35 @@ class WC_Admin_Api_Init {
|
|||
$order_ids = $order_query->get_orders();
|
||||
|
||||
foreach ( $order_ids as $order_id ) {
|
||||
// @todo: schedule single order update if this fails?
|
||||
WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id );
|
||||
WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id );
|
||||
WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id );
|
||||
WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id );
|
||||
self::orders_lookup_process_order( $order_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init customers report data store.
|
||||
* Process a single order to update lookup tables for.
|
||||
* If an error is encountered in one of the updates, a retry action is scheduled.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return void
|
||||
*/
|
||||
public static function customers_report_data_store_init() {
|
||||
WC_Admin_Reports_Customers_Data_Store::init();
|
||||
public static function orders_lookup_process_order( $order_id ) {
|
||||
$result = array_sum(
|
||||
array(
|
||||
WC_Admin_Reports_Orders_Stats_Data_Store::sync_order( $order_id ),
|
||||
WC_Admin_Reports_Products_Data_Store::sync_order_products( $order_id ),
|
||||
WC_Admin_Reports_Coupons_Data_Store::sync_order_coupons( $order_id ),
|
||||
WC_Admin_Reports_Taxes_Data_Store::sync_order_taxes( $order_id ),
|
||||
)
|
||||
);
|
||||
|
||||
// If all updates were either skipped or successful, we're done.
|
||||
// The update methods return -1 for skip, or a boolean success indicator.
|
||||
if ( 4 === absint( $result ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise assume an error occurred and reschedule.
|
||||
self::schedule_single_order_process( $order_id );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -579,9 +652,10 @@ class WC_Admin_Api_Init {
|
|||
* Queue an action to run after another.
|
||||
*
|
||||
* @param string $action Action to run after prerequisite.
|
||||
* @param array $action_args Action arguments.
|
||||
* @param string $prerequisite_action Prerequisite action.
|
||||
*/
|
||||
public static function queue_dependent_action( $action, $prerequisite_action ) {
|
||||
public static function queue_dependent_action( $action, $action_args, $prerequisite_action ) {
|
||||
$blocking_jobs = self::queue()->search(
|
||||
array(
|
||||
'status' => 'pending',
|
||||
|
@ -600,10 +674,10 @@ class WC_Admin_Api_Init {
|
|||
self::queue()->schedule_single(
|
||||
$after_blocking_job,
|
||||
self::QUEUE_DEPEDENT_ACTION,
|
||||
array( $action, $prerequisite_action )
|
||||
array( $action, $action_args, $prerequisite_action )
|
||||
);
|
||||
} else {
|
||||
self::queue()->schedule_single( time() + 5, $action );
|
||||
self::queue()->schedule_single( time() + 5, $action, $action_args );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,15 +51,6 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im
|
|||
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up all the hooks for maintaining and populating table data.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( 'save_post', array( __CLASS__, 'sync_order_coupons' ) );
|
||||
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_coupons' ) );
|
||||
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_coupons' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns comma separated ids of included coupons, based on query arguments from the user.
|
||||
*
|
||||
|
@ -287,7 +278,7 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im
|
|||
$this->include_extended_info( $coupon_data, $query_args );
|
||||
|
||||
$coupon_data = array_map( array( $this, 'cast_numbers' ), $coupon_data );
|
||||
$data = (object) array(
|
||||
$data = (object) array(
|
||||
'data' => $coupon_data,
|
||||
'total' => $db_records_count,
|
||||
'pages' => $total_pages,
|
||||
|
@ -315,21 +306,22 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im
|
|||
*
|
||||
* @since 3.5.0
|
||||
* @param int $order_id Order ID.
|
||||
* @return void
|
||||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function sync_order_coupons( $order_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
$coupon_items = $order->get_items( 'coupon' );
|
||||
$num_updated = 0;
|
||||
|
||||
foreach ( $coupon_items as $coupon_item ) {
|
||||
$coupon_id = wc_get_coupon_id_by_code( $coupon_item->get_code() );
|
||||
|
||||
$wpdb->replace(
|
||||
$result = $wpdb->replace(
|
||||
$wpdb->prefix . self::TABLE_NAME,
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
|
@ -352,7 +344,11 @@ class WC_Admin_Reports_Coupons_Data_Store extends WC_Admin_Reports_Data_Store im
|
|||
* @param int $order_id Order ID.
|
||||
*/
|
||||
do_action( 'woocommerce_reports_update_coupon', $coupon_id, $order_id );
|
||||
|
||||
$num_updated += intval( $result );
|
||||
}
|
||||
|
||||
return ( count( $coupon_items ) === $num_updated );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -417,8 +417,8 @@ class WC_Admin_Reports_Data_Store {
|
|||
* @return array
|
||||
*/
|
||||
protected static function get_excluded_report_order_statuses() {
|
||||
$excluded_statuses = WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) );
|
||||
$excluded_statuses[] = 'refunded';
|
||||
$excluded_statuses = WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) );
|
||||
$excluded_statuses = array_merge( array( 'refunded', 'trash' ), $excluded_statuses );
|
||||
return apply_filters( 'woocommerce_reports_excluded_order_statuses', $excluded_statuses );
|
||||
}
|
||||
|
||||
|
|
|
@ -73,10 +73,6 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
* Set up all the hooks for maintaining and populating table data.
|
||||
*/
|
||||
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' ) );
|
||||
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order' ) );
|
||||
add_action( 'woocommerce_refund_deleted', array( __CLASS__, 'sync_on_refund_delete' ), 10, 2 );
|
||||
add_action( 'delete_post', array( __CLASS__, 'delete_order' ) );
|
||||
}
|
||||
|
@ -248,10 +244,8 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
|
||||
$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;
|
||||
|
||||
$segmenting = new WC_Admin_Reports_Orders_Stats_Segmenting( $query_args, $this->report_columns );
|
||||
$totals[0]['segments'] = $segmenting->get_totals_segments( $totals_query, $table_name );
|
||||
|
||||
$totals = (object) $this->cast_numbers( $totals[0] );
|
||||
|
||||
$db_intervals = $wpdb->get_col(
|
||||
|
@ -360,18 +354,19 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
* Add order information to the lookup table when orders are created or modified.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function sync_order( $post_id ) {
|
||||
if ( 'shop_order' !== get_post_type( $post_id ) ) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
$order = wc_get_order( $post_id );
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
self::update( $order );
|
||||
return self::update( $order );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -388,14 +383,14 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
* Update the database with stats data.
|
||||
*
|
||||
* @param WC_Order $order Order to update row for.
|
||||
* @return int|bool|null Number or rows modified or false on failure.
|
||||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function update( $order ) {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
|
||||
if ( ! $order->get_id() || ! $order->get_date_created() ) {
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
|
@ -437,7 +432,7 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
|
||||
if ( $customer_id ) {
|
||||
$data['customer_id'] = $customer_id;
|
||||
$format[] = '%d';
|
||||
$format[] = '%d';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -445,12 +440,12 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
|
||||
if ( $customer && $customer['customer_id'] ) {
|
||||
$data['customer_id'] = $customer['customer_id'];
|
||||
$format[] = '%d';
|
||||
$format[] = '%d';
|
||||
}
|
||||
}
|
||||
|
||||
// Update or add the information to the DB.
|
||||
$results = $wpdb->replace( $table_name, $data, $format );
|
||||
$result = $wpdb->replace( $table_name, $data, $format );
|
||||
|
||||
/**
|
||||
* Fires when order's stats reports are updated.
|
||||
|
@ -458,7 +453,8 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
* @param int $order_id Order ID.
|
||||
*/
|
||||
do_action( 'woocommerce_reports_update_order_stats', $order->get_id() );
|
||||
return $results;
|
||||
|
||||
return ( 1 === $result );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -82,15 +82,6 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up all the hooks for maintaining and populating table data.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( 'save_post', array( __CLASS__, 'sync_order_products' ) );
|
||||
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_products' ) );
|
||||
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_products' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills ORDER BY clause of SQL request based on user supplied parameters.
|
||||
*
|
||||
|
@ -319,7 +310,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
*
|
||||
* @since 3.5.0
|
||||
* @param int $order_id Order ID.
|
||||
* @return void
|
||||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function sync_order_products( $order_id ) {
|
||||
global $wpdb;
|
||||
|
@ -328,10 +319,13 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
|
||||
// This hook gets called on refunds as well, so return early to avoid errors.
|
||||
if ( ! $order || 'shop_order_refund' === $order->get_type() ) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
foreach ( $order->get_items() as $order_item ) {
|
||||
$order_items = $order->get_items();
|
||||
$num_updated = 0;
|
||||
|
||||
foreach ( $order_items as $order_item ) {
|
||||
$order_item_id = $order_item->get_id();
|
||||
$quantity_refunded = $order->get_item_quantity_refunded( $order_item );
|
||||
$amount_refunded = $order->get_item_amount_refunded( $order_item );
|
||||
|
@ -355,7 +349,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
$net_revenue = $order_item->get_subtotal( 'edit' ) - $amount_refunded;
|
||||
|
||||
if ( $quantity_refunded >= $order_item->get_quantity( 'edit' ) ) {
|
||||
$wpdb->delete(
|
||||
$result = $wpdb->delete(
|
||||
$wpdb->prefix . self::TABLE_NAME,
|
||||
array( 'order_item_id' => $order_item_id ),
|
||||
array( '%d' )
|
||||
|
@ -369,7 +363,7 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
*/
|
||||
do_action( 'woocommerce_reports_delete_product', $order_item_id, $order->get_id() );
|
||||
} else {
|
||||
$wpdb->replace(
|
||||
$result = $wpdb->replace(
|
||||
$wpdb->prefix . self::TABLE_NAME,
|
||||
array(
|
||||
'order_item_id' => $order_item_id,
|
||||
|
@ -414,6 +408,10 @@ class WC_Admin_Reports_Products_Data_Store extends WC_Admin_Reports_Data_Store i
|
|||
*/
|
||||
do_action( 'woocommerce_reports_update_product', $order_item_id, $order->get_id() );
|
||||
}
|
||||
|
||||
$num_updated += intval( $result );
|
||||
}
|
||||
|
||||
return ( count( $order_items ) === $num_updated );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,21 +60,12 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl
|
|||
*/
|
||||
public function __construct() {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
// Avoid ambigious columns in SQL query.
|
||||
$this->report_columns['tax_rate_id'] = $table_name . '.' . $this->report_columns['tax_rate_id'];
|
||||
$this->report_columns['orders_count'] = str_replace( 'order_id', $table_name . '.order_id', $this->report_columns['orders_count'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up all the hooks for maintaining and populating table data.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( 'save_post', array( __CLASS__, 'sync_order_taxes' ) );
|
||||
add_action( 'clean_post_cache', array( __CLASS__, 'sync_order_taxes' ) );
|
||||
add_action( 'woocommerce_order_refunded', array( __CLASS__, 'sync_order_taxes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the database query with parameters used for Taxes report: categories and order status.
|
||||
*
|
||||
|
@ -255,17 +246,20 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl
|
|||
* Create or update an entry in the wc_order_tax_lookup table for an order.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @return void
|
||||
* @return int|bool Returns -1 if order won't be processed, or a boolean indicating processing success.
|
||||
*/
|
||||
public static function sync_order_taxes( $order_id ) {
|
||||
global $wpdb;
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
foreach ( $order->get_items( 'tax' ) as $tax_item ) {
|
||||
$wpdb->replace(
|
||||
$tax_items = $order->get_items( 'tax' );
|
||||
$num_updated = 0;
|
||||
|
||||
foreach ( $tax_items as $tax_item ) {
|
||||
$result = $wpdb->replace(
|
||||
$wpdb->prefix . self::TABLE_NAME,
|
||||
array(
|
||||
'order_id' => $order->get_id(),
|
||||
|
@ -292,7 +286,11 @@ class WC_Admin_Reports_Taxes_Data_Store extends WC_Admin_Reports_Data_Store impl
|
|||
* @param int $order_id Order ID.
|
||||
*/
|
||||
do_action( 'woocommerce_reports_update_tax', $tax_item->get_rate_id(), $order->get_id() );
|
||||
|
||||
$num_updated += intval( $result );
|
||||
}
|
||||
|
||||
return ( count( $tax_items ) === $num_updated );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,11 +60,11 @@
|
|||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.0.tgz",
|
||||
"integrity": "sha512-dZTwMvTgWfhmibq4V9X+LMf6Bgl7zAodRn9PvcPdhlzFMbvUutx74dbEv7Atz3ToeEpevYEJtAwfxq/bDCzHWg==",
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.2.tgz",
|
||||
"integrity": "sha512-f3QCuPppXxtZOEm5GWPra/uYUjmNQlu9pbAD8D/9jze4pTY83rTtB1igTBSwvkeNlC5gR24zFFkz+2WHLFQhqQ==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.3.0",
|
||||
"@babel/types": "^7.3.2",
|
||||
"jsesc": "^2.5.1",
|
||||
"lodash": "^4.17.10",
|
||||
"source-map": "^0.5.0",
|
||||
|
@ -274,9 +274,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.1.tgz",
|
||||
"integrity": "sha512-ATz6yX/L8LEnC3dtLQnIx4ydcPxhLcoy9Vl6re00zb2w5lG6itY6Vhnr1KFRPq/FHNsgl/gh2mjNN20f9iJTTA=="
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.2.tgz",
|
||||
"integrity": "sha512-QzNUC2RO1gadg+fs21fi0Uu0OuGNzRKEmgCxoLNzbCdoprLwjfmZwzUrpUNfJPaVRwBpDY47A17yYEGWyRelnQ=="
|
||||
},
|
||||
"@babel/plugin-proposal-async-generator-functions": {
|
||||
"version": "7.2.0",
|
||||
|
@ -298,9 +298,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-proposal-object-rest-spread": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.1.tgz",
|
||||
"integrity": "sha512-Nmmv1+3LqxJu/V5jU9vJmxR/KIRWFk2qLHmbB56yRRRFhlaSuOVXscX3gUmhaKgUhzA3otOHVubbIEVYsZ0eZg==",
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz",
|
||||
"integrity": "sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.0.0",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.2.0"
|
||||
|
@ -424,9 +424,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/plugin-transform-destructuring": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.2.0.tgz",
|
||||
"integrity": "sha512-coVO2Ayv7g0qdDbrNiadE4bU7lvCd9H539m2gMknyVjjMdwF/iCOM7R+E8PkntoqLkltO0rk+3axhpp/0v68VQ==",
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz",
|
||||
"integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.0.0"
|
||||
}
|
||||
|
@ -730,9 +730,9 @@
|
|||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.0.tgz",
|
||||
"integrity": "sha512-QkFPw68QqWU1/RVPyBe8SO7lXbPfjtqAxRYQKpFpaB8yMq7X2qAqfwK5LKoQufEkSmO5NQ70O6Kc3Afk03RwXw==",
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.2.tgz",
|
||||
"integrity": "sha512-3Y6H8xlUlpbGR+XvawiH0UXehqydTmNmEpozWcXymqwcrwYAl5KMvKtQ+TF6f6E08V6Jur7v/ykdDSF+WDEIXQ==",
|
||||
"requires": {
|
||||
"esutils": "^2.0.2",
|
||||
"lodash": "^4.17.10",
|
||||
|
@ -1765,21 +1765,21 @@
|
|||
}
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
|
||||
"integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
|
||||
"integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^3.0.0",
|
||||
"chalk": "^2.0.0",
|
||||
"ansi-escapes": "^3.2.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cli-cursor": "^2.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash": "^4.17.11",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rxjs": "^6.1.0",
|
||||
"rxjs": "^6.4.0",
|
||||
"string-width": "^2.1.0",
|
||||
"strip-ansi": "^5.0.0",
|
||||
"through": "^2.3.6"
|
||||
|
@ -2113,9 +2113,9 @@
|
|||
"integrity": "sha512-y+h7tNlxDPDrH/TrSw1wCSm6FoEAY8FrbUxYng3BMSYBTUsX1utLooizk9v8J1yy6F9AioXNnPZ1qiu2vsa08Q=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "10.12.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.19.tgz",
|
||||
"integrity": "sha512-2NVovndCjJQj6fUUn9jCgpP4WSqr+u1SoUZMZyJkhGeBFsm6dE46l31S7lPUYt9uQ28XI+ibrJA1f5XyH5HNtA=="
|
||||
"version": "10.12.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.21.tgz",
|
||||
"integrity": "sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ=="
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.7.11",
|
||||
|
@ -2999,9 +2999,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz",
|
||||
"integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA=="
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.7.tgz",
|
||||
"integrity": "sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3060,9 +3060,9 @@
|
|||
}
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz",
|
||||
"integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==",
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.8.1.tgz",
|
||||
"integrity": "sha512-eqxCp82P+JfqL683wwsL73XmFs1eG6qjw+RD3YHx+Jll1r0jNd4dh8QG9NYAeNGA/hnZjeEDgtTskgJULbxpWQ==",
|
||||
"requires": {
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
@ -4262,9 +4262,9 @@
|
|||
}
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz",
|
||||
"integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz",
|
||||
"integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==",
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
|
@ -4632,9 +4632,9 @@
|
|||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30000932",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000932.tgz",
|
||||
"integrity": "sha512-4bghJFItvzz8m0T3lLZbacmEY9X1Z2AtIzTr7s7byqZIOumASfr4ynDx7rtm0J85nDmx8vsgR6vnaSoeU8Oh0A=="
|
||||
"version": "1.0.30000934",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000934.tgz",
|
||||
"integrity": "sha512-o7yfZn0R9N+mWAuksDsdLsb1gu9o//XK0QSU0zSSReKNRsXsFc/n/psxi0YSPNiqlKxImp5h4DHnAPdwYJ8nNA=="
|
||||
},
|
||||
"capture-exit": {
|
||||
"version": "1.2.0",
|
||||
|
@ -6357,9 +6357,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"cssom": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.4.tgz",
|
||||
"integrity": "sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog=="
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz",
|
||||
"integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A=="
|
||||
},
|
||||
"cssstyle": {
|
||||
"version": "1.1.1",
|
||||
|
@ -6456,17 +6456,17 @@
|
|||
"integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg=="
|
||||
},
|
||||
"d3-shape": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.3.tgz",
|
||||
"integrity": "sha512-f7V9wHQCmv4s4N7EmD5i0mwJ5y09L8r1rWVrzH1Av0YfgBKJCnTJGho76rS4HNUIw6tTBbWfFcs4ntP/MKWF4A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.4.tgz",
|
||||
"integrity": "sha512-izaz4fOpOnY3CD17hkZWNxbaN70sIGagLR/5jb6RS96Y+6VqX+q1BQf1av6QSBRdfULi3Gb8Js4CzG4+KAPjMg==",
|
||||
"requires": {
|
||||
"d3-path": "1"
|
||||
}
|
||||
},
|
||||
"d3-time": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.10.tgz",
|
||||
"integrity": "sha512-hF+NTLCaJHF/JqHN5hE8HVGAXPStEq6/omumPE/SxyHVrR7/qQxusFDo0t0c/44+sCGHthC7yNGFZIEgju0P8g=="
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
|
||||
"integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
|
||||
},
|
||||
"d3-time-format": {
|
||||
"version": "2.1.3",
|
||||
|
@ -7234,9 +7234,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"duplexify": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz",
|
||||
"integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==",
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
|
||||
"integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"end-of-stream": "^1.0.0",
|
||||
|
@ -7317,9 +7317,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.109",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.109.tgz",
|
||||
"integrity": "sha512-1qhgVZD9KIULMyeBkbjU/dWmm30zpPUfdWZfVO3nPhbtqMHJqHr4Ua5wBcWtAymVFrUCuAJxjMF1OhG+bR21Ow=="
|
||||
"version": "1.3.113",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz",
|
||||
"integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.4.1",
|
||||
|
@ -7422,9 +7422,9 @@
|
|||
}
|
||||
},
|
||||
"enzyme-adapter-react-16": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.8.0.tgz",
|
||||
"integrity": "sha512-7cVHIKutqnesGeM3CjNFHSvktpypSWBokrBO8wIW+BVx+HGxWCF87W9TpkIIYJqgCtdw9FQGFrAbLg8kSwPRuQ==",
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.9.0.tgz",
|
||||
"integrity": "sha512-tUqmeLi0Y3PxuiPSykjn8ZMqzCnaRIVywNx0i50+nhd4y/b3JtXRbsvIc8HKxn3heE4t969EI2461Kc9FYxjdw==",
|
||||
"requires": {
|
||||
"enzyme-adapter-utils": "^1.10.0",
|
||||
"function.prototype.name": "^1.1.0",
|
||||
|
@ -7607,9 +7607,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.6.tgz",
|
||||
"integrity": "sha512-5M3G/A4uBSMIlfJ+h9W125vJvPFH/zirISsW5qfxF5YzEvXJCtolLoQvM5yZft0DvMcUrPGKPOlgEu55I6iUtA==",
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.7.tgz",
|
||||
"integrity": "sha512-HNJNgE60C9eOTgn974Tlp3dpLZdUr+SoxxDwPaY9J/kDNOLQTkaDgwBUXAF4SSsrAwD9RpdxuHK/EbuF+W9Ahw==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-jsx": {
|
||||
|
@ -7682,21 +7682,21 @@
|
|||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
|
||||
"integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
|
||||
"integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^3.0.0",
|
||||
"chalk": "^2.0.0",
|
||||
"ansi-escapes": "^3.2.0",
|
||||
"chalk": "^2.4.2",
|
||||
"cli-cursor": "^2.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash": "^4.17.11",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rxjs": "^6.1.0",
|
||||
"rxjs": "^6.4.0",
|
||||
"string-width": "^2.1.0",
|
||||
"strip-ansi": "^5.0.0",
|
||||
"through": "^2.3.6"
|
||||
|
@ -8656,39 +8656,13 @@
|
|||
"dev": true
|
||||
},
|
||||
"flush-write-stream": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
|
||||
"integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.0.tgz",
|
||||
"integrity": "sha512-6MHED/cmsyux1G4/Cek2Z776y9t7WCNd3h2h/HW91vFeU7pzMhA8XvAlDhHcanG5IWuIh/xcC7JASY4WQpG6xg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^2.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"readable-stream": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
}
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"for-in": {
|
||||
|
@ -11339,8 +11313,7 @@
|
|||
"is-wsl": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
|
||||
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
|
@ -13263,11 +13236,11 @@
|
|||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.1.tgz",
|
||||
"integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==",
|
||||
"version": "0.25.2",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz",
|
||||
"integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==",
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.1"
|
||||
"sourcemap-codec": "^1.4.4"
|
||||
}
|
||||
},
|
||||
"make-dir": {
|
||||
|
@ -14163,20 +14136,21 @@
|
|||
}
|
||||
},
|
||||
"node-notifier": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.3.0.tgz",
|
||||
"integrity": "sha512-AhENzCSGZnZJgBARsUjnQ7DnZbzyP+HxlVXuD0xqAnvL8q+OqtSX7lGg9e8nHzwXkMMXNdVeqq4E2M3EUAqX6Q==",
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz",
|
||||
"integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==",
|
||||
"requires": {
|
||||
"growly": "^1.3.0",
|
||||
"is-wsl": "^1.1.0",
|
||||
"semver": "^5.5.0",
|
||||
"shellwords": "^0.1.1",
|
||||
"which": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.6.tgz",
|
||||
"integrity": "sha512-lODUVHEIZutZx+TDdOk47qLik8FJMXzJ+WnyUGci1MTvTOyzZrz5eVPIIpc5Hb3NfHZGeGHeuwrRYVI1PEITWg==",
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.7.tgz",
|
||||
"integrity": "sha512-bKdrwaqJUPHqlCzDD7so/R+Nk0jGv9a11ZhLrD9f6i947qGLrGAhU3OxRENa19QQmwzGy/g6zCDEuLGDO8HPvA==",
|
||||
"requires": {
|
||||
"semver": "^5.3.0"
|
||||
}
|
||||
|
@ -14457,13 +14431,14 @@
|
|||
}
|
||||
},
|
||||
"npm-package-json-lint": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-3.4.1.tgz",
|
||||
"integrity": "sha512-W4xlmeFRAY34GQoHUywqoI3PxVZ0hugjbZLiGnVgFjgmvRRcmxKwwmubMe0lAD78vgOHgJZRGubdVXwkp9d3QA==",
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-3.5.0.tgz",
|
||||
"integrity": "sha512-MELethOnZW5uVzP65oTQEH2fI6eS/BQEXjvOTyQkUQqGHP9si5pxCWcO+Q4dsahb+4yG7GMxFhpF42AjhCbgRA==",
|
||||
"requires": {
|
||||
"ajv": "^6.5.4",
|
||||
"chalk": "^2.4.1",
|
||||
"ajv": "^6.7.0",
|
||||
"chalk": "^2.4.2",
|
||||
"glob": "^7.1.3",
|
||||
"ignore": "^5.0.5",
|
||||
"is-path-inside": "^2.0.0",
|
||||
"is-plain-obj": "^1.1.0",
|
||||
"is-resolvable": "^1.1.0",
|
||||
|
@ -14472,7 +14447,14 @@
|
|||
"plur": "^3.0.1",
|
||||
"semver": "^5.6.0",
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"validator": "^10.8.0"
|
||||
"validator": "^10.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ignore": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.0.5.tgz",
|
||||
"integrity": "sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-packlist": {
|
||||
|
@ -14561,9 +14543,9 @@
|
|||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||
},
|
||||
"nwsapi": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz",
|
||||
"integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ=="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.0.tgz",
|
||||
"integrity": "sha512-ZG3bLAvdHmhIjaQ/Db1qvBxsGvFMLIRpQszyqbg31VJ53UP++uZX1/gf3Ut96pdwN9AuDwlMqIYLm0UPCdUeHg=="
|
||||
},
|
||||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
|
@ -19717,9 +19699,9 @@
|
|||
}
|
||||
},
|
||||
"stylelint-scss": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.5.1.tgz",
|
||||
"integrity": "sha512-XNWKTU1a2EUNWdauxHPTJlGNNQzIbg48OTTIdBs5xTXxpbYAGtX/J+jBqMPjxfdySXijc/mexubuZ+ZinUGGgw==",
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.5.2.tgz",
|
||||
"integrity": "sha512-HL95s8Q6wihbJe7c7z6rL9GHVHOF3H3tXkVmGutitwn14LYR52JYMwCkcifqlf4nRsvXrUDaoH6OHOdilifyjw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.11",
|
||||
|
@ -19931,14 +19913,14 @@
|
|||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-3.14.1.tgz",
|
||||
"integrity": "sha512-NSo3E99QDbYSMeJaEk9YW2lTg3qS9V0aKGlb+PlOrei1X02r1wSBHCNX/O+yeTRFSWPKPIGj6MqvvdqV4rnVGw==",
|
||||
"version": "3.16.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz",
|
||||
"integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "~2.17.1",
|
||||
"source-map": "~0.6.1",
|
||||
"source-map-support": "~0.5.6"
|
||||
"source-map-support": "~0.5.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
|
@ -19966,9 +19948,9 @@
|
|||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.1.tgz",
|
||||
"integrity": "sha512-GGSt+gbT0oKcMDmPx4SRSfJPE1XaN3kQRWG4ghxKQw9cn5G9x6aCKSsgYdvyM0na9NJ4Drv0RG6jbBByZ5CMjw==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz",
|
||||
"integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^11.0.2",
|
||||
|
@ -19976,7 +19958,7 @@
|
|||
"schema-utils": "^1.0.0",
|
||||
"serialize-javascript": "^1.4.0",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^3.8.1",
|
||||
"terser": "^3.16.1",
|
||||
"webpack-sources": "^1.1.0",
|
||||
"worker-farm": "^1.5.2"
|
||||
},
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# 1.5.0 (unreleased)
|
||||
- Improves display of charts where all values are 0.
|
||||
- Fix X-axis labels in hourly bar charts.
|
||||
- New `<Search>` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags.
|
||||
|
||||
# 1.4.2
|
||||
- Add emoji-flags dependency
|
||||
|
||||
|
@ -5,7 +10,6 @@
|
|||
- Chart component: format numbers and prices using store currency settings.
|
||||
- Make `href`/linking optional in SummaryNumber.
|
||||
- Fix SummaryNumber example code.
|
||||
- New `<Search>` prop named `showClearButton`, that will display a 'Clear' button when the search box contains one or more tags.
|
||||
|
||||
# 1.4.0
|
||||
- Add download log ip address autocompleter to search component
|
||||
|
|
|
@ -197,7 +197,7 @@ export const drawAxis = ( node, params, xOffset ) => {
|
|||
: compareStrings( formatter( prevMonth ), formatter( monthDate ) ).join( ' ' );
|
||||
};
|
||||
|
||||
const yGrids = getYGrids( params.yMax );
|
||||
const yGrids = getYGrids( params.yMax === 0 ? 1 : params.yMax );
|
||||
|
||||
const ticks = params.xTicks.map( d => ( params.type === 'line' ? moment( d ).toDate() : d ) );
|
||||
|
||||
|
@ -210,7 +210,7 @@ export const drawAxis = ( node, params, xOffset ) => {
|
|||
d3AxisBottom( xScale )
|
||||
.tickValues( ticks )
|
||||
.tickFormat( ( d, i ) => params.interval === 'hour'
|
||||
? params.xFormat( d )
|
||||
? params.xFormat( d instanceof Date ? d : moment( d ).toDate() )
|
||||
: removeDuplicateDates( d, i, ticks, params.xFormat ) )
|
||||
);
|
||||
|
||||
|
@ -257,7 +257,7 @@ export const drawAxis = ( node, params, xOffset ) => {
|
|||
.attr( 'text-anchor', 'start' )
|
||||
.call(
|
||||
d3AxisLeft( params.yTickOffset )
|
||||
.tickValues( yGrids )
|
||||
.tickValues( params.yMax === 0 ? [ yGrids[ 0 ] ] : yGrids )
|
||||
.tickFormat( d => params.yFormat( d !== 0 ? d : 0 ) )
|
||||
);
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export const getYMax = lineData => {
|
|||
*/
|
||||
export const getYScale = ( height, yMax ) =>
|
||||
d3ScaleLinear()
|
||||
.domain( [ 0, yMax ] )
|
||||
.domain( [ 0, yMax === 0 ? 1 : yMax ] )
|
||||
.rangeRound( [ height, 0 ] );
|
||||
|
||||
/**
|
||||
|
@ -83,5 +83,5 @@ export const getYScale = ( height, yMax ) =>
|
|||
*/
|
||||
export const getYTickOffset = ( height, yMax ) =>
|
||||
d3ScaleLinear()
|
||||
.domain( [ 0, yMax ] )
|
||||
.domain( [ 0, yMax === 0 ? 1 : yMax ] )
|
||||
.rangeRound( [ height + 12, 12 ] );
|
||||
|
|
|
@ -107,6 +107,14 @@ describe( 'Y scales', () => {
|
|||
expect( scaleLinear().domain ).toHaveBeenLastCalledWith( [ 0, 15000000 ] );
|
||||
expect( scaleLinear().rangeRound ).toHaveBeenLastCalledWith( [ 100, 0 ] );
|
||||
} );
|
||||
|
||||
it( 'avoids the domain starting and ending at the same point when yMax is 0', () => {
|
||||
getYScale( 100, 0 );
|
||||
|
||||
const args = scaleLinear().domain.mock.calls;
|
||||
const lastArgs = args[ args.length - 1 ][ 0 ];
|
||||
expect( lastArgs[ 0 ] ).toBeLessThan( lastArgs[ 1 ] );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'getYTickOffset', () => {
|
||||
|
@ -116,5 +124,13 @@ describe( 'Y scales', () => {
|
|||
expect( scaleLinear().domain ).toHaveBeenLastCalledWith( [ 0, 15000000 ] );
|
||||
expect( scaleLinear().rangeRound ).toHaveBeenLastCalledWith( [ 112, 12 ] );
|
||||
} );
|
||||
|
||||
it( 'avoids the domain starting and ending at the same point when yMax is 0', () => {
|
||||
getYTickOffset( 100, 0 );
|
||||
|
||||
const args = scaleLinear().domain.mock.calls;
|
||||
const lastArgs = args[ args.length - 1 ][ 0 ];
|
||||
expect( lastArgs[ 0 ] ).toBeLessThan( lastArgs[ 1 ] );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
.woocommerce-search__clear {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: calc( 50% - 10px );
|
||||
top: calc(50% - 10px);
|
||||
|
||||
& > .dashicon {
|
||||
color: #c9c9c9;
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
/**
|
||||
* REST API Init Class Test
|
||||
*
|
||||
* @package WooCommerce\Tests\API
|
||||
* @since 3.5.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Tests_API_Init
|
||||
*/
|
||||
class WC_Tests_API_Init extends WC_REST_Unit_Test_Case {
|
||||
/**
|
||||
* Set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->queue = new WC_Admin_Test_Action_Queue();
|
||||
WC_Admin_Api_Init::set_queue( $this->queue );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down.
|
||||
*/
|
||||
public function tearDown() {
|
||||
parent::tearDown();
|
||||
WC_Admin_Api_Init::set_queue( null );
|
||||
$this->queue->actions = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause a failure when updating order stats for the test order, without deleting it.
|
||||
*
|
||||
* @param string $query Query.
|
||||
* @return string
|
||||
*/
|
||||
public function filter_order_query( $query ) {
|
||||
if (
|
||||
0 === strpos( $query, 'REPLACE INTO' ) &&
|
||||
false !== strpos( $query, WC_Admin_Reports_Orders_Stats_Data_Store::TABLE_NAME )
|
||||
) {
|
||||
remove_filter( 'query', array( $this, 'filter_order_query' ) );
|
||||
return 'THIS WONT MATCH';
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a retry job is scheduled for a failed sync.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_order_sync_retries_on_failure() {
|
||||
// Create a test Order.
|
||||
$product = new WC_Product_Simple();
|
||||
$product->set_name( 'Test Product' );
|
||||
$product->set_regular_price( 25 );
|
||||
$product->save();
|
||||
|
||||
$order = WC_Helper_Order::create_order( 1, $product );
|
||||
$order->set_status( 'completed' );
|
||||
$order->set_total( 100 ); // $25 x 4.
|
||||
$order->save();
|
||||
|
||||
// Clear the existing action queue (the above save adds an action).
|
||||
$this->queue->actions = array();
|
||||
|
||||
// Force a failure by sabotaging the query run after retreiving order coupons.
|
||||
add_filter( 'query', array( $this, 'filter_order_query' ) );
|
||||
|
||||
// Initiate sync.
|
||||
WC_Admin_Api_Init::orders_lookup_process_order( $order->get_id() );
|
||||
|
||||
// Verify that a retry job was scheduled.
|
||||
$this->assertCount( 1, $this->queue->actions );
|
||||
$this->assertArraySubset(
|
||||
array(
|
||||
'hook' => WC_Admin_Api_Init::SINGLE_ORDER_ACTION,
|
||||
'args' => array( $order->get_id() ),
|
||||
),
|
||||
$this->queue->actions[0]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -64,6 +64,8 @@ class WC_Tests_API_Reports_Categories extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 100 ); // $25 x 4.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
|
|
|
@ -87,6 +87,8 @@ class WC_Tests_API_Reports_Coupons_Stats extends WC_REST_Unit_Test_Case {
|
|||
$order_2c->set_date_created( $time );
|
||||
$order_2c->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
|
|
|
@ -82,6 +82,8 @@ class WC_Tests_API_Reports_Coupons extends WC_REST_Unit_Test_Case {
|
|||
$order_2c->calculate_totals();
|
||||
$order_2c->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
$coupon_reports = $response->get_data();
|
||||
|
||||
|
|
|
@ -126,6 +126,8 @@ class WC_Tests_API_Reports_Customers_Stats extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 9.12 );
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
|
|
|
@ -134,6 +134,8 @@ class WC_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 100 );
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
|
|
|
@ -67,6 +67,8 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 100 ); // $25 x 4.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$expected_customer_id = WC_Admin_Reports_Customers_Data_Store::get_customer_id_by_user_id( 1 );
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
|
|
|
@ -84,6 +84,8 @@ class WC_Tests_API_Reports_Performance_Indicators extends WC_REST_Unit_Test_Case
|
|||
$object->set_user_ip_address( '1.2.3.4' );
|
||||
$object->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$time = time();
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
|
|
|
@ -71,6 +71,8 @@ class WC_Tests_API_Reports_Products_Stats extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
|
|
|
@ -67,6 +67,8 @@ class WC_Tests_API_Reports_Products extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 100 ); // $25 x 4.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
$reports = $response->get_data();
|
||||
|
||||
|
|
|
@ -91,6 +91,8 @@ class WC_Tests_API_Reports_Taxes extends WC_REST_Unit_Test_Case {
|
|||
)
|
||||
);
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
$reports = $response->get_data();
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ class WC_Tests_API_Reports_Variations extends WC_REST_Unit_Test_Case {
|
|||
$order->set_total( 100 ); // $25 x 4.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', $this->endpoint ) );
|
||||
$reports = $response->get_data();
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case {
|
|||
// insert a blocking job.
|
||||
WC_Admin_Api_Init::queue()->schedule_single( time(), 'blocking_job', array( 'stuff' ) );
|
||||
// queue an action that depends on blocking job.
|
||||
WC_Admin_Api_Init::queue_dependent_action( 'dependent_action', 'blocking_job' );
|
||||
WC_Admin_Api_Init::queue_dependent_action( 'dependent_action', array(), 'blocking_job' );
|
||||
// verify that the action was properly blocked.
|
||||
$this->assertEmpty(
|
||||
WC_Admin_Api_Init::queue()->search(
|
||||
|
@ -151,13 +151,13 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case {
|
|||
WC_Admin_Api_Init::queue()->search(
|
||||
array(
|
||||
'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION,
|
||||
'args' => array( 'dependent_action', 'blocking_job' ),
|
||||
'args' => array( 'dependent_action', array(), 'blocking_job' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// queue an action that isn't blocked.
|
||||
WC_Admin_Api_Init::queue_dependent_action( 'another_dependent_action', 'nonexistant_blocking_job' );
|
||||
WC_Admin_Api_Init::queue_dependent_action( 'another_dependent_action', array(), 'nonexistant_blocking_job' );
|
||||
// verify that the dependent action was queued.
|
||||
$this->assertCount(
|
||||
1,
|
||||
|
@ -172,7 +172,7 @@ class WC_Tests_Reports_Regenerate_Batching extends WC_REST_Unit_Test_Case {
|
|||
WC_Admin_Api_Init::queue()->search(
|
||||
array(
|
||||
'hook' => WC_Admin_Api_Init::QUEUE_DEPEDENT_ACTION,
|
||||
'args' => array( 'another_dependent_action', 'nonexistant_blocking_job' ),
|
||||
'args' => array( 'another_dependent_action', array(), 'nonexistant_blocking_job' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -123,3 +123,4 @@ wc_test_includes();
|
|||
require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-reports.php';
|
||||
require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-admin-notes.php';
|
||||
require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-test-action-queue.php';
|
||||
require_once dirname( __FILE__ ) . '/framework/helpers/class-wc-helper-queue.php';
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper code for wc-admin unit tests.
|
||||
*
|
||||
* @package WooCommerce\Tests\Framework\Helpers
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Helper_Queue.
|
||||
*
|
||||
* This helper class should ONLY be used for unit tests!.
|
||||
*/
|
||||
class WC_Helper_Queue {
|
||||
/**
|
||||
* Run all pending queued actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function run_all_pending() {
|
||||
$jobs = WC()->queue()->search(
|
||||
array(
|
||||
'per_page' => -1,
|
||||
'status' => 'pending',
|
||||
'claimed' => false,
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $jobs as $job ) {
|
||||
$job->execute();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,6 +54,8 @@ class WC_Tests_Reports_Coupons_Stats extends WC_Unit_Test_Case {
|
|||
$order_2c->calculate_totals();
|
||||
$order_2c->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Coupons_Stats_Data_Store();
|
||||
$start_time = date( 'Y-m-d 00:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d 23:59:59', $order->get_date_created()->getOffsetTimestamp() );
|
||||
|
|
|
@ -54,6 +54,8 @@ class WC_Tests_Reports_Coupons extends WC_Unit_Test_Case {
|
|||
$order_2c->calculate_totals();
|
||||
$order_2c->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Coupons_Data_Store();
|
||||
$start_time = date( 'Y-m-d 00:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d 23:59:59', $order->get_date_created()->getOffsetTimestamp() );
|
||||
|
|
|
@ -36,11 +36,13 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
|
|||
|
||||
$refund = wc_create_refund(
|
||||
array(
|
||||
'amount' => 12,
|
||||
'order_id' => $order->get_id(),
|
||||
'amount' => 12,
|
||||
'order_id' => $order->get_id(),
|
||||
)
|
||||
);
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Orders_Stats_Data_Store();
|
||||
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
|
@ -142,6 +144,162 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
|
|||
$this->assertEquals( $expected_stats, json_decode( json_encode( $query->get_data() ), true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that querying statuses includes the default or query-specific statuses.
|
||||
*/
|
||||
public function test_populate_and_query_statuses() {
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
// Populate all of the data.
|
||||
$product = new WC_Product_Simple();
|
||||
$product->set_name( 'Test Product' );
|
||||
$product->set_regular_price( 25 );
|
||||
$product->save();
|
||||
|
||||
$order_types = array(
|
||||
array(
|
||||
'status' => 'refunded',
|
||||
'total' => 50,
|
||||
),
|
||||
array(
|
||||
'status' => 'completed',
|
||||
'total' => 100,
|
||||
),
|
||||
array(
|
||||
'status' => 'failed',
|
||||
'total' => 75,
|
||||
),
|
||||
);
|
||||
|
||||
foreach ( $order_types as $order_type ) {
|
||||
$order = WC_Helper_Order::create_order( 1, $product );
|
||||
$order->set_status( $order_type['status'] );
|
||||
$order->set_total( $order_type['total'] );
|
||||
$order->set_shipping_total( 0 );
|
||||
$order->set_cart_tax( 0 );
|
||||
$order->save();
|
||||
|
||||
// Wait one second to avoid potentially ambiguous new/returning customer.
|
||||
sleep( 1 );
|
||||
}
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Orders_Stats_Data_Store();
|
||||
|
||||
$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() );
|
||||
|
||||
// Query default statuses that should not include excluded or refunded order statuses.
|
||||
$args = array(
|
||||
'interval' => 'hour',
|
||||
'after' => $start_time,
|
||||
'before' => $end_time,
|
||||
);
|
||||
$expected_stats = array(
|
||||
'totals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'avg_items_per_order' => 4,
|
||||
'avg_order_value' => 100,
|
||||
'gross_revenue' => 100,
|
||||
'coupons' => 0,
|
||||
'refunds' => 0,
|
||||
'taxes' => 0,
|
||||
'shipping' => 0,
|
||||
'net_revenue' => 100,
|
||||
'num_returning_customers' => 1,
|
||||
'num_new_customers' => 0,
|
||||
'products' => 1,
|
||||
'segments' => array(),
|
||||
),
|
||||
'intervals' => array(
|
||||
array(
|
||||
'interval' => date( 'Y-m-d H', $order->get_date_created()->getOffsetTimestamp() ),
|
||||
'date_start' => $start_time,
|
||||
'date_start_gmt' => $start_time,
|
||||
'date_end' => $end_time,
|
||||
'date_end_gmt' => $end_time,
|
||||
'subtotals' => array(
|
||||
'gross_revenue' => 100,
|
||||
'net_revenue' => 100,
|
||||
'coupons' => 0,
|
||||
'shipping' => 0,
|
||||
'taxes' => 0,
|
||||
'refunds' => 0,
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'avg_items_per_order' => 4,
|
||||
'avg_order_value' => 100,
|
||||
'num_returning_customers' => 1,
|
||||
'num_new_customers' => 0,
|
||||
'segments' => array(),
|
||||
),
|
||||
),
|
||||
),
|
||||
'total' => 1,
|
||||
'pages' => 1,
|
||||
'page_no' => 1,
|
||||
);
|
||||
|
||||
$this->assertEquals( $expected_stats, json_decode( json_encode( $data_store->get_data( $args ) ), true ) );
|
||||
|
||||
// Query an excluded status which should still return orders with the queried status.
|
||||
$args = array(
|
||||
'interval' => 'hour',
|
||||
'after' => $start_time,
|
||||
'before' => $end_time,
|
||||
'status_is' => array( 'failed' ),
|
||||
);
|
||||
$expected_stats = array(
|
||||
'totals' => array(
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'avg_items_per_order' => 4,
|
||||
'avg_order_value' => 75,
|
||||
'gross_revenue' => 75,
|
||||
'coupons' => 0,
|
||||
'refunds' => 0,
|
||||
'taxes' => 0,
|
||||
'shipping' => 0,
|
||||
'net_revenue' => 75,
|
||||
'num_returning_customers' => 1,
|
||||
'num_new_customers' => 0,
|
||||
'products' => 1,
|
||||
'segments' => array(),
|
||||
),
|
||||
'intervals' => array(
|
||||
array(
|
||||
'interval' => date( 'Y-m-d H', $order->get_date_created()->getOffsetTimestamp() ),
|
||||
'date_start' => $start_time,
|
||||
'date_start_gmt' => $start_time,
|
||||
'date_end' => $end_time,
|
||||
'date_end_gmt' => $end_time,
|
||||
'subtotals' => array(
|
||||
'gross_revenue' => 75,
|
||||
'net_revenue' => 75,
|
||||
'coupons' => 0,
|
||||
'shipping' => 0,
|
||||
'taxes' => 0,
|
||||
'refunds' => 0,
|
||||
'orders_count' => 1,
|
||||
'num_items_sold' => 4,
|
||||
'avg_items_per_order' => 4,
|
||||
'avg_order_value' => 75,
|
||||
'num_returning_customers' => 1,
|
||||
'num_new_customers' => 0,
|
||||
'segments' => array(),
|
||||
),
|
||||
),
|
||||
),
|
||||
'total' => 1,
|
||||
'pages' => 1,
|
||||
'page_no' => 1,
|
||||
);
|
||||
|
||||
$this->assertEquals( $expected_stats, json_decode( json_encode( $data_store->get_data( $args ) ), true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the calculations and querying works correctly for the case of multiple orders.
|
||||
*/
|
||||
|
@ -330,6 +488,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
|
|||
}
|
||||
}
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Orders_Stats_Data_Store();
|
||||
|
||||
// Tests for before & after set to current hour.
|
||||
|
@ -1544,6 +1704,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
|
|||
$returning_order->set_date_created( $order_1_time + 1 ); // This is guaranteed to belong to the same hour by the adjustment to $order_1_time.
|
||||
$returning_order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$query_args = array(
|
||||
'after' => $current_hour_start->format( WC_Admin_Reports_Interval::$sql_datetime_format ), // I don't think this makes sense.... date( 'Y-m-d H:i:s', $orders[0]->get_date_created()->getOffsetTimestamp() + 1 ), // Date after initial order to get a returning customer.
|
||||
'before' => $current_hour_end->format( WC_Admin_Reports_Interval::$sql_datetime_format ),
|
||||
|
@ -3171,6 +3333,8 @@ class WC_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
|
|||
$order_2->calculate_totals();
|
||||
$order_2->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Orders_Stats_Data_Store();
|
||||
|
||||
// Tests for before & after set to current hour.
|
||||
|
|
|
@ -38,6 +38,8 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case {
|
|||
$order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Products_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
|
@ -113,6 +115,8 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case {
|
|||
$order_2->set_date_created( $date_created_2 );
|
||||
$order_2->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Products_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order_2->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
|
@ -211,6 +215,9 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case {
|
|||
$order->set_shipping_tax( 2 );
|
||||
$order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Products_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
|
@ -249,4 +256,76 @@ class WC_Tests_Reports_Products extends WC_Unit_Test_Case {
|
|||
);
|
||||
$this->assertEquals( $expected_data, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that line item refunds are reflected in product stats.
|
||||
*/
|
||||
public function test_populate_and_refund() {
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
// Populate all of the data.
|
||||
$product = new WC_Product_Simple();
|
||||
$product->set_name( 'Test Product' );
|
||||
$product->set_regular_price( 25 );
|
||||
$product->save();
|
||||
|
||||
$order = WC_Helper_Order::create_order( 1, $product );
|
||||
$order->set_status( 'completed' );
|
||||
$order->set_shipping_total( 10 );
|
||||
$order->set_discount_total( 20 );
|
||||
$order->set_discount_tax( 0 );
|
||||
$order->set_cart_tax( 5 );
|
||||
$order->set_shipping_tax( 2 );
|
||||
$order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax.
|
||||
$order->save();
|
||||
|
||||
foreach ( $order->get_items() as $item_key => $item_values ) {
|
||||
$item_data = $item_values->get_data();
|
||||
$refund = wc_create_refund(
|
||||
array(
|
||||
'amount' => 12,
|
||||
'order_id' => $order->get_id(),
|
||||
'line_items' => array(
|
||||
$item_data['id'] => array(
|
||||
'qty' => 1,
|
||||
'refund_total' => 10,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Products_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
$args = array(
|
||||
'after' => $start_time,
|
||||
'before' => $end_time,
|
||||
);
|
||||
|
||||
// Test retrieving the stats through the data store.
|
||||
$data = $data_store->get_data( $args );
|
||||
$expected_data = (object) array(
|
||||
'total' => 1,
|
||||
'pages' => 1,
|
||||
'page_no' => 1,
|
||||
'data' => array(
|
||||
0 => array(
|
||||
'product_id' => $product->get_id(),
|
||||
'items_sold' => 3,
|
||||
'net_revenue' => 90.0, // $25 * 4 - $10 refund.
|
||||
'orders_count' => 1,
|
||||
'extended_info' => new ArrayObject(),
|
||||
),
|
||||
),
|
||||
);
|
||||
$this->assertEquals( $expected_data, $data );
|
||||
|
||||
// Test retrieving the stats through the query class.
|
||||
$query = new WC_Admin_Reports_Products_Query( $args );
|
||||
$this->assertEquals( $expected_data, $query->get_data() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ class WC_Admin_Tests_Reports_Revenue_Stats extends WC_Unit_Test_Case {
|
|||
$order->set_total( 97 ); // $25x4 products + $10 shipping - $20 discount + $7 tax.
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
// /reports/revenue/stats is mapped to Orders_Data_Store.
|
||||
$data_store = new WC_Admin_Reports_Orders_Stats_Data_Store();
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ class WC_Tests_Reports_Variations extends WC_Unit_Test_Case {
|
|||
$order->set_status( 'completed' );
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Variations_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
|
@ -106,6 +108,8 @@ class WC_Tests_Reports_Variations extends WC_Unit_Test_Case {
|
|||
$order->set_status( 'completed' );
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$data_store = new WC_Admin_Reports_Variations_Data_Store();
|
||||
$start_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() );
|
||||
$end_time = date( 'Y-m-d H:00:00', $order->get_date_created()->getOffsetTimestamp() + HOUR_IN_SECONDS );
|
||||
|
|
Loading…
Reference in New Issue