From 126ed39432582da974b8d29999acff1687a63f90 Mon Sep 17 00:00:00 2001 From: mustapayev Date: Sun, 29 Dec 2024 19:05:47 +0100 Subject: [PATCH] param integration initial --- composer.json | 3 +- config/pos_test.php | 7 +- examples/_common-codes/3d/form.php | 8 +- src/Crypt/ParamPosCrypt.php | 20 +- .../ParamPosRequestDataMapper.php | 75 +- .../ParamPosResponseDataMapper.php | 85 +- src/Gateways/ParamPos.php | 152 +- src/PosInterface.php | 4 +- src/Serializer/ParamPosSerializer.php | 34 +- tests/Unit/Crypt/ParamPosCryptTest.php | 133 ++ .../ParamPosRequestDataMapperTest.php | 632 +++++ .../ParamPosResponseDataMapperTest.php | 2100 +++++++++++++++++ tests/Unit/Gateways/ParamPosTest.php | 956 ++++++++ .../Serializer/ParamPosSerializerTest.php | 105 + .../parampos/3d_form_response_success.xml | 123 + 15 files changed, 4298 insertions(+), 139 deletions(-) create mode 100644 tests/Unit/Crypt/ParamPosCryptTest.php create mode 100644 tests/Unit/DataMapper/RequestDataMapper/ParamPosRequestDataMapperTest.php create mode 100644 tests/Unit/DataMapper/ResponseDataMapper/ParamPosResponseDataMapperTest.php create mode 100644 tests/Unit/Gateways/ParamPosTest.php create mode 100644 tests/Unit/Serializer/ParamPosSerializerTest.php create mode 100644 tests/Unit/test_data/parampos/3d_form_response_success.xml diff --git a/composer.json b/composer.json index 60173ffd..9aa13566 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,8 @@ "squizlabs/php_codesniffer": "^3.5", "symfony/event-dispatcher": "^5.4", "symfony/http-client": "^5.4", - "symfony/var-dumper": "^5.1" + "symfony/var-dumper": "^5.1", + "symfony/var-exporter": "^5.4" }, "suggest": { "ext-soap": "ParamPos kullanacaksanız veya KuveytPos ile iptal/iade gibi ödeme olmayan işlemleri yapacaksanız." diff --git a/config/pos_test.php b/config/pos_test.php index 4b388e80..09d5636a 100644 --- a/config/pos_test.php +++ b/config/pos_test.php @@ -15,7 +15,12 @@ 'name' => 'TURK Elektronik Para A.Ş', 'class' => Mews\Pos\Gateways\ParamPos::class, 'gateway_endpoints' => [ - 'payment_api' => 'https://testposws.param.com.tr/turkpos.ws/service_turkpos_prod.asmx', + //'payment_api' => 'https://testposws.param.com.tr/turkpos.ws/service_turkpos_prod.asmx', + //'payment_api' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx?wsdl', + // 'payment_api' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx?wsdl', + 'payment_api' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', //xml + //'payment_api' => 'https://test-dmz.param.com.tr:4443/turkpos.ws/service_turkpos_test.asmx?WSDL', + //prod: 'payment_api' => 'https://posws.param.com.tr/turkpos.ws/service_turkpos_prod.asmx?wsdl', ], ], 'payten_v3_hash' => [ diff --git a/examples/_common-codes/3d/form.php b/examples/_common-codes/3d/form.php index 7df39b30..3be9a134 100644 --- a/examples/_common-codes/3d/form.php +++ b/examples/_common-codes/3d/form.php @@ -14,8 +14,6 @@ // ornegin /examples/finansbank-payfor/3d/_config.php require '_config.php'; -require '../../_templates/_header.php'; - if ($request->getMethod() !== 'POST') { echo new RedirectResponse($baseUrl.'index.php'); exit(); @@ -165,6 +163,10 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent): void { try { $formData = $pos->get3DFormData($order, $paymentModel, $transaction, $card, false); //dd($formData); + if (is_string($formData)) { + echo $formData; + exit(); + } } catch (\InvalidArgumentException $e) { // örneğin kart bilgisi sağlanmadığında bu exception'i alırsınız. dd($e); @@ -215,7 +217,7 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent): void { // OZEL DURUMLAR ICIN KODLAR END // ============================================================================================ - +require '../../_templates/_header.php'; $flowType = $request->get('payment_flow_type'); ?> diff --git a/src/Crypt/ParamPosCrypt.php b/src/Crypt/ParamPosCrypt.php index dcdc2357..7dc1aba8 100644 --- a/src/Crypt/ParamPosCrypt.php +++ b/src/Crypt/ParamPosCrypt.php @@ -8,6 +8,7 @@ use Mews\Pos\Entity\Account\AbstractPosAccount; use Mews\Pos\Exceptions\NotImplementedException; +use Symfony\Component\VarExporter\VarExporter; class ParamPosCrypt extends AbstractCrypt { @@ -43,9 +44,18 @@ public function check3DHash(AbstractPosAccount $posAccount, array $data): bool throw new \LogicException('Account storeKey eksik!'); } - $actualHash = $this->hashFromParams($posAccount->getStoreKey(), $data, 'HASHPARAMS', ':'); + $hashParamsArr = [ + 'islemGUID', + 'md', + 'mdStatus', + 'orderId', + ]; + + $hashStr = $this->buildHashString($data, $hashParamsArr, '', $posAccount->getStoreKey()); + + $actualHash = $this->hashString($hashStr); - if ($data['HASH'] === $actualHash) { + if ($data['islemHash'] === $actualHash) { $this->logger->debug('hash check is successful'); return true; @@ -54,7 +64,7 @@ public function check3DHash(AbstractPosAccount $posAccount, array $data): bool $this->logger->error('hash check failed', [ 'data' => $data, 'generated_hash' => $actualHash, - 'expected_hash' => $data['HASH'], + 'expected_hash' => $data['islemHash'], ]); return false; @@ -72,8 +82,8 @@ public function createHash(AbstractPosAccount $posAccount, array $requestData): $requestData['Islem_Tutar'], $requestData['Toplam_Tutar'], $requestData['Siparis_ID'], - $requestData['Hata_URL'] ?? '', - $requestData['Basarili_URL'] ?? '', +// $requestData['Hata_URL'] ?? '', //todo +// $requestData['Basarili_URL'] ?? '', ]; $hashStr = \implode(static::HASH_SEPARATOR, $map); diff --git a/src/DataMapper/RequestDataMapper/ParamPosRequestDataMapper.php b/src/DataMapper/RequestDataMapper/ParamPosRequestDataMapper.php index edbe1b82..02d53823 100644 --- a/src/DataMapper/RequestDataMapper/ParamPosRequestDataMapper.php +++ b/src/DataMapper/RequestDataMapper/ParamPosRequestDataMapper.php @@ -75,29 +75,21 @@ class ParamPosRequestDataMapper extends AbstractRequestDataMapper /** * {@inheritDoc} * - * @param array{md: string, xid: string, eci: string, cavv: string} $responseData + * @param array{UCD_MD: string, Islem_GUID: string, Siparis_ID: string, cavv: string, G: array{CLIENT_CODE: string, CLIENT_USERNAME: string, CLIENT_PASSWORD: string}} $responseData */ public function create3DPaymentRequestData(AbstractPosAccount $posAccount, array $order, string $txType, array $responseData): array { $order = $this->preparePaymentOrder($order); $requestData = $this->getRequestAccountData($posAccount) + [ - 'Type' => $this->mapTxType($txType), - 'IPAddress' => (string) $order['ip'], - 'OrderId' => (string) $order['id'], - 'Total' => (string) $order['amount'], - 'Currency' => $this->mapCurrency($order['currency']), - 'Taksit' => $this->mapInstallment((int) $order['installment']), - 'Number' => $responseData['md'], - 'PayerTxnId' => $responseData['xid'], - 'PayerSecurityLevel' => $responseData['eci'], - 'PayerAuthenticationCode' => $responseData['cavv'], - 'Mode' => 'P', + 'UCD_MD' => (string) $responseData['md'], + 'Islem_GUID' => (string) $responseData['islemGUID'], + 'Siparis_ID' => (string) $responseData['orderId'], ]; - - if (isset($order['recurring'])) { - $requestData += $this->createRecurringData($order['recurring']); - } +// //todo +// if (isset($order['recurring'])) { +// $requestData += $this->createRecurringData($order['recurring']); +// } return $requestData; } @@ -118,17 +110,25 @@ public function create3DEnrollmentCheckRequestData(AbstractPosAccount $posAccoun 'Islem_ID' => $this->crypt->generateRandomString(), 'IPAdr' => (string) $order['ip'], 'Siparis_ID' => (string) $order['id'], - 'Islem_Tutar' => (string) $order['amount'], - 'Toplam_Tutar' => (string) $order['amount'], //todo + 'Islem_Tutar' => $this->formatAmount($order['amount']), + 'Toplam_Tutar' => $this->formatAmount($order['amount']), //todo 'Basarili_URL' => (string) $order['success_url'], 'Hata_URL' => (string) $order['fail_url'], - 'Currency' => $this->mapCurrency($order['currency']), + //'Currency' => $this->mapCurrency($order['currency']), //todo 'Taksit' => $this->mapInstallment((int) $order['installment']), 'KK_Sahibi' => $creditCard->getHolderName(), 'KK_No' => $creditCard->getNumber(), 'KK_SK_Ay' => $creditCard->getExpirationDate(self::CREDIT_CARD_EXP_MONTH_FORMAT), 'KK_SK_Yil' => $creditCard->getExpirationDate(self::CREDIT_CARD_EXP_YEAR_FORMAT), 'KK_CVC' => $creditCard->getCvv(), + 'KK_Sahibi_GSM' => '', //optional olmasina ragmen hic gonderilmeyince hata aliniyor. + // 'Siparis_Aciklama' => '', + //'Ref_URL' => 'https://dev.param.com.tr/tr', +// 'Data1' => '', +// 'Data2' => '', +// 'Data3' => '', +// 'Data4' => '', +// 'Data5' => '', ]; $requestData['Islem_Hash'] = $this->crypt->createHash($posAccount, $requestData); @@ -137,6 +137,11 @@ public function create3DEnrollmentCheckRequestData(AbstractPosAccount $posAccoun // $requestData += $this->createRecurringData($order['recurring']); // } +// return [ +// 'TP_WMD_UCD' => $requestData, +// '@xmlns' => 'https://turkpos.com.tr/', +// ]; + return $requestData; } @@ -318,25 +323,9 @@ public function createHistoryRequestData(AbstractPosAccount $posAccount, array $ /** * {@inheritDoc} */ - public function create3DFormData(AbstractPosAccount $posAccount, array $order, string $paymentModel, string $txType, string $gatewayURL, ?CreditCardInterface $creditCard = null): array + public function create3DFormData(?AbstractPosAccount $posAccount, ?array $order, string $paymentModel, string $txType, ?string $gatewayURL = null, ?CreditCardInterface $creditCard = null, array $extraData = []): array { - $preparedOrder = $this->preparePaymentOrder($order); - - $data = $this->create3DFormDataCommon($posAccount, $preparedOrder, $paymentModel, $txType, $gatewayURL, $creditCard); - - $event = new Before3DFormHashCalculatedEvent( - $data['inputs'], - $posAccount->getBank(), - $txType, - $paymentModel, - EstPos::class - ); - $this->eventDispatcher->dispatch($event); - $data['inputs'] = $event->getFormInputs(); - - $data['inputs']['hash'] = $this->crypt->create3DHash($posAccount, $data['inputs']); - - return $data; + throw new NotImplementedException(); } //todo @@ -477,6 +466,18 @@ protected function mapCurrency(string $currency): string return (string) $this->currencyMappings[$currency] ?? $currency; } + /** + * 10.0 => 10,00 + * 1000.5 => 1000,50 + * @param float $amount + * + * @return string + */ + protected function formatAmount(float $amount): string + { + return \number_format($amount, 2, ',', ''); + } + /** * @param AbstractPosAccount $posAccount * diff --git a/src/DataMapper/ResponseDataMapper/ParamPosResponseDataMapper.php b/src/DataMapper/ResponseDataMapper/ParamPosResponseDataMapper.php index b8050af1..b7eb4156 100644 --- a/src/DataMapper/ResponseDataMapper/ParamPosResponseDataMapper.php +++ b/src/DataMapper/ResponseDataMapper/ParamPosResponseDataMapper.php @@ -44,9 +44,7 @@ class ParamPosResponseDataMapper extends AbstractResponseDataMapper 'V' => PosInterface::PAYMENT_STATUS_CANCELED, ]; - // todo /** - * @param PaymentStatusModel $rawPaymentResponseData * {@inheritDoc} */ public function mapPaymentResponse(array $rawPaymentResponseData, string $txType, array $order): array @@ -60,29 +58,28 @@ public function mapPaymentResponse(array $rawPaymentResponseData, string $txType $rawPaymentResponseData = $this->emptyStringsToNull($rawPaymentResponseData); - $procReturnCode = $this->getProcReturnCode($rawPaymentResponseData); + $payResult = $rawPaymentResponseData['TP_WMD_PayResponse']['TP_WMD_PayResult']; + + $procReturnCode = $this->getProcReturnCode($payResult); $status = self::TX_DECLINED; - if (self::PROCEDURE_SUCCESS_CODE === $procReturnCode) { + if ($procReturnCode > 0 && $payResult['Dekont_ID'] > 0) { $status = self::TX_APPROVED; } - $extra = $rawPaymentResponseData['Extra']; - $mappedResponse = [ - 'order_id' => $rawPaymentResponseData['OrderId'], + 'order_id' => $payResult['Siparis_ID'], + 'transaction_id' => $payResult['Bank_Trans_ID'], + 'auth_code' => $payResult['Bank_AuthCode'], + 'ref_ret_num' => $payResult['Bank_HostRefNum'], 'currency' => $order['currency'], - 'amount' => $order['amount'], - 'group_id' => $rawPaymentResponseData['GroupId'], - 'transaction_id' => $rawPaymentResponseData['TransId'], - 'transaction_time' => self::TX_APPROVED === $status ? new \DateTimeImmutable($extra['TRXDATE']) : null, - 'auth_code' => $rawPaymentResponseData['AuthCode'] ?? null, - 'ref_ret_num' => $rawPaymentResponseData['HostRefNum'], + 'amount' => null, + 'proc_return_code' => $procReturnCode, 'status' => $status, 'status_detail' => $this->getStatusDetail($procReturnCode), - 'error_code' => self::TX_APPROVED === $status ? null : $extra['ERRORCODE'], - 'error_message' => self::TX_APPROVED === $status ? null : $rawPaymentResponseData['ErrMsg'], - 'recurring_id' => $extra['RECURRINGID'] ?? null, // set when recurring payment is made + 'error_code' => self::TX_APPROVED === $status ? null : $procReturnCode, + 'error_message' => self::TX_APPROVED === $status ? null : $rawPaymentResponseData['Bank_HostMsg'], + 'transaction_time' => new \DateTimeImmutable(), 'all' => $rawPaymentResponseData, ]; @@ -93,7 +90,6 @@ public function mapPaymentResponse(array $rawPaymentResponseData, string $txType // todo /** - * @param PaymentStatusModel|null $rawPaymentResponseData * {@inheritdoc} */ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymentResponseData, string $txType, array $order): array @@ -103,7 +99,7 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen 'provision_response' => $rawPaymentResponseData, ]); $raw3DAuthResponseData = $this->emptyStringsToNull($raw3DAuthResponseData); - $paymentModel = $this->mapSecurityType($raw3DAuthResponseData['storetype']); + $paymentModel = PosInterface::MODEL_3D_SECURE; $paymentResponseData = $this->getDefaultPaymentResponse($txType, $paymentModel); $mdStatus = $this->extractMdStatus($raw3DAuthResponseData); if (null !== $rawPaymentResponseData) { @@ -111,34 +107,24 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen } $threeDResponse = [ - 'transaction_security' => null === $mdStatus ? null : $this->mapResponseTransactionSecurity($mdStatus), + 'transaction_security' => null, 'md_status' => $mdStatus, - 'order_id' => $raw3DAuthResponseData['oid'], - 'masked_number' => $raw3DAuthResponseData['maskedCreditCard'], - 'month' => $raw3DAuthResponseData['Ecom_Payment_Card_ExpDate_Month'], - 'year' => $raw3DAuthResponseData['Ecom_Payment_Card_ExpDate_Year'], - 'amount' => null !== $raw3DAuthResponseData['amount'] ? $this->formatAmount($raw3DAuthResponseData['amount']) : null, - 'currency' => '*' === $raw3DAuthResponseData['currency'] ? null : $this->mapCurrency($raw3DAuthResponseData['currency']), - 'installment_count' => $this->mapInstallment($raw3DAuthResponseData['taksit']), - 'eci' => null, - 'tx_status' => null, - 'cavv' => null, + 'order_id' => $raw3DAuthResponseData['orderId'], + 'amount' => null !== $raw3DAuthResponseData['transactionAmount'] ? $this->formatAmount($raw3DAuthResponseData['transactionAmount']) : null, + 'currency' => $order['currency'], + 'installment_count' => null, 'md_error_message' => null, '3d_all' => $raw3DAuthResponseData, ]; if (null !== $mdStatus) { if (!$this->is3dAuthSuccess($mdStatus)) { - $threeDResponse['md_error_message'] = $raw3DAuthResponseData['mdErrorMsg']; + $threeDResponse['md_error_message'] = null; //todo } } else { - $threeDResponse['error_code'] = $raw3DAuthResponseData['ErrorCode']; - $threeDResponse['error_message'] = $raw3DAuthResponseData['ErrMsg']; - } - - if ($this->is3dAuthSuccess($mdStatus)) { - $threeDResponse['eci'] = $raw3DAuthResponseData['eci']; - $threeDResponse['cavv'] = $raw3DAuthResponseData['cavv']; + //todo +// $threeDResponse['error_code'] = $raw3DAuthResponseData['ErrorCode']; +// $threeDResponse['error_message'] = $raw3DAuthResponseData['ErrMsg']; } $result = $this->mergeArraysPreferNonNullValues($threeDResponse, $paymentResponseData); @@ -249,12 +235,10 @@ public function map3DHostResponseData(array $raw3DAuthResponseData, string $txTy // todo /** - * @param PaymentStatusModel $rawResponseData * {@inheritdoc} */ public function mapRefundResponse(array $rawResponseData): array { - /** @var PaymentStatusModel $rawResponseData */ $rawResponseData = $this->emptyStringsToNull($rawResponseData); $procReturnCode = $this->getProcReturnCode($rawResponseData); $status = self::TX_DECLINED; @@ -290,13 +274,10 @@ public function mapRefundResponse(array $rawResponseData): array // todo /** - * @param PaymentStatusModel $rawResponseData - * * {@inheritdoc} */ public function mapCancelResponse(array $rawResponseData): array { - /** @var PaymentStatusModel $rawResponseData */ $rawResponseData = $this->emptyStringsToNull($rawResponseData); $procReturnCode = $this->getProcReturnCode($rawResponseData); $status = self::TX_DECLINED; @@ -344,7 +325,6 @@ public function mapCancelResponse(array $rawResponseData): array // todo /** - * @param PaymentStatusModel $rawResponseData * {@inheritdoc} */ public function mapStatusResponse(array $rawResponseData): array @@ -425,8 +405,6 @@ public function mapRecurringStatusResponse(array $rawResponseData): array // todo /** - * @param PaymentStatusModel $rawResponseData - * * {@inheritDoc} */ public function mapOrderHistoryResponse(array $rawResponseData): array @@ -447,7 +425,6 @@ public function mapOrderHistoryResponse(array $rawResponseData): array } return [ - /** @var PaymentStatusModel $rawResponseData */ 'order_id' => $rawResponseData['OrderId'], 'proc_return_code' => $procReturnCode, 'error_message' => $rawResponseData['ErrMsg'], @@ -518,23 +495,19 @@ protected function getStatusDetail(?string $procReturnCode): ?string return $this->codes[$procReturnCode] ?? null; } - // todo /** - * Get ProcReturnCode - * * @param array $response * - * @return string|null + * @return int|null */ - protected function getProcReturnCode(array $response): ?string + protected function getProcReturnCode(array $response): ?int { - return $response['ProcReturnCode'] ?? null; + return $response['Sonuc'] ?? null; } - // todo + // todo test with amount 1000.01 /** - * "100001" => 1000.01 odeme durum sorgulandiginda gelen amount format - * "1000.01" => 1000.01 odeme yapildiginda gelen amount format + * "1000,01" => 1000.01 odeme durum sorgulandiginda gelen amount format * * @param string $amount * @@ -542,7 +515,7 @@ protected function getProcReturnCode(array $response): ?string */ protected function formatAmount(string $amount): float { - return ((float) \str_replace('.', '', $amount)) / 100; + return ((float) \str_replace(',', '.', $amount)); } // todo diff --git a/src/Gateways/ParamPos.php b/src/Gateways/ParamPos.php index 24c21bec..bd574935 100644 --- a/src/Gateways/ParamPos.php +++ b/src/Gateways/ParamPos.php @@ -21,6 +21,7 @@ use Psr\Http\Client\ClientExceptionInterface; use SoapFault; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\VarExporter\VarExporter; /** * Documentation: @@ -109,7 +110,64 @@ public function get3DGatewayURL(string $paymentModel = PosInterface::MODEL_3D_SE */ public function make3DPayment(Request $request, array $order, string $txType, CreditCardInterface $creditCard = null): PosInterface { - throw new UnsupportedPaymentModelException(); + $request = $request->request; + + if (!$this->is3DAuthSuccess($request->all())) { + $this->response = $this->responseDataMapper->map3DPaymentData( + $request->all(), + null, + $txType, + $order + ); + + return $this; + } + + if (!$this->requestDataMapper->getCrypt()->check3DHash($this->account, $request->all())) { + throw new HashMismatchException(); + } + dump($request->all()); + $requestData = $this->requestDataMapper->create3DPaymentRequestData($this->account, $order, $txType, $request->all()); + + $event = new RequestDataPreparedEvent( + $requestData, + $this->account->getBank(), + $txType, + \get_class($this), + $order, + PosInterface::MODEL_3D_SECURE + ); + /** @var RequestDataPreparedEvent $event */ + $event = $this->eventDispatcher->dispatch($event); + if ($requestData !== $event->getRequestData()) { + $this->logger->debug('Request data is changed via listeners', [ + 'txType' => $event->getTxType(), + 'bank' => $event->getBank(), + 'initialData' => $requestData, + 'updatedData' => $event->getRequestData(), + ]); + $requestData = $event->getRequestData(); + } + + $contents = $this->serializer->encode($requestData, 'TP_WMD_Pay'); + $provisionResponse = $this->send( + $contents, + $txType, + PosInterface::MODEL_3D_SECURE, + $this->getApiURL($txType) + ); + echo VarExporter::export($provisionResponse); + //dd($provisionResponse); + + $this->response = $this->responseDataMapper->map3DPaymentData( + $request->all(), + $provisionResponse, + $txType, + $order + ); + $this->logger->debug('finished 3D payment', ['mapped_response' => $this->response]); + + return $this; } // todo @@ -154,30 +212,51 @@ public function make3DHostPayment(Request $request, array $order, string $txType /** * @inheritDoc */ - public function get3DFormData(array $order, string $paymentModel, string $txType, CreditCardInterface $creditCard = null, bool $createWithoutCard = true): array + public function get3DFormData(array $order, string $paymentModel, string $txType, CreditCardInterface $creditCard = null, bool $createWithoutCard = true): string { $this->check3DFormInputs($paymentModel, $txType, $creditCard); $data = $this->registerPayment($order, $paymentModel, $txType, $creditCard); + dump($data); + if (isset($data['soap:Fault'])) { + $this->logger->error('soap error response', $data['soap:Fault']); - $status = $data['Code']; - - if (0 !== $status) { - $this->logger->error('payment register failed', $data); - - throw new \RuntimeException($data['Message'], $data['Code']); + throw new \RuntimeException('Bankaya istek başarısız!'); + } + //^ array:1 [▼ + // "TP_WMD_UCDResponse" => array:1 [▼ + // "TP_WMD_UCDResult" => array:4 [▼ + // "Islem_ID" => "0" + // "Sonuc" => "-112" + // "Sonuc_Str" => "Tutar formatı geçersiz. Nokta kullanmayınız. Kuruş formatında virgüllü gönderiniz." + // "Banka_Sonuc_Kod" => "0" + // ] + // ] + //] + $result = $data['TP_WMD_UCDResponse']['TP_WMD_UCDResult']; + if ($result['Sonuc'] < 1) { + $this->logger->error('soap error response', $result); + + throw new \RuntimeException($result['Sonuc_Str'], $result['Sonuc']); } + // dd($data); + // todo check response code +// xdebug_break(); +// $html = $data['soap:Body']['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML']; +// echo $html; +// exit(); +// dd($data['soap:Body']['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML']); +// $status = $data['Code']; +// +// if (0 !== $status) { +// $this->logger->error('payment register failed', $data); +// +// throw new \RuntimeException($data['Message'], $data['Code']); +// } $this->logger->debug('preparing 3D form data'); - return $this->requestDataMapper->create3DFormData( - $this->account, - $data, - $paymentModel, - $txType, - $this->get3DGatewayURL($paymentModel, $data['ThreeDSessionId'] ?? null), - $creditCard - ); + return $result['UCD_HTML']; } // todo @@ -210,26 +289,36 @@ public function history(array $data): PosInterface */ protected function send($contents, string $txType, string $paymentModel, string $url): array { + // dump($contents); +// $contents = <<$contents*/ +//HTML; + //dd($contents); + //$contents = str_replace([''], '', $contents); + //dump($contents); $this->logger->debug('sending request', ['url' => $url]); - return $this->data = $this->sendSoapRequest($contents, $txType, $url); -// $response = $this->client->post($url, [ -// 'headers' => [ -// 'Content-Type' => 'application/json', -// ], -// 'body' => $contents, -// ]); +// return $this->data = $this->sendSoapRequest($contents, $txType, $url); + $response = $this->client->post($url, [ + 'headers' => [ + 'Content-Type' => 'text/xml', + //'Content-Length' => strlen($contents), + ], + 'body' => $contents, + ]); $this->logger->debug('request completed', ['status_code' => $response->getStatusCode()]); - if ($response->getStatusCode() === 204) { - $this->logger->warning('response from api is empty'); - - return $this->data = []; - } +// if ($response->getStatusCode() === 204) { +// $this->logger->warning('response from api is empty'); +// +// return $this->data = []; +// } $responseContent = $response->getBody()->getContents(); + dump('$responseContent', $responseContent); + //dd($response->getStatusCode(), $responseContent); return $this->data = $this->serializer->decode($responseContent, $txType); } @@ -275,11 +364,16 @@ private function sendSoapRequest(array $contents, string $txType, string $url): $client = new \SoapClient($url, $options); try { + //$contents = json_decode(json_encode($contents)); + dump($url, $contents); +// $result = $client->TP_WMD_UCD($contents); $result = $client->__soapCall( + //'Pos_Odeme', 'TP_WMD_UCD', [$contents] //['parameters' => ['request' => $contents]] ); + dd($result); } catch (SoapFault $soapFault) { $this->logger->error('soap error response', [ 'message' => $soapFault->getMessage(), @@ -353,7 +447,7 @@ private function registerPayment(array $order, string $paymentModel, string $txT $requestData = $event->getRequestData(); } - $requestData = $this->serializer->encode($requestData, $txType); + $requestData = $this->serializer->encode($requestData, 'TP_WMD_UCD'); //todo TP_WMD_UCD return $this->send( $requestData, diff --git a/src/PosInterface.php b/src/PosInterface.php index 9658c78c..2b132468 100644 --- a/src/PosInterface.php +++ b/src/PosInterface.php @@ -121,7 +121,7 @@ interface PosInterface * @param CreditCardInterface|null $creditCard * @param bool $createWithoutCard 3D ve 3D_PAY ödemelerde kart bilgisi olmadan 3D formu oluşturulmasına izin verir. * - * @return array{gateway: string, method: 'POST'|'GET', inputs: array} + * @return string|array{gateway: string, method: 'POST'|'GET', inputs: array} HTML oldugu durumda string doner. * * @throws \RuntimeException when request to the bank to get 3D form data failed * @throws ClientExceptionInterface when request to the bank to get 3D form data failed @@ -130,7 +130,7 @@ interface PosInterface * @throws UnsupportedTransactionTypeException * @throws ClientExceptionInterface */ - public function get3DFormData(array $order, string $paymentModel, string $txType, ?CreditCardInterface $creditCard = null, bool $createWithoutCard = true): array; + public function get3DFormData(array $order, string $paymentModel, string $txType, ?CreditCardInterface $creditCard = null, bool $createWithoutCard = true); /** * Regular Payment diff --git a/src/Serializer/ParamPosSerializer.php b/src/Serializer/ParamPosSerializer.php index bb7b4674..5e9566b9 100644 --- a/src/Serializer/ParamPosSerializer.php +++ b/src/Serializer/ParamPosSerializer.php @@ -8,6 +8,7 @@ use Mews\Pos\Gateways\ParamPos; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Serializer; class ParamPosSerializer implements SerializerInterface @@ -16,7 +17,11 @@ class ParamPosSerializer implements SerializerInterface public function __construct() { - $this->serializer = new Serializer([], [new JsonEncoder()]); + $encoder = new XmlEncoder([ + XmlEncoder::ROOT_NODE_NAME => 'soap:Envelope', + XmlEncoder::ENCODING => 'utf-8', + ]); + $this->serializer = new Serializer([], [$encoder, new JsonEncoder()]); } /** @@ -30,9 +35,19 @@ public static function supports(string $gatewayClass): bool /** * @inheritDoc */ - public function encode(array $data, ?string $txType = null): array + public function encode(array $data, ?string $txType = null) //todo { - return $data; + $data['@xmlns'] = 'https://turkpos.com.tr/'; + $wrapper = [ + '@xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + '@xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', + '@xmlns:soap' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'soap:Body' => [ + $txType => $data, + ], + ]; + + return $this->serializer->encode($wrapper, XmlEncoder::FORMAT); } /** @@ -40,7 +55,16 @@ public function encode(array $data, ?string $txType = null): array */ public function decode(string $data, ?string $txType = null): array { - dd($data); - return $this->serializer->decode($data, JsonEncoder::FORMAT); + // example fail response: + // ^ array:1 [▼ + // "soap:Fault" => array:3 [▼ + // "faultcode" => "soap:Server" + // "faultstring" => "Server was unable to process request. ---> Object reference not set to an instance of an object." + // "detail" => "" + // ] + //dd($data); + $result = $this->serializer->decode($data, XmlEncoder::FORMAT); + + return $result['soap:Body']; } } diff --git a/tests/Unit/Crypt/ParamPosCryptTest.php b/tests/Unit/Crypt/ParamPosCryptTest.php new file mode 100644 index 00000000..d5cd0979 --- /dev/null +++ b/tests/Unit/Crypt/ParamPosCryptTest.php @@ -0,0 +1,133 @@ +account = AccountFactory::createParamPosAccount( + 'param-pos', + 10738, + 'Test', + 'Test', + '0c13d406-873b-403b-9c09-a5766840d98c' + ); + + $logger = $this->createMock(LoggerInterface::class); + $this->crypt = new ParamPosCrypt($logger); + } + + public function testCreate3DHash(): void + { + $requestData = [ + 'clientid' => '700655000200', + 'oid' => 'order222', + 'amount' => '100.25', + 'taksit' => '', + 'islemtipi' => 'Auth', + 'okUrl' => 'https://domain.com/success', + 'failUrl' => 'https://domain.com/fail_url', + 'rnd' => 'rand', + ]; + $expected = 'S7UxUAohxaxzl35WxHyDfuQx0sg='; + + $actual = $this->crypt->create3DHash($this->account, $requestData); + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider threeDHashCheckDataProvider + */ + public function testCheck3DHash(bool $expected, array $responseData): void + { + $this->assertSame($expected, $this->crypt->check3DHash($this->account, $responseData)); + + $responseData['mdStatus'] = ''; + $this->assertFalse($this->crypt->check3DHash($this->account, $responseData)); + } + + public function testCheck3DHashException(): void + { + $account = $this->createMock(AbstractPosAccount::class); + $this->expectException(\LogicException::class); + $this->crypt->check3DHash($account, []); + } + + /** + * @dataProvider hashCreateDataProvider + */ + public function testCreateHash(array $requestData, string $expected): void + { + $actual = $this->crypt->createHash($this->account, $requestData); + $this->assertSame($expected, $actual); + } + + public static function threeDHashCheckDataProvider(): array + { + return [ + [ + 'expectedResult' => true, + 'responseData' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData'], + ], + ]; + } + + + public static function hashCreateDataProvider(): array + { + return [ + [ + 'requestData' => [ + 'G' => [ + 'CLIENT_CODE' => '10738', + 'CLIENT_USERNAME' => 'Test', + 'CLIENT_PASSWORD' => 'Test', + ], + 'GUID' => '0c13d406-873b-403b-9c09-a5766840d98c', + 'Islem_Guvenlik_Tip' => '3D', + 'Islem_ID' => '4FF84F9EA8BE63C25EFB15A2', + 'IPAdr' => '192.168.192.1', + 'Siparis_ID' => '202412293F4E', + 'Islem_Tutar' => '1.000,01', + 'Toplam_Tutar' => '1.000,01', + 'Basarili_URL' => 'http://localhost/parampos/3d/response.php', + 'Hata_URL' => 'http://localhost/parampos/3d/response.php', + 'Taksit' => '3', + 'KK_Sahibi' => 'John Doe', + 'KK_No' => '4446763125813623', + 'KK_SK_Ay' => '12', + 'KK_SK_Yil' => '2026', + 'KK_CVC' => '000', + 'KK_Sahibi_GSM' => '', + ], + 'expected' => 'jsLYSB3lJ81leFgDLw4D8PbXURs=', + ], + ]; + } +} diff --git a/tests/Unit/DataMapper/RequestDataMapper/ParamPosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/ParamPosRequestDataMapperTest.php new file mode 100644 index 00000000..7c317f9e --- /dev/null +++ b/tests/Unit/DataMapper/RequestDataMapper/ParamPosRequestDataMapperTest.php @@ -0,0 +1,632 @@ +account = AccountFactory::createParamPosAccount( + 'param-pos', + 10738, + 'Test1', + 'Test2', + '0c13d406-873b-403b-9c09-a5766840d98c' + ); + + $this->dispatcher = $this->createMock(EventDispatcherInterface::class); + + $this->crypt = $this->createMock(CryptInterface::class); + $this->requestDataMapper = new ParamPosRequestDataMapper($this->dispatcher, $this->crypt); + } + + /** + * @testWith ["pay", "1"] + * ["pre", "2"] + */ + public function testMapTxType(string $txType, string $expected): void + { + $actual = $this->requestDataMapper->mapTxType($txType); + $this->assertSame($expected, $actual); + } + + /** + * @testWith ["1"] + */ + public function testMapTxTypeException(string $txType): void + { + $this->expectException(UnsupportedTransactionTypeException::class); + $this->requestDataMapper->mapTxType($txType); + } + + + /** + * @return void + */ + public function testMapCurrency(): void + { + $class = new \ReflectionObject($this->requestDataMapper); + $method = $class->getMethod('mapCurrency'); + $method->setAccessible(true); + $this->assertSame('949', $method->invokeArgs($this->requestDataMapper, [PosInterface::CURRENCY_TRY])); + $this->assertSame('978', $method->invokeArgs($this->requestDataMapper, [PosInterface::CURRENCY_EUR])); + } + + /** + * @param string|int|null $installment + * @param string|int $expected + * + * @testWith ["0", "1"] + * ["1", "1"] + * ["2", "2"] + * [2, "2"] + * + * @return void + */ + public function testMapInstallment($installment, $expected): void + { + $class = new \ReflectionObject($this->requestDataMapper); + $method = $class->getMethod('mapInstallment'); + $method->setAccessible(true); + $this->assertSame($expected, $method->invokeArgs($this->requestDataMapper, [$installment])); + } + + /** + * @testWith [10.0, "10,00"] + * [1000.0, "1000,00"] + * [1000.5, "1000,50"] + */ + public function testFormatAmount(float $amount, string $formattedAmount): void + { + $class = new \ReflectionObject($this->requestDataMapper); + $method = $class->getMethod('formatAmount'); + $method->setAccessible(true); + $this->assertSame($formattedAmount, $method->invokeArgs($this->requestDataMapper, [$amount])); + } + + /** + * @dataProvider nonSecurePaymentPostRequestDataProvider + */ + public function testCreateNonSecurePostAuthPaymentRequestData(array $order, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actual = $this->requestDataMapper->createNonSecurePostAuthPaymentRequestData($this->account, $order); + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider paymentRegisterRequestDataProvider + */ + public function testCreate3DEnrollmentCheckRequestData(array $order, string $paymentModel, string $txType, CreditCardInterface $card, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['Islem_Hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['Islem_ID']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['Islem_Hash']); + + $actual = $this->requestDataMapper->create3DEnrollmentCheckRequestData($this->account, $order, $card); + + ksort($actual); + ksort($expected); + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider nonSecurePaymentRequestDataProvider + */ + public function testCreateNonSecurePaymentRequestData(array $order, string $txType, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actual = $this->requestDataMapper->createNonSecurePaymentRequestData($this->account, $order, $txType, $this->card); + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider cancelRequestDataProvider + */ + public function testCreateCancelRequestData(array $order, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actual = $this->requestDataMapper->createCancelRequestData($this->account, $order); + + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider orderHistoryRequestDataProvider + */ + public function testCreateOrderHistoryRequestData(array $order, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actual = $this->requestDataMapper->createOrderHistoryRequestData($this->account, $order); + + $this->assertSame($expected, $actual); + } + + + /** + * @dataProvider threeDFormDataProvider + */ + public function testGet3DFormData(array $order, string $txType, string $paymentModel, bool $withCard, string $gatewayURL, array $expected): void + { + $card = $withCard ? $this->card : null; + + $this->crypt->expects(self::never()) + ->method('create3DHash'); + + $this->crypt->expects(self::never()) + ->method('generateRandomString'); + + $this->dispatcher->expects(self::never()) + ->method('dispatch'); + + $actual = $this->requestDataMapper->create3DFormData( + $this->account, + $order, + $paymentModel, + $txType, + $gatewayURL, + $card + ); + + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider statusRequestDataProvider + */ + public function testCreateStatusRequestData(array $order, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actualData = $this->requestDataMapper->createStatusRequestData($this->account, $order); + + $this->assertSame($expected, $actualData); + } + + /** + * @dataProvider refundRequestDataProvider + */ + public function testCreateRefundRequestData(array $order, string $txType, array $expected): void + { + $requestDataWithoutHash = $expected; + unset($requestDataWithoutHash['hash']); + + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expected['rnd']); + $this->crypt->expects(self::once()) + ->method('createHash') + ->with($this->account, $requestDataWithoutHash) + ->willReturn($expected['hash']); + + $actual = $this->requestDataMapper->createRefundRequestData($this->account, $order, $txType); + + ksort($actual); + ksort($expected); + $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); + } + + /** + * @dataProvider createCustomQueryRequestDataDataProvider + */ + public function testCreateCustomQueryRequestData(array $requestData, array $expectedData): void + { + $this->crypt->expects(self::once()) + ->method('generateRandomString') + ->willReturn($expectedData['rnd']); + if (!isset($requestData['hash'])) { + $this->crypt->expects(self::once()) + ->method('createHash') + ->willReturn($expectedData['hash']); + } + + $actual = $this->requestDataMapper->createCustomQueryRequestData($this->account, $requestData); + $this->assertSame(14, \strlen($actual['timeSpan'])); + unset($actual['timeSpan'], $expectedData['timeSpan']); + + \ksort($actual); + \ksort($expectedData); + $this->assertSame($expectedData, $actual); + } + + public static function createCustomQueryRequestDataDataProvider(): \Generator + { + yield 'without_account_data_installment_option_inquiry' => [ + 'request_data' => [ + 'bin' => 415956, + ], + 'expected' => [ + 'apiUser' => 'POS_ENT_Test_001', + 'bin' => 415956, + 'clientId' => '1000000494', + 'hash' => '12fsdfdsfsfs', + 'rnd' => 'rndsfldfls', + 'timeSpan' => '20241103144302', + ], + ]; + + yield 'with_account_data_installment_option_inquiry' => [ + 'request_data' => [ + 'apiUser' => 'POS_ENT_Test_001xxx', + 'bin' => 415956, + 'clientId' => '1000000494xx', + 'hash' => '12fsdfdsfsfsxxx', + 'rnd' => 'rndsfldfls', + 'timeSpan' => '20241103144302', + ], + 'expected' => [ + 'apiUser' => 'POS_ENT_Test_001xxx', + 'bin' => 415956, + 'clientId' => '1000000494xx', + 'hash' => '12fsdfdsfsfsxxx', + 'rnd' => 'rndsfldfls', + 'timeSpan' => '20241103144302', + ], + ]; + } + + public static function statusRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => 'id-12', + 'time_span' => '20231209215355', + ], + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => 'id-12', + 'rnd' => 'rand-212s', + 'timeSpan' => '20231209215355', + 'hash' => 'jcgZOAf/m/E1uwYXmOPrdgqXRuEmVuG3Q14yri0okhULvRDbAicyAU8hflUP634yRRSZkOnIOeLZNqXfLhzz7g==', + ], + ], + ]; + } + + public static function cancelRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => 'id-12', + 'time_span' => '20231209215355', + ], + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => 'id-12', + 'rnd' => 'rand-212s', + 'timeSpan' => '20231209215355', + 'hash' => 'jcgZOAf/m/E1uwYXmOPrdgqXRuEmVuG3Q14yri0okhULvRDbAicyAU8hflUP634yRRSZkOnIOeLZNqXfLhzz7g==', + ], + ], + ]; + } + + public static function refundRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => 'id-12', + 'amount' => 1.02, + 'time_span' => '20231209215355', + ], + 'tx_type' => PosInterface::TX_TYPE_REFUND, + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => 'id-12', + 'rnd' => 'rand-212s', + 'timeSpan' => '20231209215355', + 'hash' => 'jcgZOAf/m/E1uwYXmOPrdgqXRuEmVuG3Q14yri0okhULvRDbAicyAU8hflUP634yRRSZkOnIOeLZNqXfLhzz7g==', + 'amount' => 102, + ], + ], + ]; + } + + public static function paymentRegisterRequestDataProvider(): array + { + $order = [ + 'id' => 'order222', + 'amount' => 1000.25, + 'installment' => 0, + 'currency' => PosInterface::CURRENCY_TRY, + 'ip' => '127.0.0.1', + 'success_url' => 'https://domain.com/success', + 'fail_url' => 'https://domain.com/fail', + ]; + + $card = CreditCardFactory::create('5555444433332222', '22', '01', '123', 'ahmet', CreditCardInterface::CARD_TYPE_VISA); + + return [ + [ + 'order' => $order, + 'paymentModel' => PosInterface::MODEL_3D_SECURE, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'card' => $card, + 'expected' => [ + 'Islem_ID' => 'rand', + 'Islem_Hash' => 'jsLYSB3lJ81leFgDLw4D8PbXURs=', + 'G' => [ + 'CLIENT_CODE' => '10738', + 'CLIENT_USERNAME' => 'Test1', + 'CLIENT_PASSWORD' => 'Test2', + ], + 'GUID' => '0c13d406-873b-403b-9c09-a5766840d98c', + 'Islem_Guvenlik_Tip' => '3D', + 'IPAdr' => '127.0.0.1', + 'Siparis_ID' => 'order222', + 'Islem_Tutar' => '1000,25', + 'Toplam_Tutar' => '1000,25', + 'Basarili_URL' => 'https://domain.com/success', + 'Hata_URL' => 'https://domain.com/fail', + 'Taksit' => '1', + 'KK_Sahibi' => 'ahmet', + 'KK_No' => '5555444433332222', + 'KK_SK_Ay' => '01', + 'KK_SK_Yil' => '2022', + 'KK_CVC' => '123', + 'KK_Sahibi_GSM' => '', + ], + ], + ]; + } + + public static function nonSecurePaymentRequestDataProvider(): array + { + $order = [ + 'id' => 'order222', + 'amount' => 100.25, + 'installment' => 0, + 'currency' => PosInterface::CURRENCY_TRY, + 'success_url' => 'https://domain.com/success', + 'time_span' => '20231209214708', + ]; + + return [ + [ + 'order' => $order, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => 'order222', + 'amount' => 10025, + 'currency' => 949, + 'installmentCount' => 0, + 'rnd' => 'rand', + 'timeSpan' => '20231209214708', + 'cardHolderName' => 'ahmet', + 'cardNo' => '5555444433332222', + 'expireDate' => '0122', + 'cvv' => '123', + 'hash' => '+XGO1qv+6W7nXZwSsYMaRrWXhi+99jffLvExGsFDodYyNadOG7OQKsygzly5ESDoNIS19oD2U+hSkVeT6UTAFA==', + ], + ], + ]; + } + + public static function nonSecurePaymentPostRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + 'amount' => 1.10, + 'time_span' => '20231209213944', + ], + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => '2020110828BC', + 'amount' => 110, + 'rnd' => 'raranra', + 'timeSpan' => '20231209213944', + 'hash' => 'bLp8WNYiaKrnW+EfwHuUZ1ovao0laSeuU/DqUMhjI40QNWdcHJWRKpkoE+eb1U07GGDgsIKKvx9nh84s6K1+pQ==', + ], + ], + ]; + } + + public static function orderHistoryRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + 'time_span' => '20231209215355', + 'transaction_date' => new \DateTime('2023-12-09 00:00:00'), + ], + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => '2020110828BC', + 'transactionDate' => '20231209', + 'page' => 1, + 'pageSize' => 10, + 'rnd' => 'rand-123', + 'timeSpan' => '20231209215355', + 'hash' => 'csrJh00U/nYGim8jPp9uddRdRvEWZf8pYu9Elss5RtA9JQt6DRkXxrTTY4iYQt5iABp5bj+/RYhlnTflyD9eBw==', + ], + ], + [ + 'order' => [ + 'id' => '2020110828BC', + 'time_span' => '20231209215355', + 'page' => 2, + 'page_size' => 5, + 'transaction_date' => new \DateTime('2023-12-09 00:00:00'), + ], + 'expected' => [ + 'clientId' => '1000000494', + 'apiUser' => 'POS_ENT_Test_001', + 'orderId' => '2020110828BC', + 'transactionDate' => '20231209', + 'page' => 2, + 'pageSize' => 5, + 'rnd' => 'rand-123', + 'timeSpan' => '20231209215355', + 'hash' => 'csrJh00U/nYGim8jPp9uddRdRvEWZf8pYu9Elss5RtA9JQt6DRkXxrTTY4iYQt5iABp5bj+/RYhlnTflyD9eBw==', + ], + ], + ]; + } + + public static function threeDFormDataProvider(): array + { + return [ + '3d_host_form_data' => [ + 'order' => [], + 'tx_type' => PosInterface::TX_TYPE_PAY_AUTH, + 'payment_model' => PosInterface::MODEL_3D_HOST, + 'is_with_card' => false, + 'gateway' => 'https://ent.akodepos.com/api/Payment/threeDSecure/A2A6E942BD2AE4A68BC42FE99D1BC917D67AFF54AB2BA44EBA675843744187708', + 'expected' => [ + 'gateway' => 'https://ent.akodepos.com/api/Payment/threeDSecure/A2A6E942BD2AE4A68BC42FE99D1BC917D67AFF54AB2BA44EBA675843744187708', + 'method' => 'GET', + 'inputs' => [], + ], + ], + '3d_pay_form_data' => [ + 'order' => [ + 'ThreeDSessionId' => 'P6D383818909442128AB50AB1EC7A4B83080874341688447DA74B90150C8857F2', + 'TransactionId' => '2000000000032631', + 'Code' => 0, + 'Message' => 'Başarılı', + ], + 'tx_type' => PosInterface::TX_TYPE_PAY_AUTH, + 'payment_model' => PosInterface::MODEL_3D_PAY, + 'is_with_card' => true, + 'gateway' => 'https://ent.akodepos.com/api/Payment/ProcessCardForm', + '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/ParamPosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/ParamPosResponseDataMapperTest.php new file mode 100644 index 00000000..0a16ec3f --- /dev/null +++ b/tests/Unit/DataMapper/ResponseDataMapper/ParamPosResponseDataMapperTest.php @@ -0,0 +1,2100 @@ +logger = $this->createMock(LoggerInterface::class); + + $requestDataMapper = new ParamPosRequestDataMapper( + $this->createMock(EventDispatcherInterface::class), + $this->createMock(CryptInterface::class), + ); + + $this->responseDataMapper = new ParamPosResponseDataMapper( + $requestDataMapper->getCurrencyMappings(), + $requestDataMapper->getTxTypeMappings(), + $requestDataMapper->getSecureTypeMappings(), + $this->logger, + ); + } + + /** + * @testWith [null, false] + * ["", false] + * ["2", false] + * ["3", false] + * ["4", false] + * ["7", false] + * ["1", true] + * ["0", false] + * + */ + public function testIs3dAuthSuccess(?string $mdStatus, bool $expected): void + { + $actual = $this->responseDataMapper->is3dAuthSuccess($mdStatus); + $this->assertSame($expected, $actual); + } + + + /** + * @testWith [[], null] + * [{"mdStatus": "1"}, "1"] + * + */ + public function testExtractMdStatus(array $responseData, ?string $expected): void + { + $actual = $this->responseDataMapper->extractMdStatus($responseData); + $this->assertSame($expected, $actual); + } + + + /** + * @dataProvider paymentTestDataProvider + */ + public function testMapPaymentResponse(array $order, string $txType, array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->mapPaymentResponse($responseData, $txType, $order); + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + unset($actualData['transaction_time'], $expectedData['transaction_time']); + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + \ksort($expectedData); + \ksort($actualData); + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider threeDPaymentDataProvider + */ + public function testMap3DPaymentData(array $order, string $txType, array $threeDResponseData, array $paymentResponse, array $expectedData): void + { + $actualData = $this->responseDataMapper->map3DPaymentData( + $threeDResponseData, + $paymentResponse, + $txType, + $order, + ); + if ($expectedData['transaction_time'] instanceof \DateTimeImmutable && $actualData['transaction_time'] instanceof \DateTimeImmutable) { + $this->assertSame($expectedData['transaction_time']->format('Ymd'), $actualData['transaction_time']->format('Ymd')); + } else { + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + } + unset($actualData['transaction_time'], $expectedData['transaction_time']); + + $this->assertArrayHasKey('all', $actualData); + if ([] !== $paymentResponse) { + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + } + + $this->assertArrayHasKey('3d_all', $actualData); + $this->assertIsArray($actualData['3d_all']); + $this->assertNotEmpty($actualData['3d_all']); + unset($actualData['all'], $actualData['3d_all']); + + \ksort($expectedData); + \ksort($actualData); + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider threeDPayPaymentDataProvider + */ + public function testMap3DPayResponseData(array $order, string $txType, array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->map3DPayResponseData($responseData, $txType, $order); + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + unset($actualData['transaction_time'], $expectedData['transaction_time']); + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + \ksort($expectedData); + \ksort($actualData); + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider threeDHostPaymentDataProvider + */ + public function testMap3DHostResponseData(array $order, string $txType, array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->map3DHostResponseData($responseData, $txType, $order); + if ($expectedData['transaction_time'] instanceof \DateTimeImmutable && $actualData['transaction_time'] instanceof \DateTimeImmutable) { + $this->assertSame($expectedData['transaction_time']->format('Ymd'), $actualData['transaction_time']->format('Ymd')); + } else { + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + } + + unset($actualData['transaction_time'], $expectedData['transaction_time']); + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + \ksort($expectedData); + \ksort($actualData); + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider statusTestDataProvider + */ + public function testMapStatusResponse(array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->mapStatusResponse($responseData); + + if (isset($actualData['recurringOrders'])) { + foreach ($actualData['recurringOrders'] as $key => $actualRecurringOrder) { + $expectedRecurringOrder = $expectedData['recurringOrders'][$key]; + \ksort($expectedData['recurringOrders'][$key]); + \ksort($actualData['recurringOrders'][$key]); + $this->assertEquals($expectedRecurringOrder['transaction_time'], $actualRecurringOrder['transaction_time']); + $this->assertEquals($expectedRecurringOrder['capture_time'], $actualRecurringOrder['capture_time']); + unset($actualData['recurringOrders'][$key]['transaction_time'], $expectedData['recurringOrders'][$key]['transaction_time']); + unset($actualData['recurringOrders'][$key]['capture_time'], $expectedData['recurringOrders'][$key]['capture_time']); + } + } else { + $this->assertEquals($expectedData['transaction_time'], $actualData['transaction_time']); + $this->assertEquals($expectedData['capture_time'], $actualData['capture_time']); + $this->assertEquals($expectedData['refund_time'], $actualData['refund_time']); + $this->assertEquals($expectedData['cancel_time'], $actualData['cancel_time']); + unset($actualData['transaction_time'], $expectedData['transaction_time']); + unset($actualData['capture_time'], $expectedData['capture_time']); + unset($actualData['cancel_time'], $expectedData['cancel_time']); + unset($actualData['refund_time'], $expectedData['refund_time']); + } + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + \ksort($expectedData); + \ksort($actualData); + + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider refundTestDataProvider + */ + public function testMapRefundResponse(array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->mapRefundResponse($responseData); + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider cancelTestDataProvider + */ + public function testMapCancelResponse(array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->mapCancelResponse($responseData); + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + $this->assertSame($expectedData, $actualData); + } + + /** + * @dataProvider orderHistoryTestDataProvider + */ + public function testMapOrderHistoryResponse(array $responseData, array $expectedData): void + { + $actualData = $this->responseDataMapper->mapOrderHistoryResponse($responseData); + if (count($responseData['Extra']) > 0) { + if (count($actualData['transactions']) > 1 + && null !== $actualData['transactions'][0]['transaction_time'] + && null !== $actualData['transactions'][1]['transaction_time'] + ) { + $this->assertGreaterThan( + $actualData['transactions'][0]['transaction_time'], + $actualData['transactions'][1]['transaction_time'], + ); + } + + foreach (array_keys($actualData['transactions']) as $key) { + $this->assertEquals($expectedData['transactions'][$key]['transaction_time'], $actualData['transactions'][$key]['transaction_time']); + $this->assertEquals($expectedData['transactions'][$key]['capture_time'], $actualData['transactions'][$key]['capture_time']); + unset($actualData['transactions'][$key]['transaction_time'], $expectedData['transactions'][$key]['transaction_time']); + \ksort($actualData['transactions'][$key]); + \ksort($expectedData['transactions'][$key]); + } + + $this->assertCount($actualData['trans_count'], $actualData['transactions']); + } + + $this->assertArrayHasKey('all', $actualData); + $this->assertIsArray($actualData['all']); + $this->assertNotEmpty($actualData['all']); + unset($actualData['all']); + + \ksort($expectedData); + \ksort($actualData); + $this->assertSame($expectedData, $actualData); + } + + public function testMapHistoryResponse(): void + { + $this->expectException(NotImplementedException::class); + $this->responseDataMapper->mapHistoryResponse([]); + } + + public static function paymentTestDataProvider(): iterable + { + yield 'success1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'responseData' => [ + 'OrderId' => '202210293885', + 'GroupId' => '202210293885', + 'Response' => 'Approved', + 'AuthCode' => 'P48911', + 'HostRefNum' => '230200671758', + 'ProcReturnCode' => '00', + 'TransId' => '22302V8rE11732', + 'ErrMsg' => null, + 'Extra' => [ + 'SETTLEID' => '2286', + 'TRXDATE' => '20221029 21:58:43', + 'ERRORCODE' => null, + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'CARDBRAND' => 'VISA', + 'CARDISSUER' => 'AKBANK T.A.S.', + 'AVSAPPROVE' => 'Y', + 'HOSTDATE' => '1029-215844', + 'AVSERRORCODEDETAIL' => 'avshatali-avshatali-avshatali-avshatali-', + 'NUMCODE' => '00', + ], + ], + 'expectedData' => [ + 'transaction_id' => '22302V8rE11732', + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable('2022-10-29 21:58:43'), + 'payment_model' => 'regular', + 'order_id' => '202210293885', + 'group_id' => '202210293885', + 'auth_code' => 'P48911', + 'ref_ret_num' => '230200671758', + 'batch_num' => null, + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'error_code' => null, + 'error_message' => null, + 'recurring_id' => null, + 'currency' => 'TRY', + 'amount' => 1.01, + 'installment_count' => null, + ], + ]; + yield 'success2WithoutERRORCODE' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'responseData' => [ + 'OrderId' => '202210293885', + 'GroupId' => '202210293885', + 'Response' => 'Approved', + 'AuthCode' => 'P48911', + 'HostRefNum' => '230200671758', + 'ProcReturnCode' => '00', + 'TransId' => '22302V8rE11732', + 'ErrMsg' => null, + 'Extra' => [ + 'SETTLEID' => '2286', + 'TRXDATE' => '20221029 21:58:43', + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'CARDBRAND' => 'VISA', + 'CARDISSUER' => 'AKBANK T.A.S.', + 'AVSAPPROVE' => 'Y', + 'HOSTDATE' => '1029-215844', + 'AVSERRORCODEDETAIL' => 'avshatali-avshatali-avshatali-avshatali-', + 'NUMCODE' => '00', + ], + ], + 'expectedData' => [ + 'transaction_id' => '22302V8rE11732', + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable('2022-10-29 21:58:43'), + 'payment_model' => 'regular', + 'order_id' => '202210293885', + 'group_id' => '202210293885', + 'auth_code' => 'P48911', + 'ref_ret_num' => '230200671758', + 'batch_num' => null, + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'error_code' => null, + 'error_message' => null, + 'recurring_id' => null, + 'currency' => 'TRY', + 'amount' => 1.01, + 'installment_count' => null, + ], + ]; + yield 'fail1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'responseData' => [ + 'OrderId' => '20221029B541', + 'GroupId' => '20221029B541', + 'Response' => 'Error', + 'AuthCode' => '', + 'HostRefNum' => '', + 'ProcReturnCode' => '99', + 'TransId' => '22302WcCC13836', + 'ErrMsg' => 'Kredi karti numarasi gecerli formatta degil.', + 'Extra' => [ + 'SETTLEID' => '', + 'TRXDATE' => '20221029 22:28:01', + 'ERRORCODE' => 'CORE-2012', + 'NUMCODE' => '992012', + ], + ], + 'expectedData' => [ + 'transaction_id' => '22302WcCC13836', + 'transaction_type' => 'pay', + 'transaction_time' => null, + 'payment_model' => 'regular', + 'order_id' => '20221029B541', + 'group_id' => '20221029B541', + 'auth_code' => null, + 'ref_ret_num' => null, + 'batch_num' => null, + 'proc_return_code' => '99', + 'status' => 'declined', + 'status_detail' => 'general_error', + 'error_code' => 'CORE-2012', + 'error_message' => 'Kredi karti numarasi gecerli formatta degil.', + 'recurring_id' => null, + 'currency' => 'TRY', + 'amount' => 1.01, + 'installment_count' => null, + ], + ]; + + yield 'success_2' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'responseData' => [ + 'OrderId' => '20221030FAC5', + 'GroupId' => '20221030FAC5', + 'Response' => 'Approved', + 'AuthCode' => 'P90325', + 'HostRefNum' => '230300671782', + 'ProcReturnCode' => '00', + 'TransId' => '22303Md4C19254', + 'ErrMsg' => '', + 'Extra' => [ + 'SETTLEID' => '2287', + 'TRXDATE' => '20221030 12:29:53', + 'ERRORCODE' => '', + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'CARDBRAND' => 'VISA', + 'CARDISSUER' => 'AKBANK T.A.S.', + 'AVSAPPROVE' => 'Y', + 'HOSTDATE' => '1030-122954', + 'AVSERRORCODEDETAIL' => 'avshatali-avshatali-avshatali-avshatali-', + 'NUMCODE' => '00', + ], + ], + 'expectedData' => [ + 'transaction_id' => '22303Md4C19254', + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable('2022-10-30 12:29:53'), + 'payment_model' => 'regular', + 'order_id' => '20221030FAC5', + 'group_id' => '20221030FAC5', + 'auth_code' => 'P90325', + 'ref_ret_num' => '230300671782', + 'batch_num' => null, + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'error_code' => null, + 'error_message' => null, + 'recurring_id' => null, + 'currency' => 'TRY', + 'amount' => 1.01, + 'installment_count' => null, + ], + ]; + } + + + public static function threeDPaymentDataProvider(): array + { + return [ + 'success1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'md' => '444676:13FDE30917BF65D853787DB838390849D73151A10FC8C1192AC72660F2464521:3473:##190100000', + 'mdStatus' => '1', + 'orderId' => '202412292160', + 'transactionAmount' => '10,01', + 'islemGUID' => '8b6868fe-a553-4164-a7cc-528461f21759', + 'islemHash' => 'jF0PD92E+dM394Z1h5qm4SB6pPo=', + 'bankResult' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/DkaeFfwOZ334oKIk/creq;token=338860451.17354 1', + 'dc' => '', + 'dcURL' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', + ], + 'paymentData' => [ + 'TP_WMD_PayResponse' => [ + 'TP_WMD_PayResult' => [ + 'Sonuc' => '1', + 'Sonuc_Ack' => 'Başarılı', + 'Dekont_ID' => '3007295376', + 'Siparis_ID' => '202412292160', + 'UCD_MD' => '444676:E997FB32A642B0929CCDB822BB3BB2B65050DAAA2E57A31F3E510B8664954C03:3915:##190100000', + 'Bank_Trans_ID' => '24364TKkF16602', + 'Bank_AuthCode' => '150888', + 'Bank_HostMsg' => 'Approved', + 'Bank_Extra' => ' +2881 +20241229 19:10:36 + +VISA +ZİRAAT BANKASI +000000010.00 +00 +', + 'Bank_Sonuc_Kod' => '0', + 'Bank_HostRefNum' => '436419200463', + 'Komisyon_Oran' => '1.01', + ], + ], + ], + 'expectedData' => [ + 'amount' => 10.01, + 'auth_code' => '150888', + 'batch_num' => null, + 'currency' => 'TRY', + 'error_code' => null, + 'error_message' => null, + 'installment_count' => null, + 'md_error_message' => null, + 'md_status' => '1', + 'order_id' => '202412292160', + 'payment_model' => '3d', + 'proc_return_code' => 1, + 'ref_ret_num' => '436419200463', + 'status' => 'approved', + 'status_detail' => null, + 'transaction_id' => '24364TKkF16602', + 'transaction_security' => null, + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable(), + ], + ], + '3d_auth_fail' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'md' => '444676:84E83D96A7CEC3A5815D49EB7F64D2709D1BC30425D578D118B9819A81749FB8:4429:##190100000', + 'mdStatus' => '0', + 'orderId' => '20241229C152', + 'transactionAmount' => '1000,01', + 'islemGUID' => 'c1ee369b-ec27-4ab6-8c27-2e15e62793d3', + 'islemHash' => 'N1/W7/GcbuT3UVwVM9Q5C/rmoKg=', + 'bankResult' => 'N-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/wkwLCHgiNwZCiVZp/creq;token=338863271.17354 0', + 'dc' => null, + 'dcURL' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', + ], + 'paymentData' => [], + 'expectedData' => [ + 'amount' => 1000.01, + 'auth_code' => null, + 'batch_num' => null, + 'currency' => 'TRY', + 'error_code' => null, + 'error_message' => null, + 'installment_count' => null, + 'md_error_message' => null, + 'md_status' => '0', + 'order_id' => '20241229C152', + 'payment_model' => '3d', + 'proc_return_code' => null, + 'ref_ret_num' => null, + 'status' => 'declined', + 'status_detail' => null, + 'transaction_id' => null, + 'transaction_security' => null, + 'transaction_time' => null, + 'transaction_type' => 'pay', + ], + ], + '3d_auth_success_payment_fail' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'TRANID' => '', + 'PAResSyntaxOK' => 'true', + 'firmaadi' => 'John Doe', + 'islemtipi' => 'Auth', + 'lang' => 'tr', + 'merchantID' => '190100000', + 'maskedCreditCard' => '4355 08** **** 4358', + 'amount' => '1.01', + 'sID' => '1', + 'ACQBIN' => '454672', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'Email' => 'mail@customer.com', + 'MaskedPan' => '435508***4358', + 'merchantName' => 'Ziraat 3D', + 'clientIp' => '89.244.149.137', + 'okUrl' => 'http://localhost/akbank/3d/response.php', + 'md' => '435508:9716234382F9D9B630CC01452A6F160D31A2E1DBD41706C6AF8B8E6F730FE65D:3677:##190100000', + 'taksit' => '12', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'storetype' => '3d', + 'mdErrorMsg' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704701.1667119495.sIHzA7ckv-0', + 'PAResVerified' => 'true', + 'cavv' => 'ABABA##################AEJI=', + 'digest' => 'digest', + 'callbackCall' => 'true', + 'failUrl' => 'http://localhost/akbank/3d/response.php', + 'xid' => '2aeoSfQde3NyV2XjSeTL0sGNYSg=', + 'encoding' => 'ISO-8859-9', + 'currency' => '949', + 'oid' => '20221030FE4C', + 'mdStatus' => '1', + 'dsId' => '1', + 'eci' => '05', + 'version' => '2.0', + 'clientid' => '190100000', + 'txstatus' => 'Y', + 'HASH' => '+NYQKADaaWWUIAIg6U77nGIK+8k=', + 'rnd' => 'IXa1XnlaOxpMCacqG/cB', + 'HASHPARAMS' => 'clientid:oid:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '19010000020221030FE4C1ABABA##################AEJI=05435508:9716234382F9D9B630CC01452A6F160D31A2E1DBD41706C6AF8B8E6F730FE65D:3677:##190100000IXa1XnlaOxpMCacqG/cB', + ], + 'paymentData' => [ + 'OrderId' => '20221030FE4C', + 'GroupId' => '20221030FE4C', + 'Response' => 'Error', + 'AuthCode' => '', + 'HostRefNum' => '', + 'ProcReturnCode' => '99', + 'TransId' => '22303LtCH15933', + 'ErrMsg' => 'Taksit tablosu icin gecersiz deger', + 'Extra' => [ + 'SETTLEID' => '', + 'TRXDATE' => '20221030 11:45:02', + 'ERRORCODE' => 'CORE-2603', + 'NUMCODE' => '992603', + ], + ], + 'expectedData' => [ + 'transaction_id' => '22303LtCH15933', + 'transaction_type' => 'pay', + 'transaction_time' => null, + 'transaction_security' => 'Full 3D Secure', + 'md_status' => '1', + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'eci' => '05', + 'tx_status' => null, + 'cavv' => 'ABABA##################AEJI=', + 'md_error_message' => null, + 'group_id' => '20221030FE4C', + 'auth_code' => null, + 'ref_ret_num' => null, + 'batch_num' => null, + 'proc_return_code' => '99', + 'status' => 'declined', + 'status_detail' => 'general_error', + 'error_code' => 'CORE-2603', + 'error_message' => 'Taksit tablosu icin gecersiz deger', + 'recurring_id' => null, + 'installment_count' => 12, + 'order_id' => '20221030FE4C', + 'payment_model' => '3d', + ], + ], + '3d_auth_success_payment_fail_wong_cvv' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'threeDResponseData' => [ + 'TRANID' => '', + 'PAResSyntaxOK' => 'true', + 'firmaadi' => 'John Doe', + 'islemtipi' => 'Auth', + 'lang' => 'tr', + 'merchantID' => '190100000', + 'maskedCreditCard' => '4355 08** **** 4358', + 'amount' => '1.01', + 'sID' => '1', + 'ACQBIN' => '454672', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'Email' => 'mail@customer.com', + 'MaskedPan' => '435508***4358', + 'merchantName' => 'Ziraat 3D', + 'clientIp' => '89.244.149.137', + 'okUrl' => 'http://localhost/akbank/3d/response.php', + 'md' => '435508:9716234382F9D9B630CC01452A6F160D31A2E1DBD41706C6AF8B8E6F730FE65D:3677:##190100000', + 'taksit' => '12', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'storetype' => '3d', + 'mdErrorMsg' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704701.1667119495.sIHzA7ckv-0', + 'PAResVerified' => 'true', + 'cavv' => 'ABABA##################AEJI=', + 'digest' => 'digest', + 'callbackCall' => 'true', + 'failUrl' => 'http://localhost/akbank/3d/response.php', + 'xid' => '2aeoSfQde3NyV2XjSeTL0sGNYSg=', + 'encoding' => 'ISO-8859-9', + 'currency' => '949', + 'oid' => '20221030FE4C', + 'mdStatus' => '1', + 'dsId' => '1', + 'eci' => '05', + 'version' => '2.0', + 'clientid' => '190100000', + 'txstatus' => 'Y', + 'HASH' => '+NYQKADaaWWUIAIg6U77nGIK+8k=', + 'rnd' => 'IXa1XnlaOxpMCacqG/cB', + 'HASHPARAMS' => 'clientid:oid:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '19010000020221030FE4C1ABABA##################AEJI=05435508:9716234382F9D9B630CC01452A6F160D31A2E1DBD41706C6AF8B8E6F730FE65D:3677:##190100000IXa1XnlaOxpMCacqG/cB', + ], + 'paymentData' => [ + 'OrderId' => '4c4', + 'GroupId' => '4aa841c4', + 'Response' => 'Declined', + 'HostRefNum' => '4139489', + 'ProcReturnCode' => '82', + 'TransId' => '24138rt2596', + 'ErrMsg' => 'CVV Hatasi veya girilen CVV gecersiz.', + 'Extra' => [ + 'KULLANILANPUAN' => '000000000000', + 'CARDBRAND' => 'VISA', + 'CARDISSUER' => 'ZİRAAT BANKASI', + 'ERRORCODE' => 'ISO8583-82', + 'TRXDATE' => '20240517 13:17:31', + 'KULLANILABILIRPUAN' => '000000000000', + 'ACQSTAN' => '769489', + 'KAZANILANPUAN' => '000000000105', + 'TRACEID' => '2c4e0abd4560418ace038267fa57f5c9', + 'NUMCODE' => '82', + ], + ], + 'expectedData' => [ + 'transaction_id' => '24138rt2596', + 'transaction_type' => 'pay', + 'transaction_time' => null, + 'transaction_security' => 'Full 3D Secure', + 'md_status' => '1', + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'eci' => '05', + 'tx_status' => null, + 'cavv' => 'ABABA##################AEJI=', + 'md_error_message' => null, + 'group_id' => '4aa841c4', + 'auth_code' => null, + 'ref_ret_num' => '4139489', + 'batch_num' => null, + 'proc_return_code' => '82', + 'status' => 'declined', + 'status_detail' => null, + 'error_code' => 'ISO8583-82', + 'error_message' => 'CVV Hatasi veya girilen CVV gecersiz.', + 'recurring_id' => null, + 'installment_count' => 12, + 'order_id' => '4c4', + 'payment_model' => '3d', + ], + ], + ]; + } + + + public static function threeDPayPaymentDataProvider(): array + { + return [ + 'success1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentData' => [ + 'ReturnOid' => '2022103030CB', + 'TRANID' => '', + 'EXTRA_MERCHANTID' => '655000200', + 'PAResSyntaxOK' => 'true', + 'EXTRA_HOSTDATE' => '1030-112244', + 'firmaadi' => 'John Doe', + 'islemtipi' => 'Auth', + 'EXTRA_TERMINALID' => '00655020', + 'lang' => 'tr', + 'merchantID' => '700655000200', + 'maskedCreditCard' => '4355 08** **** 4358', + 'amount' => '1.01', + 'sID' => '1', + 'ACQBIN' => '406456', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'EXTRA_CARDBRAND' => 'VISA', + 'Email' => 'mail@customer.com', + 'MaskedPan' => '435508***4358', + 'acqStan' => '671764', + 'merchantName' => 'İşbank 3d_pay Store', + 'clientIp' => '89.244.149.137', + 'okUrl' => 'http://localhost/akbank/3d-pay/response.php', + 'md' => '435508:EC9CDC37975501A4B29BBD5BE1580279238BF88D888B23E7ECC293581C75EE40:4333:##700655000200', + 'ProcReturnCode' => '00', + 'payResults_dsId' => '1', + 'taksit' => '', + 'TransId' => '22303LWsA14386', + 'EXTRA_TRXDATE' => '20221030 11:22:43', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'storetype' => '3d_pay', + 'Response' => 'Approved', + 'SettleId' => '2287', + 'mdErrorMsg' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704511.1667118159.BUW_iXHm4_6', + 'ErrMsg' => '', + 'PAResVerified' => 'true', + 'cavv' => 'ABABByBkEgAAAABllJMDdVWUGZE=', + 'EXTRA_AVSERRORCODEDETAIL' => 'avshatali-avshatali-avshatali-avshatali-', + 'digest' => 'digest', + 'HostRefNum' => '230300671764', + 'callbackCall' => 'true', + 'AuthCode' => 'P37891', + 'failUrl' => 'http://localhost/akbank/3d-pay/response.php', + 'xid' => 'xyxZZ/eJ3eVDkqYiDOdwPfCkq5U=', + 'encoding' => 'ISO-8859-9', + 'currency' => '949', + 'oid' => '2022103030CB', + 'mdStatus' => '1', + 'dsId' => '1', + 'EXTRA_AVSAPPROVE' => 'Y', + 'eci' => '05', + 'version' => '2.0', + 'EXTRA_CARDISSUER' => 'AKBANK T.A.S.', + 'clientid' => '700655000200', + 'txstatus' => 'Y', + 'HASH' => 'FQLnGOxBBMIoMIRxehiaLtkEd34=', + 'rnd' => 'kP/2JB5ajHJt+yVhHNG9', + 'HASHPARAMS' => 'clientid:oid:AuthCode:ProcReturnCode:Response:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '7006550002002022103030CBP3789100Approved1ABABByBkEgAAAABllJMDdVWUGZE=05435508:EC9CDC37975501A4B29BBD5BE1580279238BF88D888B23E7ECC293581C75EE40:4333:##700655000200kP/2JB5ajHJt+yVhHNG9', + 'NATIONALIDNO' => '', + ], + 'expectedData' => [ + 'transaction_id' => '22303LWsA14386', + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable('2022-10-30 11:22:43'), + 'transaction_security' => 'Full 3D Secure', + 'md_status' => '1', + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'tx_status' => null, + 'eci' => '05', + 'cavv' => 'ABABByBkEgAAAABllJMDdVWUGZE=', + 'md_error_message' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704511.1667118159.BUW_iXHm4_6', + 'order_id' => '2022103030CB', + 'auth_code' => 'P37891', + 'ref_ret_num' => '230300671764', + 'batch_num' => null, + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'error_code' => null, + 'error_message' => null, + 'payment_model' => '3d_pay', + 'installment_count' => 0, + ], + ], + 'authFail1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentData' => [ + 'sID' => '1', + 'oid' => '2022103008A3', + 'encoding' => 'ISO-8859-9', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'version' => '2.0', + 'currency' => '949', + 'dsId' => '1', + 'callbackCall' => 'true', + 'amount' => '1.01', + 'maskedCreditCard' => '4355 08** **** 4358', + 'islemtipi' => 'Auth', + 'firmaadi' => 'John Doe', + 'merchantName' => 'İşbank 3d_pay Store', + 'ACQBIN' => '406456', + 'PAResSyntaxOK' => 'true', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'storetype' => '3d_pay', + 'mdStatus' => '0', + 'failUrl' => 'http://localhost/akbank/3d-pay/response.php', + 'clientIp' => '89.244.149.137', + 'merchantID' => '700655000200', + 'mdErrorMsg' => 'N-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704541.1667118445.QQ1EjzXz8nm', + 'clientid' => '700655000200', + 'MaskedPan' => '435508***4358', + 'txstatus' => 'N', + 'digest' => 'digest', + 'PAResVerified' => 'true', + 'Email' => 'mail@customer.com', + 'taksit' => '', + 'okUrl' => 'http://localhost/akbank/3d-pay/response.php', + 'md' => '435508:44868DF53C03B6FFC4479AF5C897CC86F10D7D3D6C20859EA77277B0E954125F:4320:##700655000200', + 'lang' => 'tr', + 'xid' => 'jDiMogllA6etX+EvmM+zG+VMvo4=', + 'TRANID' => '', + 'HASH' => 'mbWDXpM1SQfYIEJ5M1KfP/hOE18=', + 'rnd' => 'I6wQZkKfEnDG1myeLBlt', + 'HASHPARAMS' => 'clientid:oid:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '7006550002002022103008A30435508:44868DF53C03B6FFC4479AF5C897CC86F10D7D3D6C20859EA77277B0E954125F:4320:##700655000200I6wQZkKfEnDG1myeLBlt', + ], + 'expectedData' => [ + 'transaction_id' => null, + 'transaction_type' => 'pay', + 'transaction_time' => null, + 'transaction_security' => 'MPI fallback', + 'auth_code' => null, + 'ref_ret_num' => null, + 'batch_num' => null, + 'status_detail' => null, + 'error_code' => null, + 'error_message' => null, + 'md_status' => '0', + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'tx_status' => null, + 'eci' => null, + 'cavv' => null, + 'md_error_message' => 'N-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704541.1667118445.QQ1EjzXz8nm', + 'order_id' => '2022103008A3', + 'proc_return_code' => null, + 'status' => 'declined', + 'payment_model' => '3d_pay', + 'installment_count' => 0, + ], + ], + ]; + } + + + public static function threeDHostPaymentDataProvider(): array + { + return [ + 'success1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentData' => [ + 'panFirst6' => '', + 'TRANID' => '', + 'tadres2' => '', + 'SECMELIKAMPANYAKOD' => '000001', + 'PAResSyntaxOK' => 'true', + 'querydcchash' => 'ibQg/1ukwQq0I713SvZmfOpsWemylDZj+CJAYfSYn1aHbkycJ2HWJCVYUNcuZWOV7SGHaYp6cHAc9/dZq4wahA==', + 'panLast4' => '', + 'firmaadi' => 'John Doe', + 'islemtipi' => 'Auth', + 'campaignOptions' => '000001', + 'refreshTime' => '300', + 'lang' => 'tr', + 'merchantID' => '700655000200', + 'maskedCreditCard' => '4355 08** **** 4358', + 'amount' => '1.01', + 'sID' => '1', + 'ACQBIN' => '406456', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'MAXTIPLIMIT' => '0.00', + 'MaskedPan' => '435508***4358', + 'Email' => 'mail@customer.com', + 'Fadres' => '', + 'merchantName' => 'İşbank 3d_pay Store', + 'clientIp' => '89.244.149.137', + 'girogateParamReqHash' => '9Cfbi+RsV2HVXB5LNB68ypK5twIcyk7ZyOZ64rl7ZNs8c/QzMyFtReUmtIBLxrxzTEd2C04ImgQFjTWr/OsTOw==', + 'okUrl' => 'http://localhost/akbank/3d-host/response.php', + 'tismi' => '', + 'md' => '435508:ABC94F203210DDBC157B3E04D9C1BF62BEC966DB554A878EFC62B4C7F75F045D:4183:##700655000200', + 'taksit' => '', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'tcknvkn' => '', + 'showdcchash' => '/M4AcoVyOILQme8b6dVSEFgTPo+AnXQRE2fGisdVUWUxV+oODWIYC3iOThJD1OqdDGC8M+wVQ/MN5Of7dWRS9Q==', + 'storetype' => '3d_host', + 'querycampainghash' => 'dt+GSalwGNZfYZm/ZV5JbiTIo95NP8LP6Wvuihdc11sokCUczXbC6lUcCskKWEcrvIAtlAPs562Izc71fiYOVw==', + 'mdErrorMsg' => 'Y-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214704861.1667120442.x-PxIquJzuV', + 'PAResVerified' => 'true', + 'cavv' => 'ABABA##################UGZE=', + 'digest' => 'digest', + 'callbackCall' => 'true', + 'failUrl' => 'http://localhost/akbank/3d-host/response.php', + 'pbirimsembol' => 'TL ', + 'xid' => 'J/CJIQ171+w/IOvf6CfmRXOYKfU=', + 'checkisonushash' => 'jnjgIUP8ji/mifImB8JTrlA1Mc32r7DsD4cKeKD+RUEZG+POkS2hdsORLaUksXlpoc8DAuFvnOXcZZlRVMh35g==', + 'encoding' => 'ISO-8859-9', + 'currency' => '949', + 'oid' => '202210305DCF', + 'mdStatus' => '1', + 'dsId' => '1', + 'eci' => '05', + 'version' => '2.0', + 'Fadres2' => '', + 'Fismi' => '', + 'clientid' => '700655000200', + 'txstatus' => 'Y', + 'tadres' => '', + 'HASH' => 'EP5x+IDL3+TSIBXwTNG7YgKUoHY=', + 'rnd' => 'wxI/n3+bu0CbyBo5OMXY', + 'HASHPARAMS' => 'clientid:oid:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '700655000200202210305DCF1ABABA##################UGZE=05435508:ABC94F203210DDBC157B3E04D9C1BF62BEC966DB554A878EFC62B4C7F75F045D:4183:##700655000200wxI/n3+bu0CbyBo5OMXY', + ], + 'expectedData' => [ + 'transaction_id' => null, + 'transaction_type' => 'pay', + 'transaction_time' => new \DateTimeImmutable(), + 'transaction_security' => 'Full 3D Secure', + 'auth_code' => null, + 'ref_ret_num' => null, + 'batch_num' => null, + 'proc_return_code' => null, + 'status_detail' => null, + 'error_code' => null, + 'error_message' => null, + 'md_status' => '1', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'tx_status' => null, + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'eci' => '05', + 'cavv' => 'ABABA##################UGZE=', + 'md_error_message' => null, + 'order_id' => '202210305DCF', + 'status' => 'approved', + 'payment_model' => '3d_host', + 'installment_count' => 0, + ], + ], + '3d_auth_fail1' => [ + 'order' => [ + 'currency' => PosInterface::CURRENCY_TRY, + 'amount' => 1.01, + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'paymentData' => [ + 'panFirst6' => '', + 'TRANID' => '', + 'tadres2' => '', + 'SECMELIKAMPANYAKOD' => '000002', + 'PAResSyntaxOK' => 'true', + 'querydcchash' => 'cDZR0kiNLFGnXovfVkcmh1/kTMHP4cOBai1GWNxy7Tdw0QYD6SruG2GmtwPJYiB4CACP941/mitzPYhRwIsJ9g==', + 'panLast4' => '', + 'firmaadi' => 'John Doe', + 'islemtipi' => 'Auth', + 'campaignOptions' => '000002', + 'refreshTime' => '300', + 'lang' => 'tr', + 'merchantID' => '700655000200', + 'maskedCreditCard' => '4355 08** **** 4358', + 'amount' => '1.01', + 'sID' => '1', + 'ACQBIN' => '406456', + 'Ecom_Payment_Card_ExpDate_Year' => '26', + 'MAXTIPLIMIT' => '0.00', + 'MaskedPan' => '435508***4358', + 'Email' => 'mail@customer.com', + 'Fadres' => '', + 'merchantName' => 'İşbank 3d_pay Store', + 'clientIp' => '89.244.149.137', + 'girogateParamReqHash' => 'LDlrIEcHEBZjEO7LacpO0FbuhCEcmPjtVBxiaWV7DLMnorzP6fHeNl6aQKGD1PzkYBSHIyzQLl3pvD5n3AUxhA==', + 'okUrl' => 'http://localhost/akbank/3d-host/response.php', + 'tismi' => '', + 'md' => '435508:EC7C0D35B47A5AB9CBF87E1062A6FC528B887325EAD2ED49C3E2ED3338E32006:4405:##700655000200', + 'taksit' => '', + 'Ecom_Payment_Card_ExpDate_Month' => '12', + 'tcknvkn' => '', + 'showdcchash' => 'xGahhHd5b5Fpon+TtsAUbuifmuuvq/mNTM0e/5yjvyOF1bZHjnDEoc8HQVObxkgsgJlmfUoWVy/K3uEqPk+OTg==', + 'storetype' => '3d_host', + 'querycampainghash' => 'ICWXZOhSTlmJ1Zl8CvlsInBd1/mObXeyaCAo9YVgEz1glY4638PIJQN6CrC6aR4rvgPtg9i4EQAMI5T7w/Cg/w==', + 'mdErrorMsg' => 'N-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214705021.1667121056.gc2NvdPjGQ6', + 'PAResVerified' => 'true', + 'digest' => 'digest', + 'callbackCall' => 'true', + 'failUrl' => 'http://localhost/akbank/3d-host/response.php', + 'pbirimsembol' => 'TL ', + 'xid' => 'OCQM6dAL3/ahoUbE6JlWk3vlCsU=', + 'checkisonushash' => '0pGKxQM71jDv3OEqKwcB/W7R1ZYXg6BSpGxeA5W6sc83OjX7vPeC36eCl0u4jH1CZtfICwSMflknF70O0S5ddQ==', + 'encoding' => 'ISO-8859-9', + 'currency' => '949', + 'oid' => '20221030F11F', + 'mdStatus' => '0', + 'dsId' => '1', + 'version' => '2.0', + 'Fadres2' => '', + 'Fismi' => '', + 'clientid' => '700655000200', + 'txstatus' => 'N', + 'tadres' => '', + 'HASH' => 'chQ2wvSGxQQRuzDEHcnBZkjD0fg=', + 'rnd' => '5ZUbhzQFiV+w1VedcpUs', + 'HASHPARAMS' => 'clientid:oid:mdStatus:cavv:eci:md:rnd:', + 'HASHPARAMSVAL' => '70065500020020221030F11F0435508:EC7C0D35B47A5AB9CBF87E1062A6FC528B887325EAD2ED49C3E2ED3338E32006:4405:##7006550002005ZUbhzQFiV+w1VedcpUs', + ], + 'expectedData' => [ + 'transaction_id' => null, + 'transaction_time' => null, + 'transaction_type' => 'pay', + 'transaction_security' => 'MPI fallback', + 'auth_code' => null, + 'ref_ret_num' => null, + 'batch_num' => null, + 'proc_return_code' => null, + 'status_detail' => null, + 'error_code' => null, + 'error_message' => null, + 'md_status' => '0', + 'amount' => 1.01, + 'currency' => PosInterface::CURRENCY_TRY, + 'tx_status' => null, + 'masked_number' => '4355 08** **** 4358', + 'month' => '12', + 'year' => '26', + 'eci' => null, + 'cavv' => null, + 'md_error_message' => 'N-status/Challenge authentication via ACS: https://3ds-acs.test.modirum.com/mdpayacs/creq?token=214705021.1667121056.gc2NvdPjGQ6', + 'order_id' => '20221030F11F', + 'status' => 'declined', + 'payment_model' => '3d_host', + 'installment_count' => 0, + ], + ], + ]; + } + + + public static function statusTestDataProvider(): array + { + return [ + 'success1' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 20221030FAC5', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '20221030FAC5', + 'TransId' => '22303Md4C19254', + 'Extra' => [ + 'AUTH_CODE' => 'P90325', + 'AUTH_DTTM' => '2022-10-30 12:29:53.773', + 'CAPTURE_AMT' => '', + 'CAPTURE_DTTM' => '', + 'CAVV_3D' => '', + 'CHARGE_TYPE_CD' => 'S', + 'ECI_3D' => '', + 'HOSTDATE' => '1030-122954', + 'HOST_REF_NUM' => '230300671782', + 'MDSTATUS' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS' => "ORD_ID:20221030FAC5\tCHARGE_TYPE_CD:S\tORIG_TRANS_AMT:101\tCAPTURE_AMT:\tTRANS_STAT:A\tAUTH_DTTM:2022-10-30 12:29:53.773\tCAPTURE_DTTM:\tAUTH_CODE:P90325\tTRANS_ID:22303Md4C19254", + 'ORD_ID' => '20221030FAC5', + 'ORIG_TRANS_AMT' => '101', + 'PAN' => '4355 08** **** 4358', + 'PROC_RET_CD' => '00', + 'SETTLEID' => '', + 'TRANS_ID' => '22303Md4C19254', + 'TRANS_STAT' => 'A', + 'XID_3D' => '', + ], + ], + 'expectedData' => [ + 'order_id' => '20221030FAC5', + 'auth_code' => 'P90325', + 'proc_return_code' => '00', + 'transaction_id' => '22303Md4C19254', + 'error_message' => null, + 'ref_ret_num' => '230300671782', + 'order_status' => 'PAYMENT_COMPLETED', + 'transaction_type' => 'pay', + 'masked_number' => '4355 08** **** 4358', + 'num_code' => '0', + 'first_amount' => 1.01, + 'capture_amount' => null, + 'currency' => null, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => false, + 'transaction_time' => new \DateTimeImmutable('2022-10-30 12:29:53.773'), + 'capture_time' => null, + 'cancel_time' => null, + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'fail1' => [ + 'responseData' => [ + 'ErrMsg' => 'No record found for 2022103088D22', + 'ProcReturnCode' => '99', + 'Response' => 'Declined', + 'OrderId' => '', + 'TransId' => '', + 'Extra' => [ + 'NUMCODE' => '0', + 'ORDERSTATUS' => "ORD_ID:\tCHARGE_TYPE_CD:\tORIG_TRANS_AMT:\tCAPTURE_AMT:\tTRANS_STAT:\tAUTH_DTTM:\tCAPTURE_DTTM:\tAUTH_CODE:", + ], + ], + 'expectedData' => [ + 'order_id' => null, + 'auth_code' => null, + 'proc_return_code' => '99', + 'transaction_id' => null, + 'error_message' => 'No record found for 2022103088D22', + 'ref_ret_num' => null, + 'order_status' => null, + 'transaction_type' => null, + 'masked_number' => null, + 'first_amount' => null, + 'capture_amount' => null, + 'status' => 'declined', + 'error_code' => null, + 'status_detail' => 'general_error', + 'capture' => null, + 'transaction_time' => null, + 'capture_time' => null, + 'currency' => null, + 'cancel_time' => null, + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'pay_order_status' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 2024010354F1', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '2024010354F1', + 'TransId' => '24003Vl7F13152', + 'Extra' => [ + 'AUTH_CODE' => 'P77974', + 'AUTH_DTTM' => '2024-01-03 21:37:57.259', + 'CAPTURE_AMT' => '101', + 'CAPTURE_DTTM' => '2024-01-03 21:37:57.259', + 'CAVV_3D' => '', + 'CHARGE_TYPE_CD' => 'S', + 'ECI_3D' => '', + 'HOSTDATE' => '0103-213757', + 'HOST_REF_NUM' => '400300744233', + 'MDSTATUS' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS' => "ORD_ID:2024010354F1\tCHARGE_TYPE_CD:S\tORIG_TRANS_AMT:101\tCAPTURE_AMT:101\tTRANS_STAT:C\tAUTH_DTTM:2024-01-03 21:37:57.259\tCAPTURE_DTTM:2024-01-03 21:37:57.259\tAUTH_CODE:P77974\tTRANS_ID:24003Vl7F13152", + 'ORD_ID' => '2024010354F1', + 'ORIG_TRANS_AMT' => '101', + 'PAN' => '4546 71** **** 7894', + 'PROC_RET_CD' => '00', + 'SETTLEID' => '', + 'TRANS_ID' => '24003Vl7F13152', + 'TRANS_STAT' => 'C', + 'XID_3D' => '', + ], + ], + 'expectedData' => [ + 'auth_code' => 'P77974', + 'capture' => true, + 'capture_amount' => 1.01, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 1.01, + 'masked_number' => '4546 71** **** 7894', + 'num_code' => '0', + 'order_id' => '2024010354F1', + 'order_status' => 'PAYMENT_COMPLETED', + 'proc_return_code' => '00', + 'ref_ret_num' => '400300744233', + 'status' => 'approved', + 'status_detail' => 'approved', + 'transaction_time' => new \DateTimeImmutable('2024-01-03 21:37:57.259'), + 'capture_time' => new \DateTimeImmutable('2024-01-03 21:37:57.259'), + 'transaction_id' => '24003Vl7F13152', + 'transaction_type' => 'pay', + 'cancel_time' => null, + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'pre_pay_order_status' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 202401032AF3', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '202401032AF3', + 'TransId' => '24003VqkA14152', + 'Extra' => [ + 'AUTH_CODE' => 'T87380', + 'AUTH_DTTM' => '2024-01-03 21:42:35.902', + 'CAPTURE_AMT' => '', + 'CAPTURE_DTTM' => '', + 'CAVV_3D' => '', + 'CHARGE_TYPE_CD' => 'S', + 'ECI_3D' => '', + 'HOSTDATE' => '0103-214236', + 'HOST_REF_NUM' => '400300744234', + 'MDSTATUS' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS' => 'ORD_ID:202401032AF3 CHARGE_TYPE_CD:S ORIG_TRANS_AMT:205 CAPTURE_AMT: TRANS_STAT:A AUTH_DTTM:2024-01-03 21:42:35.902 CAPTURE_DTTM: AUTH_CODE:T87380 TRANS_ID:24003VqkA14152', + 'ORD_ID' => '202401032AF3', + 'ORIG_TRANS_AMT' => '205', + 'PAN' => '4546 71** **** 7894', + 'PROC_RET_CD' => '00', + 'SETTLEID' => '', + 'TRANS_ID' => '24003VqkA14152', + 'TRANS_STAT' => 'A', + 'XID_3D' => '', + ], + ], + 'expectedData' => [ + 'auth_code' => 'T87380', + 'capture' => false, + 'capture_amount' => null, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 2.05, + 'masked_number' => '4546 71** **** 7894', + 'num_code' => '0', + 'order_id' => '202401032AF3', + 'order_status' => 'PAYMENT_COMPLETED', + 'proc_return_code' => '00', + 'ref_ret_num' => '400300744234', + 'status' => 'approved', + 'status_detail' => 'approved', + 'transaction_time' => new \DateTimeImmutable('2024-01-03 21:42:35.902'), + 'capture_time' => null, + 'transaction_id' => '24003VqkA14152', + 'transaction_type' => 'pay', + 'cancel_time' => null, + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'canceled_order_status' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 20240103BBF9', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '20240103BBF9', + 'TransId' => '24003VxrB15662', + 'Extra' => [ + 'AUTH_CODE' => 'P42795', + 'AUTH_DTTM' => '2024-01-03 21:49:42.929', + 'CAPTURE_AMT' => '101', + 'CAPTURE_DTTM' => '2024-01-03 21:49:42.929', + 'CAVV_3D' => '', + 'CHARGE_TYPE_CD' => 'S', + 'ECI_3D' => '', + 'HOSTDATE' => '0103-214944', + 'HOST_REF_NUM' => '400300744237', + 'MDSTATUS' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS' => "ORD_ID:20240103BBF9\tCHARGE_TYPE_CD:S\tORIG_TRANS_AMT:101\tCAPTURE_AMT:101\tTRANS_STAT:V\tAUTH_DTTM:2024-01-03 21:49:42.929\tCAPTURE_DTTM:2024-01-03 21:49:42.929\tAUTH_CODE:P42795\tTRANS_ID:24003VxrB15662", + 'ORD_ID' => '20240103BBF9', + 'ORIG_TRANS_AMT' => '101', + 'PAN' => '4546 71** **** 7894', + 'PROC_RET_CD' => '00', + 'SETTLEID' => '', + 'TRANS_ID' => '24003VxrB15662', + 'TRANS_STAT' => 'V', + 'VOID_DTTM' => '2024-01-03 21:49:44.301', + 'XID_3D' => '', + ], + ], + 'expectedData' => [ + 'auth_code' => 'P42795', + 'capture' => true, + 'capture_amount' => 1.01, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 1.01, + 'masked_number' => '4546 71** **** 7894', + 'num_code' => '0', + 'order_id' => '20240103BBF9', + 'order_status' => 'CANCELED', + 'proc_return_code' => '00', + 'ref_ret_num' => '400300744237', + 'status' => 'approved', + 'status_detail' => 'approved', + 'transaction_time' => new \DateTimeImmutable('2024-01-03 21:49:42.929'), + 'capture_time' => new \DateTimeImmutable('2024-01-03 21:49:42.929'), + 'transaction_id' => '24003VxrB15662', + 'transaction_type' => 'pay', + 'cancel_time' => new \DateTimeImmutable('2024-01-03 21:49:44.301'), + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'refund_order_status' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 20240128C0B7', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '20240128C0B7', + 'TransId' => '24028T8xG11980', + 'Extra' => [ + 'AUTH_CODE' => 'P93736', + 'AUTH_DTTM' => '2024-01-28 19:58:49.382', + 'CAPTURE_AMT' => '201', + 'CAPTURE_DTTM' => '2024-01-28 19:58:49.382', + 'CAVV_3D' => '', + 'CHARGE_TYPE_CD' => 'C', + 'ECI_3D' => '', + 'HOSTDATE' => '0128-195850', + 'HOST_REF_NUM' => '402800747548', + 'MDSTATUS' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS' => 'ORD_ID:20240128C0B7 CHARGE_TYPE_CD:C ORIG_TRANS_AMT:201 CAPTURE_AMT:201 TRANS_STAT:C AUTH_DTTM:2024-01-28 19:58:49.382 CAPTURE_DTTM:2024-01-28 19:58:49.382 AUTH_CODE:P93736 TRANS_ID:24028T8xG11980', + 'ORD_ID' => '20240128C0B7', + 'ORIG_TRANS_AMT' => '201', + 'PAN' => '4546 71** **** 7894', + 'PROC_RET_CD' => '00', + 'SETTLEID' => '', + 'TRANS_ID' => '24028T8xG11980', + 'TRANS_STAT' => 'C', + 'XID_3D' => '', + ], + ], + 'expectedData' => [ + 'auth_code' => 'P93736', + 'capture' => true, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 2.01, + 'capture_amount' => 2.01, + 'masked_number' => '4546 71** **** 7894', + 'num_code' => '0', + 'order_id' => '20240128C0B7', + 'order_status' => 'PAYMENT_COMPLETED', + 'proc_return_code' => '00', + 'ref_ret_num' => '402800747548', + 'status' => 'approved', + 'status_detail' => 'approved', + 'transaction_time' => new \DateTimeImmutable('2024-01-28 19:58:49.382'), + 'capture_time' => new \DateTimeImmutable('2024-01-28 19:58:49.382'), + 'transaction_id' => '24028T8xG11980', + 'transaction_type' => 'refund', + 'cancel_time' => null, + 'refund_amount' => null, + 'refund_time' => null, + 'installment_count' => null, + ], + ], + 'recurring_order_status' => [ + 'responseData' => [ + 'ErrMsg' => 'Record(s) found for 22303O8EA19252', + 'Extra' => [ + 'AUTH_CODE_1' => 'P34325', + 'AUTH_DTTM_1' => '2022-10-30 14:58:03.449', + 'CAPTURE_AMT_1' => '101', + 'CAPTURE_DTTM_1' => '2022-10-30 14:58:03.449', + 'CAVV_3D_1' => '', + 'CHARGE_TYPE_CD_1' => 'S', + 'CHARGE_TYPE_CD_2' => 'S', + 'ECI_3D_1' => '', + 'HOSTDATE_1' => '1030-145804', + 'HOST_REF_NUM_1' => '230300671790', + 'MDSTATUS_1' => '', + 'NUMCODE' => '0', + 'ORDERSTATUS_1' => "ORD_ID:2022103097CD\tCHARGE_TYPE_CD:S\tORIG_TRANS_AMT:101\tCAPTURE_AMT:101\tTRANS_STAT:C\tAUTH_DTTM:2022-10-30 14:58:03.449\tCAPTURE_DTTM:2022-10-30 14:58:03.449\tAUTH_CODE:P34325\tTRANS_ID:22303O8EB19253", + 'ORDERSTATUS_2' => "ORD_ID:2022103097CD-2\tCHARGE_TYPE_CD:S\tORIG_TRANS_AMT:101\tTRANS_STAT:PN\tPLANNED_START_DTTM:2023-01-30 14:58:03.449", + 'ORD_ID_1' => '2022103097CD', + 'ORD_ID_2' => '2022103097CD-2', + 'ORIG_TRANS_AMT_1' => '101', + 'ORIG_TRANS_AMT_2' => '101', + 'PAN_1' => '4355 08** **** 4358', + 'PAN_2' => '4355 08** **** 4358', + 'PLANNED_START_DTTM_2' => '2023-01-30 14:58:03.449', + 'PROC_RET_CD_1' => '00', + 'RECURRINGCOUNT' => '2', + 'RECURRINGID' => '22303O8EA19252', + 'SETTLEID_1' => '', + 'TRANS_ID_1' => '22303O8EB19253', + 'TRANS_STAT_1' => 'C', + 'TRANS_STAT_2' => 'PN', + 'XID_3D_1' => '', + ], + ], + 'expectedData' => [ + 'recurringId' => '22303O8EA19252', + 'recurringInstallmentCount' => '2', + 'status' => 'approved', + 'num_code' => '0', + 'error_message' => null, + 'recurringOrders' => [ + [ + 'auth_code' => 'P34325', + 'capture' => true, + 'capture_amount' => 1.01, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 1.01, + 'masked_number' => '4355 08** **** 4358', + 'order_id' => '2022103097CD', + 'order_status' => 'PAYMENT_COMPLETED', + 'proc_return_code' => '00', + 'ref_ret_num' => '230300671790', + 'status' => 'approved', + 'status_detail' => 'approved', + 'transaction_time' => new \DateTimeImmutable('2022-10-30 14:58:03.449'), + 'capture_time' => new \DateTimeImmutable('2022-10-30 14:58:03.449'), + 'transaction_id' => '22303O8EB19253', + 'transaction_type' => 'pay', + ], + [ + 'auth_code' => null, + 'capture' => false, + 'capture_amount' => null, + 'currency' => null, + 'error_code' => null, + 'error_message' => null, + 'first_amount' => 1.01, + 'masked_number' => '4355 08** **** 4358', + 'order_id' => '2022103097CD-2', + 'order_status' => 'PAYMENT_PENDING', + 'proc_return_code' => null, + 'ref_ret_num' => null, + 'status' => 'declined', + 'status_detail' => null, + 'transaction_id' => null, + 'transaction_time' => null, + 'capture_time' => null, + 'transaction_type' => 'pay', + ], + ], + ], + ], + ]; + } + + public static function cancelTestDataProvider(): array + { + return + [ + 'success1' => [ + 'responseData' => [ + 'OrderId' => '20221030B3FF', + 'GroupId' => '20221030B3FF', + 'Response' => 'Approved', + 'AuthCode' => 'P43467', + 'HostRefNum' => '230300671786', + 'ProcReturnCode' => '00', + 'TransId' => '22303MzZG10851', + 'ErrMsg' => '', + 'Extra' => [ + 'SETTLEID' => '2287', + 'TRXDATE' => '20221030 12:51:25', + 'ERRORCODE' => '', + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'CARDBRAND' => 'VISA', + 'CARDISSUER' => 'AKBANK T.A.S.', + 'HOSTDATE' => '1030-125130', + 'NUMCODE' => '00', + ], + ], + 'expectedData' => [ + 'order_id' => '20221030B3FF', + 'group_id' => '20221030B3FF', + 'auth_code' => 'P43467', + 'ref_ret_num' => '230300671786', + 'proc_return_code' => '00', + 'transaction_id' => '22303MzZG10851', + 'error_code' => null, + 'num_code' => '00', + 'error_message' => null, + 'status' => 'approved', + 'status_detail' => 'approved', + ], + ], + 'success_without_extra_error_code' => [ + 'responseData' => [ + 'OrderId' => '230', + 'GroupId' => '800', + 'Response' => 'Approved', + 'AuthCode' => '160769', + 'HostRefNum' => '48', + 'ProcReturnCode' => '00', + 'TransId' => '2836', + 'ErrMsg' => '', + 'ERRORCODE' => '', + 'Extra' => [ + 'KULLANILANPUAN' => '000000000000', + 'CARDBRAND' => 'VISA', + 'TRXDATE' => '2017 13:14:06', + 'KULLANILABILIRPUAN' => '000000000380', + 'ACQSTAN' => '769388', + 'KAZANILANPUAN' => '000000000229', + 'TRACEID' => '4d68eab86e6', + 'NUMCODE' => '00', + 'SETTLEID' => '87', + ], + ], + 'expectedData' => [ + 'order_id' => '230', + 'group_id' => '800', + 'auth_code' => '160769', + 'ref_ret_num' => '48', + 'proc_return_code' => '00', + 'transaction_id' => '2836', + 'error_code' => null, + 'num_code' => '00', + 'error_message' => null, + 'status' => 'approved', + 'status_detail' => 'approved', + ], + ], + 'fail_order_not_found_1' => [ + 'responseData' => [ + 'OrderId' => '', + 'GroupId' => '', + 'Response' => 'Error', + 'AuthCode' => '', + 'HostRefNum' => '', + 'ProcReturnCode' => '99', + 'TransId' => '22303M5IA11121', + 'ErrMsg' => 'İptal edilmeye uygun satış işlemi bulunamadı.', + 'Extra' => [ + 'SETTLEID' => '', + 'TRXDATE' => '20221030 12:55:08', + 'ERRORCODE' => 'CORE-2008', + 'NUMCODE' => '992008', + ], + ], + 'expectedData' => [ + 'order_id' => null, + 'group_id' => null, + 'auth_code' => null, + 'ref_ret_num' => null, + 'proc_return_code' => '99', + 'transaction_id' => '22303M5IA11121', + 'error_code' => 'CORE-2008', + 'num_code' => null, + 'error_message' => 'İptal edilmeye uygun satış işlemi bulunamadı.', + 'status' => 'declined', + 'status_detail' => 'general_error', + ], + ], + 'fail_order_not_found_2' => [ + 'responseData' => [ + 'OrderId' => 'a1a7d184', + 'GroupId' => 'a1a7d184', + 'Response' => 'Declined', + 'HostRefNum' => '413719757716', + 'ProcReturnCode' => '99', + 'TransId' => '', + 'ErrMsg' => 'İptal edilmeye uygun satış işlemi bulunamadı.', + 'Extra' => [ + 'TRXDATE' => '20240516 22:56:09', + 'EXTENDED_ERROR_CODE' => '215001', + 'TRACEID' => '3f423f86e9d886bf1cffae49d93268be', + 'NUMCODE' => '99', + 'ERRORCODE' => 'CORE-2008', + ], + ], + 'expectedData' => [ + 'order_id' => 'a1a7d184', + 'group_id' => null, + 'auth_code' => null, + 'ref_ret_num' => '413719757716', + 'proc_return_code' => '99', + 'transaction_id' => null, + 'error_code' => 'CORE-2008', + 'num_code' => null, + 'error_message' => 'İptal edilmeye uygun satış işlemi bulunamadı.', + 'status' => 'declined', + 'status_detail' => 'general_error', + ], + ], + 'success_recurring_1' => [ + 'responseData' => [ + 'RECURRINGOPERATION' => 'CANCEL', + 'RECORDTYPE' => 'ORDER', + 'RECORDID' => '2022103072C1-2', + 'RESULT' => 'Successfull', + 'Extra' => '', + ], + 'expectedData' => [ + 'order_id' => '2022103072C1-2', + 'status' => 'approved', + ], + ], + ]; + } + + public static function refundTestDataProvider(): array + { + return [ + 'success1' => [ + 'responseData' => [ + 'OrderId' => 'df0e', + 'GroupId' => 'dfc36f0e', + 'Response' => 'Approved', + 'AuthCode' => '46', + 'HostRefNum' => '41', + 'ProcReturnCode' => '00', + 'TransId' => '24138', + 'ErrMsg' => '', + 'ERRORCODE' => '', + 'Extra' => [ + 'KULLANILANPUAN' => '000000000000', + 'CARDBRAND' => 'MASTERCARD', + 'CARDHOLDERNAME' => 'ME* DE*', + 'TRXDATE' => '20240517 13:30:43', + 'KULLANILABILIRPUAN' => '000000005450', + 'ACQSTAN' => '74', + 'KAZANILANPUAN' => '000000000000', + 'TRACEID' => 'e7ba2a6', + 'NUMCODE' => '00', + 'SETTLEID' => '', + ], + ], + 'expectedData' => [ + 'order_id' => 'df0e', + 'group_id' => 'dfc36f0e', + 'auth_code' => '46', + 'ref_ret_num' => '41', + 'proc_return_code' => '00', + 'transaction_id' => '24138', + 'num_code' => '00', + 'error_code' => null, + 'error_message' => null, + 'status' => 'approved', + 'status_detail' => 'approved', + ], + ], + 'fail1' => [ + 'responseData' => [ + 'OrderId' => '20221030B3FF', + 'GroupId' => '20221030B3FF', + 'Response' => 'Error', + 'AuthCode' => '', + 'HostRefNum' => '', + 'ProcReturnCode' => '99', + 'TransId' => '22303M8rC11328', + 'ErrMsg' => 'Iade yapilamaz, siparis gunsonuna girmemis.', + 'Extra' => [ + 'SETTLEID' => '', + 'TRXDATE' => '20221030 12:58:42', + 'ERRORCODE' => 'CORE-2508', + 'NUMCODE' => '992508', + ], + ], + 'expectedData' => [ + 'order_id' => '20221030B3FF', + 'group_id' => null, + 'auth_code' => null, + 'ref_ret_num' => null, + 'proc_return_code' => '99', + 'transaction_id' => '22303M8rC11328', + 'num_code' => null, + 'error_code' => 'CORE-2508', + 'error_message' => 'Iade yapilamaz, siparis gunsonuna girmemis.', + 'status' => 'declined', + 'status_detail' => 'general_error', + ], + ], + 'fail2' => [ + 'responseData' => [ + 'OrderId' => '2c544d', + 'Response' => 'Declined', + 'HostRefNum' => '413051', + 'TransId' => '24082', + 'ErrMsg' => 'Net Tutar 0.', + 'Extra' => [ + 'TRXDATE' => '20240517 14:28:33', + 'TRACEID' => '73631448ab0c1e', + 'ERRORCODE' => '215021', + ], + ], + 'expectedData' => [ + 'order_id' => '2c544d', + 'group_id' => null, + 'auth_code' => null, + 'ref_ret_num' => '413051', + 'proc_return_code' => null, + 'transaction_id' => '24082', + 'num_code' => null, + 'error_code' => '215021', + 'error_message' => 'Net Tutar 0.', + 'status' => 'declined', + 'status_detail' => null, + ], + ], + ]; + } + + public static function orderHistoryTestDataProvider(): array + { + return [ + 'success_cancel_success_refund_fail' => [ + 'responseData' => [ + 'ErrMsg' => '', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '20240102D8F1', + 'Extra' => [ + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'NUMCODE' => '0', + 'TRX1' => "C\tD\t100\t100\t2024-01-02 21:53:02.486\t2024-01-02 21:53:02.486\t\t\t\t99\t24002V3CG19993", + 'TRX2' => "S\tV\t101\t101\t2024-01-02 21:52:59.261\t2024-01-02 21:52:59.261\t2024-01-02 21:53:01.297\t400200744059\tP78955\t00\t24002V29G19979", + 'TRXCOUNT' => '2', + ], + ], + 'expectedData' => [ + 'order_id' => '20240102D8F1', + 'proc_return_code' => '00', + 'error_message' => null, + 'num_code' => '0', + 'trans_count' => 2, + 'transactions' => [ + [ + 'auth_code' => 'P78955', + 'proc_return_code' => '00', + 'transaction_id' => '24002V29G19979', + 'error_message' => null, + 'ref_ret_num' => '400200744059', + 'order_status' => 'CANCELED', + 'transaction_type' => 'pay', + 'first_amount' => 1.01, + 'capture_amount' => 1.01, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => true, + 'currency' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-02 21:52:59.261'), + 'capture_time' => null, + 'masked_number' => null, + ], + [ + 'auth_code' => null, + 'proc_return_code' => '99', + 'transaction_id' => '24002V3CG19993', + 'error_message' => null, + 'ref_ret_num' => null, + 'order_status' => 'ERROR', + 'transaction_type' => 'refund', + 'first_amount' => 1.0, + 'capture_amount' => 1.0, + 'status' => 'declined', + 'error_code' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-02 21:53:02.486'), + 'capture_time' => null, + 'masked_number' => null, + 'status_detail' => 'general_error', + 'capture' => false, + 'currency' => null, + ], + ], + 'status' => 'approved', + 'status_detail' => 'approved', + ], + ], + 'success_payment_then_cancel_tx' => [ + 'responseData' => [ + 'ErrMsg' => '', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '202401029F10', + 'Extra' => [ + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'NUMCODE' => '0', + 'TRX1' => "S\tV\t101\t101\t2024-01-02 21:47:28.785\t2024-01-02 21:47:28.785\t2024-01-02 21:47:40.156\t400200744054\tP77381\t00\t24002VvdA19109", + 'TRXCOUNT' => '1', + ], + ], + 'expectedData' => [ + 'error_message' => null, + 'num_code' => '0', + 'order_id' => '202401029F10', + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'trans_count' => 1, + 'transactions' => [ + [ + 'auth_code' => 'P77381', + 'proc_return_code' => '00', + 'transaction_id' => '24002VvdA19109', + 'error_message' => null, + 'ref_ret_num' => '400200744054', + 'order_status' => 'CANCELED', + 'transaction_type' => 'pay', + 'first_amount' => 1.01, + 'capture_amount' => 1.01, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => true, + 'currency' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-02 21:47:28.785'), + 'capture_time' => null, + 'masked_number' => null, + ], + ], + ], + ], + 'success_one_payment_tx' => [ + 'responseData' => [ + 'ErrMsg' => '', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '202401010C20', + 'Extra' => [ + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'NUMCODE' => '0', + 'TRX1' => "S\tC\t101\t101\t2024-01-01 22:15:27.511\t2024-01-01 22:15:27.511\t\t400100743898\tP14578\t00\t24001WPbH16694", + 'TRXCOUNT' => '1', + ], + ], + 'expectedData' => [ + 'error_message' => null, + 'num_code' => '0', + 'order_id' => '202401010C20', + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'trans_count' => 1, + 'transactions' => [ + [ + 'auth_code' => 'P14578', + 'proc_return_code' => '00', + 'transaction_id' => '24001WPbH16694', + 'error_message' => null, + 'ref_ret_num' => '400100743898', + 'order_status' => 'PAYMENT_COMPLETED', + 'transaction_type' => 'pay', + 'first_amount' => 1.01, + 'capture_amount' => 1.01, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => true, + 'currency' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-01 22:15:27.511'), + 'capture_time' => null, + 'masked_number' => null, + ], + ], + ], + ], + 'success_one_pre_auth_tx' => [ + 'responseData' => [ + 'ErrMsg' => '', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '20240101CCCF', + 'Extra' => [ + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'NUMCODE' => '0', + 'TRX1' => "S\tA\t205\t\t2024-01-01 22:28:30.716\t\t\t400100743899\tT56045\t00\t24001WceJ18839", + 'TRXCOUNT' => '1', + ], + ], + 'expectedData' => [ + 'error_message' => null, + 'num_code' => '0', + 'order_id' => '20240101CCCF', + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'trans_count' => 1, + 'transactions' => [ + [ + 'auth_code' => 'T56045', + 'proc_return_code' => '00', + 'transaction_id' => '24001WceJ18839', + 'error_message' => null, + 'ref_ret_num' => '400100743899', + 'order_status' => 'PAYMENT_COMPLETED', + 'transaction_type' => 'pay', + 'first_amount' => 2.05, + 'capture_amount' => null, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => false, + 'currency' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-01 22:28:30.716'), + 'capture_time' => null, + 'masked_number' => null, + ], + ], + ], + ], + 'success_pre_auth_and_post_tx' => [ + 'responseData' => [ + 'ErrMsg' => '', + 'ProcReturnCode' => '00', + 'Response' => 'Approved', + 'OrderId' => '202401014456', + 'Extra' => [ + 'TERMINALID' => '00655020', + 'MERCHANTID' => '655000200', + 'NUMCODE' => '0', + 'TRX1' => "S\tC\t200\t200\t2024-01-01 22:37:53.396\t2024-01-01 22:37:53.396\t\t400100743901\tT14446\t00\t24001Wl3G10348", + 'TRXCOUNT' => '1', + ], + ], + 'expectedData' => [ + 'error_message' => null, + 'num_code' => '0', + 'order_id' => '202401014456', + 'proc_return_code' => '00', + 'status' => 'approved', + 'status_detail' => 'approved', + 'trans_count' => 1, + 'transactions' => [ + [ + 'auth_code' => 'T14446', + 'proc_return_code' => '00', + 'transaction_id' => '24001Wl3G10348', + 'error_message' => null, + 'ref_ret_num' => '400100743901', + 'order_status' => 'PAYMENT_COMPLETED', + 'transaction_type' => 'pay', + 'first_amount' => 2.0, + 'capture_amount' => 2.0, + 'status' => 'approved', + 'error_code' => null, + 'status_detail' => 'approved', + 'capture' => true, + 'currency' => null, + 'transaction_time' => new \DateTimeImmutable('2024-01-01 22:37:53.396'), + 'capture_time' => null, + 'masked_number' => null, + ], + ], + ], + ], + 'fail1' => [ + 'responseData' => [ + 'ErrMsg' => 'No record found for 20221030B3FF2', + 'ProcReturnCode' => '05', + 'Response' => 'Declined', + 'OrderId' => '20221030B3FF2', + 'Extra' => [ + 'NUMCODE' => '0', + 'TRXCOUNT' => '0', + ], + ], + 'expectedData' => [ + 'order_id' => '20221030B3FF2', + 'proc_return_code' => '05', + 'error_message' => 'No record found for 20221030B3FF2', + 'num_code' => '0', + 'trans_count' => 0, + 'transactions' => [], + 'status' => 'declined', + 'status_detail' => 'reject', + ], + ], + ]; + } +} diff --git a/tests/Unit/Gateways/ParamPosTest.php b/tests/Unit/Gateways/ParamPosTest.php new file mode 100644 index 00000000..1243c494 --- /dev/null +++ b/tests/Unit/Gateways/ParamPosTest.php @@ -0,0 +1,956 @@ +config = [ + 'name' => 'param-pos', + 'class' => ParamPos::class, + 'gateway_endpoints' => [ + 'payment_api' => 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', + ], + ]; + + $this->account = AccountFactory::createParamPosAccount( + 'param-pos', + 10738, + 'Test', + 'Test', + '0c13d406-873b-403b-9c09-a5766840d98c' + ); + + $this->requestMapperMock = $this->createMock(ParamPosRequestDataMapper::class); + $this->responseMapperMock = $this->createMock(ResponseDataMapperInterface::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 ParamPos( + $this->config, + $this->account, + $this->requestMapperMock, + $this->responseMapperMock, + $this->serializerMock, + $this->eventDispatcherMock, + $this->httpClientMock, + $this->loggerMock, + ); + + $this->pos->setTestMode(true); + + $this->card = CreditCardFactory::createForGateway( + $this->pos, + '5555444433332222', + '21', + '12', + '122', + 'ahmet', + CreditCardInterface::CARD_TYPE_VISA + ); + } + + /** + * @return void + */ + public function testInit(): void + { + $this->requestMapperMock->expects(self::once()) + ->method('getCurrencyMappings') + ->willReturn([PosInterface::CURRENCY_TRY => '949']); + $this->assertSame($this->config, $this->pos->getConfig()); + $this->assertSame($this->account, $this->pos->getAccount()); + $this->assertSame([PosInterface::CURRENCY_TRY], $this->pos->getCurrencies()); + $this->assertSame($this->config['gateway_endpoints']['gateway_3d_host'], $this->pos->get3DGatewayURL(PosInterface::MODEL_3D_HOST)); + $this->assertSame($this->config['gateway_endpoints']['gateway_3d'], $this->pos->get3DGatewayURL()); + $this->assertSame($this->config['gateway_endpoints']['payment_api'], $this->pos->getApiURL()); + } + + /** + * @return void + */ + public function testSetTestMode(): void + { + $this->pos->setTestMode(false); + $this->assertFalse($this->pos->isTestMode()); + $this->pos->setTestMode(true); + $this->assertTrue($this->pos->isTestMode()); + } + + /** + * @dataProvider threeDFormDataProvider + */ + public function testGet3DFormData( + array $order, + string $paymentModel, + string $txType, + bool $isWithCard, + array $requestData, + string $encodedRequestData, + string $responseData, + array $decodedResponseData, + string $formData + ): void { + + $card = $isWithCard ? $this->card : null; + $this->requestMapperMock->expects(self::once()) + ->method('create3DEnrollmentCheckRequestData') + ->with($this->pos->getAccount(), $order) + ->willReturn($requestData); + + $this->configureClientResponse( + $txType, + 'TP_WMD_UCD', + 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', + $requestData, + $encodedRequestData, + $responseData, + $decodedResponseData, + $order, + $paymentModel + ); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $actual = $this->pos->get3DFormData($order, $paymentModel, $txType, $card); + + $this->assertSame($actual, $formData); + } + + /** + * @dataProvider threeDFormDataFailResponseProvider + */ + public function testGet3DFormDataFailResponse( + array $order, + string $paymentModel, + string $txType, + bool $isWithCard, + array $requestData, + string $encodedRequestData, + string $responseData, + array $decodedResponseData, + string $formData + ): void { + $card = $isWithCard ? $this->card : null; + $this->requestMapperMock->expects(self::once()) + ->method('create3DEnrollmentCheckRequestData') + ->with($this->pos->getAccount(), $order) + ->willReturn($requestData); + + $this->configureClientResponse( + $txType, + 'TP_WMD_UCD', + 'https://test-dmz.param.com.tr/turkpos.ws/service_turkpos_test.asmx', + $requestData, + $encodedRequestData, + $responseData, + $decodedResponseData, + $order, + $paymentModel + ); + + $this->requestMapperMock->expects(self::never()) + ->method('create3DFormData'); + + $actual = $this->pos->get3DFormData($order, $paymentModel, $txType, $card); + + $this->assertSame($actual, $formData); + } + + /** + * @dataProvider threeDFormDataBadInputsProvider + */ + public function testGet3DFormDataWithBadInputs( + array $order, + string $paymentModel, + string $txType, + bool $isWithCard, + bool $createWithoutCard, + string $expectedExceptionClass + ): void { + $card = $isWithCard ? $this->card : null; + + $this->expectException($expectedExceptionClass); + + $this->pos->get3DFormData($order, $paymentModel, $txType, $card, $createWithoutCard); + } + + /** + * @dataProvider make3DPaymentDataProvider + */ + public function testMake3DPayment( + array $order, + string $txType, + Request $request, + array $paymentResponse, + array $expectedResponse, + bool $is3DSuccess, + bool $isSuccess + ): void { + if ($is3DSuccess) { + $this->cryptMock->expects(self::once()) + ->method('check3DHash') + ->with($this->account, $request->request->all()) + ->willReturn(true); + } + + $this->responseMapperMock->expects(self::once()) + ->method('extractMdStatus') + ->with($request->request->all()) + ->willReturn('3d-status'); + + $this->responseMapperMock->expects(self::once()) + ->method('is3dAuthSuccess') + ->with('3d-status') + ->willReturn($is3DSuccess); + + + $create3DPaymentRequestData = [ + 'create3DPaymentRequestData', + ]; + + if ($is3DSuccess) { + $this->requestMapperMock->expects(self::once()) + ->method('create3DPaymentRequestData') + ->with($this->account, $order, $txType, $request->request->all()) + ->willReturn($create3DPaymentRequestData); + + $this->configureClientResponse( + $txType, + $this->config['gateway_endpoints']['payment_api'], + $create3DPaymentRequestData, + 'request-body', + 'response-body', + $paymentResponse, + $order, + PosInterface::MODEL_3D_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('map3DPaymentData') + ->with($request->request->all(), $paymentResponse, $txType, $order) + ->willReturn($expectedResponse); + } else { + $this->responseMapperMock->expects(self::once()) + ->method('map3DPaymentData') + ->with($request->request->all(), null, $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->eventDispatcherMock->expects(self::never()) + ->method('dispatch'); + } + + $this->pos->make3DPayment($request, $order, $txType); + + $result = $this->pos->getResponse(); + $this->assertSame($expectedResponse, $result); + $this->assertSame($isSuccess, $this->pos->isSuccess()); + } + + public function testMake3DPaymentHashMismatchException(): void + { + $data = ParamPosResponseDataMapperTest::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 + */ + public function testMake3DPayPayment(): void + { + $this->cryptMock->expects(self::never()) + ->method('check3DHash'); + + $responseData = ['$responseData']; + $request = Request::create('', 'POST', $responseData); + $order = ['id' => '123']; + $txType = PosInterface::TX_TYPE_PAY_AUTH; + + $this->responseMapperMock->expects(self::once()) + ->method('map3DPayResponseData') + ->with($request->request->all(), $txType, $order) + ->willReturn(['status' => 'approved']); + + $pos = $this->pos; + + $pos->make3DPayPayment($request, $order, $txType); + + $result = $pos->getResponse(); + $this->assertSame(['status' => 'approved'], $result); + $this->assertTrue($pos->isSuccess()); + } + + /** + * @return void + */ + public function testMake3DHostPayment(): void + { + $this->cryptMock->expects(self::never()) + ->method('check3DHash'); + + $responseData = ['$responseData']; + $request = Request::create('', 'POST', $responseData); + $order = ['id' => '123']; + $txType = PosInterface::TX_TYPE_PAY_AUTH; + + $this->responseMapperMock->expects(self::once()) + ->method('map3DHostResponseData') + ->with($request->request->all(), $txType, $order) + ->willReturn(['status' => 'approved']); + + $pos = $this->pos; + + $pos->make3DHostPayment($request, $order, $txType); + + $result = $pos->getResponse(); + $this->assertSame(['status' => 'approved'], $result); + $this->assertTrue($pos->isSuccess()); + } + + /** + * @dataProvider makeRegularPaymentDataProvider + */ + public function testMakeRegularPayment(array $order, string $txType, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $card = $this->card; + $requestData = ['createNonSecurePaymentRequestData']; + $this->requestMapperMock->expects(self::once()) + ->method('createNonSecurePaymentRequestData') + ->with($account, $order, $txType, $card) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapPaymentResponse') + ->with($decodedResponse, $txType, $order) + ->willReturn(['result']); + + $this->pos->makeRegularPayment($order, $card, $txType); + } + + /** + * @dataProvider makeRegularPostAuthPaymentDataProvider + */ + public function testMakeRegularPostAuthPayment(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_PAY_POST_AUTH; + $requestData = ['createNonSecurePostAuthPaymentRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createNonSecurePostAuthPaymentRequestData') + ->with($account, $order) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapPaymentResponse') + ->with($decodedResponse, $txType, $order) + ->willReturn(['result']); + + $this->pos->makeRegularPostPayment($order); + } + + + /** + * @dataProvider statusRequestDataProvider + */ + public function testStatusRequest(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_STATUS; + $requestData = ['createStatusRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createStatusRequestData') + ->with($account, $order) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapStatusResponse') + ->with($decodedResponse) + ->willReturn(['result']); + + $this->pos->status($order); + } + + /** + * @dataProvider cancelRequestDataProvider + */ + public function testCancelRequest(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_CANCEL; + $requestData = ['createCancelRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createCancelRequestData') + ->with($account, $order) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapCancelResponse') + ->with($decodedResponse) + ->willReturn(['result']); + + $this->pos->cancel($order); + } + + /** + * @dataProvider refundRequestDataProvider + */ + public function testRefundRequest(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_REFUND; + $requestData = ['createRefundRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createRefundRequestData') + ->with($account, $order, $txType) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapRefundResponse') + ->with($decodedResponse) + ->willReturn(['result']); + + $this->pos->refund($order); + } + + /** + * @dataProvider historyRequestDataProvider + */ + public function testHistoryRequest(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_HISTORY; + $requestData = ['createHistoryRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createHistoryRequestData') + ->with($account, $order) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapHistoryResponse') + ->with($decodedResponse) + ->willReturn(['result']); + + $this->pos->history($order); + } + + /** + * @dataProvider orderHistoryRequestDataProvider + */ + public function testOrderHistoryRequest(array $order, string $apiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_ORDER_HISTORY; + $requestData = ['createOrderHistoryRequestData']; + + $this->requestMapperMock->expects(self::once()) + ->method('createOrderHistoryRequestData') + ->with($account, $order) + ->willReturn($requestData); + + $decodedResponse = ['decodedData']; + $this->configureClientResponse( + $txType, + $apiUrl, + $requestData, + 'request-body', + 'response-body', + $decodedResponse, + $order, + PosInterface::MODEL_NON_SECURE + ); + + $this->responseMapperMock->expects(self::once()) + ->method('mapOrderHistoryResponse') + ->with($decodedResponse) + ->willReturn(['result']); + + $this->pos->orderHistory($order); + } + + /** + * @dataProvider customQueryRequestDataProvider + */ + public function testCustomQueryRequest(array $requestData, ?string $apiUrl, string $expectedApiUrl): void + { + $account = $this->pos->getAccount(); + $txType = PosInterface::TX_TYPE_CUSTOM_QUERY; + + $updatedRequestData = $requestData + [ + 'abc' => 'def', + ]; + $this->requestMapperMock->expects(self::once()) + ->method('createCustomQueryRequestData') + ->with($account, $requestData) + ->willReturn($updatedRequestData); + + $this->configureClientResponse( + $txType, + $expectedApiUrl, + $updatedRequestData, + 'request-body', + 'response-body', + ['decodedResponse'], + $requestData, + PosInterface::MODEL_NON_SECURE + ); + + $this->pos->customQuery($requestData, $apiUrl); + } + + public static function customQueryRequestDataProvider(): array + { + return [ + [ + 'requestData' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx/xxxx', + 'expected_api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx/xxxx', + ], + [ + 'requestData' => [ + 'id' => '2020110828BC', + ], + 'api_url' => null, + 'expected_api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function make3DPaymentDataProvider(): array + { + return [ + 'auth_fail' => [ + 'order' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['order'], + 'txType' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['txType'], + 'request' => Request::create( + '', + 'POST', + ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['threeDResponseData'] + ), + 'paymentResponse' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['paymentData'], + 'expected' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['auth_fail1']['expectedData'], + 'is3DSuccess' => false, + 'isSuccess' => false, + ], + 'order_number_already_exist' => [ + 'order' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['order'], + 'txType' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['txType'], + 'request' => Request::create( + '', + 'POST', + ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['threeDResponseData'] + ), + 'paymentResponse' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['paymentData'], + 'expected' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['order_number_already_exist']['expectedData'], + 'is3DSuccess' => false, + 'isSuccess' => false, + ], + 'success' => [ + 'order' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['order'], + 'txType' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['txType'], + 'request' => Request::create( + '', + 'POST', + ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['threeDResponseData'] + ), + 'paymentResponse' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['paymentData'], + 'expected' => ParamPosResponseDataMapperTest::threeDPaymentDataProvider()['success1']['expectedData'], + 'is3DSuccess' => true, + 'isSuccess' => true, + ], + ]; + } + + public static function makeRegularPaymentDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'txType' => PosInterface::TX_TYPE_PAY_PRE_AUTH, + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function makeRegularPostAuthPaymentDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function statusRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function cancelRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function refundRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function historyRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function orderHistoryRequestDataProvider(): array + { + return [ + [ + 'order' => [ + 'id' => '2020110828BC', + ], + 'api_url' => 'https://vpostest.qnbfinansbank.com/Gateway/XMLGate.aspx', + ], + ]; + } + + public static function threeDFormDataBadInputsProvider(): array + { + return [ + '3d_secure_without_card' => [ + 'order' => ['id' => '2020110828BC'], + 'paymentModel' => PosInterface::MODEL_3D_SECURE, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'isWithCard' => false, + 'create_without_card' => false, + 'expectedExceptionClass' => \InvalidArgumentException::class, + ], + '3d_pay_without_card' => [ + 'order' => ['id' => '2020110828BC'], + 'paymentModel' => PosInterface::MODEL_3D_PAY, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'isWithCard' => false, + 'create_without_card' => false, + 'expectedExceptionClass' => \InvalidArgumentException::class, + ], + 'unsupported_payment_model' => [ + 'order' => ['id' => '2020110828BC'], + 'paymentModel' => PosInterface::MODEL_3D_PAY_HOSTING, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'isWithCard' => false, + 'create_without_card' => true, + 'expectedExceptionClass' => \LogicException::class, + ], + ]; + } + + private function configureClientResponse( + string $txType, + string $soapMethod, + string $apiUrl, + array $requestData, + string $encodedRequestData, + string $responseContent, + array $decodedResponse, + array $order, + string $paymentModel + ): void { + $updatedRequestDataPreparedEvent = null; + + $this->serializerMock->expects(self::once()) + ->method('encode') + ->with($this->logicalAnd($this->arrayHasKey('test-update-request-data-with-event')), $soapMethod) + ->willReturn($encodedRequestData); + + $this->serializerMock->expects(self::once()) + ->method('decode') + ->with($responseContent, $txType) + ->willReturn($decodedResponse); + + $this->prepareClient( + $this->httpClientMock, + $responseContent, + $apiUrl, + [ + 'headers' => [ + 'Content-Type' => 'text/xml', + ], + 'body' => $encodedRequestData, + ], + ); + + $this->eventDispatcherMock->expects(self::once()) + ->method('dispatch') + ->with($this->logicalAnd( + $this->isInstanceOf(RequestDataPreparedEvent::class), + $this->callback(function (RequestDataPreparedEvent $dispatchedEvent) use ($requestData, $txType, $order, $paymentModel, &$updatedRequestDataPreparedEvent): bool { + $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): ?\Mews\Pos\Event\RequestDataPreparedEvent { + $updatedRequestData = $updatedRequestDataPreparedEvent->getRequestData(); + $updatedRequestData['test-update-request-data-with-event'] = true; + $updatedRequestDataPreparedEvent->setRequestData($updatedRequestData); + + return $updatedRequestDataPreparedEvent; + }); + } + + public static function threeDFormDataProvider(): iterable + { + $responseTestData = \iterator_to_array(ParamPosSerializerTest::decodeDataProvider()); + yield '3d_secure' => [ + 'order' => ParamPosRequestDataMapperTest::paymentRegisterRequestDataProvider()[0]['order'], + 'paymentModel' => PosInterface::MODEL_3D_PAY, + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'isWithCard' => true, + 'requestData' => ParamPosRequestDataMapperTest::paymentRegisterRequestDataProvider()[0]['expected'], + 'encodedRequestData' => 'encoded-request-data', + 'responseData' => $responseTestData['3d_form_success']['input'], + 'decodedResponseData' => $responseTestData['3d_form_success']['expected'], + 'formData' => $responseTestData['3d_form_success']['expected']['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML'], + ]; + + +// yield '3d_host' => [ +// 'order' => ToslaPosRequestDataMapperTest::paymentRegisterRequestDataProvider()[0]['order'], +// 'paymentModel' => PosInterface::MODEL_3D_HOST, +// 'txType' => PosInterface::TX_TYPE_PAY_AUTH, +// 'isWithCard' => false, +// 'requestData' => ToslaPosRequestDataMapperTest::paymentRegisterRequestDataProvider()[0]['expected'], +// 'encodedRequestData' => \json_encode(ToslaPosRequestDataMapperTest::statusRequestDataProvider()[0]['expected'], JSON_THROW_ON_ERROR), +// 'responseData' => ToslaPosSerializerTest::decodeDataProvider()['payment_register']['input'], +// 'decodedResponseData' => ToslaPosSerializerTest::decodeDataProvider()['payment_register']['decoded'], +// 'formData' => ToslaPosRequestDataMapperTest::threeDFormDataProvider()['3d_pay_form_data']['expected'], +// 'gateway_url' => 'https://ent.akodepos.com/api/Payment/threeDSecure/PA49E341381C94587AB4CB196DAC10DC02E509578520E4471A3EEE2BB4830AE4F', +// ]; + } +} diff --git a/tests/Unit/Serializer/ParamPosSerializerTest.php b/tests/Unit/Serializer/ParamPosSerializerTest.php new file mode 100644 index 00000000..f4ac9737 --- /dev/null +++ b/tests/Unit/Serializer/ParamPosSerializerTest.php @@ -0,0 +1,105 @@ +serializer = new ParamPosSerializer(); + } + + public function testSupports(): void + { + $supports = $this->serializer::supports(ParamPos::class); + + $this->assertTrue($supports); + } + + /** + * @dataProvider encodeDataProvider + */ + public function testEncode(array $data, string $txType, string $expected): void + { + $result = $this->serializer->encode($data, $txType); + $expected = str_replace(["\r"], '', $expected); + + $this->assertSame($expected, $result); + } + + + /** + * @dataProvider decodeDataProvider + */ + public function testDecode(string $data, string $txType, array $expected): void + { + $result = $this->serializer->decode($data, $txType); + if (isset($result['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML'])) { + $result['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML'] = $expected['TP_WMD_UCDResponse']['TP_WMD_UCDResult']['UCD_HTML']; + } + + $this->assertSame($expected, $result); + } + + public static function encodeDataProvider(): Generator + { + yield 'test1' => [ + 'input' => [ + 'Islem_ID' => 'rand', + 'Islem_Hash' => 'jsLYSB3lJ81leFgDLw4D8PbXURs=', + 'G' => [ + 'CLIENT_CODE' => '10738', + 'CLIENT_USERNAME' => 'Test1', + 'CLIENT_PASSWORD' => 'Test2', + ], + 'GUID' => '0c13d406-873b-403b-9c09-a5766840d98c', + 'Islem_Guvenlik_Tip' => '3D', + ], + 'txType' => 'TP_WMD_UCD', + 'expected' => ' +randjsLYSB3lJ81leFgDLw4D8PbXURs=10738Test1Test20c13d406-873b-403b-9c09-a5766840d98c3D +', + ]; + } + + public static function decodeDataProvider(): Generator + { + yield '3d_form_success' => [ + 'input' => \file_get_contents(__DIR__.'/../test_data/parampos/3d_form_response_success.xml'), + 'txType' => PosInterface::TX_TYPE_PAY_AUTH, + 'expected' => [ + 'TP_WMD_UCDResponse' => [ + 'TP_WMD_UCDResult' => [ + 'Islem_ID' => '6021840768', + 'Islem_GUID' => 'd68ac15c-17ca-4b7d-a046-10700291b249', + 'UCD_HTML' => 'html-document', + 'UCD_MD' => 'MosNOirpqxod2A0BdoPpFNf7E/hJX2pKvt8hunrQF2RSrggeWpNj9p+XDEgRdWfGdtGMHF5A7X/uVbJTb3cCN5LGcG2JsGd69bXc7yYBGGw/VMFTcHDObj+cVR6fP2k1s531ozcBEFN1hv+fwBH80YGHP2a6xbRujYzME2iPuPgCdr7wkoSWcZvwB5M73bFow3Jx3vqkwceaPUO6dat7m5Uv1dKmbp+py3yOR0nVaFGnKTmIB4JIAIuP24hCU2MJi+hvKDf7+IJIEl5cjotiUx/J0AINoeuIGrklDAZ8JRA7pxYXpZLwc3ZX60VpWvfS7sSOdayadMBOvltQSdRrPPhJztVNmkztgUe7s3rbpdVr4Fc/KzGtPa5PZLnpkXszhOO4g+pw0A3KuFsqTdFuuu25CqBTX/aG4yZ4VO7UKfG27cTgRaObKsU+YiwOhH/VgGODvd5qrR02gOY8f9Xqtw==', + 'Sonuc' => '1', + 'Sonuc_Str' => 'İşlem Başarılı', + 'Banka_Sonuc_Kod' => '0', + 'Siparis_ID' => '20241229D2FF', + ], + ], + ], + ]; + } +} diff --git a/tests/Unit/test_data/parampos/3d_form_response_success.xml b/tests/Unit/test_data/parampos/3d_form_response_success.xml new file mode 100644 index 00000000..f66ce409 --- /dev/null +++ b/tests/Unit/test_data/parampos/3d_form_response_success.xml @@ -0,0 +1,123 @@ +6021840768d68ac15c-17ca-4b7d-a046-10700291b249<!DOCTYPE html SYSTEM "about:legacy-compat"> + <html class="no-js" lang="en" xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta charset="utf-8"/> + <title>3-D Secure Processing</title> + <link href="https://testvpos.asseco-see.com.tr/mdpaympi/static/mpi.css" rel="stylesheet" type="text/css"/> + </head> + <body> + <div id="main"> + <div id="content"> + <div id="order"> + <h2>3-D Secure Processing</h2> + <div style="padding-bottom: 15px"> + <img src="https://testvpos.asseco-see.com.tr/mdpaympi/static/preloader.gif" alt="Please wait.."/> + </div> + <img src="https://testvpos.asseco-see.com.tr/mdpaympi/static/verifiedbyvisa.png" alt="Verified by VISA"/> + <iframe id="tdsMmethodTgtFrame" name="tdsMmethodTgtFrame" style="width: 1px; height: 1px; visibility: hidden;" src="javascript:false;" xmlns="http://www.w3.org/1999/xhtml"> + <!--.--> + </iframe><form id="tdsMmethodForm" name="tdsMmethodForm" action="https://3ds-acs.test.modirum.com/mdpayacs/3ds-method" method="post" target="tdsMmethodTgtFrame" xmlns="http://www.w3.org/1999/xhtml"> + <input type="hidden" name="3DSMethodData" value="eyAidGhyZWVEU1NlcnZlclRyYW5zSUQiIDogImViZjRkNTlkLWY1NDMtNWZkMi04MDAwLTAwMDAwMWVkYzc5NSIsICJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIiA6ICJodHRwczovL3Rlc3R2cG9zLmFzc2Vjby1zZWUuY29tLnRyL21kcGF5bXBpL01lcmNoYW50U2VydmVyP21uPVkmdHhpZD0zMjM2MDM0MSZkaWdlc3Q9a21jeFpjN3Z6dnNnJTJGZjJXQVRwcldGMnNYMTA3d1JqYkZNaDE2UEwlMkJJMUElM0QiIH0"/> + <input type="hidden" name="threeDSMethodData" value="eyAidGhyZWVEU1NlcnZlclRyYW5zSUQiIDogImViZjRkNTlkLWY1NDMtNWZkMi04MDAwLTAwMDAwMWVkYzc5NSIsICJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIiA6ICJodHRwczovL3Rlc3R2cG9zLmFzc2Vjby1zZWUuY29tLnRyL21kcGF5bXBpL01lcmNoYW50U2VydmVyP21uPVkmdHhpZD0zMjM2MDM0MSZkaWdlc3Q9a21jeFpjN3Z6dnNnJTJGZjJXQVRwcldGMnNYMTA3d1JqYkZNaDE2UEwlMkJJMUElM0QiIH0"/> + </form><script type="text/javascript" xmlns="http://www.w3.org/1999/xhtml"> + document.getElementById("tdsMmethodForm").submit(); + </script> + <div id="formdiv"> + <script type="text/javascript"> + function hideAndSubmitTimed(formid) + { + var timer=setTimeout("hideAndSubmit('"+formid+"');",2500); + } + + function hideAndSubmit(formid) + { + var formx=document.getElementById(formid); + if (formx!=null) + { + formx.style.visibility="hidden"; + formx.submit(); + } + } + </script> + <div> + <form id="webform0" name="ddcoll" method="POST" action="https://testvpos.asseco-see.com.tr/mdpaympi/MerchantServer" accept_charset="UTF-8"> + <input type="hidden" name="txid" value="32360341"/> + <input type="hidden" name="TDS2_Navigator_language" value=""/> + <input type="hidden" name="TDS2_Navigator_javaEnabled" value=""/> + <input type="hidden" name="TDS2_Navigator_jsEnabled" value=""/> + <input type="hidden" name="TDS2_Screen_colorDepth" value=""/> + <input type="hidden" name="TDS2_Screen_height" value=""/> + <input type="hidden" name="TDS2_Screen_width" value=""/> + <input type="hidden" name="TDS2_Screen_PixelDepth" value=""/> + <input type="hidden" name="TDS2_TimezoneOffset" value=""/> + <input type="text" name="digest" value="gr3kz8S943+/9q8M3Dw9lsKMFirZ7tFLqGGRaQOKnyU=" readonly="true" style="display:none;"/> + <input type="hidden" name="transientData" value="MosNOirpqxod2A0BdoPpFNf7E/hJX2pKvt8hunrQF2RSrggeWpNj9p+XDEgRdWfGdtGMHF5A7X/uVbJTb3cCN5LGcG2JsGd69bXc7yYBGGw/VMFTcHDObj+cVR6fP2k1s531ozcBEFN1hv+fwBH80YGHP2a6xbRujYzME2iPuPgCdr7wkoSWcZvwB5M73bFow3Jx3vqkwceaPUO6dat7m5Uv1dKmbp+py3yOR0nVaFGnKTmIB4JIAIuP24hCU2MJi+hvKDf7+IJIEl5cjotiUx/J0AINoeuIGrklDAZ8JRA7pxYXpZLwc3ZX60VpWvfS7sSOdayadMBOvltQSdRrPPhJztVNmkztgUe7s3rbpdVr4Fc/KzGtPa5PZLnpkXszhOO4g+pw0A3KuFsqTdFuuu25CqBTX/aG4yZ4VO7UKfG27cTgRaObKsU+YiwOhH/VgGODvd5qrR02gOY8f9Xqtw=="/> + <noscript> + <input type="submit" name="submitBtn" value="Please click here to continue"/> + </noscript> + </form> + </div> + </div> + <script type="text/javascript"> + hideAndSubmitTimed('webform0'); + </script> + <noscript> + <div align="center"> + <b>Javascript is turned off or not supported!</b> + <br/> + </div> + </noscript> + <script type="text/javascript"> + function populateData() + { + var form = document.getElementById("webform0"); + if (form != null) + { + if (form["TDS2_Navigator_language"]!=null) + { + form["TDS2_Navigator_language"].value=(navigator.language || ''); + } + if (form["TDS2_Navigator_jsEnabled"]!=null) + { + // if this scipt runs js is enabled + form["TDS2_Navigator_jsEnabled"].value="true"; + } + if (form["TDS2_Navigator_javaEnabled"]!=null) + { + form["TDS2_Navigator_javaEnabled"].value=navigator.javaEnabled(); + } + if (form["TDS2_Screen_colorDepth"]!=null) + { + form["TDS2_Screen_colorDepth"].value=screen.colorDepth; + } + if (form["TDS2_Screen_height"]!=null) + { + form["TDS2_Screen_height"].value=screen.height; + } + if (form["TDS2_Screen_width"]!=null) + { + form["TDS2_Screen_width"].value=screen.width; + } + if (form["TDS2_Screen_pixelDepth"]!=null) + { + form["TDS2_Screen_pixelDepth"].value=screen.pixelDepth; + } + + var timezoneOffsetField = form["TDS2_TimezoneOffset"]; + if (timezoneOffsetField!=null) + { + timezoneOffsetField.value=new Date().getTimezoneOffset(); + } + } + } + populateData(); + </script> + </div> + <div id="content-footer"/> + </div> + </div> + </body> + </html> + +MosNOirpqxod2A0BdoPpFNf7E/hJX2pKvt8hunrQF2RSrggeWpNj9p+XDEgRdWfGdtGMHF5A7X/uVbJTb3cCN5LGcG2JsGd69bXc7yYBGGw/VMFTcHDObj+cVR6fP2k1s531ozcBEFN1hv+fwBH80YGHP2a6xbRujYzME2iPuPgCdr7wkoSWcZvwB5M73bFow3Jx3vqkwceaPUO6dat7m5Uv1dKmbp+py3yOR0nVaFGnKTmIB4JIAIuP24hCU2MJi+hvKDf7+IJIEl5cjotiUx/J0AINoeuIGrklDAZ8JRA7pxYXpZLwc3ZX60VpWvfS7sSOdayadMBOvltQSdRrPPhJztVNmkztgUe7s3rbpdVr4Fc/KzGtPa5PZLnpkXszhOO4g+pw0A3KuFsqTdFuuu25CqBTX/aG4yZ4VO7UKfG27cTgRaObKsU+YiwOhH/VgGODvd5qrR02gOY8f9Xqtw==1İşlem Başarılı020241229D2FF