validate($request, [ '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', 'per_page' => 'nullable|integer|min:1|max:100', 'page' => 'nullable|integer|min:1', 'branch_scope' => 'nullable|string|max:30', ]); try { $query = ShorakaFinancing::query(); foreach (['kodcaw', 'norujukan', 'state'] as $field) { if ($request->filled($field)) { $query->where($field, $request->input($field)); } } if ($request->filled('date_from')) { $query->where('created_at', '>=', $request->input('date_from') . ' 00:00:00'); } if ($request->filled('date_to')) { $query->where('created_at', '<', Carbon::parse($request->input('date_to'))->addDay()->format('Y-m-d') . ' 00:00:00'); } $records = $query->orderByDesc('created_at')->orderByDesc('id') ->paginate(min(100, max(1, (int) $request->input('per_page', 25)))); $payload = [ 'data' => $records->getCollection()->map(function (ShorakaFinancing $record) { return $this->present($record, false); })->values(), 'total' => $records->total(), 'current_page' => $records->currentPage(), 'per_page' => $records->perPage(), 'last_page' => $records->lastPage(), ]; if ($request->input('with_branches')) { $branches = ShorakaFinancing::query(); if ($request->filled('branch_scope')) { $branches->where('kodcaw', $request->input('branch_scope')); } $payload['branches'] = $branches->distinct()->orderBy('kodcaw')->pluck('kodcaw')->values(); } return response()->json($payload); } catch (QueryException $exception) { return $this->unavailable(); } } public function show(string $kodcaw, string $norujukan) { try { $record = $this->find($kodcaw, $norujukan); } catch (QueryException $exception) { return $this->unavailable(); } if (!$record) { return response()->json(['message' => 'Rekod pembiayaan tidak dijumpai.'], 404); } return response()->json(['data' => $this->present($record)]); } public function store(string $kodcaw, string $norujukan, Request $request) { $this->validate($request, [ 'teller' => 'required|string|max:255', 'action' => 'required|string|max:30', 'context' => 'present|array', ]); try { $existing = $this->find($kodcaw, $norujukan); if ($existing) { return response()->json(['created' => false, 'data' => $this->present($existing)]); } $record = ShorakaFinancing::create([ 'kodcaw' => $kodcaw, 'norujukan' => $norujukan, 'teller' => $request->input('teller'), 'action' => $request->input('action'), 'state' => 'WAITING', 'context' => $request->input('context'), ]); return response()->json(['created' => true, 'data' => $this->present($record)], 201); } catch (QueryException $exception) { try { $existing = $this->find($kodcaw, $norujukan); } catch (QueryException $again) { return $this->unavailable(); } if ($existing) { return response()->json(['created' => false, 'data' => $this->present($existing)]); } return $this->unavailable(); } } public function update(string $kodcaw, string $norujukan, Request $request) { $this->validate($request, [ 'state' => 'required|in:WAITING,PROCESSING,REVIEW,DONE', 'expected_state' => 'nullable|in:WAITING,PROCESSING,REVIEW,DONE', 'context' => 'nullable|array', ]); try { $record = $this->find($kodcaw, $norujukan); if (!$record) { return response()->json(['message' => 'Rekod pembiayaan tidak dijumpai.'], 404); } if ($request->filled('expected_state')) { $claimed = ShorakaFinancing::where('id', $record->id) ->where('state', $request->input('expected_state')) ->update(['state' => $request->input('state'), 'updated_at' => Carbon::now()]); return response()->json([ 'claimed' => $claimed === 1, 'data' => $this->present($record->fresh()), ]); } $fields = ['state' => $request->input('state')]; if ($request->exists('context')) { $fields['context'] = $request->input('context') ?? []; } $record->update($fields); return response()->json(['claimed' => true, 'data' => $this->present($record->fresh())]); } catch (QueryException $exception) { return $this->unavailable(); } } private function find(string $kodcaw, string $norujukan): ?ShorakaFinancing { return ShorakaFinancing::where('kodcaw', $kodcaw)->where('norujukan', $norujukan)->first(); } private function present(ShorakaFinancing $record, bool $withContext = true): array { $data = [ 'id' => $record->id, 'kodcaw' => $record->kodcaw, 'norujukan' => $record->norujukan, 'teller' => $record->teller, 'action' => $record->action, 'state' => $record->state, 'created_at' => optional($record->created_at)->toDateTimeString(), 'updated_at' => optional($record->updated_at)->toDateTimeString(), ]; if ($withContext) { $data['context'] = $record->context ?? []; } return $data; } private function unavailable() { return response()->json(['message' => 'Rekod pembiayaan Shoraka tidak tersedia.'], 503); } }