Files
online.tbbank.gov.tm-larave…/app/Helpers/helpers.php
2025-09-10 17:22:53 +05:00

586 lines
15 KiB
PHP

<?php
use App\Events\EventType;
use App\Models\Payment\OnlinePaymentHistory;
use App\Models\System\Roles\Permission;
use App\Models\System\Verification;
use App\Modules\SberPaymentOrder\Models\SberPaymentOrderItem;
use App\Nova\Resources\Order\Card\CardTransaction\Actions\DownloadCardTransaction;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request as GuzzleRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Stevebauman\Location\Facades\Location;
use Symfony\Component\HttpFoundation\IpUtils;
/**
* Application locales
*
* @return array<string, string>
*/
function appLocales(): array
{
return is_array(config('app.locales')) ? config('app.locales') : [];
}
/**
* Modules directory path
*/
function modules_path(string $path = ''): string
{
return app_path('Modules/'.$path);
}
/**
* Check if module exists
*/
function module_exists(string $module): bool
{
return is_dir(modules_path(ucfirst($module)));
}
/**
* Check if a client IP is in our Server subnet
*
* @param string $ip
*/
function isLocalIp(string $ip = ''): bool
{
return ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
}
/**
* Is turkmen ip
*/
function isTurkmenIp(string $ip = ''): bool
{
return IpUtils::checkIp($ip, [
'95.85.192.0/19',
'95.85.224.0/20',
'95.85.240.0/21',
'95.85.248.0/22',
'95.85.252.0/22',
'217.174.224.0/19',
'91.207.136.0/22',
]);
}
/**
* Un mask phone from "+(993)-xx-xx-xx-xx"
*/
function unMaskPhone(string|int $phone): string
{
return substr(str_replace(['+', '(', ')', '-', '_'], '', strval($phone)), 3);
}
/**
* Send a sms
*
* @return mixed|void
*/
function sendSMS(string|int $phone, string|int $message)
{
if (! app()->isProduction()) {
return;
}
$client = new Client;
$headers = [
'Content-Type' => 'application/json;charset=utf-8;',
'Charset' => 'UTF-8',
];
$body = 'JSON={
"SendRequest": {
"TerminalID": "Online_PANEL",
"Version": "1",
"Lang": "EN",
"MobilePhone": "993'.$phone.'",
"Text": "'.$message.'"
}
}';
// 10.3.158.103
$request = new GuzzleRequest('POST', 'http://10.3.158.28:8080/kpsmsroute/online.request', $headers, $body);
try {
$res = $client->sendAsync($request)->wait();
return $res->getBody();
} catch (Exception $e) {
Log::error($e);
}
}
/**
* Send a sms verification code
*/
function sendSMSVerification(string|int $phone_number): ?Verification
{
$phone_code = rand(100000, 999999);
$verification = Verification::where(['username' => $phone_number])->first();
$verification ? $verification->update(['code' => $phone_code]) : Verification::create(['username' => $phone_number, 'code' => $phone_code]);
sendSMS($phone_number, 'Tassyklaýyş belgi: '.$phone_code);
return $verification;
}
/**
* Store auth events
*/
function storeAuthEvent(string $name, Request $request): void
{
Log::channel('auth_activity')
->{EventType::logType($name)}(sprintf(
'%s, APP_NAME: %s, REQUEST_TYPE: %s, SOURCE_IP: %s, SOURCE_PORT: %s, SOURCE_URL: %s, DESTINATION_IP: %s, DESTINATION_PORT: %s, DESTINATION_COUNTRY: %s, USER_ID: %s',
$name,
config('app.name'),
$request->method(),
$request->ip(),
$_SERVER['REMOTE_PORT'],
$request->url(),
$request->host(),
$request->getPort(),
isLocalIp($request->ip())
? 'TM'
: Location::get($request->ip())?->countryCode ?? 'TM',
$request->user()->id ?? '-',
));
}
/**
* Store resource events
*
* @param string $name Event name
* @param array<int, mixed> $data Event data
* @param Request $request
*/
function storeResourceEvent(string $name, array $data, Request $request): void
{
if ($name === EventType::laravelNovaActionEvent() || empty($data)) {
return;
}
try {
$before = [];
$after = [];
foreach ($data[0]->getChanges() as $key => $value) {
try {
if (array_key_exists($key, $data[0]->getOriginal())) {
$before[] = [$key => $data[0]->getOriginal()[$key]];
}
$after[] = [$key => $value];
} catch (Exception $e) {
Log::error($e->getMessage(), ['trace' => $e->getTraceAsString()]);
}
}
Log::channel('resource_activity')
->{EventType::logType($name)}(sprintf(
'%s, APP_NAME: %s, REQUEST_TYPE: %s, SOURCE_IP: %s, SOURCE_PORT: %s, SOURCE_URL: %s, DESTINATION_IP: %s, DESTINATION_PORT: %s, DESTINATION_COUNTRY: %s, USER_ID: %s, MODEL_NAME: %s, BEFORE: %s, AFTER: %s',
$name,
config('app.name'),
$request->method(),
$request->ip(),
$_SERVER['REMOTE_PORT'] ?? '-',
$request->url(),
$request->host(),
$request->getPort(),
isLocalIp($request->ip())
? 'TM'
: Location::get($request->ip())?->countryCode ?? 'TM',
$request->user()->id ?? '-',
get_class($data[0]),
json_encode($before),
json_encode($after),
));
} catch (Exception $e) {
Log::error('Error in storeResourceEvent() helpers', ['error' => $e]);
}
}
/**
* Locale app path
*/
function localeAppPath(): string
{
return config('app.locale_app.path');
}
/**
* Locale app url
*/
function localeAppUrl(): string
{
return config('app.locale_app.url');
}
/**
* Original quality :D
*/
function convertToOriginalFormat(int|float|string $apiPrice): string
{
$originalPrice = intval($apiPrice) / 100;
return number_format($originalPrice, 2, '.', '');
}
/**
* Date day mf
*
* @param string $month
* @param string $year
*/
function lastDayOfMonth(string $month, int|string $year): DateTime
{
$date = new DateTime("$year-$month-01");
$date->modify('last day of this month');
return $date;
}
/**
* Get index by value from array
*
* @param mixed $value Value to be searched
* @param array<int, mixed> $array Array
* @return null|int
*/
function indexByValue(mixed $value, array $array): ?int
{
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] == $value) {
return $i;
}
}
return null;
}
/**
* Convert db type to php type
*/
function dbTypeToPhp(string $type): string
{
return match ($type) {
'bigint' => 'int',
'varchar' => 'string',
'boolean' => 'bool',
'timestamp(0) without time zone' => 'string',
'json' => 'string',
'jsonb' => 'string',
default => 'string',
};
}
/**
* Cached value
*
* @param string $name
* @param mixed $value
* @param int $seconds
*/
function cached(string $name, mixed $value, int $seconds = 60): mixed
{
return cache()->has($name)
? cache($name)
: cache()->remember(
key: $name,
ttl: $seconds,
callback: fn () => is_callable($value) ? call_user_func($value) : $value
);
}
/**
* view-loan-order-permission-id
*/
function view_loan_order_permission_id(): int
{
return Cache::rememberForever('view_loan_order_permission_id', function () {
return Permission::query()->where('name', 'ViewLoanOrders')->first(['id', 'name'])->id;
});
}
/**
* VP fetch client info all
*
* @param $model
* @param $start_date
* @param $end_date
*/
function vp_fetch_ClientInfoAll($model, $start_date, $end_date)
{
$response = DownloadCardTransaction::make()->fetchApi(
passport_serie: $model->passport_serie,
passport_id: $model->passport_id,
card_number_masked: Str::mask($model->card_number, '*', 6, 6),
card_expire_date: $model->card_month.'/'.substr($model->card_year, 2),
start_date: $start_date,
end_date: $end_date,
);
return Str::isJson($response)
? json_decode($response)
: emptyClass(errCode: 1, message: 'Connection issue to VP');
}
/**
* Create an anonymous class that acts as a dynamic object.
*
* @param mixed ...$arguments Key-value pairs passed as an associative array.
* @return object Anonymous class instance with dynamic properties.
*/
function emptyClass(...$arguments): object
{
/**
* @var array<string, mixed> $arguments
*/
return new class($arguments)
{
/**
* Internal data storage.
*
* @var array<string, mixed>
*/
private array $data = [];
/**
* Constructor that sets properties.
*
* @param array<string, mixed> $props
*/
public function __construct(array $props)
{
foreach ($props as $key => $value) {
$this->data[$key] = $value;
}
}
/**
* Magic getter.
*
* @param string $key
* @return mixed|null
*/
public function __get(string $key): mixed
{
return $this->data[$key] ?? null;
}
/**
* Magic setter.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set(string $key, mixed $value): void
{
$this->data[$key] = $value;
}
/**
* Magic isset.
*
* @param string $key
* @return bool
*/
public function __isset(string $key): bool
{
return isset($this->data[$key]);
}
};
}
/**
* Check online payment
*
* @param string $orderId
* @param int|string $username
* @param string $password
*
* @return mixed
*/
function checkOnlinePayment(string $orderId, int|string $username, string $password): mixed
{
$response = Http::asForm()->post('https://mpi.gov.tm/payment/rest/getOrderStatusExtended.do', [
'language' => 'ru',
'orderId' => $orderId,
'userName' => $username,
'password' => $password,
]);
return $response;
}
/**
* Sync with bank system
*
* @param string $online_payment_order_uuid
* @param string $bank_unique_code
* @param string $online_payment_terminal_id
* @param string $user_deposit_account
* @param string $online_payment_auth_ref_num
* @param string $online_payment_tmt_amount
* @param string $pay_purpose
*
* @return mixed
*/
function syncWithBankSystem(
$online_payment_order_uuid,
$bank_unique_code,
$online_payment_terminal_id,
$user_deposit_account,
$online_payment_auth_ref_num,
$online_payment_tmt_amount,
$pay_purpose
): mixed {
$ecomId = $online_payment_order_uuid;
$agentId = $bank_unique_code;
$eposId = $online_payment_terminal_id;
$account = $user_deposit_account;
$rrn = $online_payment_auth_ref_num;
$amount = $online_payment_tmt_amount;
$payPurpose = $pay_purpose;
$client = new Client([
'timeout' => 5, // seconds before it fails
'connect_timeout' => 1, // seconds to wait for connection
]);
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'Basic YWRtaW46UUFad3N4MTIz',
];
$body = sprintf('{
"ecomId": "%s",
"agentId": "%s",
"eposId": "%s",
"account": "%s",
"rrn": "%s",
"amount": "%s",
"payPurpose": "%s"
}', $ecomId, $agentId, $eposId, $account, $rrn, $amount, $payPurpose);
$request = new GuzzleRequest('POST', 'http://10.3.158.102:8888/api/paytrn/new', $headers, $body);
try {
$res = $client->sendAsync($request)->wait();
return (string) $res->getBody();
} catch (Exception $e) {
info([$e->getMessage(), $e->getTraceAsString()]);
return null;
}
}
/**
* Get Sber credentials for a given payment item.
*
* @param SberPaymentOrderItem $item
* @return array{username?: string, password?: string, onlinePaymentResource?: OnlinePaymentHistory, relatedResource?: mixed, error?: string, type?: 'danger'|'modal'}
*/
function getSberCredentials(SberPaymentOrderItem $item): array
{
/** @var \App\Models\Payment\OnlinePaymentHistory|null $onlinePaymentResource */
$onlinePaymentResource = OnlinePaymentHistory::find($item->online_payment_history_id);
if (! $onlinePaymentResource) {
return ['error' => 'Online payment resource tapylmady', 'type' => 'danger'];
}
$relatedResource = (new $onlinePaymentResource->online_paymantable_type)
->find(id: $onlinePaymentResource->online_paymantable_id);
if (! $relatedResource) {
return ['error' => 'Bu resource tapylmady', 'type' => 'danger'];
}
$relatedResource->loadMissing(['branch']);
if (! $relatedResource->branch) {
return ['error' => 'Şahamça bilen birikdirilmedik', 'type' => 'danger'];
}
$username = $relatedResource->branch->billing_sber_username;
$password = $relatedResource->branch->billing_sber_password;
if (empty($username) || empty($password)) {
return ['error' => 'Ulanyjy ady bilen açar sözi gabat gelmedi', 'type' => 'modal'];
}
return [
'username' => $username,
'password' => $password,
'onlinePaymentResource' => $onlinePaymentResource,
'relatedResource' => $relatedResource,
];
}
function syncWithAzatAPI(SberPaymentOrderItem $orderItem): array
{
$result = getSberCredentials($orderItem);
if (isset($result['error'])) {
return $result;
}
/** @var \App\Models\Payment\OnlinePaymentHistory $onlinePaymentResource */
$onlinePaymentResource = $result['onlinePaymentResource'];
/** @var \App\Modules\SberPaymentOrder\Models\SberPaymentOrder $sberPaymentOrder */
$sberPaymentOrder = $result['relatedResource'];
$response = checkOnlinePayment($onlinePaymentResource->orderId, $result['username'], $result['password']);
info([
'response' => $response['errorCode'],
]);
if ($response['errorCode'] != 0) {
return [
'error' => $response['errorMessage'],
'type' => 'modal',
];
}
$systemRawResponse = syncWithBankSystem(
online_payment_order_uuid: $onlinePaymentResource->orderId,
bank_unique_code: $sberPaymentOrder->branch->unique_code,
online_payment_terminal_id: $response['terminalId'],
user_deposit_account: number_format($sberPaymentOrder->sender_deposit_account, 0, '', ''),
online_payment_auth_ref_num: $response['authRefNum'],
online_payment_tmt_amount: $orderItem->tmt_payment_amount,
pay_purpose: $orderItem->created_at->translatedFormat('F').' '.$orderItem->created_at->format('Y')
);
if ($systemRawResponse == null) {
return [
'error' => 'Connection issue to SYSTEM',
'type' => 'modal',
];
}
$systemResponse = json_decode($systemRawResponse);
$success = false;
if (is_object($systemResponse)) {
$success = $systemResponse->errCode == 0;
} else {
$success = $systemResponse['errCode'] == 0;
}
$orderItem->update([
'synced_with_system' => $success ? true : false,
]);
return [
'success' => $success,
'type' => 'modal',
];
}