diff --git a/.editorconfig b/.editorconfig index c01f950c..5b3b9654 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,6 +3,7 @@ root = true # Unix-style newlines with a newline ending every file [*] +charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true @@ -11,5 +12,10 @@ trim_trailing_whitespace = true indent_style = space indent_size = 4 +ij_php_align_assignments = true +ij_php_align_class_constants = true +ij_php_align_key_value_pairs = true +ij_php_phpdoc_param_spaces_between_tag_and_type = 1 + [*.md] max_line_length = 80 diff --git a/composer.json b/composer.json index 8e665d4e..006fe0c6 100644 --- a/composer.json +++ b/composer.json @@ -49,6 +49,9 @@ "symfony/http-client": "^5.4", "symfony/var-dumper": "^5.1" }, + "suggest": { + "ext-soap": "KuveytPos ile iptal/iade gibi ödeme olmayan işlemleri yapacaksanız." + }, "config": { "sort-packages": true, "allow-plugins": { diff --git a/src/Crypt/PosNetV1PosCrypt.php b/src/Crypt/PosNetV1PosCrypt.php index 242f152b..8426ddfd 100644 --- a/src/Crypt/PosNetV1PosCrypt.php +++ b/src/Crypt/PosNetV1PosCrypt.php @@ -26,13 +26,15 @@ public function create3DHash(AbstractPosAccount $posAccount, array $requestData, $hashData = [ $posAccount->getClientId(), $posAccount->getTerminalId(), - $requestData['CardNo'], - $requestData['Cvv'], - $requestData['ExpiredDate'], + // no card data for 3D host payment + $requestData['CardNo'] ?? null, + $requestData['Cvv'] ?? null, + $requestData['ExpiredDate'] ?? null, + $requestData['Amount'], $posAccount->getStoreKey(), ]; - $hashStr = implode(static::HASH_SEPARATOR, $hashData); + $hashStr = \implode(static::HASH_SEPARATOR, $hashData); return $this->hashString($hashStr); } diff --git a/src/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapper.php b/src/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapper.php index 2e912cb2..a06d65b7 100644 --- a/src/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapper.php +++ b/src/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapper.php @@ -382,7 +382,8 @@ public function create3DFormData(AbstractPosAccount $posAccount, array $order, s * UseOOS alanını 1 yaparak bankanın ortak ödeme sayfasının açılmasını ve * bu ortak ödeme sayfası ile müşterinin kart bilgilerini girmesini sağlatabilir. */ - 'UseOOS' => '1', + 'UseOOS' => '1', + 'MacParams' => 'MerchantNo:TerminalNo:Amount', ]; } diff --git a/src/DataMapper/ResponseDataMapper/PosNetResponseDataMapper.php b/src/DataMapper/ResponseDataMapper/PosNetResponseDataMapper.php index bdeff45e..fc4227ae 100644 --- a/src/DataMapper/ResponseDataMapper/PosNetResponseDataMapper.php +++ b/src/DataMapper/ResponseDataMapper/PosNetResponseDataMapper.php @@ -154,7 +154,7 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen */ public function map3DPayResponseData(array $raw3DAuthResponseData, string $txType, array $order): array { - return $this->map3DPaymentData($raw3DAuthResponseData, $raw3DAuthResponseData, $txType, $order); + throw new NotImplementedException(); } /** @@ -162,7 +162,7 @@ public function map3DPayResponseData(array $raw3DAuthResponseData, string $txTyp */ public function map3DHostResponseData(array $raw3DAuthResponseData, string $txType, array $order): array { - return $this->map3DPayResponseData($raw3DAuthResponseData, $txType, $order); + throw new NotImplementedException(); } /** diff --git a/src/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapper.php b/src/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapper.php index c62ad704..7d1c0514 100644 --- a/src/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapper.php +++ b/src/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapper.php @@ -158,7 +158,7 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen */ public function map3DPayResponseData(array $raw3DAuthResponseData, string $txType, array $order): array { - return $this->map3DPaymentData($raw3DAuthResponseData, $raw3DAuthResponseData, $txType, $order); + throw new NotImplementedException(); } /** @@ -166,7 +166,7 @@ public function map3DPayResponseData(array $raw3DAuthResponseData, string $txTyp */ public function map3DHostResponseData(array $raw3DAuthResponseData, string $txType, array $order): array { - return $this->map3DPayResponseData($raw3DAuthResponseData, $txType, $order); + throw new NotImplementedException(); } /** diff --git a/src/Gateways/AbstractGateway.php b/src/Gateways/AbstractGateway.php index 32c44c0f..4fd2b332 100644 --- a/src/Gateways/AbstractGateway.php +++ b/src/Gateways/AbstractGateway.php @@ -238,7 +238,8 @@ public function makeRegularPayment(array $order, CreditCardInterface $creditCard $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -282,7 +283,8 @@ public function makeRegularPostPayment(array $order): PosInterface $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -325,7 +327,8 @@ public function refund(array $order): PosInterface $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -368,7 +371,8 @@ public function cancel(array $order): PosInterface $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -411,7 +415,8 @@ public function status(array $order): PosInterface $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -450,7 +455,8 @@ public function history(array $data): PosInterface $data, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -489,7 +495,8 @@ public function orderHistory(array $order): PosInterface $order, PosInterface::MODEL_NON_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/AkbankPos.php b/src/Gateways/AkbankPos.php index 54d2b752..fd613801 100644 --- a/src/Gateways/AkbankPos.php +++ b/src/Gateways/AkbankPos.php @@ -45,6 +45,8 @@ class AkbankPos extends AbstractGateway /** * @inheritDoc + * + * @throws \InvalidArgumentException when transaction type is not provided */ public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string { @@ -52,7 +54,7 @@ public function getApiURL(string $txType = null, string $paymentModel = null, ?s return parent::getApiURL().'/'.$this->getRequestURIByTransactionType($txType); } - return parent::getApiURL(); + throw new \InvalidArgumentException('Transaction type is required to generate API URL'); } /** @return AkbankPosAccount */ @@ -93,7 +95,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/EstPos.php b/src/Gateways/EstPos.php index 9fc39856..d70723f7 100644 --- a/src/Gateways/EstPos.php +++ b/src/Gateways/EstPos.php @@ -92,7 +92,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/GarantiPos.php b/src/Gateways/GarantiPos.php index 4824c711..0ca3d684 100644 --- a/src/Gateways/GarantiPos.php +++ b/src/Gateways/GarantiPos.php @@ -85,7 +85,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/InterPos.php b/src/Gateways/InterPos.php index b2b450d9..9277dfb8 100644 --- a/src/Gateways/InterPos.php +++ b/src/Gateways/InterPos.php @@ -92,7 +92,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/KuveytPos.php b/src/Gateways/KuveytPos.php index fcab2e4a..5f16af41 100644 --- a/src/Gateways/KuveytPos.php +++ b/src/Gateways/KuveytPos.php @@ -67,6 +67,7 @@ public function getAccount(): AbstractPosAccount * @inheritDoc * * @throws UnsupportedTransactionTypeException + * @throws \InvalidArgumentException when transaction type is not provided */ public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string { @@ -87,7 +88,7 @@ public function getApiURL(string $txType = null, string $paymentModel = null, ?s return parent::getApiURL().'/'.$this->getRequestURIByTransactionType($txType, $paymentModel); } - return parent::getApiURL(); + throw new \InvalidArgumentException('Transaction type is required to generate API URL'); } /** @@ -178,7 +179,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -345,7 +347,8 @@ private function getCommon3DFormData(KuveytPosAccount $kuveytPosAccount, array $ $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/PayFlexCPV4Pos.php b/src/Gateways/PayFlexCPV4Pos.php index fe9bab34..74361962 100644 --- a/src/Gateways/PayFlexCPV4Pos.php +++ b/src/Gateways/PayFlexCPV4Pos.php @@ -97,7 +97,8 @@ public function make3DPayPayment(Request $request, array $order, string $txType) $order, PosInterface::MODEL_3D_PAY ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -254,7 +255,8 @@ private function registerPayment(array $order, string $txType, string $paymentMo $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/PayFlexV4Pos.php b/src/Gateways/PayFlexV4Pos.php index 13af344f..765582af 100644 --- a/src/Gateways/PayFlexV4Pos.php +++ b/src/Gateways/PayFlexV4Pos.php @@ -87,7 +87,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -231,7 +232,8 @@ private function sendEnrollmentRequest(array $order, CreditCardInterface $credit $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/PayForPos.php b/src/Gateways/PayForPos.php index 4b0a2a05..76742f46 100644 --- a/src/Gateways/PayForPos.php +++ b/src/Gateways/PayForPos.php @@ -86,7 +86,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -131,12 +132,7 @@ public function make3DHostPayment(Request $request, array $order, string $txType } /** - * Refund Order - * refund amount should be exactly the same with order amount. - * otherwise operation will be rejected - * - * Warning: You can not use refund for purchases made at the same date. - * Instead, you need to use cancel. + * Satış işlemi ile farklı batchtlerde olmalıdır. * * @inheritDoc */ diff --git a/src/Gateways/PosNet.php b/src/Gateways/PosNet.php index bf7317a6..b19d1e19 100644 --- a/src/Gateways/PosNet.php +++ b/src/Gateways/PosNet.php @@ -78,7 +78,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -118,7 +119,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -266,7 +268,8 @@ private function getOosTransactionData(array $order, string $txType, string $pay $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/PosNetV1Pos.php b/src/Gateways/PosNetV1Pos.php index adf17d20..d869868d 100644 --- a/src/Gateways/PosNetV1Pos.php +++ b/src/Gateways/PosNetV1Pos.php @@ -60,6 +60,7 @@ public function getAccount(): AbstractPosAccount * @inheritDoc * * @throws UnsupportedTransactionTypeException + * @throws \InvalidArgumentException when transaction type is not provided */ public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string { @@ -67,7 +68,7 @@ public function getApiURL(string $txType = null, string $paymentModel = null, ?s return parent::getApiURL().'/'.$this->requestDataMapper->mapTxType($txType); } - return parent::getApiURL(); + throw new \InvalidArgumentException('Transaction type is required to generate API URL'); } /** @@ -98,7 +99,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/ToslaPos.php b/src/Gateways/ToslaPos.php index 7cb51ce1..fba23529 100644 --- a/src/Gateways/ToslaPos.php +++ b/src/Gateways/ToslaPos.php @@ -69,6 +69,7 @@ public function getAccount(): AbstractPosAccount * @inheritDoc * * @throws UnsupportedTransactionTypeException + * @throws \InvalidArgumentException when transaction type or payment model are not provided */ public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string { @@ -76,7 +77,7 @@ public function getApiURL(string $txType = null, string $paymentModel = null, ?s return parent::getApiURL().'/'.$this->getRequestURIByTransactionType($txType, $paymentModel); } - return parent::getApiURL(); + throw new \InvalidArgumentException('Transaction type and payment model are required to generate API URL'); } /** @@ -229,7 +230,8 @@ private function registerPayment(array $order, string $paymentModel, string $txT $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/src/Gateways/VakifKatilimPos.php b/src/Gateways/VakifKatilimPos.php index 2ffa8b59..d93b5160 100644 --- a/src/Gateways/VakifKatilimPos.php +++ b/src/Gateways/VakifKatilimPos.php @@ -66,6 +66,7 @@ public function getAccount(): AbstractPosAccount * @inheritDoc * * @throws UnsupportedTransactionTypeException + * @throws \InvalidArgumentException when transaction type or payment model are not provided */ public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string { @@ -73,7 +74,7 @@ public function getApiURL(string $txType = null, string $paymentModel = null, ?s return parent::getApiURL().'/'.$this->getRequestURIByTransactionType($txType, $paymentModel, $orderTxType); } - return parent::getApiURL(); + throw new \InvalidArgumentException('Transaction type and payment model are required to generate API URL'); } /** @@ -136,7 +137,8 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr $order, PosInterface::MODEL_3D_SECURE ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), @@ -209,7 +211,8 @@ private function sendEnrollmentRequest(KuveytPosAccount $kuveytPosAccount, array $order, $paymentModel ); - $this->eventDispatcher->dispatch($event); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); if ($requestData !== $event->getRequestData()) { $this->logger->debug('Request data is changed via listeners', [ 'txType' => $event->getTxType(), diff --git a/tests/Unit/DataMapper/RequestDataMapper/EstPosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/EstPosRequestDataMapperTest.php index b3694e12..8dcbea4a 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/EstPosRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/EstPosRequestDataMapperTest.php @@ -22,6 +22,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\EstPosRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class EstPosRequestDataMapperTest extends TestCase { @@ -66,7 +67,13 @@ protected function setUp(): void $this->crypt = $this->createMock(CryptInterface::class); $this->requestDataMapper = new EstPosRequestDataMapper($this->dispatcher, $this->crypt); - $this->card = CreditCardFactory::create('5555444433332222', '22', '01', '123', 'ahmet', CreditCardInterface::CARD_TYPE_VISA); + $this->card = CreditCardFactory::create( + '5555444433332222', + '22', + '01', + '123', + 'ahmet', + ); } /** @@ -142,14 +149,18 @@ public function testCreateNonSecurePostAuthPaymentRequestData(array $order, arra } /** - * @return void + * @dataProvider nonSecurePaymentRequestDataDataProvider */ - public function testCreateNonSecurePaymentRequestData(): void + public function testCreateNonSecurePaymentRequestData(array $order, CreditCardInterface $card, string $txType, array $expectedData): void { - $actual = $this->requestDataMapper->createNonSecurePaymentRequestData($this->account, $this->order, PosInterface::TX_TYPE_PAY_AUTH, $this->card); + $actual = $this->requestDataMapper->createNonSecurePaymentRequestData( + $this->account, + $order, + $txType, + $card + ); - $expectedData = $this->getSampleNonSecurePaymentRequestData($this->account, $this->order, $this->card); - $this->assertEquals($expectedData, $actual); + $this->assertSame($expectedData, $actual); } /** @@ -192,6 +203,12 @@ public function testCreateOrderHistoryRequestData(array $order, array $expected) $this->assertEquals($expected, $actual); } + public function testCreateHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createHistoryRequestData($this->account); + } + /** * @dataProvider threeDPaymentRequestDataDataProvider */ @@ -617,29 +634,76 @@ private function getSampleRecurringOrderCancelXMLData(AbstractPosAccount $posAcc ]; } - /** - * @param AbstractPosAccount $posAccount - * @param array $order - * @param CreditCardInterface $creditCard - * - * @return array - */ - private function getSampleNonSecurePaymentRequestData(AbstractPosAccount $posAccount, array $order, CreditCardInterface $creditCard): array + public static function nonSecurePaymentRequestDataDataProvider(): array { + $card = CreditCardFactory::create( + '5555444433332222', + '22', + '01', + '123', + 'ahmet', + ); + return [ - 'Name' => $posAccount->getUsername(), - 'Password' => $posAccount->getPassword(), - 'ClientId' => $posAccount->getClientId(), - 'Type' => 'Auth', - 'IPAddress' => $order['ip'], - 'OrderId' => $order['id'], - 'Total' => '100.25', - 'Currency' => '949', - 'Taksit' => '', - 'Number' => $creditCard->getNumber(), - 'Expires' => '01/22', - 'Cvv2Val' => $creditCard->getCvv(), - 'Mode' => 'P', + 'basic' => [ + 'order' => [ + 'id' => 'order222', + 'amount' => 10.01, + 'ip' => '127.0.0.1', + ], + 'card' => $card, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'expected' => [ + 'Name' => 'ISBANKAPI', + 'Password' => 'ISBANK07', + 'ClientId' => '700655000200', + 'Type' => 'Auth', + 'IPAddress' => '127.0.0.1', + 'OrderId' => 'order222', + 'Total' => '10.01', + 'Currency' => '949', + 'Taksit' => '', + 'Number' => '5555444433332222', + 'Expires' => '01/22', + 'Cvv2Val' => '123', + 'Mode' => 'P', + ], + ], + 'recurring' => [ + 'order' => [ + 'id' => 'order222', + 'amount' => 10.01, + 'ip' => '127.0.0.1', + 'recurring' => [ + 'frequency' => 3, + 'frequencyType' => 'MONTH', + 'installment' => 4, + ], + ], + 'card' => $card, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'expected' => [ + 'Name' => 'ISBANKAPI', + 'Password' => 'ISBANK07', + 'ClientId' => '700655000200', + 'Type' => 'Auth', + 'IPAddress' => '127.0.0.1', + 'OrderId' => 'order222', + 'Total' => '10.01', + 'Currency' => '949', + 'Taksit' => '', + 'Number' => '5555444433332222', + 'Expires' => '01/22', + 'Cvv2Val' => '123', + 'Mode' => 'P', + 'PbOrder' => [ + 'OrderType' => '0', + 'OrderFrequencyInterval' => '3', + 'OrderFrequencyCycle' => 'M', + 'TotalNumberPayments' => '4', + ], + ], + ], ]; } diff --git a/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php index 3d237618..5a6e3962 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php @@ -23,6 +23,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\GarantiPosRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class GarantiPosRequestDataMapperTest extends TestCase { @@ -150,14 +151,18 @@ public function testCreateNonSecurePostAuthPaymentRequestData(): void } /** - * @return void + * @dataProvider nonSecurePaymentRequestDataDataProvider */ - public function testCreateNonSecurePaymentRequestData(): void + public function testCreateNonSecurePaymentRequestData(array $order, string $txType, CreditCardInterface $card, array $expectedData): void { - $actual = $this->requestDataMapper->createNonSecurePaymentRequestData($this->account, $this->order, PosInterface::TX_TYPE_PAY_AUTH, $this->card); + $actual = $this->requestDataMapper->createNonSecurePaymentRequestData( + $this->account, + $order, + $txType, + $card + ); - $expectedData = $this->getSampleNonSecurePaymentRequestData($this->account, $this->order, $this->card); - $this->assertEquals($expectedData, $actual); + $this->assertSame($expectedData, $actual); } /** @@ -303,6 +308,34 @@ public function testCreateRefundRequestData(array $order, string $txType, array $this->assertSame($expectedData, $actual); } + public function testCreateRefundRequestDataWithoutRefundCredentials(): void + { + $this->account = AccountFactory::createGarantiPosAccount( + 'garanti', + '7000679', + 'PROVAUT', + '123qweASD/', + '30691298', + PosInterface::MODEL_3D_SECURE, + '12345678', + ); + $order = [ + 'id' => '2020110828BC', + 'ip' => '127.15.15.1', + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 123.1, + 'ref_ret_num' => '831803579226', + 'installment' => 0, + ]; + + $this->expectException(\LogicException::class); + $this->requestDataMapper->createRefundRequestData( + $this->account, + $order, + PosInterface::TX_TYPE_REFUND + ); + } + /** * @param GarantiPosAccount $posAccount * @param $order @@ -339,43 +372,110 @@ private function getSampleCancelXMLData(AbstractPosAccount $posAccount, array $o ]; } - /** - * @param GarantiPosAccount $posAccount - * @param array $order - * @param CreditCardInterface $creditCard - * - * @return array - */ - private function getSampleNonSecurePaymentRequestData(AbstractPosAccount $posAccount, array $order, CreditCardInterface $creditCard): array + public static function nonSecurePaymentRequestDataDataProvider(): array { + $card = CreditCardFactory::create( + '5555444433332222', + '22', + '01', + '123', + 'ahmet', + ); + return [ - 'Mode' => 'TEST', - 'Version' => '512', - 'Terminal' => [ - 'ProvUserID' => $posAccount->getUsername(), - 'UserID' => $posAccount->getUsername(), - 'HashData' => '2005F771B622399C0EC7B8BBBE9B5F7989B9587175239F0695C1E5D3BFAA0CF6D747A9CEE64D78B7081CB5193541AD9D129B929653E2B68BCAE6939E281D752E', - 'ID' => $posAccount->getTerminalId(), - 'MerchantID' => $posAccount->getClientId(), - ], - 'Customer' => [ - 'IPAddress' => $order['ip'], - ], - 'Card' => [ - 'Number' => $creditCard->getNumber(), - 'ExpireDate' => '0122', - 'CVV2' => $creditCard->getCvv(), - ], - 'Order' => [ - 'OrderID' => $order['id'], + 'basic' => [ + 'order' => [ + 'id' => 'order222', + 'amount' => 100.25, + 'currency' => PosInterface::CURRENCY_TRY, + 'installment' => 0, + 'ip' => '127.0.0.1', + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'card' => $card, + 'expected' => [ + 'Mode' => 'TEST', + 'Version' => '512', + 'Terminal' => [ + 'ProvUserID' => 'PROVAUT', + 'UserID' => 'PROVAUT', + 'HashData' => '2005F771B622399C0EC7B8BBBE9B5F7989B9587175239F0695C1E5D3BFAA0CF6D747A9CEE64D78B7081CB5193541AD9D129B929653E2B68BCAE6939E281D752E', + 'ID' => '30691298', + 'MerchantID' => '7000679', + ], + 'Customer' => [ + 'IPAddress' => '127.0.0.1', + ], + 'Card' => [ + 'Number' => '5555444433332222', + 'ExpireDate' => '0122', + 'CVV2' => '123', + ], + 'Order' => [ + 'OrderID' => 'order222', + ], + 'Transaction' => [ + 'Type' => 'sales', + 'InstallmentCnt' => '', + 'Amount' => 10025, + 'CurrencyCode' => '949', + 'CardholderPresentCode' => '0', + 'MotoInd' => 'N', + ], + ], ], - 'Transaction' => [ - 'Type' => 'sales', - 'InstallmentCnt' => '', - 'Amount' => 10025, - 'CurrencyCode' => 949, - 'CardholderPresentCode' => '0', - 'MotoInd' => 'N', + 'recurring' => [ + 'order' => [ + 'id' => 'order222', + 'amount' => 100.25, + 'currency' => PosInterface::CURRENCY_TRY, + 'ip' => '127.0.0.1', + 'recurring' => [ + 'frequency' => 3, + 'frequencyType' => 'MONTH', + 'installment' => 4, + 'startDate' => new \DateTimeImmutable('2024-09-09 00:00:00'), + ], + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'card' => $card, + 'expected' => [ + 'Mode' => 'TEST', + 'Version' => '512', + 'Terminal' => [ + 'ProvUserID' => 'PROVAUT', + 'UserID' => 'PROVAUT', + 'HashData' => '2005F771B622399C0EC7B8BBBE9B5F7989B9587175239F0695C1E5D3BFAA0CF6D747A9CEE64D78B7081CB5193541AD9D129B929653E2B68BCAE6939E281D752E', + 'ID' => '30691298', + 'MerchantID' => '7000679', + ], + 'Customer' => [ + 'IPAddress' => '127.0.0.1', + ], + 'Card' => [ + 'Number' => '5555444433332222', + 'ExpireDate' => '0122', + 'CVV2' => '123', + ], + 'Order' => [ + 'OrderID' => 'order222', + ], + 'Transaction' => [ + 'Type' => 'sales', + 'InstallmentCnt' => '', + 'Amount' => 10025, + 'CurrencyCode' => '949', + 'CardholderPresentCode' => '0', + 'MotoInd' => 'N', + ], + 'Recurring' => [ + 'TotalPaymentNum' => '4', + 'FrequencyType' => 'M', + 'FrequencyInterval' => '3', + 'Type' => 'R', + 'StartDate' => '20240909', + ], + ], ], ]; } diff --git a/tests/Unit/DataMapper/RequestDataMapper/PayFlexCPV4PosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/PayFlexCPV4PosRequestDataMapperTest.php index 988b09ef..920c0b15 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/PayFlexCPV4PosRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/PayFlexCPV4PosRequestDataMapperTest.php @@ -23,6 +23,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\PayFlexCPV4PosRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class PayFlexCPV4PosRequestDataMapperTest extends TestCase { @@ -159,10 +160,37 @@ public function testCreate3DFormData(array $queryParams, array $expected): void $this->assertSame($expected, $actualData); } - public static function registerDataProvider(): iterable + public function testCreate3DPaymentRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->create3DPaymentRequestData( + $this->account, + [], + PosInterface::TX_TYPE_PAY_AUTH, + [] + ); + } + + public function testCreateStatusRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createStatusRequestData($this->account, []); + } + + public function testCreateHistoryRequestData(): void { - $config = require __DIR__.'/../../../../config/pos_test.php'; + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createHistoryRequestData($this->account); + } + public function testCreateOrderHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createOrderHistoryRequestData($this->account, []); + } + + public static function registerDataProvider(): iterable + { $account = AccountFactory::createPayFlexAccount( 'vakifbank-cp', '000000000111111', diff --git a/tests/Unit/DataMapper/RequestDataMapper/PosNetRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/PosNetRequestDataMapperTest.php index 6c23fa7d..889dead6 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/PosNetRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/PosNetRequestDataMapperTest.php @@ -22,6 +22,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\PosNetRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class PosNetRequestDataMapperTest extends TestCase { @@ -245,7 +246,25 @@ public function testCreate3DFormData(array $ooTxSuccessData, array $order, strin $ooTxSuccessData['oosRequestDataResponse'] ); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider threeDFormDataDataProvider + */ + public function testCreate3DFormDataWithMissingData(): void + { + $this->dispatcher->expects(self::never()) + ->method('dispatch'); + + $this->expectException(InvalidArgumentException::class); + $this->requestDataMapper->create3DFormData( + $this->account, + [], + PosInterface::MODEL_3D_SECURE, + PosInterface::TX_TYPE_PAY_AUTH, + '/api', + ); } /** @@ -270,6 +289,18 @@ public function testCreateRefundRequestData(array $order, string $txType, array $this->assertSame($expectedData, $actual); } + public function testCreateHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createHistoryRequestData($this->account); + } + + public function testCreateOrderHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createOrderHistoryRequestData($this->account, []); + } + public static function threeDFormDataDataProvider(): array { return [ @@ -294,10 +325,10 @@ public static function threeDFormDataDataProvider(): array 'gateway' => 'https://setmpos.ykb.com/3DSWebService/YKBPaymentService', 'method' => 'POST', 'inputs' => [ - 'posnetData' => 'AEFE78BFC852867FF57078B723E284D1BD52EED8264C6CBD110A1A9EA5EAA7533D1A82EFD614032D686C507738FDCDD2EDD00B22DEFEFE0795DC4674C16C02EBBFEC9DF0F495D5E23BE487A798BF8293C7C1D517D9600C96CBFD8816C9D8F8257442906CB9B10D8F1AABFBBD24AA6FB0E5533CDE67B0D9EA5ED621B91BF6991D5362182302B781241B56E47BAE1E86BC3D5AE7606212126A4E97AFC2', - 'posnetData2' => '69D04861340091B7014B15158CA3C83413031B406F08B3792A0114C9958E6F0F216966C5EE32EAEEC7158BFF59DFCB77E20CD625', 'mid' => '6706598320', 'posnetID' => '27426', + 'posnetData' => 'AEFE78BFC852867FF57078B723E284D1BD52EED8264C6CBD110A1A9EA5EAA7533D1A82EFD614032D686C507738FDCDD2EDD00B22DEFEFE0795DC4674C16C02EBBFEC9DF0F495D5E23BE487A798BF8293C7C1D517D9600C96CBFD8816C9D8F8257442906CB9B10D8F1AABFBBD24AA6FB0E5533CDE67B0D9EA5ED621B91BF6991D5362182302B781241B56E47BAE1E86BC3D5AE7606212126A4E97AFC2', + 'posnetData2' => '69D04861340091B7014B15158CA3C83413031B406F08B3792A0114C9958E6F0F216966C5EE32EAEEC7158BFF59DFCB77E20CD625', 'digest' => '9998F61E1D0C0FB6EC5203A748124F30', 'merchantReturnURL' => 'https://domain.com/success', 'url' => '', @@ -376,6 +407,25 @@ public static function cancelDataProvider(): array ], ], ], + 'with_auth_code' => [ + 'order' => [ + 'id' => '2020110828BC', + 'auth_code' => '901477', + 'payment_model' => PosInterface::MODEL_3D_SECURE, + 'amount' => 50, + 'currency' => PosInterface::CURRENCY_TRY, + ], + 'expected' => [ + 'mid' => '6706598320', + 'tid' => '67005551', + 'tranDateRequired' => '1', + 'reverse' => [ + 'transaction' => 'sale', + 'authCode' => '901477', + 'orderID' => 'TDSC000000002020110828BC', + ], + ], + ], ]; } diff --git a/tests/Unit/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapperTest.php index c88de79c..7c1bd702 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/PosNetV1PosRequestDataMapperTest.php @@ -23,6 +23,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\PosNetV1PosRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class PosNetV1PosRequestDataMapperTest extends TestCase { @@ -181,7 +182,7 @@ public function testCreate3DPaymentRequestData(array $order, string $txType, arr /** * @dataProvider threeDFormDataTestProvider */ - public function testCreate3DFormData(array $order, string $txType, string $gatewayUrl, array $expected): void + public function testCreate3DFormData(array $order, string $txType, string $gatewayUrl, ?CreditCardInterface $card, array $expected): void { $paymentModel = PosInterface::MODEL_3D_SECURE; $this->dispatcher->expects(self::once()) @@ -198,10 +199,10 @@ public function testCreate3DFormData(array $order, string $txType, string $gatew $paymentModel, $txType, $gatewayUrl, - $this->card + $card ); - $this->assertEquals($expected, $actual); + $this->assertSame($expected, $actual); } /** @@ -235,6 +236,18 @@ public function testCreateCancelRequestData(array $order, array $expected): void $this->assertEquals($expected, $actual); } + public function testCreateHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createHistoryRequestData($this->account); + } + + public function testCreateOrderHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createOrderHistoryRequestData($this->account, []); + } + /** * @return array */ @@ -248,12 +261,17 @@ public static function threeDFormDataTestProvider(): iterable 'success_url' => 'https://domain.com/success', 'lang' => PosInterface::LANG_TR, ]; + $card = CreditCardFactory::create('5400619360964581', '20', '01', '056', 'ahmet'); + $gatewayUrl = 'https://epostest.albarakaturk.com.tr/ALBSecurePaymentUI/SecureProcess/SecureVerification.aspx'; yield [ 'order' => $order, 'txType' => PosInterface::TX_TYPE_PAY_AUTH, 'gatewayUrl' => $gatewayUrl, + 'card' => $card, 'expected' => [ + 'gateway' => $gatewayUrl, + 'method' => 'POST', 'inputs' => [ 'MerchantNo' => '6700950031', 'TerminalNo' => '67540050', @@ -275,8 +293,34 @@ public static function threeDFormDataTestProvider(): iterable 'UseOOS' => '0', 'Mac' => 'xuhPbpcPJ6kVs7JeIXS8f06Cv0mb9cNPMfjp1HiB7Ew=', ], - 'method' => 'POST', + ], + ]; + + yield '3d_host_order' => [ + 'order' => $order, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'gatewayUrl' => $gatewayUrl, + 'card' => null, + 'expected' => [ 'gateway' => $gatewayUrl, + 'method' => 'POST', + 'inputs' => [ + 'MerchantNo' => '6700950031', + 'TerminalNo' => '67540050', + 'PosnetID' => '1010028724242434', + 'TransactionType' => 'Sale', + 'OrderId' => '0000000620093100_024', + 'Amount' => '175', + 'CurrencyCode' => 'TL', + 'MerchantReturnURL' => 'https://domain.com/success', + 'InstallmentCount' => '0', + 'Language' => 'tr', + 'TxnState' => 'INITIAL', + 'OpenNewWindow' => '0', + 'UseOOS' => '1', + 'MacParams' => 'MerchantNo:TerminalNo:Amount', + 'Mac' => 'UBdwWJh9rBCM0YWkBti7vHZm2G+nag16hAguohNrq1Y=', + ], ], ]; } @@ -394,6 +438,33 @@ public static function nonSecurePostPaymentDataProvider(): iterable 'MAC' => 'wgyfAJPbEPtTtce/+HRlXajSRfYA0J6mUcH+16EbB78=', ], ]; + + yield 'with_installment' => [ + 'order' => [ + 'id' => '123', + 'installment' => 2, + 'amount' => 12.3, + 'currency' => PosInterface::CURRENCY_TRY, + 'ref_ret_num' => '159044932490000231', + ], + 'expected' => [ + 'ApiType' => 'JSON', + 'ApiVersion' => 'V100', + 'MACParams' => 'MerchantNo:TerminalNo', + 'MerchantNo' => '6700950031', + 'TerminalNo' => '67540050', + 'CipheredData' => null, + 'DealerData' => null, + 'IsEncrypted' => null, + 'PaymentFacilitatorData' => null, + 'Amount' => 1230, + 'CurrencyCode' => 'TL', + 'ReferenceCode' => '159044932490000231', + 'InstallmentCount' => '2', + 'InstallmentType' => 'Y', + 'MAC' => 'wgyfAJPbEPtTtce/+HRlXajSRfYA0J6mUcH+16EbB78=', + ], + ]; } public static function create3DPaymentRequestDataProvider(): \Generator @@ -401,7 +472,7 @@ public static function create3DPaymentRequestDataProvider(): \Generator $order = [ 'id' => '2020110828BC', 'amount' => 100.01, - 'installment' => '0', + 'installment' => 0, 'currency' => PosInterface::CURRENCY_TRY, ]; yield [ @@ -440,6 +511,45 @@ public static function create3DPaymentRequestDataProvider(): \Generator 'MAC' => 'kAKxvbwXvmrM6lapGx1UcRTs454tsSuPrBXV7oA7L7w=', ], ]; + + $order['installment'] = 2; + + yield 'with_installment' => [ + 'order' => $order, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'responseData' => [ + 'SecureTransactionId' => '1010028947569644', + 'CAVV' => 'jKOBaLBL3hQ+CREBPu1HBQQAAAA=', + 'ECI' => '02', + 'MdStatus' => '1', + 'MD' => '9998F61E1D0C0FB6EC5203A748124F30', + ], + 'expected' => [ + 'ApiType' => 'JSON', + 'ApiVersion' => 'V100', + 'MerchantNo' => '6700950031', + 'TerminalNo' => '67540050', + 'PaymentInstrumentType' => 'CARD', + 'IsEncrypted' => 'N', + 'IsTDSecureMerchant' => 'Y', + 'IsMailOrder' => 'N', + 'ThreeDSecureData' => [ + 'SecureTransactionId' => '1010028947569644', + 'CavvData' => 'jKOBaLBL3hQ+CREBPu1HBQQAAAA=', + 'Eci' => '02', + 'MdStatus' => 1, + 'MD' => '9998F61E1D0C0FB6EC5203A748124F30', + ], + 'MACParams' => 'MerchantNo:TerminalNo:SecureTransactionId:CavvData:Eci:MdStatus', + 'Amount' => 10001, + 'CurrencyCode' => 'TL', + 'PointAmount' => 0, + 'OrderId' => '000000002020110828BC', + 'InstallmentCount' => '2', + 'InstallmentType' => 'Y', + 'MAC' => 'kAKxvbwXvmrM6lapGx1UcRTs454tsSuPrBXV7oA7L7w=', + ], + ]; } public static function createRefundRequestDataDataProvider(): iterable @@ -470,6 +580,33 @@ public static function createRefundRequestDataDataProvider(): iterable ], ]; + yield 'refund_non_secure_order' => [ + 'order' => [ + 'id' => '000000002020110828BC', + 'amount' => 112, + 'payment_model' => PosInterface::MODEL_NON_SECURE, + 'transaction_type' => PosInterface::TX_TYPE_PAY_AUTH, + ], + 'tx_type' => PosInterface::TX_TYPE_REFUND, + 'expected' => [ + 'ApiType' => 'JSON', + 'ApiVersion' => 'V100', + 'MerchantNo' => '6700950031', + 'TerminalNo' => '67540050', + 'MACParams' => 'MerchantNo:TerminalNo:ReferenceCode:OrderId', + 'MAC' => '9Ffy2cgMphKFSg2nyXr38gKXJhC8HL+L6X3KEkpt0AQ=', + 'CipheredData' => null, + 'DealerData' => null, + 'IsEncrypted' => null, + 'PaymentFacilitatorData' => null, + 'ReferenceCode' => null, + 'OrderId' => '0000000000002020110828BC', + 'TransactionType' => 'Sale', + 'Amount' => 11200, + 'CurrencyCode' => 'TL', + ], + ]; + yield 'withOrderId' => [ 'order' => [ 'id' => '000000002020110828BC', diff --git a/tests/Unit/DataMapper/RequestDataMapper/ToslaPosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/ToslaPosRequestDataMapperTest.php index bf04cad4..f39e28da 100644 --- a/tests/Unit/DataMapper/RequestDataMapper/ToslaPosRequestDataMapperTest.php +++ b/tests/Unit/DataMapper/RequestDataMapper/ToslaPosRequestDataMapperTest.php @@ -19,6 +19,7 @@ /** * @covers \Mews\Pos\DataMapper\RequestDataMapper\ToslaPosRequestDataMapper + * @covers \Mews\Pos\DataMapper\RequestDataMapper\AbstractRequestDataMapper */ class ToslaPosRequestDataMapperTest extends TestCase { @@ -250,6 +251,24 @@ public function testCreateRefundRequestData(array $order, string $txType, array $this->assertSame($expected, $actual); } + public function testCreate3DPaymentRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->create3DPaymentRequestData( + $this->account, + [], + PosInterface::TX_TYPE_PAY_AUTH, + [] + ); + } + + public function testCreateHistoryRequestData(): void + { + $this->expectException(\Mews\Pos\Exceptions\NotImplementedException::class); + $this->requestDataMapper->createHistoryRequestData($this->account); + } + + public static function statusRequestDataProvider(): array { return [ @@ -469,13 +488,17 @@ public static function threeDFormDataProvider(): array ], 'tx_type' => PosInterface::TX_TYPE_PAY_AUTH, 'payment_model' => PosInterface::MODEL_3D_PAY, - 'is_with_card' => false, + 'is_with_card' => true, 'gateway' => 'https://ent.akodepos.com/api/Payment/ProcessCardForm', - 'expected' => [ + 'expected' => [ 'gateway' => 'https://ent.akodepos.com/api/Payment/ProcessCardForm', 'method' => 'POST', 'inputs' => [ 'ThreeDSessionId' => 'P6D383818909442128AB50AB1EC7A4B83080874341688447DA74B90150C8857F2', + 'CardHolderName' => 'ahmet', + 'CardNo' => '5555444433332222', + 'ExpireDate' => '01/22', + 'Cvv' => '123', ], ], ], diff --git a/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php index 758c58ab..5589809b 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php @@ -612,6 +612,83 @@ public static function threeDPaymentDataProvider(): array 'transaction_time' => null, ], ], + '3d_auth_fail_1' => [ + 'order' => [], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'apiversion' => '512', + 'authcode' => '', + 'cavv' => '', + 'cavvalgorithm' => '', + 'clientid' => '30691298', + 'customeripaddress' => '192.168.0.1', + 'eci' => '', + 'errmsg' => '', + 'errorurl' => 'http://localhost:807/garanti/3d/response.php', + 'garanticardind' => '', + 'hash' => 'FD9BF014BFBC3D977B123AE84247CE3F639913644429304C4EE108C0F40212853628CAECAADB798EE73D467F50C3B5D90FE0F3B921EDAA94B6E2EA888F9FE9B7', + 'hashparams' => 'clientid:oid:authcode:procreturncode:response:mdstatus:cavv:eci:md:rnd:', + 'hashparamsval' => '30691298202409078CF30aW5kZXg6MDIYjoYTHmZE91tOHZxS3PEkMcb8vBvm21xQz107TS6WKHVjLlrZP9AMx7KFu8jZRZA3WtZxMUuaUynWLxQGsVrw1vTKIofUQ0dw2P/jVVvPMX/RxI7Bpjvo/pZp3Nmbj2wd1W146UhNNmge7eA+hdrNSHuPp7PmjAihyZEPujAi3Q==6ga2Y3buKZ3ZcJSC7uE6', + 'hostmsg' => '', + 'hostrefnum' => '', + 'ireqcode' => '', + 'ireqdetail' => '', + 'MaskedPan' => '42822090****8012', + 'md' => 'aW5kZXg6MDIYjoYTHmZE91tOHZxS3PEkMcb8vBvm21xQz107TS6WKHVjLlrZP9AMx7KFu8jZRZA3WtZxMUuaUynWLxQGsVrw1vTKIofUQ0dw2P/jVVvPMX/RxI7Bpjvo/pZp3Nmbj2wd1W146UhNNmge7eA+hdrNSHuPp7PmjAihyZEPujAi3Q==', + 'mderrormessage' => '', + 'mdstatus' => '0', + 'mode' => 'TEST', + 'oid' => '202409078CF3', + 'orderid' => '202409078CF3', + 'paressyntaxok' => '', + 'paresverified' => '', + 'procreturncode' => '', + 'response' => '', + 'rnd' => '6ga2Y3buKZ3ZcJSC7uE6', + 'secure3dhash' => '9F3027C22FB3485484144993E5EE0B0B99FB30A7CF76EBF885F0F01BC0898FB54C3892F02FAB1BF8C16B0F8C868A6C6F7689381D0DBC882ABA786EA764B13DCA', + 'secure3dsecuritylevel' => '3D', + 'successurl' => 'http://localhost:807/garanti/3d/response.php', + 'terminalid' => '30691298', + 'terminalmerchantid' => '7000679', + 'terminalprovuserid' => 'PROVAUT', + 'terminaluserid' => 'PROVAUT', + 'transid' => '202409078CF3', + 'txnamount' => '1001', + 'txncurrencycode' => '949', + 'txninstallmentcount' => '', + 'txnstatus' => '', + 'txntype' => 'sales', + 'vendorcode' => '', + 'version' => '', + 'xid' => '9df81889-86f6-42bf-9129-8189d30e6fef', + ], + 'paymentData' => [], + 'expectedData' => [ + 'order_id' => '202409078CF3', + 'transaction_id' => null, + 'auth_code' => null, + 'ref_ret_num' => null, + 'transaction_security' => 'MPI fallback', + 'proc_return_code' => null, + 'md_status' => '0', + 'status' => 'declined', + 'status_detail' => null, + 'masked_number' => null, + 'amount' => 10.01, + 'currency' => 'TRY', + 'tx_status' => null, + 'eci' => null, + 'cavv' => null, + 'error_code' => null, + 'error_message' => null, + 'md_error_message' => null, + 'batch_num' => null, + 'transaction_type' => 'pay', + 'payment_model' => '3d', + 'installment_count' => 0, + 'transaction_time' => null, + ], + ], 'success1' => [ 'order' => [], 'txType' => PosInterface::TX_TYPE_PAY_AUTH, diff --git a/tests/Unit/DataMapper/ResponseDataMapper/PosNetResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/PosNetResponseDataMapperTest.php index cbc872cf..8dbbd31e 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/PosNetResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/PosNetResponseDataMapperTest.php @@ -7,6 +7,7 @@ use Mews\Pos\DataMapper\RequestDataMapper\PosNetRequestDataMapper; use Mews\Pos\DataMapper\ResponseDataMapper\PosNetResponseDataMapper; +use Mews\Pos\Exceptions\NotImplementedException; use Mews\Pos\Factory\CryptFactory; use Mews\Pos\Gateways\PosNet; use Mews\Pos\PosInterface; @@ -139,6 +140,23 @@ public function testMapRefundResponse(array $responseData, array $expectedData): $this->assertSame($expectedData, $actualData); } + public function testMapHistoryResponse(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->mapHistoryResponse([]); + } + + public function testMap3DPayResponseData(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->map3DPayResponseData([], PosInterface::TX_TYPE_PAY_AUTH, []); + } + + public function testMap3DHostResponseData(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->map3DHostResponseData([], PosInterface::TX_TYPE_PAY_AUTH, []); + } public function paymentTestDataProvider(): array { diff --git a/tests/Unit/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapperTest.php index 421be0b2..164368c3 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/PosNetV1PosResponseDataMapperTest.php @@ -7,6 +7,7 @@ use Mews\Pos\DataMapper\RequestDataMapper\PosNetV1PosRequestDataMapper; use Mews\Pos\DataMapper\ResponseDataMapper\PosNetV1PosResponseDataMapper; +use Mews\Pos\Exceptions\NotImplementedException; use Mews\Pos\Factory\CryptFactory; use Mews\Pos\Gateways\PosNetV1Pos; use Mews\Pos\PosInterface; @@ -148,6 +149,29 @@ public function testMapRefundResponse(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 testMap3DPayResponseData(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->map3DPayResponseData([], PosInterface::TX_TYPE_PAY_AUTH, []); + } + + public function testMap3DHostResponseData(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->map3DHostResponseData([], PosInterface::TX_TYPE_PAY_AUTH, []); + } public static function paymentTestDataProvider(): iterable { diff --git a/tests/Unit/DataMapper/ResponseDataMapper/ToslaPosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/ToslaPosResponseDataMapperTest.php index 1b9a2463..37809300 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/ToslaPosResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/ToslaPosResponseDataMapperTest.php @@ -7,6 +7,7 @@ use Mews\Pos\DataMapper\RequestDataMapper\ToslaPosRequestDataMapper; use Mews\Pos\DataMapper\ResponseDataMapper\ToslaPosResponseDataMapper; +use Mews\Pos\Exceptions\NotImplementedException; use Mews\Pos\Factory\CryptFactory; use Mews\Pos\Gateways\ToslaPos; use Mews\Pos\PosInterface; @@ -169,7 +170,7 @@ public function testMapCancelResponse(array $responseData, array $expectedData): /** * @dataProvider orderHistoryDataProvider */ - public function testMapHistoryResponse(array $responseData, array $expectedData): void + public function testMapOrderHistoryResponse(array $responseData, array $expectedData): void { $actualData = $this->responseDataMapper->mapOrderHistoryResponse($responseData); if (isset($responseData['Transactions'])) { @@ -203,6 +204,18 @@ public function testMapHistoryResponse(array $responseData, array $expectedData) $this->assertSame($expectedData, $actualData); } + public function testMap3DPaymentResponseData(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->map3DPaymentData([], [], PosInterface::TX_TYPE_PAY_AUTH, []); + } + + public function testMapHistoryResponse(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->mapHistoryResponse([]); + } + public static function paymentDataProvider(): iterable { yield 'success1' => [ diff --git a/tests/Unit/Gateways/AkbankPosTest.php b/tests/Unit/Gateways/AkbankPosTest.php index 179c2b39..917ebb77 100644 --- a/tests/Unit/Gateways/AkbankPosTest.php +++ b/tests/Unit/Gateways/AkbankPosTest.php @@ -3,7 +3,7 @@ * @license MIT */ -namespace Gateways; +namespace Mews\Pos\Tests\Unit\Gateways; use Mews\Pos\Client\HttpClient; use Mews\Pos\Crypt\CryptInterface; @@ -132,6 +132,16 @@ public function testGetApiURL(?string $txType, string $paymentModel, string $exp $this->assertSame($expected, $actual); } + /** + * @dataProvider getApiUrlExceptionDataProvider + */ + public function testGetApiURLException(?string $txType, string $exceptionClass): void + { + $this->expectException($exceptionClass); + + $this->pos->getApiURL($txType); + } + public function testGet3DGatewayURL(): void { $actual = $this->pos->get3DGatewayURL(); @@ -657,10 +667,15 @@ public static function getApiUrlDataProvider(): array 'paymentModel' => PosInterface::MODEL_NON_SECURE, 'expected' => 'https://apipre.akbank.com/api/v1/payment/virtualpos/portal/report/transaction', ], + ]; + } + + public static function getApiUrlExceptionDataProvider(): array + { + return [ [ - 'txType' => null, - 'paymentModel' => PosInterface::MODEL_NON_SECURE, - 'expected' => 'https://apipre.akbank.com/api/v1/payment/virtualpos', + 'txType' => null, + 'exception_class' => \InvalidArgumentException::class, ], ]; } @@ -887,6 +902,8 @@ private function configureClientResponse( ?int $statusCode = null ): void { + $updatedRequestDataPreparedEvent = null; + $this->cryptMock->expects(self::once()) ->method('hashString') ->with($encodedRequestData, $this->account->getStoreKey()) @@ -894,7 +911,7 @@ private function configureClientResponse( $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -918,11 +935,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/EstPosTest.php b/tests/Unit/Gateways/EstPosTest.php index d032f8dc..8e793276 100644 --- a/tests/Unit/Gateways/EstPosTest.php +++ b/tests/Unit/Gateways/EstPosTest.php @@ -12,6 +12,7 @@ use Mews\Pos\Entity\Account\EstPosAccount; 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; @@ -205,6 +206,23 @@ public function testMake3DHostPaymentSuccess(): void $this->assertTrue($pos->isSuccess()); } + public function testMake3DHostPaymentHashMismatchException(): void + { + $data = EstPosResponseDataMapperTest::threeDHostPaymentDataProvider()['success1']['paymentData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DHostResponseData'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DHostPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @return void */ @@ -233,6 +251,23 @@ public function testMake3DPayPaymentSuccess(): void $this->assertTrue($pos->isSuccess()); } + public function testMake3DPayPaymentHashMismatchException(): void + { + $data = EstPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['paymentData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPayResponseData'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @dataProvider statusDataProvider */ @@ -467,6 +502,36 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $data = EstPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['threeDResponseData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPaymentData'); + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + $this->eventDispatcherMock->expects(self::never()) + ->method('dispatch'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + + /** * @dataProvider makeRegularPaymentDataProvider */ @@ -701,9 +766,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -722,11 +789,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/GarantiPosTest.php b/tests/Unit/Gateways/GarantiPosTest.php index 2d5532c8..7c226550 100644 --- a/tests/Unit/Gateways/GarantiPosTest.php +++ b/tests/Unit/Gateways/GarantiPosTest.php @@ -12,6 +12,7 @@ use Mews\Pos\Entity\Account\GarantiPosAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Exceptions\UnsupportedPaymentModelException; use Mews\Pos\Factory\AccountFactory; use Mews\Pos\Factory\CreditCardFactory; @@ -244,6 +245,35 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $data = GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['threeDResponseData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPaymentData'); + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + $this->eventDispatcherMock->expects(self::never()) + ->method('dispatch'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + public function testMake3DHostPayment(): void { $request = Request::create('', 'POST'); @@ -519,10 +549,27 @@ public function testOrderHistoryRequest(array $order, string $apiUrl): void public static function make3DPaymentDataProvider(): array { return [ + '3d_auth_fail_1' => [ + 'order' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_fail_1']['order'], + 'txType' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_fail_1']['txType'], + 'request' => Request::create( + '', + 'POST', + GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_fail_1']['threeDResponseData'] + ), + 'paymentResponse' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_fail_1']['paymentData'], + 'expected' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_fail_1']['expectedData'], + 'is3DSuccess' => false, + 'isSuccess' => false, + ], '3d_auth_success_payment_fail' => [ 'order' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['order'], 'txType' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['txType'], - 'request' => Request::create('', 'POST', GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['threeDResponseData']), + 'request' => Request::create( + '', + 'POST', + GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['threeDResponseData'] + ), 'paymentResponse' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['paymentData'], 'expected' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['paymentFail1']['expectedData'], 'is3DSuccess' => true, @@ -531,7 +578,11 @@ public static function make3DPaymentDataProvider(): array 'success' => [ 'order' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['order'], 'txType' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['txType'], - 'request' => Request::create('', 'POST', GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData']), + 'request' => Request::create( + '', + 'POST', + GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData'] + ), 'paymentResponse' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['paymentData'], 'expected' => GarantiPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['expectedData'], 'is3DSuccess' => true, @@ -631,9 +682,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -652,12 +705,25 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } public static function historyRequestDataProvider(): array diff --git a/tests/Unit/Gateways/InterPosTest.php b/tests/Unit/Gateways/InterPosTest.php index 59226a72..45405d9b 100644 --- a/tests/Unit/Gateways/InterPosTest.php +++ b/tests/Unit/Gateways/InterPosTest.php @@ -621,9 +621,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -642,11 +644,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/KuveytPosTest.php b/tests/Unit/Gateways/KuveytPosTest.php index 0d433790..7e1eeaa9 100644 --- a/tests/Unit/Gateways/KuveytPosTest.php +++ b/tests/Unit/Gateways/KuveytPosTest.php @@ -179,7 +179,7 @@ public function testGetApiURL(?string $txType, ?string $paymentModel, string $ex /** * @dataProvider getApiUrlExceptionDataProvider */ - public function testGetApiURLException(string $txType, string $paymentModel, string $exceptionClass): void + public function testGetApiURLException(?string $txType, ?string $paymentModel, string $exceptionClass): void { $this->expectException($exceptionClass); @@ -265,6 +265,7 @@ public function testMake3DPayment( $create3DPaymentRequestData = [ 'create3DPaymentRequestData', ]; + $encodedRequestData = 'request-body'; if ($is3DSuccess) { @@ -277,7 +278,7 @@ public function testMake3DPayment( 'response-body', 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelProvisionGate', [ - 'body' => 'request-body', + 'body' => $encodedRequestData, 'headers' => [ 'Content-Type' => 'text/xml; charset=UTF-8', ], @@ -286,17 +287,30 @@ public function testMake3DPayment( $paymentModel = PosInterface::MODEL_3D_SECURE; $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $create3DPaymentRequestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($create3DPaymentRequestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $create3DPaymentRequestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function() use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); $this->serializerMock->expects(self::once()) ->method('encode') - ->with($create3DPaymentRequestData, $txType) - ->willReturn('request-body'); + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) + ->willReturn($encodedRequestData); $this->serializerMock->expects(self::exactly(2)) ->method('decode') @@ -339,6 +353,34 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentException(): void + { + $request = Request::create(''); + + $this->cryptMock->expects(self::never()) + ->method('check3DHash'); + + $this->responseMapperMock->expects(self::never()) + ->method('extractMdStatus'); + + $this->responseMapperMock->expects(self::never()) + ->method('is3dAuthSuccess'); + + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPaymentData'); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + + $this->expectException(\LogicException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @dataProvider makeRegularPaymentDataProvider */ @@ -502,11 +544,6 @@ public static function getApiUrlDataProvider(): array 'paymentModel' => PosInterface::MODEL_NON_SECURE, 'expected' => 'https://boatest.kuveytturk.com.tr/BOA.Integration.WCFService/BOA.Integration.VirtualPos/VirtualPosService.svc?wsdl', ], - [ - 'txType' => null, - 'paymentModel' => null, - 'expected' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home', - ], ]; } @@ -518,6 +555,26 @@ public static function getApiUrlExceptionDataProvider(): array 'paymentModel' => PosInterface::MODEL_3D_PAY, 'exception_class' => UnsupportedTransactionTypeException::class, ], + [ + 'txType' => PosInterface::TX_TYPE_PAY_PRE_AUTH, + 'paymentModel' => PosInterface::MODEL_NON_SECURE, + 'exception_class' => UnsupportedTransactionTypeException::class, + ], + [ + 'txType' => null, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => null, + 'paymentModel' => PosInterface::MODEL_3D_PAY, + 'exception_class' => \InvalidArgumentException::class, + ], ]; } @@ -533,9 +590,11 @@ private function configureClientResponse( ?int $statusCode = null ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -558,11 +617,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/PayFlexCPV4PosTest.php b/tests/Unit/Gateways/PayFlexCPV4PosTest.php index f4939630..b039bcb8 100644 --- a/tests/Unit/Gateways/PayFlexCPV4PosTest.php +++ b/tests/Unit/Gateways/PayFlexCPV4PosTest.php @@ -582,13 +582,16 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + if ($requestData === $encodedRequestData) { $this->serializerMock->expects(self::never()) ->method('encode'); + $encodedRequestData['test-update-request-data-with-event'] = true; } else { $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); } @@ -606,11 +609,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/PayFlexV4PosTest.php b/tests/Unit/Gateways/PayFlexV4PosTest.php index 232ef759..1f359b55 100644 --- a/tests/Unit/Gateways/PayFlexV4PosTest.php +++ b/tests/Unit/Gateways/PayFlexV4PosTest.php @@ -75,12 +75,12 @@ protected function setUp(): void parent::setUp(); $this->config = [ - 'name' => 'VakifBank-VPOS', - 'class' => PayFlexV4Pos::class, - 'gateway_endpoints' => [ - 'payment_api' => 'https://onlineodemetest.vakifbank.com.tr:4443/VposService/v3/Vposreq.aspx', - 'gateway_3d' => 'https://3dsecuretest.vakifbank.com.tr:4443/MPIAPI/MPI_Enrollment.aspxs', - 'query_api' => 'https://sanalpos.vakifbank.com.tr/v4/UIWebService/Search.aspx', + 'name' => 'VakifBank-VPOS', + 'class' => PayFlexV4Pos::class, + 'gateway_endpoints' => [ + 'payment_api' => 'https://onlineodemetest.vakifbank.com.tr:4443/VposService/v3/Vposreq.aspx', + 'gateway_3d' => 'https://3dsecuretest.vakifbank.com.tr:4443/MPIAPI/MPI_Enrollment.aspxs', + 'query_api' => 'https://sanalpos.vakifbank.com.tr/v4/UIWebService/Search.aspx', ], ]; @@ -128,7 +128,14 @@ protected function setUp(): void $this->pos->setTestMode(true); - $this->card = CreditCardFactory::createForGateway($this->pos, '5555444433332222', '2021', '12', '122', 'ahmet', CreditCardInterface::CARD_TYPE_VISA); + $this->card = CreditCardFactory::create( + '5555444433332222', + '2021', + '12', + '122', + 'ahmet', + CreditCardInterface::CARD_TYPE_VISA + ); } /** @@ -147,11 +154,10 @@ public function testInit(): void /** * @return void * - * @throws Exception + * @dataProvider enrollmentFailResponseDataProvider */ - public function testGet3DFormDataEnrollmentFail(): void + public function testGet3DFormDataEnrollmentFail(array $response): void { - $this->expectException(Exception::class); $txType = PosInterface::TX_TYPE_PAY_AUTH; $requestData = ['request-data']; $order = $this->order; @@ -162,11 +168,11 @@ public function testGet3DFormDataEnrollmentFail(): void $this->configureClientResponse( $txType, - $this->config['gateway_endpoints']['gateway_3d'], + 'https://3dsecuretest.vakifbank.com.tr:4443/MPIAPI/MPI_Enrollment.aspxs', $requestData, $requestData, 'response-body', - self::getSampleEnrollmentFailResponseDataProvider(), + $response, $order, PosInterface::MODEL_3D_SECURE ); @@ -174,9 +180,25 @@ public function testGet3DFormDataEnrollmentFail(): void $this->requestMapperMock->expects(self::never()) ->method('create3DFormData'); + $this->expectException(\RuntimeException::class); $this->pos->get3DFormData($order, PosInterface::MODEL_3D_SECURE, $txType, $this->card); } + public function testGet3DFormDataWithoutCard(): void + { + $this->requestMapperMock->expects(self::never()) + ->method('create3DEnrollmentCheckRequestData'); + + $this->httpClientMock->expects(self::never()) + ->method('post'); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $this->expectException(\LogicException::class); + $this->pos->get3DFormData([], PosInterface::MODEL_3D_SECURE, PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @return void * @@ -496,17 +518,21 @@ public function testOrderHistoryRequest(): void $this->pos->orderHistory([]); } - public static function getSampleEnrollmentFailResponseDataProvider(): array + public static function enrollmentFailResponseDataProvider(): array { return [ - 'Message' => [ - 'VERes' => [ - 'Status' => 'E', + 'merchant_not_found' => [ + 'response' => [ + 'Message' => [ + 'VERes' => [ + 'Status' => 'E', + ], + ], + 'VerifyEnrollmentRequestId' => '0aebb0757acccae6fba75b2e4d78cecf', + 'MessageErrorCode' => '2005', + 'ErrorMessage' => 'Merchant cannot be found for this bank', ], ], - 'VerifyEnrollmentRequestId' => '0aebb0757acccae6fba75b2e4d78cecf', - 'MessageErrorCode' => '2005', - 'ErrorMessage' => 'Merchant cannot be found for this bank', ]; } @@ -595,28 +621,28 @@ public static function make3DPaymentDataProvider(): array 'isSuccess' => false, ], '3d_auth_success_payment_fail' => [ - 'order' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['order'], - 'txType' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['txType'], - 'request' => Request::create( + 'order' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['order'], + 'txType' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['txType'], + 'request' => Request::create( '', 'POST', PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['threeDResponseData'] - ), 'paymentResponse' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['paymentData'], - 'expected' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['expectedData'], - 'is3DSuccess' => true, - 'isSuccess' => false, + ), 'paymentResponse' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['paymentData'], + 'expected' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['expectedData'], + 'is3DSuccess' => true, + 'isSuccess' => false, ], 'success' => [ - 'order' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['order'], - 'txType' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['txType'], - 'request' => Request::create( + 'order' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['order'], + 'txType' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['txType'], + 'request' => Request::create( '', 'POST', PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['3d_auth_success_payment_fail']['threeDResponseData'] - ), 'paymentResponse' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['paymentData'], - 'expected' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['expectedData'], - 'is3DSuccess' => true, - 'isSuccess' => true, + ), 'paymentResponse' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['paymentData'], + 'expected' => PayFlexV4PosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['expectedData'], + 'is3DSuccess' => true, + 'isSuccess' => true, ], ]; } @@ -625,20 +651,23 @@ private function configureClientResponse( string $txType, string $apiUrl, array $requestData, - $encodedRequestData, + $encodedRequestData, string $responseContent, array $decodedResponse, array $order, string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + if ($requestData === $encodedRequestData) { $this->serializerMock->expects(self::never()) ->method('encode'); + $encodedRequestData['test-update-request-data-with-event'] = true; } else { $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); } @@ -658,11 +687,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function() use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/PayForTest.php b/tests/Unit/Gateways/PayForTest.php index 04f71d13..34577dd3 100644 --- a/tests/Unit/Gateways/PayForTest.php +++ b/tests/Unit/Gateways/PayForTest.php @@ -12,6 +12,7 @@ use Mews\Pos\Entity\Account\PayForAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Factory\AccountFactory; use Mews\Pos\Factory\CreditCardFactory; use Mews\Pos\Gateways\PayForPos; @@ -258,6 +259,35 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $data = PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPaymentData'); + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + $this->eventDispatcherMock->expects(self::never()) + ->method('dispatch'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @return void */ @@ -556,7 +586,11 @@ public static function make3DPaymentDataProvider(): array 'auth_fail' => [ 'order' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['order'], 'txType' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['txType'], - 'request' => Request::create('', 'POST', PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['threeDResponseData']), + 'request' => Request::create( + '', + 'POST', + PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['threeDResponseData'] + ), 'paymentResponse' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['paymentData'], 'expected' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['expectedData'], 'is3DSuccess' => false, @@ -565,7 +599,11 @@ public static function make3DPaymentDataProvider(): array 'order_number_already_exist' => [ 'order' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['order'], 'txType' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['txType'], - 'request' => Request::create('', 'POST', PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['threeDResponseData']), + 'request' => Request::create( + '', + 'POST', + PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['threeDResponseData'] + ), 'paymentResponse' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['paymentData'], 'expected' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['expectedData'], 'is3DSuccess' => false, @@ -574,7 +612,11 @@ public static function make3DPaymentDataProvider(): array 'success' => [ 'order' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['order'], 'txType' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['txType'], - 'request' => Request::create('', 'POST', PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData']), + 'request' => Request::create( + '', + 'POST', + PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData'] + ), 'paymentResponse' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['paymentData'], 'expected' => PayForPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['expectedData'], 'is3DSuccess' => true, @@ -686,9 +728,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -710,11 +754,23 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + }))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/PosNetTest.php b/tests/Unit/Gateways/PosNetTest.php index 8989393b..9525d4f7 100644 --- a/tests/Unit/Gateways/PosNetTest.php +++ b/tests/Unit/Gateways/PosNetTest.php @@ -15,6 +15,7 @@ use Mews\Pos\Entity\Account\PosNetAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Exceptions\UnsupportedPaymentModelException; use Mews\Pos\Exceptions\UnsupportedTransactionTypeException; use Mews\Pos\Factory\AccountFactory; @@ -182,6 +183,21 @@ public function testGet3DFormDataOosTransactionFail(): void $this->pos->get3DFormData($order, PosInterface::MODEL_3D_SECURE, $txType, $this->card); } + public function testGet3DFormDataWithoutCard(): void + { + $this->requestMapperMock->expects(self::never()) + ->method('create3DEnrollmentCheckRequestData'); + + $this->httpClientMock->expects(self::never()) + ->method('post'); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $this->expectException(\LogicException::class); + $this->pos->get3DFormData([], PosInterface::MODEL_3D_SECURE, PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @dataProvider make3DPaymentDataProvider */ @@ -232,20 +248,36 @@ public function testMake3DPayment( ->with($this->account, $order, $txType, $request->request->all()) ->willReturn($create3DPaymentRequestData); - $this->serializerMock->expects(self::exactly(2)) + + $matcher = self::exactly(2); + $updatedRequestDataPreparedEvent1 = null; + $updatedRequestDataPreparedEvent2 = null; + + $this->serializerMock->expects($matcher) ->method('encode') - ->willReturnMap([ - [ - $resolveMerchantRequestData, - $txType, - 'resolveMerchantRequestData-body', - ], - [ - $create3DPaymentRequestData, - $txType, - 'payment-request-body', - ], - ]); + ->with($this->callback(function ($requestData) use ($matcher, &$updatedRequestDataPreparedEvent1, &$updatedRequestDataPreparedEvent2) { + if ($matcher->getInvocationCount() === 1) { + return $updatedRequestDataPreparedEvent1->getRequestData() === $requestData; + } + + if ($matcher->getInvocationCount() === 2) { + return $updatedRequestDataPreparedEvent2->getRequestData() === $requestData; + } + + return true; + }), $this->callback(function ($txT) use ($txType) { + return $txT === $txType; + })) + ->willReturnCallback(function () use ($matcher) { + if ($matcher->getInvocationCount() === 1) { + return 'resolveMerchantRequestData-body'; + } + if ($matcher->getInvocationCount() === 2) { + return 'payment-request-body'; + } + + return null; + }); $this->serializerMock->expects(self::exactly(2)) ->method('decode') @@ -289,23 +321,62 @@ public function testMake3DPayment( ); $paymentModel = PosInterface::MODEL_3D_SECURE; - $this->eventDispatcherMock->expects(self::exactly(2)) + + $matcher2 = self::exactly(2); + $this->eventDispatcherMock->expects($matcher2) ->method('dispatch') - // could not find another way expect using deprecated withConsecutive() function - ->withConsecutive( - [$this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $resolveMerchantRequestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())], - [$this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $create3DPaymentRequestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())] - ); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function ($dispatchedEvent) use ( + $resolveMerchantRequestData, + $create3DPaymentRequestData, + $txType, + $order, + $paymentModel, + $matcher2, + &$updatedRequestDataPreparedEvent1, + &$updatedRequestDataPreparedEvent2 + ) { + if ($matcher2->getInvocationCount() === 1) { + $updatedRequestDataPreparedEvent1 = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $resolveMerchantRequestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + + if ($matcher2->getInvocationCount() === 2) { + $updatedRequestDataPreparedEvent2 = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $create3DPaymentRequestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + + return false; + }))) + ->willReturnCallback(function () use ($matcher2, &$updatedRequestDataPreparedEvent1, &$updatedRequestDataPreparedEvent2) { + if ($matcher2->getInvocationCount() === 1) { + $updatedRequestData = $updatedRequestDataPreparedEvent1->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent1->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent1; + } + if ($matcher2->getInvocationCount() === 2) { + $updatedRequestData = $updatedRequestDataPreparedEvent2->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent2->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent2; + } + + return false; + }); $this->responseMapperMock->expects(self::once()) ->method('map3DPaymentData') @@ -339,6 +410,48 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $resolveResponse = PosNetResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData']; + $request = Request::create( + '', + 'POST', + $resolveResponse + ); + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $resolveResponse['oosResolveMerchantDataResponse']) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $resolveMerchantRequestData = [ + 'resolveMerchantRequestData', + ]; + $this->requestMapperMock->expects(self::once()) + ->method('create3DResolveMerchantRequestData') + ->willReturn($resolveMerchantRequestData); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + + $this->configureClientResponse( + PosInterface::TX_TYPE_PAY_AUTH, + 'https://setmpos.ykb.com/PosnetWebService/XML', + $resolveMerchantRequestData, + 'request-body', + 'response-body', + $resolveResponse, + [], + PosInterface::MODEL_3D_SECURE + ); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + public function testMake3DHostPayment(): void { $request = Request::create('', 'POST'); @@ -658,9 +771,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -682,11 +797,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/PosNetV1PosTest.php b/tests/Unit/Gateways/PosNetV1PosTest.php index f656c860..929b2872 100644 --- a/tests/Unit/Gateways/PosNetV1PosTest.php +++ b/tests/Unit/Gateways/PosNetV1PosTest.php @@ -12,6 +12,7 @@ use Mews\Pos\Entity\Account\PosNetAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Exceptions\UnsupportedPaymentModelException; use Mews\Pos\Exceptions\UnsupportedTransactionTypeException; use Mews\Pos\Factory\AccountFactory; @@ -141,6 +142,15 @@ public function testGetApiURL(string $txType, string $mappedTxType, string $expe $this->assertSame($expected, $this->pos->getApiURL($txType)); } + public function testGetApiURLException(): void + { + $this->requestMapperMock->expects(self::never()) + ->method('mapTxType'); + + $this->expectException(\InvalidArgumentException::class); + $this->pos->getApiURL(); + } + /** * @testWith [true] * [false] @@ -251,6 +261,36 @@ public function testMake3DPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPaymentHashMismatchException(): void + { + $dataSamples = iterator_to_array(PosNetV1PosResponseDataMapperTest::threeDPaymentDataProvider()); + $data = $dataSamples['3d_auth_success_payment_fail']['threeDResponseData']; + $request = Request::create('', 'POST', $data); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPaymentData'); + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + $this->eventDispatcherMock->expects(self::never()) + ->method('dispatch'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + public function testMake3DHostPayment(): void { $request = Request::create('', 'POST'); @@ -614,9 +654,11 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); $this->serializerMock->expects(self::once()) @@ -638,11 +680,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function() use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/ToslaPosTest.php b/tests/Unit/Gateways/ToslaPosTest.php index 90cf1a80..acb3aa5c 100644 --- a/tests/Unit/Gateways/ToslaPosTest.php +++ b/tests/Unit/Gateways/ToslaPosTest.php @@ -12,6 +12,7 @@ use Mews\Pos\Entity\Account\ToslaPosAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Event\RequestDataPreparedEvent; +use Mews\Pos\Exceptions\HashMismatchException; use Mews\Pos\Exceptions\UnsupportedPaymentModelException; use Mews\Pos\Exceptions\UnsupportedTransactionTypeException; use Mews\Pos\Factory\AccountFactory; @@ -132,6 +133,15 @@ public function testGetApiURL(string $txType, string $paymentModel, string $expe $this->assertSame($expected, $actual); } + /** + * @dataProvider getApiUrlExceptionDataProvider + */ + public function testGetApiURLException(?string $txType, ?string $paymentModel, string $exceptionClass): void + { + $this->expectException($exceptionClass); + $this->pos->getApiURL($txType, $paymentModel); + } + public function testGet3DGatewayURL(): void { $actual = $this->pos->get3DGatewayURL(); @@ -192,6 +202,27 @@ public function testMake3DPayPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DPayPaymentHashMismatchException(): void + { + $data = ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['paymentData']; + $request = Request::create('', 'POST', $data); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DPayResponseData'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DPayPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @dataProvider make3DPayPaymentDataProvider */ @@ -232,6 +263,27 @@ public function testMake3DHostPayment( $this->assertSame($isSuccess, $this->pos->isSuccess()); } + public function testMake3DHostPaymentHashMismatchException(): void + { + $data = ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['paymentData']; + $request = Request::create('', 'POST', $data); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->willReturn(true); + + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $data) + ->willReturn(false); + + $this->responseMapperMock->expects(self::never()) + ->method('map3DHostResponseData'); + + $this->expectException(HashMismatchException::class); + $this->pos->make3DHostPayment($request, [], PosInterface::TX_TYPE_PAY_AUTH); + } + /** * @dataProvider make3DPayPaymentDataProvider */ @@ -292,6 +344,54 @@ public function testGet3DFormData( $this->assertSame($actual, $formData); } + public function testGet3DFormDataWithoutCard(): void + { + $this->requestMapperMock->expects(self::never()) + ->method('create3DEnrollmentCheckRequestData'); + + $this->httpClientMock->expects(self::never()) + ->method('post'); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $this->expectException(\LogicException::class); + $this->pos->get3DFormData([], PosInterface::MODEL_3D_SECURE, PosInterface::TX_TYPE_PAY_AUTH); + } + + /** + * @return void + * + * @dataProvider registerFailResponseDataProvider + */ + public function testGet3DFormDataRegisterPaymentFail(array $response): void + { + $txType = PosInterface::TX_TYPE_PAY_AUTH; + $requestData = ['request-data']; + $order = ['order']; + $this->requestMapperMock->expects(self::once()) + ->method('create3DEnrollmentCheckRequestData') + ->with($this->pos->getAccount(), $order) + ->willReturn($requestData); + + $this->configureClientResponse( + $txType, + 'https://ent.akodepos.com/api/Payment/threeDPayment', + $requestData, + 'encoded-request', + 'response-body', + $response, + $order, + PosInterface::MODEL_3D_PAY + ); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $this->expectException(\RuntimeException::class); + $this->pos->get3DFormData($order, PosInterface::MODEL_3D_PAY, $txType, $this->card); + } + /** * @dataProvider statusDataProvider */ @@ -439,8 +539,8 @@ public function testOrderHistory( bool $isSuccess ): void { - $account = $this->pos->getAccount(); - $txType = PosInterface::TX_TYPE_ORDER_HISTORY; + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_ORDER_HISTORY; $this->requestMapperMock->expects(self::once()) ->method('createOrderHistoryRequestData') @@ -559,7 +659,11 @@ public static function make3DPayPaymentDataProvider(): array 'auth_fail' => [ 'order' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['auth_fail']['order'], 'txType' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['auth_fail']['txType'], - 'request' => Request::create('', 'POST', ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['auth_fail']['paymentData']), + 'request' => Request::create( + '', + 'POST', + ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['auth_fail']['paymentData'] + ), 'expected' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['auth_fail']['expectedData'], 'is3DSuccess' => false, 'isSuccess' => false, @@ -567,7 +671,11 @@ public static function make3DPayPaymentDataProvider(): array 'success' => [ 'order' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['order'], 'txType' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['txType'], - 'request' => Request::create('', 'POST', ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['paymentData']), + 'request' => Request::create( + '', + 'POST', + ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['paymentData'] + ), 'expected' => ToslaPosResponseDataMapperTest::threeDPayPaymentDataProvider()['success1']['expectedData'], 'is3DSuccess' => true, 'isSuccess' => true, @@ -808,6 +916,37 @@ public static function getApiUrlDataProvider(): array ]; } + public static function getApiUrlExceptionDataProvider(): array + { + return [ + [ + 'txType' => PosInterface::TX_TYPE_HISTORY, + 'paymentModel' => PosInterface::MODEL_NON_SECURE, + 'exception_class' => UnsupportedTransactionTypeException::class, + ], + [ + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentModel' => PosInterface::MODEL_3D_SECURE, + 'exception_class' => UnsupportedTransactionTypeException::class, + ], + [ + 'txType' => null, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => null, + 'paymentModel' => PosInterface::MODEL_3D_PAY, + 'exception_class' => \InvalidArgumentException::class, + ], + ]; + } + public static function makeRegularPaymentDataProvider(): array { @@ -870,6 +1009,20 @@ public static function refundRequestDataProvider(): array ]; } + public static function registerFailResponseDataProvider(): array + { + return [ + 'merchant_not_found' => [ + 'response' => [ + 'Code' => 202, + 'Message' => 'Üye İşyeri Kullanıcısı Bulunamadı', + 'ThreeDSessionId' => null, + 'TransactionId' => null, + ], + ], + ]; + } + private function configureClientResponse( string $txType, string $apiUrl, @@ -881,10 +1034,13 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); + $this->serializerMock->expects(self::once()) ->method('decode') ->with($responseContent, $txType) @@ -904,11 +1060,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/Gateways/VakifKatilimTest.php b/tests/Unit/Gateways/VakifKatilimTest.php index 0c8f1461..336a7f4b 100644 --- a/tests/Unit/Gateways/VakifKatilimTest.php +++ b/tests/Unit/Gateways/VakifKatilimTest.php @@ -3,7 +3,7 @@ * @license MIT */ -namespace Gateways; +namespace Mews\Pos\Tests\Unit\Gateways; use Mews\Pos\Client\HttpClient; use Mews\Pos\Crypt\CryptInterface; @@ -164,7 +164,7 @@ public function testGetApiURL(string $txType, ?string $orderTxType, string $paym /** * @dataProvider getApiUrlExceptionDataProvider */ - public function testGetApiURLException(string $txType, string $paymentModel, string $exceptionClass): void + public function testGetApiURLException(?string $txType, ?string $paymentModel, string $exceptionClass): void { $this->expectException($exceptionClass); @@ -698,6 +698,21 @@ public static function getApiUrlExceptionDataProvider(): array 'paymentModel' => PosInterface::MODEL_3D_PAY, 'exception_class' => UnsupportedTransactionTypeException::class, ], + [ + 'txType' => null, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentModel' => null, + 'exception_class' => \InvalidArgumentException::class, + ], + [ + 'txType' => null, + 'paymentModel' => PosInterface::MODEL_3D_PAY, + 'exception_class' => \InvalidArgumentException::class, + ], ]; } @@ -832,10 +847,13 @@ private function configureClientResponse( string $paymentModel ): void { + $updatedRequestDataPreparedEvent = null; + $this->serializerMock->expects(self::once()) ->method('encode') - ->with($requestData, $txType) + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $txType) ->willReturn($encodedRequestData); + $this->serializerMock->expects(self::once()) ->method('decode') ->with($responseContent, $txType) @@ -855,11 +873,24 @@ private function configureClientResponse( $this->eventDispatcherMock->expects(self::once()) ->method('dispatch') - ->with($this->callback(fn($dispatchedEvent): bool => $dispatchedEvent instanceof RequestDataPreparedEvent - && get_class($this->pos) === $dispatchedEvent->getGatewayClass() - && $txType === $dispatchedEvent->getTxType() - && $requestData === $dispatchedEvent->getRequestData() - && $order === $dispatchedEvent->getOrder() - && $paymentModel === $dispatchedEvent->getPaymentModel())); + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent) { + $updatedRequestDataPreparedEvent = $dispatchedEvent; + + return get_class($this->pos) === $dispatchedEvent->getGatewayClass() + && $txType === $dispatchedEvent->getTxType() + && $requestData === $dispatchedEvent->getRequestData() + && $order === $dispatchedEvent->getOrder() + && $paymentModel === $dispatchedEvent->getPaymentModel(); + } + ))) + ->willReturnCallback(function () use (&$updatedRequestDataPreparedEvent) { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); } } diff --git a/tests/Unit/HttpClientTestTrait.php b/tests/Unit/HttpClientTestTrait.php index e50d0773..46c0845b 100644 --- a/tests/Unit/HttpClientTestTrait.php +++ b/tests/Unit/HttpClientTestTrait.php @@ -6,11 +6,15 @@ namespace Mews\Pos\Tests\Unit; use Mews\Pos\Client\HttpClient; +use PHPUnit\Framework\MockObject\MockObject; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; trait HttpClientTestTrait { + /** + * @param HttpClient|MockObject $httpClient + */ private function prepareClient( HttpClient $httpClient, string $responseContent, @@ -26,6 +30,9 @@ private function prepareClient( ->willReturn($responseMock); } + /** + * @param HttpClient|MockObject $httpClient + */ private function prepareHttpClientRequestMulti( HttpClient $httpClient, array $responseContents,