From f3799ac63fbf86e5e761a50e47d08cba46adda99 Mon Sep 17 00:00:00 2001 From: "david.owusu" Date: Mon, 6 Oct 2025 12:10:42 +0200 Subject: [PATCH 1/2] [CC-2868] [CC-2868] Add chargeback webhook handling. --- src/Services/ResourceService.php | 10 ++++ test/integration/WebhookTest.php | 23 +++++++++ test/unit/Services/WebhooksServiceTest.php | 56 ++++++++++++++++++++-- 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/src/Services/ResourceService.php b/src/Services/ResourceService.php index b4bedfe1f..16821523e 100755 --- a/src/Services/ResourceService.php +++ b/src/Services/ResourceService.php @@ -209,6 +209,16 @@ public function fetchResourceByUrl($url) } $resource = $unzer->fetchReversal($paymentId, $resourceId); break; + case $resourceType === IdStrings::CHARGEBACK: + $paymentId = IdService::getResourceIdFromUrl($url, IdStrings::PAYMENT); + $chargeId = IdService::getResourceIdOrNullFromUrl($url, IdStrings::CHARGE); + + $resource = $this->fetchChargebackById( + $paymentId, + $resourceId, + $chargeId + ); + break; case $resourceType === IdStrings::PAYOUT: $resource = $unzer->fetchPayout(IdService::getResourceIdFromUrl($url, IdStrings::PAYMENT)); break; diff --git a/test/integration/WebhookTest.php b/test/integration/WebhookTest.php index beeb0f52e..57954480f 100755 --- a/test/integration/WebhookTest.php +++ b/test/integration/WebhookTest.php @@ -14,6 +14,7 @@ use UnzerSDK\Constants\ApiResponseCodes; use UnzerSDK\Constants\WebhookEvents; use UnzerSDK\Exceptions\UnzerApiException; +use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\Webhook; use UnzerSDK\test\BaseIntegrationTest; use function count; @@ -22,6 +23,7 @@ class WebhookTest extends BaseIntegrationTest { // + const CHARGEDBACK_PAYMENT_ID = 's-pay-341196'; /** * Verify Webhook resource can be registered and fetched. @@ -221,6 +223,27 @@ public function bulkSettingOnlyOneWebhookShouldBePossible(): void $this->assertEquals($url, $webhook->getUrl()); } + /** + * @test + */ + public function testFetchResourceFromEvent(): void + { + $webhookNotification = [ + 'event' => 'chargebacks', + 'publicKey' => 's-pub-xyz', + 'retrieveUrl' => 'https=>//sbx-api.unzer.com/v1/payments/' . self::CHARGEDBACK_PAYMENT_ID . '/charges/s-chg-1/chargebacks/s-cbk-1', + 'paymentId' => self::CHARGEDBACK_PAYMENT_ID + ]; + + // when + $chargeback = $this->unzer->fetchResourceFromEvent(json_encode($webhookNotification)); + + // then + $this->assertInstanceOf(Chargeback::class, $chargeback); + $this->assertNotNull($chargeback); + $this->assertEquals('s-cbk-1', $chargeback->getId()); + } + // // diff --git a/test/unit/Services/WebhooksServiceTest.php b/test/unit/Services/WebhooksServiceTest.php index b21f94043..c710522d1 100755 --- a/test/unit/Services/WebhooksServiceTest.php +++ b/test/unit/Services/WebhooksServiceTest.php @@ -11,16 +11,18 @@ namespace UnzerSDK\test\unit\Services; -use UnzerSDK\Unzer; +use RuntimeException; +use stdClass; use UnzerSDK\Interfaces\ResourceServiceInterface; +use UnzerSDK\Resources\TransactionTypes\Charge; +use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\Webhook; use UnzerSDK\Resources\Webhooks; use UnzerSDK\Services\ResourceService; use UnzerSDK\Services\WebhookService; use UnzerSDK\test\BasePaymentTest; use UnzerSDK\test\unit\DummyResource; -use RuntimeException; -use stdClass; +use UnzerSDK\Unzer; class WebhooksServiceTest extends BasePaymentTest { @@ -328,6 +330,54 @@ public function fetchResourceByEventWithEmptyRetrieveUrlShouldThrowException(): $webhookService->fetchResourceFromEvent(); } + /** + * Verify exception is thrown if the retrieveURL is empty. + * + * @test + */ + public function fetchChargebackByEventShouldReturnChargeback(): void + { + // given + $unzer = new Unzer('s-priv-1234'); + $webhookService = new WebhookService($unzer); + + $paymentId = 'p-pay-42'; + $chargeId = 'p-chg-1'; + $chargebackId = 'p-cbk-1'; + $retrieveUrl = "https://api.unzer.com/v1/payments/{$paymentId}/charges/{$chargeId}/chargebacks/{$chargebackId}"; + + // Partial mock: keep original behavior except fetchChargebackById which we want to intercept + $resourceServiceMock = $this->getMockBuilder(ResourceService::class) + ->setConstructorArgs([$unzer]) + ->setMethods(['fetchChargebackById']) + ->getMock(); + + $chargeback = (new Chargeback(10.0)) + ->setId($chargebackId) + ->setParentResource((new Charge())->setId($chargeId)); + + $resourceServiceMock->expects($this->once()) + ->method('fetchChargebackById') + ->with($paymentId, $chargebackId, $chargeId) + ->willReturn($chargeback); + + $webhookService->setResourceService($resourceServiceMock); + + $eventJson = json_encode([ + 'event' => 'chargeback', + 'publicKey' => 's-pub-xyz', + 'retrieveUrl' => $retrieveUrl, + 'paymentId' => $paymentId + ]); + + // when + $fetchedChargeback = $webhookService->fetchResourceFromEvent($eventJson); + + // then + $this->assertSame($chargeback, $fetchedChargeback); + $this->assertNotNull($fetchedChargeback); + } + /** * Verify exception is thrown if the retrieveURL is empty. * From 9bd90e359775e654dbefa60be2a59933bb22c7b7 Mon Sep 17 00:00:00 2001 From: "david.owusu" Date: Tue, 7 Oct 2025 09:16:56 +0200 Subject: [PATCH 2/2] [CC-2868] [CC-2868] Add chargeback webhook handling. --- test/integration/WebhookTest.php | 2 +- test/unit/Services/WebhooksServiceTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/WebhookTest.php b/test/integration/WebhookTest.php index 57954480f..bdae8add7 100755 --- a/test/integration/WebhookTest.php +++ b/test/integration/WebhookTest.php @@ -231,7 +231,7 @@ public function testFetchResourceFromEvent(): void $webhookNotification = [ 'event' => 'chargebacks', 'publicKey' => 's-pub-xyz', - 'retrieveUrl' => 'https=>//sbx-api.unzer.com/v1/payments/' . self::CHARGEDBACK_PAYMENT_ID . '/charges/s-chg-1/chargebacks/s-cbk-1', + 'retrieveUrl' => 'https://sbx-api.unzer.com/v1/payments/' . self::CHARGEDBACK_PAYMENT_ID . '/charges/s-chg-1/chargebacks/s-cbk-1', 'paymentId' => self::CHARGEDBACK_PAYMENT_ID ]; diff --git a/test/unit/Services/WebhooksServiceTest.php b/test/unit/Services/WebhooksServiceTest.php index c710522d1..df5519c66 100755 --- a/test/unit/Services/WebhooksServiceTest.php +++ b/test/unit/Services/WebhooksServiceTest.php @@ -331,7 +331,7 @@ public function fetchResourceByEventWithEmptyRetrieveUrlShouldThrowException(): } /** - * Verify exception is thrown if the retrieveURL is empty. + * Verify that a chargeback is returned from a webhook event. * * @test */ @@ -341,9 +341,9 @@ public function fetchChargebackByEventShouldReturnChargeback(): void $unzer = new Unzer('s-priv-1234'); $webhookService = new WebhookService($unzer); - $paymentId = 'p-pay-42'; - $chargeId = 'p-chg-1'; - $chargebackId = 'p-cbk-1'; + $paymentId = 's-pay-42'; + $chargeId = 's-chg-1'; + $chargebackId = 's-cbk-1'; $retrieveUrl = "https://api.unzer.com/v1/payments/{$paymentId}/charges/{$chargeId}/chargebacks/{$chargebackId}"; // Partial mock: keep original behavior except fetchChargebackById which we want to intercept