month; $year = $date->year; return [ 'today_issue' => $this->getTodayIssue($date), 'monthly_expense' => $this->getMonthlyExpense($year, $month), 'card_management' => $this->getCardManagement($year, $month), 'entertainment' => $this->getEntertainment($year, $month), 'welfare' => $this->getWelfare($year, $month), 'receivable' => $this->getReceivable($year, $month), 'debt_collection' => $this->getDebtCollection(), ]; } /** * 오늘의 이슈 - 결재 대기 문서 */ protected function getTodayIssue(Carbon $date): array { $tenantId = $this->tenantId(); $pendingApprovals = Approval::where('tenant_id', $tenantId) ->pending() ->with(['form', 'drafter']) ->orderBy('drafted_at', 'desc') ->limit(10) ->get(); $categories = ['전체필터']; $items = []; foreach ($pendingApprovals as $approval) { $category = $approval->form?->name ?? '결재요청'; if (! in_array($category, $categories)) { $categories[] = $category; } $items[] = [ 'id' => (string) $approval->id, 'category' => $category, 'description' => $approval->title, 'requires_approval' => true, 'time' => $approval->drafted_at?->format('H:i') ?? '', ]; } return [ 'filter_options' => $categories, 'items' => $items, ]; } /** * 당월 예상 지출 내역 */ protected function getMonthlyExpense(int $year, int $month): array { $tenantId = $this->tenantId(); // 이번 달 예상 지출 합계 $expenses = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->selectRaw('transaction_type, SUM(amount) as total') ->groupBy('transaction_type') ->get() ->keyBy('transaction_type'); // 미지급 금액 $unpaidTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->where('payment_status', 'pending') ->sum('amount'); // 지급 완료 금액 $paidTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->where('payment_status', 'paid') ->sum('amount'); // 연체 금액 $overdueTotal = ExpectedExpense::where('tenant_id', $tenantId) ->where('expected_payment_date', '<', Carbon::today()) ->where('payment_status', 'pending') ->sum('amount'); $cards = [ ['id' => 'expense-1', 'label' => '이번 달 예상 지출', 'amount' => (float) ($unpaidTotal + $paidTotal)], ['id' => 'expense-2', 'label' => '미지급 금액', 'amount' => (float) $unpaidTotal], ['id' => 'expense-3', 'label' => '지급 완료', 'amount' => (float) $paidTotal], ['id' => 'expense-4', 'label' => '연체 금액', 'amount' => (float) $overdueTotal], ]; $checkPoints = []; if ($overdueTotal > 0) { $checkPoints[] = [ 'id' => 'expense-cp-1', 'type' => 'warning', 'message' => '연체 중인 지출이 있습니다.', 'highlight' => number_format($overdueTotal).'원', ]; } if ($unpaidTotal > $paidTotal * 2) { $checkPoints[] = [ 'id' => 'expense-cp-2', 'type' => 'info', 'message' => '미지급 금액이 지급 완료 금액보다 많습니다.', ]; } return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } /** * 카드/가지급금 관리 */ protected function getCardManagement(int $year, int $month): array { $tenantId = $this->tenantId(); // 가지급금 (suspense) $suspenseTotal = ExpectedExpense::where('tenant_id', $tenantId) ->where('transaction_type', 'suspense') ->where('payment_status', '!=', 'paid') ->sum('amount'); // 선급금 (advance) $advanceTotal = ExpectedExpense::where('tenant_id', $tenantId) ->where('transaction_type', 'advance') ->where('payment_status', '!=', 'paid') ->sum('amount'); // 이번 달 카드 사용액 (가상 - 실제로는 CardTransaction 등 필요) $monthlyCardUsage = ExpectedExpense::where('tenant_id', $tenantId) ->whereIn('transaction_type', ['suspense', 'advance']) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->sum('amount'); // 미정산 금액 $unsettledTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereIn('transaction_type', ['suspense', 'advance']) ->where('payment_status', 'pending') ->sum('amount'); $cards = [ ['id' => 'card-1', 'label' => '가지급금 잔액', 'amount' => (float) $suspenseTotal], ['id' => 'card-2', 'label' => '선급금 잔액', 'amount' => (float) $advanceTotal], ['id' => 'card-3', 'label' => '이번 달 카드 사용액', 'amount' => (float) $monthlyCardUsage], ['id' => 'card-4', 'label' => '미정산 금액', 'amount' => (float) $unsettledTotal], ]; $checkPoints = []; if ($suspenseTotal > 10000000) { $checkPoints[] = [ 'id' => 'card-cp-1', 'type' => 'warning', 'message' => '가지급금이 1,000만원을 초과했습니다.', 'highlight' => '정산이 필요합니다.', ]; } if ($unsettledTotal > 0) { $checkPoints[] = [ 'id' => 'card-cp-2', 'type' => 'info', 'message' => '미정산 금액이 '.number_format($unsettledTotal).'원 있습니다.', ]; } return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } /** * 접대비 현황 */ protected function getEntertainment(int $year, int $month): array { $tenantId = $this->tenantId(); // 실제로는 expense_category 등으로 접대비 분류 필요 // 현재는 기본값 반환 $monthlyTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->where('transaction_type', 'other') ->sum('amount'); $yearlyTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->where('transaction_type', 'other') ->sum('amount'); $cards = [ ['id' => 'ent-1', 'label' => '이번 달 접대비', 'amount' => (float) ($monthlyTotal * 0.1)], ['id' => 'ent-2', 'label' => '연간 접대비 누계', 'amount' => (float) ($yearlyTotal * 0.1)], ]; $checkPoints = []; // 접대비 한도 초과 경고 (예시) $limit = 5000000; // 월 500만원 한도 if ($monthlyTotal * 0.1 > $limit) { $checkPoints[] = [ 'id' => 'ent-cp-1', 'type' => 'error', 'message' => '접대비가 월 한도를 초과했습니다.', 'highlight' => number_format($limit).'원 초과', ]; } return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } /** * 복리후생비 현황 */ protected function getWelfare(int $year, int $month): array { $tenantId = $this->tenantId(); // 실제로는 expense_category 등으로 복리후생비 분류 필요 $monthlyTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->whereIn('transaction_type', ['salary', 'insurance']) ->sum('amount'); $salaryTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->where('transaction_type', 'salary') ->sum('amount'); $insuranceTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereMonth('expected_payment_date', $month) ->where('transaction_type', 'insurance') ->sum('amount'); $yearlyTotal = ExpectedExpense::where('tenant_id', $tenantId) ->whereYear('expected_payment_date', $year) ->whereIn('transaction_type', ['salary', 'insurance']) ->sum('amount'); $cards = [ ['id' => 'wf-1', 'label' => '이번 달 복리후생비', 'amount' => (float) $monthlyTotal], ['id' => 'wf-2', 'label' => '급여 지출', 'amount' => (float) $salaryTotal], ['id' => 'wf-3', 'label' => '보험료 지출', 'amount' => (float) $insuranceTotal], ['id' => 'wf-4', 'label' => '연간 복리후생비 누계', 'amount' => (float) $yearlyTotal], ]; $checkPoints = []; // 복리후생비 비율 경고 (예시) if ($monthlyTotal > 0 && $salaryTotal > 0) { $ratio = ($monthlyTotal / $salaryTotal) * 100; if ($ratio < 5 || $ratio > 20) { $checkPoints[] = [ 'id' => 'wf-cp-1', 'type' => 'warning', 'message' => '복리후생비 비율이 정상 범위(5~20%)를 벗어났습니다.', ]; } } return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } /** * 미수금 현황 */ protected function getReceivable(int $year, int $month): array { $tenantId = $this->tenantId(); // 총 미수금 (거래처별) $totalReceivable = Client::where('tenant_id', $tenantId) ->where('is_active', true) ->sum('outstanding_balance'); // 이번 달 입금 $monthlyDeposit = Deposit::where('tenant_id', $tenantId) ->whereYear('deposit_date', $year) ->whereMonth('deposit_date', $month) ->sum('amount'); // 오늘 입금 $todayDeposit = Deposit::where('tenant_id', $tenantId) ->whereDate('deposit_date', Carbon::today()) ->sum('amount'); // 연체 미수금 (credit_limit 초과 거래처) $overdueReceivable = Client::where('tenant_id', $tenantId) ->where('is_active', true) ->whereColumn('outstanding_balance', '>', 'credit_limit') ->sum('outstanding_balance'); $cards = [ [ 'id' => 'rcv-1', 'label' => '총 미수금', 'amount' => (float) $totalReceivable, 'sub_amount' => (float) $overdueReceivable, 'sub_label' => '한도초과', ], [ 'id' => 'rcv-2', 'label' => '이번 달 입금', 'amount' => (float) $monthlyDeposit, ], [ 'id' => 'rcv-3', 'label' => '오늘 입금', 'amount' => (float) $todayDeposit, ], [ 'id' => 'rcv-4', 'label' => '연체 미수금', 'amount' => (float) $overdueReceivable, ], ]; $checkPoints = []; // 한도 초과 거래처 $overdueClients = Client::where('tenant_id', $tenantId) ->where('is_active', true) ->whereColumn('outstanding_balance', '>', 'credit_limit') ->select('name', 'outstanding_balance') ->limit(3) ->get(); foreach ($overdueClients as $client) { $checkPoints[] = [ 'id' => 'rcv-cp-'.($client->id ?? uniqid()), 'type' => 'error', 'message' => $client->name.'의 미수금이 한도를 초과했습니다.', 'highlight' => '거래 주의가 필요합니다.', ]; } return [ 'cards' => $cards, 'check_points' => $checkPoints, 'has_detail_button' => true, 'detail_button_label' => '거래처별 미수금 현황', 'detail_button_path' => '/accounting/receivables-status', ]; } /** * 채권추심 현황 */ protected function getDebtCollection(): array { $tenantId = $this->tenantId(); // 추심중 건수 및 금액 $collectingData = BadDebt::where('tenant_id', $tenantId) ->collecting() ->selectRaw('COUNT(*) as count, SUM(debt_amount) as total') ->first(); // 법적조치 건수 및 금액 $legalData = BadDebt::where('tenant_id', $tenantId) ->legalAction() ->selectRaw('COUNT(*) as count, SUM(debt_amount) as total') ->first(); // 회수완료 금액 (이번 년도) $recoveredTotal = BadDebt::where('tenant_id', $tenantId) ->recovered() ->whereYear('closed_at', Carbon::now()->year) ->sum('debt_amount'); // 대손처리 금액 $badDebtTotal = BadDebt::where('tenant_id', $tenantId) ->badDebt() ->sum('debt_amount'); $cards = [ ['id' => 'debt-1', 'label' => '추심중', 'amount' => (float) ($collectingData->total ?? 0)], ['id' => 'debt-2', 'label' => '법적조치 진행', 'amount' => (float) ($legalData->total ?? 0)], ['id' => 'debt-3', 'label' => '올해 회수 완료', 'amount' => (float) $recoveredTotal], ['id' => 'debt-4', 'label' => '대손처리 금액', 'amount' => (float) $badDebtTotal], ]; $checkPoints = []; $collectingCount = $collectingData->count ?? 0; $legalCount = $legalData->count ?? 0; if ($collectingCount > 0) { $checkPoints[] = [ 'id' => 'debt-cp-1', 'type' => 'info', 'message' => '현재 추심 진행 중인 건이 '.$collectingCount.'건 있습니다.', ]; } if ($legalCount > 0) { $checkPoints[] = [ 'id' => 'debt-cp-2', 'type' => 'warning', 'message' => '법적조치 진행 중인 건이 '.$legalCount.'건 있습니다.', ]; } return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } }