validate([ 'start_date' => 'nullable|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'bank_account_num' => 'nullable|string|max:50', 'search' => 'nullable|string|max:100', 'per_page' => 'nullable|integer|min:1|max:100', 'page' => 'nullable|integer|min:1', ]); return $this->service->index($params); }, __('message.fetched')); } /** * 계좌 목록 (필터용) */ public function accounts(): JsonResponse { return ApiResponse::handle(function () { return $this->service->accounts(); }, __('message.fetched')); } /** * 잔액 요약 */ public function balanceSummary(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $params = $request->validate([ 'date' => 'nullable|date', ]); return $this->service->balanceSummary($params); }, __('message.fetched')); } // ========================================================================= // 분할 (Splits) // ========================================================================= /** * 거래 분할 조회 */ public function getSplits(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'unique_key' => 'required|string|max:500', ]); return $this->service->getSplits($validated['unique_key']); }, __('message.fetched')); } /** * 거래 분할 저장 */ public function saveSplits(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'unique_key' => 'required|string|max:500', 'items' => 'required|array|min:1', 'items.*.split_amount' => 'required|numeric', 'items.*.account_code' => 'nullable|string|max:20', 'items.*.account_name' => 'nullable|string|max:100', 'items.*.deduction_type' => 'nullable|string|max:20', 'items.*.evidence_name' => 'nullable|string|max:100', 'items.*.description' => 'nullable|string|max:500', 'items.*.memo' => 'nullable|string|max:500', 'items.*.bank_account_num' => 'nullable|string|max:50', 'items.*.trans_dt' => 'nullable|string|max:20', 'items.*.trans_date' => 'nullable|date', 'items.*.original_deposit' => 'nullable|numeric', 'items.*.original_withdraw' => 'nullable|numeric', 'items.*.summary' => 'nullable|string|max:500', ]); return $this->service->saveSplits($validated['unique_key'], $validated['items']); }, __('message.created')); } /** * 거래 분할 삭제 */ public function deleteSplits(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'unique_key' => 'required|string|max:500', ]); return $this->service->deleteSplits($validated['unique_key']); }, __('message.deleted')); } // ========================================================================= // 오버라이드 (Override) // ========================================================================= /** * 적요/분류 오버라이드 저장 */ public function saveOverride(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'unique_key' => 'required|string|max:500', 'modified_summary' => 'nullable|string|max:500', 'modified_cast' => 'nullable|string|max:100', ]); return $this->service->saveOverride( $validated['unique_key'], $validated['modified_summary'] ?? null, $validated['modified_cast'] ?? null ); }, __('message.updated')); } // ========================================================================= // 수동 입력 (Manual) // ========================================================================= /** * 수동 은행 거래 등록 */ public function storeManual(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'bank_account_num' => 'required|string|max:50', 'bank_code' => 'nullable|string|max:10', 'bank_name' => 'nullable|string|max:50', 'trans_date' => 'required|date', 'trans_time' => 'nullable|string|max:10', 'trans_dt' => 'nullable|string|max:20', 'deposit' => 'nullable|numeric|min:0', 'withdraw' => 'nullable|numeric|min:0', 'balance' => 'nullable|numeric', 'summary' => 'nullable|string|max:500', 'cast' => 'nullable|string|max:100', 'memo' => 'nullable|string|max:500', 'trans_office' => 'nullable|string|max:100', 'account_code' => 'nullable|string|max:20', 'account_name' => 'nullable|string|max:100', 'client_code' => 'nullable|string|max:20', 'client_name' => 'nullable|string|max:200', ]); return $this->service->storeManual($validated); }, __('message.created')); } /** * 수동 은행 거래 수정 */ public function updateManual(Request $request, int $id): JsonResponse { return ApiResponse::handle(function () use ($request, $id) { $validated = $request->validate([ 'deposit' => 'nullable|numeric|min:0', 'withdraw' => 'nullable|numeric|min:0', 'balance' => 'nullable|numeric', 'summary' => 'nullable|string|max:500', 'cast' => 'nullable|string|max:100', 'memo' => 'nullable|string|max:500', 'account_code' => 'nullable|string|max:20', 'account_name' => 'nullable|string|max:100', 'client_code' => 'nullable|string|max:20', 'client_name' => 'nullable|string|max:200', ]); return $this->service->updateManual($id, $validated); }, __('message.updated')); } /** * 수동 은행 거래 삭제 */ public function destroyManual(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { return $this->service->destroyManual($id); }, __('message.deleted')); } // ========================================================================= // 분개 (Journal Entries) // ========================================================================= /** * 은행 거래 분개 조회 */ public function getJournalEntries(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { $sourceKey = "barobill_bank_{$id}"; return $this->journalSyncService->getForSource( JournalEntry::SOURCE_BAROBILL_BANK, $sourceKey ) ?? ['items' => []]; }, __('message.fetched')); } /** * 은행 거래 분개 저장 */ public function storeJournalEntries(Request $request, int $id): JsonResponse { return ApiResponse::handle(function () use ($request, $id) { $validated = $request->validate([ 'items' => 'required|array|min:1', 'items.*.side' => 'required|in:debit,credit', 'items.*.account_code' => 'required|string|max:20', 'items.*.account_name' => 'nullable|string|max:100', 'items.*.debit_amount' => 'required|integer|min:0', 'items.*.credit_amount' => 'required|integer|min:0', 'items.*.vendor_name' => 'nullable|string|max:200', 'items.*.memo' => 'nullable|string|max:500', ]); $bankTx = \App\Models\Barobill\BarobillBankTransaction::find($id); if (! $bankTx) { throw new \Illuminate\Database\Eloquent\ModelNotFoundException; } $entryDate = $bankTx->trans_date ?? now()->format('Y-m-d'); $sourceKey = "barobill_bank_{$id}"; return $this->journalSyncService->saveForSource( JournalEntry::SOURCE_BAROBILL_BANK, $sourceKey, $entryDate, "바로빌 은행거래 분개 (#{$id})", $validated['items'], ); }, __('message.created')); } /** * 은행 거래 분개 삭제 */ public function deleteJournalEntries(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { $sourceKey = "barobill_bank_{$id}"; return $this->journalSyncService->deleteForSource( JournalEntry::SOURCE_BAROBILL_BANK, $sourceKey ); }, __('message.deleted')); } }