Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kuveytpos non secure payment integration #201

Merged
merged 4 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ sistemlerinin kullanılabilmesidir.
| PosNetV1<br/>(JSON API) | Albaraka Türk | NonSecure<br/>3DSecure | İptal<br/>İade<br/>Durum sorgulama |
| PayFor | Finansbank<br/>Enpara | NonSecure<br/>3DSecure<br/>3DPay<br/>3DHost | İptal<br/>İade<br/>Durum sorgulama<br/>Sipariş Tarihçesini sorgulama<br/>Geçmiş İşlemleri sorgulama |
| InterPOS | Deniz bank | NonSecure<br/>3DSecure<br/>3DPay<br/>3DHost | İptal<br/>İade<br/>Durum sorgulama |
| Kuveyt POS TDV2.0.0 | Kuveyt Türk | 3DSecure | İptal<br/>İade<br/>Durum sorgulama<br/>(SOAP API) |
| Kuveyt POS TDV2.0.0 | Kuveyt Türk | NonSecure<br/>3DSecure | İptal<br/>İade<br/>Durum sorgulama<br/>(SOAP API) |
| VakifKatilimPos<br/>(test edilmesi gerekiyor) | Vakıf Katılım | NonSecure<br/>3DSecure<br/>3DHost | İptal<br/>İade<br/>Durum sorgulama<br/>Sipariş Tarihçesini sorgulama<br/>Geçmiş İşlemleri sorgulama |

### Ana başlıklar
Expand Down
2 changes: 1 addition & 1 deletion config/pos_production.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
'name' => 'kuveyt-pos',
'class' => Mews\Pos\Gateways\KuveytPos::class,
'gateway_endpoints' => [
'payment_api' => 'https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelProvisionGate',
'payment_api' => 'https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home',
'gateway_3d' => 'https://sanalpos.kuveytturk.com.tr/ServiceGateWay/Home/ThreeDModelPayGate',
'query_api' => 'https://boa.kuveytturk.com.tr/BOA.Integration.WCFService/BOA.Integration.VirtualPos/VirtualPosService.svc?wsdl',
],
Expand Down
2 changes: 1 addition & 1 deletion config/pos_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
'name' => 'kuveyt-pos',
'class' => Mews\Pos\Gateways\KuveytPos::class,
'gateway_endpoints' => [
'payment_api' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelProvisionGate',
'payment_api' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home',
'gateway_3d' => 'https://boatest.kuveytturk.com.tr/boa.virtualpos.services/Home/ThreeDModelPayGate',
'query_api' => 'https://boatest.kuveytturk.com.tr/BOA.Integration.WCFService/BOA.Integration.VirtualPos/VirtualPosService.svc?wsdl',
],
Expand Down
2 changes: 1 addition & 1 deletion docs/PRE-AUTH-POST-EXAMPLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ try {
}
```
```html
<!-- $formData içeriği HTML forma render ediyoruz ve kullanıcıyı banka gateway'ine yönlendiriyoruy. -->
<!-- $formData içeriği HTML forma render ediyoruz ve kullanıcıyı banka gateway'ine yönlendiriyoruz. -->
<form method="<?= $formData['method']; ?>" action="<?= $formData['gateway']; ?>" class="redirect-form" role="form">
<?php foreach ($formData['inputs'] as $key => $value) : ?>
<input type="hidden" name="<?= $key; ?>" value="<?= $value; ?>">
Expand Down
2 changes: 1 addition & 1 deletion docs/THREED-PAYMENT-EXAMPLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ try {
}
```
```html
<!-- $formData içeriği HTML forma render ediyoruz ve kullanıcıyı banka gateway'ine yönlendiriyoruy. -->
<!-- $formData içeriği HTML forma render ediyoruz ve kullanıcıyı banka gateway'ine yönlendiriyoruz. -->
<form method="<?= $formData['method']; ?>" action="<?= $formData['gateway']; ?>" class="redirect-form" role="form">
<?php foreach ($formData['inputs'] as $key => $value) : ?>
<input type="hidden" name="<?= $key; ?>" value="<?= $value; ?>">
Expand Down
6 changes: 3 additions & 3 deletions examples/kuveytpos/regular/_config.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
$account = \Mews\Pos\Factory\AccountFactory::createKuveytPosAccount(
'kuveytpos',
'496',
'apiuser1',
'apitest',
'400235',
'Api1232',
'api123',
PosInterface::MODEL_3D_SECURE
);

$pos = getGateway($account, $eventDispatcher);

$templateTitle = 'Regular Payment';
$paymentModel = PosInterface::MODEL_3D_SECURE;
$paymentModel = PosInterface::MODEL_NON_SECURE;
3 changes: 2 additions & 1 deletion src/Crypt/KuveytPosCrypt.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace Mews\Pos\Crypt;

use Mews\Pos\Entity\Account\AbstractPosAccount;
use Mews\Pos\Exceptions\NotImplementedException;

class KuveytPosCrypt extends AbstractCrypt
{
Expand Down Expand Up @@ -40,7 +41,7 @@ public function create3DHash(AbstractPosAccount $posAccount, array $requestData)
*/
public function check3DHash(AbstractPosAccount $posAccount, array $data): bool
{
return true;
throw new NotImplementedException();
}

/**
Expand Down
31 changes: 27 additions & 4 deletions src/DataMapper/RequestDataMapper/KuveytPosRequestDataMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public function create3DPaymentRequestData(AbstractPosAccount $posAccount, array
'TransactionType' => $this->mapTxType($txType),
'InstallmentCount' => $responseData['VPosMessage']['InstallmentCount'],
'Amount' => $responseData['VPosMessage']['Amount'],
'DisplayAmount' => $this->formatAmount($responseData['VPosMessage']['Amount']),
'DisplayAmount' => $responseData['VPosMessage']['Amount'],
'CurrencyCode' => $responseData['VPosMessage']['CurrencyCode'],
'MerchantOrderId' => $responseData['VPosMessage']['MerchantOrderId'],
'TransactionSecurity' => $responseData['VPosMessage']['TransactionSecurity'],
Expand Down Expand Up @@ -161,11 +161,34 @@ public function createNonSecurePostAuthPaymentRequestData(AbstractPosAccount $po
}

/**
* @param KuveytPosAccount $posAccount
*
* {@inheritDoc}
*/
public function createNonSecurePaymentRequestData(AbstractPosAccount $posAccount, array $order, string $txType, CreditCardInterface $creditCard): array
{
throw new NotImplementedException();
$order = $this->preparePaymentOrder($order);

$requestData = $this->getRequestAccountData($posAccount) + [
'APIVersion' => self::API_VERSION,
'HashData' => '',
'TransactionType' => $this->mapTxType($txType),
'TransactionSecurity' => '1',
'MerchantOrderId' => (string) $order['id'],
'Amount' => $this->formatAmount($order['amount']),
'DisplayAmount' => $this->formatAmount($order['amount']),
'CurrencyCode' => $this->mapCurrency($order['currency']),
'InstallmentCount' => $this->mapInstallment($order['installment']),
'CardHolderName' => $creditCard->getHolderName(),
'CardNumber' => $creditCard->getNumber(),
'CardExpireDateYear' => $creditCard->getExpireYear(self::CREDIT_CARD_EXP_YEAR_FORMAT),
'CardExpireDateMonth' => $creditCard->getExpireMonth(self::CREDIT_CARD_EXP_MONTH_FORMAT),
'CardCVV2' => $creditCard->getCvv(),
];

$requestData['HashData'] = $this->crypt->createHash($posAccount, $requestData);

return $requestData;
}

/**
Expand Down Expand Up @@ -392,7 +415,7 @@ protected function mapInstallment(int $installment): string
*/
protected function preparePaymentOrder(array $order): array
{
return array_merge($order, [
return \array_merge($order, [
'installment' => $order['installment'] ?? 0,
'currency' => $order['currency'] ?? PosInterface::CURRENCY_TRY,
]);
Expand All @@ -403,7 +426,7 @@ protected function preparePaymentOrder(array $order): array
*/
protected function prepareStatusOrder(array $order): array
{
return array_merge($order, [
return \array_merge($order, [
'id' => $order['id'],
'currency' => $order['currency'] ?? PosInterface::CURRENCY_TRY,
'start_date' => $order['start_date'] ?? date_create('-360 day'),
Expand Down
20 changes: 15 additions & 5 deletions src/DataMapper/ResponseDataMapper/KuveytPosResponseDataMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class KuveytPosResponseDataMapper extends AbstractResponseDataMapper
*/
protected array $orderStatusMappings = [
1 => PosInterface::PAYMENT_STATUS_PAYMENT_COMPLETED,
5 => PosInterface::PAYMENT_STATUS_FULLY_REFUNDED,
4 => PosInterface::PAYMENT_STATUS_FULLY_REFUNDED,
5 => PosInterface::PAYMENT_STATUS_PARTIALLY_REFUNDED,
6 => PosInterface::PAYMENT_STATUS_CANCELED,
];

Expand Down Expand Up @@ -123,15 +124,15 @@ public function map3DPaymentData(array $raw3DAuthResponseData, ?array $rawPaymen
*/
public function map3DPayResponseData(array $raw3DAuthResponseData, string $txType, array $order): array
{
return $this->map3DPaymentData($raw3DAuthResponseData, $raw3DAuthResponseData, $txType, $order);
throw new NotImplementedException();
}

/**
* {@inheritdoc}
*/
public function map3DHostResponseData(array $raw3DAuthResponseData, string $txType, array $order): array
{
return $this->map3DPayResponseData($raw3DAuthResponseData, $txType, $order);
throw new NotImplementedException();
}

/**
Expand Down Expand Up @@ -176,11 +177,20 @@ public function mapStatusResponse(array $rawResponseData): array
$defaultResponse['transaction_id'] = $orderContract['Stan'];
$defaultResponse['currency'] = $this->mapCurrency($orderContract['FEC']);
$defaultResponse['first_amount'] = (float) $orderContract['FirstAmount'];
$defaultResponse['capture_amount'] = null !== $orderContract['FirstAmount'] ? (float) $orderContract['FirstAmount'] : null;
$defaultResponse['capture'] = $defaultResponse['first_amount'] > 0 && $defaultResponse['first_amount'] === $defaultResponse['capture_amount'];
$defaultResponse['masked_number'] = $orderContract['CardNumber'];
$defaultResponse['transaction_time'] = new \DateTimeImmutable($orderContract['OrderDate']);
$defaultResponse['installment_count'] = $this->mapInstallment($orderContract['InstallmentCount']);
if (PosInterface::PAYMENT_STATUS_PAYMENT_COMPLETED === $defaultResponse['order_status']) {
$defaultResponse['capture_amount'] = null !== $orderContract['FirstAmount'] ? (float) $orderContract['FirstAmount'] : null;
$defaultResponse['capture'] = $defaultResponse['first_amount'] > 0 && $defaultResponse['first_amount'] === $defaultResponse['capture_amount'];
if ($defaultResponse['capture']) {
$defaultResponse['capture_time'] = new \DateTimeImmutable($orderContract['UpdateSystemDate']);
}
} elseif (PosInterface::PAYMENT_STATUS_CANCELED === $defaultResponse['order_status']) {
$defaultResponse['cancel_time'] = new \DateTimeImmutable($orderContract['UpdateSystemDate']);
} elseif (PosInterface::PAYMENT_STATUS_FULLY_REFUNDED === $defaultResponse['order_status']) {
$defaultResponse['refund_time'] = new \DateTimeImmutable($orderContract['UpdateSystemDate']);
}
}

return $defaultResponse;
Expand Down
77 changes: 58 additions & 19 deletions src/Gateways/KuveytPos.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
use Mews\Pos\Entity\Account\KuveytPosAccount;
use Mews\Pos\Entity\Card\CreditCardInterface;
use Mews\Pos\Event\RequestDataPreparedEvent;
use Mews\Pos\Exceptions\HashMismatchException;
use Mews\Pos\Exceptions\UnsupportedPaymentModelException;
use Mews\Pos\Exceptions\UnsupportedTransactionTypeException;
use Mews\Pos\PosInterface;
Expand Down Expand Up @@ -46,6 +45,7 @@ class KuveytPos extends AbstractGateway
/** @inheritdoc */
protected static array $supportedTransactions = [
PosInterface::TX_TYPE_PAY_AUTH => [
PosInterface::MODEL_NON_SECURE,
PosInterface::MODEL_3D_SECURE,
],
PosInterface::TX_TYPE_PAY_PRE_AUTH => false,
Expand All @@ -63,6 +63,29 @@ public function getAccount(): AbstractPosAccount
return $this->account;
}

/**
* @inheritDoc
*/
public function getApiURL(string $txType = null, string $paymentModel = null, ?string $orderTxType = null): string
{
if (\in_array(
$txType,
[
PosInterface::TX_TYPE_REFUND,
PosInterface::TX_TYPE_STATUS,
PosInterface::TX_TYPE_CANCEL,
],
true
)) {
return $this->getQueryAPIUrl();
}
if (null !== $txType && null !== $paymentModel) {
return parent::getApiURL().'/'.$this->getRequestURIByTransactionType($txType, $paymentModel);
}

return parent::getApiURL();
}

/**
* @inheritDoc
*/
Expand Down Expand Up @@ -108,14 +131,6 @@ public function get3DFormData(array $order, string $paymentModel, string $txType
return $this->getCommon3DFormData($this->account, $order, $paymentModel, $txType, $gatewayUrl, $creditCard);
}

/**
* @inheritDoc
*/
public function makeRegularPayment(array $order, CreditCardInterface $creditCard, string $txType): PosInterface
{
throw new UnsupportedPaymentModelException();
}

/**
* @inheritDoc
*/
Expand Down Expand Up @@ -143,10 +158,6 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr
return $this;
}

if (!$this->requestDataMapper->getCrypt()->check3DHash($this->account, $gatewayResponse)) {
throw new HashMismatchException();
}

$this->logger->debug('finishing payment');

$requestData = $this->requestDataMapper->create3DPaymentRequestData($this->account, $order, $txType, $gatewayResponse);
Expand All @@ -168,7 +179,7 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr
$contents,
$txType,
PosInterface::MODEL_3D_SECURE,
$this->getApiURL()
$this->getApiURL($txType, PosInterface::MODEL_3D_SECURE)
);

$this->response = $this->responseDataMapper->map3DPaymentData($gatewayResponse, $bankResponse, $txType, $order);
Expand All @@ -190,7 +201,7 @@ protected function send($contents, string $txType, string $paymentModel, string
throw new InvalidArgumentException(\sprintf('Invalid data type provided for %s transaction!', $txType));
}

return $this->data = $this->sendSoapRequest($contents, $txType);
return $this->data = $this->sendSoapRequest($contents, $txType, $url);
}

$this->logger->debug('sending request', ['url' => $url]);
Expand All @@ -209,17 +220,17 @@ protected function send($contents, string $txType, string $paymentModel, string
/**
* @phpstan-param PosInterface::TX_TYPE_STATUS|PosInterface::TX_TYPE_REFUND|PosInterface::TX_TYPE_CANCEL $txType
*
* @param array<string, mixed> $contents
* @param string $txType
* @param array<string, mixed> $contents
* @param string $txType
* @param string $url
*
* @return array<string, mixed>
*
* @throws SoapFault
* @throws Throwable
*/
protected function sendSoapRequest(array $contents, string $txType): array
private function sendSoapRequest(array $contents, string $txType, string $url): array
{
$url = $this->getQueryAPIUrl();
$this->logger->debug('sending soap request', [
'txType' => $txType,
'url' => $url,
Expand Down Expand Up @@ -313,4 +324,32 @@ private function getCommon3DFormData(KuveytPosAccount $kuveytPosAccount, array $

return $this->requestDataMapper->create3DFormData($this->account, $decodedResponse['form_inputs'], $paymentModel, $txType, $decodedResponse['gateway'], $creditCard);
}

/**
* @phpstan-param PosInterface::TX_TYPE_* $txType
* @phpstan-param PosInterface::MODEL_* $paymentModel
*
* @return string
*
* @throws UnsupportedTransactionTypeException
*/
private function getRequestURIByTransactionType(string $txType, string $paymentModel): string
{
$arr = [
PosInterface::TX_TYPE_PAY_AUTH => [
PosInterface::MODEL_NON_SECURE => 'Non3DPayGate',
PosInterface::MODEL_3D_SECURE => 'ThreeDModelProvisionGate',
],
];

if (!isset($arr[$txType])) {
throw new UnsupportedTransactionTypeException();
}

if (!isset($arr[$txType][$paymentModel])) {
throw new UnsupportedTransactionTypeException();
}

return $arr[$txType][$paymentModel];
}
}
5 changes: 0 additions & 5 deletions src/Gateways/VakifKatilimPos.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Mews\Pos\Entity\Account\KuveytPosAccount;
use Mews\Pos\Entity\Card\CreditCardInterface;
use Mews\Pos\Event\RequestDataPreparedEvent;
use Mews\Pos\Exceptions\HashMismatchException;
use Mews\Pos\Exceptions\UnsupportedPaymentModelException;
use Mews\Pos\Exceptions\UnsupportedTransactionTypeException;
use Mews\Pos\PosInterface;
Expand Down Expand Up @@ -122,10 +121,6 @@ public function make3DPayment(Request $request, array $order, string $txType, Cr
return $this;
}

if (!$this->requestDataMapper->getCrypt()->check3DHash($this->account, $gatewayResponse)) {
throw new HashMismatchException();
}

$this->logger->debug('finishing payment');

$requestData = $this->requestDataMapper->create3DPaymentRequestData($this->account, $order, $txType, $gatewayResponse);
Expand Down
Loading