validate([ 'start_date' => 'nullable|date', 'end_date' => 'nullable|date|after_or_equal:start_date', 'card_num' => 'nullable|string|max:50', 'search' => 'nullable|string|max:100', 'include_hidden' => 'nullable|boolean', 'per_page' => 'nullable|integer|min:1|max:100', 'page' => 'nullable|integer|min:1', ]); return $this->service->index($params); }, __('message.fetched')); } /** * 단일 카드 거래 상세 */ public function show(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { $tx = $this->service->show($id); if (! $tx) { throw new \Illuminate\Database\Eloquent\ModelNotFoundException; } return $tx; }, __('message.fetched')); } /** * 카드 번호 목록 (필터용) */ public function cardNumbers(): JsonResponse { return ApiResponse::handle(function () { return $this->service->cardNumbers(); }, __('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.*.split_supply_amount' => 'nullable|numeric', 'items.*.split_tax' => 'nullable|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.*.card_num' => 'nullable|string|max:50', 'items.*.use_dt' => 'nullable|string|max:20', 'items.*.use_date' => 'nullable|date', 'items.*.approval_num' => 'nullable|string|max:50', 'items.*.original_amount' => 'nullable|numeric', 'items.*.merchant_name' => 'nullable|string|max:200', ]); 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')); } // ========================================================================= // 수동 입력 (Manual) // ========================================================================= /** * 수동 카드 거래 등록 */ public function storeManual(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $validated = $request->validate([ 'card_num' => 'required|string|max:50', 'card_company' => 'nullable|string|max:10', 'card_company_name' => 'nullable|string|max:50', 'use_dt' => 'required|string|max:20', 'use_date' => 'required|date', 'use_time' => 'nullable|string|max:10', 'approval_num' => 'nullable|string|max:50', 'approval_type' => 'nullable|string|max:10', 'approval_amount' => 'required|numeric', 'tax' => 'nullable|numeric', 'service_charge' => 'nullable|numeric', 'merchant_name' => 'required|string|max:200', 'merchant_biz_num' => 'nullable|string|max:20', 'account_code' => 'nullable|string|max:20', 'account_name' => 'nullable|string|max:100', 'deduction_type' => 'nullable|string|max:20', 'evidence_name' => 'nullable|string|max:100', 'description' => 'nullable|string|max:500', 'memo' => 'nullable|string|max:500', ]); 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([ 'approval_amount' => 'nullable|numeric', 'tax' => 'nullable|numeric', 'merchant_name' => 'nullable|string|max:200', 'account_code' => 'nullable|string|max:20', 'account_name' => 'nullable|string|max:100', 'deduction_type' => 'nullable|string|max:20', 'description' => 'nullable|string|max:500', 'memo' => 'nullable|string|max:500', ]); 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')); } // ========================================================================= // 숨김/복원 (Hide/Restore) // ========================================================================= /** * 카드 거래 숨김 */ public function hide(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { return $this->service->hide($id); }, __('message.updated')); } /** * 카드 거래 숨김 복원 */ public function restore(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { return $this->service->restore($id); }, __('message.updated')); } /** * 숨겨진 거래 목록 */ public function hiddenList(Request $request): JsonResponse { return ApiResponse::handle(function () use ($request) { $params = $request->validate([ 'start_date' => 'nullable|date', 'end_date' => 'nullable|date|after_or_equal:start_date', ]); return $this->service->hiddenList($params); }, __('message.fetched')); } // ========================================================================= // 금액 수정 // ========================================================================= /** * 공급가액/세액 수정 */ public function updateAmount(Request $request, int $id): JsonResponse { return ApiResponse::handle(function () use ($request, $id) { $validated = $request->validate([ 'supply_amount' => 'required|numeric', 'tax' => 'required|numeric', 'modified_by_name' => 'nullable|string|max:50', ]); return $this->service->updateAmount($id, $validated); }, __('message.updated')); } // ========================================================================= // 분개 (Journal Entries) // ========================================================================= /** * 카드 거래 분개 조회 */ public function getJournalEntries(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { $sourceKey = "barobill_card_{$id}"; return $this->journalSyncService->getForSource( JournalEntry::SOURCE_BAROBILL_CARD, $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', ]); $tx = $this->service->show($id); if (! $tx) { throw new \Illuminate\Database\Eloquent\ModelNotFoundException; } $entryDate = $tx->use_date ?? now()->format('Y-m-d'); $sourceKey = "barobill_card_{$id}"; return $this->journalSyncService->saveForSource( JournalEntry::SOURCE_BAROBILL_CARD, $sourceKey, $entryDate, "바로빌 카드거래 분개 (#{$id})", $validated['items'], ); }, __('message.created')); } /** * 카드 거래 분개 삭제 */ public function deleteJournalEntries(int $id): JsonResponse { return ApiResponse::handle(function () use ($id) { $sourceKey = "barobill_card_{$id}"; return $this->journalSyncService->deleteForSource( JournalEntry::SOURCE_BAROBILL_CARD, $sourceKey ); }, __('message.deleted')); } }