Skip to content

Commit

Permalink
Persisting the dispute status when closed (#3445)
Browse files Browse the repository at this point in the history
* Persisting the dispute status

* Renaming the meta

* Changelog and readme entries

* Adding specific unit tests
  • Loading branch information
wjrosa authored Sep 20, 2024
1 parent a592a76 commit 5010cc7
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 14 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** Changelog ***

= 8.8.0 - xxxx-xx-xx =
* Add - Introduce a new meta data that persists the status of a dispute.
* Fix - Fix mandate creation for subscriptions and saved payment methods.
* Fix - Fix Google Pay address fields mapping for UAE addresses.
* Tweak - Render the Klarna payment page in the store locale.
Expand Down
15 changes: 9 additions & 6 deletions includes/class-wc-stripe-webhook-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ public function process_webhook_dispute_closed( $notification ) {
// Mark final so that order status is not overridden by out-of-sequence events.
$order->update_meta_data( '_stripe_status_final', true );

// Mark the dispute status.
$order->update_meta_data( '_dispute_closed_status', $status );

// Fail order if dispute is lost, or else revert to pre-dispute status.
$order_status = 'lost' === $status ? 'failed' : $this->get_stripe_order_status_before_hold( $order );
$order->update_status( $order_status, $message );
Expand Down Expand Up @@ -583,7 +586,7 @@ public function process_webhook_source_canceled( $notification ) {
*/
public function process_webhook_refund( $notification ) {
$refund_object = $this->get_refund_object( $notification );
$order = WC_Stripe_Helper::get_order_by_refund_id( $refund_object->id );
$order = WC_Stripe_Helper::get_order_by_refund_id( $refund_object->id );

if ( ! $order ) {
WC_Stripe_Logger::log( 'Could not find order via refund ID: ' . $refund_object->id );
Expand All @@ -598,11 +601,11 @@ public function process_webhook_refund( $notification ) {
$order_id = $order->get_id();

if ( 'stripe' === substr( (string) $order->get_payment_method(), 0, 6 ) ) {
$charge = $order->get_transaction_id();
$captured = $order->get_meta( '_stripe_charge_captured' );
$refund_id = $order->get_meta( '_stripe_refund_id' );
$currency = $order->get_currency();
$raw_amount = $refund_object->amount;
$charge = $order->get_transaction_id();
$captured = $order->get_meta( '_stripe_charge_captured' );
$refund_id = $order->get_meta( '_stripe_refund_id' );
$currency = $order->get_currency();
$raw_amount = $refund_object->amount;

if ( ! in_array( strtolower( $currency ), WC_Stripe_Helper::no_decimal_currencies(), true ) ) {
$raw_amount /= 100;
Expand Down
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ If you get stuck, you can ask for help in the Plugin Forum.
== Changelog ==

= 8.8.0 - xxxx-xx-xx =
* Add - Introduce a new meta data that persists the status of a dispute.
* Fix - Fix mandate creation for subscriptions and saved payment methods.
* Fix - Fix Google Pay address fields mapping for UAE addresses.
* Tweak - Render the Klarna payment page in the store locale.
Expand Down
103 changes: 95 additions & 8 deletions tests/phpunit/test-wc-stripe-webhook-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ class WC_Stripe_Webhook_Handler_Test extends WP_UnitTestCase {
* Mock card payment intent template.
*/
const MOCK_PAYMENT_INTENT = [
'id' => 'pi_mock',
'object' => 'payment_intent',
'status' => 'succeeded',
'charges' => [
'id' => 'pi_mock',
'object' => 'payment_intent',
'status' => 'succeeded',
'charges' => [
'total_count' => 1,
'data' => [
[
Expand Down Expand Up @@ -96,7 +96,7 @@ public function test_process_deferred_webhook_invalid_args() {
$this->mock_webhook_handler->process_deferred_webhook( 'payment_intent.succeeded', $data );

// No payment intent.
$order = WC_Helper_Order::create_order();
$order = WC_Helper_Order::create_order();
$data['order_id'] = $order->get_id();

$this->expectExceptionMessage( "Missing required data. 'intent_id' is missing for the deferred 'payment_intent.succeeded' event." );
Expand All @@ -110,7 +110,7 @@ public function test_process_deferred_webhook() {
$order = WC_Helper_Order::create_order();
$intent_id = 'pi_mock_1234';
$data = [
'order_id' => $order->get_id(),
'order_id' => $order->get_id(),
'intent_id' => $intent_id,
];

Expand All @@ -134,7 +134,7 @@ function( $passed_order ) use ( $order ) {
public function test_mismatch_intent_id_process_deferred_webhook() {
$order = WC_Helper_Order::create_order();
$data = [
'order_id' => $order->get_id(),
'order_id' => $order->get_id(),
'intent_id' => 'pi_wrong_id',
];

Expand Down Expand Up @@ -168,7 +168,7 @@ function( $passed_order ) use ( $order ) {
public function test_process_of_successful_payment_intent_deferred_webhook() {
$order = WC_Helper_Order::create_order();
$data = [
'order_id' => $order->get_id(),
'order_id' => $order->get_id(),
'intent_id' => self::MOCK_PAYMENT_INTENT['id'],
];

Expand Down Expand Up @@ -198,4 +198,91 @@ function( $passed_order ) use ( $order ) {

$this->mock_webhook_handler->process_deferred_webhook( 'payment_intent.succeeded', $data );
}

/**
* Test for `process_webhook_dispute_closed`
*
* @param string $charge_id Charge ID.
* @param string $dispute_status Dispute status.
* @param array $expected_metas Expected order metas.
* @param string $expected_status Expected order status.
* @return void
* @dataProvider provide_test_process_webhook_dispute_closed
* @throws WC_Data_Exception When order creation fails.
*/
public function test_process_webhook_dispute_closed( $charge_id, $dispute_status, $expected_metas, $expected_status ) {
$order = WC_Helper_Order::create_order();
$order->set_transaction_id( $charge_id );
$order->update_meta_data( '_stripe_status_before_hold', 'completed' );
$order->save();

$notification = (object) [
'data' => (object) [
'object' => (object) [
'charge' => $charge_id,
'status' => $dispute_status,
],
],
];

$this->mock_webhook_handler->process_webhook_dispute_closed( $notification );

// Reload the order.
$order = wc_get_order( $order->get_id() );

foreach ( $expected_metas as $meta_key => $meta_value ) {
$this->assertSame( $meta_value, get_post_meta( $order->get_id(), $meta_key, true ) );
}

$this->assertSame( $expected_status, $order->get_status() );
}

/**
* Provider for `test_process_webhook_dispute_closed`
*
* @return array
*/
public function provide_test_process_webhook_dispute_closed() {
return [
'order not found' => [
'charge id' => '',
'dispute status' => '',
'expected metas' => [],
'expected status' => 'pending',
],
'dispute lost' => [
'charge id' => '123',
'dispute status' => 'lost',
'expected metas' => [
'_stripe_status_final' => '1',
'_dispute_closed_status' => 'lost',
],
'expected status' => 'failed',
],
'dispute won' => [
'charge id' => '123',
'dispute status' => 'won',
'expected metas' => [
'_stripe_status_final' => '1',
'_dispute_closed_status' => 'won',
],
'expected status' => 'completed',
],
'inquiry closed' => [
'charge id' => '123',
'dispute status' => 'warning_closed',
'expected metas' => [
'_stripe_status_final' => '1',
'_dispute_closed_status' => 'warning_closed',
],
'expected status' => 'completed',
],
'unknown status' => [
'charge id' => '123',
'dispute status' => 'unknown',
'expected metas' => [],
'expected status' => 'pending',
],
];
}
}

0 comments on commit 5010cc7

Please sign in to comment.