From 1a7b150b38d6e7212e909be9873aade4ab740b5d Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 29 Aug 2019 16:44:25 +0200 Subject: [PATCH 01/88] [cleanup] Remove obsolete comment. --- examples/_enableExamples.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/_enableExamples.php b/examples/_enableExamples.php index 44337ee5..03980683 100755 --- a/examples/_enableExamples.php +++ b/examples/_enableExamples.php @@ -39,8 +39,6 @@ * Default Values are: * Private key: s-priv-2a102ZMq3gV4I3zJ888J7RR6u75oqK3n * Public key: s-pub-2a10ifVINFAjpQJ9qW8jBe5OJPBx6Gxa - * - * Please keep in mind, */ define('HEIDELPAY_PHP_PAYMENT_API_PRIVATE_KEY', 's-priv-2a102ZMq3gV4I3zJ888J7RR6u75oqK3n'); define('HEIDELPAY_PHP_PAYMENT_API_PUBLIC_KEY', 's-pub-2a10ifVINFAjpQJ9qW8jBe5OJPBx6Gxa'); From b7ffae2d2e737580ef5ae36fcd3d89613217fb26 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 29 Aug 2019 17:08:43 +0200 Subject: [PATCH 02/88] [bugfix] (PHPLIB-228) Payment: Move cancel integration tests to dedicated file. --- src/Resources/Payment.php | 3 + test/integration/PaymentCancelTest.php | 109 +++++++++++++++++++++++++ test/integration/PaymentTest.php | 76 ----------------- 3 files changed, 112 insertions(+), 76 deletions(-) create mode 100644 test/integration/PaymentCancelTest.php diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index ff58a1f5..5fe0f9b4 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -637,6 +637,9 @@ public function getExternalId() */ public function cancel($amount = null): Cancellation { + + + list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); list($authCancel, $authException) = $this->cancelAuthorization($amount); diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php new file mode 100644 index 00000000..eb556eb6 --- /dev/null +++ b/test/integration/PaymentCancelTest.php @@ -0,0 +1,109 @@ + + * + * @package heidelpayPHP/test/integration + */ +namespace heidelpayPHP\test\integration; + +use heidelpayPHP\Constants\ApiResponseCodes; +use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\test\BasePaymentTest; +use RuntimeException; + +class PaymentCancelTest extends BasePaymentTest +{ + /** + * Verify full cancel on authorize throws exception if already canceled. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() + { + $authorization = $this->createCardAuthorization(); + $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); + $cancel = $fetchedPayment->getAuthorization()->cancel(); + $this->assertNotNull($cancel); + $this->assertEquals('s-cnl-1', $cancel->getId()); + $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); + + $this->expectException(HeidelpayApiException::class); + $this->expectExceptionCode(ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); + $fetchedPayment->cancel(); + } + + /** + * Verify partial cancel on authorize. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partialCancelOnAuthorizeShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); + $this->assertAmounts($fetchedPayment, 100.0, 0, 100.0, 0); + + $cancel = $fetchedPayment->cancel(10.0); + $this->assertNotNull($cancel); + $this->assertEquals('s-cnl-1', $cancel->getId()); + $this->assertEquals('10.0', $cancel->getAmount()); + $this->assertAmounts($fetchedPayment, 90.0, 0, 90.0, 0); + } + + /** + * Verify full cancel on charge. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnChargeShouldBePossible() + { + $charge = $this->createCharge(); + $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); + $fetchedCharge = $fetchedPayment->getCharge('s-chg-1'); + $cancellation = $fetchedCharge->cancel(); + $this->assertNotNull($cancellation); + } + + /** + * Verify partial cancel on charge. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partialCancelShouldBePossible() + { + $charge = $this->createCharge(); + $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); + $cancel = $fetchedPayment->getChargeByIndex(0)->cancel(10.0); + $this->assertNotNull($cancel); + } +} diff --git a/test/integration/PaymentTest.php b/test/integration/PaymentTest.php index 6bb61939..41261c3a 100755 --- a/test/integration/PaymentTest.php +++ b/test/integration/PaymentTest.php @@ -129,82 +129,6 @@ public function partialChargeAfterAuthorization() $this->assertEquals('10.0', $charge->getAmount()); } - /** - * Verify full cancel on authorize throws exception if already canceled. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() - { - $authorization = $this->createCardAuthorization(); - $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $cancel = $fetchedPayment->getAuthorization()->cancel(); - $this->assertNotNull($cancel); - $this->assertEquals('s-cnl-1', $cancel->getId()); - $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); - - $this->expectException(HeidelpayApiException::class); - $this->expectExceptionCode(ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); - $fetchedPayment->cancel(); - } - - /** - * Verify partial cancel on authorize. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function partialCancelOnAuthorizeShouldBePossible() - { - $authorization = $this->createCardAuthorization(); - $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $this->assertAmounts($fetchedPayment, 100.0, 0, 100.0, 0); - - $cancel = $fetchedPayment->cancel(10.0); - $this->assertNotNull($cancel); - $this->assertEquals('s-cnl-1', $cancel->getId()); - $this->assertEquals('10.0', $cancel->getAmount()); - $this->assertAmounts($fetchedPayment, 90.0, 0, 90.0, 0); - } - - /** - * Verify full cancel on charge. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function fullCancelOnChargeShouldBePossible() - { - $charge = $this->createCharge(); - $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); - $fetchedCharge = $fetchedPayment->getCharge('s-chg-1'); - $cancellation = $fetchedCharge->cancel(); - $this->assertNotNull($cancellation); - } - - /** - * Verify partial cancel on charge. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function partialCancelShouldBePossible() - { - $charge = $this->createCharge(); - $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); - $cancel = $fetchedPayment->getChargeByIndex(0)->cancel(10.0); - $this->assertNotNull($cancel); - } - /** * Verify authorization on payment. * From a6ee268d611fd6b34bc70562f7b59b6f2315311d Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 29 Aug 2019 17:20:37 +0200 Subject: [PATCH 03/88] [bugfix] (PHPLIB-228) Payment: Refactor tests for payment cancels with uncharged authorize. --- test/integration/PaymentCancelTest.php | 39 +++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index eb556eb6..d34cabcb 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -53,15 +53,39 @@ public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() $fetchedPayment->cancel(); } + /** + * Verify full cancel on authorize. + * Case 6 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnAuthorizeShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); + $this->assertAmounts($fetchedPayment, 100.0, 0, 100.0, 0); + + $cancel = $fetchedPayment->cancel(); + $this->assertNotNull($cancel); + $this->assertEquals('s-cnl-1', $cancel->getId()); + $this->assertEquals('100.0', $cancel->getAmount()); + $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); + $this->assertTrue($fetchedPayment->isCanceled()); + } + /** * Verify partial cancel on authorize. + * Case 7 * * @test * * @throws HeidelpayApiException * @throws RuntimeException */ - public function partialCancelOnAuthorizeShouldBePossible() + public function fullCancelOnPartCanceledAuthorizeShouldBePossible() { $authorization = $this->createCardAuthorization(); $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); @@ -72,6 +96,19 @@ public function partialCancelOnAuthorizeShouldBePossible() $this->assertEquals('s-cnl-1', $cancel->getId()); $this->assertEquals('10.0', $cancel->getAmount()); $this->assertAmounts($fetchedPayment, 90.0, 0, 90.0, 0); + + $secondCancel = $fetchedPayment->cancel(10.0); + $this->assertNotNull($secondCancel); + $this->assertEquals('s-cnl-2', $secondCancel->getId()); + $this->assertEquals('10.0', $secondCancel->getAmount()); + $this->assertAmounts($fetchedPayment, 80.0, 0, 80.0, 0); + + $thirdCancel = $fetchedPayment->cancel(); + $this->assertNotNull($thirdCancel); + $this->assertEquals('s-cnl-3', $thirdCancel->getId()); + $this->assertEquals('80.0', $thirdCancel->getAmount()); + $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); + $this->assertTrue($fetchedPayment->isCanceled()); } /** From 98584a41ab5aae3794849f7651862b0342cd2c7a Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 9 Sep 2019 15:35:11 +0200 Subject: [PATCH 04/88] [change] (PHPLIB-221) KeyPair: Refactor to use keypair/types/ path. --- src/Resources/Keypair.php | 90 +++++++++++++++++++++++++++-- test/integration/KeyTest.php | 2 +- test/unit/Resources/KeypairTest.php | 8 +-- 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 993c0b4e..88dacafe 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -32,8 +32,17 @@ class Keypair extends AbstractHeidelpayResource /** @var string $privateKey */ private $privateKey; - /** @var array $availablePaymentTypes */ - private $availablePaymentTypes = []; + /** @var array $paymentTypes */ + private $paymentTypes = []; + + /** @var string $secureLevel */ + private $secureLevel; + + /** @var string $alias */ + private $alias; + + /** @var bool $imageScanningEnabled */ + private $imageScanningEnabled; // @@ -72,17 +81,86 @@ protected function setPrivateKey(string $privateKey) /** * @return array */ - public function getAvailablePaymentTypes(): array + public function getPaymentTypes(): array { - return $this->availablePaymentTypes; + return $this->paymentTypes; } /** * @param array $paymentTypes */ - protected function setAvailablePaymentTypes(array $paymentTypes) + protected function setPaymentTypes(array $paymentTypes) + { + $this->paymentTypes = $paymentTypes; + } + + /** + * @return string + */ + public function getSecureLevel(): string + { + return $this->secureLevel; + } + + /** + * @param string $secureLevel + * + * @return Keypair + */ + public function setSecureLevel(string $secureLevel): Keypair + { + $this->secureLevel = $secureLevel; + return $this; + } + + /** + * @return string + */ + public function getAlias(): string + { + return $this->alias; + } + + /** + * @param string|null $alias + * + * @return Keypair + */ + public function setAlias($alias): Keypair + { + $this->alias = $alias; + return $this; + } + + /** + * @return bool + */ + public function isImageScanningEnabled(): bool + { + return $this->imageScanningEnabled; + } + + /** + * @param bool $imageScanningEnabled + * + * @return Keypair + */ + public function setImageScanningEnabled(bool $imageScanningEnabled): Keypair + { + $this->imageScanningEnabled = $imageScanningEnabled; + return $this; + } + + // + + // + + /** + * {@inheritDoc} + */ + protected function getResourcePath(): string { - $this->availablePaymentTypes = $paymentTypes; + return 'keypair/types'; } // diff --git a/test/integration/KeyTest.php b/test/integration/KeyTest.php index a8b99fa7..06e3198e 100755 --- a/test/integration/KeyTest.php +++ b/test/integration/KeyTest.php @@ -76,6 +76,6 @@ public function keypairShouldReturnExpectedValues() $keypair = $this->heidelpay->fetchKeypair(); $this->assertNotNull($keypair); $this->assertNotEmpty($keypair->getPublicKey()); - $this->assertNotEmpty($keypair->getAvailablePaymentTypes()); +// $this->assertNotEmpty($keypair->getPaymentTypes()); } } diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 41609064..d3678afb 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -44,8 +44,8 @@ public function anAuthorizationShouldBeUpdatedThroughResponseHandling() $this->assertNull($keypair->getPublicKey()); $this->assertNull($keypair->getPrivateKey()); /** @noinspection UnnecessaryAssertionInspection */ - $this->assertInternalType('array', $keypair->getAvailablePaymentTypes()); - $this->assertEmpty($keypair->getAvailablePaymentTypes()); + $this->assertInternalType('array', $keypair->getPaymentTypes()); + $this->assertEmpty($keypair->getPaymentTypes()); $paymentTypes = [ 'przelewy24', @@ -64,10 +64,10 @@ public function anAuthorizationShouldBeUpdatedThroughResponseHandling() $testResponse = new stdClass(); $testResponse->publicKey = 's-pub-1234'; $testResponse->privateKey = 's-priv-4321'; - $testResponse->availablePaymentTypes = $paymentTypes; + $testResponse->paymentTypes = $paymentTypes; $keypair->handleResponse($testResponse); - $this->assertArraySubset($paymentTypes, $keypair->getAvailablePaymentTypes()); + $this->assertArraySubset($paymentTypes, $keypair->getPaymentTypes()); $this->assertEquals('s-pub-1234', $keypair->getPublicKey()); $this->assertEquals('s-priv-4321', $keypair->getPrivateKey()); } From 4d75148e988bc5000c74a29c4fca08a3f5687768 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 9 Sep 2019 15:35:45 +0200 Subject: [PATCH 05/88] [change] (PHPLIB-221) KeyPair: Add test which is failing to remember to fix issue. --- test/integration/KeyTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/KeyTest.php b/test/integration/KeyTest.php index 06e3198e..f7174446 100755 --- a/test/integration/KeyTest.php +++ b/test/integration/KeyTest.php @@ -76,6 +76,6 @@ public function keypairShouldReturnExpectedValues() $keypair = $this->heidelpay->fetchKeypair(); $this->assertNotNull($keypair); $this->assertNotEmpty($keypair->getPublicKey()); -// $this->assertNotEmpty($keypair->getPaymentTypes()); + $this->assertNotEmpty($keypair->getPaymentTypes()); } } From 85558c713885728b9588871ea0983a91e9866d64 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 17 Sep 2019 17:08:26 +0200 Subject: [PATCH 06/88] [change] (PHPLIB-219) Prepayment: Add example. --- examples/Prepayment/Constants.php | 30 +++++++++ examples/Prepayment/Controller.php | 98 ++++++++++++++++++++++++++++++ examples/Prepayment/index.php | 56 +++++++++++++++++ examples/index.php | 12 ++++ 4 files changed, 196 insertions(+) create mode 100644 examples/Prepayment/Constants.php create mode 100644 examples/Prepayment/Controller.php create mode 100644 examples/Prepayment/index.php diff --git a/examples/Prepayment/Constants.php b/examples/Prepayment/Constants.php new file mode 100644 index 00000000..917dff7e --- /dev/null +++ b/examples/Prepayment/Constants.php @@ -0,0 +1,30 @@ + + * + * @package heidelpayPHP/examples + */ + +require_once __DIR__ . '/../Constants.php'; + +define('EXAMPLE_PATH', __DIR__); +define('EXAMPLE_URL', EXAMPLE_BASE_FOLDER . 'Prepayment'); +define('CONTROLLER_URL', EXAMPLE_URL . '/Controller.php'); diff --git a/examples/Prepayment/Controller.php b/examples/Prepayment/Controller.php new file mode 100644 index 00000000..b33ad4d4 --- /dev/null +++ b/examples/Prepayment/Controller.php @@ -0,0 +1,98 @@ + + * + * @package heidelpayPHP/examples + */ + +/** Require the constants of this example */ +require_once __DIR__ . '/Constants.php'; + +/** @noinspection PhpIncludeInspection */ +/** Require the composer autoloader file */ +require_once __DIR__ . '/../../../../autoload.php'; + +use heidelpayPHP\examples\ExampleDebugHandler; +use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Heidelpay; +use heidelpayPHP\Resources\CustomerFactory; +use heidelpayPHP\Resources\PaymentTypes\Prepayment; + +session_start(); +session_unset(); + +$clientMessage = 'Something went wrong. Please try again later.'; +$merchantMessage = 'Something went wrong. Please try again later.'; + +function redirect($url, $merchantMessage = '', $clientMessage = '') +{ + $_SESSION['merchantMessage'] = $merchantMessage; + $_SESSION['clientMessage'] = $clientMessage; + header('Location: ' . $url); + die(); +} + +// Catch API errors, write the message to your log and show the ClientMessage to the client. +try { + // Create a heidelpay object using your private key and register a debug handler if you want to. + $heidelpay = new Heidelpay(HEIDELPAY_PHP_PAYMENT_API_PRIVATE_KEY); + $heidelpay->setDebugMode(true)->setDebugHandler(new ExampleDebugHandler()); + + /** @var Prepayment $prepayment */ + $prepayment = $heidelpay->createPaymentType(new Prepayment()); + + $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); + $orderId = str_replace(['0.', ' '], '', microtime(false)); + + $transaction = $prepayment->charge(12.99, 'EUR', CONTROLLER_URL, $customer, $orderId); + + // You'll need to remember the shortId to show it on the success or failure page + $_SESSION['ShortId'] = $transaction->getShortId(); + + // Redirect to the success or failure page depending on the state of the transaction + $payment = $transaction->getPayment(); + + if ($payment->isPending()) { + // In case of authorization this is normal since you will later charge the payment. + // You can create the order with status pending payment and show a success page to the customer if you want. + + // In cases of redirection to an external service (e.g. 3D secure, PayPal, etc) it sometimes takes time for + // the payment to update it's status. In this case it might be pending at first and change to cancel or success later. + // Use the webhooks feature to stay informed about changes of the payment (e.g. cancel, success) + // then you can cancel the order later or mark it paid as soon as the event is triggered. + + // In any case, the payment is not done when the payment is pending and you should ship until it changes to success. + redirect(PENDING_URL); + } + // If the payment is neither success nor pending something went wrong. + // In this case do not create the order. + // Redirect to an error page in your shop and show an message if you want. + + // Check the result message of the transaction to find out what went wrong. + $merchantMessage = $transaction->getMessage()->getCustomer(); +} catch (HeidelpayApiException $e) { + $merchantMessage = $e->getMerchantMessage(); + $clientMessage = $e->getClientMessage(); +} catch (RuntimeException $e) { + $merchantMessage = $e->getMessage(); +} +redirect(FAILURE_URL, $merchantMessage, $clientMessage); diff --git a/examples/Prepayment/index.php b/examples/Prepayment/index.php new file mode 100644 index 00000000..b6739ec5 --- /dev/null +++ b/examples/Prepayment/index.php @@ -0,0 +1,56 @@ + + * + * @package heidelpayPHP/examples + */ + +/** Require the constants of this example */ +require_once __DIR__ . '/Constants.php'; + +/** @noinspection PhpIncludeInspection */ + +/** Require the composer autoloader file */ +require_once __DIR__ . '/../../../../autoload.php'; +?> + + + + + + + Heidelpay UI Examples + + + + + + + + + +
+ +
+ + + diff --git a/examples/index.php b/examples/index.php index 6cf810b0..8b47ce9f 100755 --- a/examples/index.php +++ b/examples/index.php @@ -140,6 +140,18 @@ Try +
+
+
+ Prepayment +
+
+
+
+
+ Try +
+
From 2d0c293d94e712609869a7479d97bc4bdec4f2e3 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 17 Sep 2019 17:16:09 +0200 Subject: [PATCH 07/88] [change] (PHPLIB-219) Prepayment: Update changelog and version. --- CHANGELOG.md | 6 ++++++ src/Heidelpay.php | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b98bbf1..d6cfcebe 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ 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.2.2.1][1.2.2.1] + +### Added +* An example for prepayment payment method. + ## [1.2.2.0][1.2.2.0] ### Fixed @@ -274,3 +279,4 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a [1.2.0.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.1.6.0..1.2.0.0 [1.2.1.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.0.0..1.2.1.0 [1.2.2.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.1.0..1.2.2.0 +[1.2.2.1]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.2.0..1.2.2.1 diff --git a/src/Heidelpay.php b/src/Heidelpay.php index 7ba4c7fa..50f9473b 100755 --- a/src/Heidelpay.php +++ b/src/Heidelpay.php @@ -56,7 +56,7 @@ class Heidelpay implements HeidelpayParentInterface const BASE_URL = 'api.heidelpay.com'; const API_VERSION = 'v1'; const SDK_TYPE = 'HeidelpayPHP'; - const SDK_VERSION = '1.2.2.0'; + const SDK_VERSION = '1.2.2.1'; /** @var string $key */ private $key; From 2554d7f04c5981ee2614c4e7f10a3f2dd1b6e6f0 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 17 Sep 2019 17:37:12 +0200 Subject: [PATCH 08/88] [change] (PHPLIB-220) Invoice: Add example. --- examples/Invoice/Constants.php | 30 ++++++++++ examples/Invoice/Controller.php | 99 +++++++++++++++++++++++++++++++++ examples/Invoice/index.php | 56 +++++++++++++++++++ examples/index.php | 12 ++++ 4 files changed, 197 insertions(+) create mode 100644 examples/Invoice/Constants.php create mode 100644 examples/Invoice/Controller.php create mode 100644 examples/Invoice/index.php diff --git a/examples/Invoice/Constants.php b/examples/Invoice/Constants.php new file mode 100644 index 00000000..82c782a9 --- /dev/null +++ b/examples/Invoice/Constants.php @@ -0,0 +1,30 @@ + + * + * @package heidelpayPHP/examples + */ + +require_once __DIR__ . '/../Constants.php'; + +define('EXAMPLE_PATH', __DIR__); +define('EXAMPLE_URL', EXAMPLE_BASE_FOLDER . 'Invoice'); +define('CONTROLLER_URL', EXAMPLE_URL . '/Controller.php'); diff --git a/examples/Invoice/Controller.php b/examples/Invoice/Controller.php new file mode 100644 index 00000000..b4dfb3e6 --- /dev/null +++ b/examples/Invoice/Controller.php @@ -0,0 +1,99 @@ + + * + * @package heidelpayPHP/examples + */ + +/** Require the constants of this example */ +require_once __DIR__ . '/Constants.php'; + +/** @noinspection PhpIncludeInspection */ +/** Require the composer autoloader file */ +require_once __DIR__ . '/../../../../autoload.php'; + +use heidelpayPHP\examples\ExampleDebugHandler; +use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Heidelpay; +use heidelpayPHP\Resources\CustomerFactory; +use heidelpayPHP\Resources\PaymentTypes\Invoice; +use heidelpayPHP\Resources\PaymentTypes\Prepayment; + +session_start(); +session_unset(); + +$clientMessage = 'Something went wrong. Please try again later.'; +$merchantMessage = 'Something went wrong. Please try again later.'; + +function redirect($url, $merchantMessage = '', $clientMessage = '') +{ + $_SESSION['merchantMessage'] = $merchantMessage; + $_SESSION['clientMessage'] = $clientMessage; + header('Location: ' . $url); + die(); +} + +// Catch API errors, write the message to your log and show the ClientMessage to the client. +try { + // Create a heidelpay object using your private key and register a debug handler if you want to. + $heidelpay = new Heidelpay(HEIDELPAY_PHP_PAYMENT_API_PRIVATE_KEY); + $heidelpay->setDebugMode(true)->setDebugHandler(new ExampleDebugHandler()); + + /** @var Invoice $invoice */ + $invoice = $heidelpay->createPaymentType(new Invoice()); + + $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); + $orderId = str_replace(['0.', ' '], '', microtime(false)); + + $transaction = $invoice->charge(12.99, 'EUR', CONTROLLER_URL, $customer, $orderId); + + // You'll need to remember the shortId to show it on the success or failure page + $_SESSION['ShortId'] = $transaction->getShortId(); + + // Redirect to the success or failure page depending on the state of the transaction + $payment = $transaction->getPayment(); + + if ($payment->isPending()) { + // In case of authorization this is normal since you will later charge the payment. + // You can create the order with status pending payment and show a success page to the customer if you want. + + // In cases of redirection to an external service (e.g. 3D secure, PayPal, etc) it sometimes takes time for + // the payment to update it's status. In this case it might be pending at first and change to cancel or success later. + // Use the webhooks feature to stay informed about changes of the payment (e.g. cancel, success) + // then you can cancel the order later or mark it paid as soon as the event is triggered. + + // In any case, the payment is not done when the payment is pending and you should ship until it changes to success. + redirect(PENDING_URL); + } + // If the payment is neither success nor pending something went wrong. + // In this case do not create the order. + // Redirect to an error page in your shop and show an message if you want. + + // Check the result message of the transaction to find out what went wrong. + $merchantMessage = $transaction->getMessage()->getCustomer(); +} catch (HeidelpayApiException $e) { + $merchantMessage = $e->getMerchantMessage(); + $clientMessage = $e->getClientMessage(); +} catch (RuntimeException $e) { + $merchantMessage = $e->getMessage(); +} +redirect(FAILURE_URL, $merchantMessage, $clientMessage); diff --git a/examples/Invoice/index.php b/examples/Invoice/index.php new file mode 100644 index 00000000..b6739ec5 --- /dev/null +++ b/examples/Invoice/index.php @@ -0,0 +1,56 @@ + + * + * @package heidelpayPHP/examples + */ + +/** Require the constants of this example */ +require_once __DIR__ . '/Constants.php'; + +/** @noinspection PhpIncludeInspection */ + +/** Require the composer autoloader file */ +require_once __DIR__ . '/../../../../autoload.php'; +?> + + + + + + + Heidelpay UI Examples + + + + + + + + + +
+ +
+ + + diff --git a/examples/index.php b/examples/index.php index 8b47ce9f..dd1359ed 100755 --- a/examples/index.php +++ b/examples/index.php @@ -152,6 +152,18 @@ Try
+
+
+
+ Invoice +
+
+
+
+
+ Try +
+
From 042d3a83ddacca90b878fc368caa4b55760b2735 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 17 Sep 2019 17:37:56 +0200 Subject: [PATCH 09/88] [change] (PHPLIB-220) Invoice: Update changelog. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6cfcebe..0d759c55 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ## [1.2.2.1][1.2.2.1] ### Added -* An example for prepayment payment method. +* An example for `prepayment` payment method. +* An example for `invoice` payment method. ## [1.2.2.0][1.2.2.0] From 3ad788e570e12b2d97eef29086553fb9378f377f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 18 Sep 2019 17:04:34 +0200 Subject: [PATCH 10/88] [change] (PHPLIB-236) HeidelpayApiException: Fixed a problem with the parameters in the exception. --- CHANGELOG.md | 6 ++++ src/Exceptions/HeidelpayApiException.php | 6 ++-- .../Exceptions/HeidelpayApiExceptionTest.php | 34 +++++++++---------- test/unit/Services/HttpServiceTest.php | 8 ++--- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d759c55..7bd7a95a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a * An example for `prepayment` payment method. * An example for `invoice` payment method. +### Fixed +* Problem with HeidelpayApiException. + +### Changed +* Refactored and extended unit tests. + ## [1.2.2.0][1.2.2.0] ### Fixed diff --git a/src/Exceptions/HeidelpayApiException.php b/src/Exceptions/HeidelpayApiException.php index 38f6e07b..9eb52118 100755 --- a/src/Exceptions/HeidelpayApiException.php +++ b/src/Exceptions/HeidelpayApiException.php @@ -45,13 +45,13 @@ class HeidelpayApiException extends Exception * @param string $code * @param string $errorId */ - public function __construct($merchantMessage = '', $clientMessage = '', $code = 'No error code provided', $errorId = 'No error id provided') + public function __construct($merchantMessage = '', $clientMessage = '', $code = null, $errorId = null) { $merchantMessage = empty($merchantMessage) ? static::MESSAGE : $merchantMessage; $this->clientMessage = empty($clientMessage) ? static::CLIENT_MESSAGE : $clientMessage; parent::__construct($merchantMessage); - $this->code = $code; - $this->errorId = $errorId; + $this->code = empty($code) ? 'No error code provided' : $code; + $this->errorId = empty($errorId) ? 'No error id provided' : $errorId; } /** diff --git a/test/unit/Exceptions/HeidelpayApiExceptionTest.php b/test/unit/Exceptions/HeidelpayApiExceptionTest.php index 40b31a31..1c1279ff 100755 --- a/test/unit/Exceptions/HeidelpayApiExceptionTest.php +++ b/test/unit/Exceptions/HeidelpayApiExceptionTest.php @@ -42,6 +42,7 @@ public function heidelpayApiExceptionShouldReturnDefaultDataWhenNoneIsSet() $exception = new HeidelpayApiException(); $this->assertEquals(HeidelpayApiException::CLIENT_MESSAGE, $exception->getClientMessage()); $this->assertEquals(HeidelpayApiException::MESSAGE, $exception->getMerchantMessage()); + $this->assertEquals('No error id provided', $exception->getErrorId()); $this->assertEquals('No error code provided', $exception->getCode()); } @@ -58,9 +59,10 @@ public function heidelpayApiExceptionShouldReturnDefaultDataWhenNoneIsSet() */ public function heidelpayApiExceptionShouldReturnTheGivenData(array $testData, array $expected) { - $exception = new HeidelpayApiException($testData['message'], $testData['client_message'], $testData['code']); + $exception = new HeidelpayApiException($testData['message'], $testData['clientMessage'], $testData['code'], $testData['errorId']); $this->assertEquals($expected['message'], $exception->getMerchantMessage()); - $this->assertEquals($expected['client_message'], $exception->getClientMessage()); + $this->assertEquals($expected['clientMessage'], $exception->getClientMessage()); + $this->assertEquals($expected['errorId'], $exception->getErrorId()); $this->assertEquals($expected['code'], $exception->getCode()); } @@ -73,28 +75,24 @@ public function exceptionDataProvider(): array { return [ 'default' => [ - 'testData' => ['message' => null, 'client_message' => null, 'code' => null], - 'expected' => [ - 'message' => HeidelpayApiException::MESSAGE, - 'client_message' => HeidelpayApiException::CLIENT_MESSAGE, - 'code' => '' - ] + 'testData' => ['message' => null, 'clientMessage' => null, 'code' => null, 'errorId' => null], + 'expected' => ['message' => HeidelpayApiException::MESSAGE, 'clientMessage' => HeidelpayApiException::CLIENT_MESSAGE, 'code' => 'No error code provided', 'errorId' => 'No error id provided'] ], 'message' => [ - 'testData' => ['message' => 'myMessage', 'client_message' => null, 'code' => null], - 'expected' => [ - 'message' => 'myMessage', - 'client_message' => HeidelpayApiException::CLIENT_MESSAGE, - 'code' => '' - ] + 'testData' => ['message' => 'myMessage', 'clientMessage' => null, 'code' => null, 'errorId' => ''], + 'expected' => ['message' => 'myMessage', 'clientMessage' => HeidelpayApiException::CLIENT_MESSAGE, 'code' => 'No error code provided', 'errorId' => 'No error id provided'] ], 'clientMessage' => [ - 'testData' => ['message' => 'myMessage', 'client_message' => 'myClientMessage', 'code' => null], - 'expected' => ['message' => 'myMessage', 'client_message' => 'myClientMessage', 'code' => null] + 'testData' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => null, 'errorId' => null], + 'expected' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => 'No error code provided', 'errorId' => 'No error id provided'] ], 'code' => [ - 'testData' => ['message' => 'myMessage', 'client_message' => 'myClientMessage', 'code' => 'myCode'], - 'expected' => ['message' => 'myMessage', 'client_message' => 'myClientMessage', 'code' => 'myCode'] + 'testData' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => 'myCode', 'errorId' => null], + 'expected' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => 'myCode', 'errorId' => 'No error id provided'] + ], + 'errorId' => [ + 'testData' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => 'myCode', 'errorId' => 'myErrorId'], + 'expected' => ['message' => 'myMessage', 'clientMessage' => 'myClientMessage', 'code' => 'myCode', 'errorId' => 'myErrorId'] ] ]; } diff --git a/test/unit/Services/HttpServiceTest.php b/test/unit/Services/HttpServiceTest.php index c10749e1..a1704661 100755 --- a/test/unit/Services/HttpServiceTest.php +++ b/test/unit/Services/HttpServiceTest.php @@ -280,7 +280,7 @@ public function handleErrorsShouldThrowExceptionIfResponseCodeIsGoE400($response $this->expectException(HeidelpayApiException::class); $this->expectExceptionMessage('The payment api returned an error!'); - $this->expectExceptionCode(''); + $this->expectExceptionCode('No error code provided'); /** @var HttpService $httpServiceMock*/ $httpServiceMock->send('/my/uri/123', $resource); @@ -324,7 +324,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() } catch (HeidelpayApiException $e) { $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); - $this->assertEmpty($e->getCode()); + $this->assertEquals('No error code provided', $e->getCode()); } try { @@ -333,7 +333,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() } catch (HeidelpayApiException $e) { $this->assertEquals('This is an error message for the merchant!', $e->getMerchantMessage()); $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); - $this->assertEmpty($e->getCode()); + $this->assertEquals('No error code provided', $e->getCode()); } try { @@ -342,7 +342,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() } catch (HeidelpayApiException $e) { $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); $this->assertEquals('This is an error message for the customer!', $e->getClientMessage()); - $this->assertEmpty($e->getCode()); + $this->assertEquals('No error code provided', $e->getCode()); } try { From 6a9527a27a7c022b03ee6b6f8db44239c8d3212f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 18 Sep 2019 17:14:51 +0200 Subject: [PATCH 11/88] [change] (PHPLIB-236) Unit tests: Added missing tests. --- test/unit/Resources/EmbeddedResources/BasketItemTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/unit/Resources/EmbeddedResources/BasketItemTest.php b/test/unit/Resources/EmbeddedResources/BasketItemTest.php index 02577610..6fb4c11a 100755 --- a/test/unit/Resources/EmbeddedResources/BasketItemTest.php +++ b/test/unit/Resources/EmbeddedResources/BasketItemTest.php @@ -51,6 +51,7 @@ public function settersAndGettersShouldWork() $this->assertEquals('', $basketItem->getUnit()); $this->assertEquals('', $basketItem->getTitle()); $this->assertEquals('', $basketItem->getSubTitle()); + $this->assertEquals('', $basketItem->getTitle()); $this->assertNull($basketItem->getImageUrl()); $basketItem->setQuantity(2); @@ -65,6 +66,7 @@ public function settersAndGettersShouldWork() $basketItem->setTitle('myTitle'); $basketItem->setSubTitle('mySubTitle'); $basketItem->setImageUrl('https://my.image.url'); + $basketItem->setType('myType'); $this->assertEquals(2, $basketItem->getQuantity()); $this->assertEquals(9876, $basketItem->getAmountDiscount()); @@ -77,6 +79,7 @@ public function settersAndGettersShouldWork() $this->assertEquals('myUnit', $basketItem->getUnit()); $this->assertEquals('myTitle', $basketItem->getTitle()); $this->assertEquals('mySubTitle', $basketItem->getSubTitle()); + $this->assertEquals('myType', $basketItem->getType()); $this->assertEquals('https://my.image.url', $basketItem->getImageUrl()); } } From bba654a6546d63a217cfe65fb92a2e957ad00ba7 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 18 Sep 2019 17:29:36 +0200 Subject: [PATCH 12/88] [change] (PHPLIB-236) Unit tests: Verify removing restricted symbols from company info fields. --- test/unit/Resources/CustomerTest.php | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/unit/Resources/CustomerTest.php b/test/unit/Resources/CustomerTest.php index b2064a34..efb8253c 100755 --- a/test/unit/Resources/CustomerTest.php +++ b/test/unit/Resources/CustomerTest.php @@ -191,6 +191,27 @@ public function gettersAndSettersOfCompanyInfoShouldWork() $this->assertSame($companyInfo, $customer->getCompanyInfo()); } + /** + * Verify removeRestrictedSymbols method works. + * + * @test + * + * @dataProvider removeRestrictedSymbolsMethodShouldReturnTheCorrectValueDP + * + * @throws Exception + * + * @param mixed $value + * @param mixed $expected + */ + public function removeRestrictedSymbolsMethodShouldReturnTheCorrectValue($value, $expected) + { + $companyInfo = new CompanyInfo(); + $this->assertNull($companyInfo->getFunction()); + + $companyInfo->setFunction($value); + $this->assertEquals($expected, $companyInfo->getFunction()); + } + /** * Verify salutation only uses the given values. * @@ -250,4 +271,25 @@ static function ($customer) use ($heidelpay) { /** @var ResourceService $resourceSrvMock */ $resourceSrvMock->fetchCustomerByExtCustomerId('myCustomerId'); } + + // + + /** + * DataProvider for removeRestrictedSymbolsMethodShouldReturnTheCorrectValue. + */ + public function removeRestrictedSymbolsMethodShouldReturnTheCorrectValueDP(): array + { + return [ + 'null' => [null, null], + 'empty' => ['', ''], + 'blank' => [' ', ' '], + 'string' => ['MyTestString', 'MyTestString'], + '<' => ['<', ''], + '>' => ['>', ''], + '' => ['', 'test'], + 'Text1' => [' >>>This >>>text >>>should << } From 279c51929e4975d7afe5fa550cb7897941c2bb4b Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 18 Sep 2019 17:33:50 +0200 Subject: [PATCH 13/88] [change] (PHPLIB-236) Unit tests: Add missing tests. --- .../Resources/TransactionTypes/AuthorizationTest.php | 9 ++++++--- test/unit/Resources/TransactionTypes/PayoutTest.php | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/test/unit/Resources/TransactionTypes/AuthorizationTest.php b/test/unit/Resources/TransactionTypes/AuthorizationTest.php index f03fa8de..feffe4d7 100755 --- a/test/unit/Resources/TransactionTypes/AuthorizationTest.php +++ b/test/unit/Resources/TransactionTypes/AuthorizationTest.php @@ -2,7 +2,7 @@ /** * This class defines unit tests to verify functionality of the Authorization transaction type. * - * Copyright (C) 2018 heidelpay GmbH + * Copyright (C) 2019 heidelpay GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,19 +54,22 @@ public function gettersAndSettersShouldWorkProperly() $this->assertNull($authorization->getCurrency()); $this->assertNull($authorization->getReturnUrl()); $this->assertNull($authorization->isCard3ds()); + $this->assertNull($authorization->getPaymentReference()); $authorization = new Authorization(123.4, 'myCurrency', 'https://my-return-url.test'); - $authorization->setCard3ds(true); + $authorization->setCard3ds(true)->setPaymentReference('my payment reference'); $this->assertEquals(123.4, $authorization->getAmount()); $this->assertEquals('myCurrency', $authorization->getCurrency()); $this->assertEquals('https://my-return-url.test', $authorization->getReturnUrl()); + $this->assertEquals('my payment reference', $authorization->getPaymentReference()); $this->assertTrue($authorization->isCard3ds()); $authorization->setAmount(567.8)->setCurrency('myNewCurrency')->setReturnUrl('https://another-return-url.test'); - $authorization->setCard3ds(false); + $authorization->setCard3ds(false)->setPaymentReference('different payment reference'); $this->assertEquals(567.8, $authorization->getAmount()); $this->assertEquals('myNewCurrency', $authorization->getCurrency()); $this->assertEquals('https://another-return-url.test', $authorization->getReturnUrl()); + $this->assertEquals('different payment reference', $authorization->getPaymentReference()); $this->assertFalse($authorization->isCard3ds()); } diff --git a/test/unit/Resources/TransactionTypes/PayoutTest.php b/test/unit/Resources/TransactionTypes/PayoutTest.php index 3fa655a0..c144c785 100644 --- a/test/unit/Resources/TransactionTypes/PayoutTest.php +++ b/test/unit/Resources/TransactionTypes/PayoutTest.php @@ -49,16 +49,21 @@ public function gettersAndSettersShouldWorkProperly() $this->assertNull($payout->getAmount()); $this->assertNull($payout->getCurrency()); $this->assertNull($payout->getReturnUrl()); + $this->assertNull($payout->getPaymentReference()); $payout = new Payout(123.4, 'myCurrency', 'https://my-return-url.test'); + $payout->setPaymentReference('my payment reference'); $this->assertEquals(123.4, $payout->getAmount()); $this->assertEquals('myCurrency', $payout->getCurrency()); $this->assertEquals('https://my-return-url.test', $payout->getReturnUrl()); + $this->assertEquals('my payment reference', $payout->getPaymentReference()); $payout->setAmount(567.8)->setCurrency('myNewCurrency')->setReturnUrl('https://another-return-url.test'); + $payout->setPaymentReference('different payment reference'); $this->assertEquals(567.8, $payout->getAmount()); $this->assertEquals('myNewCurrency', $payout->getCurrency()); $this->assertEquals('https://another-return-url.test', $payout->getReturnUrl()); + $this->assertEquals('different payment reference', $payout->getPaymentReference()); } /** From d4ac99a7c304844c40f3364f8c4790e5e89303bb Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 19 Sep 2019 16:57:55 +0200 Subject: [PATCH 14/88] [change] (PHPLIB-236) Unit tests: Add missing tests. --- test/unit/Resources/BasketTest.php | 17 ++++++++ .../unit/Resources/DummyHeidelpayResource.php | 3 ++ test/unit/Resources/PaymentTest.php | 39 ++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/test/unit/Resources/BasketTest.php b/test/unit/Resources/BasketTest.php index ea16dc8d..97e31158 100755 --- a/test/unit/Resources/BasketTest.php +++ b/test/unit/Resources/BasketTest.php @@ -168,4 +168,21 @@ public function referenceIdShouldBeAutomaticallySetToTheArrayIndexIfItIsNotSet() $this->assertEquals('0', $basketItem3->getBasketItemReferenceId()); $this->assertEquals('1', $basketItem4->getBasketItemReferenceId()); } + + /** + * Verify amount total is replaced by amount total gross. + * + * @test + * + * @throws Exception + */ + public function amountTotalSetterGetterAccessAmountTotalGross() + { + $basket = new Basket(); + $this->assertEquals($basket->getAmountTotalGross(), $basket->getAmountTotal()); + $basket->setAmountTotalGross(123.45); + $this->assertEquals($basket->getAmountTotalGross(), $basket->getAmountTotal()); + $basket->setAmountTotal(45.321); + $this->assertEquals($basket->getAmountTotalGross(), $basket->getAmountTotal()); + } } diff --git a/test/unit/Resources/DummyHeidelpayResource.php b/test/unit/Resources/DummyHeidelpayResource.php index 6e67a44a..a8125574 100755 --- a/test/unit/Resources/DummyHeidelpayResource.php +++ b/test/unit/Resources/DummyHeidelpayResource.php @@ -42,6 +42,9 @@ public function __construct(Customer $customer) $this->customer = $customer; } + /** + * {@inheritDoc} + */ public function getLinkedResources(): array { return ['customer' => $this->customer]; diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index ecc81841..45b42471 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1649,8 +1649,7 @@ public function setMetaDataShouldSetParentResourceAndCreateMetaDataObject() { $metadata = (new Metadata())->addMetadata('myData', 'myValue'); - $resourceSrvMock = $this->getMockBuilder(ResourceService::class)->setMethods(['create']) - ->disableOriginalConstructor()->getMock(); + $resourceSrvMock = $this->getMockBuilder(ResourceService::class)->setMethods(['create'])->disableOriginalConstructor()->getMock(); $resourceSrvMock->expects($this->once())->method('create')->with($metadata); /** @var ResourceService $resourceSrvMock */ @@ -1669,6 +1668,42 @@ public function setMetaDataShouldSetParentResourceAndCreateMetaDataObject() $this->assertSame($heidelpay, $metadata->getParentResource()); } + /** + * Verify setMetadata will not set the metadata property if it is not of type metadata. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + * @throws ReflectionException + */ + public function metadataMustBeOfTypeMetadata() + { + $metadata = new Metadata(); + $resourceSrvMock = $this->getMockBuilder(ResourceService::class)->setMethods(['create'])->disableOriginalConstructor()->getMock(); + $resourceSrvMock->expects($this->once())->method('create')->with($metadata); + /** @var ResourceService $resourceSrvMock */ + $heidelpay = (new Heidelpay('s-priv-1234'))->setResourceService($resourceSrvMock); + + // when + $payment = new Payment($heidelpay); + + // then + $this->assertNull($payment->getMetadata()); + + // when + $payment->setMetadata('test'); + + // then + $this->assertNull($payment->getMetadata()); + + // when + $payment->setMetadata($metadata); + + // then + $this->assertSame($metadata, $payment->getMetadata()); + } + /** * Verify set Basket will call create if the given basket object does not exist yet. * From 7b5b2e16ad24a5bbdaa28ed73bf62594a7a5f88e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 19 Sep 2019 17:05:43 +0200 Subject: [PATCH 15/88] [change] (PHPLIB-236) Unit tests: Add missing tests. --- src/Resources/AbstractHeidelpayResource.php | 2 +- test/unit/Resources/PaymentTest.php | 30 +++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Resources/AbstractHeidelpayResource.php b/src/Resources/AbstractHeidelpayResource.php index 909b6987..e0c5c488 100755 --- a/src/Resources/AbstractHeidelpayResource.php +++ b/src/Resources/AbstractHeidelpayResource.php @@ -248,7 +248,7 @@ private function getResourceService(): ResourceService } /** - * Fetches the Resource if necessary. + * Fetches the Resource if it has not been fetched yet and the id is set. * * @param AbstractHeidelpayResource $resource * diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index 45b42471..685a551b 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -788,15 +788,35 @@ public function handleResponseShouldFetchAndUpdatePaymentTypeIfTheIdIsSet() */ public function handleResponseShouldFetchAndUpdateMetadataIfTheIdIsSet() { - $payment = (new Payment())->setId('myPaymentId'); - - $resourceServiceMock = $this->getMockBuilder(ResourceService::class) - ->disableOriginalConstructor()->setMethods(['fetchMetadata'])->getMock(); + $resourceServiceMock = $this->getMockBuilder(ResourceService::class)->disableOriginalConstructor()->setMethods(['fetchMetadata'])->getMock(); $resourceServiceMock->expects($this->once())->method('fetchMetadata')->with('MetadataId'); + /** @var ResourceService $resourceServiceMock */ + $heidelpayObj = (new Heidelpay('s-priv-123'))->setResourceService($resourceServiceMock); + $payment = (new Payment())->setId('myPaymentId')->setParentResource($heidelpayObj); + + $response = new stdClass(); + $response->resources = new stdClass(); + $response->resources->metadataId = 'MetadataId'; + $payment->handleResponse($response); + } + /** + * Verify handleResponse updates metadata. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + * @throws ReflectionException + */ + public function handleResponseShouldGetMetadataIfUnfetchedMetadataObjectWithIdIsGiven() + { + $metadata = (new Metadata())->setId('MetadataId'); + $resourceServiceMock = $this->getMockBuilder(ResourceService::class)->disableOriginalConstructor()->setMethods(['getResource'])->getMock(); + $resourceServiceMock->expects($this->once())->method('getResource')->with($metadata); /** @var ResourceService $resourceServiceMock */ $heidelpayObj = (new Heidelpay('s-priv-123'))->setResourceService($resourceServiceMock); - $payment->setParentResource($heidelpayObj); + $payment = (new Payment())->setId('myPaymentId')->setParentResource($heidelpayObj)->setMetadata($metadata); $response = new stdClass(); $response->resources = new stdClass(); From 448c331310f173027b24da9e722f92123b37fb65 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 19 Sep 2019 17:11:47 +0200 Subject: [PATCH 16/88] [change] (PHPLIB-236) Unit tests: Add missing tests for error id. --- test/unit/Services/HttpServiceTest.php | 35 ++++++++++++++++++++------ 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/test/unit/Services/HttpServiceTest.php b/test/unit/Services/HttpServiceTest.php index a1704661..84f13a53 100755 --- a/test/unit/Services/HttpServiceTest.php +++ b/test/unit/Services/HttpServiceTest.php @@ -297,7 +297,6 @@ public function handleErrorsShouldThrowExceptionIfResponseCodeIsGoE400($response public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() { $httpServiceMock = $this->getMockBuilder(HttpService::class)->setMethods(['getAdapter'])->getMock(); - $adapterMock = $this->getMockBuilder(CurlAdapter::class)->setMethods( ['init', 'setUserAgent', 'setHeaders', 'execute', 'getResponseCode', 'close'] )->getMock(); @@ -306,13 +305,10 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $secondResponse = '{"errors": [{"merchantMessage": "This is an error message for the merchant!"}]}'; $thirdResponse = '{"errors": [{"customerMessage": "This is an error message for the customer!"}]}'; $fourthResponse = '{"errors": [{"code": "This is the error code!"}]}'; + $fifthResponse = '{"errors": [{"code": "This is the error code!"}], "id": "s-err-1234"}'; + $sixthResponse = '{"errors": [{"code": "This is the error code!"}], "id": "s-rre-1234"}'; - $adapterMock->method('execute')->willReturnOnConsecutiveCalls( - $firstResponse, - $secondResponse, - $thirdResponse, - $fourthResponse - ); + $adapterMock->method('execute')->willReturnOnConsecutiveCalls($firstResponse, $secondResponse, $thirdResponse, $fourthResponse, $fifthResponse, $sixthResponse); $httpServiceMock->method('getAdapter')->willReturn($adapterMock); $resource = (new DummyResource())->setParentResource(new Heidelpay('s-priv-MyTestKey')); @@ -325,6 +321,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); $this->assertEquals('No error code provided', $e->getCode()); + $this->assertEquals('No error id provided', $e->getErrorId()); } try { @@ -334,6 +331,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $this->assertEquals('This is an error message for the merchant!', $e->getMerchantMessage()); $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); $this->assertEquals('No error code provided', $e->getCode()); + $this->assertEquals('No error id provided', $e->getErrorId()); } try { @@ -343,6 +341,7 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); $this->assertEquals('This is an error message for the customer!', $e->getClientMessage()); $this->assertEquals('No error code provided', $e->getCode()); + $this->assertEquals('No error id provided', $e->getErrorId()); } try { @@ -352,7 +351,29 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); $this->assertEquals('This is the error code!', $e->getCode()); + $this->assertEquals('No error id provided', $e->getErrorId()); + } + + try { + $httpServiceMock->send('/my/uri/123', $resource); + $this->assertTrue(false, 'The fifth exception should have been thrown!'); + } catch (HeidelpayApiException $e) { + $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); + $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); + $this->assertEquals('This is the error code!', $e->getCode()); + $this->assertEquals('s-err-1234', $e->getErrorId()); } + + try { + $httpServiceMock->send('/my/uri/123', $resource); + $this->assertTrue(false, 'The sixth exception should have been thrown!'); + } catch (HeidelpayApiException $e) { + $this->assertEquals('The payment api returned an error!', $e->getMerchantMessage()); + $this->assertEquals('The payment api returned an error!', $e->getClientMessage()); + $this->assertEquals('This is the error code!', $e->getCode()); + $this->assertEquals('No error id provided', $e->getErrorId()); + } + } /** From 7521a484b334f06db57ef2cb0dcfed4f3f917a82 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 19 Sep 2019 17:13:56 +0200 Subject: [PATCH 17/88] [change] (PHPLIB-236) Unit tests: Add missing tests for error id. --- test/unit/Services/HttpServiceTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/Services/HttpServiceTest.php b/test/unit/Services/HttpServiceTest.php index 84f13a53..cd012d15 100755 --- a/test/unit/Services/HttpServiceTest.php +++ b/test/unit/Services/HttpServiceTest.php @@ -373,7 +373,6 @@ public function handleErrorsShouldThrowExceptionIfResponseContainsErrorField() $this->assertEquals('This is the error code!', $e->getCode()); $this->assertEquals('No error id provided', $e->getErrorId()); } - } /** From f9181ad507231febd36457d8f026902e15f0904c Mon Sep 17 00:00:00 2001 From: Simon Gabriel Date: Mon, 7 Oct 2019 16:29:53 +0200 Subject: [PATCH 18/88] Update examples/Invoice/index.php Co-Authored-By: David Owusu <33735090+Ryouzanpaku@users.noreply.github.com> --- examples/Invoice/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Invoice/index.php b/examples/Invoice/index.php index b6739ec5..7081e6fc 100644 --- a/examples/Invoice/index.php +++ b/examples/Invoice/index.php @@ -1,6 +1,6 @@ Date: Mon, 7 Oct 2019 16:32:07 +0200 Subject: [PATCH 19/88] [change] (PHPLIB-220) Apply changes from code review. --- examples/Invoice/Controller.php | 1 - examples/Invoice/index.php | 1 - examples/Prepayment/index.php | 1 - 3 files changed, 3 deletions(-) diff --git a/examples/Invoice/Controller.php b/examples/Invoice/Controller.php index b4dfb3e6..8a2aaafe 100644 --- a/examples/Invoice/Controller.php +++ b/examples/Invoice/Controller.php @@ -36,7 +36,6 @@ use heidelpayPHP\Heidelpay; use heidelpayPHP\Resources\CustomerFactory; use heidelpayPHP\Resources\PaymentTypes\Invoice; -use heidelpayPHP\Resources\PaymentTypes\Prepayment; session_start(); session_unset(); diff --git a/examples/Invoice/index.php b/examples/Invoice/index.php index 7081e6fc..d3c1a749 100644 --- a/examples/Invoice/index.php +++ b/examples/Invoice/index.php @@ -43,7 +43,6 @@ integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"> - diff --git a/examples/Prepayment/index.php b/examples/Prepayment/index.php index b6739ec5..dedf71df 100644 --- a/examples/Prepayment/index.php +++ b/examples/Prepayment/index.php @@ -43,7 +43,6 @@ integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"> - From cc67c9b0d72039cde1ca3742e9a57ac088831c05 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 08:41:48 +0200 Subject: [PATCH 20/88] [change] (PHPLIB-236) Apply change requests from code review. --- test/unit/Resources/EmbeddedResources/BasketItemTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/Resources/EmbeddedResources/BasketItemTest.php b/test/unit/Resources/EmbeddedResources/BasketItemTest.php index 6fb4c11a..80fa2d17 100755 --- a/test/unit/Resources/EmbeddedResources/BasketItemTest.php +++ b/test/unit/Resources/EmbeddedResources/BasketItemTest.php @@ -51,7 +51,6 @@ public function settersAndGettersShouldWork() $this->assertEquals('', $basketItem->getUnit()); $this->assertEquals('', $basketItem->getTitle()); $this->assertEquals('', $basketItem->getSubTitle()); - $this->assertEquals('', $basketItem->getTitle()); $this->assertNull($basketItem->getImageUrl()); $basketItem->setQuantity(2); From 290c1363682349c06dba20c259a0e1862cc9f5f9 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 08:43:33 +0200 Subject: [PATCH 21/88] [change] Fix PIS name in examples. --- examples/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/index.php b/examples/index.php index dd1359ed..3b6cfd4c 100755 --- a/examples/index.php +++ b/examples/index.php @@ -245,7 +245,7 @@
- Flexipay (PIS) + Flexipay direct (PIS)
From c1891add3c6b26ab749b568e818dae62c907881a Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 09:32:42 +0200 Subject: [PATCH 22/88] [change] (PHPLIB-221) Reset keypair class. --- src/Resources/Keypair.php | 90 ++--------------------------- test/integration/KeyTest.php | 2 +- test/unit/Resources/KeypairTest.php | 8 +-- 3 files changed, 11 insertions(+), 89 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 88dacafe..993c0b4e 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -32,17 +32,8 @@ class Keypair extends AbstractHeidelpayResource /** @var string $privateKey */ private $privateKey; - /** @var array $paymentTypes */ - private $paymentTypes = []; - - /** @var string $secureLevel */ - private $secureLevel; - - /** @var string $alias */ - private $alias; - - /** @var bool $imageScanningEnabled */ - private $imageScanningEnabled; + /** @var array $availablePaymentTypes */ + private $availablePaymentTypes = []; // @@ -81,86 +72,17 @@ protected function setPrivateKey(string $privateKey) /** * @return array */ - public function getPaymentTypes(): array + public function getAvailablePaymentTypes(): array { - return $this->paymentTypes; + return $this->availablePaymentTypes; } /** * @param array $paymentTypes */ - protected function setPaymentTypes(array $paymentTypes) - { - $this->paymentTypes = $paymentTypes; - } - - /** - * @return string - */ - public function getSecureLevel(): string - { - return $this->secureLevel; - } - - /** - * @param string $secureLevel - * - * @return Keypair - */ - public function setSecureLevel(string $secureLevel): Keypair - { - $this->secureLevel = $secureLevel; - return $this; - } - - /** - * @return string - */ - public function getAlias(): string - { - return $this->alias; - } - - /** - * @param string|null $alias - * - * @return Keypair - */ - public function setAlias($alias): Keypair - { - $this->alias = $alias; - return $this; - } - - /** - * @return bool - */ - public function isImageScanningEnabled(): bool - { - return $this->imageScanningEnabled; - } - - /** - * @param bool $imageScanningEnabled - * - * @return Keypair - */ - public function setImageScanningEnabled(bool $imageScanningEnabled): Keypair - { - $this->imageScanningEnabled = $imageScanningEnabled; - return $this; - } - - // - - // - - /** - * {@inheritDoc} - */ - protected function getResourcePath(): string + protected function setAvailablePaymentTypes(array $paymentTypes) { - return 'keypair/types'; + $this->availablePaymentTypes = $paymentTypes; } // diff --git a/test/integration/KeyTest.php b/test/integration/KeyTest.php index f7174446..a8b99fa7 100755 --- a/test/integration/KeyTest.php +++ b/test/integration/KeyTest.php @@ -76,6 +76,6 @@ public function keypairShouldReturnExpectedValues() $keypair = $this->heidelpay->fetchKeypair(); $this->assertNotNull($keypair); $this->assertNotEmpty($keypair->getPublicKey()); - $this->assertNotEmpty($keypair->getPaymentTypes()); + $this->assertNotEmpty($keypair->getAvailablePaymentTypes()); } } diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index d3678afb..41609064 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -44,8 +44,8 @@ public function anAuthorizationShouldBeUpdatedThroughResponseHandling() $this->assertNull($keypair->getPublicKey()); $this->assertNull($keypair->getPrivateKey()); /** @noinspection UnnecessaryAssertionInspection */ - $this->assertInternalType('array', $keypair->getPaymentTypes()); - $this->assertEmpty($keypair->getPaymentTypes()); + $this->assertInternalType('array', $keypair->getAvailablePaymentTypes()); + $this->assertEmpty($keypair->getAvailablePaymentTypes()); $paymentTypes = [ 'przelewy24', @@ -64,10 +64,10 @@ public function anAuthorizationShouldBeUpdatedThroughResponseHandling() $testResponse = new stdClass(); $testResponse->publicKey = 's-pub-1234'; $testResponse->privateKey = 's-priv-4321'; - $testResponse->paymentTypes = $paymentTypes; + $testResponse->availablePaymentTypes = $paymentTypes; $keypair->handleResponse($testResponse); - $this->assertArraySubset($paymentTypes, $keypair->getPaymentTypes()); + $this->assertArraySubset($paymentTypes, $keypair->getAvailablePaymentTypes()); $this->assertEquals('s-pub-1234', $keypair->getPublicKey()); $this->assertEquals('s-priv-4321', $keypair->getPrivateKey()); } From b5cb180a8b39253c3735ad409a2552bf60ce7935 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 11:33:52 +0200 Subject: [PATCH 23/88] [change] (PHPLIB-221) Add detailed keypair fetch. --- src/Heidelpay.php | 6 +- src/Resources/Keypair.php | 190 +++++++++++++++++- src/Services/ResourceService.php | 6 +- .../{KeyTest.php => KeypairTest.php} | 29 ++- test/unit/Resources/KeypairTest.php | 82 +++++++- 5 files changed, 298 insertions(+), 15 deletions(-) rename test/integration/{KeyTest.php => KeypairTest.php} (66%) mode change 100755 => 100644 diff --git a/src/Heidelpay.php b/src/Heidelpay.php index 50f9473b..6d3339c5 100755 --- a/src/Heidelpay.php +++ b/src/Heidelpay.php @@ -396,14 +396,16 @@ public function fetchPaymentByOrderId($orderId): Payment /** * Read and return the public key and configured payment types from API. * + * @param bool $detailed If this flag is set detailed information are fetched. + * * @return Keypair The Keypair object composed of the data returned by the API. * * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. */ - public function fetchKeypair(): AbstractHeidelpayResource + public function fetchKeypair($detailed = false): AbstractHeidelpayResource { - return $this->resourceService->fetchKeypair(); + return $this->resourceService->fetchKeypair($detailed); } // diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 993c0b4e..bc956bdf 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -24,6 +24,9 @@ */ namespace heidelpayPHP\Resources; +use heidelpayPHP\Adapter\HttpAdapterInterface; +use stdClass; + class Keypair extends AbstractHeidelpayResource { /** @var string $publicKey */ @@ -32,8 +35,26 @@ class Keypair extends AbstractHeidelpayResource /** @var string $privateKey */ private $privateKey; - /** @var array $availablePaymentTypes */ - private $availablePaymentTypes = []; + /** @var bool $detailed */ + private $detailed = false; + + /** @var array $paymentTypes */ + private $paymentTypes = []; + + /** @var string $secureLevel */ + private $secureLevel; + + /** @var string $alias */ + private $alias; + + /** @var string $merchantName */ + private $merchantName; + + /** @var bool $imageScanningEnabled */ + private $imageScanningEnabled; + + /** @var string $merchantAddress */ + private $merchantAddress; // @@ -69,12 +90,28 @@ protected function setPrivateKey(string $privateKey) $this->privateKey = $privateKey; } + /** + * @return array + */ + public function getPaymentTypes(): array + { + return $this->paymentTypes; + } + + /** + * @param array $paymentTypes + */ + protected function setPaymentTypes(array $paymentTypes) + { + $this->paymentTypes = $paymentTypes; + } + /** * @return array */ public function getAvailablePaymentTypes(): array { - return $this->availablePaymentTypes; + return $this->getPaymentTypes(); } /** @@ -82,7 +119,152 @@ public function getAvailablePaymentTypes(): array */ protected function setAvailablePaymentTypes(array $paymentTypes) { - $this->availablePaymentTypes = $paymentTypes; + $this->setPaymentTypes($paymentTypes); + } + + /** + * @return string + */ + public function getSecureLevel(): string + { + return $this->secureLevel ?: ''; + } + + /** + * @param string|null $secureLevel + * + * @return Keypair + */ + public function setSecureLevel($secureLevel): Keypair + { + $this->secureLevel = $secureLevel; + return $this; + } + + /** + * @return string + */ + public function getAlias(): string + { + return $this->alias ?: ''; + } + + /** + * @param string|null $alias + * + * @return Keypair + */ + public function setAlias($alias): Keypair + { + $this->alias = $alias; + return $this; + } + + /** + * @return string + */ + public function getMerchantName(): string + { + return $this->merchantName ?: ''; + } + + /** + * @param string|null $merchantName + * + * @return Keypair + */ + public function setMerchantName($merchantName): Keypair + { + $this->merchantName = $merchantName; + return $this; + } + + /** + * @return string + */ + public function getMerchantAddress(): string + { + return $this->merchantAddress ?: ''; + } + + /** + * @param string|null $merchantAddress + * + * @return Keypair + */ + public function setMerchantAddress($merchantAddress): Keypair + { + $this->merchantAddress = $merchantAddress; + return $this; + } + + /** + * @return bool + */ + public function isImageScanningEnabled(): bool + { + return $this->imageScanningEnabled; + } + + /** + * @param bool $imageScanningEnabled + * + * @return Keypair + */ + public function setImageScanningEnabled(bool $imageScanningEnabled): Keypair + { + $this->imageScanningEnabled = $imageScanningEnabled; + return $this; + } + + /** + * @return bool + */ + public function isDetailed(): bool + { + return $this->detailed; + } + + /** + * @param bool $detailed + * + * @return Keypair + */ + public function setDetailed(bool $detailed): Keypair + { + $this->detailed = $detailed; + return $this; + } + + // + + // + + /** + * @inheritDoc + */ + public function handleResponse(stdClass $response, $method = HttpAdapterInterface::REQUEST_GET) + { + parent::handleResponse($response, $method); + + $paymentTypes = []; + if (isset($response->paymentTypes)) { + $paymentTypes = $response->paymentTypes; + } elseif (isset($response->availablePaymentTypes)) { + $paymentTypes = $response->availablePaymentTypes; + } + + foreach ($paymentTypes as $paymentType) { + $this->paymentTypes[] = $paymentType; + } + } + + /** + * @inheritDoc + */ + protected function getResourcePath(): string + { + return parent::getResourcePath() . ($this->isDetailed() ? '/types' : ''); } // diff --git a/src/Services/ResourceService.php b/src/Services/ResourceService.php index b3f35c00..ae4c532a 100755 --- a/src/Services/ResourceService.php +++ b/src/Services/ResourceService.php @@ -417,14 +417,16 @@ public function fetchPaymentByOrderId($orderId): Payment /** * Fetch public key and configured payment types from API. * + * @param bool $detailed If this flag is set detailed information are fetched. + * * @return Keypair * * @throws HeidelpayApiException * @throws RuntimeException */ - public function fetchKeypair(): AbstractHeidelpayResource + public function fetchKeypair($detailed = false): AbstractHeidelpayResource { - $keyPair = (new Keypair())->setParentResource($this->heidelpay); + $keyPair = (new Keypair())->setParentResource($this->heidelpay)->setDetailed($detailed); return $this->fetch($keyPair); } diff --git a/test/integration/KeyTest.php b/test/integration/KeypairTest.php old mode 100755 new mode 100644 similarity index 66% rename from test/integration/KeyTest.php rename to test/integration/KeypairTest.php index a8b99fa7..826284ba --- a/test/integration/KeyTest.php +++ b/test/integration/KeypairTest.php @@ -29,7 +29,7 @@ use heidelpayPHP\test\BasePaymentTest; use RuntimeException; -class KeyTest extends BasePaymentTest +class KeypairTest extends BasePaymentTest { /** * Validate valid keys are accepted. @@ -64,7 +64,7 @@ public function invalidKeysShouldResultInException($key) } /** - * Verify key pair command can be performed. + * Verify key pair config can be fetched. * * @test * @@ -76,6 +76,31 @@ public function keypairShouldReturnExpectedValues() $keypair = $this->heidelpay->fetchKeypair(); $this->assertNotNull($keypair); $this->assertNotEmpty($keypair->getPublicKey()); + $this->assertNotEmpty($keypair->getPrivateKey()); $this->assertNotEmpty($keypair->getAvailablePaymentTypes()); + $this->assertNotEmpty($keypair->getMerchantAddress()); + $this->assertNotEmpty($keypair->getMerchantName()); + $this->assertNotEmpty($keypair->getSecureLevel()); + } + + /** + * Verify key pair config can be fetched with details. + * + * @test + * + * @throws RuntimeException + * @throws HeidelpayApiException + */ + public function keypairShouldBeFetchableWithDetails() + { + $keypair = $this->heidelpay->fetchKeypair(true); + $this->assertNotNull($keypair); + $this->assertNotEmpty($keypair->getPublicKey()); + $this->assertNotEmpty($keypair->getPrivateKey()); + $this->assertNotEmpty($keypair->getPaymentTypes()); + $this->assertNotEmpty($keypair->getAlias()); + $this->assertNotEmpty($keypair->getMerchantAddress()); + $this->assertNotEmpty($keypair->getMerchantName()); + $this->assertNotEmpty($keypair->getSecureLevel()); } } diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 41609064..8c8212df 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -32,20 +32,21 @@ class KeypairTest extends BaseUnitTest { /** - * Verify that an Authorization can be updated on handle response. + * Verify that a key pair can be updated on handle response. * * @test * * @throws RuntimeException */ - public function anAuthorizationShouldBeUpdatedThroughResponseHandling() + public function aKeypairShouldBeUpdatedThroughResponseHandling() { $keypair = new Keypair(); $this->assertNull($keypair->getPublicKey()); $this->assertNull($keypair->getPrivateKey()); /** @noinspection UnnecessaryAssertionInspection */ - $this->assertInternalType('array', $keypair->getAvailablePaymentTypes()); - $this->assertEmpty($keypair->getAvailablePaymentTypes()); + $this->assertInternalType('array', $keypair->getPaymentTypes()); + $this->assertEmpty($keypair->getPaymentTypes()); + $this->assertEquals($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); $paymentTypes = [ 'przelewy24', @@ -67,8 +68,79 @@ public function anAuthorizationShouldBeUpdatedThroughResponseHandling() $testResponse->availablePaymentTypes = $paymentTypes; $keypair->handleResponse($testResponse); - $this->assertArraySubset($paymentTypes, $keypair->getAvailablePaymentTypes()); + $this->assertArraySubset($paymentTypes, $keypair->getPaymentTypes()); $this->assertEquals('s-pub-1234', $keypair->getPublicKey()); $this->assertEquals('s-priv-4321', $keypair->getPrivateKey()); } + + /** + * Verify that a key pair can be updated with details on handle response. + * + * @test + * + * @throws RuntimeException + */ + public function aKeypairShouldBeUpdatedWithDetailsThroughResponseHandling() + { + $keypair = new Keypair(); + $this->assertNull($keypair->getPublicKey()); + $this->assertNull($keypair->getPrivateKey()); + $this->assertEmpty($keypair->getPaymentTypes()); + $this->assertSame($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); + $this->assertEmpty($keypair->getSecureLevel()); + $this->assertEmpty($keypair->getMerchantName()); + $this->assertEmpty($keypair->getMerchantAddress()); + $this->assertEmpty($keypair->getAlias()); + + $paymentTypes = [ + (object) [ + 'supports' => [ + (object) [ + 'brands' => ['JCB', 'VISAELECTRON', 'MAESTRO', 'VISA', 'MASTER'], + 'countries' => [], + 'channel' => '31HA07BC819430D3495C56BC18C55622', + 'currency' => ['CHF', 'CNY', 'JPY', 'USD', 'GBP', 'EUR'] + ] + ], + 'type' => 'card', + 'allowCustomerTypes' => 'B2C', + 'allowCreditTransaction' => true, + '3ds' => true + ], + (object) [ + 'supports' => [ + (object) [ + 'brands' => ['CUP', 'SOLO', 'CARTEBLEUE', 'VISAELECTRON', 'MAESTRO', 'AMEX', 'VISA', 'MASTER'], + 'countries' => [], + 'channel' => '31HA07BC819430D3495C7C9D07B1A922', + 'currency' => ['MGA', 'USD', 'GBP', 'EUR'] + ] + ], + 'type' => 'card', + 'allowCustomerTypes' => 'B2C', + 'allowCreditTransaction' => true, + '3ds' => false + ] + ]; + + $testResponse = (object) [ + 'publicKey' => 's-pub-1234', + 'privateKey' => 's-priv-4321', + 'secureLevel' => 'SAQ-D', + 'alias' => 'Readme.io user', + 'merchantName' => 'Heidelpay GmbH', + 'merchantAddress' => 'Vangerowstraße 18, 69115 Heidelberg', + 'paymentTypes' => $paymentTypes + ]; + + $keypair->handleResponse($testResponse); + $this->assertEquals($paymentTypes, $keypair->getPaymentTypes()); + $this->assertSame($keypair->getAvailablePaymentTypes(), $keypair->getPaymentTypes()); + $this->assertEquals('s-pub-1234', $keypair->getPublicKey()); + $this->assertEquals('s-priv-4321', $keypair->getPrivateKey()); + $this->assertEquals('SAQ-D', $keypair->getSecureLevel()); + $this->assertEquals('Readme.io user', $keypair->getAlias()); + $this->assertEquals('Heidelpay GmbH', $keypair->getMerchantName()); + $this->assertEquals('Vangerowstraße 18, 69115 Heidelberg', $keypair->getMerchantAddress()); + } } From d50a80f31307e24db9d473f9378ba1ca9efcdc7a Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 11:34:47 +0200 Subject: [PATCH 24/88] [change] (PHPLIB-221) Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d759c55..3f1bc869 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Added * An example for `prepayment` payment method. * An example for `invoice` payment method. +* Detailed `keypair` fetch. ## [1.2.2.0][1.2.2.0] From bd8c5acf9a94abbf1d1e94af901d6c8f1a44abf7 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 13:44:32 +0200 Subject: [PATCH 25/88] [change] (PHPLIB-221) Keypair: remove unused parameter. --- src/Resources/Keypair.php | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index bc956bdf..fcac9650 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -50,9 +50,6 @@ class Keypair extends AbstractHeidelpayResource /** @var string $merchantName */ private $merchantName; - /** @var bool $imageScanningEnabled */ - private $imageScanningEnabled; - /** @var string $merchantAddress */ private $merchantAddress; @@ -198,25 +195,6 @@ public function setMerchantAddress($merchantAddress): Keypair return $this; } - /** - * @return bool - */ - public function isImageScanningEnabled(): bool - { - return $this->imageScanningEnabled; - } - - /** - * @param bool $imageScanningEnabled - * - * @return Keypair - */ - public function setImageScanningEnabled(bool $imageScanningEnabled): Keypair - { - $this->imageScanningEnabled = $imageScanningEnabled; - return $this; - } - /** * @return bool */ From 5d14d2ad8baf4b789c0323bcf42f3978d01f8c85 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 13:45:02 +0200 Subject: [PATCH 26/88] [change] (PHPLIB-221) Keypair: Restrict access to setters. --- src/Resources/Keypair.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index fcac9650..f1757c88 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -132,7 +132,7 @@ public function getSecureLevel(): string * * @return Keypair */ - public function setSecureLevel($secureLevel): Keypair + protected function setSecureLevel($secureLevel): Keypair { $this->secureLevel = $secureLevel; return $this; @@ -151,7 +151,7 @@ public function getAlias(): string * * @return Keypair */ - public function setAlias($alias): Keypair + protected function setAlias($alias): Keypair { $this->alias = $alias; return $this; @@ -170,7 +170,7 @@ public function getMerchantName(): string * * @return Keypair */ - public function setMerchantName($merchantName): Keypair + protected function setMerchantName($merchantName): Keypair { $this->merchantName = $merchantName; return $this; @@ -189,7 +189,7 @@ public function getMerchantAddress(): string * * @return Keypair */ - public function setMerchantAddress($merchantAddress): Keypair + protected function setMerchantAddress($merchantAddress): Keypair { $this->merchantAddress = $merchantAddress; return $this; From 83bd496f56d9598c268761e2ab68b8ca96bd4fee Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 13:45:16 +0200 Subject: [PATCH 27/88] [change] (PHPLIB-221) Keypair: Refactor unit tests. --- test/unit/Resources/KeypairTest.php | 42 +++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 8c8212df..1321ad90 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -26,11 +26,39 @@ use heidelpayPHP\Resources\Keypair; use heidelpayPHP\test\BaseUnitTest; +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\Exception; use RuntimeException; use stdClass; class KeypairTest extends BaseUnitTest { + /** + * Verify getters and setters work properly. + * + * @test + * @throws AssertionFailedError + * @throws Exception + */ + public function gettersAndSettersWorkAsExpected() + { + $keypair = new Keypair(); + $this->assertFalse($keypair->isDetailed()); + $this->assertNull($keypair->getPublicKey()); + $this->assertNull($keypair->getPrivateKey()); + $this->assertEmpty($keypair->getPaymentTypes()); + $this->assertSame($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); + $this->assertEquals('', $keypair->getSecureLevel()); + $this->assertEquals('', $keypair->getMerchantName()); + $this->assertEquals('', $keypair->getMerchantAddress()); + $this->assertEquals('', $keypair->getAlias()); + $this->assertFalse($keypair->isDetailed()); + + $keypair->setDetailed(true); + + $this->assertTrue($keypair->isDetailed()); + } + /** * Verify that a key pair can be updated on handle response. * @@ -41,12 +69,6 @@ class KeypairTest extends BaseUnitTest public function aKeypairShouldBeUpdatedThroughResponseHandling() { $keypair = new Keypair(); - $this->assertNull($keypair->getPublicKey()); - $this->assertNull($keypair->getPrivateKey()); - /** @noinspection UnnecessaryAssertionInspection */ - $this->assertInternalType('array', $keypair->getPaymentTypes()); - $this->assertEmpty($keypair->getPaymentTypes()); - $this->assertEquals($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); $paymentTypes = [ 'przelewy24', @@ -83,14 +105,6 @@ public function aKeypairShouldBeUpdatedThroughResponseHandling() public function aKeypairShouldBeUpdatedWithDetailsThroughResponseHandling() { $keypair = new Keypair(); - $this->assertNull($keypair->getPublicKey()); - $this->assertNull($keypair->getPrivateKey()); - $this->assertEmpty($keypair->getPaymentTypes()); - $this->assertSame($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); - $this->assertEmpty($keypair->getSecureLevel()); - $this->assertEmpty($keypair->getMerchantName()); - $this->assertEmpty($keypair->getMerchantAddress()); - $this->assertEmpty($keypair->getAlias()); $paymentTypes = [ (object) [ From bc967e81e6f8bb88bfb604194d1e842834401d48 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 13:46:10 +0200 Subject: [PATCH 28/88] [change] (PHPLIB-221) Keypair: Fix style issue. --- test/unit/Resources/KeypairTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 1321ad90..2c6c0b2e 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -37,6 +37,7 @@ class KeypairTest extends BaseUnitTest * Verify getters and setters work properly. * * @test + * * @throws AssertionFailedError * @throws Exception */ From a3547bf491674256975e9c4aac12fe8e5f6f7103 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 14:16:52 +0200 Subject: [PATCH 29/88] [change] (PHPLIB-228) Remove blank lines. --- src/Resources/Payment.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 4eac928d..3766cb04 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -637,9 +637,6 @@ public function getExternalId() */ public function cancel($amount = null): Cancellation { - - - list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); list($authCancel, $authException) = $this->cancelAuthorization($amount); From 250c2d0ce249d31fc1f4e758a43ad291fc283ddc Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 14:19:30 +0200 Subject: [PATCH 30/88] [change] (PHPLIB-228) Cancel: Add test for cancel case 1. --- test/integration/PaymentCancelTest.php | 38 ++++++++++++++------------ 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index d34cabcb..504619c9 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -53,6 +53,27 @@ public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() $fetchedPayment->cancel(); } + /** + * Verify full cancel on charge. + * PHPLIB-228 Case 1 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnChargeShouldBePossible() + { + $charge = $this->createCharge(); + $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); + $fetchedCharge = $fetchedPayment->getCharge('s-chg-1'); + $cancellation = $fetchedCharge->cancel(); + $this->assertNotNull($cancellation); + $this->assertTrue($cancellation->getPayment()->isCanceled()); + $this->assertArraySubset([$cancellation], $fetchedPayment->getCancellations()); + $this->assertEquals($fetchedCharge->getAmount(), $cancellation->getAmount()); + } + /** * Verify full cancel on authorize. * Case 6 @@ -111,23 +132,6 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertTrue($fetchedPayment->isCanceled()); } - /** - * Verify full cancel on charge. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function fullCancelOnChargeShouldBePossible() - { - $charge = $this->createCharge(); - $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); - $fetchedCharge = $fetchedPayment->getCharge('s-chg-1'); - $cancellation = $fetchedCharge->cancel(); - $this->assertNotNull($cancellation); - } - /** * Verify partial cancel on charge. * From 3fa34e2d25e7a02767134e97e6afdfdbf4d18a94 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 14:26:11 +0200 Subject: [PATCH 31/88] [change] (PHPLIB-228) Cancel: Add amount to create charge method. --- test/BasePaymentTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/BasePaymentTest.php b/test/BasePaymentTest.php index cc618612..f4d4bf87 100755 --- a/test/BasePaymentTest.php +++ b/test/BasePaymentTest.php @@ -238,15 +238,16 @@ public function createPaypalAuthorization(): Authorization /** * Creates and returns a Charge object with the API which can be used in test methods. * + * @param float $amount * @return Charge * - * @throws RuntimeException * @throws HeidelpayApiException + * @throws RuntimeException */ - public function createCharge(): Charge + public function createCharge($amount = 100.0): Charge { $card = $this->heidelpay->createPaymentType(new SepaDirectDebit('DE89370400440532013000')); - return $this->heidelpay->charge(100.0, 'EUR', $card, self::RETURN_URL); + return $this->heidelpay->charge($amount, 'EUR', $card, self::RETURN_URL); } /** From c0231c6714e41d4662f564d241bf576d61fcfea9 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 15:01:53 +0200 Subject: [PATCH 32/88] [change] (PHPLIB-228) Cancel: Add test for cancel case 3. --- test/BasePaymentTest.php | 1 + test/integration/PaymentCancelTest.php | 51 +++++++++++++++++--------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/test/BasePaymentTest.php b/test/BasePaymentTest.php index f4d4bf87..5189f8cc 100755 --- a/test/BasePaymentTest.php +++ b/test/BasePaymentTest.php @@ -239,6 +239,7 @@ public function createPaypalAuthorization(): Authorization * Creates and returns a Charge object with the API which can be used in test methods. * * @param float $amount + * * @return Charge * * @throws HeidelpayApiException diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 504619c9..c57a7797 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -55,7 +55,7 @@ public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() /** * Verify full cancel on charge. - * PHPLIB-228 Case 1 + * PHPLIB-228 - Case 1 * * @test * @@ -74,6 +74,39 @@ public function fullCancelOnChargeShouldBePossible() $this->assertEquals($fetchedCharge->getAmount(), $cancellation->getAmount()); } + /** + * Verify partial cancel on charge. + * PHPLIB-228 - Case 3 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partialCancelOnSingleChargeShouldBePossible() + { + $charge = $this->createCharge(222.33); + $this->assertEquals(222.33, $charge->getAmount()); + + $payment = $charge->getPayment(); + $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); + $this->assertTrue($payment->isCompleted()); + + $cancel = $charge->cancel(123.12); + $this->assertEquals(123.12, $cancel->getAmount()); + + $this->heidelpay->fetchPayment($payment); + $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); + $this->assertTrue($payment->isCompleted()); + + $cancel = $charge->cancel(99.21); + $this->assertEquals(99.21, $cancel->getAmount()); + + $this->heidelpay->fetchPayment($payment); + $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); + $this->assertTrue($payment->isCanceled()); + } + /** * Verify full cancel on authorize. * Case 6 @@ -131,20 +164,4 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); $this->assertTrue($fetchedPayment->isCanceled()); } - - /** - * Verify partial cancel on charge. - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function partialCancelShouldBePossible() - { - $charge = $this->createCharge(); - $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); - $cancel = $fetchedPayment->getChargeByIndex(0)->cancel(10.0); - $this->assertNotNull($cancel); - } } From 8825ac7ec6f691fd605a7a114de58e157a47709f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 15:02:34 +0200 Subject: [PATCH 33/88] [change] (PHPLIB-228) Cancel: Small changes,. --- test/integration/PaymentCancelTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index c57a7797..c3f808e4 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -109,7 +109,7 @@ public function partialCancelOnSingleChargeShouldBePossible() /** * Verify full cancel on authorize. - * Case 6 + * PHPLIB-228 - Case 6 * * @test * @@ -132,7 +132,7 @@ public function fullCancelOnAuthorizeShouldBePossible() /** * Verify partial cancel on authorize. - * Case 7 + * PHPLIB-228 - Case 7 * * @test * From 942f098bb04fd23306530a9027b2401940cc6479 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 15:45:34 +0200 Subject: [PATCH 34/88] [change] (PHPLIB-228) Cancel: Add cancel case 2. --- test/BasePaymentTest.php | 7 ++-- test/integration/PaymentCancelTest.php | 54 +++++++++++++++++++++----- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/test/BasePaymentTest.php b/test/BasePaymentTest.php index 5189f8cc..e4f8ad9b 100755 --- a/test/BasePaymentTest.php +++ b/test/BasePaymentTest.php @@ -205,16 +205,17 @@ protected function createCardObject(): Card /** * Creates and returns an Authorization object with the API which can be used in test methods. * + * @param float $amount * @return Authorization * - * @throws RuntimeException * @throws HeidelpayApiException + * @throws RuntimeException */ - public function createCardAuthorization(): Authorization + public function createCardAuthorization($amount = 100.0): Authorization { $card = $this->heidelpay->createPaymentType($this->createCardObject()); $orderId = microtime(true); - $authorization = $this->heidelpay->authorize(100.0, 'EUR', $card, self::RETURN_URL, null, $orderId, null, null, false); + $authorization = $this->heidelpay->authorize($amount, 'EUR', $card, self::RETURN_URL, null, $orderId, null, null, false); return $authorization; } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index c3f808e4..e3394df5 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -26,6 +26,7 @@ use heidelpayPHP\Constants\ApiResponseCodes; use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Resources\TransactionTypes\Cancellation; use heidelpayPHP\test\BasePaymentTest; use RuntimeException; @@ -42,15 +43,15 @@ class PaymentCancelTest extends BasePaymentTest public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() { $authorization = $this->createCardAuthorization(); - $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $cancel = $fetchedPayment->getAuthorization()->cancel(); + $payment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); + $cancel = $payment->cancel(); $this->assertNotNull($cancel); $this->assertEquals('s-cnl-1', $cancel->getId()); $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); $this->expectException(HeidelpayApiException::class); $this->expectExceptionCode(ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); - $fetchedPayment->cancel(); + $payment->cancel(); } /** @@ -64,14 +65,47 @@ public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() */ public function fullCancelOnChargeShouldBePossible() { - $charge = $this->createCharge(); - $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPayment()->getId()); - $fetchedCharge = $fetchedPayment->getCharge('s-chg-1'); - $cancellation = $fetchedCharge->cancel(); - $this->assertNotNull($cancellation); + $charge = $this->createCharge(123.44); + $payment = $charge->getPayment(); + $cancellation = $payment->cancel(); $this->assertTrue($cancellation->getPayment()->isCanceled()); - $this->assertArraySubset([$cancellation], $fetchedPayment->getCancellations()); - $this->assertEquals($fetchedCharge->getAmount(), $cancellation->getAmount()); + $this->assertArraySubset([$cancellation], $payment->getCancellations()); + $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + } + + /** + * Verify full cancel on multiple charges. + * PHPLIB-228 - Case 2 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossible() + { + $authorization = $this->createCardAuthorization(123.44); + $payment = $authorization->getPayment(); + + $charge1 = $payment->charge(100.44); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0); + $this->assertArraySubset([$charge1], $payment->getCharges()); + + $charge2 = $payment->charge(23.00); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); + $this->assertArraySubset([$charge1, $charge2], $payment->getCharges()); + + $payment->cancel(); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); + $cancellationTotal = 0.0; + foreach ($payment->getCancellations() as $cancellation) { + /** @var Cancellation $cancellation */ + $cancellationTotal += $cancellation->getAmount(); + } + $this->assertEquals($authorization->getAmount(), $cancellationTotal); } /** From f03bfe5fc40713f1c4766f65ffe044d0f940546c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 16:42:48 +0200 Subject: [PATCH 35/88] [refactor] (PHPLIB-228) Cancel: Refactor payment cancel method to handle identified cases. --- src/Resources/Payment.php | 62 +++++++++++++++++++++----- test/BasePaymentTest.php | 1 + test/integration/PaymentCancelTest.php | 30 +++++++++++++ 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 3766cb04..a3a5c8d2 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -26,6 +26,7 @@ use heidelpayPHP\Adapter\HttpAdapterInterface; use heidelpayPHP\Constants\ApiResponseCodes; +use heidelpayPHP\Constants\CancelReasonCodes; use heidelpayPHP\Constants\IdStrings; use heidelpayPHP\Constants\TransactionTypes; use heidelpayPHP\Exceptions\HeidelpayApiException; @@ -628,6 +629,7 @@ public function getExternalId() * If no amount is given a full cancel will be performed i. e. all Charges and Authorizations will be cancelled. * * @param float|null $amount The amount to canceled. + * @param string $reason * * @return Cancellation The resulting Cancellation object. * If more then one cancellation is performed the last one will be returned. @@ -635,24 +637,62 @@ public function getExternalId() * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. */ - public function cancel($amount = null): Cancellation + public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): Cancellation { - list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); - list($authCancel, $authException) = $this->cancelAuthorization($amount); + $charges = array_reverse($this->charges); + $amountToCancel = $amount; - $cancels = array_merge($chargeCancels, $authCancel); - $exceptions = array_merge($chargeExceptions, $authException); + if (count($charges) === 0) { + $authorize = $this->getAuthorization(); + if ($authorize !== null) { + return $authorize->cancel($amountToCancel); + } - if (isset($cancels[0]) && $cancels[0] instanceof Cancellation) { - return $cancels[0]; + throw new RuntimeException('This Payment could not be cancelled.'); } - // throw the last exception if no cancellation has been created - if (isset($exceptions[0]) && $exceptions[0] instanceof HeidelpayApiException) { - throw $exceptions[0]; + $cancel = null; + + /** @var Charge $charge */ + foreach ($charges as $charge) { + if ($amountToCancel === null || $amountToCancel >= $charge->getAmount()) { + try { + $cancel = $charge->cancel(null, $reason); + } catch (HeidelpayApiException $e) { + continue; + } + } else { + try { + $cancel = $charge->cancel($amountToCancel, $reason); + } catch (HeidelpayApiException $e) { + continue; + } + } + + if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount() <= 0)) { + break; + } } - throw new RuntimeException('This Payment could not be cancelled.'); + return $cancel; + +// todo: handle exceptions (e.g.) second cancel +// list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); +// list($authCancel, $authException) = $this->cancelAuthorization($amount); +// +// $cancels = array_merge($chargeCancels, $authCancel); +// $exceptions = array_merge($chargeExceptions, $authException); +// +// if (isset($cancels[0]) && $cancels[0] instanceof Cancellation) { +// return $cancels[0]; +// } +// +// // throw the last exception if no cancellation has been created +// if (isset($exceptions[0]) && $exceptions[0] instanceof HeidelpayApiException) { +// throw $exceptions[0]; +// } +// +// throw new RuntimeException('This Payment could not be cancelled.'); } /** diff --git a/test/BasePaymentTest.php b/test/BasePaymentTest.php index e4f8ad9b..c003222f 100755 --- a/test/BasePaymentTest.php +++ b/test/BasePaymentTest.php @@ -206,6 +206,7 @@ protected function createCardObject(): Card * Creates and returns an Authorization object with the API which can be used in test methods. * * @param float $amount + * * @return Authorization * * @throws HeidelpayApiException diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index e3394df5..ca155b7a 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -141,6 +141,36 @@ public function partialCancelOnSingleChargeShouldBePossible() $this->assertTrue($payment->isCanceled()); } + /** + * Verify partial cancel on multiple charges (cancel < last charge). + * PHPLIB-228 - Case 4 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenLastCharge() + { + $authorization = $this->createCardAuthorization(123.44); + $payment = $authorization->getPayment(); + + $charge1 = $payment->charge(100.44); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0); + $this->assertArraySubset([$charge1], $payment->getCharges()); + + $charge2 = $payment->charge(23.00); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); + $this->assertArraySubset([$charge1, $charge2], $payment->getCharges()); + + $cancellation = $payment->cancel(20.0); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 103.44, 123.44, 20.00); + $this->assertEquals(20.0, $cancellation->getAmount()); + } + /** * Verify full cancel on authorize. * PHPLIB-228 - Case 6 From 61032ebc714b393370411ac119147ff26eb3f8d1 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 8 Oct 2019 17:03:26 +0200 Subject: [PATCH 36/88] [refactor] (PHPLIB-228) Cancel: Add cancel scenario with cancel amount > or < than last charge amount. --- src/Resources/Payment.php | 2 +- test/integration/PaymentCancelTest.php | 42 ++++++++++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index a3a5c8d2..0fcb214d 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -669,7 +669,7 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ } } - if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount() <= 0)) { + if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount()) <= 0) { break; } } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index ca155b7a..ff423f25 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -28,6 +28,8 @@ use heidelpayPHP\Exceptions\HeidelpayApiException; use heidelpayPHP\Resources\TransactionTypes\Cancellation; use heidelpayPHP\test\BasePaymentTest; +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\Exception; use RuntimeException; class PaymentCancelTest extends BasePaymentTest @@ -143,32 +145,41 @@ public function partialCancelOnSingleChargeShouldBePossible() /** * Verify partial cancel on multiple charges (cancel < last charge). - * PHPLIB-228 - Case 4 + * PHPLIB-228 - Case 4 + 5 * * @test - * + * @dataProvider partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorizeDP + * @param $amount + * @throws AssertionFailedError + * @throws Exception * @throws HeidelpayApiException * @throws RuntimeException */ - public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenLastCharge() + public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorize($amount) { - $authorization = $this->createCardAuthorization(123.44); - $payment = $authorization->getPayment(); + $authorizeAmount = 123.44; + $authorization = $this->createCardAuthorization($authorizeAmount); + $payment = $authorization->getPayment(); $charge1 = $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0); + $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0); $this->assertArraySubset([$charge1], $payment->getCharges()); $charge2 = $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); + $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0); $this->assertArraySubset([$charge1, $charge2], $payment->getCharges()); - $cancellation = $payment->cancel(20.0); + $payment->cancel($amount); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0.0, 103.44, 123.44, 20.00); - $this->assertEquals(20.0, $cancellation->getAmount()); + $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); + $cancellationTotal = 0.0; + foreach ($payment->getCancellations() as $cancellation) { + /** @var Cancellation $cancellation */ + $cancellationTotal += $cancellation->getAmount(); + } + $this->assertEquals($amount, $cancellationTotal); } /** @@ -228,4 +239,15 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); $this->assertTrue($fetchedPayment->isCanceled()); } + + /** + * @return array + */ + public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorizeDP(): array + { + return [ + 'cancel amount lt last charge' => [20], + 'cancel amount gt last charge' => [40] + ]; + } } From 207fb2d845ab241cf693743b5daef2a738d3e390 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 9 Oct 2019 13:46:30 +0200 Subject: [PATCH 37/88] [refactor] (PHPLIB-228) Cancel: Add test for cancel case 8. --- test/integration/PaymentCancelTest.php | 79 ++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index ff423f25..f1d0fb24 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -26,6 +26,7 @@ use heidelpayPHP\Constants\ApiResponseCodes; use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Resources\Payment; use heidelpayPHP\Resources\TransactionTypes\Cancellation; use heidelpayPHP\test\BasePaymentTest; use PHPUnit\Framework\AssertionFailedError; @@ -149,7 +150,9 @@ public function partialCancelOnSingleChargeShouldBePossible() * * @test * @dataProvider partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorizeDP + * * @param $amount + * * @throws AssertionFailedError * @throws Exception * @throws HeidelpayApiException @@ -174,12 +177,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $payment->cancel($amount); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); - $cancellationTotal = 0.0; - foreach ($payment->getCancellations() as $cancellation) { - /** @var Cancellation $cancellation */ - $cancellationTotal += $cancellation->getAmount(); - } - $this->assertEquals($amount, $cancellationTotal); + $this->assertCancelledAmount($amount, $payment); } /** @@ -240,6 +238,40 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertTrue($fetchedPayment->isCanceled()); } + /** + * Verify full cancel on fully charged authorize. + * PHPLIB-228 - Case 8 + * + * @test + * @dataProvider fullCancelOnFullyCanceledAuthorizeShouldBePossibleDP + * + * @param float $amount The amount to be cancelled. + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnFullyCanceledAuthorizeShouldBePossible($amount) + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertTrue($payment->isPending()); + + $payment->charge(); + $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0); + $this->assertTrue($payment->isCompleted()); + + $payment->cancel($amount); + $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); + $this->assertTrue($payment->isCanceled()); + + $this->assertCancelledAmount(100.0, $payment); + } + + // + /** * @return array */ @@ -250,4 +282,39 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth 'cancel amount gt last charge' => [40] ]; } + + /** + * @return array + */ + public function fullCancelOnFullyCanceledAuthorizeShouldBePossibleDP(): array + { + return [ + 'no amount given' => [null], + 'amount given' => [100.0] + ]; + } + + // + + // + + /** + * @param float $expectedAmount The total amount of all cancellations of the given payment. + * @param Payment $payment The payment whose cancellations are to be asserted. + * + * @throws Exception + * @throws RuntimeException + * @throws HeidelpayApiException + */ + private function assertCancelledAmount($expectedAmount, Payment $payment) + { + $cancellationTotal = 0.0; + foreach ($payment->getCancellations() as $cancellation) { + /** @var Cancellation $cancellation */ + $cancellationTotal += $cancellation->getAmount(); + } + $this->assertEquals($expectedAmount, $cancellationTotal); + } + + // } From ea2887f9be51f928c748d2ba1fb405e51582303f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 9 Oct 2019 15:06:13 +0200 Subject: [PATCH 38/88] [refactor] (PHPLIB-228) Cancel: Return existing cancellation of already cancelled authorization on cancel. --- src/Resources/Payment.php | 102 ++++++++++++++++++------- test/integration/PaymentCancelTest.php | 39 ++++++++-- 2 files changed, 106 insertions(+), 35 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 0fcb214d..a85afb07 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -642,44 +642,25 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ $charges = array_reverse($this->charges); $amountToCancel = $amount; - if (count($charges) === 0) { - $authorize = $this->getAuthorization(); - if ($authorize !== null) { - return $authorize->cancel($amountToCancel); - } + $cancel = $this->cancelChargeAmount($reason, $charges, $amountToCancel); - throw new RuntimeException('This Payment could not be cancelled.'); + if ($cancel === null || $amountToCancel === null) { + $cancel = $this->cancelAmountFromAuthorization($amountToCancel) ?: $cancel; } - $cancel = null; - - /** @var Charge $charge */ - foreach ($charges as $charge) { - if ($amountToCancel === null || $amountToCancel >= $charge->getAmount()) { - try { - $cancel = $charge->cancel(null, $reason); - } catch (HeidelpayApiException $e) { - continue; - } - } else { - try { - $cancel = $charge->cancel($amountToCancel, $reason); - } catch (HeidelpayApiException $e) { - continue; - } - } - - if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount()) <= 0) { - break; - } + if (!$cancel instanceof Cancellation) { + throw new RuntimeException('Error cancelling the given payment.'); } return $cancel; -// todo: handle exceptions (e.g.) second cancel + // todo: handle exceptions (e.g.) second cancel // list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); // list($authCancel, $authException) = $this->cancelAuthorization($amount); -// +// todo: cancel without amount should cancel remaining auth as well +// todo: cancel more than captured --> ? +// todo: cancel all authorized and which has been partly captured --> ? + // $cancels = array_merge($chargeCancels, $authCancel); // $exceptions = array_merge($chargeExceptions, $authException); // @@ -1005,4 +986,67 @@ private function updatePayoutTransaction($transaction) } // + + /** + * Cancels the given amount from the array of charged using the give reason code. + * + * @param string $reason + * @param array $charges + * @param float|null $amountToCancel + * + * @return Cancellation|null + * + * @throws RuntimeException + */ + private function cancelChargeAmount($reason, array $charges, $amountToCancel = null) + { + $cancel = null; + + /** @var Charge $charge */ + foreach ($charges as $charge) { + if ($amountToCancel === null || $amountToCancel >= $charge->getAmount()) { + try { + $cancel = $charge->cancel(null, $reason); + } catch (HeidelpayApiException $e) { + continue; + } + } else { + try { + $cancel = $charge->cancel($amountToCancel, $reason); + } catch (HeidelpayApiException $e) { + continue; + } + } + + if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount()) <= 0) { + break; + } + } + return $cancel; + } + + /** + * @param $amountToCancel + * + * @return Cancellation|null + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + private function cancelAmountFromAuthorization($amountToCancel) + { + $authorize = $this->getAuthorization(); + if ($authorize !== null) { + try { + return $authorize->cancel($amountToCancel); + } catch (HeidelpayApiException $e) { + if ($e->getCode() === ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED) { + return $authorize->getCancellations()[0]; + } + + throw $e; + } + } + return null; + } } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index f1d0fb24..2bf3d075 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -24,7 +24,6 @@ */ namespace heidelpayPHP\test\integration; -use heidelpayPHP\Constants\ApiResponseCodes; use heidelpayPHP\Exceptions\HeidelpayApiException; use heidelpayPHP\Resources\Payment; use heidelpayPHP\Resources\TransactionTypes\Cancellation; @@ -43,7 +42,7 @@ class PaymentCancelTest extends BasePaymentTest * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() + public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCanceled() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); @@ -52,9 +51,8 @@ public function fullCancelOnAuthorizeShouldThrowExceptionIfAlreadyCanceled() $this->assertEquals('s-cnl-1', $cancel->getId()); $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); - $this->expectException(HeidelpayApiException::class); - $this->expectExceptionCode(ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); - $payment->cancel(); + $newCancel = $payment->cancel(); + $this->assertEquals($cancel, $newCancel); } /** @@ -252,7 +250,7 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnFullyCanceledAuthorizeShouldBePossible($amount) + public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); @@ -270,6 +268,35 @@ public function fullCancelOnFullyCanceledAuthorizeShouldBePossible($amount) $this->assertCancelledAmount(100.0, $payment); } + /** + * Verify full cancel on partly charged authorize. + * PHPLIB-228 - Case 8 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnPartlyChargedAuthorizeShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertTrue($payment->isPending()); + + $payment->charge(50.0); + $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); + $this->assertTrue($payment->isPartlyPaid()); + + $payment->cancel(); + $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); + $this->assertTrue($payment->isCanceled()); + + $this->assertCancelledAmount(100.0, $payment); + } + // /** From 1f840b3f064f55602e10806e755c19aa36f887ab Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 9 Oct 2019 16:32:09 +0200 Subject: [PATCH 39/88] [refactor] (PHPLIB-228) Cancel: Refactor payment cancel to return correct cancel object. --- src/Constants/ApiResponseCodes.php | 3 +- src/Resources/Payment.php | 46 +++++++++++++++++--------- test/integration/PaymentCancelTest.php | 22 ++++++++++++ test/unit/Resources/PaymentTest.php | 2 +- 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/Constants/ApiResponseCodes.php b/src/Constants/ApiResponseCodes.php index 8a128895..d598adbc 100755 --- a/src/Constants/ApiResponseCodes.php +++ b/src/Constants/ApiResponseCodes.php @@ -44,7 +44,8 @@ class ApiResponseCodes const API_ERROR_IVF_REQUIRES_BASKET = 'API.330.100.023'; const API_ERROR_ADDRESSES_DO_NOT_MATCH = 'API.330.100.106'; const API_ERROR_CURRENCY_IS_NOT_SUPPORTED = 'API.330.100.202'; - const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; + const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; // replaced by API_ERROR_ALREADY_CANCELLED + const API_ERROR_ALREADY_CANCELLED = 'API.340.100.014'; const API_ERROR_CHARGE_ALREADY_CHARGED_BACK = 'API.340.100.015'; const API_ERROR_ALREADY_CHARGED = 'API.340.100.018'; const API_ERROR_CANCEL_REASON_CODE_IS_MISSING = 'API.340.100.024'; diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index a85afb07..a5b5b031 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -695,13 +695,12 @@ public function cancelAllCharges(): array try { $cancels[] = $charge->cancel(); } catch (HeidelpayApiException $e) { - if (!in_array($e->getCode(), - [ - ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK, - ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED - ], - true - )) { + $allowedErrors = [ + ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK, + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK + ]; + if (!in_array($e->getCode(), $allowedErrors, true)) { throw $e; } $exceptions[] = $e; @@ -728,7 +727,7 @@ public function cancelAuthorization($amount = null): array try { $cancels[] = $authorization->cancel($amount); } catch (HeidelpayApiException $e) { - if (ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED !== $e->getCode()) { + if (ApiResponseCodes::API_ERROR_ALREADY_CANCELLED !== $e->getCode()) { throw $e; } $exceptions[] = $e; @@ -1000,25 +999,36 @@ private function updatePayoutTransaction($transaction) */ private function cancelChargeAmount($reason, array $charges, $amountToCancel = null) { + $cancelWholePayment = $amountToCancel === null; $cancel = null; /** @var Charge $charge */ foreach ($charges as $charge) { - if ($amountToCancel === null || $amountToCancel >= $charge->getAmount()) { + if ($cancelWholePayment || $amountToCancel >= $charge->getAmount()) { try { $cancel = $charge->cancel(null, $reason); } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; continue; } } else { try { $cancel = $charge->cancel($amountToCancel, $reason); } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; continue; } } - if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount()) <= 0) { + if (!$cancelWholePayment && ($amountToCancel -= $cancel instanceof Cancellation ? $cancel->getAmount() : 0.0) <= 0) { break; } } @@ -1036,17 +1046,23 @@ private function cancelChargeAmount($reason, array $charges, $amountToCancel = n private function cancelAmountFromAuthorization($amountToCancel) { $authorize = $this->getAuthorization(); + $cancel = null; if ($authorize !== null) { try { - return $authorize->cancel($amountToCancel); + $cancel = $authorize->cancel($amountToCancel); } catch (HeidelpayApiException $e) { - if ($e->getCode() === ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED) { - return $authorize->getCancellations()[0]; + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; } - throw $e; + $cancel = $authorize->getCancellations()[0]; } } - return null; + return $cancel; } } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 2bf3d075..f8687a1d 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -55,6 +55,28 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa $this->assertEquals($cancel, $newCancel); } + /** + * Return first cancel if charge is already fully cancelled. + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function doubleCancelOnChargeShouldReturnFirstCancel() + { + $charge = $this->createCharge(123.44); + $payment = $charge->getPayment(); + $cancellation = $payment->cancel(); + $this->assertTrue($cancellation->getPayment()->isCanceled()); + $this->assertArraySubset([$cancellation], $payment->getCancellations()); + $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + + $newCancellation = $payment->cancel(); + $this->assertEquals($cancellation, $newCancellation); + $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + } + /** * Verify full cancel on charge. * PHPLIB-228 - Case 1 diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index 685a551b..8c627845 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1551,7 +1551,7 @@ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCa */ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnExceptions() { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); + $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CANCELLED); $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); From 20f131838f472906c9679e1f74b2a5be9dae7441 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 9 Oct 2019 16:32:09 +0200 Subject: [PATCH 40/88] [refactor] (PHPLIB-228) Cancel: Refactor payment cancel. * Prepare for a new cancel method in the future. * Add test for payment cancel for invoice with initial charge. * Simplify existing tests. --- src/Constants/ApiResponseCodes.php | 3 +- src/Resources/Payment.php | 52 ++++--- test/integration/PaymentCancelTest.php | 207 +++++++++++++------------ test/unit/Resources/PaymentTest.php | 6 +- 4 files changed, 145 insertions(+), 123 deletions(-) diff --git a/src/Constants/ApiResponseCodes.php b/src/Constants/ApiResponseCodes.php index 8a128895..d598adbc 100755 --- a/src/Constants/ApiResponseCodes.php +++ b/src/Constants/ApiResponseCodes.php @@ -44,7 +44,8 @@ class ApiResponseCodes const API_ERROR_IVF_REQUIRES_BASKET = 'API.330.100.023'; const API_ERROR_ADDRESSES_DO_NOT_MATCH = 'API.330.100.106'; const API_ERROR_CURRENCY_IS_NOT_SUPPORTED = 'API.330.100.202'; - const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; + const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; // replaced by API_ERROR_ALREADY_CANCELLED + const API_ERROR_ALREADY_CANCELLED = 'API.340.100.014'; const API_ERROR_CHARGE_ALREADY_CHARGED_BACK = 'API.340.100.015'; const API_ERROR_ALREADY_CHARGED = 'API.340.100.018'; const API_ERROR_CANCEL_REASON_CODE_IS_MISSING = 'API.340.100.024'; diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index a85afb07..53d4e646 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -654,7 +654,6 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ return $cancel; - // todo: handle exceptions (e.g.) second cancel // list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); // list($authCancel, $authException) = $this->cancelAuthorization($amount); // todo: cancel without amount should cancel remaining auth as well @@ -677,13 +676,14 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ } /** - * Cancels all charges of the payment and returns an array of the cancellations and already charged exceptions that - * occur. + * Cancels all charges of the payment and returns an array of the cancellations and exceptions that occur. * * @return array * * @throws HeidelpayApiException * @throws RuntimeException + * + * @deprecated since 1.2.2.1 please use Payment::cancel() */ public function cancelAllCharges(): array { @@ -695,13 +695,12 @@ public function cancelAllCharges(): array try { $cancels[] = $charge->cancel(); } catch (HeidelpayApiException $e) { - if (!in_array($e->getCode(), - [ - ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK, - ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED - ], - true - )) { + $allowedErrors = [ + ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK, + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK + ]; + if (!in_array($e->getCode(), $allowedErrors, true)) { throw $e; } $exceptions[] = $e; @@ -728,7 +727,7 @@ public function cancelAuthorization($amount = null): array try { $cancels[] = $authorization->cancel($amount); } catch (HeidelpayApiException $e) { - if (ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED !== $e->getCode()) { + if (ApiResponseCodes::API_ERROR_ALREADY_CANCELLED !== $e->getCode()) { throw $e; } $exceptions[] = $e; @@ -1000,25 +999,36 @@ private function updatePayoutTransaction($transaction) */ private function cancelChargeAmount($reason, array $charges, $amountToCancel = null) { + $cancelWholePayment = $amountToCancel === null; $cancel = null; /** @var Charge $charge */ foreach ($charges as $charge) { - if ($amountToCancel === null || $amountToCancel >= $charge->getAmount()) { + if ($cancelWholePayment || $amountToCancel >= $charge->getAmount()) { try { $cancel = $charge->cancel(null, $reason); } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; continue; } } else { try { $cancel = $charge->cancel($amountToCancel, $reason); } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; continue; } } - if ($amountToCancel !== null && ($amountToCancel -= $cancel->getAmount()) <= 0) { + if (!$cancelWholePayment && ($amountToCancel -= $cancel instanceof Cancellation ? $cancel->getAmount() : 0.0) <= 0) { break; } } @@ -1036,17 +1046,23 @@ private function cancelChargeAmount($reason, array $charges, $amountToCancel = n private function cancelAmountFromAuthorization($amountToCancel) { $authorize = $this->getAuthorization(); + $cancel = null; if ($authorize !== null) { try { - return $authorize->cancel($amountToCancel); + $cancel = $authorize->cancel($amountToCancel); } catch (HeidelpayApiException $e) { - if ($e->getCode() === ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED) { - return $authorize->getCancellations()[0]; + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; } - throw $e; + $cancel = $authorize->getCancellations()[0]; } } - return null; + return $cancel; } } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 2bf3d075..a67b5b27 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -25,8 +25,7 @@ namespace heidelpayPHP\test\integration; use heidelpayPHP\Exceptions\HeidelpayApiException; -use heidelpayPHP\Resources\Payment; -use heidelpayPHP\Resources\TransactionTypes\Cancellation; +use heidelpayPHP\Resources\PaymentTypes\Invoice; use heidelpayPHP\test\BasePaymentTest; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Exception; @@ -35,7 +34,7 @@ class PaymentCancelTest extends BasePaymentTest { /** - * Verify full cancel on authorize throws exception if already canceled. + * Verify full cancel on authorize returns first cancellation if already cancelled. * * @test * @@ -46,32 +45,54 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $cancel = $payment->cancel(); - $this->assertNotNull($cancel); - $this->assertEquals('s-cnl-1', $cancel->getId()); + $cancel = $payment->cancel(); // todo: array mit den erzeugten cancellations + $this->assertTrue($payment->isCanceled()); $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); - $newCancel = $payment->cancel(); + $newCancel = $payment->cancel(); // todo: leeres array $this->assertEquals($cancel, $newCancel); } /** - * Verify full cancel on charge. - * PHPLIB-228 - Case 1 + * Return first cancel if charge is already fully cancelled. * * @test * * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnChargeShouldBePossible() + public function doubleCancelOnChargeShouldReturnFirstCancel() { $charge = $this->createCharge(123.44); $payment = $charge->getPayment(); $cancellation = $payment->cancel(); - $this->assertTrue($cancellation->getPayment()->isCanceled()); + $this->assertTrue($payment->isCanceled()); // todo: array mit den erzeugten cancellations $this->assertArraySubset([$cancellation], $payment->getCancellations()); $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + + $newCancellation = $payment->cancel(); // todo: leeres array + $this->assertEquals($cancellation, $newCancellation); + $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + } + + /** + * Verify full cancel on charge. + * PHPLIB-228 - Case 1 + * + * @test + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnChargeShouldBePossible() + { + $charge = $this->createCharge(123.44); + $payment = $charge->getPayment(); + $this->assertAmounts($payment, 0, 123.44, 123.44, 0); + + $payment->cancel(); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0, 0, 123.44, 123.44); } /** @@ -87,26 +108,20 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib { $authorization = $this->createCardAuthorization(123.44); $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 123.44, 0.0, 123.44, 0); - $charge1 = $payment->charge(100.44); + $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0); - $this->assertArraySubset([$charge1], $payment->getCharges()); - $charge2 = $payment->charge(23.00); + $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); - $this->assertArraySubset([$charge1, $charge2], $payment->getCharges()); $payment->cancel(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); - $cancellationTotal = 0.0; - foreach ($payment->getCancellations() as $cancellation) { - /** @var Cancellation $cancellation */ - $cancellationTotal += $cancellation->getAmount(); - } - $this->assertEquals($authorization->getAmount(), $cancellationTotal); } /** @@ -121,25 +136,17 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib public function partialCancelOnSingleChargeShouldBePossible() { $charge = $this->createCharge(222.33); - $this->assertEquals(222.33, $charge->getAmount()); - $payment = $charge->getPayment(); - $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); - $cancel = $charge->cancel(123.12); - $this->assertEquals(123.12, $cancel->getAmount()); - - $this->heidelpay->fetchPayment($payment); - $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); + $charge->cancel(123.12); $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); - $cancel = $charge->cancel(99.21); - $this->assertEquals(99.21, $cancel->getAmount()); - - $this->heidelpay->fetchPayment($payment); - $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); + $payment->cancel(99.21); $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); } /** @@ -162,20 +169,17 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $authorization = $this->createCardAuthorization($authorizeAmount); $payment = $authorization->getPayment(); - $charge1 = $payment->charge(100.44); + $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0); - $this->assertArraySubset([$charge1], $payment->getCharges()); - $charge2 = $payment->charge(23.00); + $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0); - $this->assertArraySubset([$charge1, $charge2], $payment->getCharges()); $payment->cancel($amount); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); - $this->assertCancelledAmount($amount, $payment); } /** @@ -183,22 +187,25 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth * PHPLIB-228 - Case 6 * * @test + * @dataProvider fullCancelDataProvider + * + * @param float $amount * + * @throws AssertionFailedError + * @throws Exception * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnAuthorizeShouldBePossible() + public function fullCancelOnAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); - $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $this->assertAmounts($fetchedPayment, 100.0, 0, 100.0, 0); - - $cancel = $fetchedPayment->cancel(); - $this->assertNotNull($cancel); - $this->assertEquals('s-cnl-1', $cancel->getId()); - $this->assertEquals('100.0', $cancel->getAmount()); - $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); - $this->assertTrue($fetchedPayment->isCanceled()); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + + $payment->cancel($amount); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0, 0.0, 0); } /** @@ -213,27 +220,21 @@ public function fullCancelOnAuthorizeShouldBePossible() public function fullCancelOnPartCanceledAuthorizeShouldBePossible() { $authorization = $this->createCardAuthorization(); - $fetchedPayment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $this->assertAmounts($fetchedPayment, 100.0, 0, 100.0, 0); - - $cancel = $fetchedPayment->cancel(10.0); - $this->assertNotNull($cancel); - $this->assertEquals('s-cnl-1', $cancel->getId()); - $this->assertEquals('10.0', $cancel->getAmount()); - $this->assertAmounts($fetchedPayment, 90.0, 0, 90.0, 0); - - $secondCancel = $fetchedPayment->cancel(10.0); - $this->assertNotNull($secondCancel); - $this->assertEquals('s-cnl-2', $secondCancel->getId()); - $this->assertEquals('10.0', $secondCancel->getAmount()); - $this->assertAmounts($fetchedPayment, 80.0, 0, 80.0, 0); - - $thirdCancel = $fetchedPayment->cancel(); - $this->assertNotNull($thirdCancel); - $this->assertEquals('s-cnl-3', $thirdCancel->getId()); - $this->assertEquals('80.0', $thirdCancel->getAmount()); - $this->assertAmounts($fetchedPayment, 0.0, 0, 0.0, 0); - $this->assertTrue($fetchedPayment->isCanceled()); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + + $payment->cancel(10.0); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 90.0, 0, 90.0, 0); + + $payment->cancel(10.0); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 80.0, 0, 80.0, 0); + + $payment->cancel(); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0, 0.0, 0); } /** @@ -241,7 +242,7 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() * PHPLIB-228 - Case 8 * * @test - * @dataProvider fullCancelOnFullyCanceledAuthorizeShouldBePossibleDP + * @dataProvider fullCancelDataProvider * * @param float $amount The amount to be cancelled. * @@ -254,18 +255,16 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); $payment->charge(); - $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0); $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0); $payment->cancel($amount); - $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); $this->assertTrue($payment->isCanceled()); - - $this->assertCancelledAmount(100.0, $payment); + $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); } /** @@ -283,18 +282,42 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible() { $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); $payment->charge(50.0); - $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); $payment->cancel(); - $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); + } - $this->assertCancelledAmount(100.0, $payment); + /** + * Verify full cancel on initial iv charge (reversal) + * + * @test + * @dataProvider fullCancelDataProvider + * + * @param float $amount + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) + { + /** @var Invoice $invoice */ + $invoice = $this->heidelpay->createPaymentType(new Invoice()); + $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); + $payment = $charge->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + + $payment->cancel($amount); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } // @@ -313,7 +336,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth /** * @return array */ - public function fullCancelOnFullyCanceledAuthorizeShouldBePossibleDP(): array + public function fullCancelDataProvider(): array { return [ 'no amount given' => [null], @@ -322,26 +345,4 @@ public function fullCancelOnFullyCanceledAuthorizeShouldBePossibleDP(): array } // - - // - - /** - * @param float $expectedAmount The total amount of all cancellations of the given payment. - * @param Payment $payment The payment whose cancellations are to be asserted. - * - * @throws Exception - * @throws RuntimeException - * @throws HeidelpayApiException - */ - private function assertCancelledAmount($expectedAmount, Payment $payment) - { - $cancellationTotal = 0.0; - foreach ($payment->getCancellations() as $cancellation) { - /** @var Cancellation $cancellation */ - $cancellationTotal += $cancellation->getAmount(); - } - $this->assertEquals($expectedAmount, $cancellationTotal); - } - - // } diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index 685a551b..9f56005e 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1435,6 +1435,8 @@ public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() * @throws HeidelpayApiException * @throws ReflectionException * @throws RuntimeException + * + * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated */ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndExceptions() { @@ -1486,6 +1488,8 @@ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndE * * @throws ReflectionException * @throws RuntimeException + * + * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated */ public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlreadyCharged() { @@ -1551,7 +1555,7 @@ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCa */ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnExceptions() { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED); + $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CANCELLED); $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); From 4cdac55e45ed04bf26a6b3bcc68b473a374d9841 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 12:01:36 +0200 Subject: [PATCH 41/88] [refactor] (PHPLIB-228) Cancel: Add test to verify part cancel on initial iv charge. --- test/integration/PaymentCancelTest.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index a67b5b27..eb55e13f 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -320,6 +320,32 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } + /** + * Verify part cancel on initial iv charge (reversal) + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partCancelOnInitialInvoiceChargeShouldBePossible() + { + /** @var Invoice $invoice */ + $invoice = $this->heidelpay->createPaymentType(new Invoice()); + $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); + $payment = $charge->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + + $payment->cancel(50); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); + } + + + // /** From 5272c99e75130b333781adbe556751d96aa88ab3 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 12:04:26 +0200 Subject: [PATCH 42/88] [cleanup] (PHPLIB-228) Cancel: remove todo. --- src/Resources/Payment.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 53d4e646..5944a11d 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -656,7 +656,6 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ // list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); // list($authCancel, $authException) = $this->cancelAuthorization($amount); -// todo: cancel without amount should cancel remaining auth as well // todo: cancel more than captured --> ? // todo: cancel all authorized and which has been partly captured --> ? From a43e80c99573a23181f064505cd3a417c0fc67f5 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 13:57:19 +0200 Subject: [PATCH 43/88] [cleanup] (PHPLIB-228) Cancel: Refactor payment cancel and add test for additional case. --- src/Resources/Payment.php | 134 ++++++++++--------------- test/integration/PaymentCancelTest.php | 50 +++++++-- 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 5944a11d..4f56c1f1 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -642,10 +642,58 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ $charges = array_reverse($this->charges); $amountToCancel = $amount; - $cancel = $this->cancelChargeAmount($reason, $charges, $amountToCancel); + $cancelWholePayment = $amountToCancel === null; + $cancel = null; + + /** @var Charge $charge */ + foreach ($charges as $charge) { + if ($cancelWholePayment || $amountToCancel >= $charge->getAmount()) { + try { + $cancel = $charge->cancel(null, $reason); + } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; + continue; + } + } else { + try { + $cancel = $charge->cancel($amountToCancel, $reason); + } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); + } + // return existing cancel object if there is no charge left in the loop + $cancel = $charge->getCancellations()[0]; + continue; + } + } + + if (!$cancelWholePayment && ($amountToCancel -= $cancel instanceof Cancellation ? $cancel->getAmount() : 0.0) <= 0) { + break; + } + } + + if ($cancel === null || $amountToCancel === null || $amountToCancel !== 0.0) { + $authorize = $this->getAuthorization(); + if ($authorize !== null) { + try { + $cancel = $authorize->cancel($amountToCancel); + } catch (HeidelpayApiException $e) { + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; + } - if ($cancel === null || $amountToCancel === null) { - $cancel = $this->cancelAmountFromAuthorization($amountToCancel) ?: $cancel; + $cancel = $authorize->getCancellations()[0]; + } + } } if (!$cancel instanceof Cancellation) { @@ -984,84 +1032,4 @@ private function updatePayoutTransaction($transaction) } // - - /** - * Cancels the given amount from the array of charged using the give reason code. - * - * @param string $reason - * @param array $charges - * @param float|null $amountToCancel - * - * @return Cancellation|null - * - * @throws RuntimeException - */ - private function cancelChargeAmount($reason, array $charges, $amountToCancel = null) - { - $cancelWholePayment = $amountToCancel === null; - $cancel = null; - - /** @var Charge $charge */ - foreach ($charges as $charge) { - if ($cancelWholePayment || $amountToCancel >= $charge->getAmount()) { - try { - $cancel = $charge->cancel(null, $reason); - } catch (HeidelpayApiException $e) { - if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { - throw new RuntimeException($e->getCode()); - } - // return existing cancel object if there is no charge left in the loop - $cancel = $charge->getCancellations()[0]; - continue; - } - } else { - try { - $cancel = $charge->cancel($amountToCancel, $reason); - } catch (HeidelpayApiException $e) { - if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { - throw new RuntimeException($e->getCode()); - } - // return existing cancel object if there is no charge left in the loop - $cancel = $charge->getCancellations()[0]; - continue; - } - } - - if (!$cancelWholePayment && ($amountToCancel -= $cancel instanceof Cancellation ? $cancel->getAmount() : 0.0) <= 0) { - break; - } - } - return $cancel; - } - - /** - * @param $amountToCancel - * - * @return Cancellation|null - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - private function cancelAmountFromAuthorization($amountToCancel) - { - $authorize = $this->getAuthorization(); - $cancel = null; - if ($authorize !== null) { - try { - $cancel = $authorize->cancel($amountToCancel); - } catch (HeidelpayApiException $e) { - $allowedErrors = [ - ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, - ApiResponseCodes::API_ERROR_ALREADY_CHARGED - ]; - - if (!in_array($e->getCode(), $allowedErrors, true)) { - throw $e; - } - - $cancel = $authorize->getCancellations()[0]; - } - } - return $cancel; - } } diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index eb55e13f..59f8d2f3 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -154,7 +154,7 @@ public function partialCancelOnSingleChargeShouldBePossible() * PHPLIB-228 - Case 4 + 5 * * @test - * @dataProvider partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorizeDP + * @dataProvider partCancelDataProvider * * @param $amount * @@ -225,11 +225,11 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertAmounts($payment, 100.0, 0, 100.0, 0); $payment->cancel(10.0); - $this->assertTrue($payment->isPartlyPaid()); + $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 90.0, 0, 90.0, 0); $payment->cancel(10.0); - $this->assertTrue($payment->isPartlyPaid()); + $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 80.0, 0, 80.0, 0); $payment->cancel(); @@ -269,16 +269,19 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) /** * Verify full cancel on partly charged authorize. - * PHPLIB-228 - Case 8 + * PHPLIB-228 - Case 9 * * @test + * @dataProvider fullCancelDataProvider + * + * @param $amount * * @throws AssertionFailedError * @throws Exception * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnPartlyChargedAuthorizeShouldBePossible() + public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); @@ -289,18 +292,48 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible() $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); - $payment->cancel(); + $payment->cancel($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } + /** + * Verify part cancel on partly charged authorize with cancel amount lt charged amount. + * PHPLIB-228 - Case 11 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $authorizeAmount = 100.0; + $this->assertAmounts($payment, $authorizeAmount, 0, $authorizeAmount, 0); + + $payment->charge(25.0); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 75, 25.0, $authorizeAmount, 0); + + $payment->cancel(20); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 75, 5.0, $authorizeAmount, 20.0); + } + /** * Verify full cancel on initial iv charge (reversal) + * PHPLIB-228 - Case 13 * * @test * @dataProvider fullCancelDataProvider * * @param float $amount + * * @throws AssertionFailedError * @throws Exception * @throws HeidelpayApiException @@ -322,6 +355,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) /** * Verify part cancel on initial iv charge (reversal) + * PHPLIB-228 - Case 14 * * @test * @@ -344,14 +378,12 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } - - // /** * @return array */ - public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorizeDP(): array + public function partCancelDataProvider(): array { return [ 'cancel amount lt last charge' => [20], From 4f7c7c9a8efb016e67adf16acc64933587049d0e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 15:04:42 +0200 Subject: [PATCH 44/88] [cleanup] (PHPLIB-228) Cancel: Replace payment cancel method. --- src/Resources/Payment.php | 98 +++++++++++++++----------- test/integration/PaymentCancelTest.php | 65 +++++++++-------- 2 files changed, 93 insertions(+), 70 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 4f56c1f1..0216f963 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -631,56 +631,78 @@ public function getExternalId() * @param float|null $amount The amount to canceled. * @param string $reason * - * @return Cancellation The resulting Cancellation object. - * If more then one cancellation is performed the last one will be returned. + * @return Cancellation|null The resulting Cancellation object. + * If more then one cancellation is performed the last one will be returned. + * + * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. + * + * @deprecated since 1.2.2.1 Please use cancelPayment. + */ + public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL) + { + $cancellations = $this->cancelPayment($amount, $reason); + + return $cancellations[0] ?: null; + } + + /** + * Performs a Cancellation transaction on the Payment. + * If no amount is given a full cancel will be performed i. e. all Charges and Authorizations will be cancelled. + * + * @param float|null $totalCancelAmount The amount to canceled. + * @param string $reason + * + * @return Cancellation[] The resulting Cancellation object. + * If more then one cancellation is performed the last one will be returned. * * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. */ - public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): Cancellation + public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): array { $charges = array_reverse($this->charges); - $amountToCancel = $amount; + $remainingAmountToCancel = $totalCancelAmount; - $cancelWholePayment = $amountToCancel === null; - $cancel = null; + $cancelWholePayment = $remainingAmountToCancel === null; + $cancellations = []; + $cancellation = null; /** @var Charge $charge */ foreach ($charges as $charge) { - if ($cancelWholePayment || $amountToCancel >= $charge->getAmount()) { - try { - $cancel = $charge->cancel(null, $reason); - } catch (HeidelpayApiException $e) { - if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { - throw new RuntimeException($e->getCode()); - } - // return existing cancel object if there is no charge left in the loop - $cancel = $charge->getCancellations()[0]; - continue; + $cancelAmount = null; + if (!$cancelWholePayment && $remainingAmountToCancel < $charge->getAmount()) { + $cancelAmount = $remainingAmountToCancel; + } + + try { + $cancellation = $charge->cancel($cancelAmount, $reason); + } catch (HeidelpayApiException $e) { + if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { + throw new RuntimeException($e->getCode()); } - } else { - try { - $cancel = $charge->cancel($amountToCancel, $reason); - } catch (HeidelpayApiException $e) { - if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { - throw new RuntimeException($e->getCode()); - } - // return existing cancel object if there is no charge left in the loop - $cancel = $charge->getCancellations()[0]; - continue; + continue; // try next charge object + } + + if ($cancellation instanceof Cancellation) { + $cancellations[] = $cancellation; + if (!$cancelWholePayment) { + $remainingAmountToCancel -= $cancellation->getAmount(); } + $cancellation = null; } - if (!$cancelWholePayment && ($amountToCancel -= $cancel instanceof Cancellation ? $cancel->getAmount() : 0.0) <= 0) { + if (!$cancelWholePayment && $remainingAmountToCancel <= 0) { break; } } - if ($cancel === null || $amountToCancel === null || $amountToCancel !== 0.0) { + if ($cancelWholePayment || $remainingAmountToCancel > 0.0 || count($cancellations) === 0) { $authorize = $this->getAuthorization(); if ($authorize !== null) { try { - $cancel = $authorize->cancel($amountToCancel); + $cancellation = $authorize->cancel($remainingAmountToCancel); + $cancellations[] = $cancellation; } catch (HeidelpayApiException $e) { $allowedErrors = [ ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, @@ -690,28 +712,22 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ if (!in_array($e->getCode(), $allowedErrors, true)) { throw $e; } - - $cancel = $authorize->getCancellations()[0]; } } } - if (!$cancel instanceof Cancellation) { - throw new RuntimeException('Error cancelling the given payment.'); - } - - return $cancel; + return $cancellations; // list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); // list($authCancel, $authException) = $this->cancelAuthorization($amount); -// todo: cancel more than captured --> ? -// todo: cancel all authorized and which has been partly captured --> ? +// todo: cancellation more than captured --> ? +// todo: cancellation all authorized and which has been partly captured --> ? -// $cancels = array_merge($chargeCancels, $authCancel); +// $cancellations = array_merge($chargeCancels, $authCancel); // $exceptions = array_merge($chargeExceptions, $authException); // -// if (isset($cancels[0]) && $cancels[0] instanceof Cancellation) { -// return $cancels[0]; +// if (isset($cancellations[0]) && $cancellations[0] instanceof Cancellation) { +// return $cancellations[0]; // } // // // throw the last exception if no cancellation has been created diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 59f8d2f3..b10b3599 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -44,13 +44,16 @@ class PaymentCancelTest extends BasePaymentTest public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCanceled() { $authorization = $this->createCardAuthorization(); - $payment = $this->heidelpay->fetchPayment($authorization->getPayment()->getId()); - $cancel = $payment->cancel(); // todo: array mit den erzeugten cancellations + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); + + $cancellations = $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); - $this->assertEquals($authorization->getAmount(), $cancel->getAmount()); + $this->assertAmounts($payment, 0.0, 0.0, 0.00, 0.0); + $this->assertCount(1, $cancellations); - $newCancel = $payment->cancel(); // todo: leeres array - $this->assertEquals($cancel, $newCancel); + $this->assertCount(0, $payment->cancelPayment()); } /** @@ -61,18 +64,21 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa * @throws HeidelpayApiException * @throws RuntimeException */ - public function doubleCancelOnChargeShouldReturnFirstCancel() + public function doubleCancelOnChargeShouldReturnEmptyArray() { $charge = $this->createCharge(123.44); $payment = $charge->getPayment(); - $cancellation = $payment->cancel(); - $this->assertTrue($payment->isCanceled()); // todo: array mit den erzeugten cancellations - $this->assertArraySubset([$cancellation], $payment->getCancellations()); - $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); - - $newCancellation = $payment->cancel(); // todo: leeres array - $this->assertEquals($cancellation, $newCancellation); - $this->assertEquals($charge->getAmount(), $cancellation->getAmount()); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0, 123.44, 123.44, 0); + + $cancellations = $payment->cancelPayment(); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0, 0.0, 123.44, 123.44); + $this->assertCount(1, $cancellations); + + $newCancellations = $payment->cancelPayment(); + $this->assertAmounts($payment, 0, 0.0, 123.44, 123.44); + $this->assertCount(0, $newCancellations); } /** @@ -88,11 +94,11 @@ public function fullCancelOnChargeShouldBePossible() { $charge = $this->createCharge(123.44); $payment = $charge->getPayment(); - $this->assertAmounts($payment, 0, 123.44, 123.44, 0); + $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); - $payment->cancel(); + $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); - $this->assertAmounts($payment, 0, 0, 123.44, 123.44); + $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); } /** @@ -119,9 +125,10 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); - $payment->cancel(); + $cancellations = $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); + $this->assertCount(2, $cancellations); } /** @@ -144,7 +151,7 @@ public function partialCancelOnSingleChargeShouldBePossible() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); - $payment->cancel(99.21); + $payment->cancelPayment(99.21); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); } @@ -177,7 +184,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0); - $payment->cancel($amount); + $payment->cancelPayment($amount); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); } @@ -203,7 +210,7 @@ public function fullCancelOnAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0, 100.0, 0); - $payment->cancel($amount); + $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0, 0.0, 0); } @@ -224,15 +231,15 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0, 100.0, 0); - $payment->cancel(10.0); + $payment->cancelPayment(10.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 90.0, 0, 90.0, 0); - $payment->cancel(10.0); + $payment->cancelPayment(10.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 80.0, 0, 80.0, 0); - $payment->cancel(); + $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0, 0.0, 0); } @@ -262,7 +269,7 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0); - $payment->cancel($amount); + $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); } @@ -292,7 +299,7 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); - $payment->cancel($amount); + $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } @@ -320,7 +327,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 75, 25.0, $authorizeAmount, 0); - $payment->cancel(20); + $payment->cancelPayment(20); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 75, 5.0, $authorizeAmount, 20.0); } @@ -348,7 +355,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0, 100.0, 0); - $payment->cancel($amount); + $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -373,7 +380,7 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0, 100.0, 0); - $payment->cancel(50); + $payment->cancelPayment(50); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } From 3f805649b6ad6744450e8d1dd40b4cd148f188ab Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 15:38:55 +0200 Subject: [PATCH 45/88] [cleanup] (PHPLIB-228) Cancel: Refactor cancelPayment method to match actual use cases. --- src/Resources/Payment.php | 51 ++++++++++++++++---------- test/integration/PaymentCancelTest.php | 9 ++--- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 0216f963..c3749f45 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -668,6 +668,38 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC $cancellations = []; $cancellation = null; + if ($cancelWholePayment || $remainingAmountToCancel > 0.0) { + $authorize = $this->getAuthorization(); + if ($authorize !== null) { + $cancelAmount = null; + if (!$cancelWholePayment) { + $remainingAuthorized = $this->amount->getRemaining(); + + // cancel nur das, was noch nicht gecharged wurde + $cancelAmount = $remainingAmountToCancel > $remainingAuthorized ? + $remainingAuthorized : $remainingAmountToCancel; + } + + try { + $cancellation = $authorize->cancel($cancelAmount); + $cancellations[] = $cancellation; + } catch (HeidelpayApiException $e) { + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; + } + } + } + } + + if (!$cancelWholePayment && $remainingAmountToCancel <= 0.0) { + return $cancellations; + } + /** @var Charge $charge */ foreach ($charges as $charge) { $cancelAmount = null; @@ -697,25 +729,6 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC } } - if ($cancelWholePayment || $remainingAmountToCancel > 0.0 || count($cancellations) === 0) { - $authorize = $this->getAuthorization(); - if ($authorize !== null) { - try { - $cancellation = $authorize->cancel($remainingAmountToCancel); - $cancellations[] = $cancellation; - } catch (HeidelpayApiException $e) { - $allowedErrors = [ - ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, - ApiResponseCodes::API_ERROR_ALREADY_CHARGED - ]; - - if (!in_array($e->getCode(), $allowedErrors, true)) { - throw $e; - } - } - } - } - return $cancellations; // list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index b10b3599..5c2b1059 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -320,16 +320,15 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $authorizeAmount = 100.0; - $this->assertAmounts($payment, $authorizeAmount, 0, $authorizeAmount, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->charge(25.0); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 75, 25.0, $authorizeAmount, 0); + $this->assertAmounts($payment, 75.0, 25.0, 100.0, 0.0); - $payment->cancelPayment(20); + $payment->cancelPayment(20.0); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 75, 5.0, $authorizeAmount, 20.0); + $this->assertAmounts($payment, 55.0, 5.0, 80.0, 20.0); } /** From 849b07aacdf712c2e46b92508b5f33fedf241212 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 15:39:50 +0200 Subject: [PATCH 46/88] [cleanup] (PHPLIB-228) Cancel: Remove obsolete (and dead) code. --- src/Resources/Payment.php | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index c3749f45..774fe8a3 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -42,9 +42,9 @@ use heidelpayPHP\Services\IdService; use heidelpayPHP\Traits\HasOrderId; use heidelpayPHP\Traits\HasPaymentState; -use function is_string; use RuntimeException; use stdClass; +use function is_string; class Payment extends AbstractHeidelpayResource { @@ -731,24 +731,8 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC return $cancellations; -// list($chargeCancels, $chargeExceptions) = $this->cancelAllCharges(); -// list($authCancel, $authException) = $this->cancelAuthorization($amount); -// todo: cancellation more than captured --> ? -// todo: cancellation all authorized and which has been partly captured --> ? - -// $cancellations = array_merge($chargeCancels, $authCancel); -// $exceptions = array_merge($chargeExceptions, $authException); -// -// if (isset($cancellations[0]) && $cancellations[0] instanceof Cancellation) { -// return $cancellations[0]; -// } -// -// // throw the last exception if no cancellation has been created -// if (isset($exceptions[0]) && $exceptions[0] instanceof HeidelpayApiException) { -// throw $exceptions[0]; -// } -// -// throw new RuntimeException('This Payment could not be cancelled.'); + // todo: cancellation more than captured --> ? + // todo: cancellation all authorized and which has been partly captured --> ? } /** From c1e5a05037ff0905579fe10ca241b36b5e9e49ec Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 15:49:52 +0200 Subject: [PATCH 47/88] [change] (PHPLIB-228) Cancel: Add case no 12. --- src/Resources/Payment.php | 12 ++++++++--- test/integration/PaymentCancelTest.php | 29 +++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 774fe8a3..a2b5bced 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -675,14 +675,12 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC if (!$cancelWholePayment) { $remainingAuthorized = $this->amount->getRemaining(); - // cancel nur das, was noch nicht gecharged wurde $cancelAmount = $remainingAmountToCancel > $remainingAuthorized ? $remainingAuthorized : $remainingAmountToCancel; } try { $cancellation = $authorize->cancel($cancelAmount); - $cancellations[] = $cancellation; } catch (HeidelpayApiException $e) { $allowedErrors = [ ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, @@ -694,6 +692,14 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC } } } + + if ($cancellation instanceof Cancellation) { + $cancellations[] = $cancellation; + if (!$cancelWholePayment) { + $remainingAmountToCancel -= $cancellation->getAmount(); + } + $cancellation = null; + } } if (!$cancelWholePayment && $remainingAmountToCancel <= 0.0) { @@ -743,7 +749,7 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC * @throws HeidelpayApiException * @throws RuntimeException * - * @deprecated since 1.2.2.1 please use Payment::cancel() + * @deprecated since 1.2.2.1 please use Payment::cancelPayment() */ public function cancelAllCharges(): array { diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 5c2b1059..160fccbe 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -328,7 +328,34 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $payment->cancelPayment(20.0); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 55.0, 5.0, 80.0, 20.0); + $this->assertAmounts($payment, 55.0, 25.0, 80.0, 0.0); + } + + /** + * Verify part cancel on partly charged authorize with cancel amount gt charged amount. + * PHPLIB-228 - Case 12 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + + $payment->charge(40.0); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0); + + $payment->cancelPayment(80.0); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 20.0, 40.0, 20.0); } /** From 33ea9bd826c0978ef31c271ec75cdc084d496c10 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 15:59:28 +0200 Subject: [PATCH 48/88] [cleanup] (PHPLIB-228) Cancel: Changed numbers to float in order to avoid implicit type casts and reduce runtime for tests. --- test/integration/PaymentCancelTest.php | 46 +++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 160fccbe..ea362d16 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -69,15 +69,15 @@ public function doubleCancelOnChargeShouldReturnEmptyArray() $charge = $this->createCharge(123.44); $payment = $charge->getPayment(); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0, 123.44, 123.44, 0); + $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); $cancellations = $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); - $this->assertAmounts($payment, 0, 0.0, 123.44, 123.44); + $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(1, $cancellations); $newCancellations = $payment->cancelPayment(); - $this->assertAmounts($payment, 0, 0.0, 123.44, 123.44); + $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(0, $newCancellations); } @@ -115,15 +115,15 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib $authorization = $this->createCardAuthorization(123.44); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 123.44, 0.0, 123.44, 0); + $this->assertAmounts($payment, 123.44, 0.0, 123.44, 0.0); $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0); + $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0.0); $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0); + $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); $cancellations = $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); @@ -178,11 +178,11 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0); + $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0.0); $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0); + $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0.0); $payment->cancelPayment($amount); $this->assertTrue($payment->isCompleted()); @@ -208,11 +208,11 @@ public function fullCancelOnAuthorizeShouldBePossible($amount) $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); - $this->assertAmounts($payment, 0.0, 0, 0.0, 0); + $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } /** @@ -229,19 +229,19 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->cancelPayment(10.0); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 90.0, 0, 90.0, 0); + $this->assertAmounts($payment, 90.0, 0.0, 90.0, 0.0); $payment->cancelPayment(10.0); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 80.0, 0, 80.0, 0); + $this->assertAmounts($payment, 80.0, 0.0, 80.0, 0.0); $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); - $this->assertAmounts($payment, 0.0, 0, 0.0, 0); + $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } /** @@ -263,11 +263,11 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->charge(); $this->assertTrue($payment->isCompleted()); - $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0); + $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); @@ -293,11 +293,11 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->charge(50.0); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0); + $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); @@ -347,11 +347,11 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePos $authorization = $this->createCardAuthorization(); $payment = $authorization->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->charge(40.0); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0); + $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0.0); $payment->cancelPayment(80.0); $this->assertTrue($payment->isCompleted()); @@ -379,7 +379,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); $payment = $charge->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); @@ -404,9 +404,9 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); $payment = $charge->getPayment(); $this->assertTrue($payment->isPending()); - $this->assertAmounts($payment, 100.0, 0, 100.0, 0); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment(50); + $payment->cancelPayment(50.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } From 718d45871fe3b090e1701e9a1d656fcd9dc814d4 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 16:02:16 +0200 Subject: [PATCH 49/88] [change] (PHPLIB-228) Cancel: Add case 11. --- test/integration/PaymentCancelTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index ea362d16..ddfd7b29 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -304,6 +304,29 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } + /** + * Verify part cancel on umcharged authorize. + * PHPLIB-228 - Case 10 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function partCancelOnUnchargedAuthorizeShouldBePossible() + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); + + $payment->cancelPayment(50.0); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); + } + /** * Verify part cancel on partly charged authorize with cancel amount lt charged amount. * PHPLIB-228 - Case 11 From dd70b19e3ee11440df5780ecdf8e59370f6bb654 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 10 Oct 2019 17:13:22 +0200 Subject: [PATCH 50/88] [change] (PHPLIB-228) Cancel: Add case 15. --- test/integration/PaymentCancelTest.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index ddfd7b29..3d0d299e 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -434,6 +434,29 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } + /** + * Verify cancelling more than was charged. + * PHPLIB-228 - Case 15 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function cancelMoreThanWasCharged() + { + $charge = $this->createCharge(50.0); + $payment = $charge->getPayment(); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 50.0, 50.0, 0.0); + + $payment->cancelPayment(100.0); + $this->assertTrue($payment->isCanceled()); + $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); + } + // /** From 64c2bdca9ec218aa036ef6f5cd4ac40be2596161 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 09:12:36 +0200 Subject: [PATCH 51/88] [change] (PHPLIB-228) Cancel: Add case 16. --- src/Resources/Payment.php | 14 +++++--- src/Resources/TransactionTypes/Charge.php | 22 +++++++++++++ test/integration/PaymentCancelTest.php | 39 +++++++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index a2b5bced..ed98030c 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -709,17 +709,23 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC /** @var Charge $charge */ foreach ($charges as $charge) { $cancelAmount = null; - if (!$cancelWholePayment && $remainingAmountToCancel < $charge->getAmount()) { + if (!$cancelWholePayment && $remainingAmountToCancel <= $charge->getTotalAmount()) { $cancelAmount = $remainingAmountToCancel; } try { $cancellation = $charge->cancel($cancelAmount, $reason); } catch (HeidelpayApiException $e) { - if ($e->getCode() !== ApiResponseCodes::API_ERROR_ALREADY_CANCELLED) { - throw new RuntimeException($e->getCode()); + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED, + ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; } - continue; // try next charge object + continue; } if ($cancellation instanceof Cancellation) { diff --git a/src/Resources/TransactionTypes/Charge.php b/src/Resources/TransactionTypes/Charge.php index bcad2364..8cc60736 100755 --- a/src/Resources/TransactionTypes/Charge.php +++ b/src/Resources/TransactionTypes/Charge.php @@ -98,6 +98,28 @@ public function setAmount($amount): self return $this; } + /** + * @return float|null + */ + public function getCancelledAmount() + { + $amount = 0.0; + foreach ($this->getCancellations() as $cancellation) { + /** @var Cancellation $cancellation */ + $amount += $cancellation->getAmount(); + } + + return $amount; + } + + /** + * @return float|null + */ + public function getTotalAmount() + { + return $this->getAmount() - $this->getCancelledAmount(); + } + /** * @return string|null */ diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 3d0d299e..8aa0b9e4 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -33,6 +33,8 @@ class PaymentCancelTest extends BasePaymentTest { + // + /** * Verify full cancel on authorize returns first cancellation if already cancelled. * @@ -457,6 +459,43 @@ public function cancelMoreThanWasCharged() $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } + /** + * Verify second cancel on partly cancelled charge. + * PHPLIB-228 - Case 16 + * + * @test + * + * @throws AssertionFailedError + * @throws Exception + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function secondCancelExceedsRemainderOfPartlyCancelledCharge() + { + $authorization = $this->createCardAuthorization(); + $payment = $authorization->getPayment(); + $this->assertTrue($payment->isPending()); + $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); + + $payment->charge(50.0); + $this->assertTrue($payment->isPartlyPaid()); + $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); + + $payment->charge(50.0); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); + + $payment->cancelPayment(40.0); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 60.0, 100.0, 40.0); + + $payment->cancelPayment(30.0); + $this->assertTrue($payment->isCompleted()); + $this->assertAmounts($payment, 0.0, 30.0, 100.0, 70.0); + } + + // + // /** From ecdc4b7554be3325cb7a3323e35f36f4fb1c8806 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 10:33:01 +0200 Subject: [PATCH 52/88] [change] (PHPLIB-228) Cancel: Refactor to make sure everything works with a freshly fetched payment. --- test/integration/PaymentCancelTest.php | 53 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 8aa0b9e4..5a61e241 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -33,7 +33,7 @@ class PaymentCancelTest extends BasePaymentTest { - // + // /** * Verify full cancel on authorize returns first cancellation if already cancelled. @@ -46,7 +46,7 @@ class PaymentCancelTest extends BasePaymentTest public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCanceled() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -69,7 +69,7 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa public function doubleCancelOnChargeShouldReturnEmptyArray() { $charge = $this->createCharge(123.44); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); @@ -78,6 +78,7 @@ public function doubleCancelOnChargeShouldReturnEmptyArray() $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(1, $cancellations); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $newCancellations = $payment->cancelPayment(); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(0, $newCancellations); @@ -95,7 +96,7 @@ public function doubleCancelOnChargeShouldReturnEmptyArray() public function fullCancelOnChargeShouldBePossible() { $charge = $this->createCharge(123.44); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); $payment->cancelPayment(); @@ -115,7 +116,7 @@ public function fullCancelOnChargeShouldBePossible() public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossible() { $authorization = $this->createCardAuthorization(123.44); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 123.44, 0.0, 123.44, 0.0); @@ -123,10 +124,12 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 23.0, 100.44, 123.44, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $cancellations = $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); @@ -145,14 +148,15 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib public function partialCancelOnSingleChargeShouldBePossible() { $charge = $this->createCharge(222.33); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); - $charge->cancel(123.12); + $payment->cancelPayment(123.12); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $payment->cancelPayment(99.21); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); @@ -176,16 +180,18 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth { $authorizeAmount = 123.44; $authorization = $this->createCardAuthorization($authorizeAmount); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->charge(100.44); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->charge(23.00); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment($amount); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); @@ -208,7 +214,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth public function fullCancelOnAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -229,7 +235,7 @@ public function fullCancelOnAuthorizeShouldBePossible($amount) public function fullCancelOnPartCanceledAuthorizeShouldBePossible() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -237,10 +243,12 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 90.0, 0.0, 90.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(10.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 80.0, 0.0, 80.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); @@ -263,7 +271,7 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -271,6 +279,7 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); @@ -293,7 +302,7 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -301,6 +310,7 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); @@ -320,7 +330,7 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) public function partCancelOnUnchargedAuthorizeShouldBePossible() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -343,7 +353,7 @@ public function partCancelOnUnchargedAuthorizeShouldBePossible() public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePossible() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -351,6 +361,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 75.0, 25.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(20.0); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 55.0, 25.0, 80.0, 0.0); @@ -370,7 +381,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePossible() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -378,6 +389,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePos $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(80.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 20.0, 40.0, 20.0); @@ -402,7 +414,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) /** @var Invoice $invoice */ $invoice = $this->heidelpay->createPaymentType(new Invoice()); $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -427,7 +439,7 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() /** @var Invoice $invoice */ $invoice = $this->heidelpay->createPaymentType(new Invoice()); $charge = $invoice->charge(100.0, 'EUR', self::RETURN_URL); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -450,7 +462,7 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() public function cancelMoreThanWasCharged() { $charge = $this->createCharge(50.0); - $payment = $charge->getPayment(); + $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 50.0, 50.0, 0.0); @@ -473,7 +485,7 @@ public function cancelMoreThanWasCharged() public function secondCancelExceedsRemainderOfPartlyCancelledCharge() { $authorization = $this->createCardAuthorization(); - $payment = $authorization->getPayment(); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); @@ -481,14 +493,17 @@ public function secondCancelExceedsRemainderOfPartlyCancelledCharge() $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->charge(50.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(40.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 60.0, 100.0, 40.0); + $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $payment->cancelPayment(30.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 30.0, 100.0, 70.0); From ac67b60e780731838f36f7e537e516f139e8fba6 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 10:39:50 +0200 Subject: [PATCH 53/88] [change] (PHPLIB-228) Cancel: Fix cancel return value. --- src/Resources/Payment.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index ed98030c..4216777c 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -643,7 +643,7 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ { $cancellations = $this->cancelPayment($amount, $reason); - return $cancellations[0] ?: null; + return count($cancellations) > 0 ? $cancellations[0] : null; } /** @@ -742,9 +742,6 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC } return $cancellations; - - // todo: cancellation more than captured --> ? - // todo: cancellation all authorized and which has been partly captured --> ? } /** From 7eee4a8bfc569990d3d7c574e2368c115539de2d Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 12:08:40 +0200 Subject: [PATCH 54/88] [cleanup] Fix deprecation notices. --- src/Resources/Basket.php | 8 +++++--- src/Resources/Customer.php | 7 +++++-- src/Resources/Payment.php | 9 +++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Resources/Basket.php b/src/Resources/Basket.php index 83e6a359..d7e1a2f5 100755 --- a/src/Resources/Basket.php +++ b/src/Resources/Basket.php @@ -24,10 +24,10 @@ */ namespace heidelpayPHP\Resources; -use function count; use heidelpayPHP\Adapter\HttpAdapterInterface; use heidelpayPHP\Resources\EmbeddedResources\BasketItem; use stdClass; +use function count; class Basket extends AbstractHeidelpayResource { @@ -96,7 +96,8 @@ public function setAmountTotalGross(float $amountTotalGross): Basket /** * @return float * - * @deprecated since 1.2.0.0 Please use getAmountTotalGross instead. + * @deprecated since 1.2.0.0 + * @see Basket::getAmountTotalGross() */ public function getAmountTotal(): float { @@ -108,7 +109,8 @@ public function getAmountTotal(): float * * @return Basket * - * @deprecated since 1.2.0.0 Please use setAmountTotalGross instead. + * @deprecated since 1.2.0.0 + * @see Basket::setAmountTotalGross() */ public function setAmountTotal(float $amountTotal): Basket { diff --git a/src/Resources/Customer.php b/src/Resources/Customer.php index 734fa906..f22f85bb 100755 --- a/src/Resources/Customer.php +++ b/src/Resources/Customer.php @@ -28,8 +28,8 @@ use heidelpayPHP\Constants\Salutations; use heidelpayPHP\Resources\EmbeddedResources\Address; use heidelpayPHP\Resources\EmbeddedResources\CompanyInfo; -use function in_array; use stdClass; +use function in_array; class Customer extends AbstractHeidelpayResource { @@ -75,7 +75,10 @@ class Customer extends AbstractHeidelpayResource * @param string|null $firstname * @param string|null $lastname * - * @deprecated since Version 1.1.5.0 use CustomerFactory::createCustomer(...) in the future. + * @deprecated since Version 1.1.5.0 + * @see CustomerFactory::createCustomer() + * @see CustomerFactory::createNotRegisteredB2bCustomer() + * @see CustomerFactory::createRegisteredB2bCustomer() */ public function __construct(string $firstname = null, string $lastname = null) { diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 4216777c..9fe58122 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -637,7 +637,8 @@ public function getExternalId() * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. * - * @deprecated since 1.2.2.1 Please use cancelPayment. + * @deprecated since 1.2.2.1 + * @see Payment::cancelPayment() */ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL) { @@ -752,7 +753,8 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC * @throws HeidelpayApiException * @throws RuntimeException * - * @deprecated since 1.2.2.1 please use Payment::cancelPayment() + * @deprecated since 1.2.2.1 + * @see Payment::cancelPayment() */ public function cancelAllCharges(): array { @@ -785,6 +787,9 @@ public function cancelAllCharges(): array * * @throws HeidelpayApiException * @throws RuntimeException + * + * @deprecated since 1.2.2.1 + * @see Payment::cancelAuthorizationAmount() */ public function cancelAuthorization($amount = null): array { From 9387473b60e02b20274c575f98eacddaede09c4e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 12:30:15 +0200 Subject: [PATCH 55/88] [change] ApiResponseCodes: Replaced constants. --- src/Constants/ApiResponseCodes.php | 11 ++++++++++- src/Resources/Payment.php | 5 ++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Constants/ApiResponseCodes.php b/src/Constants/ApiResponseCodes.php index d598adbc..017027c6 100755 --- a/src/Constants/ApiResponseCodes.php +++ b/src/Constants/ApiResponseCodes.php @@ -44,9 +44,18 @@ class ApiResponseCodes const API_ERROR_IVF_REQUIRES_BASKET = 'API.330.100.023'; const API_ERROR_ADDRESSES_DO_NOT_MATCH = 'API.330.100.106'; const API_ERROR_CURRENCY_IS_NOT_SUPPORTED = 'API.330.100.202'; - const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; // replaced by API_ERROR_ALREADY_CANCELLED + /** + * @deprecated since 1.2.2.1 + * @see ApiResponseCodes::API_ERROR_ALREADY_CANCELLED + */ + const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; const API_ERROR_ALREADY_CANCELLED = 'API.340.100.014'; + /** + * @deprecated since 1.2.2.1 + * @see ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK + */ const API_ERROR_CHARGE_ALREADY_CHARGED_BACK = 'API.340.100.015'; + const API_ERROR_ALREADY_CHARGED_BACK = 'API.340.100.015'; const API_ERROR_ALREADY_CHARGED = 'API.340.100.018'; const API_ERROR_CANCEL_REASON_CODE_IS_MISSING = 'API.340.100.024'; const API_ERROR_AMOUNT_IS_MISSING = 'API.340.200.130'; diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 9fe58122..4051169a 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -720,7 +720,7 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC $allowedErrors = [ ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, ApiResponseCodes::API_ERROR_ALREADY_CHARGED, - ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK + ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK ]; if (!in_array($e->getCode(), $allowedErrors, true)) { @@ -767,9 +767,8 @@ public function cancelAllCharges(): array $cancels[] = $charge->cancel(); } catch (HeidelpayApiException $e) { $allowedErrors = [ - ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK, ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, - ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK ]; if (!in_array($e->getCode(), $allowedErrors, true)) { throw $e; From 7ee498f289e451e8f8cd8186c5ef040213b769a0 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 13:56:55 +0200 Subject: [PATCH 56/88] [change] Fix amount in integration tests with basket. --- test/integration/BasketTest.php | 8 +-- .../PaymentTypes/InvoiceFactoringTest.php | 62 ++----------------- test/integration/PaymentTypes/PaypageTest.php | 4 +- .../TransactionTypes/AuthorizationTest.php | 4 +- .../TransactionTypes/ChargeTest.php | 30 ++------- .../TransactionTypes/PayoutTest.php | 4 +- 6 files changed, 20 insertions(+), 92 deletions(-) diff --git a/test/integration/BasketTest.php b/test/integration/BasketTest.php index f544c105..d87a5253 100755 --- a/test/integration/BasketTest.php +++ b/test/integration/BasketTest.php @@ -185,7 +185,7 @@ public function authorizeTransactionsShouldPassAlongTheBasketIdIfSet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $authorize = $paypal->authorize(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $authorize = $paypal->authorize(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $fetchedPayment = $this->heidelpay->fetchPayment($authorize->getPaymentId()); $this->assertEquals($basket->expose(), $fetchedPayment->getBasket()->expose()); @@ -208,7 +208,7 @@ public function chargeTransactionsShouldPassAlongTheBasketIdIfSet() $this->heidelpay->createPaymentType($sdd); $customer = $this->getMaximumCustomerInclShippingAddress()->setShippingAddress($this->getBillingAddress()); - $charge = $sdd->charge(100.0, 'EUR', self::RETURN_URL, $customer, null, null, $basket); + $charge = $sdd->charge(123.4, 'EUR', self::RETURN_URL, $customer, null, null, $basket); $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertEquals($basket->expose(), $fetchedPayment->getBasket()->expose()); @@ -233,7 +233,7 @@ public function authorizeTransactionsShouldCreateBasketIfItDoesNotExistYet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $authorize = $paypal->authorize(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $authorize = $paypal->authorize(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $this->assertNotEmpty($basket->getId()); $fetchedPayment = $this->heidelpay->fetchPayment($authorize->getPaymentId()); @@ -260,7 +260,7 @@ public function chargeTransactionsShouldCreateBasketIfItDoesNotExistYet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $charge = $paypal->charge(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $charge = $paypal->charge(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $this->assertNotEmpty($basket->getId()); $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPaymentId()); diff --git a/test/integration/PaymentTypes/InvoiceFactoringTest.php b/test/integration/PaymentTypes/InvoiceFactoringTest.php index efe8e223..e4483d45 100755 --- a/test/integration/PaymentTypes/InvoiceFactoringTest.php +++ b/test/integration/PaymentTypes/InvoiceFactoringTest.php @@ -139,15 +139,7 @@ public function invoiceFactoringShouldBeChargeable(InvoiceFactoring $invoiceFact $customer->setShippingAddress($customer->getBillingAddress()); $basket = $this->createBasket(); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket); $this->assertNotNull($charge); $this->assertNotEmpty($charge->getId()); $this->assertNotEmpty($charge->getIban()); @@ -178,15 +170,7 @@ public function verifyInvoiceFactoringIsNotShippableWoInvoiceIdOnHeidelpayObject $customer->setShippingAddress($customer->getBillingAddress()); $basket = $this->createBasket(); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket); // perform shipment $payment = $charge->getPayment(); @@ -215,15 +199,7 @@ public function verifyInvoiceFactoringIsNotShippableWoInvoiceIdOnPaymentObject() $customer->setShippingAddress($customer->getBillingAddress()); $basket = $this->createBasket(); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket); // perform shipment $payment = $charge->getPayment(); @@ -251,15 +227,7 @@ public function verifyInvoiceFactoringShipmentWithInvoiceIdOnHeidelpayObject() $customer->setShippingAddress($customer->getBillingAddress()); $basket = $this->createBasket(); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket); // perform shipment $payment = $charge->getPayment(); @@ -288,15 +256,7 @@ public function verifyInvoiceFactoringShipmentWithInvoiceIdOnPaymentObject() $customer->setShippingAddress($customer->getBillingAddress()); $basket = $this->createBasket(); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket); $payment = $charge->getPayment(); $invoiceId = substr(str_replace(['0.',' '], '', microtime(false)), 0, 16); @@ -323,17 +283,7 @@ public function verifyInvoiceFactoringShipmentWithPreSetInvoiceId() $basket = $this->createBasket(); $invoiceId = substr(str_replace(['0.',' '], '', microtime(false)), 0, 16); - $charge = $invoiceFactoring->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $basket->getOrderId(), - null, - $basket, - null, - $invoiceId - ); + $charge = $invoiceFactoring->charge(123.4, 'EUR', self::RETURN_URL, $customer, $basket->getOrderId(), null, $basket, null, $invoiceId); $payment = $charge->getPayment(); $shipment = $this->heidelpay->ship($payment); diff --git a/test/integration/PaymentTypes/PaypageTest.php b/test/integration/PaymentTypes/PaypageTest.php index decd9668..024988b1 100644 --- a/test/integration/PaymentTypes/PaypageTest.php +++ b/test/integration/PaymentTypes/PaypageTest.php @@ -66,7 +66,7 @@ public function maximumPaypageChargeShouldBeCreatable() $basket = $this->createBasket(); $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); $invoiceId = $this->generateRandomId(); - $paypage = (new Paypage(100.0, 'EUR', self::RETURN_URL)) + $paypage = (new Paypage(123.4, 'EUR', self::RETURN_URL)) ->setLogoImage('https://dev.heidelpay.com/devHeidelpay_400_180.jpg') ->setFullPageImage('https://www.heidelpay.com/fileadmin/content/header-Imges-neu/Header_Phone_12.jpg') ->setShopName('My Test Shop') @@ -120,7 +120,7 @@ public function maximumPaypageAuthorizeShouldBeCreatable() $basket = $this->createBasket(); $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); $invoiceId = $this->generateRandomId(); - $paypage = (new Paypage(100.0, 'EUR', self::RETURN_URL)) + $paypage = (new Paypage(123.4, 'EUR', self::RETURN_URL)) ->setLogoImage('https://dev.heidelpay.com/devHeidelpay_400_180.jpg') ->setFullPageImage('https://www.heidelpay.com/fileadmin/content/header-Imges-neu/Header_Phone_12.jpg') ->setShopName('My Test Shop') diff --git a/test/integration/TransactionTypes/AuthorizationTest.php b/test/integration/TransactionTypes/AuthorizationTest.php index f2bde4e5..9da2d582 100644 --- a/test/integration/TransactionTypes/AuthorizationTest.php +++ b/test/integration/TransactionTypes/AuthorizationTest.php @@ -181,11 +181,11 @@ public function authorizeShouldAcceptAllParameters() $invoiceId = $this->generateRandomId(); $paymentReference = 'paymentReference'; - $authorize = $card->authorize(100.0, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, true, $invoiceId, $paymentReference); + $authorize = $card->authorize(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, true, $invoiceId, $paymentReference); $payment = $authorize->getPayment(); $this->assertSame($card, $payment->getPaymentType()); - $this->assertEquals(100.0, $authorize->getAmount()); + $this->assertEquals(123.4, $authorize->getAmount()); $this->assertEquals('EUR', $authorize->getCurrency()); $this->assertEquals(self::RETURN_URL, $authorize->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); diff --git a/test/integration/TransactionTypes/ChargeTest.php b/test/integration/TransactionTypes/ChargeTest.php index 12734555..4a3baf19 100644 --- a/test/integration/TransactionTypes/ChargeTest.php +++ b/test/integration/TransactionTypes/ChargeTest.php @@ -105,23 +105,12 @@ public function chargeShouldAcceptAllParameters() $paymentReference = 'paymentReference'; // perform request - $charge = $paymentType->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $orderId, - $metadata, - $basket, - true, - $invoiceId, - $paymentReference - ); + $charge = $paymentType->charge(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, true, $invoiceId, $paymentReference); // verify the data sent and received match $payment = $charge->getPayment(); $this->assertSame($paymentType, $payment->getPaymentType()); - $this->assertEquals(100.0, $charge->getAmount()); + $this->assertEquals(123.4, $charge->getAmount()); $this->assertEquals('EUR', $charge->getCurrency()); $this->assertEquals(self::RETURN_URL, $charge->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); @@ -166,23 +155,12 @@ public function chargeWithCustomerShouldAcceptAllParameters() $paymentReference = 'paymentReference'; // perform request - $charge = $ivg->charge( - 100.0, - 'EUR', - self::RETURN_URL, - $customer, - $orderId, - $metadata, - $basket, - null, - $invoiceId, - $paymentReference - ); + $charge = $ivg->charge(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, null, $invoiceId, $paymentReference); // verify the data sent and received match $payment = $charge->getPayment(); $this->assertSame($ivg, $payment->getPaymentType()); - $this->assertEquals(100.0, $charge->getAmount()); + $this->assertEquals(123.4, $charge->getAmount()); $this->assertEquals('EUR', $charge->getCurrency()); $this->assertEquals(self::RETURN_URL, $charge->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); diff --git a/test/integration/TransactionTypes/PayoutTest.php b/test/integration/TransactionTypes/PayoutTest.php index a2554ebd..bf22d408 100644 --- a/test/integration/TransactionTypes/PayoutTest.php +++ b/test/integration/TransactionTypes/PayoutTest.php @@ -166,11 +166,11 @@ public function payoutShouldAcceptAllParameters() $invoiceId = $this->generateRandomId(); $paymentReference = 'paymentReference'; - $payout = $card->payout(100.0, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, $invoiceId, $paymentReference); + $payout = $card->payout(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, $invoiceId, $paymentReference); $payment = $payout->getPayment(); $this->assertSame($card, $payment->getPaymentType()); - $this->assertEquals(100.0, $payout->getAmount()); + $this->assertEquals(123.4, $payout->getAmount()); $this->assertEquals('EUR', $payout->getCurrency()); $this->assertEquals(self::RETURN_URL, $payout->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); From 94df3001ecdf5c443535337de670a7e24bca1145 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 13:58:55 +0200 Subject: [PATCH 57/88] [change] (PHPLIB-228) Cancel: Replace authorization cancel. --- src/Resources/Payment.php | 66 +++++++++++++++++++---------- test/unit/Resources/PaymentTest.php | 12 ++---- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 4051169a..1ddb3092 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -670,29 +670,7 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC $cancellation = null; if ($cancelWholePayment || $remainingAmountToCancel > 0.0) { - $authorize = $this->getAuthorization(); - if ($authorize !== null) { - $cancelAmount = null; - if (!$cancelWholePayment) { - $remainingAuthorized = $this->amount->getRemaining(); - - $cancelAmount = $remainingAmountToCancel > $remainingAuthorized ? - $remainingAuthorized : $remainingAmountToCancel; - } - - try { - $cancellation = $authorize->cancel($cancelAmount); - } catch (HeidelpayApiException $e) { - $allowedErrors = [ - ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, - ApiResponseCodes::API_ERROR_ALREADY_CHARGED - ]; - - if (!in_array($e->getCode(), $allowedErrors, true)) { - throw $e; - } - } - } + $cancellation = $this->cancelAuthorizationAmount($remainingAmountToCancel); if ($cancellation instanceof Cancellation) { $cancellations[] = $cancellation; @@ -809,6 +787,48 @@ public function cancelAuthorization($amount = null): array return array($cancels, $exceptions); } + /** + * Cancel the given amount of the payments authorization. + * + * @param float|null $amount The amount to be cancelled. If null the remaining uncharged amount of the authorization + * will be cancelled completely. If it exceeds the remaining uncharged amount the + * cancellation will only cancel the remaining uncharged amount. + * + * @return Cancellation|null + * + * @throws HeidelpayApiException + * @throws RuntimeException + */ + public function cancelAuthorizationAmount($amount = null) + { + $cancellation = null; + $completeCancel = $amount === null; + + $authorize = $this->getAuthorization(); + if ($authorize !== null) { + $cancelAmount = null; + if (!$completeCancel) { + $remainingAuthorized = $this->getAmount()->getRemaining(); + $cancelAmount = $amount > $remainingAuthorized ? $remainingAuthorized : $amount; + } + + try { + $cancellation = $authorize->cancel($cancelAmount); + } catch (HeidelpayApiException $e) { + $allowedErrors = [ + ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, + ApiResponseCodes::API_ERROR_ALREADY_CHARGED + ]; + + if (!in_array($e->getCode(), $allowedErrors, true)) { + throw $e; + } + } + } + + return $cancellation; + } + /** * Performs a Charge transaction on the payment. * diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index 9f56005e..257d094e 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1539,9 +1539,7 @@ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCa * @var Payment $paymentMock */ $paymentMock->setAuthorization($authorizationMock); - list($cancellations, $exceptions) = $paymentMock->cancelAuthorization(); - $this->assertArraySubset([$cancellation], $cancellations); - $this->assertIsEmptyArray($exceptions); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount()); } /** @@ -1568,10 +1566,7 @@ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnEx * @var Payment $paymentMock */ $paymentMock->setAuthorization($authorizationMock); - list($cancellations, $exceptions) = $paymentMock->cancelAuthorization(); - - $this->assertIsEmptyArray($cancellations); - $this->assertArraySubset([$exception], $exceptions); + $this->assertNull($paymentMock->cancelAuthorizationAmount()); } /** @@ -1600,7 +1595,7 @@ public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherTha $paymentMock->setAuthorization($authorizationMock); try { - $paymentMock->cancelAuthorization(); + $paymentMock->cancelAuthorizationAmount(); $this->assertFalse(true, 'The expected exception has not been thrown.'); } catch (HeidelpayApiException $e) { $this->assertSame($exception, $e); @@ -1716,6 +1711,7 @@ public function metadataMustBeOfTypeMetadata() $this->assertNull($payment->getMetadata()); // when + /** @noinspection PhpParamsInspection */ $payment->setMetadata('test'); // then From d36485159c6890d9f1e84ae1c536c5ae69a6f96f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 14:10:51 +0200 Subject: [PATCH 58/88] [change] (PHPLIB-228) Cancel: Fix deprecated cancel method to behave like before (sort of). --- src/Resources/Payment.php | 6 +- test/unit/Resources/PaymentTest.php | 110 +++------------------------- 2 files changed, 14 insertions(+), 102 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 1ddb3092..aab3d774 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -644,7 +644,11 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ { $cancellations = $this->cancelPayment($amount, $reason); - return count($cancellations) > 0 ? $cancellations[0] : null; + if (count($cancellations) > 0) { + return $cancellations[0]; + } + + throw new RuntimeException('This Payment could not be cancelled.'); } /** diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index 257d094e..b6c9bce7 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1310,99 +1310,14 @@ public function handleResponseShouldAddPayoutFromResponseIfItDoesNotExists() */ public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnFirstChargeCancellationObject() { - $paymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelPayment'])->getMock(); $cancellation = new Cancellation(1.0); - $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception3 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $paymentMock->expects($this->once())->method('cancelAllCharges') - ->willReturn([[$cancellation], [$exception1, $exception2]]); - $paymentMock->expects($this->once())->method('cancelAuthorization')->willReturn([[], [$exception3]]); + $paymentMock->expects($this->once())->method('cancelPayment')->willReturn([$cancellation]); /** @var Payment $paymentMock */ $this->assertSame($cancellation, $paymentMock->cancel()); } - /** - * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns authorize cancellation object if - * no charge cancellation object exist. - * - * @test - * - * @throws HeidelpayApiException - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelShouldReturnAuthorizationCancellationObjectIfNoChargeCancellationsExist() - { - $paymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); - $cancellation = new Cancellation(2.0); - $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception3 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $paymentMock->expects($this->once())->method('cancelAllCharges') - ->willReturn([[], [$exception1, $exception2]]); - $paymentMock->expects($this->once())->method('cancelAuthorization') - ->willReturn([[$cancellation], [$exception3]]); - - /** @var Payment $paymentMock */ - $this->assertSame($cancellation, $paymentMock->cancel()); - } - - /** - * Verify payment:cancel throws first charge exception if all charges and auth have already been cancelled. - * - * @test - * - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelShouldThrowFirstChargeAlreadyCancelledExceptionIfNoCancellationTookPlace() - { - $paymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); - $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception3 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $paymentMock->expects($this->once())->method('cancelAllCharges')->willReturn([[], [$exception1, $exception2]]); - $paymentMock->expects($this->once())->method('cancelAuthorization')->willReturn([[], [$exception3]]); - - try { - /** @var Payment $paymentMock */ - $paymentMock->cancel(); - $this->assertFalse(true, 'The expected exception has not been thrown.'); - } catch (HeidelpayApiException $e) { - $this->assertSame($exception1, $e); - } - } - - /** - * Verify payment:cancel throws auth exception if no charges existed and the authorization was already cancelled. - * - * @test - * - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelShouldThrowAuthAlreadyCancelledExceptionIfNoCancellationTookPlaceAndNoChargeExceptionExists() - { - $paymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $paymentMock->expects($this->once())->method('cancelAllCharges')->willReturn([[], []]); - $paymentMock->expects($this->once())->method('cancelAuthorization')->willReturn([[], [$exception]]); - - try { - /** @var Payment $paymentMock */ - $paymentMock->cancel(); - $this->assertFalse(true, 'The expected exception has not been thrown.'); - } catch (HeidelpayApiException $e) { - $this->assertSame($exception, $e); - } - } - /** * Verify payment:cancel throws Exception if no cancellation and no auth existed to be cancelled. * @@ -1414,10 +1329,7 @@ public function cancelShouldThrowAuthAlreadyCancelledExceptionIfNoCancellationTo */ public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() { - $paymentMock = $this->getMockBuilder(Payment::class) - ->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('cancelAllCharges')->willReturn([[], []]); - $paymentMock->expects($this->once())->method('cancelAuthorization')->willReturn([[], []]); + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('This Payment could not be cancelled.'); @@ -1436,15 +1348,15 @@ public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() * @throws ReflectionException * @throws RuntimeException * - * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated + * @deprecated since 1.2.2.1 */ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndExceptions() { $cancellation1 = new Cancellation(1.0); $cancellation2 = new Cancellation(2.0); $cancellation3 = new Cancellation(3.0); - $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); - $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); + $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); + $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); $chargeMock1->expects($this->once())->method('cancel')->willReturn($cancellation1); @@ -1469,11 +1381,7 @@ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndE * @var Charge $chargeMock5 */ $payment = new Payment(); - $payment->addCharge($chargeMock1) - ->addCharge($chargeMock2) - ->addCharge($chargeMock3) - ->addCharge($chargeMock4) - ->addCharge($chargeMock5); + $payment->addCharge($chargeMock1)->addCharge($chargeMock2)->addCharge($chargeMock3)->addCharge($chargeMock4)->addCharge($chargeMock5); list($cancellations, $exceptions) = $payment->cancelAllCharges(); $this->assertArraySubset([$cancellation1, $cancellation2, $cancellation3], $cancellations); @@ -1481,7 +1389,7 @@ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndE } /** - * Verify cancelAllCharges will throw any erxception with Code different to + * Verify cancelAllCharges will throw any exception with Code different to * ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CANCELED. * * @test @@ -1493,7 +1401,7 @@ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndE */ public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlreadyCharged() { - $ex1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK); + $ex1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); $ex2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); From b7932af33e10b7cec3e8b6e5455d498b11fff668 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 14:23:17 +0200 Subject: [PATCH 59/88] [change] (PHPLIB-228) Cancel: Rename cancelPayment to cancelAmount. --- src/Resources/Payment.php | 8 ++--- test/integration/PaymentCancelTest.php | 46 +++++++++++++------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index aab3d774..19b0dd7f 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -638,11 +638,11 @@ public function getExternalId() * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. * * @deprecated since 1.2.2.1 - * @see Payment::cancelPayment() + * @see Payment::cancelAmount() */ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL) { - $cancellations = $this->cancelPayment($amount, $reason); + $cancellations = $this->cancelAmount($amount, $reason); if (count($cancellations) > 0) { return $cancellations[0]; @@ -664,7 +664,7 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. */ - public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): array + public function cancelAmount($totalCancelAmount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): array { $charges = array_reverse($this->charges); $remainingAmountToCancel = $totalCancelAmount; @@ -736,7 +736,7 @@ public function cancelPayment($totalCancelAmount = null, $reason = CancelReasonC * @throws RuntimeException * * @deprecated since 1.2.2.1 - * @see Payment::cancelPayment() + * @see Payment::cancelAmount() */ public function cancelAllCharges(): array { diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 5a61e241..a9b68dbd 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -50,12 +50,12 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $cancellations = $payment->cancelPayment(); + $cancellations = $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.00, 0.0); $this->assertCount(1, $cancellations); - $this->assertCount(0, $payment->cancelPayment()); + $this->assertCount(0, $payment->cancelAmount()); } /** @@ -73,13 +73,13 @@ public function doubleCancelOnChargeShouldReturnEmptyArray() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); - $cancellations = $payment->cancelPayment(); + $cancellations = $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(1, $cancellations); $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); - $newCancellations = $payment->cancelPayment(); + $newCancellations = $payment->cancelAmount(); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(0, $newCancellations); } @@ -99,7 +99,7 @@ public function fullCancelOnChargeShouldBePossible() $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); - $payment->cancelPayment(); + $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); } @@ -130,7 +130,7 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $cancellations = $payment->cancelPayment(); + $cancellations = $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); $this->assertCount(2, $cancellations); @@ -152,12 +152,12 @@ public function partialCancelOnSingleChargeShouldBePossible() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); - $payment->cancelPayment(123.12); + $payment->cancelAmount(123.12); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); - $payment->cancelPayment(99.21); + $payment->cancelAmount(99.21); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); } @@ -192,7 +192,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment($amount); + $payment->cancelAmount($amount); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); } @@ -218,7 +218,7 @@ public function fullCancelOnAuthorizeShouldBePossible($amount) $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment($amount); + $payment->cancelAmount($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -239,17 +239,17 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment(10.0); + $payment->cancelAmount(10.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 90.0, 0.0, 90.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(10.0); + $payment->cancelAmount(10.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 80.0, 0.0, 80.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(); + $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -280,7 +280,7 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment($amount); + $payment->cancelAmount($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); } @@ -311,7 +311,7 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment($amount); + $payment->cancelAmount($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } @@ -334,7 +334,7 @@ public function partCancelOnUnchargedAuthorizeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment(50.0); + $payment->cancelAmount(50.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } @@ -362,7 +362,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $this->assertAmounts($payment, 75.0, 25.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(20.0); + $payment->cancelAmount(20.0); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 55.0, 25.0, 80.0, 0.0); } @@ -390,7 +390,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePos $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(80.0); + $payment->cancelAmount(80.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 20.0, 40.0, 20.0); } @@ -418,7 +418,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment($amount); + $payment->cancelAmount($amount); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -443,7 +443,7 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelPayment(50.0); + $payment->cancelAmount(50.0); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } @@ -466,7 +466,7 @@ public function cancelMoreThanWasCharged() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 50.0, 50.0, 0.0); - $payment->cancelPayment(100.0); + $payment->cancelAmount(100.0); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } @@ -499,12 +499,12 @@ public function secondCancelExceedsRemainderOfPartlyCancelledCharge() $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(40.0); + $payment->cancelAmount(40.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 60.0, 100.0, 40.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelPayment(30.0); + $payment->cancelAmount(30.0); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 30.0, 100.0, 70.0); } From f839f920eb9c2da5ccf4f21641011b59c46c8e9e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 14:33:06 +0200 Subject: [PATCH 60/88] [change] Add method to get cancelled amount from authorization. --- src/Resources/TransactionTypes/Authorization.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Resources/TransactionTypes/Authorization.php b/src/Resources/TransactionTypes/Authorization.php index a6c37f31..08e7a761 100755 --- a/src/Resources/TransactionTypes/Authorization.php +++ b/src/Resources/TransactionTypes/Authorization.php @@ -87,6 +87,20 @@ public function setAmount($amount): self return $this; } + /** + * @return float|null + */ + public function getCancelledAmount() + { + $amount = 0.0; + foreach ($this->getCancellations() as $cancellation) { + /** @var Cancellation $cancellation */ + $amount += $cancellation->getAmount(); + } + + return $amount; + } + /** * @return string|null */ From 602f66f743dfd50e6605445c1224da28c3239386 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 14:40:46 +0200 Subject: [PATCH 61/88] [change] (PHPLIB-228) Update changelog. --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd7a95a..a0aec0dc 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a ### Added * An example for `prepayment` payment method. * An example for `invoice` payment method. +* Charge methods `getCancelledAmount` and `getTotalAmount`. +* Authorize method `getCancelledAmount`. ### Fixed * Problem with HeidelpayApiException. ### Changed * Refactored and extended unit tests. +* Replaced `ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED` with `ApiResponseCodes::API_ERROR_ALREADY_CANCELLED`. +* Replaced `ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK` with `ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK`. +* Replaced `Payment::cancel()` method with `Payment::cancelAmount()`. +* Add deprecation notice for `Payment::cancelAllCharges` and `Payment::cancelAuthorization` +* Adapted integration tests with basket to changes in API. +* Refactor deprecation notices. ## [1.2.2.0][1.2.2.0] From 8b533bb2ed2a48107a509d1e0f63c37b664733ad Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 14:43:03 +0200 Subject: [PATCH 62/88] [change] (PHPLIB-228) Fix unit test. --- test/unit/Resources/PaymentTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index b6c9bce7..e5731e63 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -1310,9 +1310,9 @@ public function handleResponseShouldAddPayoutFromResponseIfItDoesNotExists() */ public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnFirstChargeCancellationObject() { - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelPayment'])->getMock(); + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAmount'])->getMock(); $cancellation = new Cancellation(1.0); - $paymentMock->expects($this->once())->method('cancelPayment')->willReturn([$cancellation]); + $paymentMock->expects($this->once())->method('cancelAmount')->willReturn([$cancellation]); /** @var Payment $paymentMock */ $this->assertSame($cancellation, $paymentMock->cancel()); From f9b6a1cf512b4347af5088bd2a9dd5e2dbc04745 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 16:55:34 +0200 Subject: [PATCH 63/88] [cleanup] (PHPLIB-228) Apply changes from review. --- test/integration/PaymentCancelTest.php | 95 +++++++++++--------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index a9b68dbd..2f3e6317 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -36,14 +36,14 @@ class PaymentCancelTest extends BasePaymentTest // /** - * Verify full cancel on authorize returns first cancellation if already cancelled. + * Verify full cancel on cancelled authorize returns empty array. * * @test * * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCanceled() + public function doubleCancelOnAuthorizeShouldReturnEmptyArray() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); @@ -52,21 +52,25 @@ public function fullCancelOnAuthorizeShouldReturnExistingCancellationIfAlreadyCa $cancellations = $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); - $this->assertAmounts($payment, 0.0, 0.0, 0.00, 0.0); + $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); $this->assertCount(1, $cancellations); - $this->assertCount(0, $payment->cancelAmount()); + $newCancellations = $payment->cancelAmount(); + $this->assertCount(0, $newCancellations); } /** - * Return first cancel if charge is already fully cancelled. + * Verify full cancel on charge. + * AND + * Return empty array if charge is already fully cancelled. + * PHPLIB-228 - Case 1 + double cancel * * @test * * @throws HeidelpayApiException * @throws RuntimeException */ - public function doubleCancelOnChargeShouldReturnEmptyArray() + public function cancelOnChargeAndDoubleCancel() { $charge = $this->createCharge(123.44); $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); @@ -80,28 +84,9 @@ public function doubleCancelOnChargeShouldReturnEmptyArray() $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $newCancellations = $payment->cancelAmount(); - $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); - $this->assertCount(0, $newCancellations); - } - - /** - * Verify full cancel on charge. - * PHPLIB-228 - Case 1 - * - * @test - * - * @throws HeidelpayApiException - * @throws RuntimeException - */ - public function fullCancelOnChargeShouldBePossible() - { - $charge = $this->createCharge(123.44); - $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); - $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); - - $payment->cancelAmount(); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); + $this->assertCount(0, $newCancellations); } /** @@ -145,7 +130,7 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib * @throws HeidelpayApiException * @throws RuntimeException */ - public function partialCancelOnSingleChargeShouldBePossible() + public function partialCancelAndFullCancelOnSingleCharge() { $charge = $this->createCharge(222.33); $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); @@ -169,14 +154,15 @@ public function partialCancelOnSingleChargeShouldBePossible() * @test * @dataProvider partCancelDataProvider * - * @param $amount + * @param float $amount + * @param int $numberCancels * * @throws AssertionFailedError * @throws Exception * @throws HeidelpayApiException * @throws RuntimeException */ - public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuthorize($amount) + public function partialCancelOnMultipleChargedAuthorization($amount, $numberCancels) { $authorizeAmount = 123.44; $authorization = $this->createCardAuthorization($authorizeAmount); @@ -192,7 +178,7 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount($amount); + $this->assertCount($numberCancels, $payment->cancelAmount($amount)); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount - $amount, $authorizeAmount, $amount); } @@ -211,14 +197,14 @@ public function partialCancelOnMultipleChargedAuthorizationAmountSmallerThenAuth * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnAuthorizeShouldBePossible($amount) + public function fullCancelOnAuthorize($amount) { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelAmount($amount); + $this->assertCount(1, $payment->cancelAmount($amount)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -232,24 +218,24 @@ public function fullCancelOnAuthorizeShouldBePossible($amount) * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnPartCanceledAuthorizeShouldBePossible() + public function fullCancelOnPartCanceledAuthorize() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelAmount(10.0); + $this->assertCount(1, $payment->cancelAmount(10.0)); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 90.0, 0.0, 90.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(10.0); + $this->assertCount(1, $payment->cancelAmount(10.0)); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 80.0, 0.0, 80.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(); + $this->assertCount(1, $payment->cancelAmount()); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -268,7 +254,7 @@ public function fullCancelOnPartCanceledAuthorizeShouldBePossible() * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) + public function fullCancelOnFullyChargedAuthorize($amount) { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); @@ -280,7 +266,7 @@ public function fullCancelOnFullyChargedAuthorizeShouldBePossible($amount) $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount($amount); + $this->assertCount(1, $payment->cancelAmount($amount)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 100.0, 100.0); } @@ -311,13 +297,13 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) $this->assertAmounts($payment, 50.0, 50.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount($amount); + $this->assertCount(2, $payment->cancelAmount($amount)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } /** - * Verify part cancel on umcharged authorize. + * Verify part cancel on uncharged authorize. * PHPLIB-228 - Case 10 * * @test @@ -327,14 +313,14 @@ public function fullCancelOnPartlyChargedAuthorizeShouldBePossible($amount) * @throws HeidelpayApiException * @throws RuntimeException */ - public function partCancelOnUnchargedAuthorizeShouldBePossible() + public function partCancelOnUnchargedAuthorize() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelAmount(50.0); + $this->assertCount(1, $payment->cancelAmount(50.0)); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } @@ -350,7 +336,7 @@ public function partCancelOnUnchargedAuthorizeShouldBePossible() * @throws HeidelpayApiException * @throws RuntimeException */ - public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePossible() + public function partCancelOnPartlyChargedAuthorizeWithAmountLtCharged() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); @@ -362,7 +348,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos $this->assertAmounts($payment, 75.0, 25.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(20.0); + $this->assertCount(1, $payment->cancelAmount(20.0)); $this->assertTrue($payment->isPartlyPaid()); $this->assertAmounts($payment, 55.0, 25.0, 80.0, 0.0); } @@ -378,7 +364,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountLtChargedShouldBePos * @throws HeidelpayApiException * @throws RuntimeException */ - public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePossible() + public function partCancelOnPartlyChargedAuthorizeWithAmountGtCharged() { $authorization = $this->createCardAuthorization(); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); @@ -390,7 +376,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePos $this->assertAmounts($payment, 60.0, 40.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(80.0); + $this->assertCount(2, $payment->cancelAmount(80.0)); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 20.0, 40.0, 20.0); } @@ -409,7 +395,7 @@ public function partCancelOnPartlyChargedAuthorizeWithAmountGtChargedShouldBePos * @throws HeidelpayApiException * @throws RuntimeException */ - public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) + public function fullCancelOnInitialInvoiceCharge($amount) { /** @var Invoice $invoice */ $invoice = $this->heidelpay->createPaymentType(new Invoice()); @@ -418,7 +404,7 @@ public function fullCancelOnInitialInvoiceChargeShouldBePossible($amount) $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelAmount($amount); + $this->assertCount(1, $payment->cancelAmount($amount)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 0.0, 0.0); } @@ -443,7 +429,7 @@ public function partCancelOnInitialInvoiceChargeShouldBePossible() $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 100.0, 0.0, 100.0, 0.0); - $payment->cancelAmount(50.0); + $this->assertCount(1, $payment->cancelAmount(50.0)); $this->assertTrue($payment->isPending()); $this->assertAmounts($payment, 50.0, 0.0, 50.0, 0.0); } @@ -466,7 +452,7 @@ public function cancelMoreThanWasCharged() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 50.0, 50.0, 0.0); - $payment->cancelAmount(100.0); + $this->assertCount(1, $payment->cancelAmount(100.0)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 50.0, 50.0); } @@ -499,12 +485,12 @@ public function secondCancelExceedsRemainderOfPartlyCancelledCharge() $this->assertAmounts($payment, 0.0, 100.0, 100.0, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(40.0); + $this->assertCount(1, $payment->cancelAmount(40.0)); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 60.0, 100.0, 40.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->cancelAmount(30.0); + $this->assertCount(2, $payment->cancelAmount(30.0)); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 30.0, 100.0, 70.0); } @@ -519,8 +505,9 @@ public function secondCancelExceedsRemainderOfPartlyCancelledCharge() public function partCancelDataProvider(): array { return [ - 'cancel amount lt last charge' => [20], - 'cancel amount gt last charge' => [40] + 'cancel amount lt last charge' => [20, 1], + 'cancel amount eq to last charge' => [23, 1], + 'cancel amount gt last charge' => [40, 2] ]; } From 42cda1dd19777fe233e1d6b6b4908078293976ff Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 17:08:47 +0200 Subject: [PATCH 64/88] [cleanup] (PHPLIB-228) Cancel: Unreverse charge cancel order (FCFS). --- src/Resources/Payment.php | 2 +- test/integration/PaymentCancelTest.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 19b0dd7f..e859720e 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -666,7 +666,7 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ */ public function cancelAmount($totalCancelAmount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL): array { - $charges = array_reverse($this->charges); + $charges = $this->charges; $remainingAmountToCancel = $totalCancelAmount; $cancelWholePayment = $remainingAmountToCancel === null; diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 2f3e6317..8c8d570d 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -168,12 +168,12 @@ public function partialCancelOnMultipleChargedAuthorization($amount, $numberCanc $authorization = $this->createCardAuthorization($authorizeAmount); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->charge(100.44); + $payment->charge(23.00); $this->assertTrue($payment->isPartlyPaid()); - $this->assertAmounts($payment, 23.0, 100.44, $authorizeAmount, 0.0); + $this->assertAmounts($payment, 100.44, 23.0, $authorizeAmount, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $payment->charge(23.00); + $payment->charge(100.44); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, $authorizeAmount, $authorizeAmount, 0.0); From 0ba14b2ca3b38bf11c126425cdcce70f6512aa63 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 17:09:11 +0200 Subject: [PATCH 65/88] [cleanup] (PHPLIB-228) Cancel: Refactor cancelAmount tests. --- test/integration/PaymentCancelTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/integration/PaymentCancelTest.php b/test/integration/PaymentCancelTest.php index 8c8d570d..8b922c6d 100644 --- a/test/integration/PaymentCancelTest.php +++ b/test/integration/PaymentCancelTest.php @@ -115,10 +115,9 @@ public function fullCancelOnPaymentWithAuthorizeAndMultipleChargesShouldBePossib $this->assertAmounts($payment, 0.0, 123.44, 123.44, 0.0); $payment = $this->heidelpay->fetchPayment($authorization->getPaymentId()); - $cancellations = $payment->cancelAmount(); + $this->assertCount(2, $payment->cancelAmount()); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 123.44, 123.44); - $this->assertCount(2, $cancellations); } /** @@ -137,12 +136,12 @@ public function partialCancelAndFullCancelOnSingleCharge() $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 222.33, 222.33, 0.0); - $payment->cancelAmount(123.12); + $this->assertCount(1, $payment->cancelAmount(123.12)); $this->assertTrue($payment->isCompleted()); $this->assertAmounts($payment, 0.0, 99.21, 222.33, 123.12); $payment = $this->heidelpay->fetchPayment($charge->getPaymentId()); - $payment->cancelAmount(99.21); + $this->assertCount(1, $payment->cancelAmount(99.21)); $this->assertTrue($payment->isCanceled()); $this->assertAmounts($payment, 0.0, 0.0, 222.33, 222.33); } From 1e3c533723bc046c181d3d3c2b7dc085f81f6ab6 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 11 Oct 2019 17:12:46 +0200 Subject: [PATCH 66/88] [cleanup] (PHPLIB-228) Cancel: Update version and Changelog. --- CHANGELOG.md | 8 ++++---- src/Heidelpay.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0aec0dc..f135e8f2 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ 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.2.2.1][1.2.2.1] +## [1.2.3.0][1.2.3.0] ### Added * An example for `prepayment` payment method. @@ -15,13 +15,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a * Problem with HeidelpayApiException. ### Changed -* Refactored and extended unit tests. +* Replaced unreliable `Payment::cancel()` method with `Payment::cancelAmount()` which takes multiple cancellation scenarios into account. * Replaced `ApiResponseCodes::API_ERROR_AUTHORIZE_ALREADY_CANCELLED` with `ApiResponseCodes::API_ERROR_ALREADY_CANCELLED`. * Replaced `ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CHARGED_BACK` with `ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK`. -* Replaced `Payment::cancel()` method with `Payment::cancelAmount()`. * Add deprecation notice for `Payment::cancelAllCharges` and `Payment::cancelAuthorization` * Adapted integration tests with basket to changes in API. * Refactor deprecation notices. +* Refactored and extended unit tests. ## [1.2.2.0][1.2.2.0] @@ -294,4 +294,4 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a [1.2.0.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.1.6.0..1.2.0.0 [1.2.1.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.0.0..1.2.1.0 [1.2.2.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.1.0..1.2.2.0 -[1.2.2.1]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.2.0..1.2.2.1 +[1.2.3.0]: https://github.com/heidelpay/heidelpayPHP/compare/1.2.2.0..1.2.3.0 diff --git a/src/Heidelpay.php b/src/Heidelpay.php index 50f9473b..5754b175 100755 --- a/src/Heidelpay.php +++ b/src/Heidelpay.php @@ -56,7 +56,7 @@ class Heidelpay implements HeidelpayParentInterface const BASE_URL = 'api.heidelpay.com'; const API_VERSION = 'v1'; const SDK_TYPE = 'HeidelpayPHP'; - const SDK_VERSION = '1.2.2.1'; + const SDK_VERSION = '1.2.3.0'; /** @var string $key */ private $key; From da9badfc883b8715c823aaf6e9a412a415014d42 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 10:23:00 +0200 Subject: [PATCH 67/88] [cleanup] Fix tests to pass validation in API. --- test/integration/BasketTest.php | 8 ++++---- .../PaymentTypes/InvoiceFactoringTest.php | 12 ++++++------ test/integration/PaymentTypes/PaypageTest.php | 4 ++-- .../TransactionTypes/AuthorizationTest.php | 4 ++-- test/integration/TransactionTypes/ChargeTest.php | 8 ++++---- test/integration/TransactionTypes/PayoutTest.php | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/test/integration/BasketTest.php b/test/integration/BasketTest.php index f544c105..d87a5253 100755 --- a/test/integration/BasketTest.php +++ b/test/integration/BasketTest.php @@ -185,7 +185,7 @@ public function authorizeTransactionsShouldPassAlongTheBasketIdIfSet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $authorize = $paypal->authorize(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $authorize = $paypal->authorize(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $fetchedPayment = $this->heidelpay->fetchPayment($authorize->getPaymentId()); $this->assertEquals($basket->expose(), $fetchedPayment->getBasket()->expose()); @@ -208,7 +208,7 @@ public function chargeTransactionsShouldPassAlongTheBasketIdIfSet() $this->heidelpay->createPaymentType($sdd); $customer = $this->getMaximumCustomerInclShippingAddress()->setShippingAddress($this->getBillingAddress()); - $charge = $sdd->charge(100.0, 'EUR', self::RETURN_URL, $customer, null, null, $basket); + $charge = $sdd->charge(123.4, 'EUR', self::RETURN_URL, $customer, null, null, $basket); $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPaymentId()); $this->assertEquals($basket->expose(), $fetchedPayment->getBasket()->expose()); @@ -233,7 +233,7 @@ public function authorizeTransactionsShouldCreateBasketIfItDoesNotExistYet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $authorize = $paypal->authorize(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $authorize = $paypal->authorize(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $this->assertNotEmpty($basket->getId()); $fetchedPayment = $this->heidelpay->fetchPayment($authorize->getPaymentId()); @@ -260,7 +260,7 @@ public function chargeTransactionsShouldCreateBasketIfItDoesNotExistYet() /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); - $charge = $paypal->charge(10.0, 'EUR', 'https://heidelpay.com', null, null, null, $basket); + $charge = $paypal->charge(123.4, 'EUR', 'https://heidelpay.com', null, null, null, $basket); $this->assertNotEmpty($basket->getId()); $fetchedPayment = $this->heidelpay->fetchPayment($charge->getPaymentId()); diff --git a/test/integration/PaymentTypes/InvoiceFactoringTest.php b/test/integration/PaymentTypes/InvoiceFactoringTest.php index efe8e223..99973feb 100755 --- a/test/integration/PaymentTypes/InvoiceFactoringTest.php +++ b/test/integration/PaymentTypes/InvoiceFactoringTest.php @@ -140,7 +140,7 @@ public function invoiceFactoringShouldBeChargeable(InvoiceFactoring $invoiceFact $basket = $this->createBasket(); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -179,7 +179,7 @@ public function verifyInvoiceFactoringIsNotShippableWoInvoiceIdOnHeidelpayObject $basket = $this->createBasket(); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -216,7 +216,7 @@ public function verifyInvoiceFactoringIsNotShippableWoInvoiceIdOnPaymentObject() $basket = $this->createBasket(); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -252,7 +252,7 @@ public function verifyInvoiceFactoringShipmentWithInvoiceIdOnHeidelpayObject() $basket = $this->createBasket(); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -289,7 +289,7 @@ public function verifyInvoiceFactoringShipmentWithInvoiceIdOnPaymentObject() $basket = $this->createBasket(); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -324,7 +324,7 @@ public function verifyInvoiceFactoringShipmentWithPreSetInvoiceId() $basket = $this->createBasket(); $invoiceId = substr(str_replace(['0.',' '], '', microtime(false)), 0, 16); $charge = $invoiceFactoring->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, diff --git a/test/integration/PaymentTypes/PaypageTest.php b/test/integration/PaymentTypes/PaypageTest.php index decd9668..024988b1 100644 --- a/test/integration/PaymentTypes/PaypageTest.php +++ b/test/integration/PaymentTypes/PaypageTest.php @@ -66,7 +66,7 @@ public function maximumPaypageChargeShouldBeCreatable() $basket = $this->createBasket(); $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); $invoiceId = $this->generateRandomId(); - $paypage = (new Paypage(100.0, 'EUR', self::RETURN_URL)) + $paypage = (new Paypage(123.4, 'EUR', self::RETURN_URL)) ->setLogoImage('https://dev.heidelpay.com/devHeidelpay_400_180.jpg') ->setFullPageImage('https://www.heidelpay.com/fileadmin/content/header-Imges-neu/Header_Phone_12.jpg') ->setShopName('My Test Shop') @@ -120,7 +120,7 @@ public function maximumPaypageAuthorizeShouldBeCreatable() $basket = $this->createBasket(); $customer = CustomerFactory::createCustomer('Max', 'Mustermann'); $invoiceId = $this->generateRandomId(); - $paypage = (new Paypage(100.0, 'EUR', self::RETURN_URL)) + $paypage = (new Paypage(123.4, 'EUR', self::RETURN_URL)) ->setLogoImage('https://dev.heidelpay.com/devHeidelpay_400_180.jpg') ->setFullPageImage('https://www.heidelpay.com/fileadmin/content/header-Imges-neu/Header_Phone_12.jpg') ->setShopName('My Test Shop') diff --git a/test/integration/TransactionTypes/AuthorizationTest.php b/test/integration/TransactionTypes/AuthorizationTest.php index f2bde4e5..9da2d582 100644 --- a/test/integration/TransactionTypes/AuthorizationTest.php +++ b/test/integration/TransactionTypes/AuthorizationTest.php @@ -181,11 +181,11 @@ public function authorizeShouldAcceptAllParameters() $invoiceId = $this->generateRandomId(); $paymentReference = 'paymentReference'; - $authorize = $card->authorize(100.0, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, true, $invoiceId, $paymentReference); + $authorize = $card->authorize(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, true, $invoiceId, $paymentReference); $payment = $authorize->getPayment(); $this->assertSame($card, $payment->getPaymentType()); - $this->assertEquals(100.0, $authorize->getAmount()); + $this->assertEquals(123.4, $authorize->getAmount()); $this->assertEquals('EUR', $authorize->getCurrency()); $this->assertEquals(self::RETURN_URL, $authorize->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); diff --git a/test/integration/TransactionTypes/ChargeTest.php b/test/integration/TransactionTypes/ChargeTest.php index 12734555..343249a0 100644 --- a/test/integration/TransactionTypes/ChargeTest.php +++ b/test/integration/TransactionTypes/ChargeTest.php @@ -106,7 +106,7 @@ public function chargeShouldAcceptAllParameters() // perform request $charge = $paymentType->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -121,7 +121,7 @@ public function chargeShouldAcceptAllParameters() // verify the data sent and received match $payment = $charge->getPayment(); $this->assertSame($paymentType, $payment->getPaymentType()); - $this->assertEquals(100.0, $charge->getAmount()); + $this->assertEquals(123.4, $charge->getAmount()); $this->assertEquals('EUR', $charge->getCurrency()); $this->assertEquals(self::RETURN_URL, $charge->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); @@ -167,7 +167,7 @@ public function chargeWithCustomerShouldAcceptAllParameters() // perform request $charge = $ivg->charge( - 100.0, + 123.4, 'EUR', self::RETURN_URL, $customer, @@ -182,7 +182,7 @@ public function chargeWithCustomerShouldAcceptAllParameters() // verify the data sent and received match $payment = $charge->getPayment(); $this->assertSame($ivg, $payment->getPaymentType()); - $this->assertEquals(100.0, $charge->getAmount()); + $this->assertEquals(123.4, $charge->getAmount()); $this->assertEquals('EUR', $charge->getCurrency()); $this->assertEquals(self::RETURN_URL, $charge->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); diff --git a/test/integration/TransactionTypes/PayoutTest.php b/test/integration/TransactionTypes/PayoutTest.php index a2554ebd..bf22d408 100644 --- a/test/integration/TransactionTypes/PayoutTest.php +++ b/test/integration/TransactionTypes/PayoutTest.php @@ -166,11 +166,11 @@ public function payoutShouldAcceptAllParameters() $invoiceId = $this->generateRandomId(); $paymentReference = 'paymentReference'; - $payout = $card->payout(100.0, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, $invoiceId, $paymentReference); + $payout = $card->payout(123.4, 'EUR', self::RETURN_URL, $customer, $orderId, $metadata, $basket, $invoiceId, $paymentReference); $payment = $payout->getPayment(); $this->assertSame($card, $payment->getPaymentType()); - $this->assertEquals(100.0, $payout->getAmount()); + $this->assertEquals(123.4, $payout->getAmount()); $this->assertEquals('EUR', $payout->getCurrency()); $this->assertEquals(self::RETURN_URL, $payout->getReturnUrl()); $this->assertSame($customer, $payment->getCustomer()); From 0cf6c1ae265ecfcfce63716456605aef88d93e2d Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 10:33:42 +0200 Subject: [PATCH 68/88] [cleanup] (PHPLIB-228) Cancel: Add unit test to verify authorize:getCancelledAmount method. --- .../TransactionTypes/AuthorizationTest.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/unit/Resources/TransactionTypes/AuthorizationTest.php b/test/unit/Resources/TransactionTypes/AuthorizationTest.php index feffe4d7..23270c8f 100755 --- a/test/unit/Resources/TransactionTypes/AuthorizationTest.php +++ b/test/unit/Resources/TransactionTypes/AuthorizationTest.php @@ -223,6 +223,29 @@ public function chargeShouldCallChargeAuthorizationOnHeidelpayObject() $authorization->charge(); $authorization->charge(321.9); } + /** + * Verify getters and setters. + * + * @test + * + * @throws Exception + */ + public function getCancelledAmountReturnsTheCancelledAmount() + { + $authorization = new Authorization(); + $this->assertEquals(0.0, $authorization->getCancelledAmount()); + + $authorization = new Authorization(123.4, 'myCurrency', 'https://my-return-url.test'); + $this->assertEquals(0.0, $authorization->getCancelledAmount()); + + $cancellation1 = new Cancellation(10.0); + $authorization->addCancellation($cancellation1); + $this->assertEquals(10.0, $authorization->getCancelledAmount()); + + $cancellation2 = new Cancellation(10.0); + $authorization->addCancellation($cancellation2); + $this->assertEquals(20.0, $authorization->getCancelledAmount()); + } // From 4bfd9fca24d1778dcd98645260fd2e478f1b5f4b Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 10:50:44 +0200 Subject: [PATCH 69/88] [cleanup] (PHPLIB-228) Cancel: Add unit test to verify charge:getCancelledAmount method. --- .../TransactionTypes/AuthorizationTest.php | 3 +- .../Resources/TransactionTypes/ChargeTest.php | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/test/unit/Resources/TransactionTypes/AuthorizationTest.php b/test/unit/Resources/TransactionTypes/AuthorizationTest.php index 23270c8f..3ba3f186 100755 --- a/test/unit/Resources/TransactionTypes/AuthorizationTest.php +++ b/test/unit/Resources/TransactionTypes/AuthorizationTest.php @@ -223,8 +223,9 @@ public function chargeShouldCallChargeAuthorizationOnHeidelpayObject() $authorization->charge(); $authorization->charge(321.9); } + /** - * Verify getters and setters. + * Verify getter for cancelled amount. * * @test * diff --git a/test/unit/Resources/TransactionTypes/ChargeTest.php b/test/unit/Resources/TransactionTypes/ChargeTest.php index 506d8250..f524411b 100755 --- a/test/unit/Resources/TransactionTypes/ChargeTest.php +++ b/test/unit/Resources/TransactionTypes/ChargeTest.php @@ -33,6 +33,7 @@ use heidelpayPHP\Resources\TransactionTypes\Charge; use heidelpayPHP\test\BaseUnitTest; use PHPUnit\Framework\Exception; +use PHPUnit\Framework\MockObject\MockObject; use ReflectionException; use RuntimeException; use stdClass; @@ -185,4 +186,53 @@ public function cancelShouldCallCancelChargeOnHeidelpayObject() $charge->cancel(); $charge->cancel(321.9); } + + /** + * Verify getter for cancelled amount. + * + * @test + * + * @throws Exception + */ + public function getCancelledAmountReturnsTheCancelledAmount() + { + $charge = new Charge(); + $this->assertEquals(0.0, $charge->getCancelledAmount()); + + $charge = new Charge(123.4, 'myCurrency', 'https://my-return-url.test'); + $this->assertEquals(0.0, $charge->getCancelledAmount()); + + $cancellation1 = new Cancellation(10.0); + $charge->addCancellation($cancellation1); + $this->assertEquals(10.0, $charge->getCancelledAmount()); + + $cancellation2 = new Cancellation(10.0); + $charge->addCancellation($cancellation2); + $this->assertEquals(20.0, $charge->getCancelledAmount()); + } + + /** + * Verify getter for total amount. + * + * @test + * + * @throws Exception + * @throws ReflectionException + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function getTotalAmountReturnsAmountMinusCancelledAmount() + { + /** @var MockObject|Charge $chargeMock */ + $chargeMock = $this->getMockBuilder(Charge::class) + ->setMethods(['getCancelledAmount']) + ->setConstructorArgs([123.4, 'myCurrency', 'https://my-return-url.test']) + ->getMock(); + + $chargeMock->expects($this->exactly(3))->method('getCancelledAmount') + ->willReturnOnConsecutiveCalls(0.0, 100.0, 123.4); + + $this->assertEquals(123.4, $chargeMock->getTotalAmount()); + $this->assertEquals(23.4, $chargeMock->getTotalAmount()); + $this->assertEquals(0.0, $chargeMock->getTotalAmount()); + } } From 6c536bd13cbb04e4f644659df607cb4342d23db1 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 11:30:54 +0200 Subject: [PATCH 70/88] [cleanup] (PHPLIB-228) Cancel: Move payment cancel tests to dedicated unit test class. --- test/unit/Resources/PaymentCancelTest.php | 250 ++++++++++++++++++++++ test/unit/Resources/PaymentTest.php | 217 ------------------- 2 files changed, 250 insertions(+), 217 deletions(-) create mode 100644 test/unit/Resources/PaymentCancelTest.php diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php new file mode 100644 index 00000000..58aa5a46 --- /dev/null +++ b/test/unit/Resources/PaymentCancelTest.php @@ -0,0 +1,250 @@ + + * + * @package heidelpayPHP/test/unit + */ +namespace heidelpayPHP\test\unit\Resources; + +use heidelpayPHP\Constants\ApiResponseCodes; +use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Resources\Payment; +use heidelpayPHP\Resources\TransactionTypes\Authorization; +use heidelpayPHP\Resources\TransactionTypes\Cancellation; +use heidelpayPHP\Resources\TransactionTypes\Charge; +use heidelpayPHP\test\BaseUnitTest; +use ReflectionException; +use RuntimeException; + +class PaymentCancelTest extends BaseUnitTest +{ + /** + * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns first charge cancellation + * object. + * + * @test + * + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + */ + public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnFirstChargeCancellationObject() + { + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAmount'])->getMock(); + $cancellation = new Cancellation(1.0); + $paymentMock->expects($this->once())->method('cancelAmount')->willReturn([$cancellation]); + + /** @var Payment $paymentMock */ + $this->assertSame($cancellation, $paymentMock->cancel()); + } + + /** + * Verify payment:cancel throws Exception if no cancellation and no auth existed to be cancelled. + * + * @test + * + * @throws ReflectionException + * @throws RuntimeException + * @throws HeidelpayApiException + */ + public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() + { + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('This Payment could not be cancelled.'); + + /** @var Payment $paymentMock */ + $paymentMock->cancel(); + } + + /** + * Verify cancel all charges will call cancel on each existing charge of the payment and will return a list of + * cancels and exceptions. + * + * @test + * + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + * + * @deprecated since 1.2.2.1 + */ + public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndExceptions() + { + $cancellation1 = new Cancellation(1.0); + $cancellation2 = new Cancellation(2.0); + $cancellation3 = new Cancellation(3.0); + $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); + $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); + + $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock1->expects($this->once())->method('cancel')->willReturn($cancellation1); + + $chargeMock2 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock2->expects($this->once())->method('cancel')->willThrowException($exception1); + + $chargeMock3 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock3->expects($this->once())->method('cancel')->willReturn($cancellation2); + + $chargeMock4 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock4->expects($this->once())->method('cancel')->willThrowException($exception2); + + $chargeMock5 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock5->expects($this->once())->method('cancel')->willReturn($cancellation3); + + /** + * @var Charge $chargeMock1 + * @var Charge $chargeMock2 + * @var Charge $chargeMock3 + * @var Charge $chargeMock4 + * @var Charge $chargeMock5 + */ + $payment = new Payment(); + $payment->addCharge($chargeMock1)->addCharge($chargeMock2)->addCharge($chargeMock3)->addCharge($chargeMock4)->addCharge($chargeMock5); + + list($cancellations, $exceptions) = $payment->cancelAllCharges(); + $this->assertArraySubset([$cancellation1, $cancellation2, $cancellation3], $cancellations); + $this->assertArraySubset([$exception1, $exception2], $exceptions); + } + + /** + * Verify cancelAllCharges will throw any exception with Code different to + * ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CANCELED. + * + * @test + * + * @throws ReflectionException + * @throws RuntimeException + * + * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated + */ + public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlreadyCharged() + { + $ex1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); + $ex2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); + + $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock1->expects($this->once())->method('cancel')->willThrowException($ex1); + + $chargeMock2 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + $chargeMock2->expects($this->once())->method('cancel')->willThrowException($ex2); + + /** + * @var Charge $chargeMock1 + * @var Charge $chargeMock2 + */ + $payment = (new Payment())->addCharge($chargeMock1)->addCharge($chargeMock2); + + try { + $payment->cancelAllCharges(); + $this->assertFalse(true, 'The expected exception has not been thrown.'); + } catch (HeidelpayApiException $e) { + $this->assertSame($ex2, $e); + } + } + + /** + * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. + * + * @test + * + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + */ + public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCancels() + { + $cancellation = new Cancellation(1.0); + $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); + $authorizationMock->expects($this->once())->method('cancel')->willReturn($cancellation); + + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); + $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); + + /** + * @var Authorization $authorizationMock + * @var Payment $paymentMock + */ + $paymentMock->setAuthorization($authorizationMock); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount()); + } + + /** + * Verify cancelAuthorization will call cancel on the authorization and will return a list of exceptions. + * + * @test + * + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + */ + public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnExceptions() + { + $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CANCELLED); + + $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); + $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); + + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); + $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); + + /** + * @var Authorization $authorizationMock + * @var Payment $paymentMock + */ + $paymentMock->setAuthorization($authorizationMock); + $this->assertNull($paymentMock->cancelAuthorizationAmount()); + } + + /** + * Verify cancelAuthorization will throw any exception with Code different to + * ApiResponseCodes::API_ERROR_AUTHORIZATION_ALREADY_CANCELED. + * + * @test + * + * @throws ReflectionException + * @throws RuntimeException + */ + public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherThanAlreadyCharged() + { + $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); + + $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); + $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); + + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); + $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); + + /** + * @var Authorization $authorizationMock + * @var Payment $paymentMock + */ + $paymentMock->setAuthorization($authorizationMock); + + try { + $paymentMock->cancelAuthorizationAmount(); + $this->assertFalse(true, 'The expected exception has not been thrown.'); + } catch (HeidelpayApiException $e) { + $this->assertSame($exception, $e); + } + } +} diff --git a/test/unit/Resources/PaymentTest.php b/test/unit/Resources/PaymentTest.php index e5731e63..b5b30833 100755 --- a/test/unit/Resources/PaymentTest.php +++ b/test/unit/Resources/PaymentTest.php @@ -24,7 +24,6 @@ */ namespace heidelpayPHP\test\unit\Resources; -use heidelpayPHP\Constants\ApiResponseCodes; use heidelpayPHP\Constants\PaymentState; use heidelpayPHP\Exceptions\HeidelpayApiException; use heidelpayPHP\Heidelpay; @@ -1296,222 +1295,6 @@ public function handleResponseShouldAddPayoutFromResponseIfItDoesNotExists() // - // - - /** - * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns first charge cancellation - * object. - * - * @test - * - * @throws HeidelpayApiException - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnFirstChargeCancellationObject() - { - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAmount'])->getMock(); - $cancellation = new Cancellation(1.0); - $paymentMock->expects($this->once())->method('cancelAmount')->willReturn([$cancellation]); - - /** @var Payment $paymentMock */ - $this->assertSame($cancellation, $paymentMock->cancel()); - } - - /** - * Verify payment:cancel throws Exception if no cancellation and no auth existed to be cancelled. - * - * @test - * - * @throws ReflectionException - * @throws RuntimeException - * @throws HeidelpayApiException - */ - public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() - { - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAllCharges', 'cancelAuthorization'])->getMock(); - - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('This Payment could not be cancelled.'); - - /** @var Payment $paymentMock */ - $paymentMock->cancel(); - } - - /** - * Verify cancel all charges will call cancel on each existing charge of the payment and will return a list of - * cancels and exceptions. - * - * @test - * - * @throws HeidelpayApiException - * @throws ReflectionException - * @throws RuntimeException - * - * @deprecated since 1.2.2.1 - */ - public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndExceptions() - { - $cancellation1 = new Cancellation(1.0); - $cancellation2 = new Cancellation(2.0); - $cancellation3 = new Cancellation(3.0); - $exception1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); - $exception2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); - - $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock1->expects($this->once())->method('cancel')->willReturn($cancellation1); - - $chargeMock2 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock2->expects($this->once())->method('cancel')->willThrowException($exception1); - - $chargeMock3 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock3->expects($this->once())->method('cancel')->willReturn($cancellation2); - - $chargeMock4 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock4->expects($this->once())->method('cancel')->willThrowException($exception2); - - $chargeMock5 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock5->expects($this->once())->method('cancel')->willReturn($cancellation3); - - /** - * @var Charge $chargeMock1 - * @var Charge $chargeMock2 - * @var Charge $chargeMock3 - * @var Charge $chargeMock4 - * @var Charge $chargeMock5 - */ - $payment = new Payment(); - $payment->addCharge($chargeMock1)->addCharge($chargeMock2)->addCharge($chargeMock3)->addCharge($chargeMock4)->addCharge($chargeMock5); - - list($cancellations, $exceptions) = $payment->cancelAllCharges(); - $this->assertArraySubset([$cancellation1, $cancellation2, $cancellation3], $cancellations); - $this->assertArraySubset([$exception1, $exception2], $exceptions); - } - - /** - * Verify cancelAllCharges will throw any exception with Code different to - * ApiResponseCodes::API_ERROR_CHARGE_ALREADY_CANCELED. - * - * @test - * - * @throws ReflectionException - * @throws RuntimeException - * - * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated - */ - public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlreadyCharged() - { - $ex1 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK); - $ex2 = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); - - $chargeMock1 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock1->expects($this->once())->method('cancel')->willThrowException($ex1); - - $chargeMock2 = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); - $chargeMock2->expects($this->once())->method('cancel')->willThrowException($ex2); - - /** - * @var Charge $chargeMock1 - * @var Charge $chargeMock2 - */ - $payment = (new Payment())->addCharge($chargeMock1)->addCharge($chargeMock2); - - try { - $payment->cancelAllCharges(); - $this->assertFalse(true, 'The expected exception has not been thrown.'); - } catch (HeidelpayApiException $e) { - $this->assertSame($ex2, $e); - } - } - - /** - * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. - * - * @test - * - * @throws HeidelpayApiException - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCancels() - { - $cancellation = new Cancellation(1.0); - $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); - $authorizationMock->expects($this->once())->method('cancel')->willReturn($cancellation); - - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); - - /** - * @var Authorization $authorizationMock - * @var Payment $paymentMock - */ - $paymentMock->setAuthorization($authorizationMock); - $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount()); - } - - /** - * Verify cancelAuthorization will call cancel on the authorization and will return a list of exceptions. - * - * @test - * - * @throws HeidelpayApiException - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnExceptions() - { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CANCELLED); - - $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); - $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); - - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); - - /** - * @var Authorization $authorizationMock - * @var Payment $paymentMock - */ - $paymentMock->setAuthorization($authorizationMock); - $this->assertNull($paymentMock->cancelAuthorizationAmount()); - } - - /** - * Verify cancelAuthorization will throw any exception with Code different to - * ApiResponseCodes::API_ERROR_AUTHORIZATION_ALREADY_CANCELED. - * - * @test - * - * @throws ReflectionException - * @throws RuntimeException - */ - public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherThanAlreadyCharged() - { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); - - $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); - $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); - - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); - - /** - * @var Authorization $authorizationMock - * @var Payment $paymentMock - */ - $paymentMock->setAuthorization($authorizationMock); - - try { - $paymentMock->cancelAuthorizationAmount(); - $this->assertFalse(true, 'The expected exception has not been thrown.'); - } catch (HeidelpayApiException $e) { - $this->assertSame($exception, $e); - } - } - - // - /** * Verify charge will call chargePayment on heidelpay object. * From a7c28d4abc6f8b0374603fb4b07d623fe6c3954c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 11:32:43 +0200 Subject: [PATCH 71/88] [cleanup] (PHPLIB-228) Cancel: Fix version in deprecation notices. --- src/Constants/ApiResponseCodes.php | 4 ++-- src/Resources/Payment.php | 6 +++--- test/unit/Resources/PaymentCancelTest.php | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Constants/ApiResponseCodes.php b/src/Constants/ApiResponseCodes.php index 017027c6..5ec64324 100755 --- a/src/Constants/ApiResponseCodes.php +++ b/src/Constants/ApiResponseCodes.php @@ -45,13 +45,13 @@ class ApiResponseCodes const API_ERROR_ADDRESSES_DO_NOT_MATCH = 'API.330.100.106'; const API_ERROR_CURRENCY_IS_NOT_SUPPORTED = 'API.330.100.202'; /** - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 * @see ApiResponseCodes::API_ERROR_ALREADY_CANCELLED */ const API_ERROR_AUTHORIZE_ALREADY_CANCELLED = 'API.340.100.014'; const API_ERROR_ALREADY_CANCELLED = 'API.340.100.014'; /** - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 * @see ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK */ const API_ERROR_CHARGE_ALREADY_CHARGED_BACK = 'API.340.100.015'; diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index e859720e..f6b75fce 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -637,7 +637,7 @@ public function getExternalId() * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. * - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 * @see Payment::cancelAmount() */ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_CANCEL) @@ -735,7 +735,7 @@ public function cancelAmount($totalCancelAmount = null, $reason = CancelReasonCo * @throws HeidelpayApiException * @throws RuntimeException * - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 * @see Payment::cancelAmount() */ public function cancelAllCharges(): array @@ -769,7 +769,7 @@ public function cancelAllCharges(): array * @throws HeidelpayApiException * @throws RuntimeException * - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 * @see Payment::cancelAuthorizationAmount() */ public function cancelAuthorization($amount = null): array diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index 58aa5a46..9d9993bd 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -36,6 +36,7 @@ class PaymentCancelTest extends BaseUnitTest { + // /** * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns first charge cancellation * object. @@ -86,7 +87,7 @@ public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() * @throws ReflectionException * @throws RuntimeException * - * @deprecated since 1.2.2.1 + * @deprecated since 1.2.3.0 */ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndExceptions() { @@ -135,7 +136,7 @@ public function cancelAllChargesShouldCallCancelOnAllChargesAndReturnCancelsAndE * @throws ReflectionException * @throws RuntimeException * - * @deprecated since 1.2.2.1 since Payment::cancelAllCharges is deprecated + * @deprecated since 1.2.3.0 */ public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlreadyCharged() { @@ -247,4 +248,5 @@ public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherTha $this->assertSame($exception, $e); } } + // } From 4cba9e217efbd057b269b701a37086260f76b963 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 11:35:16 +0200 Subject: [PATCH 72/88] [cleanup] (PHPLIB-228) Cancel: Re-organize class. --- test/unit/Resources/PaymentCancelTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index 9d9993bd..5c562e9a 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -37,6 +37,7 @@ class PaymentCancelTest extends BaseUnitTest { // + /** * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns first charge cancellation * object. @@ -46,6 +47,8 @@ class PaymentCancelTest extends BaseUnitTest * @throws HeidelpayApiException * @throws ReflectionException * @throws RuntimeException + * + * @deprecated since 1.2.3.0 */ public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnFirstChargeCancellationObject() { @@ -65,6 +68,8 @@ public function cancelShouldCallCancelAllChargesAndCancelAuthorizationAndReturnF * @throws ReflectionException * @throws RuntimeException * @throws HeidelpayApiException + * + * @deprecated since 1.2.3.0 */ public function cancelShouldThrowExceptionIfNoTransactionExistsToBeCancelled() { @@ -163,6 +168,8 @@ public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlread } } + // + /** * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. * @@ -248,5 +255,4 @@ public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherTha $this->assertSame($exception, $e); } } - // } From d3738ffac8b559e84f0a0a12d2dff740f64eb86e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 15:23:27 +0200 Subject: [PATCH 73/88] [cleanup] (PHPLIB-228) Cancel: Add unit test to verify that charges are cancelled when no authorize exists. --- test/unit/Resources/PaymentCancelTest.php | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index 5c562e9a..44406696 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -31,6 +31,8 @@ use heidelpayPHP\Resources\TransactionTypes\Cancellation; use heidelpayPHP\Resources\TransactionTypes\Charge; use heidelpayPHP\test\BaseUnitTest; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\MockObject\MockObject; use ReflectionException; use RuntimeException; @@ -170,6 +172,62 @@ public function cancelAllChargesShouldThrowChargeCancelExceptionsOtherThanAlread // + /** + * Verify cancelAmount will call cancelAuthorizationAmount with the amountToCancel. + * When cancelAmount is <= the value of the cancellation it Will return auth cancellation only. + * Charge cancel will not be called if the amount to cancel has been cancelled on the authorization. + * + * @test + * + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + * @throws Exception + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function cancelAmountShouldCallCancelAuthorizationAmount() + { + /** @var MockObject|Payment $paymentMock */ + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAuthorizationAmount'])->getMock(); + $chargeMock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->getMock(); + + $paymentMock->setAuthorization((new Authorization(12.3))->setPayment($paymentMock)); + + $cancellation = new Cancellation(12.3); + $paymentMock->expects($this->exactly(2))->method('cancelAuthorizationAmount')->willReturn($cancellation); + $chargeMock->expects($this->never())->method('cancel'); + + $this->assertEquals([$cancellation], $paymentMock->cancelAmount(10.0)); + $this->assertEquals([$cancellation], $paymentMock->cancelAmount(12.3)); + } + + /** + * Verify that cancel amount will be cancelled on charges if auth does not exist. + * + * @test + * @throws Exception + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function chargesShouldBeCancelledIfAuthDoesNotExist1() + { + /** @var MockObject|Payment $paymentMock */ + /** @var MockObject|Charge $chargeMock */ + /** @var MockObject|Charge $charge2Mock */ + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAuthorizationAmount'])->getMock(); + $chargeMock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->setConstructorArgs([10.0])->getMock(); + + $cancellation = new Cancellation(10.0); + + $paymentMock->expects($this->once())->method('cancelAuthorizationAmount')->willReturn(null); + $chargeMock->expects($this->once())->method('cancel')->with(10.0, 'CANCEL')->willReturn($cancellation); + $paymentMock->addCharge($chargeMock); + + $this->assertEquals([$cancellation], $paymentMock->cancelAmount(10.0)); + } + /** * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. * From 5edcceece9ac4152b0aa889c5e72aace82a7e532 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 15:33:59 +0200 Subject: [PATCH 74/88] [cleanup] (PHPLIB-228) Cancel: Add second unit test to verify that charges are cancelled when no authorize exists. --- test/unit/Resources/PaymentCancelTest.php | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index 44406696..d17bb50f 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -228,6 +228,39 @@ public function chargesShouldBeCancelledIfAuthDoesNotExist1() $this->assertEquals([$cancellation], $paymentMock->cancelAmount(10.0)); } + /** + * Verify that cancel amount will be cancelled on charges if auth does not exist. + * + * @test + * @throws Exception + * @throws HeidelpayApiException + * @throws ReflectionException + * @throws RuntimeException + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function chargesShouldBeCancelledIfAuthDoesNotExist2() + { + /** @var MockObject|Payment $paymentMock */ + /** @var MockObject|Charge $charge1Mock */ + /** @var MockObject|Charge $charge2Mock */ + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAuthorizationAmount'])->getMock(); + $charge1Mock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->setConstructorArgs([10.0])->getMock(); + $charge2Mock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->setConstructorArgs([12.3])->getMock(); + + $cancellation1 = new Cancellation(10.0); + $cancellation2 = new Cancellation(2.3); + + $paymentMock->expects($this->exactly(3))->method('cancelAuthorizationAmount')->willReturn(null); + $charge1Mock->expects($this->exactly(3))->method('cancel')->withConsecutive([10.0, 'CANCEL'], [null, 'CANCEL'], [null, 'CANCEL'])->willReturn($cancellation1); + $charge2Mock->expects($this->exactly(2))->method('cancel')->withConsecutive([2.3, 'CANCEL'], [null, 'CANCEL'])->willReturn($cancellation2); + + $paymentMock->addCharge($charge1Mock)->addCharge($charge2Mock); + + $this->assertEquals([$cancellation1], $paymentMock->cancelAmount(10.0)); + $this->assertEquals([$cancellation1, $cancellation2], $paymentMock->cancelAmount(12.3)); + $this->assertEquals([$cancellation1, $cancellation2], $paymentMock->cancelAmount()); + } + /** * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. * From f3a762c033072252997f5f5a60b5e04449199f34 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 15:49:45 +0200 Subject: [PATCH 75/88] [cleanup] (PHPLIB-228) Cancel: Add unit test to verify certain exceptions are ignored cancelling charges. --- test/unit/Resources/PaymentCancelTest.php | 55 ++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index d17bb50f..d010ef15 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -31,6 +31,7 @@ use heidelpayPHP\Resources\TransactionTypes\Cancellation; use heidelpayPHP\Resources\TransactionTypes\Charge; use heidelpayPHP\test\BaseUnitTest; +use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Exception; use PHPUnit\Framework\MockObject\MockObject; use ReflectionException; @@ -205,6 +206,7 @@ public function cancelAmountShouldCallCancelAuthorizationAmount() * Verify that cancel amount will be cancelled on charges if auth does not exist. * * @test + * * @throws Exception * @throws HeidelpayApiException * @throws ReflectionException @@ -215,7 +217,6 @@ public function chargesShouldBeCancelledIfAuthDoesNotExist1() { /** @var MockObject|Payment $paymentMock */ /** @var MockObject|Charge $chargeMock */ - /** @var MockObject|Charge $charge2Mock */ $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAuthorizationAmount'])->getMock(); $chargeMock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->setConstructorArgs([10.0])->getMock(); @@ -232,6 +233,7 @@ public function chargesShouldBeCancelledIfAuthDoesNotExist1() * Verify that cancel amount will be cancelled on charges if auth does not exist. * * @test + * * @throws Exception * @throws HeidelpayApiException * @throws ReflectionException @@ -261,6 +263,40 @@ public function chargesShouldBeCancelledIfAuthDoesNotExist2() $this->assertEquals([$cancellation1, $cancellation2], $paymentMock->cancelAmount()); } + /** + * Verify certain errors are allowed during cancellation and will be ignored. + * + * @test + * @dataProvider verifyAllowedErrorsWillBeIgnoredDuringChargeCancelDP + * + * @param string $allowedExceptionCode + * + * @param bool $shouldHaveThrownException + * @throws Exception + * @throws ReflectionException + * @throws RuntimeException + * @throws AssertionFailedError + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancel($allowedExceptionCode, $shouldHaveThrownException) + { + /** @var MockObject|Payment $paymentMock */ + /** @var MockObject|Charge $chargeMock */ + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['cancelAuthorizationAmount'])->getMock(); + $chargeMock = $this->getMockBuilder(Charge::class)->setMethods(['cancel'])->disableOriginalConstructor()->getMock(); + + $allowedException = new HeidelpayApiException(null, null, $allowedExceptionCode); + $chargeMock->method('cancel')->willThrowException($allowedException); + $paymentMock->addCharge($chargeMock); + + try { + $this->assertEquals([], $paymentMock->cancelAmount(12.3)); + $this->assertFalse($shouldHaveThrownException, 'Exception should have been thrown here!'); + } catch (HeidelpayApiException $e) { + $this->assertTrue($shouldHaveThrownException, 'Exception should not have been thrown here!'); + } + } + /** * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. * @@ -346,4 +382,21 @@ public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherTha $this->assertSame($exception, $e); } } + + // + + /** + * @return array + */ + public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancelDP(): array + { + return [ + 'already cancelled' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], + 'already chargedBack' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], + 'already charged' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], + 'other' => [ApiResponseCodes::API_ERROR_BASKET_ITEM_IMAGE_INVALID_EXTENSION, true] + ]; + } + + // } From 0461db81fd531f571c1a4576e3758d36d78ce37d Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 15:55:23 +0200 Subject: [PATCH 76/88] [cleanup] (PHPLIB-228) Cancel: Add output to error message. --- test/unit/Resources/PaymentCancelTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index d010ef15..ca173729 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -293,7 +293,7 @@ public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancel($allowedExcep $this->assertEquals([], $paymentMock->cancelAmount(12.3)); $this->assertFalse($shouldHaveThrownException, 'Exception should have been thrown here!'); } catch (HeidelpayApiException $e) { - $this->assertTrue($shouldHaveThrownException, 'Exception should not have been thrown here!'); + $this->assertTrue($shouldHaveThrownException, "Exception should not have been thrown here! ({$e->getCode()})"); } } From 22adb12f2f211abe7cf9ff4c7f47b772cd66bedb Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 16:02:37 +0200 Subject: [PATCH 77/88] [cleanup] (PHPLIB-228) Cancel: Refactor cancelAuthorization method. --- src/Resources/Payment.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index f6b75fce..791e608a 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -775,20 +775,13 @@ public function cancelAllCharges(): array public function cancelAuthorization($amount = null): array { $cancels = []; - $exceptions = []; + $cancel = $this->cancelAuthorizationAmount($amount); - $authorization = $this->getAuthorization(); - if ($authorization instanceof Authorization) { - try { - $cancels[] = $authorization->cancel($amount); - } catch (HeidelpayApiException $e) { - if (ApiResponseCodes::API_ERROR_ALREADY_CANCELLED !== $e->getCode()) { - throw $e; - } - $exceptions[] = $e; - } + if ($cancel instanceof Cancellation) { + $cancels[] = $cancel; } - return array($cancels, $exceptions); + + return array($cancels, []); } /** From c697a8e07c68d441726fa52fb43bc52984b91b7c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 14 Oct 2019 17:01:53 +0200 Subject: [PATCH 78/88] [cleanup] (PHPLIB-228) Cancel: Add unit tests to verify auth cancel in payment class. --- src/Resources/Payment.php | 1 - test/unit/Resources/PaymentCancelTest.php | 85 ++++++++++++++--------- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 791e608a..59291e58 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -701,7 +701,6 @@ public function cancelAmount($totalCancelAmount = null, $reason = CancelReasonCo } catch (HeidelpayApiException $e) { $allowedErrors = [ ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, - ApiResponseCodes::API_ERROR_ALREADY_CHARGED, ApiResponseCodes::API_ERROR_ALREADY_CHARGED_BACK ]; diff --git a/test/unit/Resources/PaymentCancelTest.php b/test/unit/Resources/PaymentCancelTest.php index ca173729..f1705583 100644 --- a/test/unit/Resources/PaymentCancelTest.php +++ b/test/unit/Resources/PaymentCancelTest.php @@ -26,6 +26,7 @@ use heidelpayPHP\Constants\ApiResponseCodes; use heidelpayPHP\Exceptions\HeidelpayApiException; +use heidelpayPHP\Resources\EmbeddedResources\Amount; use heidelpayPHP\Resources\Payment; use heidelpayPHP\Resources\TransactionTypes\Authorization; use heidelpayPHP\Resources\TransactionTypes\Cancellation; @@ -42,7 +43,7 @@ class PaymentCancelTest extends BaseUnitTest // /** - * Verify payment:cancel calls cancelAllCharges and cancelAuthorization and returns first charge cancellation + * Verify payment:cancel calls cancelAllCharges and cancelAuthorizationAmount and returns first charge cancellation * object. * * @test @@ -267,11 +268,11 @@ public function chargesShouldBeCancelledIfAuthDoesNotExist2() * Verify certain errors are allowed during cancellation and will be ignored. * * @test - * @dataProvider verifyAllowedErrorsWillBeIgnoredDuringChargeCancelDP + * @dataProvider allowedErrorCodesDuringChargeCancel * * @param string $allowedExceptionCode + * @param bool $shouldHaveThrownException * - * @param bool $shouldHaveThrownException * @throws Exception * @throws ReflectionException * @throws RuntimeException @@ -298,7 +299,7 @@ public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancel($allowedExcep } /** - * Verify cancelAuthorization will call cancel on the authorization and will return a list of cancels. + * Verify cancelAuthorizationAmount will call cancel on the authorization and will return a list of cancels. * * @test * @@ -306,7 +307,7 @@ public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancel($allowedExcep * @throws ReflectionException * @throws RuntimeException */ - public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCancels() + public function cancelAuthorizationAmountShouldCallCancelOnTheAuthorizationAndReturnCancellation() { $cancellation = new Cancellation(1.0); $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); @@ -324,62 +325,71 @@ public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnCa } /** - * Verify cancelAuthorization will call cancel on the authorization and will return a list of exceptions. + * Verify cancelAuthorizationAmount will call cancel the given amount on the authorization of the payment. + * Cancellation amount will be the remaining amount of the payment at max. * * @test * + * @throws Exception * @throws HeidelpayApiException * @throws ReflectionException * @throws RuntimeException + * @throws \PHPUnit\Framework\MockObject\RuntimeException */ - public function cancelAuthorizationShouldCallCancelOnTheAuthorizationAndReturnExceptions() + public function cancelAuthorizationAmountShouldCallCancelWithTheRemainingAmountAtMax() { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_ALREADY_CANCELLED); + $cancellation = new Cancellation(); - $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); - $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); + /** @var MockObject|Authorization $authorizationMock */ + $authorizationMock = $this->getMockBuilder(Authorization::class)->setConstructorArgs([100.0])->setMethods(['cancel'])->getMock(); + $authorizationMock->expects($this->exactly(4))->method('cancel')->withConsecutive([null], [50.0], [100.0], [100.0])->willReturn($cancellation); - $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); + $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization', 'getAmount'])->getMock(); + $paymentMock->method('getAmount')->willReturn((new Amount())->setRemaining(100.0)); + $paymentMock->expects($this->exactly(4))->method('getAuthorization')->willReturn($authorizationMock); /** * @var Authorization $authorizationMock * @var Payment $paymentMock */ $paymentMock->setAuthorization($authorizationMock); - $this->assertNull($paymentMock->cancelAuthorizationAmount()); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount()); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount(50.0)); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount(100.0)); + $this->assertEquals($cancellation, $paymentMock->cancelAuthorizationAmount(101.0)); } /** - * Verify cancelAuthorization will throw any exception with Code different to - * ApiResponseCodes::API_ERROR_AUTHORIZATION_ALREADY_CANCELED. + * Verify certain errors are allowed during cancellation and will be ignored. * * @test + * @dataProvider allowedErrorCodesDuringAuthCancel + * + * @param string $allowedExceptionCode + * @param bool $shouldHaveThrownException * + * @throws Exception * @throws ReflectionException * @throws RuntimeException + * @throws AssertionFailedError + * @throws \PHPUnit\Framework\MockObject\RuntimeException */ - public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherThanAlreadyCharged() + public function verifyAllowedErrorsWillBeIgnoredDuringAuthorizeCancel($allowedExceptionCode, $shouldHaveThrownException) { - $exception = new HeidelpayApiException('', '', ApiResponseCodes::API_ERROR_CHARGED_AMOUNT_HIGHER_THAN_EXPECTED); - - $authorizationMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->getMock(); - $authorizationMock->expects($this->once())->method('cancel')->willThrowException($exception); - + /** @var MockObject|Payment $paymentMock */ + /** @var MockObject|Authorization $authMock */ $paymentMock = $this->getMockBuilder(Payment::class)->setMethods(['getAuthorization'])->getMock(); - $paymentMock->expects($this->once())->method('getAuthorization')->willReturn($authorizationMock); + $authMock = $this->getMockBuilder(Authorization::class)->setMethods(['cancel'])->disableOriginalConstructor()->getMock(); - /** - * @var Authorization $authorizationMock - * @var Payment $paymentMock - */ - $paymentMock->setAuthorization($authorizationMock); + $allowedException = new HeidelpayApiException(null, null, $allowedExceptionCode); + $authMock->method('cancel')->willThrowException($allowedException); + $paymentMock->method('getAuthorization')->willReturn($authMock); try { - $paymentMock->cancelAuthorizationAmount(); - $this->assertFalse(true, 'The expected exception has not been thrown.'); + $this->assertEquals(null, $paymentMock->cancelAuthorizationAmount(12.3)); + $this->assertFalse($shouldHaveThrownException, 'Exception should have been thrown here!'); } catch (HeidelpayApiException $e) { - $this->assertSame($exception, $e); + $this->assertTrue($shouldHaveThrownException, "Exception should not have been thrown here! ({$e->getCode()})"); } } @@ -388,12 +398,23 @@ public function cancelAllChargesShouldThrowAuthorizationCancelExceptionsOtherTha /** * @return array */ - public function verifyAllowedErrorsWillBeIgnoredDuringChargeCancelDP(): array + public function allowedErrorCodesDuringChargeCancel(): array { return [ 'already cancelled' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], 'already chargedBack' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], - 'already charged' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], + 'other' => [ApiResponseCodes::API_ERROR_BASKET_ITEM_IMAGE_INVALID_EXTENSION, true] + ]; + } + + /** + * @return array + */ + public function allowedErrorCodesDuringAuthCancel(): array + { + return [ + 'already cancelled' => [ApiResponseCodes::API_ERROR_ALREADY_CANCELLED, false], + 'already chargedBack' => [ApiResponseCodes::API_ERROR_ALREADY_CHARGED, false], 'other' => [ApiResponseCodes::API_ERROR_BASKET_ITEM_IMAGE_INVALID_EXTENSION, true] ]; } From e587a8011c42c7270bcd70f88341fe5038650d5c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 15 Oct 2019 08:41:50 +0200 Subject: [PATCH 79/88] [change] (PHPLIB-244) Amounts: Add rounding for float amounts to avoid more than 4 decimal places. --- src/Resources/Basket.php | 6 +++--- src/Resources/EmbeddedResources/BasketItem.php | 12 ++++++------ src/Resources/PaymentTypes/Paypage.php | 8 ++++---- src/Resources/TransactionTypes/Authorization.php | 2 +- src/Resources/TransactionTypes/Cancellation.php | 2 +- src/Resources/TransactionTypes/Charge.php | 2 +- src/Resources/TransactionTypes/Payout.php | 2 +- src/Resources/TransactionTypes/Shipment.php | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Resources/Basket.php b/src/Resources/Basket.php index d7e1a2f5..bfd65ee8 100755 --- a/src/Resources/Basket.php +++ b/src/Resources/Basket.php @@ -89,7 +89,7 @@ public function getAmountTotalGross(): float */ public function setAmountTotalGross(float $amountTotalGross): Basket { - $this->amountTotalGross = $amountTotalGross; + $this->amountTotalGross = round($amountTotalGross, 4); return $this; } @@ -132,7 +132,7 @@ public function getAmountTotalDiscount(): float */ public function setAmountTotalDiscount(float $amountTotalDiscount): Basket { - $this->amountTotalDiscount = $amountTotalDiscount; + $this->amountTotalDiscount = round($amountTotalDiscount, 4); return $this; } @@ -151,7 +151,7 @@ public function getAmountTotalVat(): float */ public function setAmountTotalVat(float $amountTotalVat): Basket { - $this->amountTotalVat = $amountTotalVat; + $this->amountTotalVat = round($amountTotalVat, 4); return $this; } diff --git a/src/Resources/EmbeddedResources/BasketItem.php b/src/Resources/EmbeddedResources/BasketItem.php index d24ef682..8834bfca 100755 --- a/src/Resources/EmbeddedResources/BasketItem.php +++ b/src/Resources/EmbeddedResources/BasketItem.php @@ -142,7 +142,7 @@ public function getVat(): float */ public function setVat(float $vat): BasketItem { - $this->vat = $vat; + $this->vat = round($vat, 4); return $this; } @@ -161,7 +161,7 @@ public function getAmountDiscount(): float */ public function setAmountDiscount(float $amountDiscount): BasketItem { - $this->amountDiscount = $amountDiscount; + $this->amountDiscount = round($amountDiscount, 4); return $this; } @@ -180,7 +180,7 @@ public function getAmountGross(): float */ public function setAmountGross(float $amountGross): BasketItem { - $this->amountGross = $amountGross; + $this->amountGross = round($amountGross, 4); return $this; } @@ -199,7 +199,7 @@ public function getAmountVat(): float */ public function setAmountVat(float $amountVat): BasketItem { - $this->amountVat = $amountVat; + $this->amountVat = round($amountVat, 4); return $this; } @@ -218,7 +218,7 @@ public function getAmountPerUnit(): float */ public function setAmountPerUnit(float $amountPerUnit): BasketItem { - $this->amountPerUnit = $amountPerUnit; + $this->amountPerUnit = round($amountPerUnit, 4); return $this; } @@ -237,7 +237,7 @@ public function getAmountNet(): float */ public function setAmountNet(float $amountNet): BasketItem { - $this->amountNet = $amountNet; + $this->amountNet = round($amountNet, 4); return $this; } diff --git a/src/Resources/PaymentTypes/Paypage.php b/src/Resources/PaymentTypes/Paypage.php index f62b2c82..7feb3234 100644 --- a/src/Resources/PaymentTypes/Paypage.php +++ b/src/Resources/PaymentTypes/Paypage.php @@ -101,9 +101,9 @@ class Paypage extends BasePaymentType */ public function __construct(float $amount, string $currency, string $returnUrl) { - $this->amount = $amount; - $this->currency = $currency; - $this->returnUrl = $returnUrl; + $this->setAmount($amount); + $this->setCurrency($currency); + $this->setReturnUrl($returnUrl); } // @@ -123,7 +123,7 @@ public function getAmount(): float */ public function setAmount(float $amount): Paypage { - $this->amount = $amount; + $this->amount = round($amount, 4); return $this; } diff --git a/src/Resources/TransactionTypes/Authorization.php b/src/Resources/TransactionTypes/Authorization.php index 08e7a761..5afa3259 100755 --- a/src/Resources/TransactionTypes/Authorization.php +++ b/src/Resources/TransactionTypes/Authorization.php @@ -83,7 +83,7 @@ public function getAmount() */ public function setAmount($amount): self { - $this->amount = $amount; + $this->amount = $amount !== null ? round($amount, 4) : null; return $this; } diff --git a/src/Resources/TransactionTypes/Cancellation.php b/src/Resources/TransactionTypes/Cancellation.php index 13a100a6..7ccf6cc3 100755 --- a/src/Resources/TransactionTypes/Cancellation.php +++ b/src/Resources/TransactionTypes/Cancellation.php @@ -74,7 +74,7 @@ public function getAmount() */ public function setAmount($amount): Cancellation { - $this->amount = $amount; + $this->amount = $amount !== null ? round($amount, 4) : null; return $this; } diff --git a/src/Resources/TransactionTypes/Charge.php b/src/Resources/TransactionTypes/Charge.php index 8cc60736..c486938e 100755 --- a/src/Resources/TransactionTypes/Charge.php +++ b/src/Resources/TransactionTypes/Charge.php @@ -94,7 +94,7 @@ public function getAmount() */ public function setAmount($amount): self { - $this->amount = $amount; + $this->amount = $amount !== null ? round($amount, 4) : null; return $this; } diff --git a/src/Resources/TransactionTypes/Payout.php b/src/Resources/TransactionTypes/Payout.php index 396bc087..0e138b4d 100644 --- a/src/Resources/TransactionTypes/Payout.php +++ b/src/Resources/TransactionTypes/Payout.php @@ -75,7 +75,7 @@ public function getAmount() */ public function setAmount($amount): self { - $this->amount = $amount; + $this->amount = $amount !== null ? round($amount, 4) : null; return $this; } diff --git a/src/Resources/TransactionTypes/Shipment.php b/src/Resources/TransactionTypes/Shipment.php index 389fe585..a9fd4d3f 100755 --- a/src/Resources/TransactionTypes/Shipment.php +++ b/src/Resources/TransactionTypes/Shipment.php @@ -30,7 +30,7 @@ class Shipment extends AbstractTransactionType { use HasInvoiceId; - /** @var float $amount */ + /** @var float|null $amount */ protected $amount; // @@ -48,9 +48,9 @@ public function getAmount() * * @return Shipment */ - public function setAmount(float $amount): Shipment + public function setAmount($amount): Shipment { - $this->amount = $amount; + $this->amount = $amount !== null ? round($amount, 4) : null; return $this; } From ca0e14f1112d805a5b0602a981a8feb5aff23bee Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 15 Oct 2019 09:56:06 +0200 Subject: [PATCH 80/88] [change] (PHPLIB-446) KeyPair: Refactor keypair functionality. Add additional properties to keypair resource. Add functionality to set a test key pair via environment variable. Removed assertions which can lead to errors even when everything works well. Update changelog. --- CHANGELOG.md | 2 ++ src/Resources/Keypair.php | 44 +++++++++++++++++++++++++++++ src/Services/EnvironmentService.php | 23 +++++++++++++++ test/BasePaymentTest.php | 12 ++------ test/integration/KeypairTest.php | 5 ---- 5 files changed, 72 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 238d1cf9..685d088a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a * Charge methods `getCancelledAmount` and `getTotalAmount`. * Authorize method `getCancelledAmount`. * Detailed `keypair` fetch. +* Added properties to keypair resource. ### Fixed * Problem with HeidelpayApiException. @@ -23,6 +24,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a * Adapted integration tests with basket to changes in API. * Refactor deprecation notices. * Refactored and extended unit tests. +* Test keypair can now be set via environment variables. ## [1.2.2.0][1.2.2.0] diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index f1757c88..3466f669 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -53,6 +53,12 @@ class Keypair extends AbstractHeidelpayResource /** @var string $merchantAddress */ private $merchantAddress; + /** @var bool $cof */ + private $cof; + + /** @var bool $validateBasket */ + private $validateBasket; + // /** @@ -214,6 +220,44 @@ public function setDetailed(bool $detailed): Keypair return $this; } + /** + * @return bool + */ + public function isCof(): bool + { + return $this->cof; + } + + /** + * @param bool $cof + * + * @return Keypair + */ + public function setCof(bool $cof): Keypair + { + $this->cof = $cof; + return $this; + } + + /** + * @return bool + */ + public function isValidateBasket(): bool + { + return $this->validateBasket; + } + + /** + * @param bool $validateBasket + * + * @return Keypair + */ + public function setValidateBasket(bool $validateBasket): Keypair + { + $this->validateBasket = $validateBasket; + return $this; + } + // // diff --git a/src/Services/EnvironmentService.php b/src/Services/EnvironmentService.php index e0bb9a0a..6dfafba2 100755 --- a/src/Services/EnvironmentService.php +++ b/src/Services/EnvironmentService.php @@ -33,6 +33,11 @@ class EnvironmentService const ENV_VAR_NAME_DISABLE_TEST_LOGGING = 'HEIDELPAY_MGW_DISABLE_TEST_LOGGING'; + const ENV_VAR_TEST_PRIVATE_KEY = 'HEIDELPAY_MGW_TEST_PRIVATE_KEY'; + const ENV_VAR_TEST_PUBLIC_KEY = 'HEIDELPAY_MGW_TEST_PUBLIC_KEY'; + const DEFAULT_TEST_PRIVATE_KEY = 's-priv-2a102ZMq3gV4I3zJ888J7RR6u75oqK3n'; + const DEFAULT_TEST_PUBLIC_KEY = 's-pub-2a10ifVINFAjpQJ9qW8jBe5OJPBx6Gxa'; + const ENV_VAR_NAME_TIMEOUT = 'HEIDELPAY_MGW_TIMEOUT'; const ENV_VAR_DEFAULT_TIMEOUT = 60; @@ -68,4 +73,22 @@ public static function getTimeout(): int $timeout = $_SERVER[self::ENV_VAR_NAME_TIMEOUT] ?? ''; return is_numeric($timeout) ? (int)$timeout : self::ENV_VAR_DEFAULT_TIMEOUT; } + + /** + * @return string|null + */ + public function getTestPrivateKey() + { + $key = $_SERVER[self::ENV_VAR_TEST_PRIVATE_KEY] ?? ''; + return empty($key) ? self::DEFAULT_TEST_PRIVATE_KEY : $key; + } + + /** + * @return string|null + */ + public function getTestPublicKey() + { + $key = $_SERVER[self::ENV_VAR_TEST_PUBLIC_KEY] ?? ''; + return empty($key) ? self::DEFAULT_TEST_PUBLIC_KEY : $key; + } } diff --git a/test/BasePaymentTest.php b/test/BasePaymentTest.php index c003222f..3edd9fdc 100755 --- a/test/BasePaymentTest.php +++ b/test/BasePaymentTest.php @@ -36,6 +36,7 @@ use heidelpayPHP\Resources\TransactionTypes\AbstractTransactionType; use heidelpayPHP\Resources\TransactionTypes\Authorization; use heidelpayPHP\Resources\TransactionTypes\Charge; +use heidelpayPHP\Services\EnvironmentService; use heidelpayPHP\test\Fixtures\CustomerFixtureTrait; use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Exception; @@ -52,13 +53,6 @@ class BasePaymentTest extends TestCase const RETURN_URL = 'http://dev.heidelpay.com'; - // SAQ-D certified merchants are allowed to handle and store CreditCard data, - // thus can create a CreditCard via this SDK. - // If the merchant is not certified to handle the CreditCard data SAQ-A applies - // in which case the merchant has to embed our iFrame via JS (UIComponents). - const PRIVATE_KEY = 's-priv-2a102ZMq3gV4I3zJ888J7RR6u75oqK3n'; - const PUBLIC_KEY = 's-pub-2a10ifVINFAjpQJ9qW8jBe5OJPBx6Gxa'; - /** * {@inheritDoc} * @@ -66,8 +60,8 @@ class BasePaymentTest extends TestCase */ protected function setUp() { - $this->heidelpay = (new Heidelpay(self::PRIVATE_KEY)) - ->setDebugHandler(new TestDebugHandler())->setDebugMode(true); + $privateKey = (new EnvironmentService())->getTestPrivateKey(); + $this->heidelpay = (new Heidelpay($privateKey))->setDebugHandler(new TestDebugHandler())->setDebugMode(true); } // diff --git a/test/integration/KeypairTest.php b/test/integration/KeypairTest.php index 826284ba..f1cdcc8f 100644 --- a/test/integration/KeypairTest.php +++ b/test/integration/KeypairTest.php @@ -78,8 +78,6 @@ public function keypairShouldReturnExpectedValues() $this->assertNotEmpty($keypair->getPublicKey()); $this->assertNotEmpty($keypair->getPrivateKey()); $this->assertNotEmpty($keypair->getAvailablePaymentTypes()); - $this->assertNotEmpty($keypair->getMerchantAddress()); - $this->assertNotEmpty($keypair->getMerchantName()); $this->assertNotEmpty($keypair->getSecureLevel()); } @@ -98,9 +96,6 @@ public function keypairShouldBeFetchableWithDetails() $this->assertNotEmpty($keypair->getPublicKey()); $this->assertNotEmpty($keypair->getPrivateKey()); $this->assertNotEmpty($keypair->getPaymentTypes()); - $this->assertNotEmpty($keypair->getAlias()); - $this->assertNotEmpty($keypair->getMerchantAddress()); - $this->assertNotEmpty($keypair->getMerchantName()); $this->assertNotEmpty($keypair->getSecureLevel()); } } From 9d66be6d563191f57c22d3d17d2df0ce171f426a Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 16 Oct 2019 16:13:23 +0200 Subject: [PATCH 81/88] [change] (PHPLIB-246) Add comment to explain abbreviation. --- src/Resources/Keypair.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 3466f669..1279ab73 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -53,7 +53,12 @@ class Keypair extends AbstractHeidelpayResource /** @var string $merchantAddress */ private $merchantAddress; - /** @var bool $cof */ + /** + * Credentials on File / Card on File + * If true the credentials are stored for future transactions. + * + * @var bool $cof + */ private $cof; /** @var bool $validateBasket */ From be0997570a457098683c98ebed6a6e3731dc4166 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 16 Oct 2019 16:17:03 +0200 Subject: [PATCH 82/88] [change] (PHPLIB-228) Fix doc comment describing return value of Payment::cancelAmount method. --- src/Resources/Payment.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Resources/Payment.php b/src/Resources/Payment.php index 59291e58..c9227339 100755 --- a/src/Resources/Payment.php +++ b/src/Resources/Payment.php @@ -658,8 +658,7 @@ public function cancel($amount = null, $reason = CancelReasonCodes::REASON_CODE_ * @param float|null $totalCancelAmount The amount to canceled. * @param string $reason * - * @return Cancellation[] The resulting Cancellation object. - * If more then one cancellation is performed the last one will be returned. + * @return Cancellation[] An array holding all Cancellation objects created with this cancel call. * * @throws HeidelpayApiException A HeidelpayApiException is thrown if there is an error returned on API-request. * @throws RuntimeException A RuntimeException is thrown when there is a error while using the SDK. From 9d4f61a2f0f0fba64736b735f4631dd7b7267175 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 16 Oct 2019 16:36:06 +0200 Subject: [PATCH 83/88] [change] (PHPLIB-246) Add return type and description to methods in environment service. --- src/Services/EnvironmentService.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Services/EnvironmentService.php b/src/Services/EnvironmentService.php index 6dfafba2..4a43f2e7 100755 --- a/src/Services/EnvironmentService.php +++ b/src/Services/EnvironmentService.php @@ -75,18 +75,24 @@ public static function getTimeout(): int } /** - * @return string|null + * Returns the private key string set via environment variable. + * Returns the default key if the environment variable is not set. + * + * @return string */ - public function getTestPrivateKey() + public function getTestPrivateKey(): string { $key = $_SERVER[self::ENV_VAR_TEST_PRIVATE_KEY] ?? ''; return empty($key) ? self::DEFAULT_TEST_PRIVATE_KEY : $key; } /** - * @return string|null + * Returns the public key string set via environment variable. + * Returns the default key if the environment variable is not set. + * + * @return string */ - public function getTestPublicKey() + public function getTestPublicKey(): string { $key = $_SERVER[self::ENV_VAR_TEST_PUBLIC_KEY] ?? ''; return empty($key) ? self::DEFAULT_TEST_PUBLIC_KEY : $key; From 403862d6e7f4727f37a349596243c1001ff24df5 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Wed, 16 Oct 2019 16:41:59 +0200 Subject: [PATCH 84/88] [change] (PHPLIB-246) Fix type declarations, comments and accessibility modifiers. --- src/Resources/Keypair.php | 14 ++++++++------ test/unit/Resources/KeypairTest.php | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 1279ab73..bccae4a9 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -57,7 +57,7 @@ class Keypair extends AbstractHeidelpayResource * Credentials on File / Card on File * If true the credentials are stored for future transactions. * - * @var bool $cof + * @var bool|null $cof */ private $cof; @@ -219,16 +219,18 @@ public function isDetailed(): bool * * @return Keypair */ - public function setDetailed(bool $detailed): Keypair + protected function setDetailed(bool $detailed): Keypair { $this->detailed = $detailed; return $this; } /** - * @return bool + * Returns true if Credentials are stored for later transactions. + * + * @return bool|null */ - public function isCof(): bool + public function isCof() { return $this->cof; } @@ -238,7 +240,7 @@ public function isCof(): bool * * @return Keypair */ - public function setCof(bool $cof): Keypair + protected function setCof(bool $cof): Keypair { $this->cof = $cof; return $this; @@ -257,7 +259,7 @@ public function isValidateBasket(): bool * * @return Keypair */ - public function setValidateBasket(bool $validateBasket): Keypair + protected function setValidateBasket(bool $validateBasket): Keypair { $this->validateBasket = $validateBasket; return $this; diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 2c6c0b2e..cddca240 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -49,6 +49,7 @@ public function gettersAndSettersWorkAsExpected() $this->assertNull($keypair->getPrivateKey()); $this->assertEmpty($keypair->getPaymentTypes()); $this->assertSame($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); + $this->assertFalse($keypair->isCof()); $this->assertEquals('', $keypair->getSecureLevel()); $this->assertEquals('', $keypair->getMerchantName()); $this->assertEquals('', $keypair->getMerchantAddress()); From 2b59c33970736773fa5720b63f96511f228a3789 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 17 Oct 2019 10:08:41 +0200 Subject: [PATCH 85/88] [bugfix] (PHPLIB-247) Customer: Customer cannot be created implicitly if the ext.Id is set. --- test/integration/CustomerTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/integration/CustomerTest.php b/test/integration/CustomerTest.php index 590fb2eb..c42da02f 100755 --- a/test/integration/CustomerTest.php +++ b/test/integration/CustomerTest.php @@ -32,8 +32,8 @@ use heidelpayPHP\Resources\Payment; use heidelpayPHP\Resources\PaymentTypes\Paypal; use heidelpayPHP\test\BasePaymentTest; -use function microtime; use RuntimeException; +use function microtime; class CustomerTest extends BasePaymentTest { @@ -162,7 +162,8 @@ public function customerCanBeFetchedByObjectWithData(Customer $customer) */ public function transactionShouldCreateAndReferenceCustomerIfItDoesNotExistYet() { - $customer = $this->getMaximumCustomerInclShippingAddress(); + $customerId = 'customer' . $this->generateRandomId(); + $customer = $this->getMaximumCustomerInclShippingAddress()->setCustomerId($customerId); /** @var Paypal $paypal */ $paypal = $this->heidelpay->createPaymentType(new Paypal()); From e15cc1a812f8e2baa2a239341c7915ed337259e1 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 17 Oct 2019 10:09:48 +0200 Subject: [PATCH 86/88] [bugfix] (PHPLIB-247) Customer: Fix customer to be created implicitly on transaction. --- src/Resources/AbstractHeidelpayResource.php | 26 +++++++++++---------- test/unit/Resources/CustomerTest.php | 1 - test/unit/Services/ResourceServiceTest.php | 1 - 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Resources/AbstractHeidelpayResource.php b/src/Resources/AbstractHeidelpayResource.php index e0c5c488..1a743056 100755 --- a/src/Resources/AbstractHeidelpayResource.php +++ b/src/Resources/AbstractHeidelpayResource.php @@ -24,7 +24,6 @@ */ namespace heidelpayPHP\Resources; -use function count; use DateTime; use heidelpayPHP\Adapter\HttpAdapterInterface; use heidelpayPHP\Exceptions\HeidelpayApiException; @@ -32,13 +31,14 @@ use heidelpayPHP\Interfaces\HeidelpayParentInterface; use heidelpayPHP\Services\ResourceNameService; use heidelpayPHP\Services\ResourceService; -use function is_array; -use function is_callable; -use function is_object; use ReflectionException; use ReflectionProperty; use RuntimeException; use stdClass; +use function count; +use function is_array; +use function is_callable; +use function is_object; abstract class AbstractHeidelpayResource implements HeidelpayParentInterface { @@ -54,15 +54,13 @@ abstract class AbstractHeidelpayResource implements HeidelpayParentInterface // /** - * {@inheritDoc} + * Returns the id of this resource. + * + * @return string|null */ public function getId() { - $resourceId = $this->id; - if ($resourceId === null) { - $resourceId = $this->getExternalId(); - } - return $resourceId; + return $this->id; } /** @@ -145,8 +143,12 @@ public function getHeidelpayObject(): Heidelpay public function getUri($appendId = true): string { $uri = [rtrim($this->getParentResource()->getUri(), '/'), $this->getResourcePath()]; - if ($appendId && $this->getId() !== null) { - $uri[] = $this->getId(); + if ($appendId) { + if ($this->getId() !== null) { + $uri[] = $this->getId(); + } elseif ($this->getExternalId() !== null) { + $uri[] = $this->getExternalId(); + } } $uri[] = ''; diff --git a/test/unit/Resources/CustomerTest.php b/test/unit/Resources/CustomerTest.php index efb8253c..c4cc0f3d 100755 --- a/test/unit/Resources/CustomerTest.php +++ b/test/unit/Resources/CustomerTest.php @@ -264,7 +264,6 @@ public function fetchCustomerByOrderIdShouldCreateCustomerObjectWithCustomerIdAn static function ($customer) use ($heidelpay) { return $customer instanceof Customer && $customer->getCustomerId() === 'myCustomerId' && - $customer->getId() === 'myCustomerId' && $customer->getHeidelpayObject() === $heidelpay; })); diff --git a/test/unit/Services/ResourceServiceTest.php b/test/unit/Services/ResourceServiceTest.php index 6fcb4249..b646736f 100755 --- a/test/unit/Services/ResourceServiceTest.php +++ b/test/unit/Services/ResourceServiceTest.php @@ -407,7 +407,6 @@ public function fetchPaymentByOrderIdShouldCreatePaymentObjectWithOrderIdAndCall static function ($payment) use ($heidelpay) { return $payment instanceof Payment && $payment->getOrderId() === 'myOrderId' && - $payment->getId() === 'myOrderId' && $payment->getHeidelpayObject() === $heidelpay; })); From 0b1a3a0e2e8d2452251df1e0275cc61dce716db2 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 17 Oct 2019 10:20:35 +0200 Subject: [PATCH 87/88] [change] (PHPLIB-246) Customer: Fix keypair class. --- src/Resources/Keypair.php | 2 +- test/unit/Resources/KeypairTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index bccae4a9..1775e7b5 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -219,7 +219,7 @@ public function isDetailed(): bool * * @return Keypair */ - protected function setDetailed(bool $detailed): Keypair + public function setDetailed(bool $detailed): Keypair { $this->detailed = $detailed; return $this; diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index cddca240..d1d3f29a 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -49,7 +49,7 @@ public function gettersAndSettersWorkAsExpected() $this->assertNull($keypair->getPrivateKey()); $this->assertEmpty($keypair->getPaymentTypes()); $this->assertSame($keypair->getPaymentTypes(), $keypair->getAvailablePaymentTypes()); - $this->assertFalse($keypair->isCof()); + $this->assertNull($keypair->isCof()); $this->assertEquals('', $keypair->getSecureLevel()); $this->assertEquals('', $keypair->getMerchantName()); $this->assertEquals('', $keypair->getMerchantAddress()); From 65ee218326a03bbc09c818e7a14e326eb3fabfb6 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 17 Oct 2019 10:33:55 +0200 Subject: [PATCH 88/88] [change] (PHPLIB-246) Customer: Update Changelog. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 685d088a..28da3b5c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a * Added properties to keypair resource. ### Fixed -* Problem with HeidelpayApiException. +* A problem with HeidelpayApiException. +* A problem which resulted in an error when trying to create a `customer` implicitly with a transaction when its `customerId` was set. ### Changed * Replaced unreliable `Payment::cancel()` method with `Payment::cancelAmount()` which takes multiple cancellation scenarios into account.