2018-06-14 20:15:11 +00:00
|
|
|
/** @format */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { Component, Fragment } from '@wordpress/element';
|
2018-09-03 15:25:38 +00:00
|
|
|
import { compose } from '@wordpress/compose';
|
2018-08-01 16:00:45 +00:00
|
|
|
import { format as formatDate } from '@wordpress/date';
|
2018-10-16 17:42:13 +00:00
|
|
|
import { map } from 'lodash';
|
2018-06-14 20:15:11 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2018-09-03 15:25:38 +00:00
|
|
|
import { withSelect } from '@wordpress/data';
|
2018-06-14 20:15:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2018-10-16 17:42:13 +00:00
|
|
|
import { Card, ReportFilters, TableCard, TablePlaceholder } from '@woocommerce/components';
|
2018-09-03 07:54:45 +00:00
|
|
|
import { downloadCSVFile, generateCSVDataFromTable, generateCSVFileName } from 'lib/csv';
|
2018-08-01 16:00:45 +00:00
|
|
|
import { formatCurrency, getCurrencyFormatDecimal } from 'lib/currency';
|
2018-10-16 17:42:13 +00:00
|
|
|
import { getAdminLink, onQueryChange } from 'lib/nav-utils';
|
2018-10-17 16:01:58 +00:00
|
|
|
import { appendTimestamp, getCurrentDates, getDateFormatsForInterval, getIntervalForQuery } from 'lib/date';
|
2018-10-16 17:42:13 +00:00
|
|
|
import OrdersReportChart from './chart';
|
2018-06-20 15:09:37 +00:00
|
|
|
|
2018-09-03 15:25:38 +00:00
|
|
|
export class RevenueReport extends Component {
|
2018-06-26 14:59:35 +00:00
|
|
|
constructor() {
|
|
|
|
super();
|
2018-09-03 07:54:45 +00:00
|
|
|
this.onDownload = this.onDownload.bind( this );
|
2018-06-26 21:02:08 +00:00
|
|
|
}
|
|
|
|
|
2018-09-03 07:54:45 +00:00
|
|
|
onDownload( headers, rows, query ) {
|
|
|
|
// @TODO The current implementation only downloads the contents displayed in the table.
|
|
|
|
// Another solution is required when the data set is larger (see #311).
|
|
|
|
return () => {
|
|
|
|
downloadCSVFile(
|
|
|
|
generateCSVFileName( 'revenue', query ),
|
|
|
|
generateCSVDataFromTable( headers, rows )
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
getHeadersContent() {
|
|
|
|
return [
|
2018-08-06 17:01:41 +00:00
|
|
|
{
|
|
|
|
label: __( 'Date', 'wc-admin' ),
|
2018-10-10 13:57:16 +00:00
|
|
|
key: 'date',
|
2018-08-06 17:01:41 +00:00
|
|
|
required: true,
|
|
|
|
defaultSort: true,
|
2018-10-11 08:30:51 +00:00
|
|
|
isLeftAligned: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
isSortable: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Orders', 'wc-admin' ),
|
|
|
|
key: 'orders_count',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-10-11 08:30:51 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Gross Revenue', 'wc-admin' ),
|
|
|
|
key: 'gross_revenue',
|
|
|
|
required: true,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Refunds', 'wc-admin' ),
|
|
|
|
key: 'refunds',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Coupons', 'wc-admin' ),
|
|
|
|
key: 'coupons',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Taxes', 'wc-admin' ),
|
|
|
|
key: 'taxes',
|
|
|
|
required: false,
|
2018-09-03 15:25:38 +00:00
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Shipping', 'wc-admin' ),
|
|
|
|
key: 'shipping',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Net Revenue', 'wc-admin' ),
|
|
|
|
key: 'net_revenue',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
2018-08-01 16:00:45 +00:00
|
|
|
];
|
2018-06-26 14:59:35 +00:00
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
getRowsContent( data = [] ) {
|
2018-09-04 18:03:52 +00:00
|
|
|
const { query } = this.props;
|
|
|
|
const currentInterval = getIntervalForQuery( query );
|
|
|
|
const formats = getDateFormatsForInterval( currentInterval );
|
|
|
|
|
2018-06-26 22:17:05 +00:00
|
|
|
return map( data, row => {
|
|
|
|
const {
|
|
|
|
coupons,
|
|
|
|
gross_revenue,
|
|
|
|
net_revenue,
|
|
|
|
orders_count,
|
|
|
|
refunds,
|
|
|
|
shipping,
|
|
|
|
taxes,
|
|
|
|
} = row.subtotals;
|
|
|
|
|
2018-07-13 19:36:41 +00:00
|
|
|
// @TODO How to create this per-report? Can use `w`, `year`, `m` to build time-specific order links
|
|
|
|
// we need to know which kind of report this is, and parse the `label` to get this row's date
|
2018-06-20 15:09:37 +00:00
|
|
|
const orderLink = (
|
2018-09-03 15:25:38 +00:00
|
|
|
<a
|
|
|
|
href={ getAdminLink(
|
|
|
|
'edit.php?post_type=shop_order&m=' + formatDate( 'Ymd', row.date_start )
|
|
|
|
) }
|
|
|
|
>
|
2018-06-26 22:17:05 +00:00
|
|
|
{ orders_count }
|
2018-06-20 15:09:37 +00:00
|
|
|
</a>
|
|
|
|
);
|
|
|
|
return [
|
2018-08-01 16:00:45 +00:00
|
|
|
{
|
2018-09-04 18:03:52 +00:00
|
|
|
display: formatDate( formats.tableFormat, row.date_start ),
|
2018-08-01 16:00:45 +00:00
|
|
|
value: row.date_start,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: orderLink,
|
|
|
|
value: Number( orders_count ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( gross_revenue ),
|
|
|
|
value: getCurrencyFormatDecimal( gross_revenue ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( refunds ),
|
|
|
|
value: getCurrencyFormatDecimal( refunds ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( coupons ),
|
|
|
|
value: getCurrencyFormatDecimal( coupons ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( taxes ),
|
|
|
|
value: getCurrencyFormatDecimal( taxes ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( shipping ),
|
|
|
|
value: getCurrencyFormatDecimal( shipping ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( net_revenue ),
|
|
|
|
value: getCurrencyFormatDecimal( net_revenue ),
|
|
|
|
},
|
2018-06-20 15:09:37 +00:00
|
|
|
];
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2018-09-03 15:25:38 +00:00
|
|
|
renderTable() {
|
2018-10-10 13:57:16 +00:00
|
|
|
const { isTableDataRequesting, tableData, tableQuery } = this.props;
|
2018-08-01 16:00:45 +00:00
|
|
|
const headers = this.getHeadersContent();
|
2018-09-03 15:25:38 +00:00
|
|
|
|
2018-10-10 13:57:16 +00:00
|
|
|
if ( isTableDataRequesting ) {
|
|
|
|
return (
|
|
|
|
<Card
|
|
|
|
title={ __( 'Revenue', 'wc-admin' ) }
|
|
|
|
className="woocommerce-analytics__table-placeholder"
|
|
|
|
>
|
|
|
|
<TablePlaceholder
|
|
|
|
caption={ __( 'Revenue', 'wc-admin' ) }
|
|
|
|
headers={ headers }
|
|
|
|
query={ tableQuery }
|
|
|
|
/>
|
|
|
|
</Card>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const intervals = tableData.data.intervals;
|
|
|
|
const rows = this.getRowsContent( intervals );
|
|
|
|
|
|
|
|
const rowsPerPage =
|
|
|
|
( tableQuery && tableQuery.per_page && parseInt( tableQuery.per_page ) ) || 25;
|
|
|
|
|
2018-09-03 15:25:38 +00:00
|
|
|
return (
|
|
|
|
<TableCard
|
|
|
|
title={ __( 'Revenue', 'wc-admin' ) }
|
|
|
|
rows={ rows }
|
2018-10-10 13:57:16 +00:00
|
|
|
totalRows={ tableData.totalResults }
|
2018-09-03 15:25:38 +00:00
|
|
|
rowsPerPage={ rowsPerPage }
|
|
|
|
headers={ headers }
|
|
|
|
onClickDownload={ this.onDownload( headers, rows, tableQuery ) }
|
2018-09-17 16:50:20 +00:00
|
|
|
onQueryChange={ onQueryChange }
|
2018-09-03 15:25:38 +00:00
|
|
|
query={ tableQuery }
|
|
|
|
summary={ null }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
Add loading indicators, error state, and EmptyContent to the revenue report. (#347, woocommerce/woocommerce-admin#348)
* Add loading indiciators for the revenue report.
* Improve accessibility, and fix up some documentation comments.
* Fix top border on mobile
* Add EmptyContent Component and revenue error/empty states. (https://github.com/woocommerce/woocommerce-admin/pull/348)
* Add EmptyContent Component and revenue error/empty states.
* Move relative image handling to ImageAsset, combine secondary and primary action rendering, add some missing isRequired proptypes, add empty error handling.
* Handle PR Feedback: Clean up button css, set a default for illustration, fix deprecation typo, some code cleanup.
2018-09-05 16:45:49 +00:00
|
|
|
render() {
|
2018-10-16 17:42:13 +00:00
|
|
|
const { path, query } = this.props;
|
2018-06-20 15:09:37 +00:00
|
|
|
|
2018-06-14 20:15:11 +00:00
|
|
|
return (
|
|
|
|
<Fragment>
|
2018-08-08 21:24:48 +00:00
|
|
|
<ReportFilters query={ query } path={ path } />
|
2018-06-14 20:15:11 +00:00
|
|
|
|
2018-10-16 17:42:13 +00:00
|
|
|
<OrdersReportChart query={ query } />
|
2018-09-03 15:25:38 +00:00
|
|
|
{ this.renderTable() }
|
2018-06-14 20:15:11 +00:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RevenueReport.propTypes = {
|
|
|
|
params: PropTypes.object.isRequired,
|
|
|
|
path: PropTypes.string.isRequired,
|
|
|
|
query: PropTypes.object.isRequired,
|
|
|
|
};
|
|
|
|
|
2018-09-03 15:25:38 +00:00
|
|
|
export default compose(
|
|
|
|
withSelect( ( select, props ) => {
|
|
|
|
const { query } = props;
|
2018-10-10 13:57:16 +00:00
|
|
|
const { getReportStats, isReportStatsRequesting, isReportStatsError } = select( 'wc-admin' );
|
2018-09-03 15:25:38 +00:00
|
|
|
const datesFromQuery = getCurrentDates( query );
|
|
|
|
|
2018-10-10 13:57:16 +00:00
|
|
|
// TODO Support hour here when viewing a single day
|
|
|
|
const tableQuery = {
|
|
|
|
interval: 'day',
|
|
|
|
orderby: query.orderby || 'date',
|
|
|
|
order: query.order || 'asc',
|
|
|
|
page: query.page || 1,
|
|
|
|
per_page: query.per_page || 25,
|
2018-10-17 16:01:58 +00:00
|
|
|
after: appendTimestamp( datesFromQuery.primary.after, 'start' ),
|
|
|
|
before: appendTimestamp( datesFromQuery.primary.before, 'end' ),
|
2018-10-10 13:57:16 +00:00
|
|
|
};
|
|
|
|
const tableData = getReportStats( 'revenue', tableQuery );
|
|
|
|
const isTableDataError = isReportStatsError( 'revenue', tableQuery );
|
|
|
|
const isTableDataRequesting = isReportStatsRequesting( 'revenue', tableQuery );
|
|
|
|
|
2018-09-03 15:25:38 +00:00
|
|
|
return {
|
2018-10-10 13:57:16 +00:00
|
|
|
tableQuery,
|
|
|
|
tableData,
|
|
|
|
isTableDataError,
|
|
|
|
isTableDataRequesting,
|
2018-09-03 15:25:38 +00:00
|
|
|
};
|
|
|
|
} )
|
|
|
|
)( RevenueReport );
|