diff --git a/README.md b/README.md
index 23ad3e18..cd6e8592 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ sistemlerinin kullanılabilmesidir.
| EST V3 POS
EstPos altyapının
daha güvenli
(sha512) hash
algoritmasıyla
uygulaması. | -----"----- | -----"----- | -----"----- |
| PayFlex MPI VPOS V4 | Ziraat
Vakıfbank VPOS 7/24
İşbank | NonSecure
3DSecure
Tekrarlanan Ödeme | İptal
İade
Durum sorgulama |
| PayFlex
Common Payment V4
(Ortak Ödeme) | Ziraat
Vakıfbank
İşbank | NonSecure
3DPay
3DHost | İptal
İade |
-| Garanti Virtual POS | Garanti | NonSecure
3DSecure
3DPay
3DHost
Tekrarlanan Ödeme | İptal
İade
Durum sorgulama
Sipariş Tarihçesini sorgulama |
+| Garanti Virtual POS | Garanti | NonSecure
3DSecure
3DPay
3DHost
Tekrarlanan Ödeme | İptal
İade
Durum sorgulama
Sipariş Tarihçesini sorgulama
Geçmiş İşlemleri sorgulama |
| PosNet | YapıKredi | NonSecure
3DSecure
| İptal
İade
Durum sorgulama |
| PosNetV1
(JSON API) | Albaraka Türk | NonSecure
3DSecure | İptal
İade
Durum sorgulama |
| PayFor | Finansbank
Enpara | NonSecure
3DSecure
3DPay
3DHost | İptal
İade
Durum sorgulama
Sipariş Tarihçesini sorgulama
Geçmiş İşlemleri sorgulama |
diff --git a/docs/HISTORY-EXAMPLE.md b/docs/HISTORY-EXAMPLE.md
index 0180695a..674115af 100644
--- a/docs/HISTORY-EXAMPLE.md
+++ b/docs/HISTORY-EXAMPLE.md
@@ -45,7 +45,7 @@ try {
require 'config.php';
-function createHistoryOrder(string $gatewayClass, array $extraData): array
+function createHistoryOrder(string $gatewayClass, array $extraData, string $ip): array
{
$order = [];
$txTime = new \DateTimeImmutable();
@@ -61,6 +61,14 @@ function createHistoryOrder(string $gatewayClass, array $extraData): array
'start_date' => $txTime->modify('-1 day'),
'end_date' => $txTime->modify('+1 day'),
];
+ } elseif (\Mews\Pos\Gateways\GarantiPos::class === $gatewayClass) {
+ $order = [
+ 'ip' => $ip,
+ 'page' => 1, //optional
+ // Başlangıç ve bitiş tarihleri arasında en fazla 30 gün olabilir
+ 'start_date' => $txTime,
+ 'end_date' => $txTime->modify('+1 day'),
+ ];
} elseif (\Mews\Pos\Gateways\AkbankPos::class === $gatewayClass) {
$order = [
// Gün aralığı 1 günden fazla girilemez
@@ -76,7 +84,7 @@ function createHistoryOrder(string $gatewayClass, array $extraData): array
return $order;
}
-$order = createHistoryOrder(get_class($pos), []);
+$order = createHistoryOrder(get_class($pos), [], '127.0.0.1');
try {
$pos->history($order);
diff --git a/examples/_common-codes/regular/history.php b/examples/_common-codes/regular/history.php
index 9781fcf8..03fa8466 100644
--- a/examples/_common-codes/regular/history.php
+++ b/examples/_common-codes/regular/history.php
@@ -9,7 +9,7 @@
require '../../_templates/_header.php';
-function createHistoryOrder(string $gatewayClass, array $extraData): array
+function createHistoryOrder(string $gatewayClass, array $extraData, string $ip): array
{
$order = [];
$txTime = new \DateTimeImmutable();
@@ -28,6 +28,15 @@ function createHistoryOrder(string $gatewayClass, array $extraData): array
'start_date' => $txTime->modify('-1 day'),
'end_date' => $txTime->modify('+1 day'),
];
+ } elseif (\Mews\Pos\Gateways\GarantiPos::class === $gatewayClass) {
+ $order = [
+ 'ip' => $ip,
+ 'currency' => \Mews\Pos\PosInterface::CURRENCY_USD,
+ 'page' => 1, //optional
+ // Başlangıç ve bitiş tarihleri arasında en fazla 30 gün olabilir
+ 'start_date' => $txTime,
+ 'end_date' => $txTime->modify('+1 day'),
+ ];
} elseif (\Mews\Pos\Gateways\AkbankPos::class === $gatewayClass) {
$order = [
// Gün aralığı 1 günden fazla girilemez
@@ -43,7 +52,7 @@ function createHistoryOrder(string $gatewayClass, array $extraData): array
return $order;
}
-$order = createHistoryOrder(get_class($pos), []);
+$order = createHistoryOrder(get_class($pos), [], $ip);
dump($order);
try {
diff --git a/examples/garanti/regular/history.php b/examples/garanti/regular/history.php
new file mode 100644
index 00000000..34a3742d
--- /dev/null
+++ b/examples/garanti/regular/history.php
@@ -0,0 +1,3 @@
+ 'void',
PosInterface::TX_TYPE_REFUND => 'refund',
PosInterface::TX_TYPE_REFUND_PARTIAL => 'refund',
- PosInterface::TX_TYPE_HISTORY => 'orderhistoryinq',
+ PosInterface::TX_TYPE_ORDER_HISTORY => 'orderhistoryinq',
+ PosInterface::TX_TYPE_HISTORY => 'orderlistinq',
PosInterface::TX_TYPE_STATUS => 'orderinq',
];
@@ -80,10 +85,10 @@ public function create3DPaymentRequestData(AbstractPosAccount $posAccount, array
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount),
'Customer' => [
- 'IPAddress' => $responseData['customeripaddress'],
+ 'IPAddress' => $responseData['customeripaddress'],
],
'Order' => [
- 'OrderID' => $responseData['orderid'],
+ 'OrderID' => $responseData['orderid'],
],
'Transaction' => [
'Type' => $responseData['txntype'],
@@ -124,11 +129,11 @@ public function createNonSecurePaymentRequestData(AbstractPosAccount $posAccount
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Card' => $this->getCardData($creditCard),
'Order' => [
- 'OrderID' => $order['id'],
+ 'OrderID' => $order['id'],
],
'Transaction' => [
'Type' => $this->mapTxType($txType),
@@ -163,7 +168,7 @@ public function createNonSecurePostAuthPaymentRequestData(AbstractPosAccount $po
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Order' => [
'OrderID' => $order['id'],
@@ -195,7 +200,7 @@ public function createStatusRequestData(AbstractPosAccount $posAccount, array $o
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Order' => [
'OrderID' => $order['id'],
@@ -229,7 +234,7 @@ public function createCancelRequestData(AbstractPosAccount $posAccount, array $o
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount, true),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Order' => [
'OrderID' => $order['id'],
@@ -264,7 +269,7 @@ public function createRefundRequestData(AbstractPosAccount $posAccount, array $o
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount, true),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Order' => [
'OrderID' => $order['id'],
@@ -299,13 +304,13 @@ public function createOrderHistoryRequestData(AbstractPosAccount $posAccount, ar
'Version' => self::API_VERSION,
'Terminal' => $this->getTerminalData($posAccount),
'Customer' => [
- 'IPAddress' => $order['ip'],
+ 'IPAddress' => $order['ip'],
],
'Order' => [
'OrderID' => $order['id'],
],
'Transaction' => [
- 'Type' => $this->mapTxType(PosInterface::TX_TYPE_HISTORY),
+ 'Type' => $this->mapTxType(PosInterface::TX_TYPE_ORDER_HISTORY),
'InstallmentCnt' => $this->mapInstallment($order['installment']),
'Amount' => $this->formatAmount($order['amount']), //sabit olarak amount 100 gonderilecek
'CurrencyCode' => $this->mapCurrency($order['currency']),
@@ -320,11 +325,45 @@ public function createOrderHistoryRequestData(AbstractPosAccount $posAccount, ar
}
/**
+ * @param GarantiPosAccount $posAccount
* {@inheritDoc}
*/
public function createHistoryRequestData(AbstractPosAccount $posAccount, array $data = []): array
{
- throw new NotImplementedException();
+ $order = $this->prepareHistoryOrder($data);
+
+ $result = [
+ 'Mode' => $this->getMode(),
+ 'Version' => self::API_VERSION,
+ 'Terminal' => $this->getTerminalData($posAccount),
+ 'Customer' => [
+ 'IPAddress' => $order['ip'],
+ ],
+ 'Order' => [
+ 'OrderID' => null,
+ 'GroupID' => null,
+ 'Description' => null,
+ // Başlangıç ve bitiş tarihleri arasında en fazla 30 gün olabilir
+ 'StartDate' => $this->formatRequestDateTime($order['start_date']),
+ 'EndDate' => $this->formatRequestDateTime($order['end_date']),
+ /**
+ * 500 adetten fazla işlem olması durumunda ListPageNum alanında diğer 500 lü grupların görüntülenmesi
+ * için sayfa numarası yazılır.
+ */
+ 'ListPageNum' => $order['page'],
+ ],
+ 'Transaction' => [
+ 'Type' => $this->mapTxType(PosInterface::TX_TYPE_HISTORY),
+ 'Amount' => $this->formatAmount(1), //sabit olarak amount 100 gonderilecek
+ 'CurrencyCode' => $this->mapCurrency(PosInterface::CURRENCY_TRY),
+ 'CardholderPresentCode' => '0',
+ 'MotoInd' => self::MOTO,
+ ],
+ ];
+
+ $result['Terminal']['HashData'] = $this->crypt->createHash($posAccount, $result);
+
+ return $result;
}
@@ -463,6 +502,19 @@ protected function prepareOrderHistoryOrder(array $order): array
return $this->prepareStatusOrder($order);
}
+ /**
+ * @inheritDoc
+ */
+ protected function prepareHistoryOrder(array $data): array
+ {
+ return [
+ 'start_date' => $data['start_date'],
+ 'end_date' => $data['end_date'],
+ 'page' => $data['page'] ?? 1,
+ 'ip' => $data['ip'],
+ ];
+ }
+
/**
* @inheritDoc
*/
@@ -574,4 +626,14 @@ private function createRecurringData(array $recurringData): array
'StartDate' => isset($recurringData['startDate']) ? $recurringData['startDate']->format('Ymd') : '',
];
}
+
+ /**
+ * @param \DateTimeInterface $dateTime
+ *
+ * @return string example 01/12/2010 11:11
+ */
+ private function formatRequestDateTime(\DateTimeInterface $dateTime): string
+ {
+ return $dateTime->format('d/m/Y H:i');
+ }
}
diff --git a/src/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapper.php b/src/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapper.php
index 46979b18..62a89917 100644
--- a/src/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapper.php
+++ b/src/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapper.php
@@ -253,7 +253,7 @@ public function mapStatusResponse(array $rawResponseData): array
}
/** @var array{Response: array} $transaction */
- $transaction = $rawResponseData['Transaction'];
+ $transaction = $rawResponseData['Transaction'];
/** @var array $orderInqResult */
$orderInqResult = $rawResponseData['Order']['OrderInqResult'];
$defaultResponse = $this->getDefaultStatusResponse($rawResponseData);
@@ -333,7 +333,36 @@ public function mapOrderHistoryResponse(array $rawResponseData): array
*/
public function mapHistoryResponse(array $rawResponseData): array
{
- throw new NotImplementedException();
+ $rawResponseData = $this->emptyStringsToNull($rawResponseData);
+ $procReturnCode = $this->getProcReturnCode($rawResponseData);
+ $status = self::TX_DECLINED;
+ if (self::PROCEDURE_SUCCESS_CODE === $procReturnCode) {
+ $status = self::TX_APPROVED;
+ }
+
+ $mappedTransactions = [];
+ if (self::TX_APPROVED === $status) {
+ $rawTransactions = $rawResponseData['Order']['OrderListInqResult']['OrderTxnList']['OrderTxn'];
+ if (\count($rawTransactions) !== \count($rawTransactions, COUNT_RECURSIVE)) {
+ foreach ($rawTransactions as $transaction) {
+ $mappedTransaction = $this->mapSingleHistoryTransaction($transaction);
+ $mappedTransactions[] = $mappedTransaction;
+ }
+ } else {
+ $mappedTransactions[] = $this->mapSingleHistoryTransaction($rawTransactions);
+ }
+ }
+
+ return [
+ 'proc_return_code' => $procReturnCode,
+ 'error_code' => self::TX_DECLINED === $status ? $procReturnCode : null,
+ 'error_message' => self::TX_DECLINED === $status ? $rawResponseData['Transaction']['Response']['ErrorMsg'] : null,
+ 'status' => $status,
+ 'status_detail' => $this->getStatusDetail($procReturnCode),
+ 'trans_count' => \count($mappedTransactions),
+ 'transactions' => $mappedTransactions,
+ 'all' => $rawResponseData,
+ ];
}
/**
@@ -352,6 +381,23 @@ public function extractMdStatus(array $raw3DAuthResponseData): ?string
return $raw3DAuthResponseData['mdstatus'] ?? null;
}
+ /**
+ * @inheritDoc
+ */
+ public function mapTxType($txType): ?string
+ {
+ $historyResponseTxTypes = [
+ 'Satis' => PosInterface::TX_TYPE_PAY_AUTH,
+ 'On Otorizasyon' => PosInterface::TX_TYPE_PAY_PRE_AUTH,
+ 'On Otorizasyon Kapama' => PosInterface::TX_TYPE_PAY_POST_AUTH,
+ 'Iade' => PosInterface::TX_TYPE_REFUND,
+ 'Iptal' => PosInterface::TX_TYPE_CANCEL,
+ // ... Odul Sorgulama
+ ];
+
+ return $historyResponseTxTypes[$txType] ?? parent::mapTxType($txType);
+ }
+
/**
* 100001 => 1000.01
* @param string $amount
@@ -458,6 +504,40 @@ protected function getProcReturnCode(array $response): ?string
return $response['Transaction']['Response']['Code'] ?? null;
}
+ /**
+ * @inheritDoc
+ */
+ protected function mapCurrency(string $currency): string
+ {
+ $historyResponseCurrencyMapping = [
+ 'TL' => PosInterface::CURRENCY_TRY,
+ 'USD' => PosInterface::CURRENCY_USD,
+ 'EUR' => PosInterface::CURRENCY_EUR,
+ 'RUB' => PosInterface::CURRENCY_RUB,
+ 'JPY' => PosInterface::CURRENCY_JPY,
+ 'GBP' => PosInterface::CURRENCY_GBP,
+ ];
+
+ return $historyResponseCurrencyMapping[$currency] ?? parent::mapCurrency($currency);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ protected function mapInstallment(?string $installment): int
+ {
+ if (null === $installment) {
+ return 0;
+ }
+
+ // history response
+ if ('Pesin' === $installment || '1' === $installment) {
+ return 0;
+ }
+
+ return parent::mapInstallment($installment);
+ }
+
/**
* @param array $rawTx
*
@@ -494,4 +574,97 @@ private function mapSingleOrderHistoryTransaction(array $rawTx): array
return $defaultResponse;
}
+
+ /**
+ * @param array $rawTx
+ *
+ * @return array
+ */
+ private function mapSingleHistoryTransaction(array $rawTx): array
+ {
+ $procReturnCode = $rawTx['ResponseCode'];
+ $status = self::TX_DECLINED;
+ if (self::PROCEDURE_SUCCESS_CODE === $procReturnCode) {
+ $status = self::TX_APPROVED;
+ }
+
+ $defaultResponse = $this->getDefaultOrderHistoryTxResponse();
+ $defaultResponse['auth_code'] = $rawTx['AuthCode'] ?? null;
+ $defaultResponse['ref_ret_num'] = $rawTx['RetrefNum'] ?? null;
+ $defaultResponse['order_id'] = $rawTx['OrderID'];
+ $defaultResponse['batch_num'] = $rawTx['BatchNum'];
+ $defaultResponse['proc_return_code'] = $procReturnCode;
+ $defaultResponse['transaction_type'] = null !== $rawTx['TrxType'] ? $this->mapTxType($rawTx['TrxType']) : null;
+ $defaultResponse['order_status'] = null !== $rawTx['Status'] ? $this->mapHistoryOrderStatus($rawTx['Status'], $defaultResponse['transaction_type']) : null;
+ $defaultResponse['status'] = $status;
+ $defaultResponse['status_detail'] = $this->getStatusDetail($procReturnCode);
+ $defaultResponse['error_code'] = self::TX_APPROVED === $status ? null : $procReturnCode;
+ $defaultResponse['error_message'] = self::TX_APPROVED === $status ? null : $rawTx['SysErrMsg'];
+
+ // 3D Secure => 3D
+ // 3D Pay => 3D
+ // NonSecure => ''
+ $defaultResponse['payment_model'] = '3D' === $rawTx['SafeType'] ? PosInterface::MODEL_3D_SECURE : PosInterface::MODEL_NON_SECURE;
+ $defaultResponse['transaction_time'] = null !== $rawTx['LastTrxDate'] ? new \DateTimeImmutable($rawTx['LastTrxDate']) : null;
+ if (self::TX_APPROVED === $status) {
+ $defaultResponse['masked_number'] = $rawTx['CardNumberMasked'];
+ $defaultResponse['installment_count'] = $this->mapInstallment($rawTx['InstallmentCnt']);
+ $defaultResponse['currency'] = null !== $rawTx['CurrencyCode'] ? $this->mapCurrency($rawTx['CurrencyCode']) : null;
+ $defaultResponse['first_amount'] = null !== $rawTx['AuthAmount'] ? $this->formatAmount($rawTx['AuthAmount']) : null;
+ if ($defaultResponse['order_status'] === PosInterface::PAYMENT_STATUS_PAYMENT_COMPLETED) {
+ $defaultResponse['capture_amount'] = $defaultResponse['first_amount'];
+ $defaultResponse['capture'] = $defaultResponse['first_amount'] > 0 ? $defaultResponse['capture_amount'] === $defaultResponse['first_amount'] : null;
+ $defaultResponse['capture_time'] = $defaultResponse['transaction_time'];
+ }
+ }
+
+ return $defaultResponse;
+ }
+
+ /**
+ * todo anlasilmayan durumlar:
+ * - "Status" => "Iptal", "TrxType" => "Satis"
+ * - "Status" => "Iptal", "TrxType" => "On Otorizasyon"
+ * - "Status" => "Iptal", "TrxType" => "Iptal"
+ * - "Status" => "Iptal", "TrxType" => "Iade"
+ *
+ * @param string $txStatus
+ * @param PosInterface::TX_TYPE_*|null $txType
+ *
+ * @return string|null
+ */
+ private function mapHistoryOrderStatus(string $txStatus, ?string $txType): ?string
+ {
+ if (null === $txType) {
+ return null;
+ }
+ // txStatus possible values:
+ // Basarili
+ // Basarisiz
+ // Iptal
+ // Onaylandi
+
+ if ('Basarili' === $txStatus || 'Onaylandi' === $txStatus) {
+ if (PosInterface::TX_TYPE_CANCEL === $txType) {
+ return PosInterface::PAYMENT_STATUS_CANCELED;
+ }
+ if (PosInterface::TX_TYPE_REFUND === $txType) {
+ // todo how can we decide if order is partially or fully refunded?
+ return PosInterface::PAYMENT_STATUS_FULLY_REFUNDED;
+ }
+ if (PosInterface::TX_TYPE_PAY_AUTH === $txType || PosInterface::TX_TYPE_PAY_POST_AUTH === $txType) {
+ return PosInterface::PAYMENT_STATUS_PAYMENT_COMPLETED;
+ }
+ if (PosInterface::TX_TYPE_PAY_PRE_AUTH === $txType) {
+ return PosInterface::PAYMENT_STATUS_PRE_AUTH_COMPLETED;
+ }
+
+ return null;
+ }
+ if ('Iptal' === $txStatus) {
+ return null;
+ }
+
+ return PosInterface::PAYMENT_STATUS_ERROR;
+ }
}
diff --git a/src/Gateways/GarantiPos.php b/src/Gateways/GarantiPos.php
index 24d5df15..4824c711 100644
--- a/src/Gateways/GarantiPos.php
+++ b/src/Gateways/GarantiPos.php
@@ -14,7 +14,6 @@
use Mews\Pos\Event\RequestDataPreparedEvent;
use Mews\Pos\Exceptions\HashMismatchException;
use Mews\Pos\Exceptions\UnsupportedPaymentModelException;
-use Mews\Pos\Exceptions\UnsupportedTransactionTypeException;
use Mews\Pos\PosInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -49,7 +48,7 @@ class GarantiPos extends AbstractGateway
PosInterface::TX_TYPE_REFUND => true,
PosInterface::TX_TYPE_REFUND_PARTIAL => true,
PosInterface::TX_TYPE_ORDER_HISTORY => true,
- PosInterface::TX_TYPE_HISTORY => false,
+ PosInterface::TX_TYPE_HISTORY => true,
];
@@ -139,14 +138,6 @@ public function make3DHostPayment(Request $request, array $order, string $txType
throw new UnsupportedPaymentModelException();
}
- /**
- * @inheritDoc
- */
- public function history(array $data): PosInterface
- {
- throw new UnsupportedTransactionTypeException();
- }
-
/**
* @inheritDoc
*
diff --git a/tests/Functional/AkbankPosTest.php b/tests/Functional/AkbankPosTest.php
index 0d53f7c8..74a5fef9 100644
--- a/tests/Functional/AkbankPosTest.php
+++ b/tests/Functional/AkbankPosTest.php
@@ -146,7 +146,7 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent) use (&$eventIsThro
public function testHistorySuccess(): void
{
- $historyOrder = $this->createHistoryOrder(\get_class($this->pos), []);
+ $historyOrder = $this->createHistoryOrder(\get_class($this->pos), [], '127.0.0.1');
$eventIsThrown = false;
$this->eventDispatcher->addListener(
@@ -416,7 +416,7 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent) use (&$eventIsThro
*/
public function testRecurringHistorySuccess(): void
{
- $historyOrder = $this->createHistoryOrder(\get_class($this->pos), []);
+ $historyOrder = $this->createHistoryOrder(\get_class($this->pos), [], '127.0.0.1');
$eventIsThrown = false;
$this->eventDispatcher->addListener(
diff --git a/tests/Functional/GarantiPosTest.php b/tests/Functional/GarantiPosTest.php
index 65f6c24a..1c5a5e5c 100644
--- a/tests/Functional/GarantiPosTest.php
+++ b/tests/Functional/GarantiPosTest.php
@@ -260,4 +260,28 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent) use (&$eventIsThro
$this->assertNotEmpty($response);
$this->assertTrue($eventIsThrown);
}
+
+ /**
+ * @depends testStatusSuccess
+ */
+ public function testHistorySuccess(): void
+ {
+ $historyOrder = $this->createHistoryOrder(\get_class($this->pos), [], '127.0.0.1');
+
+ $eventIsThrown = false;
+ $this->eventDispatcher->addListener(
+ RequestDataPreparedEvent::class,
+ function (RequestDataPreparedEvent $requestDataPreparedEvent) use (&$eventIsThrown): void {
+ $eventIsThrown = true;
+ $this->assertSame(PosInterface::TX_TYPE_HISTORY, $requestDataPreparedEvent->getTxType());
+ $this->assertCount(6, $requestDataPreparedEvent->getRequestData());
+ });
+
+ $this->pos->history($historyOrder);
+
+ $response = $this->pos->getResponse();
+ $this->assertIsArray($response);
+ $this->assertTrue($eventIsThrown);
+ $this->assertNotEmpty($response['transactions']);
+ }
}
diff --git a/tests/Functional/PayForPosTest.php b/tests/Functional/PayForPosTest.php
index e72d60e8..75f157e9 100644
--- a/tests/Functional/PayForPosTest.php
+++ b/tests/Functional/PayForPosTest.php
@@ -171,7 +171,7 @@ function (RequestDataPreparedEvent $requestDataPreparedEvent) use (&$eventIsThro
public function testHistorySuccess(): void
{
- $historyOrder = $this->createHistoryOrder(\get_class($this->pos), []);
+ $historyOrder = $this->createHistoryOrder(\get_class($this->pos), [], '127.0.0.1');
$eventIsThrown = false;
$this->eventDispatcher->addListener(
diff --git a/tests/Functional/PaymentTestTrait.php b/tests/Functional/PaymentTestTrait.php
index 60144077..9119da54 100644
--- a/tests/Functional/PaymentTestTrait.php
+++ b/tests/Functional/PaymentTestTrait.php
@@ -248,18 +248,17 @@ private function createOrderHistoryOrder(string $gatewayClass, array $lastRespon
return $order;
}
- private function createHistoryOrder(string $gatewayClass, array $extraData): array
+ private function createHistoryOrder(string $gatewayClass, array $extraData, string $ip): array
{
+ $txTime = new \DateTimeImmutable();
if (PayForPos::class === $gatewayClass) {
return [
// odeme tarihi
- 'transaction_date' => $extraData['transaction_date'] ?? new \DateTimeImmutable(),
+ 'transaction_date' => $extraData['transaction_date'] ?? $txTime,
];
}
if (\Mews\Pos\Gateways\VakifKatilimPos::class === $gatewayClass) {
- $txTime = new \DateTimeImmutable();
-
return [
'page' => 1,
'page_size' => 20,
@@ -271,9 +270,17 @@ private function createHistoryOrder(string $gatewayClass, array $extraData): arr
];
}
- if (\Mews\Pos\Gateways\AkbankPos::class === $gatewayClass) {
- $txTime = new \DateTimeImmutable();
+ if (\Mews\Pos\Gateways\GarantiPos::class === $gatewayClass) {
+ return [
+ 'ip' => $ip,
+ 'page' => 1,
+ // Başlangıç ve bitiş tarihleri arasında en fazla 30 gün olabilir
+ 'start_date' => $txTime->modify('-1 day'),
+ 'end_date' => $txTime->modify('+1 day'),
+ ];
+ }
+ if (\Mews\Pos\Gateways\AkbankPos::class === $gatewayClass) {
return [
// Gün aralığı 1 günden fazla girilemez
'start_date' => $txTime->modify('-23 hour'),
diff --git a/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php b/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php
index eace3103..3d237618 100644
--- a/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php
+++ b/tests/Unit/DataMapper/RequestDataMapper/GarantiPosRequestDataMapperTest.php
@@ -190,6 +190,19 @@ public function testCreateOrderHistoryRequestData(array $order, array $expectedD
$this->assertEquals($expectedData, $actual);
}
+ /**
+ * @dataProvider historyRequestDataProvider
+ */
+ public function testCreateHistoryRequestData(array $data, array $expectedData): void
+ {
+ $actualData = $this->requestDataMapper->createHistoryRequestData($this->account, $data);
+
+ \ksort($expectedData);
+ \ksort($actualData);
+
+ $this->assertSame($expectedData, $actualData);
+ }
+
/**
* @dataProvider create3DPaymentRequestDataDataProvider
*/
@@ -547,6 +560,51 @@ public static function orderHistoryRequestDataProvider(): array
];
}
+ public static function historyRequestDataProvider(): array
+ {
+ return [
+ [
+ 'data' => [
+ 'start_date' => new \DateTime('2022-05-18 00:00:00'),
+ 'end_date' => new \DateTime('2022-05-18 23:59:59'),
+ 'ip' => '127.0.0.1',
+ ],
+ 'expected' => [
+ 'Customer' => [
+ 'IPAddress' => '127.0.0.1',
+ ],
+
+ 'Mode' => 'TEST',
+ 'Order' => [
+ 'OrderID' => null,
+ 'GroupID' => null,
+ 'Description' => null,
+ 'StartDate' => '18/05/2022 00:00',
+ 'EndDate' => '18/05/2022 23:59',
+ 'ListPageNum' => 1,
+ ],
+
+ 'Terminal' => [
+ 'ProvUserID' => 'PROVAUT',
+ 'UserID' => 'PROVAUT',
+ 'HashData' => '9B53A55199EBAD2F486089FD7310C4BC0C61A99FC37EF61F6BBAE67FA17E47641540B203E83C9F2E64DB64B971FE6FF604274316F6D010426D6AA91BE1D924E6',
+ 'ID' => '30691298',
+ 'MerchantID' => '7000679',
+ ],
+
+ 'Transaction' => [
+ 'Type' => 'orderlistinq',
+ 'Amount' => 100,
+ 'CurrencyCode' => '949',
+ 'CardholderPresentCode' => '0',
+ 'MotoInd' => 'N',
+ ],
+ 'Version' => '512',
+ ],
+ ],
+ ];
+ }
+
public static function create3DPaymentRequestDataDataProvider(): \Generator
{
$account = AccountFactory::createGarantiPosAccount(
diff --git a/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php b/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php
index 5ceca6d8..d33877b4 100644
--- a/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php
+++ b/tests/Unit/DataMapper/ResponseDataMapper/GarantiPosResponseDataMapperTest.php
@@ -7,6 +7,7 @@
use Mews\Pos\DataMapper\RequestDataMapper\GarantiPosRequestDataMapper;
use Mews\Pos\DataMapper\ResponseDataMapper\GarantiPosResponseDataMapper;
+use Mews\Pos\Exceptions\NotImplementedException;
use Mews\Pos\Factory\CryptFactory;
use Mews\Pos\Gateways\GarantiPos;
use Mews\Pos\PosInterface;
@@ -97,6 +98,12 @@ public function testMap3DPaymentData(array $order, string $txType, array $threeD
$this->assertSame($expectedData, $actualData);
}
+ public function testMap3DHostResponseData(): void
+ {
+ $this->expectException(NotImplementedException::class);
+ $this->responseDataMapper->map3DHostResponseData([], PosInterface::TX_TYPE_PAY_AUTH, []);
+ }
+
/**
* @dataProvider threeDPayPaymentDataProvider
*/
@@ -164,6 +171,44 @@ public function testOrderMapHistoryResponse(array $responseData, array $expected
$this->assertCount($actualData['trans_count'], $actualData['transactions']);
+ $this->assertArrayHasKey('all', $actualData);
+ $this->assertIsArray($actualData['all']);
+ $this->assertNotEmpty($actualData['all']);
+ unset($actualData['all']);
+ $this->assertSame($expectedData, $actualData);
+ }
+
+ /**
+ * @dataProvider historyTestDataProvider
+ */
+ public function testMapHistoryResponse(array $responseData, array $expectedData): void
+ {
+ $actualData = $this->responseDataMapper->mapHistoryResponse($responseData);
+
+ 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']
+ );
+ }
+
+ $this->assertCount($actualData['trans_count'], $actualData['transactions']);
+
+ foreach (array_keys($actualData['transactions']) as $key) {
+ $this->assertEquals($expectedData['transactions'][$key]['transaction_time'], $actualData['transactions'][$key]['transaction_time'], 'tx: '.$key);
+ $this->assertEquals($expectedData['transactions'][$key]['capture_time'], $actualData['transactions'][$key]['capture_time'], 'tx: '.$key);
+ unset($actualData['transactions'][$key]['transaction_time'], $expectedData['transactions'][$key]['transaction_time']);
+ unset($actualData['transactions'][$key]['capture_time'], $expectedData['transactions'][$key]['capture_time']);
+ \ksort($actualData['transactions'][$key]);
+ \ksort($expectedData['transactions'][$key]);
+ }
+
+ $this->assertArrayHasKey('all', $actualData);
+ $this->assertIsArray($actualData['all']);
+ $this->assertNotEmpty($actualData['all']);
unset($actualData['all']);
$this->assertSame($expectedData, $actualData);
}
@@ -1732,4 +1777,203 @@ public function orderHistoryTestDataProvider(): array
],
];
}
+
+ public static function historyTestDataProvider(): \Generator
+ {
+ $dateRangeHistoryExpected = \json_decode(\file_get_contents(__DIR__.'/../../test_data/garanti/history/daily_range_history_expected.json'), true);
+
+ foreach ($dateRangeHistoryExpected['transactions'] as &$item) {
+ if (null !== $item['transaction_time']) {
+ $item['transaction_time'] = new \DateTimeImmutable(
+ $item['transaction_time']['date'],
+ new \DateTimeZone($item['transaction_time']['timezone'])
+ );
+ }
+ if (null !== $item['capture_time']) {
+ $item['capture_time'] = new \DateTimeImmutable(
+ $item['capture_time']['date'],
+ new \DateTimeZone($item['capture_time']['timezone'])
+ );
+ }
+ }
+
+ yield 'success_data_range_history' => [
+ 'responseData' => \json_decode(\file_get_contents(__DIR__.'/../../test_data/garanti/history/date_range_history.json'), true),
+ //'responseData' => \json_decode(\file_get_contents(__DIR__.'/../../../../var/garanti-last-2-year-history.json'), true),
+ 'expectedData' => $dateRangeHistoryExpected,
+ ];
+ yield 'success_single_transaction' => [
+ 'responseData' => [
+ 'Mode' => '',
+ 'Terminal' => [
+ 'ProvUserID' => 'PROVAUT',
+ 'UserID' => 'PROVAUT',
+ 'ID' => '30691298',
+ 'MerchantID' => '7000679',
+ ],
+ 'Customer' => [
+ 'IPAddress' => '172.26.0.1',
+ 'EmailAddress' => '',
+ ],
+ 'Order' => [
+ 'OrderID' => '',
+ 'GroupID' => '',
+ 'OrderListInqResult' => [
+ 'OrderTxnList' => [
+ 'TotalTxnCount' => '1',
+ 'TotalPageCount' => '1',
+ 'ActPageNum' => '1',
+ 'OrderTxn' => [
+ 'Id' => '1',
+ 'LastTrxDate' => '2024-06-03 16:06:29',
+ 'TrxType' => 'Satis',
+ 'OrderID' => '202406036C78',
+ 'Name' => '',
+ 'CardNumberMasked' => '42822090****8015',
+ 'ExpireDate' => '0830',
+ 'BankBin' => '42822090',
+ 'BatchNum' => '576200',
+ 'AuthCode' => '304919',
+ 'RetrefNum' => '415501677066',
+ 'OrigRetrefNum' => '',
+ 'InstallmentCnt' => 'Pesin',
+ 'Status' => 'Basarili',
+ 'AuthAmount' => '1001',
+ 'CurrencyCode' => 'TL',
+ 'RemainingBNSAmount' => '0',
+ 'UsedFBBAmount' => '0',
+ 'UsedChequeType' => '',
+ 'UsedChequeCount' => '0',
+ 'UsedChequeAmount' => '0',
+ 'SafeType' => '',
+ 'Comment1' => '',
+ 'Comment2' => '',
+ 'Comment3' => '',
+ 'UserId' => 'PROVAUT',
+ 'Settlement' => 'N',
+ 'EmailAddress' => '',
+ 'RecurringTotalPaymentNum' => '0',
+ 'RecurringLastPaymentNum' => '0',
+ 'RecurringTxnAmount' => '0',
+ 'ResponseCode' => '00',
+ 'SysErrMsg' => '',
+ ],
+ ],
+ ],
+ ],
+ 'Transaction' => [
+ 'Response' => [
+ 'Source' => 'GVPS',
+ 'Code' => '00',
+ 'ReasonCode' => '',
+ 'Message' => 'Approved',
+ 'ErrorMsg' => '',
+ 'SysErrMsg' => '',
+ ],
+ 'RetrefNum' => '',
+ 'AuthCode' => '',
+ 'BatchNum' => '',
+ 'SequenceNum' => '',
+ 'ProvDate' => '20240603 16:07:07',
+ 'CardNumberMasked' => '',
+ 'CardHolderName' => '',
+ 'CardType' => '',
+ 'HashData' => 'C1DD90277E3CE36D6226FF02E59D95999D78793CF8942860600BA2800A63CB991A518C1DECA1609C99DA8F8995CBB78A54E7D34F337A8BFF60D10B6DB47C8750',
+ 'HostMsgList' => '',
+ 'RewardInqResult' => [
+ 'RewardList' => '',
+ 'ChequeList' => '',
+ ],
+ ],
+ ],
+ 'expectedData' => [
+ 'proc_return_code' => '00',
+ 'error_code' => null,
+ 'error_message' => null,
+ 'status' => 'approved',
+ 'status_detail' => 'approved',
+ 'trans_count' => 1,
+ 'transactions' => [
+ [
+ 'auth_code' => '304919',
+ 'proc_return_code' => '00',
+ 'transaction_id' => null,
+ 'transaction_time' => new \DateTimeImmutable('2024-06-03 16:06:29'),
+ 'capture_time' => new \DateTimeImmutable('2024-06-03 16:06:29'),
+ 'error_message' => null,
+ 'ref_ret_num' => '415501677066',
+ 'order_status' => 'PAYMENT_COMPLETED',
+ 'transaction_type' => 'pay',
+ 'first_amount' => 10.01,
+ 'capture_amount' => 10.01,
+ 'status' => 'approved',
+ 'error_code' => null,
+ 'status_detail' => 'approved',
+ 'capture' => true,
+ 'currency' => 'TRY',
+ 'masked_number' => '42822090****8015',
+ 'order_id' => '202406036C78',
+ 'batch_num' => '576200',
+ 'payment_model' => 'regular',
+ 'installment_count' => 0,
+ ],
+ ],
+ ],
+ ];
+ yield 'fail_invalid_fields' => [
+ 'responseData' => [
+ 'Mode' => '',
+ 'Terminal' => [
+ 'ProvUserID' => 'PROVAUT',
+ 'UserID' => 'PROVAUT',
+ 'ID' => '30691298',
+ 'MerchantID' => '7000679',
+ ],
+ 'Customer' => [
+ 'IPAddress' => '',
+ 'EmailAddress' => '',
+ ],
+ 'Order' => [
+ 'OrderID' => '',
+ 'GroupID' => '',
+ 'OrderListInqResult' => [
+ 'OrderTxnList' => '',
+ ],
+ ],
+ 'Transaction' => [
+ 'Response' => [
+ 'Source' => 'GVPS',
+ 'Code' => '92',
+ 'ReasonCode' => '0002',
+ 'Message' => 'Declined',
+ 'ErrorMsg' => 'Giriş yaptığınız işlem tipi için zorunlu alanları kontrol ediniz',
+ 'SysErrMsg' => 'CustomerIPAddress field must contain value because of the Mandatory Rule:null',
+ ],
+ 'RetrefNum' => '',
+ 'AuthCode' => '',
+ 'BatchNum' => '',
+ 'SequenceNum' => '',
+ 'ProvDate' => '20240530 12:53:46',
+ 'CardNumberMasked' => '',
+ 'CardHolderName' => '',
+ 'CardType' => '',
+ 'HashData' => '09852B466F45FE00769BE0E40F028FFF7B560CCA5871F8E562B910C2E9CEF9972A8C7F8655D67D1E31B24E81BF57F5B35F8446A94591256DCFEB92D551FEC858',
+ 'HostMsgList' => '',
+ 'RewardInqResult' => [
+ 'RewardList' => '',
+ 'ChequeList' => '',
+ ],
+ ],
+ ],
+ 'expectedData' => [
+ 'proc_return_code' => '92',
+ 'error_code' => '92',
+ 'error_message' => 'Giriş yaptığınız işlem tipi için zorunlu alanları kontrol ediniz',
+ 'status' => 'declined',
+ 'status_detail' => 'invalid_transaction',
+ 'trans_count' => 0,
+ 'transactions' => [],
+ ],
+ ];
+ }
}
diff --git a/tests/Unit/Gateways/GarantiPosTest.php b/tests/Unit/Gateways/GarantiPosTest.php
index 159bb71d..2d5532c8 100644
--- a/tests/Unit/Gateways/GarantiPosTest.php
+++ b/tests/Unit/Gateways/GarantiPosTest.php
@@ -13,7 +13,6 @@
use Mews\Pos\Entity\Card\CreditCardInterface;
use Mews\Pos\Event\RequestDataPreparedEvent;
use Mews\Pos\Exceptions\UnsupportedPaymentModelException;
-use Mews\Pos\Exceptions\UnsupportedTransactionTypeException;
use Mews\Pos\Factory\AccountFactory;
use Mews\Pos\Factory\CreditCardFactory;
use Mews\Pos\Gateways\GarantiPos;
@@ -449,10 +448,38 @@ public function testRefundRequest(array $order, string $apiUrl): void
$this->pos->refund($order);
}
- public function testHistoryRequest(): void
+ /**
+ * @dataProvider historyRequestDataProvider
+ */
+ public function testHistoryRequest(array $order, string $apiUrl): void
{
- $this->expectException(UnsupportedTransactionTypeException::class);
- $this->pos->history([]);
+ $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);
}
/**
@@ -632,4 +659,18 @@ private function configureClientResponse(
&& $order === $dispatchedEvent->getOrder()
&& $paymentModel === $dispatchedEvent->getPaymentModel()));
}
+
+ public static function historyRequestDataProvider(): array
+ {
+ return [
+ [
+ 'order' => [
+ 'ip' => '127.0.0.1',
+ 'start_date' => new \DateTimeImmutable(),
+ 'end_date' => new \DateTimeImmutable(),
+ ],
+ 'api_url' => 'https://sanalposprovtest.garantibbva.com.tr/VPServlet',
+ ],
+ ];
+ }
}
diff --git a/tests/Unit/test_data/garanti/history/daily_range_history_expected.json b/tests/Unit/test_data/garanti/history/daily_range_history_expected.json
new file mode 100644
index 00000000..aa52d2c7
--- /dev/null
+++ b/tests/Unit/test_data/garanti/history/daily_range_history_expected.json
@@ -0,0 +1,155 @@
+{
+ "proc_return_code": "00",
+ "error_code": null,
+ "error_message": null,
+ "status": "approved",
+ "status_detail": "approved",
+ "trans_count": 5,
+ "transactions": [
+ {
+ "auth_code": "304919",
+ "proc_return_code": "00",
+ "transaction_id": null,
+ "transaction_time": {
+ "date": "2024-06-03 14:04:19.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "capture_time": {
+ "date": "2024-06-03 14:04:19.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "error_message": null,
+ "ref_ret_num": "415501676495",
+ "order_status": "PAYMENT_COMPLETED",
+ "transaction_type": "pay",
+ "first_amount": 10.01,
+ "capture_amount": 10.01,
+ "status": "approved",
+ "error_code": null,
+ "status_detail": "approved",
+ "capture": true,
+ "currency": "TRY",
+ "masked_number": "42822090****8015",
+ "order_id": "202406033030",
+ "batch_num": "576200",
+ "payment_model": "regular",
+ "installment_count": 0
+ },
+ {
+ "auth_code": null,
+ "proc_return_code": "05",
+ "transaction_id": null,
+ "transaction_time": {
+ "date": "2024-06-03 14:04:29.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "capture_time": null,
+ "error_message": "RPC-05 condition was raised",
+ "ref_ret_num": "415501676496",
+ "order_status": "ERROR",
+ "transaction_type": "refund",
+ "first_amount": null,
+ "capture_amount": null,
+ "status": "declined",
+ "error_code": "05",
+ "status_detail": "reject",
+ "capture": null,
+ "currency": null,
+ "masked_number": null,
+ "order_id": "202406033030",
+ "batch_num": "576200",
+ "payment_model": "regular"
+ },
+ {
+ "auth_code": "304919",
+ "proc_return_code": "00",
+ "transaction_id": null,
+ "transaction_time": {
+ "date": "2024-06-03 14:20:59.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "capture_time": {
+ "date": "2024-06-03 14:20:59.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "error_message": null,
+ "ref_ret_num": "415501676585",
+ "order_status": "PAYMENT_COMPLETED",
+ "transaction_type": "pay",
+ "first_amount": 4903.17,
+ "capture_amount": 4903.17,
+ "status": "approved",
+ "error_code": null,
+ "status_detail": "approved",
+ "capture": true,
+ "currency": "TRY",
+ "masked_number": "42822090****8015",
+ "order_id": "__lwyvqzf9_____65848",
+ "batch_num": "576200",
+ "payment_model": "3d",
+ "installment_count": 0
+ },
+ {
+ "auth_code": "304919",
+ "proc_return_code": "00",
+ "transaction_id": null,
+ "transaction_time": {
+ "date": "2024-06-03 14:50:07.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "capture_time": {
+ "date": "2024-06-03 14:50:07.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "error_message": null,
+ "ref_ret_num": "415501676711",
+ "order_status": "PAYMENT_COMPLETED",
+ "transaction_type": "pay",
+ "first_amount": 276.0,
+ "capture_amount": 276.0,
+ "status": "approved",
+ "error_code": null,
+ "status_detail": "approved",
+ "capture": true,
+ "currency": "TRY",
+ "masked_number": "42822090****8015",
+ "order_id": "00000093877E202406031450",
+ "batch_num": "576200",
+ "payment_model": "3d",
+ "installment_count": 0
+ },
+ {
+ "auth_code": null,
+ "proc_return_code": "14",
+ "transaction_id": null,
+ "transaction_time": {
+ "date": "2024-06-03 15:09:57.000000",
+ "timezone_type": 3,
+ "timezone": "UTC"
+ },
+ "capture_time": null,
+ "error_message": "HATALI KART NUMARASI.",
+ "ref_ret_num": "415501676775",
+ "order_status": "ERROR",
+ "transaction_type": "pre",
+ "first_amount": null,
+ "capture_amount": null,
+ "status": "declined",
+ "error_code": "14",
+ "status_detail": null,
+ "capture": null,
+ "currency": null,
+ "masked_number": null,
+ "order_id": "202406038F95",
+ "batch_num": "576200",
+ "payment_model": "regular"
+ }
+ ]
+}
diff --git a/tests/Unit/test_data/garanti/history/date_range_history.json b/tests/Unit/test_data/garanti/history/date_range_history.json
new file mode 100644
index 00000000..fbfce410
--- /dev/null
+++ b/tests/Unit/test_data/garanti/history/date_range_history.json
@@ -0,0 +1,225 @@
+{
+ "Mode": "",
+ "Terminal": {
+ "ProvUserID": "PROVAUT",
+ "UserID": "PROVAUT",
+ "ID": "30691298",
+ "MerchantID": "7000679"
+ },
+ "Customer": {
+ "IPAddress": "172.26.0.1",
+ "EmailAddress": ""
+ },
+ "Order": {
+ "OrderID": "",
+ "GroupID": "",
+ "OrderListInqResult": {
+ "OrderTxnList": {
+ "TotalTxnCount": "5",
+ "TotalPageCount": "1",
+ "ActPageNum": "1",
+ "OrderTxn": [
+ {
+ "Id": "1",
+ "LastTrxDate": "2024-06-03 14:04:19",
+ "TrxType": "Satis",
+ "OrderID": "202406033030",
+ "Name": "",
+ "CardNumberMasked": "42822090****8015",
+ "ExpireDate": "0830",
+ "BankBin": "42822090",
+ "BatchNum": "576200",
+ "AuthCode": "304919",
+ "RetrefNum": "415501676495",
+ "OrigRetrefNum": "",
+ "InstallmentCnt": "Pesin",
+ "Status": "Basarili",
+ "AuthAmount": "1001",
+ "CurrencyCode": "TL",
+ "RemainingBNSAmount": "0",
+ "UsedFBBAmount": "0",
+ "UsedChequeType": "",
+ "UsedChequeCount": "0",
+ "UsedChequeAmount": "0",
+ "SafeType": "",
+ "Comment1": "",
+ "Comment2": "",
+ "Comment3": "",
+ "UserId": "PROVAUT",
+ "Settlement": "N",
+ "EmailAddress": "",
+ "RecurringTotalPaymentNum": "0",
+ "RecurringLastPaymentNum": "0",
+ "RecurringTxnAmount": "0",
+ "ResponseCode": "00",
+ "SysErrMsg": ""
+ },
+ {
+ "Id": "2",
+ "LastTrxDate": "2024-06-03 14:04:29",
+ "TrxType": "Iade",
+ "OrderID": "202406033030",
+ "Name": "",
+ "CardNumberMasked": "42822090****8015",
+ "ExpireDate": "0830",
+ "BankBin": "42822090",
+ "BatchNum": "576200",
+ "AuthCode": "",
+ "RetrefNum": "415501676496",
+ "OrigRetrefNum": "415501676495",
+ "InstallmentCnt": "Pesin",
+ "Status": "Basarisiz",
+ "AuthAmount": "801",
+ "CurrencyCode": "TL",
+ "RemainingBNSAmount": "0",
+ "UsedFBBAmount": "0",
+ "UsedChequeType": "",
+ "UsedChequeCount": "0",
+ "UsedChequeAmount": "0",
+ "SafeType": "",
+ "Comment1": "",
+ "Comment2": "",
+ "Comment3": "",
+ "UserId": "PROVRFN",
+ "Settlement": "E",
+ "EmailAddress": "",
+ "RecurringTotalPaymentNum": "0",
+ "RecurringLastPaymentNum": "0",
+ "RecurringTxnAmount": "0",
+ "ResponseCode": "05",
+ "SysErrMsg": "RPC-05 condition was raised"
+ },
+ {
+ "Id": "3",
+ "LastTrxDate": "2024-06-03 14:20:59",
+ "TrxType": "Satis",
+ "OrderID": "__lwyvqzf9_____65848",
+ "Name": "",
+ "CardNumberMasked": "42822090****8015",
+ "ExpireDate": "0327",
+ "BankBin": "42822090",
+ "BatchNum": "576200",
+ "AuthCode": "304919",
+ "RetrefNum": "415501676585",
+ "OrigRetrefNum": "",
+ "InstallmentCnt": "Pesin",
+ "Status": "Basarili",
+ "AuthAmount": "490317",
+ "CurrencyCode": "TL",
+ "RemainingBNSAmount": "0",
+ "UsedFBBAmount": "0",
+ "UsedChequeType": "",
+ "UsedChequeCount": "0",
+ "UsedChequeAmount": "0",
+ "SafeType": "3D",
+ "Comment1": "",
+ "Comment2": "",
+ "Comment3": "",
+ "UserId": "GARANTI",
+ "Settlement": "N",
+ "EmailAddress": "yigit.ozerdem@etstur.com",
+ "RecurringTotalPaymentNum": "0",
+ "RecurringLastPaymentNum": "0",
+ "RecurringTxnAmount": "0",
+ "ResponseCode": "00",
+ "SysErrMsg": ""
+ },
+ {
+ "Id": "4",
+ "LastTrxDate": "2024-06-03 14:50:07",
+ "TrxType": "Satis",
+ "OrderID": "00000093877E202406031450",
+ "Name": "",
+ "CardNumberMasked": "42822090****8015",
+ "ExpireDate": "0926",
+ "BankBin": "42822090",
+ "BatchNum": "576200",
+ "AuthCode": "304919",
+ "RetrefNum": "415501676711",
+ "OrigRetrefNum": "",
+ "InstallmentCnt": "Pesin",
+ "Status": "Basarili",
+ "AuthAmount": "27600",
+ "CurrencyCode": "TL",
+ "RemainingBNSAmount": "0",
+ "UsedFBBAmount": "0",
+ "UsedChequeType": "",
+ "UsedChequeCount": "0",
+ "UsedChequeAmount": "0",
+ "SafeType": "3D",
+ "Comment1": "",
+ "Comment2": "",
+ "Comment3": "",
+ "UserId": "KKB_USER",
+ "Settlement": "N",
+ "EmailAddress": "ozlemtopuz@kkb.com.tr",
+ "RecurringTotalPaymentNum": "0",
+ "RecurringLastPaymentNum": "0",
+ "RecurringTxnAmount": "0",
+ "ResponseCode": "00",
+ "SysErrMsg": ""
+ },
+ {
+ "Id": "5",
+ "LastTrxDate": "2024-06-03 15:09:57",
+ "TrxType": "On Otorizasyon",
+ "OrderID": "202406038F95",
+ "Name": "",
+ "CardNumberMasked": "42822090****8015",
+ "ExpireDate": "0830",
+ "BankBin": "42822090",
+ "BatchNum": "576200",
+ "AuthCode": "",
+ "RetrefNum": "415501676775",
+ "OrigRetrefNum": "",
+ "InstallmentCnt": "Pesin",
+ "Status": "Basarisiz",
+ "AuthAmount": "1001",
+ "CurrencyCode": "TL",
+ "RemainingBNSAmount": "0",
+ "UsedFBBAmount": "0",
+ "UsedChequeType": "",
+ "UsedChequeCount": "0",
+ "UsedChequeAmount": "0",
+ "SafeType": "",
+ "Comment1": "",
+ "Comment2": "",
+ "Comment3": "",
+ "UserId": "PROVAUT",
+ "Settlement": "E",
+ "EmailAddress": "",
+ "RecurringTotalPaymentNum": "0",
+ "RecurringLastPaymentNum": "0",
+ "RecurringTxnAmount": "0",
+ "ResponseCode": "14",
+ "SysErrMsg": "HATALI KART NUMARASI."
+ }
+ ]
+ }
+ }
+ },
+ "Transaction": {
+ "Response": {
+ "Source": "GVPS",
+ "Code": "00",
+ "ReasonCode": "",
+ "Message": "Approved",
+ "ErrorMsg": "",
+ "SysErrMsg": ""
+ },
+ "RetrefNum": "",
+ "AuthCode": "",
+ "BatchNum": "",
+ "SequenceNum": "",
+ "ProvDate": "20240603 15:12:44",
+ "CardNumberMasked": "",
+ "CardHolderName": "",
+ "CardType": "",
+ "HashData": "8143B6233C873EC7C38AA560C98F34C646CB1F375B84C6760D6EDEFD914F396042C88625F5F5BA205C64C0C7D4C2ACD8F478EEE730AFA159930B5D479BEEC1F5",
+ "HostMsgList": "",
+ "RewardInqResult": {
+ "RewardList": "",
+ "ChequeList": ""
+ }
+ }
+}