From 691bf200c8eada74e48e0e3d9156dc5a2865c735 Mon Sep 17 00:00:00 2001 From: kent Date: Fri, 26 Dec 2025 15:47:24 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20I-6=20=EC=9D=BC=EC=9D=BC=20=EC=83=9D?= =?UTF-8?q?=EC=82=B0=ED=98=84=ED=99=A9=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DailyReportController: 일일 리포트 조회 API - DailyReportService: 생산현황 집계 로직 - Swagger 문서화 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../Api/V1/DailyReportController.php | 61 ++++++ app/Services/DailyReportService.php | 161 +++++++++++++++ app/Swagger/v1/DailyReportApi.php | 183 ++++++++++++++++++ 3 files changed, 405 insertions(+) create mode 100644 app/Http/Controllers/Api/V1/DailyReportController.php create mode 100644 app/Services/DailyReportService.php create mode 100644 app/Swagger/v1/DailyReportApi.php diff --git a/app/Http/Controllers/Api/V1/DailyReportController.php b/app/Http/Controllers/Api/V1/DailyReportController.php new file mode 100644 index 0000000..41811ce --- /dev/null +++ b/app/Http/Controllers/Api/V1/DailyReportController.php @@ -0,0 +1,61 @@ +validate([ + 'date' => 'nullable|date', + ]); + + return $this->service->noteReceivables($params); + }, __('message.fetched')); + } + + /** + * 일별 계좌 현황 조회 + */ + public function dailyAccounts(Request $request): JsonResponse + { + return ApiResponse::handle(function () use ($request) { + $params = $request->validate([ + 'date' => 'nullable|date', + ]); + + return $this->service->dailyAccounts($params); + }, __('message.fetched')); + } + + /** + * 일일 보고서 요약 통계 + */ + public function summary(Request $request): JsonResponse + { + return ApiResponse::handle(function () use ($request) { + $params = $request->validate([ + 'date' => 'nullable|date', + ]); + + return $this->service->summary($params); + }, __('message.fetched')); + } +} diff --git a/app/Services/DailyReportService.php b/app/Services/DailyReportService.php new file mode 100644 index 0000000..252956e --- /dev/null +++ b/app/Services/DailyReportService.php @@ -0,0 +1,161 @@ +tenantId(); + $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today(); + + // 수취어음 중 보관중 상태인 것만 조회 (만기일 기준) + $bills = Bill::where('tenant_id', $tenantId) + ->where('bill_type', 'received') + ->where('status', 'stored') + ->where('maturity_date', '>=', $date->copy()->startOfDay()) + ->orderBy('maturity_date', 'asc') + ->get(); + + return $bills->map(function ($bill) { + return [ + 'id' => (string) $bill->id, + 'content' => "(수취어음) {$bill->display_client_name} - {$bill->bill_number}", + 'current_balance' => (float) $bill->amount, + 'issue_date' => $bill->issue_date?->format('Y-m-d'), + 'due_date' => $bill->maturity_date?->format('Y-m-d'), + ]; + })->values()->toArray(); + } + + /** + * 일별 계좌 현황 조회 + */ + public function dailyAccounts(array $params): array + { + $tenantId = $this->tenantId(); + $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today(); + $startOfMonth = $date->copy()->startOfMonth(); + $endOfDay = $date->copy()->endOfDay(); + + // 활성 계좌 목록 + $accounts = BankAccount::where('tenant_id', $tenantId) + ->where('status', 'active') + ->orderBy('is_primary', 'desc') + ->orderBy('bank_name', 'asc') + ->get(); + + $result = []; + + foreach ($accounts as $account) { + // 전월 이월: 이번 달 1일 이전까지의 누적 잔액 + $carryoverDeposits = Deposit::where('tenant_id', $tenantId) + ->where('bank_account_id', $account->id) + ->where('deposit_date', '<', $startOfMonth) + ->sum('amount'); + + $carryoverWithdrawals = Withdrawal::where('tenant_id', $tenantId) + ->where('bank_account_id', $account->id) + ->where('withdrawal_date', '<', $startOfMonth) + ->sum('amount'); + + $carryover = $carryoverDeposits - $carryoverWithdrawals; + + // 당일 수입 (입금) + $income = Deposit::where('tenant_id', $tenantId) + ->where('bank_account_id', $account->id) + ->whereBetween('deposit_date', [$startOfMonth, $endOfDay]) + ->sum('amount'); + + // 당일 지출 (출금) + $expense = Withdrawal::where('tenant_id', $tenantId) + ->where('bank_account_id', $account->id) + ->whereBetween('withdrawal_date', [$startOfMonth, $endOfDay]) + ->sum('amount'); + + // 잔액 = 전월이월 + 수입 - 지출 + $balance = $carryover + $income - $expense; + + // 매칭 상태: Deposit과 Withdrawal 금액이 일치하면 matched + $matchStatus = abs($income - $expense) < 0.01 ? 'matched' : 'unmatched'; + + $result[] = [ + 'id' => (string) $account->id, + 'category' => "{$account->bank_name} {$account->getMaskedAccountNumber()}", + 'match_status' => $matchStatus, + 'carryover' => (float) $carryover, + 'income' => (float) $income, + 'expense' => (float) $expense, + 'balance' => (float) $balance, + 'currency' => 'KRW', // 현재는 KRW만 지원 + ]; + } + + return $result; + } + + /** + * 일일 보고서 요약 통계 + */ + public function summary(array $params): array + { + $tenantId = $this->tenantId(); + $date = isset($params['date']) ? Carbon::parse($params['date']) : Carbon::today(); + + // 어음 합계 + $noteReceivableTotal = Bill::where('tenant_id', $tenantId) + ->where('bill_type', 'received') + ->where('status', 'stored') + ->where('maturity_date', '>=', $date->copy()->startOfDay()) + ->sum('amount'); + + // 계좌별 현황 + $dailyAccounts = $this->dailyAccounts($params); + + // 통화별 합계 + $krwTotal = collect($dailyAccounts) + ->where('currency', 'KRW') + ->reduce(function ($carry, $item) { + return [ + 'carryover' => $carry['carryover'] + $item['carryover'], + 'income' => $carry['income'] + $item['income'], + 'expense' => $carry['expense'] + $item['expense'], + 'balance' => $carry['balance'] + $item['balance'], + ]; + }, ['carryover' => 0, 'income' => 0, 'expense' => 0, 'balance' => 0]); + + $usdTotal = collect($dailyAccounts) + ->where('currency', 'USD') + ->reduce(function ($carry, $item) { + return [ + 'carryover' => $carry['carryover'] + $item['carryover'], + 'income' => $carry['income'] + $item['income'], + 'expense' => $carry['expense'] + $item['expense'], + 'balance' => $carry['balance'] + $item['balance'], + ]; + }, ['carryover' => 0, 'income' => 0, 'expense' => 0, 'balance' => 0]); + + return [ + 'date' => $date->format('Y-m-d'), + 'day_of_week' => $date->locale('ko')->dayName, + 'note_receivable_total' => (float) $noteReceivableTotal, + 'foreign_currency_total' => (float) $usdTotal['balance'], + 'cash_asset_total' => (float) $krwTotal['balance'], + 'krw_totals' => $krwTotal, + 'usd_totals' => $usdTotal, + ]; + } +} diff --git a/app/Swagger/v1/DailyReportApi.php b/app/Swagger/v1/DailyReportApi.php new file mode 100644 index 0000000..4366ad6 --- /dev/null +++ b/app/Swagger/v1/DailyReportApi.php @@ -0,0 +1,183 @@ +