diff --git a/src/DataMapper/ResponseDataMapper/InterPosResponseDataMapper.php b/src/DataMapper/ResponseDataMapper/InterPosResponseDataMapper.php index 4be8bea9..41435167 100644 --- a/src/DataMapper/ResponseDataMapper/InterPosResponseDataMapper.php +++ b/src/DataMapper/ResponseDataMapper/InterPosResponseDataMapper.php @@ -70,7 +70,7 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen { return $this->map3DCommonResponseData( $raw3DAuthResponseData, - $raw3DAuthResponseData, + $rawPaymentResponseData, $txType, PosInterface::MODEL_3D_SECURE ); @@ -306,13 +306,17 @@ private function map3DPaymentResponse(?array $rawPaymentResponseData, string $tx $result['proc_return_code'] = $procReturnCode; $result['status'] = $status; $result['status_detail'] = $this->getStatusDetail($procReturnCode); - $result['all'] = $rawPaymentResponseData; $result['order_id'] = $rawPaymentResponseData['OrderId']; $result['transaction_id'] = $rawPaymentResponseData['TransId']; $result['auth_code'] = $rawPaymentResponseData['AuthCode']; $result['ref_ret_num'] = $rawPaymentResponseData['HostRefNum']; $result['error_code'] = $rawPaymentResponseData['ErrorCode']; $result['error_message'] = $rawPaymentResponseData['ErrorMessage']; + $result['all'] = $rawPaymentResponseData; + + if (self::TX_APPROVED === $result['status']) { + $result['transaction_time'] = new \DateTimeImmutable($rawPaymentResponseData['TRXDATE']); + } $this->logger->debug('mapped payment response', $result); diff --git a/tests/Unit/DataMapper/ResponseDataMapper/InterPosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/InterPosResponseDataMapperTest.php index df281cf3..384025b3 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/InterPosResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/InterPosResponseDataMapperTest.php @@ -7,6 +7,7 @@ use Mews\Pos\DataMapper\RequestDataMapper\InterPosRequestDataMapper; use Mews\Pos\DataMapper\ResponseDataMapper\InterPosResponseDataMapper; +use Mews\Pos\Exceptions\NotImplementedException; use Mews\Pos\Factory\CryptFactory; use Mews\Pos\Gateways\InterPos; use Mews\Pos\PosInterface; @@ -89,6 +90,16 @@ public function testMap3DPaymentData(array $order, string $txType, array $threeD $txType, $order ); + if ($expectedData['transaction_time'] instanceof \DateTimeImmutable && $actualData['transaction_time'] instanceof \DateTimeImmutable) { + $this->assertSame($expectedData['transaction_time']->format('Ymd'), $actualData['transaction_time']->format('Ymd')); + } else { + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + } + unset($actualData['transaction_time'], $expectedData['transaction_time']); + + $this->assertArrayHasKey('3d_all', $actualData); + $this->assertIsArray($actualData['3d_all']); + $this->assertNotEmpty($actualData['3d_all']); unset($actualData['all'], $actualData['3d_all']); \ksort($expectedData); \ksort($actualData); @@ -161,6 +172,18 @@ public function testMapCancelResponse(array $responseData, array $expectedData): $this->assertSame($expectedData, $actualData); } + public function testMapHistoryResponse(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->mapHistoryResponse([]); + } + + public function testMapOrderHistoryResponse(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->mapOrderHistoryResponse([]); + } + public function threeDHashCheckDataProvider(): array { return [ @@ -324,6 +347,118 @@ public static function threeDPaymentDataProvider(): array 'transaction_time' => null, ], ], + 'success' => [ + 'order' => [], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'Version' => '', + 'MerchantID' => '', + 'ShopCode' => 'gizlendi', + 'TxnStat' => 'Y', + 'MD' => 'gizlendi', + 'RetCode' => '', + 'RetDet' => '', + 'VenderCode' => '', + 'Eci' => '02', + 'PayerAuthenticationCode' => 'gizlendi=', + 'PayerTxnId' => '', + 'CavvAlg' => '', + 'PAResVerified' => 'True', + 'PAResSyntaxOK' => 'True', + 'Expiry' => 'expiry-123', + 'Pan' => 'kart*****no', + 'OrderId' => '33554969', + 'PurchAmount' => '1', + 'Exponent' => '', + 'Description' => '', + 'Description2' => '', + 'Currency' => '949', + 'OkUrl' => 'gizlendi', + 'FailUrl' => 'gizlendi', + '3DStatus' => '1', + 'AuthCode' => '', + 'HostRefNum' => 'hostid', + 'TransId' => '', + 'TRXDATE' => '', + 'CardHolderName' => '', + 'mdStatus' => '1', + 'ProcReturnCode' => '', + 'TxnResult' => '', + 'ErrorMessage' => '', + 'ErrorCode' => '', + 'Response' => '', + 'HASH' => 'gizlendi/gizlendi=', + 'HASHPARAMS' => 'Version:PurchAmount:Exponent:Currency:OkUrl:FailUrl:MD:OrderId:ProcReturnCode:Response:mdStatus:', + 'HASHPARAMSVAL' => 'gizlendi', + ], + 'paymentData' => [ + 'OrderId' => '33554969', + 'ProcReturnCode' => '00', + 'HostRefNum' => 'hostid', + 'AuthCode' => 'auth-code-123', + 'TxnResult' => 'Success', + 'ErrorMessage' => '', + 'CampanyId' => '', + 'CampanyInstallCount' => '0', + 'CampanyShiftDateCount' => '0', + 'CampanyTxnId' => '', + 'CampanyType' => '', + 'CampanyInstallment' => '0', + 'CampanyDate' => '0', + 'CampanyAmnt' => '0', + 'TRXDATE' => '09.08.2024 10:40:34', + 'TransId' => 'trans-id-123', + 'ErrorCode' => '', + 'EarnedBonus' => '0,00', + 'UsedBonus' => '0,00', + 'AvailableBonus' => '0,00', + 'BonusToBonus' => '0', + 'CampaignBonus' => '0,00', + 'FoldedBonus' => '0', + 'SurchargeAmount' => '0', + 'Amount' => '1,00', + 'CardHolderName' => 'kart-sahibi-abc', + 'QrReferenceNumber' => '', + 'QrCardToken' => '', + 'QrData' => '', + 'QrPayIsSucess' => 'False', + 'QrIssuerPaymentMethod' => '', + 'QrFastMessageReferenceNo' => '', + 'QrFastParticipantReceiverCode' => '', + 'QrFastParticipantReceiverName' => '', + 'QrFastParticipantSenderCode' => '', + 'QrFastSenderIban' => '', + 'QrFastParticipantSenderName' => '', + 'QrFastPaymentResultDesc' => '', + ], + 'expectedData' => [ + 'order_id' => '33554969', + 'transaction_id' => 'trans-id-123', + 'auth_code' => 'auth-code-123', + 'ref_ret_num' => 'hostid', + 'batch_num' => null, + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'error_code' => null, + 'error_message' => null, + 'transaction_security' => 'Full 3D Secure', + 'md_status' => '1', + 'masked_number' => 'kart*****no', + 'month' => null, + 'year' => null, + 'amount' => 1.0, + 'currency' => 'TRY', + 'eci' => '02', + 'tx_status' => 'Y', + 'cavv' => null, + 'md_error_message' => null, + 'transaction_type' => 'pay', + 'payment_model' => '3d', + 'installment_count' => null, + 'transaction_time' => new \DateTimeImmutable('09.08.2024 10:40:34'), + ], + ], ]; } diff --git a/tests/Unit/Gateways/InterPosTest.php b/tests/Unit/Gateways/InterPosTest.php index 4cac171b..59226a72 100644 --- a/tests/Unit/Gateways/InterPosTest.php +++ b/tests/Unit/Gateways/InterPosTest.php @@ -11,6 +11,7 @@ use Mews\Pos\Entity\Account\InterPosAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Exceptions\UnsupportedTransactionTypeException; use Mews\Pos\Factory\AccountFactory; use Mews\Pos\Factory\CreditCardFactory; @@ -193,6 +194,16 @@ public function testMake3DPayment( ->willReturn(true); } + $this->responseMapperMock->expects(self::once()) + ->method('extractMdStatus') + ->with($request->request->all()) + ->willReturn('3d-status'); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->with('3d-status') + ->willReturn($is3DSuccess); + $create3DPaymentRequestData = [ 'create3DPaymentRequestData', ]; @@ -240,6 +251,33 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $request = Request::create( + '', + 'POST', + ['data'] + ); + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $request->request->all()) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('extractMdStatus') + ->with($request->request->all()) + ->willReturn('3d-status'); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->with('3d-status') + ->willReturn(true); + + $this->expectException(HashMismatchException::class); + + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @return void */ @@ -490,6 +528,16 @@ public static function make3DPaymentDataProvider(): array 'is3DSuccess' => false, 'isSuccess' => false, ], + 'success' => [ + 'order' => ['order'], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'request' => Request::create('', 'POST', ['gateway_response']), + 'paymentResponse' => ['paymentResponse'], + 'expected' => ['status' => 'approved'], + 'check_hash' => true, + 'is3DSuccess' => true, + 'isSuccess' => true, + ], ]; } diff --git a/tests/Unit/Serializer/InterPosSerializerTest.php b/tests/Unit/Serializer/InterPosSerializerTest.php index 81d2bc26..49180247 100644 --- a/tests/Unit/Serializer/InterPosSerializerTest.php +++ b/tests/Unit/Serializer/InterPosSerializerTest.php @@ -37,4 +37,63 @@ public function testEncode(): void $this->assertSame($data, $result); } + + /** + * @dataProvider decodeDataProvider + */ + public function testDecode(string $input, array $expected): void + { + $result = $this->serializer->decode($input); + + $this->assertSame($expected, $result); + } + + public static function decodeDataProvider(): array + { + return [ + 'success_payment' => [ + 'input' => 'OrderId=33554969;;ProcReturnCode=00;;HostRefNum=hostid;;AuthCode=gizlendi;;TxnResult=Success;;ErrorMessage=;;CampanyId=;;CampanyInstallCount=0;;CampanyShiftDateCount=0;;CampanyTxnId=;;CampanyType=;;CampanyInstallment=0;;CampanyDate=0;;CampanyAmnt=0;;TRXDATE=09.08.2024 10:40:34;;TransId=gizlendi;;ErrorCode=;;EarnedBonus=0,00;;UsedBonus=0,00;;AvailableBonus=0,00;;BonusToBonus=0;;CampaignBonus=0,00;;FoldedBonus=0;;SurchargeAmount=0;;Amount=1,00;;CardHolderName=gizlendi;;QrReferenceNumber=;;QrCardToken=;;QrData=;;QrPayIsSucess=False;;QrIssuerPaymentMethod=;;QrFastMessageReferenceNo=;;QrFastParticipantReceiverCode=;;QrFastParticipantReceiverName=;;QrFastParticipantSenderCode=;;QrFastSenderIban=;;QrFastParticipantSenderName=;;QrFastPaymentResultDesc=', + 'expected' => [ + 'OrderId' => '33554969', + 'ProcReturnCode' => '00', + 'HostRefNum' => 'hostid', + 'AuthCode' => 'gizlendi', + 'TxnResult' => 'Success', + 'ErrorMessage' => '', + 'CampanyId' => '', + 'CampanyInstallCount' => '0', + 'CampanyShiftDateCount' => '0', + 'CampanyTxnId' => '', + 'CampanyType' => '', + 'CampanyInstallment' => '0', + 'CampanyDate' => '0', + 'CampanyAmnt' => '0', + 'TRXDATE' => '09.08.2024 10:40:34', + 'TransId' => 'gizlendi', + 'ErrorCode' => '', + 'EarnedBonus' => '0,00', + 'UsedBonus' => '0,00', + 'AvailableBonus' => '0,00', + 'BonusToBonus' => '0', + 'CampaignBonus' => '0,00', + 'FoldedBonus' => '0', + 'SurchargeAmount' => '0', + 'Amount' => '1,00', + 'CardHolderName' => 'gizlendi', + 'QrReferenceNumber' => '', + 'QrCardToken' => '', + 'QrData' => '', + 'QrPayIsSucess' => 'False', + 'QrIssuerPaymentMethod' => '', + 'QrFastMessageReferenceNo' => '', + 'QrFastParticipantReceiverCode' => '', + 'QrFastParticipantReceiverName' => '', + 'QrFastParticipantSenderCode' => '', + 'QrFastSenderIban' => '', + 'QrFastParticipantSenderName' => '', + 'QrFastPaymentResultDesc' => '', + ], + ], + ]; + } }