Files
tbbank-new/app/Modules/OnlinePayment/Repositories/OnlinePaymentRepository.php
2025-11-15 21:32:03 +05:00

335 lines
8.5 KiB
PHP

<?php
namespace App\Modules\OnlinePayment\Repositories;
use App\Modules\Makeable;
use App\Modules\OnlinePayment\Contracts\PaymentProviderContract;
use App\Modules\OnlinePayment\Models\OnlinePayment;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Client\Response;
class OnlinePaymentRepository
{
use Makeable;
/**
* Pending online payments
*/
public const PENDING = 'pending';
/**
* Failed online payments
*/
public const FAILED = 'failed';
/**
* Paid online payments
*/
public const PAID = 'paid';
/**
* Related model
*/
protected ?Model $relatedModel;
/**
* Payment provider
*/
protected PaymentProviderContract $provider;
/**
* Response
*/
protected Response $response;
/**
* Online payment
*/
protected OnlinePayment $onlinePayment;
/**
* If payment is successful
*/
protected bool $successful;
/**
* If payment has failed
*/
protected bool $failed;
/**
* Payment order id
*/
protected string $orderId;
/**
* Online payment link
*/
protected string $paymentLink;
public function __construct(?Model $relatedModel = null)
{
$this->relatedModel = $relatedModel;
}
/**
* Status Values
*
* @return array<null|string, string>
*/
public static function statusValues(): array
{
return [
null => '-',
self::PENDING => __('Pending'),
self::PAID => __('Paid'),
self::FAILED => __('Cancelled'),
];
}
/**
* Generate order number for payment
*/
public function generateOrderNumber(): string
{
return date('dmyHis');
}
/**
* Payment provder
*/
public function setPaymentProvider(PaymentProviderContract $provider): self
{
$this->provider = $provider;
return $this;
}
/**
* Payment provider
*/
public function paymentProvider(): PaymentProviderContract
{
return $this->provider;
}
/**
* Online payment
*/
public function onlinePayment(): OnlinePayment
{
return $this->onlinePayment;
}
/**
* If payment has been successfull
*/
public function successful(): bool
{
return $this->successful;
}
/**
* If payment has been a failure
*/
public function failed(): bool
{
return $this->failed;
}
/**
* Set respond results
*/
public function setResponseResults(bool $result): void
{
$this->successful = $result;
$this->failed = ! $result;
}
/**
* Send request via provider
*/
public function sendRequest(): self
{
$this->response = $this->provider->sendRequest();
$this->failed = $this->response->failed();
$this->successful = $this->response->successful();
if ($this->response['errorCode'] != 0) {
$this->setResponseResults(false);
}
if ($this->successful) {
$this->orderId = string($this->response['orderId']);
$this->paymentLink = string($this->response['formUrl']);
$this->createHistory();
}
return $this;
}
/**
* Payment link
*/
public function paymentLink(): string
{
return $this->paymentLink;
}
/**
* Create online payment history
*/
public function createHistory(): void
{
$data = [
'amount' => $this->provider->amount(),
'orderNumber' => $this->provider->orderNumber(),
'description' => $this->provider->description(),
'orderId' => $this->orderId,
'formUrl' => $this->paymentLink,
'successUrl' => $this->provider->returnUrl(),
'errorUrl' => $this->provider->returnUrl(),
'username' => $this->provider->username(),
'paymentStatus' => self::PENDING,
];
if ($this->relatedModel) {
$data['online_paymantable_id'] = $this->relatedModel->id; // @phpstan-ignore-line
$data['online_paymantable_type'] = $this->relatedModel::class;
}
$this->onlinePayment = OnlinePayment::create($data);
}
/**
* Check payment
*
* @return array<string, string|bool|int>
*/
public function checkPayment(string $orderId): array
{
// Find payment order from history
/** @var \App\Modules\OnlinePayment\Models\OnlinePayment */
$paymentHistory = OnlinePayment::where('orderId', $orderId)->first();
// Resolve related resource model dynamically
/** @var \Illuminate\Database\Eloquent\Model Find related resource */
$modelClass = $paymentHistory->online_paymantable_type;
$modelId = $paymentHistory->online_paymantable_id;
if (! class_exists($modelClass)) {
return $this->paymentFailed('(RELATED RESOURCE CLASS NOT FOUND)');
}
$relatedResource = (new $modelClass)->find(id: $modelId);
// Check if resource could not be found or does not exist
if (! $relatedResource) {
return $this->paymentFailed('(RESOURCE NOT FOUND)');
}
$relatedResource->loadMissing('branch');
/** @var \App\Modules\Branch\Models\Branch */
$bankBranch = $relatedResource->branch;
if (! $bankBranch || is_null($bankBranch->billing_username) || is_null($bankBranch->billing_password)) { // @phpstan-ignore-line
return $this->paymentFailed('(BRANCH NOT FOUND)');
}
$this->provider->setUsername($bankBranch->billing_username);
$this->provider->setPassword($bankBranch->billing_password);
$response = $this->provider->checkPayment($orderId);
if ($response['errorCode'] == '99') {
return $this->paymentFailed('(REQUEST FAILURE)');
}
return $response['paymentAmountInfo']['depositedAmount'] > 0 // @phpstan-ignore-line
? $this->paymentSuccessful($relatedResource, $paymentHistory, $bankBranch->name)
: $this->paymentFailed(__('Payment has failed'), $paymentHistory, $bankBranch->name);
}
/**
* Successful payment
*
* @return array<string, string|bool|int>
*/
public function paymentSuccessful(Model $relatedResource, OnlinePayment $paymentHistory, string $branchName = ''): array
{
$relatedResource->update([
'paid' => true,
]);
$paymentHistory->update([
'paymentStatus' => OnlinePaymentRepository::PAID,
]);
return $this->paymentCheckResponseTemplate(
success: true,
pnr: $paymentHistory->online_paymantable_id,
branch_name: $branchName,
price_amount: $paymentHistory->amount.' TMT'
);
}
/**
* Failed payment
*
* @return array<string, string|bool|int>
*/
public function paymentFailed(string $title = '', ?OnlinePayment $paymentHistory = null, string $branchName = ''): array
{
if ($paymentHistory) {
$paymentHistory->update([
'paymentStatus' => OnlinePaymentRepository::FAILED,
]);
return $this->paymentCheckResponseTemplate(
success: false,
pnr: $paymentHistory->online_paymantable_id,
branch_name: $branchName,
price_amount: $paymentHistory->amount.' TMT'
);
}
return $this->paymentCheckResponseTemplate(false, $title);
}
/**
* Check payment response
*
* @return array<string, string|bool|int>
*/
public function paymentCheckResponseTemplate(
bool $success,
string $title = '',
int|string $pnr = '',
string $branch_name = '',
int|string $price_amount = '',
string $return_url = ''
): array {
return [
'success' => $success,
'title' => $title !== '' ? $title : ($success ? __('Payment is successful') : __('Payment has failed')),
'pnr' => $pnr,
'branch_name' => $branch_name,
'price_amount' => $price_amount,
'return_url' => $return_url !== '' ? $return_url : url('/'),
];
}
/**
* Show payment status
*
* @param array<string, string|bool|int> $data
*/
public function paymentStatusView(array $data): View
{
return view('module.online-payment::payment-status', $data);
}
}