Only query requested stat totals in reports. (https://github.com/woocommerce/woocommerce-admin/pull/4009)
* Pass specified totals/intervals fields parameter to the Order Stats Query. * Only request stats used in render for report summaries and charts. Implement Orders as an example. * Specify stats fields for all report requests. * Add 'fields' parameter handling to all stats endpoint controllers. * Reduce stats fields requested by dashboard charts.
This commit is contained in:
parent
5242560972
commit
f8bc173cfb
|
@ -330,6 +330,7 @@ ReportChart.defaultProps = {
|
|||
export default compose(
|
||||
withSelect( ( select, props ) => {
|
||||
const {
|
||||
charts,
|
||||
endpoint,
|
||||
filters,
|
||||
isRequesting,
|
||||
|
@ -366,6 +367,8 @@ export default compose(
|
|||
};
|
||||
}
|
||||
|
||||
const fields = charts && charts.map( chart => chart.key );
|
||||
|
||||
const primaryData = getReportChartData( {
|
||||
endpoint,
|
||||
dataType: 'primary',
|
||||
|
@ -375,6 +378,7 @@ export default compose(
|
|||
filters,
|
||||
advancedFilters,
|
||||
defaultDateRange,
|
||||
fields,
|
||||
} );
|
||||
|
||||
if ( chartMode === 'item-comparison' ) {
|
||||
|
@ -393,6 +397,7 @@ export default compose(
|
|||
filters,
|
||||
advancedFilters,
|
||||
defaultDateRange,
|
||||
fields,
|
||||
} );
|
||||
return {
|
||||
...newProps,
|
||||
|
|
|
@ -195,6 +195,7 @@ ReportSummary.defaultProps = {
|
|||
export default compose(
|
||||
withSelect( ( select, props ) => {
|
||||
const {
|
||||
charts,
|
||||
endpoint,
|
||||
isRequesting,
|
||||
limitProperties,
|
||||
|
@ -218,6 +219,8 @@ export default compose(
|
|||
};
|
||||
}
|
||||
|
||||
const fields = charts && charts.map( chart => chart.key );
|
||||
|
||||
const { woocommerce_default_date_range: defaultDateRange } = select(
|
||||
SETTINGS_STORE_NAME
|
||||
).getSetting( 'wc_admin', 'wcAdminSettings' );
|
||||
|
@ -230,6 +233,7 @@ export default compose(
|
|||
filters,
|
||||
advancedFilters,
|
||||
defaultDateRange,
|
||||
fields,
|
||||
} );
|
||||
|
||||
return {
|
||||
|
|
|
@ -552,6 +552,10 @@ ReportTable.propTypes = {
|
|||
* The string to use as a query parameter when searching row items.
|
||||
*/
|
||||
searchBy: PropTypes.string,
|
||||
/**
|
||||
* List of fields used for summary numbers. (Reduces queries)
|
||||
*/
|
||||
summaryFields: PropTypes.arrayOf( PropTypes.string ),
|
||||
/**
|
||||
* Table data of that report. If it's not provided, it will be automatically
|
||||
* loaded via the provided `endpoint`.
|
||||
|
@ -596,6 +600,7 @@ export default compose(
|
|||
columnPrefsKey,
|
||||
filters,
|
||||
advancedFilters,
|
||||
summaryFields,
|
||||
} = props;
|
||||
|
||||
let userPrefColumns = [];
|
||||
|
@ -638,6 +643,7 @@ export default compose(
|
|||
advancedFilters,
|
||||
tableQuery,
|
||||
defaultDateRange,
|
||||
fields: summaryFields,
|
||||
} )
|
||||
: {};
|
||||
const queriedTableData =
|
||||
|
|
|
@ -80,6 +80,7 @@ export default class CategoriesReport extends Component {
|
|||
report="categories"
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
filters={ filters }
|
||||
advancedFilters={ advancedFilters }
|
||||
mode={ mode }
|
||||
|
|
|
@ -183,6 +183,11 @@ class CategoriesReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'items_sold',
|
||||
'net_revenue',
|
||||
'orders_count',
|
||||
] }
|
||||
isRequesting={ isRequesting }
|
||||
itemIdField="category_id"
|
||||
query={ query }
|
||||
|
|
|
@ -63,6 +63,7 @@ export default class CouponsReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
filters={ filters }
|
||||
advancedFilters={ advancedFilters }
|
||||
mode={ mode }
|
||||
|
|
|
@ -194,6 +194,11 @@ export default class CouponsReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'coupons_count',
|
||||
'orders_count',
|
||||
'amount',
|
||||
] }
|
||||
isRequesting={ isRequesting }
|
||||
itemIdField="coupon_id"
|
||||
query={ query }
|
||||
|
|
|
@ -270,6 +270,12 @@ export default class CustomersReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'customers_count',
|
||||
'avg_orders_count',
|
||||
'avg_total_spend',
|
||||
'avg_avg_order_value',
|
||||
] }
|
||||
isRequesting={ isRequesting }
|
||||
itemIdField="id"
|
||||
query={ query }
|
||||
|
|
|
@ -36,6 +36,7 @@ export default class DownloadsReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
endpoint="downloads"
|
||||
path={ path }
|
||||
query={ query }
|
||||
|
|
|
@ -177,6 +177,7 @@ class CouponsReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [ 'download_count' ] }
|
||||
query={ query }
|
||||
tableQuery={ {
|
||||
_embed: true,
|
||||
|
|
|
@ -36,6 +36,7 @@ export default class OrdersReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
endpoint="orders"
|
||||
path={ path }
|
||||
query={ query }
|
||||
|
|
|
@ -327,6 +327,15 @@ export default class OrdersReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'orders_count',
|
||||
'num_new_customers',
|
||||
'num_returning_customers',
|
||||
'products',
|
||||
'num_items_sold',
|
||||
'coupons_count',
|
||||
'net_revenue',
|
||||
] }
|
||||
query={ query }
|
||||
tableQuery={ {
|
||||
extended_info: true,
|
||||
|
|
|
@ -94,6 +94,7 @@ class ProductsReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
mode={ mode }
|
||||
filters={ filters }
|
||||
advancedFilters={ advancedFilters }
|
||||
|
|
|
@ -243,6 +243,12 @@ export default class VariationsReportTable extends Component {
|
|||
labels={ labels }
|
||||
query={ query }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'variations_count',
|
||||
'items_sold',
|
||||
'net_revenue',
|
||||
'orders_count',
|
||||
] }
|
||||
searchBy="variations"
|
||||
tableQuery={ {
|
||||
orderby: query.orderby || 'items_sold',
|
||||
|
|
|
@ -333,6 +333,12 @@ class ProductsReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'products_count',
|
||||
'items_sold',
|
||||
'net_revenue',
|
||||
'orders_count',
|
||||
] }
|
||||
itemIdField="product_id"
|
||||
isRequesting={ isRequesting }
|
||||
labels={ labels }
|
||||
|
|
|
@ -36,6 +36,7 @@ export default class RevenueReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
endpoint="revenue"
|
||||
path={ path }
|
||||
query={ query }
|
||||
|
|
|
@ -250,6 +250,16 @@ class RevenueReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'orders_count',
|
||||
'gross_sales',
|
||||
'total_sales',
|
||||
'refunds',
|
||||
'coupons',
|
||||
'taxes',
|
||||
'shipping',
|
||||
'net_revenue',
|
||||
] }
|
||||
query={ query }
|
||||
tableData={ tableData }
|
||||
title={ __( 'Revenue', 'woocommerce-admin' ) }
|
||||
|
|
|
@ -180,6 +180,13 @@ export default class StockReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'products',
|
||||
'outofstock',
|
||||
'lowstock',
|
||||
'instock',
|
||||
'onbackorder',
|
||||
] }
|
||||
query={ query }
|
||||
tableQuery={ {
|
||||
orderby: query.orderby || 'stock_status',
|
||||
|
|
|
@ -58,6 +58,7 @@ export default class TaxesReport extends Component {
|
|||
advancedFilters={ advancedFilters }
|
||||
/>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
filters={ filters }
|
||||
advancedFilters={ advancedFilters }
|
||||
mode={ mode }
|
||||
|
|
|
@ -182,6 +182,13 @@ export default class TaxesReportTable extends Component {
|
|||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
getSummary={ this.getSummary }
|
||||
summaryFields={ [
|
||||
'tax_codes',
|
||||
'total_tax',
|
||||
'order_tax',
|
||||
'shipping_tax',
|
||||
'orders_count',
|
||||
] }
|
||||
isRequesting={ isRequesting }
|
||||
itemIdField="tax_rate_id"
|
||||
query={ query }
|
||||
|
|
|
@ -24,13 +24,9 @@ import './block.scss';
|
|||
|
||||
class ChartBlock extends Component {
|
||||
handleChartClick = () => {
|
||||
const { charts } = this.props;
|
||||
const { selectedChart } = this.props;
|
||||
|
||||
if ( ! charts || ! charts.length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
getHistory().push( this.getChartPath( charts[ 0 ] ) );
|
||||
getHistory().push( this.getChartPath( selectedChart ) );
|
||||
};
|
||||
|
||||
getChartPath( chart ) {
|
||||
|
@ -42,9 +38,15 @@ class ChartBlock extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { charts, endpoint, path, query } = this.props;
|
||||
const {
|
||||
charts,
|
||||
endpoint,
|
||||
path,
|
||||
query,
|
||||
selectedChart,
|
||||
} = this.props;
|
||||
|
||||
if ( ! charts || ! charts.length ) {
|
||||
if ( ! selectedChart ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -56,27 +58,28 @@ class ChartBlock extends Component {
|
|||
>
|
||||
<Card
|
||||
className="woocommerce-dashboard__chart-block woocommerce-analytics__card"
|
||||
title={ charts[ 0 ].label }
|
||||
title={ selectedChart.label }
|
||||
>
|
||||
<a
|
||||
className="screen-reader-text"
|
||||
href={ getAdminLink(
|
||||
this.getChartPath( charts[ 0 ] )
|
||||
this.getChartPath( selectedChart )
|
||||
) }
|
||||
>
|
||||
{ /* translators: %s is the chart type */
|
||||
sprintf(
|
||||
__( '%s Report', 'woocommerce-admin' ),
|
||||
charts[ 0 ].label
|
||||
selectedChart.label
|
||||
) }
|
||||
</a>
|
||||
<ReportChart
|
||||
charts={ charts }
|
||||
endpoint={ endpoint }
|
||||
query={ query }
|
||||
interactiveLegend={ false }
|
||||
legendPosition="bottom"
|
||||
path={ path }
|
||||
selectedChart={ charts[ 0 ] }
|
||||
selectedChart={ selectedChart }
|
||||
showHeaderControls={ false }
|
||||
/>
|
||||
</Card>
|
||||
|
@ -90,6 +93,7 @@ ChartBlock.propTypes = {
|
|||
endpoint: PropTypes.string.isRequired,
|
||||
path: PropTypes.string.isRequired,
|
||||
query: PropTypes.object.isRequired,
|
||||
selectedChart: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default ChartBlock;
|
||||
|
|
|
@ -164,8 +164,42 @@ class DashboardCharts extends Component {
|
|||
} );
|
||||
};
|
||||
|
||||
renderChartBlocks( query ) {
|
||||
const { hiddenBlocks, path } = this.props;
|
||||
|
||||
// Reduce the API response to only the necessary stat fields
|
||||
// by supplying all charts common to each endpoint.
|
||||
const chartsByEndpoint = uniqCharts.reduce( ( byEndpoint, chart ) => {
|
||||
if ( typeof byEndpoint[ chart.endpoint ] === 'undefined' ) {
|
||||
byEndpoint[ chart.endpoint ] = [];
|
||||
}
|
||||
byEndpoint[ chart.endpoint ].push( chart );
|
||||
|
||||
return byEndpoint;
|
||||
}, {} );
|
||||
|
||||
return (
|
||||
<div className="woocommerce-dashboard__columns">
|
||||
{ uniqCharts.map( ( chart ) => {
|
||||
return hiddenBlocks.includes(
|
||||
chart.endpoint + '_' + chart.key
|
||||
) ? null : (
|
||||
<ChartBlock
|
||||
charts={ chartsByEndpoint[ chart.endpoint ] }
|
||||
endpoint={ chart.endpoint }
|
||||
key={ chart.endpoint + '_' + chart.key }
|
||||
path={ path }
|
||||
query={ query }
|
||||
selectedChart={ chart }
|
||||
/>
|
||||
);
|
||||
} ) }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { hiddenBlocks, path, title } = this.props;
|
||||
const { title } = this.props;
|
||||
const { chartType, interval } = this.state;
|
||||
const query = { ...this.props.query, chartType, interval };
|
||||
return (
|
||||
|
@ -218,21 +252,7 @@ class DashboardCharts extends Component {
|
|||
/>
|
||||
</NavigableMenu>
|
||||
</SectionHeader>
|
||||
<div className="woocommerce-dashboard__columns">
|
||||
{ uniqCharts.map( ( chart ) => {
|
||||
return hiddenBlocks.includes(
|
||||
chart.endpoint + '_' + chart.key
|
||||
) ? null : (
|
||||
<ChartBlock
|
||||
charts={ [ chart ] }
|
||||
endpoint={ chart.endpoint }
|
||||
key={ chart.endpoint + '_' + chart.key }
|
||||
path={ path }
|
||||
query={ query }
|
||||
/>
|
||||
);
|
||||
} ) }
|
||||
</div>
|
||||
{ this.renderChartBlocks( query ) }
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -197,7 +197,7 @@ export function isReportDataEmpty( report, endpoint ) {
|
|||
* @return {Object} data request query parameters.
|
||||
*/
|
||||
function getRequestQuery( options ) {
|
||||
const { endpoint, dataType, query } = options;
|
||||
const { endpoint, dataType, query, fields } = options;
|
||||
const datesFromQuery = getCurrentDates( query, options.defaultDateRange );
|
||||
const interval = getIntervalForQuery( query );
|
||||
const filterQuery = getFilterQuery( options );
|
||||
|
@ -205,7 +205,7 @@ function getRequestQuery( options ) {
|
|||
|
||||
const noIntervals = includes( noIntervalEndpoints, endpoint );
|
||||
return noIntervals
|
||||
? { ...filterQuery }
|
||||
? { ...filterQuery, fields }
|
||||
: {
|
||||
order: 'asc',
|
||||
interval,
|
||||
|
@ -216,6 +216,7 @@ function getRequestQuery( options ) {
|
|||
),
|
||||
before: appendTimestamp( end, 'end' ),
|
||||
segmentby: query.segmentby,
|
||||
fields,
|
||||
...filterQuery,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$args['order'] = $request['order'];
|
||||
$args['coupons'] = (array) $request['coupons'];
|
||||
$args['segmentby'] = $request['segmentby'];
|
||||
$args['fields'] = $request['fields'];
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
@ -352,6 +353,12 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
),
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$args['last_order_before'] = $request['last_order_before'];
|
||||
$args['last_order_after'] = $request['last_order_after'];
|
||||
$args['customers'] = $request['customers'];
|
||||
$args['fields'] = $request['fields'];
|
||||
|
||||
$between_params_numeric = array( 'orders_count', 'total_spend', 'avg_order_value' );
|
||||
$normalized_params_numeric = TimeInterval::normalize_between_params( $request, $between_params_numeric, false );
|
||||
|
@ -362,6 +363,12 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$args['order_excludes'] = (array) $request['order_excludes'];
|
||||
$args['ip_address_includes'] = (array) $request['ip_address_includes'];
|
||||
$args['ip_address_excludes'] = (array) $request['ip_address_excludes'];
|
||||
$args['fields'] = $request['fields'];
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
@ -369,6 +370,12 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
'type' => 'string',
|
||||
),
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -42,15 +42,15 @@ class Controller extends \Automattic\WooCommerce\Admin\API\Reports\Controller {
|
|||
* @return array
|
||||
*/
|
||||
protected function prepare_reports_query( $request ) {
|
||||
$args = array();
|
||||
$args['before'] = $request['before'];
|
||||
$args['after'] = $request['after'];
|
||||
$args['interval'] = $request['interval'];
|
||||
$args['page'] = $request['page'];
|
||||
$args['per_page'] = $request['per_page'];
|
||||
$args['orderby'] = $request['orderby'];
|
||||
$args['order'] = $request['order'];
|
||||
|
||||
$args = array();
|
||||
$args['before'] = $request['before'];
|
||||
$args['after'] = $request['after'];
|
||||
$args['interval'] = $request['interval'];
|
||||
$args['page'] = $request['page'];
|
||||
$args['per_page'] = $request['per_page'];
|
||||
$args['orderby'] = $request['orderby'];
|
||||
$args['order'] = $request['order'];
|
||||
$args['fields'] = $request['fields'];
|
||||
$args['match'] = $request['match'];
|
||||
$args['status_is'] = (array) $request['status_is'];
|
||||
$args['status_is_not'] = (array) $request['status_is_not'];
|
||||
|
@ -513,6 +513,12 @@ class Controller extends \Automattic\WooCommerce\Admin\API\Reports\Controller {
|
|||
),
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -415,6 +415,12 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
),
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ class Controller extends \WC_REST_Reports_Controller implements ExportableInterf
|
|||
$args['orderby'] = $request['orderby'];
|
||||
$args['order'] = $request['order'];
|
||||
$args['segmentby'] = $request['segmentby'];
|
||||
$args['fields'] = $request['fields'];
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
$args['order'] = $request['order'];
|
||||
$args['taxes'] = (array) $request['taxes'];
|
||||
$args['segmentby'] = $request['segmentby'];
|
||||
$args['fields'] = $request['fields'];
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
@ -387,6 +388,12 @@ class Controller extends \WC_REST_Reports_Controller {
|
|||
),
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
$params['fields'] = array(
|
||||
'description' => __( 'Limit stats fields to the specified items.', 'woocommerce-admin' ),
|
||||
'type' => 'array',
|
||||
'sanitize_callback' => 'wp_parse_slug_list',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue