diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b4e26c26..2fded2620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# REPLACE_GLOBALLY_WITH_NEXT_VERSION +- Fixes an issue, where cookies are added even though associated payment methods are not active (shopware/SwagPayPal#457) +- Fixes an issue, where the state of a country was not correctly transmitted to PayPal (shopware/SwagPayPal#469) +- Added Apple Pay support for third-party browsers (shopware/SwagPayPal#485) +- Added setting to mark the shop as local environment to preventing connection issues when testing in a non-publicly accessible environment (shopware/SwagPayPal#463) +- Updated and optimized payment method icons +- Fixes an issue, where stale `PAYMENT.AUTHORIZATION.VOIDED` webhooks could cancel unrelated order transactions + # 10.6.1 - Fixes an issue, where declined PayPal payments were still shown as refundable in the Administration (shopware/SwagPayPal#547) - Fixes an issue, where the express checkout shipping callback returned unsupported order fields. @@ -31,11 +39,6 @@ # 10.4.0 - Fixes an issue, where the express checkout could choose a customer country that was not assigned to the correct sales channel (shopware/SwagPayPal#479) -- Fixes an issue, where cookies are added even though associated payment methods are not active (shopware/SwagPayPal#457) -- Fixes an issue, where the state of a country was not correctly transmitted to PayPal (shopware/SwagPayPal#469) -- Added Apple Pay support for third-party browsers (shopware/SwagPayPal#485) -- Added setting to mark the shop as local environment to preventing connection issues when testing in a non-publicly accessible environment (shopware/SwagPayPal#463) -- Updated and optimized payment method icons # 10.3.0 - Added compatibility with subscription mixed carts (shopware/shopware#10486) diff --git a/src/Webhook/Handler/AuthorizationVoided.php b/src/Webhook/Handler/AuthorizationVoided.php index 0ff012ebd..466953340 100644 --- a/src/Webhook/Handler/AuthorizationVoided.php +++ b/src/Webhook/Handler/AuthorizationVoided.php @@ -13,6 +13,7 @@ use Shopware\PayPalSDK\Struct\V1\Webhook\Event; use Shopware\PayPalSDK\Struct\V1\Webhook\Resource; use Shopware\PayPalSDK\Struct\V2\Order\PurchaseUnit\Payments\Authorization; +use Swag\PayPal\SwagPayPal; use Swag\PayPal\Webhook\Exception\WebhookException; use Swag\PayPal\Webhook\WebhookEventTypes; @@ -37,6 +38,15 @@ public function invoke(Event $webhook, Context $context): void throw new WebhookException($this->getEventType(), 'Order transaction could not be resolved'); } + if ($resource instanceof Authorization) { + $customFields = $orderTransaction->getCustomFields() ?? []; + $storedResourceId = $customFields[SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID] ?? null; + $isStaleAuthorization = $storedResourceId !== null && $storedResourceId !== $resource->getId(); + if ($isStaleAuthorization) { + return; + } + } + if ($this->isChangeAllowed($orderTransaction, OrderTransactionStates::STATE_CANCELLED)) { $this->orderTransactionStateHandler->cancel($orderTransaction->getId(), $context); } diff --git a/tests/Webhook/Handler/AuthorizationVoidedV2Test.php b/tests/Webhook/Handler/AuthorizationVoidedV2Test.php index 07d4c6d86..90f1e3a30 100644 --- a/tests/Webhook/Handler/AuthorizationVoidedV2Test.php +++ b/tests/Webhook/Handler/AuthorizationVoidedV2Test.php @@ -13,6 +13,8 @@ use Shopware\Core\Framework\Log\Package; use Shopware\Core\Framework\Uuid\Uuid; use Shopware\PayPalSDK\Struct\V1\Webhook\Event; +use Shopware\PayPalSDK\Struct\V2\Order\PurchaseUnit\Payments\Authorization; +use Swag\PayPal\SwagPayPal; use Swag\PayPal\Webhook\Exception\WebhookException; use Swag\PayPal\Webhook\Handler\AuthorizationVoided; use Swag\PayPal\Webhook\WebhookEventTypes; @@ -57,6 +59,54 @@ public function testInvokeWithoutTransaction(): void $this->assertInvokeWithoutTransaction(WebhookEventTypes::PAYMENT_AUTHORIZATION_VOIDED, $webhook, $reason); } + public function testInvokeWithStaleResourceId(): void + { + $context = Context::createDefaultContext(); + $container = $this->getContainer(); + $transactionId = $this->getTransactionId($context, $container); + + $this->orderTransactionRepository->update([[ + 'id' => $transactionId, + 'customFields' => [ + SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID => 'stored-auth-id', + ], + ]], $context); + + $webhook = $this->createWebhookV2(Event::RESOURCE_TYPE_AUTHORIZATION); + $resource = $webhook->getResource(); + static::assertInstanceOf(Authorization::class, $resource); + $resource->setCustomId(\json_encode(['orderTransactionId' => $transactionId]) ?: null); + $resource->assign(['id' => 'different-auth-id']); + + $this->webhookHandler->invoke($webhook, $context); + + $this->assertOrderTransactionState(OrderTransactionStates::STATE_OPEN, $transactionId, $context); + } + + public function testInvokeWithMatchingResourceId(): void + { + $context = Context::createDefaultContext(); + $container = $this->getContainer(); + $transactionId = $this->getTransactionId($context, $container); + + $this->orderTransactionRepository->update([[ + 'id' => $transactionId, + 'customFields' => [ + SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID => 'matching-auth-id', + ], + ]], $context); + + $webhook = $this->createWebhookV2(Event::RESOURCE_TYPE_AUTHORIZATION); + $resource = $webhook->getResource(); + static::assertInstanceOf(Authorization::class, $resource); + $resource->setCustomId(\json_encode(['orderTransactionId' => $transactionId]) ?: null); + $resource->assign(['id' => 'matching-auth-id']); + + $this->webhookHandler->invoke($webhook, $context); + + $this->assertOrderTransactionState(OrderTransactionStates::STATE_CANCELLED, $transactionId, $context); + } + public function testInvokeWithSameInitialState(): void { $webhook = $this->createWebhookV2(Event::RESOURCE_TYPE_AUTHORIZATION);