Add total payments volume rule processor for inbox notifications (#33192)

* Add method to get total sales for a timeframe

* Add total payments volume rule processor

* Use start and end dates for total sales method

* Add method to get start and end dates from timeframe

* Update processor rule to use timeframes

* Fix up method calls

* Add tests for timeframes

* Add tests around getting total sales by date

* Add changelog entry

* Use revenue query instead of custom query for total sales

* Update since tag on hook
This commit is contained in:
Joshua T Flowers 2022-06-02 08:38:06 -04:00 committed by GitHub
parent 7de6d18b2e
commit bec9e92b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 281 additions and 0 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: enhancement
Add total payments volume rule processor for inbox notifications #33192

View File

@ -353,6 +353,11 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
if ( $is_variation ) {
$variation = wc_get_product( $product_data['id'] );
/**
* Used to determine the separator for products and their variations titles.
*
* @since 4.0.0
*/
$separator = apply_filters( 'woocommerce_product_variation_title_attributes_separator', ' - ', $variation );
if ( false === strpos( $product_data['name'], $separator ) ) {

View File

@ -631,4 +631,80 @@ class TimeInterval {
return true;
}
/**
* Get dates from a timeframe string.
*
* @param int $timeframe Timeframe to use. One of: last_week|last_month|last_quarter|last_6_months|last_year.
* @param DateTime|null $current_date DateTime of current date to compare.
* @return array
*/
public static function get_timeframe_dates( $timeframe, $current_date = null ) {
if ( ! $current_date ) {
$current_date = new \DateTime();
}
$current_year = $current_date->format( 'Y' );
$current_month = $current_date->format( 'm' );
if ( 'last_week' === $timeframe ) {
return array(
'start' => $current_date->modify( 'last week monday' )->format( 'Y-m-d 00:00:00' ),
'end' => $current_date->modify( 'this sunday' )->format( 'Y-m-d 23:59:59' ),
);
}
if ( 'last_month' === $timeframe ) {
return array(
'start' => $current_date->modify( 'first day of previous month' )->format( 'Y-m-d 00:00:00' ),
'end' => $current_date->modify( 'last day of this month' )->format( 'Y-m-d 23:59:59' ),
);
}
if ( 'last_quarter' === $timeframe ) {
switch ( $current_month ) {
case $current_month >= 1 && $current_month <= 3:
return array(
'start' => ( $current_year - 1 ) . '-10-01 00:00:00',
'end' => ( $current_year - 1 ) . '-12-31 23:59:59',
);
case $current_month >= 4 && $current_month <= 6:
return array(
'start' => $current_year . '-01-01 00:00:00',
'end' => $current_year . '-03-31 23:59:59',
);
case $current_month >= 7 && $current_month <= 9:
return array(
'start' => $current_year . '-04-01 00:00:00',
'end' => $current_year . '-06-30 23:59:59',
);
case $current_month >= 10 && $current_month <= 12:
return array(
'start' => $current_year . '-07-01 00:00:00',
'end' => $current_year . '-09-31 23:59:59',
);
}
}
if ( 'last_6_months' === $timeframe ) {
if ( $current_month >= 1 && $current_month <= 6 ) {
return array(
'start' => ( $current_year - 1 ) . '-07-01 00:00:00',
'end' => ( $current_year - 1 ) . '-12-31 23:59:59',
);
}
return array(
'start' => $current_year . '-01-01 00:00:00',
'end' => $current_year . '-06-30 23:59:59',
);
}
if ( 'last_year' === $timeframe ) {
return array(
'start' => ( $current_year - 1 ) . '-01-01 00:00:00',
'end' => ( $current_year - 1 ) . '-12-31 23:59:59',
);
}
return false;
}
}

View File

@ -58,6 +58,8 @@ class GetRuleProcessor {
return new OptionRuleProcessor();
case 'wca_updated':
return new WooCommerceAdminUpdatedRuleProcessor();
case 'total_payments_value':
return new TotalPaymentsVolumeProcessor();
}
return new FailRuleProcessor();

View File

@ -409,6 +409,22 @@ actioned.
}
```
### Total Payments Value
This passes when the total value of all payments for a given timeframe
compared to the provided value pass the operation test.
`timeframe` can be one of `last_week`, `last_month`, `last_quarter`, `last_6_months`, `last_year`
```
{
"type": "total_payments_value",
"days": "last_month",
"value": "actioned",
"operation": ">"
}
```
`timeframe`, `value`, and `operation` are all required.
### Option
This passes when the option value matches the value using the operation.

View File

@ -0,0 +1,75 @@
<?php
/**
* Rule processor that passes when a store's payments volume exceeds a provided amount.
*/
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
defined( 'ABSPATH' ) || exit;
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
/**
* Rule processor that passes when a store's payments volume exceeds a provided amount.
*/
class TotalPaymentsVolumeProcessor implements RuleProcessorInterface {
/**
* Compare against the store's total payments volume.
*
* @param object $rule The rule being processed by this rule processor.
* @param object $stored_state Stored state.
*
* @return bool The result of the operation.
*/
public function process( $rule, $stored_state ) {
$dates = TimeInterval::get_timeframe_dates( $rule->timeframe );
$reports_revenue = new RevenueQuery(
array(
'before' => $dates['end'],
'after' => $dates['start'],
'interval' => 'year',
'fields' => array( 'total_sales' ),
)
);
$report_data = $reports_revenue->get_data();
$value = $report_data->totals->total_sales;
return ComparisonOperation::compare(
$value,
$rule->value,
$rule->operation
);
}
/**
* Validates the rule.
*
* @param object $rule The rule to validate.
*
* @return bool Pass/fail.
*/
public function validate( $rule ) {
$allowed_timeframes = array(
'last_week',
'last_month',
'last_quarter',
'last_6_months',
'last_year',
);
if ( ! isset( $rule->timeframe ) || ! in_array( $rule->timeframe, $allowed_timeframes, true ) ) {
return false;
}
if ( ! isset( $rule->value ) ) {
return false;
}
if ( ! isset( $rule->operation ) ) {
return false;
}
return true;
}
}

View File

@ -1013,4 +1013,107 @@ class WC_Admin_Tests_Reports_Interval_Stats extends WC_Unit_Test_Case {
TimeInterval::rest_validate_between_date_arg( array( '2019-01-01T00:00:00', '2019-01-15T00:00:00' ), null, 'param' )
);
}
/**
* Test that we get the correct start and end times for "last_week" timeframes.
*/
public function test_timeframes_last_week() {
$datetime = new DateTime( '2022-05-26' );
$dates = TimeInterval::get_timeframe_dates( 'last_week', $datetime );
$this->assertEquals( '2022-05-16 00:00:00', $dates['start'] );
$this->assertEquals( '2022-05-22 23:59:59', $dates['end'] );
$datetime = new DateTime( '2022-05-16' );
$dates = TimeInterval::get_timeframe_dates( 'last_week', $datetime );
$this->assertEquals( '2022-05-09 00:00:00', $dates['start'] );
$this->assertEquals( '2022-05-15 23:59:59', $dates['end'] );
$datetime = new DateTime( '2022-01-02' );
$dates = TimeInterval::get_timeframe_dates( 'last_week', $datetime );
$this->assertEquals( '2021-12-20 00:00:00', $dates['start'] );
$this->assertEquals( '2021-12-26 23:59:59', $dates['end'] );
}
/**
* Test that we get the correct start and end times for "last_month" timeframes.
*/
public function test_timeframes_last_month() {
$datetime = new DateTime( '2022-05-26' );
$dates = TimeInterval::get_timeframe_dates( 'last_month', $datetime );
$this->assertEquals( '2022-04-01 00:00:00', $dates['start'] );
$this->assertEquals( '2022-04-30 23:59:59', $dates['end'] );
$datetime = new DateTime( '2021-01-12' );
$dates = TimeInterval::get_timeframe_dates( 'last_month', $datetime );
$this->assertEquals( '2020-12-01 00:00:00', $dates['start'] );
$this->assertEquals( '2020-12-31 23:59:59', $dates['end'] );
}
/**
* Test that we get the correct start and end times for "last_quarter" timeframes.
*/
public function test_timeframes_last_quarter() {
$datetime = new DateTime( '2022-05-26' );
$dates = TimeInterval::get_timeframe_dates( 'last_quarter', $datetime );
$this->assertEquals( '2022-01-01 00:00:00', $dates['start'] );
$this->assertEquals( '2022-03-31 23:59:59', $dates['end'] );
$datetime = new DateTime( '2022-01-12' );
$dates = TimeInterval::get_timeframe_dates( 'last_quarter', $datetime );
$this->assertEquals( '2021-10-01 00:00:00', $dates['start'] );
$this->assertEquals( '2021-12-31 23:59:59', $dates['end'] );
$datetime = new DateTime( '2022-07-18' );
$dates = TimeInterval::get_timeframe_dates( 'last_quarter', $datetime );
$this->assertEquals( '2022-04-01 00:00:00', $dates['start'] );
$this->assertEquals( '2022-06-30 23:59:59', $dates['end'] );
$datetime = new DateTime( '2022-11-07' );
$dates = TimeInterval::get_timeframe_dates( 'last_quarter', $datetime );
$this->assertEquals( '2022-07-01 00:00:00', $dates['start'] );
$this->assertEquals( '2022-09-31 23:59:59', $dates['end'] );
}
/**
* Test that we get the correct start and end times for "last_6_months" timeframes.
*/
public function test_timeframes_last_6_months() {
$datetime = new DateTime( '2022-05-26' );
$dates = TimeInterval::get_timeframe_dates( 'last_6_months', $datetime );
$this->assertEquals( '2021-07-01 00:00:00', $dates['start'] );
$this->assertEquals( '2021-12-31 23:59:59', $dates['end'] );
$datetime = new DateTime( '2021-09-12' );
$dates = TimeInterval::get_timeframe_dates( 'last_6_months', $datetime );
$this->assertEquals( '2021-01-01 00:00:00', $dates['start'] );
$this->assertEquals( '2021-06-30 23:59:59', $dates['end'] );
}
/**
* Test that we get the correct start and end times for "last_year" timeframes.
*/
public function test_timeframes_last_year() {
$datetime = new DateTime( '2022-05-26' );
$dates = TimeInterval::get_timeframe_dates( 'last_year', $datetime );
$this->assertEquals( '2021-01-01 00:00:00', $dates['start'] );
$this->assertEquals( '2021-12-31 23:59:59', $dates['end'] );
$datetime = new DateTime( '2021-09-12' );
$dates = TimeInterval::get_timeframe_dates( 'last_year', $datetime );
$this->assertEquals( '2020-01-01 00:00:00', $dates['start'] );
$this->assertEquals( '2020-12-31 23:59:59', $dates['end'] );
}
}