diff --git a/CHANGELOG.md b/CHANGELOG.md index cd485ff..a97d714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ # Changelog -## Latest Version - v12.0.5 (06/07/24) +## Latest Version - v12.0.5 (06/18/24) +### Enhancements: +- [GP-ECOM] Add Multi-Capture + +## v12.0.5 (06/07/24) ### Bug Fixes: - [PAX] Corrected "partial auth" response handling - [GP-ECOM] Add HPP additional field "HPP_REMOVE_SHIPPING" diff --git a/metadata.xml b/metadata.xml index 59f1863..6948c85 100644 --- a/metadata.xml +++ b/metadata.xml @@ -1,3 +1,3 @@ - 12.0.5 + 12.0.6 \ No newline at end of file diff --git a/src/Builders/AuthorizationBuilder.php b/src/Builders/AuthorizationBuilder.php index cad2dd6..762c60c 100644 --- a/src/Builders/AuthorizationBuilder.php +++ b/src/Builders/AuthorizationBuilder.php @@ -1360,9 +1360,12 @@ public function withLastRegisteredDate($date) * * @return $this */ - public function withMultiCapture($multiCapture = false) + public function withMultiCapture(bool $multiCapture = false, int $paymentCount = 1) : AuthorizationBuilder { $this->multiCapture = $multiCapture; + if ($multiCapture === true) { + $this->multiCapturePaymentCount = $paymentCount; + } return $this; } diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php index ebc30b3..5b43251 100644 --- a/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomAuthorizationRequestBuilder.php @@ -88,11 +88,17 @@ public function buildRequest(BaseBuilder $builder, $config) // This needs to be figured out based on txn type and set to 0, 1 or MULTI if ($builder->transactionType === TransactionType::SALE || $builder->transactionType == TransactionType::AUTH) { - $autoSettle = $builder->transactionType === TransactionType::SALE ? "1" : "0"; + $autoSettle = $builder->transactionType === TransactionType::SALE ? "1" : ($builder->multiCapture === true ? "MULTI" :"0"); $element = $xml->createElement("autosettle"); $element->setAttribute("flag", $autoSettle); $request->appendChild($element); } + if ( + $builder->transactionType == TransactionType::AUTH && + !empty($builder->multiCapturePaymentCount) + ) { + $request->appendChild($xml->createElement("estnumtxn", $builder->multiCapturePaymentCount)); + } $request->appendChild($xml->createElement("orderid", $orderId)); if (isset($builder->surchargeAmount)) { diff --git a/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php b/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php index af2befc..b298dd8 100644 --- a/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php +++ b/src/Builders/RequestBuilder/GpEcom/GpEcomManagementRequestBuilder.php @@ -6,6 +6,7 @@ use GlobalPayments\Api\Builders\BaseBuilder; use GlobalPayments\Api\Builders\ManagementBuilder; use GlobalPayments\Api\Entities\Enums\AlternativePaymentType; +use GlobalPayments\Api\Entities\Enums\RecurringSequence; use GlobalPayments\Api\Entities\Enums\TransactionType; use GlobalPayments\Api\Entities\Exceptions\BuilderException; use GlobalPayments\Api\Entities\IRequestBuilder; @@ -58,7 +59,9 @@ public function buildRequest(BaseBuilder $builder, $config) if ($builder->amount !== null) { $amount = $xml->createElement("amount", preg_replace('/[^0-9]/', '', sprintf('%01.2f', $builder->amount))); - $amount->setAttribute("currency", $builder->currency ?? ''); + if (!empty($builder->currency)) { + $amount->setAttribute("currency", $builder->currency); + } $request->appendChild($amount); } elseif ($builder->transactionType === TransactionType::CAPTURE) { throw new BuilderException("Amount cannot be null for capture."); @@ -74,12 +77,21 @@ public function buildRequest(BaseBuilder $builder, $config) } $request->appendChild($xml->createElement("pasref", $builder->transactionId ?? '')); - // rebate hash - if ($builder->transactionType === TransactionType::REFUND && - is_null($builder->alternativePaymentType)) { + if ( + ($builder->transactionType === TransactionType::REFUND && is_null($builder->alternativePaymentType)) || + ($builder->multiCapture === true)) { $request->appendChild($xml->createElement("authcode", $builder->paymentMethod->authCode ?? '')); } + if ($builder->multiCapture === true) { + $isFinal = ($builder->multiCaptureSequence == RecurringSequence::LAST ? 1 : 0); + $txnseq = $xml->createElement("txnseq"); + $final = $xml->createElement("final"); + $final->setAttribute('flag', $isFinal); + $txnseq->appendChild($final); + $request->appendChild($txnseq); + } + // reason code if ($builder->reasonCode !== null) { $request->appendChild($xml->createElement("reasoncode", $builder->reasonCode ?? '')); diff --git a/src/Mapping/GpEcomMapping.php b/src/Mapping/GpEcomMapping.php index 3ee8890..f652b13 100644 --- a/src/Mapping/GpEcomMapping.php +++ b/src/Mapping/GpEcomMapping.php @@ -341,6 +341,9 @@ public static function mapManageRequestType(ManagementBuilder $builder) { switch ($builder->transactionType) { case TransactionType::CAPTURE: + if ($builder->multiCapture === true) { + return 'multisettle'; + } return 'settle'; case TransactionType::HOLD: return 'hold'; diff --git a/test/Integration/Gateways/GpEcomConnector/CreditTest.php b/test/Integration/Gateways/GpEcomConnector/CreditTest.php index 69a3467..fd2e01c 100644 --- a/test/Integration/Gateways/GpEcomConnector/CreditTest.php +++ b/test/Integration/Gateways/GpEcomConnector/CreditTest.php @@ -6,6 +6,7 @@ use GlobalPayments\Api\Entities\Enums\CreditDebitIndicator; use GlobalPayments\Api\Entities\Enums\DccProcessor; use GlobalPayments\Api\Entities\Enums\DccRateType; +use GlobalPayments\Api\Entities\Enums\RecurringSequence; use GlobalPayments\Api\Entities\Exceptions\GatewayException; use GlobalPayments\Api\PaymentMethods\CreditCardData; use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig; @@ -378,4 +379,35 @@ public function testCreditChargeWithExceededSurchargeAmount() $this->assertTrue($exceptionCaught); } } + public function testMultiCapture() + { + $transaction = $this->card->authorize(30) + ->withCurrency('EUR') + ->withMultiCapture(true, 3) + ->execute(); + + $this->assertNotNull($transaction); + $this->assertEquals('00', $transaction->responseCode); + + $capture1 = $transaction->capture(10) + ->withMultiCapture(RecurringSequence::FIRST) + ->execute(); + + $this->assertNotNull($capture1); + $this->assertEquals('00', $capture1->responseCode); + + $capture2 = $transaction->capture(10) + ->withMultiCapture(RecurringSequence::SUBSEQUENT) + ->execute(); + + $this->assertNotNull($capture2); + $this->assertEquals('00', $capture2->responseCode); + + $capture3 = $transaction->capture(10) + ->withMultiCapture(RecurringSequence::LAST) + ->execute(); + + $this->assertNotNull($capture3); + $this->assertEquals('00', $capture3->responseCode); + } }