feat: [finance] 손익계산서 월별 조회 API + 리팩토링

- GET /api/v1/income-statement/monthly?year=2026&unit=won 추가
- buildSections 공통 로직 분리
- getAccountCodes, getFiscalYear 헬퍼 분리
This commit is contained in:
김보곤
2026-03-19 12:49:04 +09:00
parent ea5591c812
commit c68cf5dfcf
3 changed files with 96 additions and 32 deletions

View File

@@ -21,7 +21,7 @@ class IncomeStatementService extends Service
];
/**
* 손익계산서 조회
* 손익계산서 조회 (기간)
*/
public function data(array $params): array
{
@@ -33,17 +33,86 @@ public function data(array $params): array
$prevStartDate = date('Y-m-d', strtotime($startDate.' -1 year'));
$prevEndDate = date('Y-m-d', strtotime($endDate.' -1 year'));
$accountCodes = $this->getAccountCodes($tenantId);
$currentSums = $this->getAccountSums($tenantId, $startDate, $endDate);
$previousSums = $this->getAccountSums($tenantId, $prevStartDate, $prevEndDate);
$sections = $this->buildSections($accountCodes, $currentSums, $previousSums, $unit);
$accountCodes = DB::table('account_codes')
$currentYear = (int) date('Y', strtotime($endDate));
$fiscalYear = $this->getFiscalYear($currentYear);
return [
'period' => [
'current' => ['start' => $startDate, 'end' => $endDate, 'label' => "{$fiscalYear} (당)기"],
'previous' => ['start' => $prevStartDate, 'end' => $prevEndDate, 'label' => '제 '.($fiscalYear - 1).' (전)기'],
],
'unit' => $unit,
'sections' => $sections,
];
}
/**
* 손익계산서 월별 조회
*/
public function monthly(array $params): array
{
$tenantId = $this->tenantId();
$year = (int) ($params['year'] ?? now()->year);
$unit = $params['unit'] ?? 'won';
$accountCodes = $this->getAccountCodes($tenantId);
$months = [];
for ($m = 1; $m <= 12; $m++) {
$startDate = sprintf('%04d-%02d-01', $year, $m);
$endDate = date('Y-m-t', strtotime($startDate));
if (strtotime($startDate) > time()) {
break;
}
$sums = $this->getAccountSums($tenantId, $startDate, $endDate);
$sections = $this->buildSections($accountCodes, $sums, $sums, $unit, true);
$months[] = [
'month' => sprintf('%02d', $m),
'label' => $m.'월',
'sections' => $sections,
];
}
$fiscalYear = $this->getFiscalYear($year);
return [
'year' => $year,
'fiscal_year' => $fiscalYear,
'fiscal_label' => "{$fiscalYear}",
'unit' => $unit,
'months' => $months,
];
}
private function getAccountCodes(int $tenantId)
{
return DB::table('account_codes')
->where('tenant_id', $tenantId)
->where('is_active', true)
->whereIn('category', ['revenue', 'expense'])
->orderBy('sort_order')
->orderBy('code')
->get();
}
private function getFiscalYear(int $currentYear): int
{
return $currentYear - 2024; // 코드브릿지엑스 설립 2025-09-13, 1기 = 2025년
}
/**
* 섹션 조립 공통 로직
*/
private function buildSections($accountCodes, array $currentSums, array $previousSums, string $unit, bool $currentOnly = false): array
{
$sections = [];
$calcValues = [];
@@ -79,24 +148,17 @@ public function data(array $params): array
foreach ($relatedAccounts as $ac) {
$curDebit = $currentSums[$ac->code]['debit'] ?? 0;
$curCredit = $currentSums[$ac->code]['credit'] ?? 0;
$prevDebit = $previousSums[$ac->code]['debit'] ?? 0;
$prevCredit = $previousSums[$ac->code]['credit'] ?? 0;
$curAmount = $ac->category === 'revenue' ? ($curCredit - $curDebit) : ($curDebit - $curCredit);
if ($ac->category === 'revenue') {
$curAmount = $curCredit - $curDebit;
$prevAmount = $prevCredit - $prevDebit;
} else {
$curAmount = $curDebit - $curCredit;
$prevAmount = $prevDebit - $prevCredit;
$prevAmount = 0;
if (! $currentOnly) {
$prevDebit = $previousSums[$ac->code]['debit'] ?? 0;
$prevCredit = $previousSums[$ac->code]['credit'] ?? 0;
$prevAmount = $ac->category === 'revenue' ? ($prevCredit - $prevDebit) : ($prevDebit - $prevCredit);
}
if ($curAmount != 0 || $prevAmount != 0) {
$section['items'][] = [
'code' => $ac->code,
'name' => $ac->name,
'current' => $curAmount,
'previous' => $prevAmount,
];
$section['items'][] = ['code' => $ac->code, 'name' => $ac->name, 'current' => $curAmount, 'previous' => $prevAmount];
}
$currentTotal += $curAmount;
@@ -117,11 +179,8 @@ public function data(array $params): array
}
$divisor = match ($unit) {
'thousand' => 1000,
'million' => 1000000,
default => 1,
'thousand' => 1000, 'million' => 1000000, default => 1
};
if ($divisor > 1) {
foreach ($sections as &$s) {
$s['current_amount'] = (int) round($s['current_amount'] / $divisor);
@@ -135,18 +194,7 @@ public function data(array $params): array
unset($s);
}
$currentYear = (int) date('Y', strtotime($endDate));
$baseYear = 2024; // 코드브릿지엑스 설립 2025-09-13, 1기 = 2025년
$fiscalYear = $currentYear - $baseYear;
return [
'period' => [
'current' => ['start' => $startDate, 'end' => $endDate, 'label' => "{$fiscalYear} (당)기"],
'previous' => ['start' => $prevStartDate, 'end' => $prevEndDate, 'label' => '제 '.($fiscalYear - 1).' (전)기'],
],
'unit' => $unit,
'sections' => $sections,
];
return $sections;
}
private function getAccountSums(int $tenantId, string $startDate, string $endDate): array