diff --git a/CHANGELOG.md b/CHANGELOG.md index 409acb52..5974a786 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.1.2.0] +### Added +* Payment type ApplePay. + ## [1.1.1.1] ### Fix @@ -60,3 +64,4 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a [1.1.0.0]: https://github.com/unzerdev/php-sdk/compare/1260b8314af1ac461e33f0cfb382ffcd0e87c105..1.1.0.0 [1.1.1.0]: https://github.com/unzerdev/php-sdk/compare/1.1.0.0..1.1.1.0 [1.1.1.1]: https://github.com/unzerdev/php-sdk/compare/1.1.1.0..1.1.1.1 +[1.1.2.0]: https://github.com/unzerdev/php-sdk/compare/1.1.1.1..1.1.2.0 diff --git a/src/Constants/IdStrings.php b/src/Constants/IdStrings.php index 13d4cd48..d80c3957 100755 --- a/src/Constants/IdStrings.php +++ b/src/Constants/IdStrings.php @@ -35,6 +35,7 @@ class IdStrings // Payment Types public const ALIPAY = 'ali'; + public const APPLEPAY = 'apl'; public const BANCONTACT = 'bct'; public const CARD = 'crd'; public const EPS = 'eps'; @@ -66,6 +67,7 @@ class IdStrings public const WEBHOOK = 'whk'; public const PAYMENT_TYPES = [ self::ALIPAY, + self::APPLEPAY, self::BANCONTACT, self::CARD, self::EPS, diff --git a/src/Resources/EmbeddedResources/ApplePayHeader.php b/src/Resources/EmbeddedResources/ApplePayHeader.php new file mode 100644 index 00000000..094f12fe --- /dev/null +++ b/src/Resources/EmbeddedResources/ApplePayHeader.php @@ -0,0 +1,110 @@ + + * + * @package UnzerSDK\Resources\EmbeddedResources + */ +namespace UnzerSDK\Resources\EmbeddedResources; + +use UnzerSDK\Resources\AbstractUnzerResource; + +class ApplePayHeader extends AbstractUnzerResource +{ + /** @var string|null */ + protected $ephemeralPublicKey; + + /** @var string|null */ + protected $publicKeyHash; + + /** @var string|null */ + protected $transactionId; + + /** + * ApplePayHeader constructor. + * + * @param string|null $ephemeralPublicKey + * @param string|null $publicKeyHash + * @param string|null $transactionId + */ + public function __construct(?string $ephemeralPublicKey, ?string $publicKeyHash, ?string $transactionId = null) + { + $this->ephemeralPublicKey = $ephemeralPublicKey; + $this->publicKeyHash = $publicKeyHash; + $this->transactionId = $transactionId; + } + + /** + * @param string|null $ephemeralPublicKey + * + * @return ApplePayHeader + */ + public function setEphemeralPublicKey(?string $ephemeralPublicKey): ApplePayHeader + { + $this->ephemeralPublicKey = $ephemeralPublicKey; + return $this; + } + + /** + * @param string|null $publicKeyHash + * + * @return ApplePayHeader + */ + public function setPublicKeyHash(?string $publicKeyHash): ApplePayHeader + { + $this->publicKeyHash = $publicKeyHash; + return $this; + } + + /** + * @param string|null $transactionId + * + * @return ApplePayHeader + */ + public function setTransactionId(?string $transactionId): ApplePayHeader + { + $this->transactionId = $transactionId; + return $this; + } + + /** + * @return string|null + */ + public function getEphemeralPublicKey(): ?string + { + return $this->ephemeralPublicKey; + } + + /** + * @return string|null + */ + public function getPublicKeyHash(): ?string + { + return $this->publicKeyHash; + } + + /** + * @return string|null + */ + public function getTransactionId(): ?string + { + return $this->transactionId; + } +} diff --git a/src/Resources/PaymentTypes/Applepay.php b/src/Resources/PaymentTypes/Applepay.php new file mode 100644 index 00000000..2eb12631 --- /dev/null +++ b/src/Resources/PaymentTypes/Applepay.php @@ -0,0 +1,274 @@ + + * + * @package UnzerSDK\PaymentTypes + */ +namespace UnzerSDK\Resources\PaymentTypes; + +use stdClass; +use UnzerSDK\Adapter\HttpAdapterInterface; +use UnzerSDK\Resources\EmbeddedResources\ApplePayHeader; +use UnzerSDK\Traits\CanAuthorize; +use UnzerSDK\Traits\CanDirectCharge; +use UnzerSDK\Traits\HasGeoLocation; + +class Applepay extends BasePaymentType +{ + use CanDirectCharge; + use CanAuthorize; + use HasGeoLocation; + + /** @var string|null $applicationExpirationDate */ + private $applicationExpirationDate; + + /** @var string|null $applicationPrimaryAccountNumber */ + private $applicationPrimaryAccountNumber; + + /** @var string|null $currencyCode */ + private $currencyCode; + + /** @var string|null $data */ + protected $data; + + /** @var string|null $method */ + private $method; + + /** @var string|null $signature */ + protected $signature; + + /** @var float $transactionAmount */ + private $transactionAmount; + + /** @var string|null $version */ + protected $version; + + /** @var ApplePayHeader|null $header */ + protected $header; + + /** + * ApplePay constructor. + * + * @param string|null $version + * @param string|null $data + * @param string|null $signature + * @param ApplePayHeader|null $header + */ + public function __construct( + ?string $version, + ?string $data, + ?string $signature, + ?ApplePayHeader $header + ) { + $this->version = $version; + $this->data = $data; + $this->signature = $signature; + $this->header = $header; + } + + //applicationExpirationDate; + } + + /** + * @return string|null + */ + public function getApplicationPrimaryAccountNumber(): ?string + { + return $this->applicationPrimaryAccountNumber; + } + + /** + * @return string|null + */ + public function getCurrencyCode(): ?string + { + return $this->currencyCode; + } + + /** + * @return string|null + */ + public function getData(): ?string + { + return $this->data; + } + + /** + * @return ApplePayHeader|null + */ + public function getHeader(): ?ApplePayHeader + { + return $this->header; + } + + /** + * @return string|null + */ + public function getMethod(): ?string + { + return $this->method; + } + + /** + * @return string|null + */ + public function getSignature(): ?string + { + return $this->signature; + } + + /** + * @return float + */ + public function getTransactionAmount(): ?float + { + return $this->transactionAmount; + } + + /** + * @return string|null + */ + public function getVersion(): ?string + { + return $this->version; + } + + /** + * @param string|null $applicationExpirationDate + * + * @return $this + */ + protected function setApplicationExpirationDate(?string $applicationExpirationDate): Applepay + { + $this->applicationExpirationDate = $applicationExpirationDate; + return $this; + } + + /** + * @param string|null $applicationPrimaryAccountNumber + * + * @return $this + */ + protected function setApplicationPrimaryAccountNumber(?string $applicationPrimaryAccountNumber): Applepay + { + $this->applicationPrimaryAccountNumber = $applicationPrimaryAccountNumber; + return $this; + } + + /** + * @param string|null $currencyCode + * + * @return $this + */ + protected function setCurrencyCode(?string $currencyCode): Applepay + { + $this->currencyCode = $currencyCode; + return $this; + } + + /** + * @param string|null $data + * + * @return $this + */ + public function setData(?string $data): Applepay + { + $this->data = $data; + return $this; + } + + /** + * @param ApplePayHeader $header + * + * @return Applepay + */ + public function setHeader(ApplePayHeader $header): Applepay + { + $this->header = $header; + return $this; + } + + /** + * @param string|null $method + * + * @return $this + */ + protected function setMethod(?string $method): Applepay + { + $this->method = $method; + return $this; + } + + /** + * @param string|null $signature + * + * @return $this + */ + public function setSignature(?string $signature): Applepay + { + $this->signature = $signature; + return $this; + } + + /** + * @param float $transactionAmount + * + * @return $this + */ + protected function setTransactionAmount(float $transactionAmount): Applepay + { + $this->transactionAmount = $transactionAmount; + return $this; + } + + /** + * @param string|null $version + * + * @return $this + */ + public function setVersion(?string $version): Applepay + { + $this->version = $version; + return $this; + } + + // + + /** + * @inheritDoc + */ + public function handleResponse(stdClass $response, $method = HttpAdapterInterface::REQUEST_GET): void + { + parent::handleResponse($response, $method); + + if (isset($response->header)) { + $this->header = new ApplePayHeader(null, null, null); + $this->header->handleResponse($response->header); + } + } +} diff --git a/src/Services/ResourceService.php b/src/Services/ResourceService.php index 8d9faa01..ae571585 100755 --- a/src/Services/ResourceService.php +++ b/src/Services/ResourceService.php @@ -30,6 +30,7 @@ use UnzerSDK\Constants\ApiResponseCodes; use UnzerSDK\Constants\IdStrings; use UnzerSDK\Exceptions\UnzerApiException; +use UnzerSDK\Resources\PaymentTypes\Applepay; use UnzerSDK\Unzer; use UnzerSDK\Interfaces\ResourceServiceInterface; use UnzerSDK\Resources\AbstractUnzerResource; @@ -515,6 +516,9 @@ public function fetchPaymentType($typeId): BasePaymentType case IdStrings::ALIPAY: $paymentType = new Alipay(); break; + case IdStrings::APPLEPAY: + $paymentType = new Applepay(null, null, null, null); + break; case IdStrings::BANCONTACT: $paymentType = new Bancontact(); break; diff --git a/src/Unzer.php b/src/Unzer.php index 65faadf8..1b0594fc 100644 --- a/src/Unzer.php +++ b/src/Unzer.php @@ -63,7 +63,7 @@ class Unzer implements UnzerParentInterface, PaymentServiceInterface, ResourceSe public const BASE_URL = 'api.unzer.com'; public const API_VERSION = 'v1'; public const SDK_TYPE = 'UnzerPHP'; - public const SDK_VERSION = '1.1.1.1'; + public const SDK_VERSION = '1.1.2.0'; /** @var string $key */ private $key; diff --git a/test/integration/PaymentTypes/ApplepayTest.php b/test/integration/PaymentTypes/ApplepayTest.php new file mode 100644 index 00000000..d76ea066 --- /dev/null +++ b/test/integration/PaymentTypes/ApplepayTest.php @@ -0,0 +1,163 @@ + + * + * @package UnzerSDK + * + */ + +namespace UnzerSDK\test\integration\PaymentTypes; + +use UnzerSDK\Resources\PaymentTypes\Applepay; +use UnzerSDK\test\BaseIntegrationTest; + +class ApplepayTest extends BaseIntegrationTest +{ + /** + * Verify applepay can be created and fetched. + * + * @test + */ + public function applepayShouldBeCreatableAndFetchable(): void + { + $applepay = $this->createApplepayObject(); + $this->unzer->createPaymentType($applepay); + $this->assertNotNull($applepay->getId()); + + /** @var Applepay $fetchedPaymentTyp */ + $fetchedPaymentTyp = $this->unzer->fetchPaymentType($applepay->getId()); + $this->assertInstanceOf(Applepay::class, $fetchedPaymentTyp); + $this->assertNull($fetchedPaymentTyp->getVersion()); + $this->assertNull($fetchedPaymentTyp->getData()); + $this->assertNull($fetchedPaymentTyp->getSignature()); + $this->assertNull($fetchedPaymentTyp->getHeader()); + } + + /** + * Verify that applepay is chargeable + * + * @test + */ + public function applepayShouldBeChargeable(): void + { + $applepay = $this->createApplepayObject(); + $this->unzer->createPaymentType($applepay); + $charge = $applepay->charge(100.0, 'EUR', self::RETURN_URL); + $this->assertNotNull($charge->getId()); + $this->assertNull($charge->getRedirectUrl()); + } + + /** + * Verify that applepay is chargeable + * + * @test + */ + public function applepayCanBeAuthorized(): void + { + $applepay = $this->createApplepayObject(); + $this->unzer->createPaymentType($applepay); + $charge = $applepay->authorize(100.0, 'EUR', self::RETURN_URL); + + $this->assertNotNull($charge->getId()); + $this->assertNull($charge->getRedirectUrl()); + } + + /** + * Verify the applepay can charge the full amount of the authorization and the payment state is updated accordingly. + * + * @test + */ + public function fullChargeAfterAuthorize(): void + { + $applepay = $this->createApplepayObject(); + $this->unzer->createPaymentType($applepay); + + $authorization = $applepay->authorize(1.0, 'EUR', self::RETURN_URL, null, null, null, null, false); + $payment = $authorization->getPayment(); + + // pre-check to verify changes due to fullCharge call + $this->assertAmounts($payment, 1.0, 0.0, 1.0, 0.0); + $this->assertTrue($payment->isPending()); + + $charge = $this->unzer->chargeAuthorization($payment->getId()); + $paymentNew = $charge->getPayment(); + + // verify payment has been updated properly + $this->assertAmounts($paymentNew, 0.0, 1.0, 1.0, 0.0); + $this->assertTrue($paymentNew->isCompleted()); + } + + /** + * Verify applepay authorize can be canceled. + * + * @test + */ + public function applepayAuthorizeCanBeCanceled(): void + { + /** @var Applepay $applepay */ + $applepay = $this->unzer->createPaymentType($this->createApplepayObject()); + $authorize = $applepay->authorize(100.0, 'EUR', self::RETURN_URL, null, null, null, null, false); + + $cancel = $authorize->cancel(); + $this->assertNotNull($cancel); + $this->assertNotEmpty($cancel->getId()); + } + + /** + * @test + */ + public function fullCancelAfterCharge(): void + { + $applepay = $this->createApplepayObject(); + $this->unzer->createPaymentType($applepay); + $charge = $applepay->charge(100.0, 'EUR', self::RETURN_URL, null, null, null, null, false); + $payment = $charge->getPayment(); + + $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); + $this->assertTrue($payment->isCompleted()); + + $payment->cancelAmount(); + $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); + $this->assertTrue($payment->isCanceled()); + } + + /** + * @return Applepay + */ + private function createApplepayObject(): Applepay + { + $applepayAutorization = '{ + "version": "EC_v1", + "data": "TwQBBorcg6aEb5eidSJm5fNG5sih+R+xgeJbvAX8oMQ7EXhIWOE+ACnvBFHOkZOjI+ump/zVrBXTMRYSw32WMWXPuiRDlYu8DMNuV3qKrbC+G5Du5qfxsm8BxJCXkc/DqtGqc70o8TJCn9lM5ePQjS3io4HDonkN4b4L20GfyEVW1QyvozaMa1u7/gaS6OhhXNk65Z70+xCZlOGmgDtgcdZK+TQIYgRLzyP+1+mpqd61pQ3vJELB8ngMoleCGd1DHx2kVWsudZQ5q97sUjpZV2ySfPXLMhWHYYfvcvSx3dKDAywUoR8clUeDKtoZ4LsBO/B8XM/T4JKnFmWfr7Z25E88vfMWIs8JpxIC5OKAPZfVZoDSNs+4LR+twVxlD5B2xkvG6ln6j4cQ+CFmiq9FPSDgQJsn8O7K9Ag0odXiK6mZczOWt2HCHaw0thF/WpudObVlmw5NN1r54/Jxoichp+DJ2Hl1NJqDHKS1fNyXQcR5jqID7QOcpQi0gE332bOTIz/xe+u328GMCl6Rms3JJxFnnskfEA7nicIH8DLFeSbG8jloLyKBBLk=", + "signature": "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", + "header": { + "ephemeralPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW7hYAxjCeE/r9SSRX/hJsfO+VxLvUqIzyeGn6lZ1v/pYYS66Bz0dsSzoMMZg8G32TAPXUr97AD4zCXfcQoZaOA==", + "publicKeyHash": "zqO5Y3ldWWm4NnIkfGCvJILw30rp3y46Jsf21gE8CNg=", + "transactionId": "94f6b37149ae2098efb287ed0ade704284cff3f672ef7f0dc17614b31e926b9d" + } + }'; + + $applepay = new Applepay(null, null, null, null); + $applepay->handleResponse(json_decode($applepayAutorization)); + return $applepay; + } +} diff --git a/test/unit/Resources/AbstractUnzerResourceTest.php b/test/unit/Resources/AbstractUnzerResourceTest.php index 494a680b..571cc0a6 100644 --- a/test/unit/Resources/AbstractUnzerResourceTest.php +++ b/test/unit/Resources/AbstractUnzerResourceTest.php @@ -33,6 +33,7 @@ use UnzerSDK\Constants\Salutations; use UnzerSDK\Constants\TransactionTypes; use UnzerSDK\Resources\InstalmentPlans; +use UnzerSDK\Resources\PaymentTypes\Applepay; use UnzerSDK\Unzer; use UnzerSDK\Resources\AbstractUnzerResource; use UnzerSDK\Resources\Basket; @@ -443,6 +444,7 @@ public function uriDataProvider(): array 'Ideal' => [new Ideal(), 'parent/resource/path/types/ideal'], 'EPS' => [new EPS(), 'parent/resource/path/types/eps'], 'Alipay' => [new Alipay(), 'parent/resource/path/types/alipay'], + 'ApplePay' => [new Applepay('EC_v1', 'data', 'sig', null), 'parent/resource/path/types/applepay'], 'SepaDirectDebit' => [new SepaDirectDebit(''), 'parent/resource/path/types/sepa-direct-debit'], 'SepaDirectDebitSecured' => [new SepaDirectDebitSecured(''), 'parent/resource/path/types/sepa-direct-debit-secured'], 'Invoice' => [new Invoice(), 'parent/resource/path/types/invoice'], @@ -467,14 +469,15 @@ public function fetchUriDataProvider() { return [ // Payment types. + 'Alipay' => [new Alipay(), 'parent/resource/path/types'], + 'ApplePay' => [new Applepay('EC_v1', 'data', 'sig', null), 'parent/resource/path/types'], 'Card' => [new Card('', '03/30'), 'parent/resource/path/types'], - 'Ideal' => [new Ideal(), 'parent/resource/path/types'], 'EPS' => [new EPS(), 'parent/resource/path/types'], - 'Alipay' => [new Alipay(), 'parent/resource/path/types'], + 'Ideal' => [new Ideal(), 'parent/resource/path/types'], + 'InstallmentSecured' => [new InstallmentSecured(), 'parent/resource/path/types'], + 'Invoice' => [new Invoice(), 'parent/resource/path/types'], 'SepaDirectDebit' => [new SepaDirectDebit(''), 'parent/resource/path/types'], 'SepaDirectDebitSecured' => [new SepaDirectDebitSecured(''), 'parent/resource/path/types'], - 'Invoice' => [new Invoice(), 'parent/resource/path/types'], - 'InstallmentSecured' => [new InstallmentSecured(), 'parent/resource/path/types'], // Other resources Uris should behave as before. 'Customer' => [new Customer(), 'parent/resource/path/customers'], diff --git a/test/unit/Resources/EmbeddedResources/ApplePayHeaderTest.php b/test/unit/Resources/EmbeddedResources/ApplePayHeaderTest.php new file mode 100644 index 00000000..0dc6a203 --- /dev/null +++ b/test/unit/Resources/EmbeddedResources/ApplePayHeaderTest.php @@ -0,0 +1,47 @@ + + * + * @package UnzerSDK\test\unit + */ +namespace UnzerSDK\test\unit\Resources\EmbeddedResources; + +use UnzerSDK\Resources\EmbeddedResources\ApplePayHeader; +use PHPUnit\Framework\TestCase; + +class ApplePayHeaderTest extends TestCase +{ + /** + * Verify the resource data is set properly. + * + * @test + */ + public function constructorShouldSetParameters(): void + { + $applepayHeader = new ApplePayHeader('ephemeralPublicKey', 'publicKeyHash', 'transactionId'); + + $this->assertEquals('ephemeralPublicKey', $applepayHeader->getEphemeralPublicKey()); + $this->assertEquals('publicKeyHash', $applepayHeader->getPublicKeyHash()); + $this->assertEquals('transactionId', $applepayHeader->getTransactionId()); + } +} diff --git a/test/unit/Resources/PaymentTypes/ApplePayTest.php b/test/unit/Resources/PaymentTypes/ApplePayTest.php new file mode 100644 index 00000000..0b6374df --- /dev/null +++ b/test/unit/Resources/PaymentTypes/ApplePayTest.php @@ -0,0 +1,149 @@ + + * + * @package UnzerSDK\test\unit + */ +namespace UnzerSDK\test\unit\Resources\PaymentTypes; + +use UnzerSDK\Resources\EmbeddedResources\ApplePayHeader; +use UnzerSDK\Resources\PaymentTypes\Applepay; +use UnzerSDK\test\BasePaymentTest; + +class ApplePayTest extends BasePaymentTest +{ + /** + * Verify the resource data is set properly. + * + * @test + */ + public function constructorShouldSetParameters(): void + { + $version = 'EC_v1'; + $data = 'some-Data'; + $signature = 'mySignature'; + $applepay = new Applepay($version, $data, $signature, $this->getTestApplePayHeader()); + + $this->assertEquals($version, $applepay->getVersion()); + $this->assertEquals($data, $applepay->getData()); + $this->assertEquals($signature, $applepay->getSignature()); + $this->assertInstanceOf(ApplePayHeader::class, $applepay->getHeader()); + } + + /** + * Test Apple Pay json serialization. + * + * @test + */ + public function jsonSerializationExposesOnlyRequestParameter(): void + { + $applepay = $this->getTestApplepay(); + + $expectedJson = '{ "data": "data", "header": { "ephemeralPublicKey": "ephemeralPublicKey", "publicKeyHash": ' . + '"publicKeyHash", "transactionId": "transactionId" }, "signature": "sig", "version": "EC_v1" }'; + + $this->assertJsonStringEqualsJsonString($expectedJson, $applepay->jsonSerialize()); + } + + /** + * Test Apple Pay json response handling. + * + * @test + */ + public function responseShouldBeMappedCorrectly(): void + { + $applepay = new Applepay(null, null, null, null); + + $jsonResponse = '{ + "id": "s-apl-faucbirhd6yy", + "method": "apple-pay", + "recurring": false, + "geoLocation": { + "clientIp": "115.77.189.143", + "countryCode": "" + }, + "applicationPrimaryAccountNumber": "370295******922", + "applicationExpirationDate": "07/2020", + "currencyCode": "EUR", + "transactionAmount": "1.5000" + }'; + + $applepay->handleResponse(json_decode($jsonResponse)); + + $this->assertEquals('s-apl-faucbirhd6yy', $applepay->getId()); + $this->assertEquals('apple-pay', $applepay->getMethod()); + $this->assertEquals('370295******922', $applepay->getApplicationPrimaryAccountNumber()); + $this->assertEquals('07/2020', $applepay->getApplicationExpirationDate()); + $this->assertEquals('EUR', $applepay->getCurrencyCode()); + $this->assertSame(1.5000, $applepay->getTransactionAmount()); + $this->assertNotNull($applepay->getGeoLocation()); + } + + /** + * Test Apple Pay json response handling. + * + * @test + */ + public function applepayAuthorizationShouldBeMappedCorrectly(): void + { + $applepay = new Applepay(null, null, null, null); + + $jsonResponse = '{ + "version": "EC_v1", + "data": "data", + "signature": "signature", + "header": { + "ephemeralPublicKey": "ephemeralPublicKey", + "publicKeyHash": "publicKeyHash", + "transactionId": "transactionId" + } + }'; + + $applepay->handleResponse(json_decode($jsonResponse)); + + $this->assertEquals('EC_v1', $applepay->getVersion()); + $this->assertEquals('data', $applepay->getData()); + $this->assertEquals('signature', $applepay->getSignature()); + $applePayHeader = $applepay->getHeader(); + $this->assertNotNull($applePayHeader); + $this->assertEquals('ephemeralPublicKey', $applePayHeader->getEphemeralPublicKey()); + $this->assertEquals('publicKeyHash', $applePayHeader->getPublicKeyHash()); + $this->assertEquals('transactionId', $applePayHeader->getTransactionId()); + } + + /** + * @return ApplePayHeader + */ + private function getTestApplePayHeader(): ApplePayHeader + { + return new ApplePayHeader('ephemeralPublicKey', 'publicKeyHash', 'transactionId'); + } + + /** + * @return Applepay + */ + private function getTestApplepay(): Applepay + { + return new Applepay('EC_v1', 'data', 'sig', $this->getTestApplePayHeader()); + } +} diff --git a/test/unit/Services/ResourceServiceTest.php b/test/unit/Services/ResourceServiceTest.php index 5489518a..e6336f2f 100755 --- a/test/unit/Services/ResourceServiceTest.php +++ b/test/unit/Services/ResourceServiceTest.php @@ -1143,26 +1143,27 @@ public function fetchResourceByUrlShouldFetchTheDesiredResourceDP(): array public function fetchResourceByUrlForAPaymentTypeShouldCallFetchPaymentTypeDP(): array { return [ + 'ALIPAY' => ['s-ali-xen2ybcovn56', 'https://api.unzer.com/v1/types/alipay/s-ali-xen2ybcovn56/'], + 'APPLEPAY' => ['s-apl-xen2ybcovn56', 'https://api.unzer.com/v1/types/appelpay/s-apl-xen2ybcovn56/'], + 'BANCONTACT' => ['s-bct-xen2ybcovn56', 'https://api.unzer.com/v1/types/bancontact/s-bct-xen2ybcovn56/'], 'CARD' => ['s-crd-xen2ybcovn56', 'https://api.unzer.com/v1/types/card/s-crd-xen2ybcovn56/'], + 'EPS' => ['s-eps-xen2ybcovn56', 'https://api.unzer.com/v1/types/eps/s-eps-xen2ybcovn56/'], 'GIROPAY' => ['s-gro-xen2ybcovn56', 'https://api.unzer.com/v1/types/giropay/s-gro-xen2ybcovn56/'], + 'HIRE_PURCHASE_DIRECT_DEBIT' => ['s-hdd-xen2ybcovn56', 'https://api.unzer.com/v1/types/hire-purchase-direct-debit/s-hdd-xen2ybcovn56/'], 'IDEAL' => ['s-idl-xen2ybcovn56', 'https://api.unzer.com/v1/types/ideal/s-idl-xen2ybcovn56/'], 'INVOICE' => ['s-ivc-xen2ybcovn56', 'https://api.unzer.com/v1/types/invoice/s-ivc-xen2ybcovn56/'], + 'INVOICE_FACTORING' => ['s-ivf-xen2ybcovn56', 'https://api.unzer.com/v1/types/wechatpay/s-ivf-xen2ybcovn56/'], 'INVOICE_GUARANTEED' => ['s-ivg-xen2ybcovn56', 'https://api.unzer.com/v1/types/invoice-guaranteed/s-ivg-xen2ybcovn56/'], 'INVOICE_SECURED' => ['s-ivs-xen2ybcovn56', 'https://api.unzer.com/v1/types/invoice-secured/s-ivs-xen2ybcovn56/'], - 'INVOICE_FACTORING' => ['s-ivf-xen2ybcovn56', 'https://api.unzer.com/v1/types/wechatpay/s-ivf-xen2ybcovn56/'], + 'Installment_SECURED' => ['s-ins-xen2ybcovn56', 'https://api.unzer.com/v1/types/installment-secured/s-ins-xen2ybcovn56/'], 'PAYPAL' => ['s-ppl-xen2ybcovn56', 'https://api.unzer.com/v1/types/paypal/s-ppl-xen2ybcovn56/'], + 'PIS' => ['s-pis-xen2ybcovn56', 'https://api.unzer.com/v1/types/pis/s-pis-xen2ybcovn56/'], 'PREPAYMENT' => ['s-ppy-xen2ybcovn56', 'https://api.unzer.com/v1/types/prepayment/s-ppy-xen2ybcovn56/'], 'PRZELEWY24' => ['s-p24-xen2ybcovn56', 'https://api.unzer.com/v1/types/przelewy24/s-p24-xen2ybcovn56/'], - 'SEPA_DIRECT_DEBIT_GUARANTEED' => ['s-ddg-xen2ybcovn56', 'https://api.unzer.com/v1/types/direct-debit-guaranteed/s-ddg-xen2ybcovn56/'], 'SEPA_DIRECT_DEBIT' => ['s-sdd-xen2ybcovn56', 'https://api.unzer.com/v1/types/direct-debit/s-sdd-xen2ybcovn56/'], + 'SEPA_DIRECT_DEBIT_GUARANTEED' => ['s-ddg-xen2ybcovn56', 'https://api.unzer.com/v1/types/direct-debit-guaranteed/s-ddg-xen2ybcovn56/'], 'SOFORT' => ['s-sft-xen2ybcovn56', 'https://api.unzer.com/v1/types/sofort/s-sft-xen2ybcovn56/'], - 'PIS' => ['s-pis-xen2ybcovn56', 'https://api.unzer.com/v1/types/pis/s-pis-xen2ybcovn56/'], - 'EPS' => ['s-eps-xen2ybcovn56', 'https://api.unzer.com/v1/types/eps/s-eps-xen2ybcovn56/'], - 'ALIPAY' => ['s-ali-xen2ybcovn56', 'https://api.unzer.com/v1/types/alipay/s-ali-xen2ybcovn56/'], - 'WECHATPAY' => ['s-wcp-xen2ybcovn56', 'https://api.unzer.com/v1/types/wechatpay/s-wcp-xen2ybcovn56/'], - 'HIRE_PURCHASE_DIRECT_DEBIT' => ['s-hdd-xen2ybcovn56', 'https://api.unzer.com/v1/types/hire-purchase-direct-debit/s-hdd-xen2ybcovn56/'], - 'Installment_SECURED' => ['s-ins-xen2ybcovn56', 'https://api.unzer.com/v1/types/installment-secured/s-ins-xen2ybcovn56/'], - 'BANCONTACT' => ['s-bct-xen2ybcovn56', 'https://api.unzer.com/v1/types/bancontact/s-bct-xen2ybcovn56/'] + 'WECHATPAY' => ['s-wcp-xen2ybcovn56', 'https://api.unzer.com/v1/types/wechatpay/s-wcp-xen2ybcovn56/'] ]; }