Files
sam-api/app/Traits/SyncsExpenseAccounts.php

99 lines
3.2 KiB
PHP
Raw Permalink Normal View History

<?php
namespace App\Traits;
use App\Models\Tenants\ExpenseAccount;
use App\Models\Tenants\JournalEntry;
/**
* 전표 저장/수정/삭제 expense_accounts 동기화 (복리후생비/접대비 CEO 대시보드)
*
* 사용처: GeneralJournalEntryService, JournalSyncService
*/
trait SyncsExpenseAccounts
{
/**
* 계정과목명 expense_accounts account_type 매핑
*/
private static array $expenseAccountMap = [
'복리후생비' => 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;
}
}