diff --git a/src/Gateways/PayFlexCPV4Pos.php b/src/Gateways/PayFlexCPV4Pos.php index 1d824722..97b22697 100644 --- a/src/Gateways/PayFlexCPV4Pos.php +++ b/src/Gateways/PayFlexCPV4Pos.php @@ -170,17 +170,38 @@ public function get3DFormData(array $order, string $paymentModel, string $txType ); } + /** + * @inheritDoc + * + * @return array + */ + protected function send($contents, string $txType, string $paymentModel, ?string $url = null): array + { + $url ??= $this->getApiURL(); + $this->logger->debug('sending request', ['url' => $url]); + + $isXML = \is_string($contents); + $body = $isXML ? ['body' => $contents] : ['form_params' => $contents]; + + $response = $this->client->post($url, $body); + $this->logger->debug('request completed', ['status_code' => $response->getStatusCode()]); + + $responseContent = $response->getBody()->getContents(); + + return $this->data = $this->serializer->decode($responseContent, $txType); + } + /** * * ORTAK ÖDEME SİSTEMİNE İŞLEM KAYDETME * * @phpstan-param PosInterface::TX_TYPE_PAY_AUTH|PosInterface::TX_TYPE_PAY_PRE_AUTH $txType - * @phpstan-param PosInterface::MODEL_3D_* $paymentModel + * @phpstan-param PosInterface::MODEL_3D_* $paymentModel * * @param array $order * @param string $txType * @param string $paymentModel - * @param CreditCardInterface|null $creditCard + * @param CreditCardInterface|null $creditCard * * Basarili durumda donen cevap formati: array{CommonPaymentUrl: string, PaymentToken: string, ErrorCode: null, * ResponseMessage: null} Basarisiz durumda donen cevap formati: array{CommonPaymentUrl: null, PaymentToken: null, @@ -190,7 +211,7 @@ public function get3DFormData(array $order, string $paymentModel, string $txType * * @throws Exception */ - public function registerPayment(array $order, string $txType, string $paymentModel, CreditCardInterface $creditCard = null): array + private function registerPayment(array $order, string $txType, string $paymentModel, CreditCardInterface $creditCard = null): array { $requestData = $this->requestDataMapper->create3DEnrollmentCheckRequestData( $this->account, @@ -217,25 +238,4 @@ public function registerPayment(array $order, string $txType, string $paymentMod return $response; } - - /** - * @inheritDoc - * - * @return array - */ - protected function send($contents, string $txType, string $paymentModel, ?string $url = null): array - { - $url ??= $this->getApiURL(); - $this->logger->debug('sending request', ['url' => $url]); - - $isXML = \is_string($contents); - $body = $isXML ? ['body' => $contents] : ['form_params' => $contents]; - - $response = $this->client->post($url, $body); - $this->logger->debug('request completed', ['status_code' => $response->getStatusCode()]); - - $responseContent = $response->getBody()->getContents(); - - return $this->data = $this->serializer->decode($responseContent, $txType); - } } diff --git a/tests/Unit/DataMapper/ResponseDataMapper/PayFlexCPV4PosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/PayFlexCPV4PosResponseDataMapperTest.php index 75e6542a..84b9b5fe 100644 --- a/tests/Unit/DataMapper/ResponseDataMapper/PayFlexCPV4PosResponseDataMapperTest.php +++ b/tests/Unit/DataMapper/ResponseDataMapper/PayFlexCPV4PosResponseDataMapperTest.php @@ -87,7 +87,7 @@ public static function threesDPayResponseDataProvider(): Generator 'TransactionId' => '0cb6a57715144178a014afbe0185b9ed', 'MaskedPan' => '49384601****4205', ], - 'expected' => [ + 'expectedData' => [ 'order_id' => null, 'transaction_id' => '0cb6a57715144178a014afbe0185b9ed', 'transaction_type' => 'pay', @@ -122,7 +122,7 @@ public static function threesDPayResponseDataProvider(): Generator 'TransactionId' => '868382724da7480c949dafbd016c7636', 'MaskedPan' => '49384601****4205', ], - 'expected' => [ + 'expectedData' => [ 'order_id' => null, 'transaction_id' => '868382724da7480c949dafbd016c7636', 'transaction_type' => 'pay', @@ -147,7 +147,7 @@ public static function threesDPayResponseDataProvider(): Generator yield 'success_response_from_gateway_1' => [ 'order' => [], - 'txType' => PosInterface::TX_TYPE_PAY_PRE_AUTH, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, 'bank_response' => [ 'Rc' => '0000', 'AuthCode' => '735879', @@ -182,7 +182,7 @@ public static function threesDPayResponseDataProvider(): Generator 'ErrorCode' => null, 'ResponseMessage' => null, ], - 'expected' => [ + 'expectedData' => [ 'order_id' => '2023030913ED', 'transaction_id' => '3ee068d5b5a747ada65dafc0016d5887', 'transaction_type' => 'pay', diff --git a/tests/Unit/Gateways/PayFlexCPV4PosTest.php b/tests/Unit/Gateways/PayFlexCPV4PosTest.php index bb7f7426..74bf256b 100644 --- a/tests/Unit/Gateways/PayFlexCPV4PosTest.php +++ b/tests/Unit/Gateways/PayFlexCPV4PosTest.php @@ -6,27 +6,26 @@ namespace Mews\Pos\Tests\Unit\Gateways; use Exception; +use Mews\Pos\Client\HttpClient; +use Mews\Pos\Crypt\CryptInterface; use Mews\Pos\DataMapper\RequestDataMapper\PayFlexCPV4PosRequestDataMapper; +use Mews\Pos\DataMapper\RequestDataMapper\RequestDataMapperInterface; use Mews\Pos\DataMapper\ResponseDataMapper\PayFlexCPV4PosResponseDataMapper; +use Mews\Pos\DataMapper\ResponseDataMapper\ResponseDataMapperInterface; use Mews\Pos\Entity\Account\PayFlexAccount; use Mews\Pos\Entity\Card\CreditCardInterface; use Mews\Pos\Factory\AccountFactory; use Mews\Pos\Factory\CreditCardFactory; -use Mews\Pos\Factory\CryptFactory; -use Mews\Pos\Factory\HttpClientFactory; -use Mews\Pos\Factory\PosFactory; -use Mews\Pos\Factory\RequestDataMapperFactory; -use Mews\Pos\Factory\ResponseDataMapperFactory; -use Mews\Pos\Factory\SerializerFactory; use Mews\Pos\Gateways\PayFlexCPV4Pos; use Mews\Pos\PosInterface; use Mews\Pos\Serializer\SerializerInterface; use Mews\Pos\Tests\Unit\DataMapper\RequestDataMapper\PayFlexCPV4PosRequestDataMapperTest; use Mews\Pos\Tests\Unit\DataMapper\ResponseDataMapper\PayFlexCPV4PosResponseDataMapperTest; +use Mews\Pos\Tests\Unit\HttpClientTestTrait; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\EventDispatcher\EventDispatcherInterface; -use Psr\Log\NullLogger; -use Symfony\Component\EventDispatcher\EventDispatcher; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; /** @@ -34,6 +33,8 @@ */ class PayFlexCPV4PosTest extends TestCase { + use HttpClientTestTrait; + private PayFlexAccount $account; /** @var PayFlexCPV4Pos */ @@ -45,11 +46,40 @@ class PayFlexCPV4PosTest extends TestCase private array $order = []; + /** @var RequestDataMapperInterface & MockObject */ + private MockObject $requestMapperMock; + + /** @var ResponseDataMapperInterface & MockObject */ + private MockObject $responseMapperMock; + + /** @var CryptInterface & MockObject */ + private MockObject $cryptMock; + + /** @var HttpClient & MockObject */ + private MockObject $httpClientMock; + + /** @var LoggerInterface & MockObject */ + private MockObject $loggerMock; + + /** @var EventDispatcherInterface & MockObject */ + private MockObject $eventDispatcherMock; + + /** @var SerializerInterface & MockObject */ + private MockObject $serializerMock; + protected function setUp(): void { parent::setUp(); - $this->config = require __DIR__.'/../../../config/pos_test.php'; + $this->config = [ + 'name' => 'VakifBank-PayFlex-Common-Payment', + 'class' => PayFlexCPV4Pos::class, + 'gateway_endpoints' => [ + 'payment_api' => 'https://cptest.vakifbank.com.tr/CommonPayment/api/RegisterTransaction', + 'gateway_3d' => 'https://cptest.vakifbank.com.tr/CommonPayment/api/VposTransaction', + 'query_api' => 'https://cptest.vakifbank.com.tr/CommonPayment/SecurePayment', + ], + ]; $this->account = AccountFactory::createPayFlexAccount( 'vakifbank-cp', @@ -70,7 +100,28 @@ protected function setUp(): void 'ip' => '127.0.0.1', ]; - $this->pos = PosFactory::createPosGateway($this->account, $this->config, new EventDispatcher()); + $this->requestMapperMock = $this->createMock(PayFlexCPV4PosRequestDataMapper::class); + $this->responseMapperMock = $this->createMock(PayFlexCPV4PosResponseDataMapper::class); + $this->serializerMock = $this->createMock(SerializerInterface::class); + $this->cryptMock = $this->createMock(CryptInterface::class); + $this->httpClientMock = $this->createMock(HttpClient::class); + $this->loggerMock = $this->createMock(LoggerInterface::class); + $this->eventDispatcherMock = $this->createMock(EventDispatcherInterface::class); + + $this->requestMapperMock->expects(self::any()) + ->method('getCrypt') + ->willReturn($this->cryptMock); + + $this->pos = new PayFlexCPV4Pos( + $this->config, + $this->account, + $this->requestMapperMock, + $this->responseMapperMock, + $this->serializerMock, + $this->eventDispatcherMock, + $this->httpClientMock, + $this->loggerMock, + ); $this->pos->setTestMode(true); @@ -82,59 +133,107 @@ protected function setUp(): void */ public function testInit(): void { - $this->assertEquals($this->config['banks'][$this->account->getBank()], $this->pos->getConfig()); - $this->assertEquals($this->account, $this->pos->getAccount()); - $this->assertNotEmpty($this->pos->getQueryAPIUrl()); - $this->assertNotEmpty($this->pos->getCurrencies()); + $this->requestMapperMock->expects(self::once()) + ->method('getCurrencyMappings') + ->willReturn([PosInterface::CURRENCY_TRY => '949']); + $this->assertSame([PosInterface::CURRENCY_TRY], $this->pos->getCurrencies()); + $this->assertSame($this->config, $this->pos->getConfig()); + $this->assertSame($this->account, $this->pos->getAccount()); } + /** + * @return void + * + * @throws Exception + */ public function testGet3DFormDataSuccess(): void { - $crypt = CryptFactory::createGatewayCrypt(PayFlexCPV4Pos::class, new NullLogger()); - $requestMapper = RequestDataMapperFactory::createGatewayRequestMapper(PayFlexCPV4Pos::class, $this->createMock(EventDispatcherInterface::class), $crypt, []); - $responseMapper = ResponseDataMapperFactory::createGatewayResponseMapper(PayFlexCPV4Pos::class, $requestMapper, new NullLogger()); - $serializer = SerializerFactory::createGatewaySerializer(PayFlexCPV4Pos::class); + $enrollmentResponse = PayFlexCPV4PosRequestDataMapperTest::threeDFormDataProvider()->current()['queryParams']; + $txType = PosInterface::TX_TYPE_PAY_AUTH; + $paymentModel = PosInterface::MODEL_3D_SECURE; + $card = $this->card; + $order = $this->order; + + $this->requestMapperMock->expects(self::once()) + ->method('create3DEnrollmentCheckRequestData') + ->with( + $this->pos->getAccount(), + $order, + $txType, + $paymentModel, + $card + ) + ->willReturn(['request-data']); + + $this->serializerMock->expects(self::never()) + ->method('encode'); + + $this->prepareClient( + $this->httpClientMock, + 'response-content', + $this->config['gateway_endpoints']['payment_api'], + ['form_params' => ['request-data']], + ); - $posMock = $this->getMockBuilder(PayFlexCPV4Pos::class) - ->setConstructorArgs([ + $this->serializerMock->expects(self::once()) + ->method('decode') + ->with('response-content', $txType) + ->willReturn($enrollmentResponse); + + $this->requestMapperMock->expects(self::once()) + ->method('create3DFormData') + ->with( + null, [], - $this->account, - $requestMapper, - $responseMapper, - $serializer, - $this->createMock(EventDispatcherInterface::class), - HttpClientFactory::createDefaultHttpClient(), - new NullLogger(), - ]) - ->onlyMethods(['registerPayment']) - ->getMock(); - $posMock->setTestMode(true); - $posMock->expects($this->once())->method('registerPayment') - ->willReturn(PayFlexCPV4PosRequestDataMapperTest::threeDFormDataProvider()->current()['queryParams']); - - $result = $posMock->get3DFormData($this->order, PosInterface::MODEL_3D_SECURE, PosInterface::TX_TYPE_PAY_AUTH, $this->card); - - $this->assertSame(PayFlexCPV4PosRequestDataMapperTest::threeDFormDataProvider()->current()['expected'], $result); + null, + null, + null, + null, + $enrollmentResponse + ) + ->willReturn(['3d-form-data']); + + $result = $this->pos->get3DFormData($order, $paymentModel, $txType, $card); + + $this->assertSame(['3d-form-data'], $result); } - public function testGet3DFormDataFail(): void + /** + * @return void + * + * @throws Exception + */ + public function testGet3DFormDataEnrollmentFail(): void { - $this->expectException(Exception::class); - $posMock = $this->getMockBuilder(PayFlexCPV4Pos::class) - ->setConstructorArgs([ - [], - $this->account, - $this->createMock(PayFlexCPV4PosRequestDataMapper::class), - $this->createMock(PayFlexCPV4PosResponseDataMapper::class), - $this->createMock(SerializerInterface::class), - $this->createMock(EventDispatcherInterface::class), - HttpClientFactory::createDefaultHttpClient(), - new NullLogger(), - ]) - ->onlyMethods(['registerPayment']) - ->getMock(); - $posMock->setTestMode(true); - $posMock->expects($this->once())->method('registerPayment') + $txType = PosInterface::TX_TYPE_PAY_AUTH; + $paymentModel = PosInterface::MODEL_3D_SECURE; + $card = $this->card; + $order = $this->order; + + $this->requestMapperMock->expects(self::once()) + ->method('create3DEnrollmentCheckRequestData') + ->with( + $this->pos->getAccount(), + $order, + $txType, + $paymentModel, + $card + ) + ->willReturn(['request-data']); + + $this->serializerMock->expects(self::never()) + ->method('encode'); + + $this->prepareClient( + $this->httpClientMock, + 'response-content', + $this->config['gateway_endpoints']['payment_api'], + ['form_params' => ['request-data']], + ); + + $this->serializerMock->expects(self::once()) + ->method('decode') + ->with('response-content', $txType) ->willReturn([ 'CommonPaymentUrl' => null, 'PaymentToken' => null, @@ -142,77 +241,120 @@ public function testGet3DFormDataFail(): void 'ResponseMessage' => 'Güvenlik Numarası Hatalı', ]); - $posMock->get3DFormData($this->order, PosInterface::MODEL_3D_SECURE, PosInterface::TX_TYPE_PAY_AUTH, $this->card); + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $this->expectException(Exception::class); + + $this->pos->get3DFormData($order, $paymentModel, $txType, $card); } - public function testMake3dPayPaymentFail(): void + /** + * @dataProvider make3DPayPaymentDataProvider + */ + public function testMake3DPayPayment( + array $order, + string $txType, + Request $request, + array $paymentResponse, + array $expectedResponse, + bool $is3DSuccess, + bool $isSuccess + ): void { - $testData = iterator_to_array( - PayFlexCPV4PosResponseDataMapperTest::threesDPayResponseDataProvider() - )['fail_response_from_gateway_1']; - $request = Request::create('', 'GET', $testData['bank_response']); - - $requestMapper = $this->createMock(PayFlexCPV4PosRequestDataMapper::class); - $requestMapper->expects($this->never()) - ->method('create3DPaymentStatusRequestData'); + if ($is3DSuccess) { + $this->cryptMock->expects(self::never()) + ->method('check3DHash'); + } + $this->responseMapperMock->expects(self::never()) + ->method('extractMdStatus'); - $responseMapper = $this->createMock(PayFlexCPV4PosResponseDataMapper::class); - $responseMapper->expects($this->once()) - ->method('map3DPayResponseData')->with($testData['bank_response']); + $this->responseMapperMock->expects(self::never()) + ->method('is3dAuthSuccess'); - $pos = new PayFlexCPV4Pos( - [], - $this->account, - $requestMapper, - $responseMapper, - $this->createMock(SerializerInterface::class), - $this->createMock(EventDispatcherInterface::class), - HttpClientFactory::createDefaultHttpClient(), - new NullLogger()); - - $pos->make3DPayPayment($request, $testData['order'], $testData['txType']); + $create3DPaymentStatusRequestData = [ + 'create3DPaymentStatusRequestData', + ]; + if ($is3DSuccess) { + $this->requestMapperMock->expects(self::once()) + ->method('create3DPaymentStatusRequestData') + ->with($this->account, $request->query->all()) + ->willReturn($create3DPaymentStatusRequestData); + $this->prepareClient( + $this->httpClientMock, + 'response-body', + $this->config['gateway_endpoints']['query_api'], + [ + 'form_params' => $create3DPaymentStatusRequestData, + ], + ); + + $this->serializerMock->expects(self::never()) + ->method('encode'); + + $this->serializerMock->expects(self::once()) + ->method('decode') + ->with('response-body', $txType) + ->willReturn($paymentResponse); + + $this->responseMapperMock->expects(self::once()) + ->method('map3DPayResponseData') + ->with($request->query->all(), $txType, $order) + ->willReturn($expectedResponse); + } else { + $this->responseMapperMock->expects(self::once()) + ->method('map3DPayResponseData') + ->with($request->query->all(), $txType, $order) + ->willReturn($expectedResponse); + $this->requestMapperMock->expects(self::never()) + ->method('create3DPaymentRequestData'); + $this->serializerMock->expects(self::never()) + ->method('encode'); + $this->serializerMock->expects(self::never()) + ->method('decode'); + } + + $this->pos->make3DPayPayment($request, $order, $txType); + + $result = $this->pos->getResponse(); + $this->assertSame($expectedResponse, $result); + $this->assertSame($isSuccess, $this->pos->isSuccess()); } - public function testMake3dPayPaymentSuccess(): void + public static function make3DPayPaymentDataProvider(): array { - $bankResponses = \iterator_to_array(PayFlexCPV4PosResponseDataMapperTest::threesDPayResponseDataProvider()); - $bankQueryResponse = [ - 'Rc' => '0000', - 'AuthCode' => '368513', - 'Message' => 'İŞLEM BAŞARILI', - 'TransactionId' => '28d2b9c27af545f48d49afc300db246b', - 'PaymentToken' => 'c6b7cecc2a1846088a4eafc300db246b', - 'MaskedPan' => '49384601****4205', + $testData = iterator_to_array( + PayFlexCPV4PosResponseDataMapperTest::threesDPayResponseDataProvider() + ); + + return [ + 'auth_fail' => [ + 'order' => $testData['fail_response_from_gateway_1']['order'], + 'txType' => $testData['fail_response_from_gateway_1']['txType'], + 'request' => Request::create( + '', + 'GET', + $testData['fail_response_from_gateway_1']['bank_response'] + ), + 'paymentResponse' => [], + 'expected' => $testData['fail_response_from_gateway_1']['expectedData'], + 'is3DSuccess' => false, + 'isSuccess' => false, + ], + 'success' => [ + 'order' => $testData['success_response_from_gateway_1']['order'], + 'txType' => $testData['success_response_from_gateway_1']['txType'], + 'request' => Request::create( + '', + 'GET', + $testData['success_response_from_gateway_1']['bank_response'] + ), + 'paymentResponse' => $testData['success_response_from_gateway_1']['bank_response'], + 'expected' => $testData['success_response_from_gateway_1']['expectedData'], + 'is3DSuccess' => true, + 'isSuccess' => true, + ], ]; - $testData = $bankResponses['success_response_from_gateway_1']; - - $request = Request::create('', 'GET', $bankQueryResponse); - - $requestMapper = $this->createMock(PayFlexCPV4PosRequestDataMapper::class); - $requestMapper->expects($this->once()) - ->method('create3DPaymentStatusRequestData')->with($this->account, $bankQueryResponse); - - $responseMapper = $this->createMock(PayFlexCPV4PosResponseDataMapper::class); - $responseMapper->expects($this->once()) - ->method('map3DPayResponseData'); - - $posMock = $this->getMockBuilder(PayFlexCPV4Pos::class) - ->setConstructorArgs([ - [], - $this->account, - $requestMapper, - $responseMapper, - $this->createMock(SerializerInterface::class), - $this->createMock(EventDispatcherInterface::class), - HttpClientFactory::createDefaultHttpClient(), - new NullLogger(), - ]) - ->onlyMethods(['send', 'getQueryAPIUrl']) - ->getMock(); - $posMock->expects($this->once())->method('getQueryAPIUrl')->willReturn($this->pos->getQueryAPIUrl()); - $posMock->expects($this->once())->method('send')->willReturn([$testData['bank_response']]); - - $posMock->make3DPayPayment($request, $testData['order'], $testData['txType']); } }