216 lines
8.3 KiB
PHP
216 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Http\Controllers\GadaianController;
|
|
use App\Http\Controllers\AliranTunaiController;
|
|
use App\Events\Dashboard\GadaiNotify;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Throwable;
|
|
|
|
class ShorakaFinancingService
|
|
{
|
|
public function ensureReady(): void
|
|
{
|
|
$response = $this->api()->get(rtrim(config('api.url'), '/') . '/api/shoraka/readiness')->throw()->json();
|
|
abort_unless(!empty($response['ready']), 503, 'Shoraka belum dikonfigurasi. Pembiayaan baharu ditahan.');
|
|
}
|
|
|
|
public function api()
|
|
{
|
|
return Http::withOptions(['verify' => config('app.api_verify')])
|
|
->acceptJson()->timeout(75);
|
|
}
|
|
|
|
public function url(string $reference, string $suffix = ''): string
|
|
{
|
|
return rtrim(config('api.url'), '/') . '/api/shoraka/gadai/'
|
|
. rawurlencode(Auth::user()->cawangan) . '/' . rawurlencode($reference) . $suffix;
|
|
}
|
|
|
|
public function hasOrder(string $reference): bool
|
|
{
|
|
$snapshot = $this->snapshot($reference);
|
|
return !empty($snapshot['order']);
|
|
}
|
|
|
|
public function snapshot(string $reference): array
|
|
{
|
|
$response = $this->api()->get($this->url($reference));
|
|
if ($response->status() === 404) {
|
|
return [];
|
|
}
|
|
if ($response->serverError()) {
|
|
abort(503, 'Shoraka belum dikonfigurasi. Pembiayaan baharu ditahan.');
|
|
}
|
|
$response->throw();
|
|
return $response->json()['data'] ?? [];
|
|
}
|
|
|
|
public function listForBranch(string $branch)
|
|
{
|
|
$response = $this->api()->get(rtrim(config('api.url'), '/') . '/api/shoraka/transactions', [
|
|
'kodcaw' => $branch,
|
|
'per_page' => 100,
|
|
])->throw()->json();
|
|
return collect($response['data'] ?? []);
|
|
}
|
|
|
|
public function search(array $filters, ?string $onlyBranch): array
|
|
{
|
|
$query = [
|
|
'per_page' => 25,
|
|
'page' => max(1, (int) request()->input('page', 1)),
|
|
'with_branches' => 1,
|
|
];
|
|
if ($onlyBranch) {
|
|
$query['kodcaw'] = $onlyBranch;
|
|
$query['branch_scope'] = $onlyBranch;
|
|
} elseif (!empty($filters['kodcaw'])) {
|
|
$query['kodcaw'] = $filters['kodcaw'];
|
|
}
|
|
foreach (['norujukan', 'status', 'date_from', 'date_to'] as $field) {
|
|
if (!empty($filters[$field])) {
|
|
$query[$field] = $filters[$field];
|
|
}
|
|
}
|
|
$response = $this->api()->get(rtrim(config('api.url'), '/') . '/api/shoraka/transactions', $query)->throw()->json();
|
|
$items = collect($response['data'] ?? []);
|
|
$records = new LengthAwarePaginator(
|
|
$items,
|
|
(int) ($response['total'] ?? 0),
|
|
(int) ($response['per_page'] ?? 25),
|
|
(int) ($response['current_page'] ?? 1),
|
|
['path' => request()->url(), 'query' => request()->query()]
|
|
);
|
|
return [$records, collect($response['branches'] ?? [])];
|
|
}
|
|
|
|
public function hold(Request $request, string $reference, string $action, array $extra = [])
|
|
{
|
|
if ($this->hasOrder($reference)) {
|
|
return $this->failed($request, 'Order Shoraka telah dihantar. Jangan hantar semula.');
|
|
}
|
|
|
|
$context = array_merge($request->except(['_token', 'password']), $extra, ['action' => $action]);
|
|
try {
|
|
$response = $this->api()->post($this->url($reference, '/submit'), [
|
|
'teller' => Auth::user()->name,
|
|
]);
|
|
} catch (Throwable $exception) {
|
|
if ($this->hasOrder($reference)) {
|
|
return $this->failed($request, 'Order Shoraka telah dihantar. Jangan hantar semula.');
|
|
}
|
|
return $this->failed($request, 'Order Shoraka tidak berjaya dihantar. Gadaian tidak dihantar.');
|
|
}
|
|
|
|
if (!$response->successful()) {
|
|
$message = $response->json()['message'] ?? ($this->hasOrder($reference)
|
|
? 'Order Shoraka telah dihantar. Jangan hantar semula.'
|
|
: 'Order Shoraka tidak berjaya dihantar. Gadaian tidak dihantar.');
|
|
return $this->failed($request, $message);
|
|
}
|
|
|
|
$snapshot = $this->waitUntilCompleted($reference);
|
|
$status = $snapshot['order']['status'] ?? null;
|
|
if ($status !== 'Completed') {
|
|
return $this->failed($request, 'Pengesahan Shoraka belum Completed. Jangan hantar semula.');
|
|
}
|
|
if (empty($snapshot['can_complete'])
|
|
|| (array_key_exists('pinjaman', $context)
|
|
&& number_format((float) $context['pinjaman'], 2, '.', '')
|
|
!== number_format((float) ($snapshot['order_amount'] ?? 0), 2, '.', ''))) {
|
|
return $this->failed($request, 'Amaun pembiayaan berubah. Bayaran tidak diproses.');
|
|
}
|
|
|
|
return $this->complete($request, $reference, $context);
|
|
}
|
|
|
|
private function waitUntilCompleted(string $reference): array
|
|
{
|
|
set_time_limit(150);
|
|
$deadline = microtime(true) + 120;
|
|
$snapshot = [];
|
|
do {
|
|
try {
|
|
$this->api()->post($this->url($reference, '/refresh'))->throw();
|
|
$snapshot = $this->snapshot($reference);
|
|
} catch (Throwable $exception) {
|
|
$snapshot = [];
|
|
}
|
|
$status = $snapshot['order']['status'] ?? null;
|
|
if ($status === 'Completed' || in_array($status, ['Cancelled', 'FAILED', 'UNKNOWN'], true)) {
|
|
return $snapshot;
|
|
}
|
|
if (microtime(true) >= $deadline) {
|
|
return $snapshot;
|
|
}
|
|
sleep(2);
|
|
} while (true);
|
|
}
|
|
|
|
private function complete(Request $request, string $reference, array $context)
|
|
{
|
|
$branch = Auth::user()->cawangan;
|
|
$saved = new Request($context);
|
|
$saved->setLaravelSession($request->session());
|
|
if (($context['action'] ?? null) === 'gadai') {
|
|
return app(GadaianController::class)->completeShorakaFinancing($saved);
|
|
}
|
|
if (!empty($context['update_history'])) {
|
|
$this->api()->put(rtrim(config('api.url'), '/') . '/api/gadai/updatehistory/'
|
|
. rawurlencode($branch) . '/' . rawurlencode($reference), [
|
|
'historygadaian' => $saved->norujukan,
|
|
'jenistebus' => $saved->jenistebus,
|
|
])->throw();
|
|
}
|
|
$cash = app(AliranTunaiController::class);
|
|
if (($context['action'] ?? null) === 'autotawarruq') {
|
|
$cash->alirantunaiTebusAutoTawarruq($saved);
|
|
} else {
|
|
$cash->alirantunaiTebus($saved);
|
|
}
|
|
event(new \App\Events\Dashboard\TebusNotify('lulus', $branch));
|
|
event(new GadaiNotify('lulus', $branch));
|
|
return redirect()->route('customer_info');
|
|
}
|
|
|
|
public function printData(string $reference): ?array
|
|
{
|
|
$response = $this->api()->get($this->url($reference))->throw()->json()['data'];
|
|
$order = $response['order'] ?? null;
|
|
if (!$order) {
|
|
return null;
|
|
}
|
|
abort_unless(!empty($response['can_complete']), 409, 'SAG ditahan: Shoraka belum Completed.');
|
|
$details = $response['details'] ?? [];
|
|
$certificateDetails = $details['certificateDetails1'] ?? '';
|
|
if (is_array($certificateDetails)) {
|
|
$certificateDetails = $certificateDetails[0] ?? '';
|
|
}
|
|
$certificate = is_string($certificateDetails) ? trim(explode('|', $certificateDetails)[0]) : '';
|
|
abort_unless($certificate !== '' && isset($details['unit'], $details['volume'], $details['commodityType']),
|
|
409, 'Maklumat sijil belum lengkap. Semak status Shoraka dahulu.');
|
|
return [
|
|
'komoditi' => ['no_sijil' => $certificate],
|
|
'product' => [
|
|
'kodproduk' => $details['commodityType'],
|
|
'description' => $details['commodityType'] === '000-COPPER' ? 'Copper' : 'Plastic resin',
|
|
'unit' => $details['unit'],
|
|
],
|
|
'kuantiti' => $details['volume'],
|
|
];
|
|
}
|
|
|
|
private function failed(Request $request, string $message)
|
|
{
|
|
if ($request->ajax() || $request->expectsJson()) {
|
|
abort(502, $message);
|
|
}
|
|
return redirect()->back()->with('error', $message);
|
|
}
|
|
}
|