-
Notifications
You must be signed in to change notification settings - Fork 72
Add remediation tool to fix incorrect analytics data from canceled authorizations #11140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 17 commits
e41ef6a
e28efb3
dba00e7
1c5aad0
ac87be1
67b4ebb
72b6a74
a917c0b
b111c29
3a83f23
ea90207
f8d44ec
1aca52c
63ce0c2
f93e62e
3f7e799
978cad5
bbf7c43
dd969e7
2fbe206
ef4a458
2b0dc25
161ee72
fa03b13
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,7 +66,7 @@ public function debug_tools( $tools ) { | |
| return array_merge( | ||
| $tools, | ||
| [ | ||
| 'clear_wcpay_account_cache' => [ | ||
| 'clear_wcpay_account_cache' => [ | ||
| 'name' => sprintf( | ||
| /* translators: %s: WooPayments */ | ||
| __( 'Clear %s account cache', 'woocommerce-payments' ), | ||
|
|
@@ -80,7 +80,7 @@ public function debug_tools( $tools ) { | |
| ), | ||
| 'callback' => [ $this->account, 'refresh_account_data' ], | ||
| ], | ||
| 'delete_wcpay_test_orders' => [ | ||
| 'delete_wcpay_test_orders' => [ | ||
| 'name' => sprintf( | ||
| /* translators: %s: WooPayments */ | ||
| __( 'Delete %s test orders', 'woocommerce-payments' ), | ||
|
|
@@ -94,6 +94,14 @@ public function debug_tools( $tools ) { | |
| ), | ||
| 'callback' => [ $this, 'delete_test_orders' ], | ||
| ], | ||
| 'remediate_canceled_auth_fees' => [ | ||
| 'name' => __( 'Fix canceled authorization analytics', 'woocommerce-payments' ), | ||
| 'button' => $this->get_remediation_button_text(), | ||
| 'desc' => $this->get_remediation_description(), | ||
| 'confirm' => __( 'This will update order metadata and delete incorrect refund records for affected orders. Make sure you have a recent backup before proceeding. Continue?', 'woocommerce-payments' ), | ||
| 'callback' => [ $this, 'schedule_canceled_auth_remediation' ], | ||
| 'disabled' => $this->is_remediation_running_or_complete(), | ||
| ], | ||
| ] | ||
| ); | ||
| } | ||
|
|
@@ -155,6 +163,151 @@ public function delete_test_orders() { | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Schedules the canceled authorization fee remediation. | ||
| * | ||
| * This tool fixes incorrect refund records and fee data from orders where | ||
| * payment authorization was canceled but never captured. | ||
| * | ||
| * @return string Success or error message. | ||
| */ | ||
| public function schedule_canceled_auth_remediation() { | ||
| // Add explicit capability check. | ||
| if ( ! current_user_can( 'manage_woocommerce' ) ) { | ||
| return __( 'You do not have permission to run this tool.', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| try { | ||
| include_once WCPAY_ABSPATH . 'includes/migrations/class-wc-payments-remediate-canceled-auth-fees.php'; | ||
| $remediation = new WC_Payments_Remediate_Canceled_Auth_Fees(); | ||
|
|
||
| // Check if already complete. | ||
| if ( $remediation->is_complete() ) { | ||
| return __( 'Remediation has already been completed.', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| // Check if already running. | ||
| if ( function_exists( 'as_has_scheduled_action' ) && as_has_scheduled_action( WC_Payments_Remediate_Canceled_Auth_Fees::ACTION_HOOK ) ) { | ||
| return __( 'Remediation is already in progress. Check the Action Scheduler for status.', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| // Schedule the remediation. | ||
| $remediation->schedule_remediation(); | ||
|
|
||
| return __( 'Remediation has been scheduled and will run in the background. You can monitor progress in the Action Scheduler.', 'woocommerce-payments' ); | ||
|
|
||
| } catch ( Exception $e ) { | ||
| return sprintf( | ||
| /* translators: %s: error message */ | ||
| __( 'Error scheduling remediation: %s', 'woocommerce-payments' ), | ||
| $e->getMessage() | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Get the button text for the remediation tool based on current status. | ||
| * | ||
| * @return string Button text. | ||
| */ | ||
| private function get_remediation_button_text(): string { | ||
| $status = get_option( 'wcpay_fee_remediation_status', '' ); | ||
|
|
||
| if ( 'completed' === $status ) { | ||
| return __( 'Completed', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| if ( 'running' === $status || $this->is_remediation_action_scheduled() ) { | ||
| return __( 'Running...', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| return __( 'Run', 'woocommerce-payments' ); | ||
| } | ||
|
|
||
| /** | ||
| * Get the description for the remediation tool including current status. | ||
| * | ||
| * @return string Tool description with status. | ||
| */ | ||
| private function get_remediation_description(): string { | ||
| $base_desc = __( 'This tool removes incorrect refund records and fee data from orders where payment authorization was canceled (not captured). This fixes negative values appearing in WooCommerce Analytics for stores using manual capture.', 'woocommerce-payments' ); | ||
|
|
||
| $status = get_option( 'wcpay_fee_remediation_status', '' ); | ||
|
|
||
| if ( 'completed' === $status ) { | ||
| $stats = get_option( 'wcpay_fee_remediation_stats', [] ); | ||
| $processed = isset( $stats['processed'] ) ? (int) $stats['processed'] : 0; | ||
| $remediated = isset( $stats['remediated'] ) ? (int) $stats['remediated'] : 0; | ||
|
|
||
| if ( $processed > 0 ) { | ||
| return sprintf( | ||
| /* translators: 1: base description, 2: number of orders processed, 3: number of orders remediated */ | ||
| __( '%1$s <strong>Status: Completed.</strong> Processed %2$d orders, remediated %3$d.', 'woocommerce-payments' ), | ||
| $base_desc, | ||
| $processed, | ||
| $remediated | ||
| ); | ||
| } | ||
|
|
||
| return sprintf( | ||
| /* translators: %s: base description */ | ||
| __( '%s <strong>Status: Completed.</strong> No affected orders found.', 'woocommerce-payments' ), | ||
| $base_desc | ||
| ); | ||
| } | ||
|
|
||
| if ( 'running' === $status || $this->is_remediation_action_scheduled() ) { | ||
| $stats = get_option( 'wcpay_fee_remediation_stats', [] ); | ||
| $processed = isset( $stats['processed'] ) ? (int) $stats['processed'] : 0; | ||
|
|
||
| if ( $processed > 0 ) { | ||
| return sprintf( | ||
| /* translators: 1: base description, 2: number of orders processed so far */ | ||
| __( '%1$s <strong>Status: Running...</strong> Processed %2$d orders so far. Check the Action Scheduler for details.', 'woocommerce-payments' ), | ||
| $base_desc, | ||
| $processed | ||
| ); | ||
| } | ||
|
|
||
| return sprintf( | ||
| /* translators: %s: base description */ | ||
| __( '%s <strong>Status: Running...</strong> Check the Action Scheduler for details.', 'woocommerce-payments' ), | ||
| $base_desc | ||
| ); | ||
| } | ||
|
|
||
| return $base_desc; | ||
| } | ||
|
|
||
| /** | ||
| * Check if the remediation is currently running or already complete. | ||
| * | ||
| * @return bool True if running or complete. | ||
| */ | ||
| private function is_remediation_running_or_complete(): bool { | ||
| $status = get_option( 'wcpay_fee_remediation_status', '' ); | ||
|
|
||
| if ( 'completed' === $status || 'running' === $status ) { | ||
| return true; | ||
| } | ||
|
|
||
| return $this->is_remediation_action_scheduled(); | ||
| } | ||
|
|
||
| /** | ||
| * Check if the remediation action is scheduled in Action Scheduler. | ||
| * | ||
| * @return bool True if action is scheduled. | ||
| */ | ||
| private function is_remediation_action_scheduled(): bool { | ||
| if ( ! function_exists( 'as_has_scheduled_action' ) ) { | ||
| return false; | ||
| } | ||
|
|
||
| include_once WCPAY_ABSPATH . 'includes/migrations/class-wc-payments-remediate-canceled-auth-fees.php'; | ||
| return as_has_scheduled_action( WC_Payments_Remediate_Canceled_Auth_Fees::ACTION_HOOK ); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that here, we only checked if Could this lead to some inconsistent UI state? I'm unsure if we need to check for the "dry run" action here, as well 🤷 |
||
| } | ||
|
|
||
| /** | ||
| * Renders WCPay information on the status page. | ||
| */ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.