Add date sorting configuration for Analytics (#36492)

* Include fields date_paid and date_completed to wp_wc_order_stats

TODO: add script to create new columns in the database

* Add update script and new columns in get_schema

* Add new configuration in Analytics > Settings to configure type of date used in Revenue report

* Change date_column_name to date_paid

TODO: This will be configurable in future

* Add date type config field

* Use customizable date field in DataStore

* Change label

* Fix linter errors

* Remove blank line

* Put default column name back to date_created

* Make date_paid and date_completed nullable to help with unit tests

* Remove new table creation in update function and use query method instead of get_var

* Extend stats constructor

* Improve date type configuration description

* Set date column name default to date_created to test if build passes

* Fix phpcs issue on constructor

* Remove cache bypass added by mistake

* Improve changelog

* Fill date_paid and date_completed for refunds to avoid problems whem they are being used to sort
Fix unit tests when date_paid or date_completed are being used as sort date

* Change default to date_created

* Bump update script to 7.5.0

* Add prefix and postmeta variables for script
This commit is contained in:
Nathan Silveira 2023-02-17 10:29:36 -03:00 committed by GitHub
parent 3b58651bd6
commit 9d7e503519
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 148 additions and 1 deletions

View File

@ -118,4 +118,31 @@ export const config = applyFilters( SETTINGS_FILTER, {
), ),
defaultValue: DEFAULT_DATE_RANGE, defaultValue: DEFAULT_DATE_RANGE,
}, },
woocommerce_date_type: {
name: 'woocommerce_date_type',
label: __( 'Date type:', 'woocommerce' ),
inputType: 'select',
options: [
{
label: __( 'Date created', 'woocommerce' ),
value: 'date_created',
key: 'date_created',
},
{
label: __( 'Date paid', 'woocommerce' ),
value: 'date_paid',
key: 'date_paid',
},
{
label: __( 'Date completed', 'woocommerce' ),
value: 'date_completed',
key: 'date_completed',
},
],
helpText: __(
'Database date field considered for Revenue and Orders reports',
'woocommerce'
),
defaultValue: 'date_created',
},
} ); } );

View File

@ -1,7 +1,7 @@
/** /**
* External dependencies * External dependencies
*/ */
import { Button, CheckboxControl } from '@wordpress/components'; import { Button, CheckboxControl, SelectControl } from '@wordpress/components';
import { Component } from '@wordpress/element'; import { Component } from '@wordpress/element';
import { compose } from '@wordpress/compose'; import { compose } from '@wordpress/compose';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -75,6 +75,22 @@ class Setting extends Component {
{ ...this.props } { ...this.props }
/> />
); );
case 'select':
return (
<SelectControl
options={ options }
value={ value }
onChange={ ( newValue ) =>
handleChange( {
target: {
name,
type: 'select',
value: newValue,
},
} )
}
/>
);
case 'text': case 'text':
default: default:
const id = uniqueId( name ); const id = uniqueId( name );
@ -188,6 +204,7 @@ Setting.propTypes = {
'checkboxGroup', 'checkboxGroup',
'text', 'text',
'component', 'component',
'select',
] ), ] ),
/** /**
* Label used for describing the setting. * Label used for describing the setting.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Add date_paid and date_completed date sorting options for Revenue and Order reports

View File

@ -350,6 +350,27 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return $this->get_prop( 'date_modified', $context ); return $this->get_prop( 'date_modified', $context );
} }
/**
* Get date_modified.
*
* @param string $context View or edit context.
* @return WC_DateTime|NULL object if the date is set or null if there is no date.
*/
public function get_date_paid( $context = 'view' ) {
return $this->get_prop( 'date_paid', $context );
}
/**
* Get date_modified.
*
* @param string $context View or edit context.
* @return WC_DateTime|NULL object if the date is set or null if there is no date.
*/
public function get_date_completed( $context = 'view' ) {
return $this->get_prop( 'date_completed', $context );
}
/** /**
* Return the order statuses without wc- internal prefix. * Return the order statuses without wc- internal prefix.
* *

View File

@ -225,6 +225,9 @@ class WC_Install {
'wc_update_722_adjust_new_zealand_states', 'wc_update_722_adjust_new_zealand_states',
'wc_update_722_adjust_ukraine_states', 'wc_update_722_adjust_ukraine_states',
), ),
'7.5.0' => array(
'wc_update_750_add_columns_to_order_stats_table',
),
); );
/** /**
@ -1312,6 +1315,8 @@ CREATE TABLE {$wpdb->prefix}wc_order_stats (
parent_id bigint(20) unsigned DEFAULT 0 NOT NULL, parent_id bigint(20) unsigned DEFAULT 0 NOT NULL,
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
date_created_gmt datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, date_created_gmt datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
date_paid datetime DEFAULT '0000-00-00 00:00:00',
date_completed datetime DEFAULT '0000-00-00 00:00:00',
num_items_sold int(11) DEFAULT 0 NOT NULL, num_items_sold int(11) DEFAULT 0 NOT NULL,
total_sales double DEFAULT 0 NOT NULL, total_sales double DEFAULT 0 NOT NULL,
tax_total double DEFAULT 0 NOT NULL, tax_total double DEFAULT 0 NOT NULL,

View File

@ -2558,3 +2558,28 @@ function wc_update_722_adjust_new_zealand_states() {
function wc_update_722_adjust_ukraine_states() { function wc_update_722_adjust_ukraine_states() {
return wc_update_721_adjust_ukraine_states(); return wc_update_721_adjust_ukraine_states();
} }
/**
* Add new columns date_paid and date_completed to wp_wc_order_stats table in order to provide the option
* of using the dates in the reports
*/
function wc_update_750_add_columns_to_order_stats_table() {
global $wpdb;
$wpdb->query(
"UPDATE {$wpdb->prefix}wc_order_stats AS order_stats
INNER JOIN {$wpdb->postmeta} AS postmeta
ON postmeta.post_id = order_stats.order_id
and postmeta.meta_key = '_date_paid'
SET order_stats.date_paid = IFNULL(FROM_UNIXTIME(postmeta.meta_value), '0000-00-00 00:00:00');"
);
$wpdb->query(
"UPDATE {$wpdb->prefix}wc_order_stats AS order_stats
INNER JOIN {$wpdb->postmeta} AS postmeta
ON postmeta.post_id = order_stats.order_id
and postmeta.meta_key = '_date_completed'
SET order_stats.date_completed = IFNULL(FROM_UNIXTIME(postmeta.meta_value), '0000-00-00 00:00:00');"
);
}

View File

@ -69,6 +69,14 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
*/ */
protected $context = 'orders_stats'; protected $context = 'orders_stats';
/**
* Dynamically sets the date column name based on configuration
*/
public function __construct() {
parent::__construct();
$this->date_column_name = get_option( 'woocommerce_date_type', 'date_created' );
}
/** /**
* Assign report columns once full table name has been assigned. * Assign report columns once full table name has been assigned.
*/ */
@ -517,6 +525,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
'order_id' => $order->get_id(), 'order_id' => $order->get_id(),
'parent_id' => $order->get_parent_id(), 'parent_id' => $order->get_parent_id(),
'date_created' => $order->get_date_created()->date( 'Y-m-d H:i:s' ), 'date_created' => $order->get_date_created()->date( 'Y-m-d H:i:s' ),
'date_paid' => $order->get_date_paid() ? $order->get_date_paid()->date( 'Y-m-d H:i:s' ) : null,
'date_completed' => $order->get_date_completed() ? $order->get_date_completed()->date( 'Y-m-d H:i:s' ) : null,
'date_created_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created()->getTimestamp() ), 'date_created_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created()->getTimestamp() ),
'num_items_sold' => self::get_num_items_sold( $order ), 'num_items_sold' => self::get_num_items_sold( $order ),
'total_sales' => $order->get_total(), 'total_sales' => $order->get_total(),
@ -535,6 +545,8 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
'%d', '%d',
'%s', '%s',
'%s', '%s',
'%s',
'%s',
'%d', '%d',
'%f', '%f',
'%f', '%f',
@ -551,6 +563,12 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
$data['parent_id'] = $parent_order->get_id(); $data['parent_id'] = $parent_order->get_id();
$data['status'] = self::normalize_order_status( $parent_order->get_status() ); $data['status'] = self::normalize_order_status( $parent_order->get_status() );
} }
/**
* Set date_completed and date_paid the same as date_created to avoid problems
* when they are being used to sort the data, as refunds don't have them filled
*/
$data['date_completed'] = $data['date_created'];
$data['date_paid'] = $data['date_created'];
} }
// Update or add the information to the DB. // Update or add the information to the DB.

View File

@ -288,6 +288,19 @@ class Settings {
'default' => 'period=month&compare=previous_year', 'default' => 'period=month&compare=previous_year',
'type' => 'text', 'type' => 'text',
); );
$settings[] = array(
'id' => 'woocommerce_date_type',
'option_key' => 'woocommerce_date_type',
'label' => __( 'Date Type', 'woocommerce' ),
'description' => __( 'Database date field considered for Revenue and Orders reports', 'woocommerce' ),
'default' => 'date_created',
'type' => 'select',
'options' => array(
'date_created' => 'date_created',
'date_paid' => 'date_paid',
'date_completed' => 'date_completed',
),
);
return $settings; return $settings;
} }

View File

@ -195,10 +195,14 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
), ),
); );
$time = time();
foreach ( $order_types as $order_type ) { foreach ( $order_types as $order_type ) {
$order = WC_Helper_Order::create_order( 1, $product ); $order = WC_Helper_Order::create_order( 1, $product );
$order->set_status( $order_type['status'] ); $order->set_status( $order_type['status'] );
$order->set_total( $order_type['total'] ); $order->set_total( $order_type['total'] );
$order->set_date_created( $time );
$order->set_date_paid( $time );
$order->set_shipping_total( 0 ); $order->set_shipping_total( 0 );
$order->set_cart_tax( 0 ); $order->set_cart_tax( 0 );
$order->save(); $order->save();
@ -352,10 +356,14 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
), ),
); );
$time = time();
foreach ( $order_types as $order_type ) { foreach ( $order_types as $order_type ) {
$order = WC_Helper_Order::create_order( 1, $product ); $order = WC_Helper_Order::create_order( 1, $product );
$order->set_status( $order_type['status'] ); $order->set_status( $order_type['status'] );
$order->set_total( $order_type['total'] ); $order->set_total( $order_type['total'] );
$order->set_date_created( $time );
$order->set_date_paid( $time );
$order->set_shipping_total( 0 ); $order->set_shipping_total( 0 );
$order->set_cart_tax( 0 ); $order->set_cart_tax( 0 );
$order->save(); $order->save();
@ -3946,6 +3954,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
// Order 3: 4 x product 1, done one hour earlier. // Order 3: 4 x product 1, done one hour earlier.
$order_3 = WC_Helper_Order::create_order( $customer_1->get_id(), $product_1 ); $order_3 = WC_Helper_Order::create_order( $customer_1->get_id(), $product_1 );
$order_3->set_date_created( $order_3_time ); $order_3->set_date_created( $order_3_time );
$order_3->set_date_paid( $order_3_time );
$order_3->set_status( $order_status ); $order_3->set_status( $order_status );
$order_3->calculate_totals(); $order_3->calculate_totals();
$order_3->save(); $order_3->save();
@ -4526,6 +4535,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
// Order with 1 product. // Order with 1 product.
$order = WC_Helper_Order::create_order( $customer->get_id(), $product ); $order = WC_Helper_Order::create_order( $customer->get_id(), $product );
$order->set_date_created( $order_time ); $order->set_date_created( $order_time );
$order->set_date_paid( $order_time );
$order->set_status( $order_status ); $order->set_status( $order_status );
$order->calculate_totals(); $order->calculate_totals();
@ -5309,6 +5319,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
// Order with 1 product. // Order with 1 product.
$order = WC_Helper_Order::create_order( $customer->get_id(), $product ); $order = WC_Helper_Order::create_order( $customer->get_id(), $product );
$order->set_date_created( $order_time ); $order->set_date_created( $order_time );
$order->set_date_paid( $order_time );
$order->set_status( $order_status ); $order->set_status( $order_status );
$order->calculate_totals(); $order->calculate_totals();
@ -6078,6 +6089,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
$order_0 = WC_Helper_Order::create_order( 0, $product ); $order_0 = WC_Helper_Order::create_order( 0, $product );
$order_0->set_date_created( $order_0_time ); $order_0->set_date_created( $order_0_time );
$order_0->set_date_paid( $order_0_time );
$order_0->set_status( 'processing' ); $order_0->set_status( 'processing' );
$order_0->set_total( 100 ); $order_0->set_total( 100 );
$order_0->save(); $order_0->save();
@ -6097,6 +6109,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
// Place an order 'one hour later', 2 orders, but still just one customer. // Place an order 'one hour later', 2 orders, but still just one customer.
$order_1 = WC_Helper_Order::create_order( 0, $product ); $order_1 = WC_Helper_Order::create_order( 0, $product );
$order_1->set_date_created( $order_1_time ); $order_1->set_date_created( $order_1_time );
$order_1->set_date_paid( $order_1_time );
$order_1->set_status( 'processing' ); $order_1->set_status( 'processing' );
$order_1->set_total( 100 ); $order_1->set_total( 100 );
$order_1->save(); $order_1->save();
@ -6135,6 +6148,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
$order_2 = WC_Helper_Order::create_order( 0, $product ); $order_2 = WC_Helper_Order::create_order( 0, $product );
$order_2->set_date_created( $order_1_time ); $order_2->set_date_created( $order_1_time );
$order_2->set_date_paid( $order_1_time );
$order_2->set_status( 'processing' ); $order_2->set_status( 'processing' );
$order_2->set_total( 100 ); $order_2->set_total( 100 );
$order_2->save(); $order_2->save();
@ -6185,6 +6199,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
$order_0 = WC_Helper_Order::create_order( $customer_1->get_id(), $product ); $order_0 = WC_Helper_Order::create_order( $customer_1->get_id(), $product );
$order_0->set_date_created( $order_0_time ); $order_0->set_date_created( $order_0_time );
$order_0->set_date_paid( $order_0_time );
$order_0->set_status( 'processing' ); $order_0->set_status( 'processing' );
$order_0->set_total( 100 ); $order_0->set_total( 100 );
$order_0->save(); $order_0->save();
@ -6204,6 +6219,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
// Place an order 'one hour later', 2 orders, but still just one customer. // Place an order 'one hour later', 2 orders, but still just one customer.
$order_1 = WC_Helper_Order::create_order( $customer_1->get_id(), $product ); $order_1 = WC_Helper_Order::create_order( $customer_1->get_id(), $product );
$order_1->set_date_created( $order_1_time ); $order_1->set_date_created( $order_1_time );
$order_1->set_date_paid( $order_1_time );
$order_1->set_status( 'processing' ); $order_1->set_status( 'processing' );
$order_1->set_total( 100 ); $order_1->set_total( 100 );
$order_1->save(); $order_1->save();
@ -6242,6 +6258,7 @@ class WC_Admin_Tests_Reports_Orders_Stats extends WC_Unit_Test_Case {
$order_2 = WC_Helper_Order::create_order( $customer_1->get_id(), $product ); $order_2 = WC_Helper_Order::create_order( $customer_1->get_id(), $product );
$order_2->set_date_created( $order_1_time ); $order_2->set_date_created( $order_1_time );
$order_2->set_date_paid( $order_1_time );
$order_2->set_status( 'processing' ); $order_2->set_status( 'processing' );
$order_2->set_total( 100 ); $order_2->set_total( 100 );
$order_2->save(); $order_2->save();