Skip to content

Commit

Permalink
fix: never delete the idempotency key between failed orders, unless t…
Browse files Browse the repository at this point in the history
…he charge has the status FAILED in the API
  • Loading branch information
Marcuzz committed Dec 6, 2024
1 parent 576da38 commit d397bc9
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
1 change: 1 addition & 0 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ Alternatively you could look into using WooCommerce "Early renewals": [https://d
* Fixed: No longer throw an error when checking a Checkout payment where the subscription is now deleted.
* Fixed: Properly handle in-app subscription cancelling.
* Added: Support for the SEK currency.
* Fixed: Identified a potentially critical bug where the idempotency key was deleted from orders upon payment retry.

= 2.0.8 =
* Fixed: We should not return `true` in `cart_supports_checkout` if the cart is empty.
Expand Down
26 changes: 15 additions & 11 deletions includes/wc-gateway-vipps-recurring.php
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ public function process_order_charge( $order, ?WC_Vipps_Charge $charge = null ):
// status: DUE or PENDING
// when DUE, we need to check that it becomes another status in a cron
$initial = WC_Vipps_Recurring_Helper::get_meta( $order, WC_Vipps_Recurring_Helper::META_ORDER_INITIAL )
&& ! wcs_order_contains_renewal( $order );
&& ! wcs_order_contains_renewal( $order );

if ( ! $initial && ! $transaction_id && ( $charge->status === WC_Vipps_Charge::STATUS_DUE
|| ( $charge->status === WC_Vipps_Charge::STATUS_PENDING
Expand Down Expand Up @@ -836,7 +836,6 @@ public function scheduled_subscription_payment( $amount_to_charge, $order ): boo
return $this->process_subscription_payment( $amount_to_charge, $order );
} catch ( Exception $e ) {
// if we reach this point we consider the error to be completely unrecoverable.
WC_Vipps_Recurring_Helper::set_order_charge_failed( $order, new WC_Vipps_Charge() );
$order->update_status( 'failed' );

/* translators: Error message */
Expand Down Expand Up @@ -2072,14 +2071,19 @@ public function delete_resubscribe_meta( $resubscribe_order ): void {
*
* @param mixed $renewal_order The renewal order
*/
public function delete_renewal_meta( $renewal_order ) {
public function delete_renewal_meta( WC_Order $renewal_order ) {
// Do not delete the idempotency key if the order has failed previously
$has_failed_previously = WC_Vipps_Recurring_Helper::get_meta( $renewal_order, '_failed_renewal_order' );
if ( $has_failed_previously !== "yes" ) {
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_ORDER_IDEMPOTENCY_KEY );
}

WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_CHARGE_FAILED );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_CHARGE_FAILED_DESCRIPTION );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_CHARGE_FAILED_REASON );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_CHARGE_LATEST_STATUS );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_SUBSCRIPTION_UPDATE_IN_APP );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_SUBSCRIPTION_UPDATE_IN_APP_DESCRIPTION_PREFIX );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_ORDER_IDEMPOTENCY_KEY );
WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_CHARGE_CAPTURED );

WC_Vipps_Recurring_Helper::delete_meta_data( $renewal_order, WC_Vipps_Recurring_Helper::META_ORDER_INITIAL );
Expand Down Expand Up @@ -2406,7 +2410,7 @@ private function maybe_get_subscription_id_from_agreement_webhook( array $webhoo
$order_id = $webhook_data['agreementExternalId'];

// Check if agreementExternalId is not set, we can get the subscription from agreementId
if ( empty( $order_id ) && isset($webhook_data['agreementId']) ) {
if ( empty( $order_id ) && isset( $webhook_data['agreementId'] ) ) {
$agreement_id = $webhook_data['agreementId'];

$options = [
Expand All @@ -2421,14 +2425,14 @@ private function maybe_get_subscription_id_from_agreement_webhook( array $webhoo
];

$order_ids = wc_get_orders( $options );
$order_id = array_pop($order_ids);
$order_id = array_pop( $order_ids );
}

// If the order id is not a subscription, we can get the subscription from the order
if ( !empty( $order_id ) && !wcs_is_subscription($order_id) ) {
$order = wc_get_order($order_id);
$subscriptions = wcs_get_subscriptions_for_order($order);
$order_id = array_pop($subscriptions);
if ( ! empty( $order_id ) && ! wcs_is_subscription( $order_id ) ) {
$order = wc_get_order( $order_id );
$subscriptions = wcs_get_subscriptions_for_order( $order );
$order_id = array_pop( $subscriptions );
}

// Otherwise the order_id is either empty, or a subscription
Expand Down Expand Up @@ -2480,7 +2484,7 @@ public function handle_webhook_callback( array $webhook_data ): void {

// Customers can now cancel their agreements directly from the app.
if ( $event_type === 'recurring.agreement-stopped.v1' ) {
$subscription_id = $this->maybe_get_subscription_id_from_agreement_webhook($webhook_data);
$subscription_id = $this->maybe_get_subscription_id_from_agreement_webhook( $webhook_data );
if ( empty( $subscription_id ) ) {
return;
}
Expand Down

0 comments on commit d397bc9

Please sign in to comment.