ExpenseAccount::TYPE_WELFARE, '접대비' => ExpenseAccount::TYPE_ENTERTAINMENT, ]; /** * 전표 저장/수정 후 expense_accounts 동기화 * 복리후생비/접대비 계정과목이 포함된 lines → expense_accounts에 반영 */ protected function syncExpenseAccounts(JournalEntry $entry): void { $tenantId = $entry->tenant_id; // 1. 기존 이 전표에서 생성된 expense_accounts 삭제 ExpenseAccount::where('tenant_id', $tenantId) ->where('journal_entry_id', $entry->id) ->forceDelete(); // 2. 현재 lines 중 복리후생비/접대비 해당하는 것만 insert $lines = $entry->lines()->get(); foreach ($lines as $line) { $accountType = $this->getExpenseAccountType($line->account_name); if (! $accountType) { continue; } // 차변(debit)이 대변보다 큰 경우만 비용 발생으로 처리 $amount = $line->debit_amount - $line->credit_amount; if ($amount <= 0) { continue; } // source_type에 따라 payment_method 결정 $paymentMethod = match ($entry->source_type) { JournalEntry::SOURCE_CARD_TRANSACTION => ExpenseAccount::PAYMENT_CARD, default => ExpenseAccount::PAYMENT_TRANSFER, }; ExpenseAccount::create([ 'tenant_id' => $tenantId, 'account_type' => $accountType, 'sub_type' => null, 'expense_date' => $entry->entry_date, 'amount' => $amount, 'description' => $line->description ?? $entry->description, 'receipt_no' => null, 'vendor_id' => $line->trading_partner_id, 'vendor_name' => $line->trading_partner_name, 'payment_method' => $paymentMethod, 'card_no' => null, 'journal_entry_id' => $entry->id, 'journal_entry_line_id' => $line->id, ]); } } /** * 전표 삭제 시 expense_accounts 정리 */ protected function cleanupExpenseAccounts(int $tenantId, int $entryId): void { ExpenseAccount::where('tenant_id', $tenantId) ->where('journal_entry_id', $entryId) ->forceDelete(); } /** * 계정과목명에서 비용 유형 판별 */ private function getExpenseAccountType(string $accountName): ?string { foreach (self::$expenseAccountMap as $keyword => $type) { if (str_contains($accountName, $keyword)) { return $type; } } return null; } }