Skip to content

Instantly share code, notes, and snippets.

@akalongman
Created January 19, 2024 11:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akalongman/d58e9eb292e1e230d0a50c8a589bd7eb to your computer and use it in GitHub Desktop.
Save akalongman/d58e9eb292e1e230d0a50c8a589bd7eb to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Api\V1;
use App\Models\Order;
use App\Services\OrdersService;
use App\Services\PurchaseService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Throwable;
use function implode;
use function jencode;
use function logger;
use function preg_replace;
use function report;
use function response;
use const PHP_EOL;
class PaymentsController extends ApiV1Controller
{
public function check(Request $request, OrdersService $service)
{
// Log request
logger()->info('Payment check request', ['request' => $request->toArray()]);
$orderId = (int) $request->get('o_order_id');
if (empty($orderId)) {
return $this->paymentAvailableError('Order ID does not found');
}
$order = $service->findOne($orderId);
if (empty($order)) {
return $this->paymentAvailableError('Order does not found');
}
if (! $order->canBeProceedByBank()) {
return $this->paymentAvailableError('This order can not be proceed');
}
$trxId = $request->get('trx_id');
if (empty($trxId)) {
return $this->paymentAvailableError('trx_id is not provided');
}
$service->update($order, ['bank_trx_id' => $trxId]);
return $this->paymentAvailableSuccess($order);
}
public function register(Request $request, OrdersService $ordersService, PurchaseService $purchaseService)
{
// Log request
logger()->info('Payment register request', ['request' => $request->toArray()]);
$orderId = (int) $request->get('o_order_id');
if (empty($orderId)) {
return $this->paymentRegisterResponse('Order ID does not found', 2);
}
$order = $ordersService->findOne($orderId);
if (empty($order)) {
return $this->paymentRegisterResponse('Order does not found', 2);
}
$trxId = $request->get('trx_id');
if (empty($trxId) || $order->getBankTrxId() !== $trxId) {
return $this->paymentRegisterResponse('Invalid trx_id passed', 2);
}
// Check if order can be proceed
if (! $order->canBeProceedByBank()) {
return $this->paymentRegisterResponse('This order can not be proceed', 2);
}
$resultCode = (int) $request->get('result_code');
if (empty($resultCode)) {
return $this->paymentRegisterResponse('result_code parameter does not found', 2);
}
// Payment failed
if ($resultCode !== Order::BANK_RESULT_CODE_SUCCESS) {
$data = [
'status' => Order::STATUS_BANK_DECLINED,
'bank_result_code' => $resultCode,
'bank_ext_result_code' => $request->get('ext_result_code'),
];
$purchaseService->bankDeclined($order, $data);
return $this->paymentRegisterResponse('Failure was registered from bank side', 1);
}
// Save payment method if requested
if ($order->getSavePayMethod()) {
$cardRegistered = $request->get('card_registered');
// Save card, if all necessary fields are present
if ($cardRegistered === 'Y') {
$cardId = $request->get('card_id');
if (empty($cardId)) {
return $this->paymentRegisterResponse('card_id does not found in request', 2);
}
$cardExpiry = $request->get('card_expiry');
if (empty($cardExpiry)) {
return $this->paymentRegisterResponse('card_expiry does not found in request', 2);
}
$cardHolder = $request->get('p_cardholder');
$maskedPan = $request->get('p_maskedPan');
$purchaseService->savePayMethodIfNotExists($order, [
'card_id' => $cardId,
'card_number' => $maskedPan,
'card_holder' => $cardHolder,
'card_expires' => $cardExpiry,
'trx_id' => $trxId,
]);
} else {
logger()->info('Card data is missing. Looks like did nod checked "save card" on bank\'s page');
}
}
// Bank payment successful
// Send result to Socar
try {
$purchaseService->sendPurchaseData($order);
} catch (Throwable $e) {
$data = [
'status_msg' => jencode($e),
'status' => Order::STATUS_BANK_SUCCESS,
'bank_result_code' => $resultCode,
'bank_ext_result_code' => $request->get('ext_result_code'),
];
$purchaseService->sgpDeclined($order, $data);
report($e);
return $this->paymentRegisterResponse('Gateway error occurred', 2);
}
$data = [
'status' => Order::STATUS_COMPLETED,
'bank_result_code' => $resultCode,
'bank_ext_result_code' => $request->get('ext_result_code'),
];
$purchaseService->completed($order, $data);
return $this->paymentRegisterResponse('OK', 1);
}
private function paymentAvailableError(string $message, int $code = 2): Response
{
$xml = <<<XML
<payment-avail-response>
<result>
<code>$code</code>
<desc>$message</desc>
</result>
</payment-avail-response>
XML;
// Log response
logger()->info('Payment check response', ['response' => $this->cleanXml($xml)]);
return response($xml, 200, [
'Content-Type' => 'application/xml',
]);
}
private function paymentAvailableSuccess(Order $order, string $message = 'OK', int $code = 1): Response
{
$xmlArray = [];
$xmlArray[] = '<payment-avail-response>';
$xmlArray[] = '<result>';
$xmlArray[] = '<code>' . $code . '</code>';
$xmlArray[] = '<desc>' . $message . '</desc>';
$xmlArray[] = '</result>';
// Use saved card
if (! empty($order->payMethod)) {
$xmlArray[] = '<card>';
$xmlArray[] = '<id>' . $order->payMethod->getCardId() . '</id>';
$xmlArray[] = '</card>';
}
$xmlArray[] = '<purchase>';
$xmlArray[] = '<shortDesc>ტრანზაქციის ნომერი ' . $order->getId() . '</shortDesc>';
$xmlArray[] = '<longDesc>P:' . $order->user->getPn() . ',O:' . $order->getId() . '</longDesc>';
$xmlArray[] = '<account-amount>';
$xmlArray[] = '<amount>' . $order->getAmount() . '</amount>';
$xmlArray[] = '<currency>981</currency>';
$xmlArray[] = '<exponent>2</exponent>';
$xmlArray[] = '<id>POS18396</id>';
$xmlArray[] = '</account-amount>';
$xmlArray[] = '</purchase>';
// Save card
if ($order->getSavePayMethod() || ! empty($order->payMethod)) {
$xmlArray[] = '<order-params>';
$xmlArray[] = '<param>';
$xmlArray[] = '<name>card_on_file</name>';
$xmlArray[] = '<value>CIT</value>';
$xmlArray[] = '</param>';
$xmlArray[] = '</order-params>';
}
$xmlArray[] = '</payment-avail-response>';
$xml = implode(PHP_EOL, $xmlArray);
// Log response
logger()->info('Payment check response', ['response' => $this->cleanXml($xml)]);
return response($xml, 200, [
'Content-Type' => 'application/xml',
]);
}
private function paymentRegisterResponse(string $message, int $code): Response
{
$xmlArray = [];
$xmlArray[] = '<register-payment-response>';
$xmlArray[] = '<result>';
$xmlArray[] = '<code>' . $code . '</code>';
$xmlArray[] = '<desc>' . $message . '</desc>';
$xmlArray[] = '</result>';
$xmlArray[] = '</register-payment-response>';
$xml = implode(PHP_EOL, $xmlArray);
// Log response
logger()->info('Payment register response', ['response' => $this->cleanXml($xml)]);
return response($xml, 200, [
'Content-Type' => 'application/xml',
]);
}
private function cleanXml(string $xml): string
{
$xml = preg_replace('#\s+#isu', ' ', $xml);
return $xml;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment