173 lines
8.5 KiB
PHP
173 lines
8.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\ShorakaFinancing;
|
|
use App\Services\ShorakaFinancingService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Throwable;
|
|
|
|
class ShorakaController extends Controller
|
|
{
|
|
public function index()
|
|
{
|
|
$records = ShorakaFinancing::where('kodcaw', Auth::user()->cawangan)
|
|
->orderByDesc('id')->limit(100)->get();
|
|
$cawangan_info = ['details_caw' => Auth::user()->cawangan, 'kodcaw' => Auth::user()->cawangan];
|
|
return view('shoraka.index', compact('records', 'cawangan_info'));
|
|
}
|
|
|
|
public function operasiIndex(Request $request)
|
|
{
|
|
abort_unless(in_array(Auth::user()->roles, ['operasi', 'pc', 'ppc'], true), 403);
|
|
$isOperasi = Auth::user()->roles === 'operasi';
|
|
$filters = $request->validate([
|
|
'kodcaw' => 'nullable|string|max:30',
|
|
'norujukan' => 'nullable|string|max:100',
|
|
'state' => 'nullable|in:WAITING,PROCESSING,REVIEW,DONE',
|
|
'date_from' => 'nullable|date_format:Y-m-d',
|
|
'date_to' => 'nullable|date_format:Y-m-d' . ($request->filled('date_from') ? '|after_or_equal:date_from' : ''),
|
|
]);
|
|
$branchQuery = ShorakaFinancing::select('kodcaw');
|
|
if (!$isOperasi) {
|
|
$branchQuery->where('kodcaw', Auth::user()->cawangan);
|
|
}
|
|
$branches = $branchQuery->distinct()->orderBy('kodcaw')->pluck('kodcaw');
|
|
$query = ShorakaFinancing::select('id', 'kodcaw', 'norujukan', 'teller', 'action', 'state', 'created_at', 'updated_at');
|
|
if (!$isOperasi) {
|
|
$query->where('kodcaw', Auth::user()->cawangan);
|
|
}
|
|
foreach (['kodcaw', 'norujukan', 'state'] as $field) {
|
|
if (!empty($filters[$field])) {
|
|
$query->where($field, $filters[$field]);
|
|
}
|
|
}
|
|
if (!empty($filters['date_from'])) {
|
|
$query->where('created_at', '>=', $filters['date_from'] . ' 00:00:00');
|
|
}
|
|
if (!empty($filters['date_to'])) {
|
|
$query->where('created_at', '<', \Carbon\Carbon::parse($filters['date_to'])->addDay()->format('Y-m-d') . ' 00:00:00');
|
|
}
|
|
$records = $query->orderByDesc('created_at')->orderByDesc('id')
|
|
->paginate(25)->appends($filters);
|
|
$cawangan_info = ['details_caw' => Auth::user()->cawangan, 'kodcaw' => Auth::user()->cawangan];
|
|
return view('shoraka.operasi', compact('records', 'branches', 'filters', 'isOperasi', 'cawangan_info'));
|
|
}
|
|
|
|
public function pcIndex(Request $request)
|
|
{
|
|
abort_unless(in_array(Auth::user()->roles, ['pc', 'ppc'], true), 403);
|
|
return $this->operasiIndex($request);
|
|
}
|
|
|
|
public function show(string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
$record = $service->local($norujukan);
|
|
$data = null;
|
|
$error = null;
|
|
try {
|
|
$data = $service->api()->get($service->url($norujukan))->throw()->json()['data'];
|
|
} catch (Throwable $exception) {
|
|
$error = 'Maklumat Shoraka tidak dapat diambil. Bayaran dan SAG masih ditahan.';
|
|
}
|
|
$cawangan_info = ['details_caw' => Auth::user()->cawangan, 'kodcaw' => Auth::user()->cawangan];
|
|
return view('shoraka.show', compact('norujukan', 'record', 'data', 'error', 'cawangan_info'));
|
|
}
|
|
|
|
public function poll(Request $request, string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
$record = $service->local($norujukan);
|
|
abort_unless($record && $record->teller === Auth::user()->name && $record->action === 'gadai', 403);
|
|
if ($record->state === 'DONE') {
|
|
return response()->json(['state' => 'done', 'redirect' => route('customer_info')]);
|
|
}
|
|
abort_unless(!empty($record->context['temporary_gadai']), 409);
|
|
if ($record->state === 'REVIEW') {
|
|
return response()->json(['state' => 'failed', 'message' => 'Penyelesaian memerlukan semakan operasi. Jangan ulang bayaran.']);
|
|
}
|
|
if ($record->state === 'PROCESSING') {
|
|
return response()->json(['state' => 'pending']);
|
|
}
|
|
try {
|
|
$data = $service->api()->get($service->url($norujukan))->throw()->json()['data'];
|
|
$order = $data['order'] ?? null;
|
|
if ($order && !empty($order['order_id']) && ($order['status'] ?? '') !== 'Cancelled') {
|
|
$service->api()->post($service->url($norujukan, '/refresh'))->throw();
|
|
$data = $service->api()->get($service->url($norujukan))->throw()->json()['data'];
|
|
$order = $data['order'] ?? null;
|
|
}
|
|
$status = $order['status'] ?? null;
|
|
if (in_array($status, ['Cancelled', 'FAILED', 'UNKNOWN'], true) || !$order) {
|
|
return response()->json(['state' => 'failed', 'message' => !empty($data['simulation'])
|
|
? 'Simulasi gagal berjaya diuji. Tiada gadaian atau marhun disimpan dan tiada bayaran diproses.'
|
|
: 'Transaksi gagal atau hasil penghantaran belum dapat dipastikan. Hubungi operasi; jangan hantar semula.']);
|
|
}
|
|
if (!empty($data['can_complete'])) {
|
|
if ($request->input('progress') === 'check') {
|
|
return response()->json(['state' => 'ready']);
|
|
}
|
|
$result = $service->finish($request, $norujukan);
|
|
return response()->json(['state' => 'done', 'redirect' => $result->getTargetUrl()]);
|
|
}
|
|
if ($status === 'Completed') {
|
|
return response()->json(['state' => 'failed', 'message' => 'Komoditi selesai tetapi maklumat gadaian belum dapat disahkan. Hubungi operasi.']);
|
|
}
|
|
return response()->json(['state' => 'pending']);
|
|
} catch (Throwable $exception) {
|
|
if ($record->fresh()->state === 'REVIEW') {
|
|
return response()->json(['state' => 'failed', 'message' => 'Penyelesaian memerlukan semakan operasi. Jangan ulang bayaran.']);
|
|
}
|
|
if ($exception instanceof \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface
|
|
&& $exception->getStatusCode() >= 400 && $exception->getStatusCode() < 500) {
|
|
return response()->json(['state' => 'failed', 'message' => $exception->getMessage()]);
|
|
}
|
|
if ($exception instanceof \Illuminate\Http\Client\RequestException
|
|
&& in_array($exception->response->status(), [404, 409], true)) {
|
|
return response()->json(['state' => 'failed', 'message' => 'Maklumat transaksi tidak dapat disahkan. Hubungi operasi; jangan hantar semula.']);
|
|
}
|
|
// Connection loss is not proof of a failed commodity trade.
|
|
return response()->json(['state' => 'pending']);
|
|
}
|
|
}
|
|
|
|
public function submit(string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
$record = $service->local($norujukan);
|
|
abort_unless($record && $record->teller === Auth::user()->name, 403);
|
|
$response = $service->api()->post($service->url($norujukan, '/submit'));
|
|
return redirect()->route('shoraka.show', compact('norujukan'))
|
|
->with('shoraka_message', $response->successful()
|
|
? 'Order dihantar. Semak status sebelum menyelesaikan pembiayaan.'
|
|
: (($response->json()['message'] ?? null) ?: 'Order belum berjaya. Semak status sebelum cuba semula.'));
|
|
}
|
|
|
|
public function refresh(string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
try {
|
|
$response = $service->api()->post($service->url($norujukan, '/refresh'));
|
|
$message = $response->successful() ? 'Status dikemas kini.'
|
|
: (($response->json()['message'] ?? null) ?: 'Status tidak dapat dikemas kini.');
|
|
} catch (Throwable $exception) {
|
|
$message = 'Sambungan terganggu. Jangan hantar order semula.';
|
|
}
|
|
return redirect()->route('shoraka.show', compact('norujukan'))->with('shoraka_message', $message);
|
|
}
|
|
|
|
public function finish(Request $request, string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
return $service->finish($request, $norujukan);
|
|
}
|
|
|
|
public function certificate(string $norujukan, ShorakaFinancingService $service)
|
|
{
|
|
$response = $service->api()->get($service->url($norujukan, '/certificate'))->throw();
|
|
abort_unless(substr($response->body(), 0, 5) === '%PDF-', 502);
|
|
return response($response->body(), 200, [
|
|
'Content-Type' => 'application/pdf',
|
|
'Content-Disposition' => 'attachment; filename="sijil-shoraka.pdf"',
|
|
'Cache-Control' => 'private, no-store',
|
|
]);
|
|
}
|
|
}
|