350 lines
13 KiB
PHP
350 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\TransactionOnlineStatus;
|
|
use Billplz\Client;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\Session;
|
|
|
|
class BillplzService
|
|
{
|
|
public $client;
|
|
public $config;
|
|
public $callbackUrl;
|
|
public $paymentTitle;
|
|
public $redirectUrl;
|
|
public $company;
|
|
|
|
public function __construct(string $company)
|
|
{
|
|
$this->company = $company;
|
|
$this->setupBillplzClient($company);
|
|
$this->setupUrls();
|
|
$this->paymentTitle = config('services.billplz.paymentTitle');
|
|
}
|
|
|
|
public function getCollections()
|
|
{
|
|
return $this->client->collection()->all()->toArray();
|
|
}
|
|
|
|
public function createBill(array $data,string $company)
|
|
{
|
|
|
|
$composed_data = [
|
|
$this->config['collection_id'],
|
|
...$data,
|
|
$this->callbackUrl,
|
|
$this->paymentTitle,
|
|
$this->redirectUrl,
|
|
];
|
|
|
|
|
|
try{
|
|
$response = $this->client->bill()->create(...$composed_data)->toArray();
|
|
|
|
OnlineTransactionLoggerService::logs($response['id'], $composed_data, $response, TransactionOnlineStatus::BILL_CREATED);
|
|
|
|
return $response;
|
|
|
|
} catch(\Exception $e){
|
|
if($e->getCode() === 404){
|
|
|
|
$errorMessage = 'Please check your billplz payment gateway collection. Ensure that api_key, x_signature, and collection_id are correctly entered';
|
|
|
|
OnlineTransactionLoggerService::logs( null, $composed_data, $errorMessage, TransactionOnlineStatus::BILL_CREATED);
|
|
|
|
throw new \ErrorException($errorMessage);
|
|
|
|
} else {
|
|
OnlineTransactionLoggerService::logs( null, $composed_data, $e->getMessage(), TransactionOnlineStatus::BILL_CREATED);
|
|
};
|
|
|
|
throw $e;
|
|
|
|
}
|
|
}
|
|
|
|
public function redirect($request)
|
|
{
|
|
try{
|
|
|
|
$response = $this->client->bill()->redirect($request);
|
|
|
|
OnlineTransactionLoggerService::logs($request['billplz']['id'], $request, $response, TransactionOnlineStatus::UPDATE_TRANSACTION_REDIRECT);
|
|
|
|
return $response;
|
|
|
|
} catch(\Exception $e){
|
|
OnlineTransactionLoggerService::logs($request['billplz']['id'], $request, $e->getMessage(), TransactionOnlineStatus::UPDATE_TRANSACTION_REDIRECT);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function webhook($request)
|
|
{
|
|
// $this->setCompany(Session::get('company'));
|
|
// $this->setupBillplzClient($this->company);
|
|
try {
|
|
$response = $this->client->webhook($request);
|
|
|
|
OnlineTransactionLoggerService::logs($request['billplz']['id'], $request, $response, TransactionOnlineStatus::UPDATE_TRANSACTION_CALLBACK);
|
|
|
|
return $response;
|
|
|
|
} catch (\Exception $e) {
|
|
OnlineTransactionLoggerService::logs($request['billplz']['id'], $request, $e->getMessage(), TransactionOnlineStatus::UPDATE_TRANSACTION_CALLBACK);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function getTransactions($date)
|
|
{
|
|
$arrahnTransactions = $this->getArrahnTransactions(['date' => $date]);
|
|
$billplzID = collect($arrahnTransactions)->pluck('billplz_id')->unique()->values();
|
|
|
|
$billplzTransactions = collect($billplzID)->map(function ($billId) {
|
|
try {
|
|
return $this->client->transaction()->get($billId)->toArray();
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
})
|
|
->filter(function ($transaction) {
|
|
return $transaction !== [];
|
|
})
|
|
->map(function ($data) {
|
|
$latestTransaction = reset($data['transactions']) == false ? [] : reset($data['transactions']);
|
|
$billId = ['bill_id' => $data['bill_id']];
|
|
return array_merge($billId, $latestTransaction);
|
|
})
|
|
->keyBy('bill_id');
|
|
|
|
return $billplzTransactions;
|
|
}
|
|
|
|
public function getTransactionsByBillId($billId)
|
|
{
|
|
$billplzID = collect([$billId]);
|
|
|
|
$billplzTransactions = collect($billplzID)->map(function ($billId) {
|
|
try {
|
|
return $this->client->transaction()->get($billId)->toArray();
|
|
} catch (\Exception $e) {
|
|
return [];
|
|
}
|
|
})
|
|
->filter(function ($transaction) {
|
|
return $transaction !== [];
|
|
})
|
|
->map(function ($data) {
|
|
$latestTransaction = reset($data['transactions']) == false ? [] : reset($data['transactions']);
|
|
$billId = ['bill_id' => $data['bill_id']];
|
|
return array_merge($billId, $latestTransaction);
|
|
})
|
|
->keyBy('bill_id');
|
|
|
|
return $billplzTransactions;
|
|
}
|
|
|
|
public function getArrahnTransactions($queryData)
|
|
{
|
|
$query_all = [];
|
|
|
|
if(isset($queryData['date'])){
|
|
$pkb_query = Http::arrahn()->get('/api/transaction/online/query', ['date' => $queryData['date']])->json();
|
|
$koop_query = Http::arrahn_koop()->get('/api/transaction/online/query', ['date' => $queryData['date']])->json();
|
|
$query_all = array_merge($pkb_query,$koop_query);
|
|
}
|
|
|
|
if(isset($queryData['billId'])){
|
|
$pkb_query = Http::arrahn()->get('/api/transaction/online/query', ['billId' => $queryData['billId']])->json();
|
|
$koop_query = Http::arrahn_koop()->get('/api/transaction/online/query', ['billId' => $queryData['billId']])->json();
|
|
$query_all = array_merge($pkb_query,$koop_query);
|
|
}
|
|
|
|
return $query_all;
|
|
}
|
|
|
|
public function getBillplzTransactionReview($date)
|
|
{
|
|
$arrahnTransactions = $this->getArrahnTransactions(['date' => $date]);
|
|
|
|
// sort array by tarikh desc and masa key desc
|
|
array_multisort(array_column($arrahnTransactions, 'tarikh'), SORT_DESC, array_column($arrahnTransactions, 'masa'), SORT_DESC, $arrahnTransactions);
|
|
|
|
|
|
$arrahnTransactionsGroupedByBill = collect($arrahnTransactions)->groupBy('billplz_id');
|
|
$billplzID = $arrahnTransactionsGroupedByBill->keys();
|
|
$billplzTransactions = $this->getTransactions($date);
|
|
|
|
$merged = $billplzID->map(function ($billId) use ($arrahnTransactionsGroupedByBill, $billplzTransactions) {
|
|
return [
|
|
'bill_id' => $billId,
|
|
'arrahn_transactions' => $arrahnTransactionsGroupedByBill->get($billId)->toArray(),
|
|
'billplz_latest_transaction' => $billplzTransactions->get($billId),
|
|
];
|
|
});
|
|
|
|
|
|
$summarizedBillplzTransactions = collect($merged)->map(function ($data) {
|
|
$data['arrahn_transactions'] = collect($data['arrahn_transactions'])->map(function ($transaction) {
|
|
return[
|
|
'nokp' => $transaction['nokp'],
|
|
'norujukan' => $transaction['norujukan'],
|
|
'kodcaw' => $transaction['kodcaw'],
|
|
'total_payment' => $transaction['total_payment'],
|
|
'customer_name' => $transaction['customer_name'],
|
|
'status' => $transaction['status'],
|
|
'paid_at' => $transaction['paid_at'],
|
|
'tarikh_attempt_bayar' => $transaction['tarikh'],
|
|
'masa_attempt_bayar' => $transaction['masa'],
|
|
'portal' => $transaction['tagportal'] == 1 ? 'Arrahn Pay' : 'SPARE',
|
|
];
|
|
});
|
|
|
|
return $data;
|
|
});
|
|
|
|
return $summarizedBillplzTransactions;
|
|
}
|
|
|
|
public function getBillplzTransactionReviewByBillId($billId)
|
|
{
|
|
|
|
$arrahnTransactions = $this->getArrahnTransactions(['billId' => $billId]);
|
|
|
|
$billplzID = collect([$billId]);
|
|
$billplzTransactions = $this->getTransactionsByBillId($billId);
|
|
|
|
|
|
$merged = $billplzID->map(function ($billId) use ($billplzTransactions, $arrahnTransactions) {
|
|
return [
|
|
'bill_id' => $billId,
|
|
'arrahn_transactions' => $arrahnTransactions,
|
|
'billplz_latest_transaction' => $billplzTransactions->get($billId),
|
|
];
|
|
});
|
|
|
|
|
|
$summarizedBillplzTransactions = collect($merged)->map(function ($data) {
|
|
$data['arrahn_transactions'] = collect($data['arrahn_transactions'])->map(function ($transaction) {
|
|
return[
|
|
'nokp' => $transaction['nokp'],
|
|
'norujukan' => $transaction['norujukan'],
|
|
'kodcaw' => $transaction['kodcaw'],
|
|
'total_payment' => $transaction['total_payment'],
|
|
'customer_name' => $transaction['customer_name'],
|
|
'status' => $transaction['status'],
|
|
'paid_at' => $transaction['paid_at'],
|
|
'tarikh_attempt_bayar' => $transaction['tarikh'],
|
|
'masa_attempt_bayar' => $transaction['masa'],
|
|
'portal' => $transaction['tagportal'] == 1 ? 'Arrahn Pay' : 'SPARE',
|
|
];
|
|
});
|
|
|
|
return $data;
|
|
});
|
|
|
|
return $summarizedBillplzTransactions;
|
|
}
|
|
|
|
public function getTransactionByBillId($billId,$company)
|
|
{
|
|
$appEnvironment = config('app.env');
|
|
|
|
$billplzEnvironments = [
|
|
'PKB' => ($appEnvironment === 'production') ? config('services.billplz.production') : config('services.billplz.sandbox'),
|
|
'KOPKB' => ($appEnvironment === 'production') ? config('services.billplz.production_kopkb') : config('services.billplz.sandbox_kopkb'),
|
|
];
|
|
|
|
$billplzConfig = $appEnvironment === 'production'
|
|
? ($billplzEnvironments[$company] ?? config('services.billplz.production'))
|
|
: ($billplzEnvironments[$company] ?? config('services.billplz.sandbox'));
|
|
|
|
$client = Client::make($billplzConfig['api_key'], ($this->isBase64($billplzConfig['x_signature'])) ? $billplzConfig['x_signature'] : base64_encode($billplzConfig['x_signature']));
|
|
$client->useVersion('v4');
|
|
|
|
try {
|
|
return $client->bill()->transaction($billId)->toArray();
|
|
} catch (\Throwable $th) {
|
|
logger()->error('Error when querying billplz id : ' . $billId);
|
|
logger()->error($th->getMessage());
|
|
throw $th;
|
|
}
|
|
}
|
|
|
|
public function getBills($billIds)
|
|
{
|
|
return array_map(function($x){
|
|
try{
|
|
return $this->client->bill()->get($x)->toArray();
|
|
}catch(\Exception $e){
|
|
return [];
|
|
}
|
|
}, $billIds);
|
|
}
|
|
|
|
protected function setupBillplzClient($company)
|
|
{
|
|
$appEnvironment = config('app.env');
|
|
|
|
$billplzEnvironments = [
|
|
'PKB' => ($appEnvironment === 'production') ? config('services.billplz.production') : config('services.billplz.sandbox'),
|
|
'KOPKB' => ($appEnvironment === 'production') ? config('services.billplz.production_kopkb') : config('services.billplz.sandbox_kopkb'),
|
|
];
|
|
|
|
$billplzConfig = $appEnvironment === 'production'
|
|
? ($billplzEnvironments[$company] ?? config('services.billplz.production'))
|
|
: ($billplzEnvironments[$company] ?? config('services.billplz.sandbox'));
|
|
|
|
$client = Client::make($billplzConfig['api_key'], ($this->isBase64($billplzConfig['x_signature'])) ? $billplzConfig['x_signature'] : base64_encode($billplzConfig['x_signature']));
|
|
$client->useVersion('v4');
|
|
|
|
if ($appEnvironment !== 'production') {
|
|
$client->useSandbox();
|
|
}
|
|
|
|
$this->config = $billplzConfig;
|
|
$this->client = $client;
|
|
}
|
|
|
|
protected function setupUrls()
|
|
{
|
|
$this->callbackUrl = route('pay.callback');
|
|
$this->redirectUrl = ['redirect_url' => route('pay.paymentStatus')];
|
|
}
|
|
|
|
protected function isBase64($string) {
|
|
if($this->isBase64UrlSafe($string)){
|
|
return true;
|
|
}
|
|
|
|
if (preg_match('/^[A-Za-z0-9+\/=]+$/', $string)) {
|
|
return base64_encode(base64_decode($string, true)) === $string;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected function isBase64UrlSafe($string) {
|
|
// Convert URL-safe Base64 to standard Base64
|
|
$standardBase64 = str_replace(['-', '_'], ['+', '/'], $string);
|
|
|
|
// Add padding if necessary
|
|
$remainder = strlen($standardBase64) % 4;
|
|
if ($remainder > 0) {
|
|
$standardBase64 .= str_repeat('=', 4 - $remainder);
|
|
}
|
|
|
|
// Attempt to decode the string
|
|
$decoded = base64_decode($standardBase64, true);
|
|
|
|
return $decoded !== false; // Return true if it successfully decodes
|
|
}
|
|
}
|