Handle orphaned order statuses in analytics settings. (https://github.com/woocommerce/woocommerce-admin/pull/4090)
* Add method to retrieve all synced order statuses. * Determine what unregistered order statuses we have and add to client-side settings object. * Stop filtering out unregistered statuses from analytics settings. * Add unregistered statuses to analytics settings fields.
This commit is contained in:
parent
1e1daaa6bb
commit
9973e7e36f
|
@ -4,7 +4,7 @@
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { applyFilters } from '@wordpress/hooks';
|
import { applyFilters } from '@wordpress/hooks';
|
||||||
import interpolateComponents from 'interpolate-components';
|
import interpolateComponents from 'interpolate-components';
|
||||||
import { ORDER_STATUSES } from '@woocommerce/wc-admin-settings';
|
import { getSetting, ORDER_STATUSES } from '@woocommerce/wc-admin-settings';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -25,8 +25,8 @@ export const DEFAULT_ORDER_STATUSES = [
|
||||||
export const DEFAULT_DATE_RANGE = 'period=month&compare=previous_year';
|
export const DEFAULT_DATE_RANGE = 'period=month&compare=previous_year';
|
||||||
|
|
||||||
const filteredOrderStatuses = Object.keys( ORDER_STATUSES )
|
const filteredOrderStatuses = Object.keys( ORDER_STATUSES )
|
||||||
.filter( status => status !== 'refunded' )
|
.filter( ( status ) => status !== 'refunded' )
|
||||||
.map( key => {
|
.map( ( key ) => {
|
||||||
return {
|
return {
|
||||||
value: key,
|
value: key,
|
||||||
label: ORDER_STATUSES[ key ],
|
label: ORDER_STATUSES[ key ],
|
||||||
|
@ -37,25 +37,46 @@ const filteredOrderStatuses = Object.keys( ORDER_STATUSES )
|
||||||
};
|
};
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
const unregisteredOrderStatuses = getSetting( 'unregisteredOrderStatuses', {} );
|
||||||
|
|
||||||
|
const orderStatusOptions = [
|
||||||
|
{
|
||||||
|
key: 'defaultStatuses',
|
||||||
|
options: filteredOrderStatuses.filter( ( status ) =>
|
||||||
|
DEFAULT_ORDER_STATUSES.includes( status.value )
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'customStatuses',
|
||||||
|
label: __( 'Custom Statuses', 'woocommerce-admin' ),
|
||||||
|
options: filteredOrderStatuses.filter(
|
||||||
|
( status ) => ! DEFAULT_ORDER_STATUSES.includes( status.value )
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unregisteredStatuses',
|
||||||
|
label: __( 'Unregistered Statuses', 'woocommerce-admin' ),
|
||||||
|
options: Object.keys( unregisteredOrderStatuses ).map( ( key ) => {
|
||||||
|
return {
|
||||||
|
value: key,
|
||||||
|
label: key,
|
||||||
|
description: sprintf(
|
||||||
|
__(
|
||||||
|
'Exclude the %s status from reports',
|
||||||
|
'woocommerce-admin'
|
||||||
|
),
|
||||||
|
key
|
||||||
|
),
|
||||||
|
};
|
||||||
|
} ),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const config = applyFilters( SETTINGS_FILTER, {
|
export const config = applyFilters( SETTINGS_FILTER, {
|
||||||
woocommerce_excluded_report_order_statuses: {
|
woocommerce_excluded_report_order_statuses: {
|
||||||
label: __( 'Excluded Statuses:', 'woocommerce-admin' ),
|
label: __( 'Excluded Statuses:', 'woocommerce-admin' ),
|
||||||
inputType: 'checkboxGroup',
|
inputType: 'checkboxGroup',
|
||||||
options: [
|
options: orderStatusOptions,
|
||||||
{
|
|
||||||
key: 'defaultStatuses',
|
|
||||||
options: filteredOrderStatuses.filter( status =>
|
|
||||||
DEFAULT_ORDER_STATUSES.includes( status.value )
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'customStatuses',
|
|
||||||
label: __( 'Custom Statuses', 'woocommerce-admin' ),
|
|
||||||
options: filteredOrderStatuses.filter(
|
|
||||||
status => ! DEFAULT_ORDER_STATUSES.includes( status.value )
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
helpText: interpolateComponents( {
|
helpText: interpolateComponents( {
|
||||||
mixedString: __(
|
mixedString: __(
|
||||||
'Orders with these statuses are excluded from the totals in your reports. ' +
|
'Orders with these statuses are excluded from the totals in your reports. ' +
|
||||||
|
@ -71,21 +92,7 @@ export const config = applyFilters( SETTINGS_FILTER, {
|
||||||
woocommerce_actionable_order_statuses: {
|
woocommerce_actionable_order_statuses: {
|
||||||
label: __( 'Actionable Statuses:', 'woocommerce-admin' ),
|
label: __( 'Actionable Statuses:', 'woocommerce-admin' ),
|
||||||
inputType: 'checkboxGroup',
|
inputType: 'checkboxGroup',
|
||||||
options: [
|
options: orderStatusOptions,
|
||||||
{
|
|
||||||
key: 'defaultStatuses',
|
|
||||||
options: filteredOrderStatuses.filter( status =>
|
|
||||||
DEFAULT_ORDER_STATUSES.includes( status.value )
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'customStatuses',
|
|
||||||
label: __( 'Custom Statuses', 'woocommerce-admin' ),
|
|
||||||
options: filteredOrderStatuses.filter(
|
|
||||||
status => ! DEFAULT_ORDER_STATUSES.includes( status.value )
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
helpText: __(
|
helpText: __(
|
||||||
'Orders with these statuses require action on behalf of the store admin.' +
|
'Orders with these statuses require action on behalf of the store admin.' +
|
||||||
'These orders will show up in the Orders tab under the activity panel.',
|
'These orders will show up in the Orders tab under the activity panel.',
|
||||||
|
|
|
@ -12,6 +12,7 @@ defined( 'ABSPATH' ) || exit;
|
||||||
use \Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
|
use \Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
|
||||||
use \Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
|
use \Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
|
||||||
use \Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
|
use \Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
|
||||||
|
use \Automattic\WooCommerce\Admin\API\Reports\Cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API\Reports\Orders\DataStore.
|
* API\Reports\Orders\DataStore.
|
||||||
|
@ -432,6 +433,29 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
||||||
return $coupons;
|
return $coupons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all statuses that have been synced.
|
||||||
|
*
|
||||||
|
* @return array Unique order statuses.
|
||||||
|
*/
|
||||||
|
public static function get_all_statuses() {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$cache_key = 'orders-all-statuses';
|
||||||
|
$statuses = Cache::get( $cache_key );
|
||||||
|
|
||||||
|
if ( false === $statuses ) {
|
||||||
|
$table_name = self::get_db_table_name();
|
||||||
|
$statuses = $wpdb->get_col(
|
||||||
|
"SELECT DISTINCT status FROM {$table_name}"
|
||||||
|
); // WPCS: cache ok, DB call ok, unprepared SQL ok.
|
||||||
|
|
||||||
|
Cache::set( $cache_key, $statuses );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $statuses;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize query objects.
|
* Initialize query objects.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Admin;
|
||||||
|
|
||||||
use \_WP_Dependency;
|
use \_WP_Dependency;
|
||||||
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
use Automattic\WooCommerce\Admin\Features\Onboarding;
|
||||||
|
use Automattic\WooCommerce\Admin\API\Reports\Orders\DataStore as OrdersDataStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loader Class.
|
* Loader Class.
|
||||||
|
@ -73,8 +74,6 @@ class Loader {
|
||||||
add_action( 'in_admin_header', array( __CLASS__, 'embed_page_header' ) );
|
add_action( 'in_admin_header', array( __CLASS__, 'embed_page_header' ) );
|
||||||
add_filter( 'woocommerce_settings_groups', array( __CLASS__, 'add_settings_group' ) );
|
add_filter( 'woocommerce_settings_groups', array( __CLASS__, 'add_settings_group' ) );
|
||||||
add_filter( 'woocommerce_settings-wc_admin', array( __CLASS__, 'add_settings' ) );
|
add_filter( 'woocommerce_settings-wc_admin', array( __CLASS__, 'add_settings' ) );
|
||||||
add_filter( 'option_woocommerce_actionable_order_statuses', array( __CLASS__, 'filter_invalid_statuses' ) );
|
|
||||||
add_filter( 'option_woocommerce_excluded_report_order_statuses', array( __CLASS__, 'filter_invalid_statuses' ) );
|
|
||||||
add_action( 'admin_head', array( __CLASS__, 'remove_notices' ) );
|
add_action( 'admin_head', array( __CLASS__, 'remove_notices' ) );
|
||||||
add_action( 'admin_notices', array( __CLASS__, 'inject_before_notices' ), -9999 );
|
add_action( 'admin_notices', array( __CLASS__, 'inject_before_notices' ), -9999 );
|
||||||
add_action( 'admin_notices', array( __CLASS__, 'inject_after_notices' ), PHP_INT_MAX );
|
add_action( 'admin_notices', array( __CLASS__, 'inject_after_notices' ), PHP_INT_MAX );
|
||||||
|
@ -724,6 +723,9 @@ class Loader {
|
||||||
// WooCommerce Branding is an example of this - so pass through the translation of
|
// WooCommerce Branding is an example of this - so pass through the translation of
|
||||||
// 'WooCommerce' to wcSettings.
|
// 'WooCommerce' to wcSettings.
|
||||||
$settings['woocommerceTranslation'] = __( 'WooCommerce', 'woocommerce-admin' );
|
$settings['woocommerceTranslation'] = __( 'WooCommerce', 'woocommerce-admin' );
|
||||||
|
// We may have synced orders with a now-unregistered status.
|
||||||
|
// E.g An extension that added statuses is now inactive or removed.
|
||||||
|
$settings['unregisteredOrderStatuses'] = self::get_unregistered_order_statuses();
|
||||||
|
|
||||||
if ( ! empty( $preload_data_endpoints ) ) {
|
if ( ! empty( $preload_data_endpoints ) ) {
|
||||||
$settings['dataEndpoints'] = isset( $settings['dataEndpoints'] )
|
$settings['dataEndpoints'] = isset( $settings['dataEndpoints'] )
|
||||||
|
@ -760,6 +762,21 @@ class Loader {
|
||||||
return $formatted_statuses;
|
return $formatted_statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all order statuses present in analytics tables that aren't registered.
|
||||||
|
*
|
||||||
|
* @return array Unregistered order statuses.
|
||||||
|
*/
|
||||||
|
public static function get_unregistered_order_statuses() {
|
||||||
|
$registered_statuses = wc_get_order_statuses();
|
||||||
|
$all_synced_statuses = OrdersDataStore::get_all_statuses();
|
||||||
|
$unregistered_statuses = array_diff( $all_synced_statuses, array_keys( $registered_statuses ) );
|
||||||
|
$formatted_status_keys = self::get_order_statuses( array_fill_keys( $unregistered_statuses, '' ) );
|
||||||
|
$formatted_statuses = array_keys( $formatted_status_keys );
|
||||||
|
|
||||||
|
return array_combine( $formatted_statuses, $formatted_statuses );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register the admin settings for use in the WC REST API
|
* Register the admin settings for use in the WC REST API
|
||||||
*
|
*
|
||||||
|
@ -782,7 +799,10 @@ class Loader {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function add_settings( $settings ) {
|
public static function add_settings( $settings ) {
|
||||||
$statuses = self::get_order_statuses( wc_get_order_statuses() );
|
$unregistered_statuses = self::get_unregistered_order_statuses();
|
||||||
|
$registered_statuses = self::get_order_statuses( wc_get_order_statuses() );
|
||||||
|
$all_statuses = array_merge( $unregistered_statuses, $registered_statuses );
|
||||||
|
|
||||||
$settings[] = array(
|
$settings[] = array(
|
||||||
'id' => 'woocommerce_excluded_report_order_statuses',
|
'id' => 'woocommerce_excluded_report_order_statuses',
|
||||||
'option_key' => 'woocommerce_excluded_report_order_statuses',
|
'option_key' => 'woocommerce_excluded_report_order_statuses',
|
||||||
|
@ -790,7 +810,7 @@ class Loader {
|
||||||
'description' => __( 'Statuses that should not be included when calculating report totals.', 'woocommerce-admin' ),
|
'description' => __( 'Statuses that should not be included when calculating report totals.', 'woocommerce-admin' ),
|
||||||
'default' => array( 'pending', 'cancelled', 'failed' ),
|
'default' => array( 'pending', 'cancelled', 'failed' ),
|
||||||
'type' => 'multiselect',
|
'type' => 'multiselect',
|
||||||
'options' => $statuses,
|
'options' => $all_statuses,
|
||||||
);
|
);
|
||||||
$settings[] = array(
|
$settings[] = array(
|
||||||
'id' => 'woocommerce_actionable_order_statuses',
|
'id' => 'woocommerce_actionable_order_statuses',
|
||||||
|
@ -799,7 +819,7 @@ class Loader {
|
||||||
'description' => __( 'Statuses that require extra action on behalf of the store admin.', 'woocommerce-admin' ),
|
'description' => __( 'Statuses that require extra action on behalf of the store admin.', 'woocommerce-admin' ),
|
||||||
'default' => array( 'processing', 'on-hold' ),
|
'default' => array( 'processing', 'on-hold' ),
|
||||||
'type' => 'multiselect',
|
'type' => 'multiselect',
|
||||||
'options' => $statuses,
|
'options' => $all_statuses,
|
||||||
);
|
);
|
||||||
$settings[] = array(
|
$settings[] = array(
|
||||||
'id' => 'woocommerce_default_date_range',
|
'id' => 'woocommerce_default_date_range',
|
||||||
|
@ -812,21 +832,6 @@ class Loader {
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter invalid statuses from saved settings to avoid removed statuses throwing errors.
|
|
||||||
*
|
|
||||||
* @param array|null $value Saved order statuses.
|
|
||||||
* @return array|null
|
|
||||||
*/
|
|
||||||
public static function filter_invalid_statuses( $value ) {
|
|
||||||
if ( is_array( $value ) ) {
|
|
||||||
$valid_statuses = array_keys( self::get_order_statuses( wc_get_order_statuses() ) );
|
|
||||||
$value = array_intersect( $value, $valid_statuses );
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets custom settings used for WC Admin.
|
* Gets custom settings used for WC Admin.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue