diff --git a/CHANGELOG.md b/CHANGELOG.md index 370059e9..491a69fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,12 @@ # Changelog -## Latest Version - v11.0.4 (12/07/23) +## Latest Version - v11.0.5 (01/09/24) +#### Bug Fixes: +- [Portico] Fixed null CustomerData exception +- [A35_PAX] Fixed long transaction processing times + +## v11.0.4 (12/07/23) ### Enhancements: - [GP-API] Add QR code payment example with Alipay - [GP-API] File Processing diff --git a/metadata.xml b/metadata.xml index d4dc702e..6d797f74 100644 --- a/metadata.xml +++ b/metadata.xml @@ -1,3 +1,3 @@ - 11.0.4 + 11.0.5 \ No newline at end of file diff --git a/src/Gateways/PorticoConnector.php b/src/Gateways/PorticoConnector.php index a889b933..41adaf9d 100644 --- a/src/Gateways/PorticoConnector.php +++ b/src/Gateways/PorticoConnector.php @@ -252,7 +252,7 @@ public function processAuthorization(AuthorizationBuilder $builder) $isCheck || $builder->billingAddress !== null || isset($builder->paymentMethod->{$propertyName}) - || $builder->customerData->email !== null + || ($builder->customerData !== null && $builder->customerData->email !== null) ) { if ($builder->transactionType !== TransactionType::REVERSAL) { $holder = $this->hydrateHolder($xml, $builder, $isCheck); @@ -2059,12 +2059,12 @@ protected function normalizeResponse($input) * Serializes builder information into XML * * @param DOMDocument $xml XML instance - * @param BaseBuilder $builder Request builder + * @param AuthorizationBuilder $builder Request builder * @param bool $isCheck If payment method is ACH * * @return DOMElement */ - protected function hydrateHolder(DOMDocument $xml, BaseBuilder $builder, $isCheck = false) + protected function hydrateHolder(DOMDocument $xml, AuthorizationBuilder $builder, $isCheck = false) { $address = new Address(); $holder = $xml->createElement($isCheck ? 'ConsumerInfo' : 'CardHolderData'); @@ -2088,7 +2088,7 @@ protected function hydrateHolder(DOMDocument $xml, BaseBuilder $builder, $isChec ); } - if ($builder->customerData->email !== null) { + if ($builder->customerData !== null && $builder->customerData->email !== null) { $holder->appendChild( $xml->createElement($isCheck ? 'EmailAddress' : 'CardHolderEmail',$builder->customerData->email)); } diff --git a/src/Terminals/PAX/Interfaces/PaxTcpInterface.php b/src/Terminals/PAX/Interfaces/PaxTcpInterface.php index c4465063..c0a2f1d6 100644 --- a/src/Terminals/PAX/Interfaces/PaxTcpInterface.php +++ b/src/Terminals/PAX/Interfaces/PaxTcpInterface.php @@ -195,18 +195,38 @@ private function getTerminalResponse() } } - private function awaitResponse($readString = false) + /** + * + * @param bool $readString + * @return string + * @throws GatewayException + */ + private function awaitResponse(bool $readString = false) : string { $startTime = time(); + do { - $part = ($readString === true) ? fgets($this->tcpConnection) : fgetc($this->tcpConnection); - if (!empty($part)) { - if ($readString) { - return substr($part, 0, strpos($part, chr(0x03)) + 2); - } - return $part; + if ($readString) { + $buffer = ''; + + do { + $buffer = $buffer . fgetc($this->tcpConnection); + + if ( + strpos($buffer, chr(0x03)) + && strlen($buffer) === strpos($buffer, chr(0x03)) + 2 + ) + break; + } while (true); + } else { + $buffer = fgetc($this->tcpConnection); } + + if (!empty($buffer)) + return $buffer; + $timeDiff = time() - $startTime; + if ($timeDiff >= $this->deviceDetails->timeout) { break; } diff --git a/src/Terminals/PAX/Responses/PaxTerminalResponse.php b/src/Terminals/PAX/Responses/PaxTerminalResponse.php index c98aa38c..632af0d0 100644 --- a/src/Terminals/PAX/Responses/PaxTerminalResponse.php +++ b/src/Terminals/PAX/Responses/PaxTerminalResponse.php @@ -53,6 +53,7 @@ class PaxTerminalResponse extends PaxBaseResponse implements IDeviceResponseHand public $taxExemptId; public $ticketNumber; public $paymentType; + public $transactionNumber; // EMV /* diff --git a/test/Integration/Gateways/PorticoConnector/Certifications/EcommerceTest.php b/test/Integration/Gateways/PorticoConnector/Certifications/EcommerceTest.php index eda6615c..afd59a58 100644 --- a/test/Integration/Gateways/PorticoConnector/Certifications/EcommerceTest.php +++ b/test/Integration/Gateways/PorticoConnector/Certifications/EcommerceTest.php @@ -36,6 +36,8 @@ use PHPUnit\Framework\TestCase; use GlobalPayments\Api\ServiceConfigs\Gateways\PorticoConfig; use GlobalPayments\Api\Services\{BatchService, ReportingService}; +use SebastianBergmann\RecursionContext\InvalidArgumentException; +use PHPUnit\Framework\ExpectationFailedException; class TestCards { @@ -2134,6 +2136,7 @@ public function testCardHolderEmail() $response = $card->charge() ->withCurrency('USD') + ->withAllowDuplicates(true) ->withCustomerData($customerData) ->withAddress($address) ->withAmount(15.01) @@ -2147,6 +2150,40 @@ public function testCardHolderEmail() $this->assertEquals($customerEmail, $transactionSummary->email); } + /** + * + * @return void + * @throws ApiException + * @throws InvalidArgumentException + * @throws ExpectationFailedException + * + * This will verify an empty string can be returned + * for email property in TransactionSummary object + */ + public function testCardHolderEmailWithoutEmail() + { + $customerEmail = ''; + $address = new Address(); + $address->streetAddress1 = '6860 Dallas Pkwy'; + $address->postalCode = '75024'; + + $card = TestCards::visaManual(); + + $response = $card->charge() + ->withCurrency('USD') + ->withAllowDuplicates(true) + ->withAddress($address) + ->withAmount(15.01) + ->execute(); + + $this->assertEquals(true, $response != null); + $this->assertEquals('00', $response->responseCode); + + $transactionSummary = ReportingService::transactionDetail($response->transactionId)->execute(); + $this->assertNotNull($transactionSummary); + $this->assertEquals($customerEmail, $transactionSummary->email); + } + /** * * @param string $pubKey