13 KiB
13 KiB
손익계산서 API 명세 (서비스 이관)
작성일: 2026-03-20 상태: API 완료, React 구현 대기 대상: React 프론트엔드 개발자
1. 개요
회계관리 메뉴에 손익계산서 화면을 구현한다. 기간별 당기/전기 비교와 월별 비교 두 가지 보기 모드를 제공한다. 한국 일반기업회계기준에 따른 10개 항목(I~X) 구조로 매출액, 매출원가, 영업이익, 당기순이익 등을 표시한다.
메뉴 위치
회계관리
├── 일반전표입력 ← 기존
├── 계정별원장 ← 기존
├── 손익계산서 ← 이 화면
├── ...
2. API 엔드포인트
2.1 기간별 손익계산서
GET /api/v1/income-statement
요청 파라미터 (Query String):
| 파라미터 | 타입 | 필수 | 설명 | 예시 |
|---|---|---|---|---|
start_date |
string(date) |
Y | 당기 시작일 | 2026-01-01 |
end_date |
string(date) |
Y | 당기 종료일 | 2026-12-31 |
unit |
string |
N | won(기본) / thousand / million |
won |
전기: API가 자동으로 전년 동기를 계산 (예: 2026 → 2025)
응답 예시:
{
"success": true,
"message": "조회되었습니다.",
"data": {
"period": {
"current": {
"start": "2026-01-01",
"end": "2026-12-31",
"label": "제 2 (당)기"
},
"previous": {
"start": "2025-01-01",
"end": "2025-12-31",
"label": "제 1 (전)기"
}
},
"unit": "won",
"sections": [
{
"code": "I",
"name": "매출액",
"current_amount": 50000000,
"previous_amount": 30000000,
"items": [
{ "code": "40400", "name": "용역매출", "current": 50000000, "previous": 30000000 }
],
"is_calculated": false
},
{
"code": "II",
"name": "매출원가",
"current_amount": 20000000,
"previous_amount": 15000000,
"items": [
{ "code": "50100", "name": "서비스매출원가", "current": 12000000, "previous": 8000000 },
{ "code": "50200", "name": "외주용역비", "current": 8000000, "previous": 7000000 }
],
"is_calculated": false
},
{
"code": "III",
"name": "매출총이익",
"current_amount": 30000000,
"previous_amount": 15000000,
"items": [],
"is_calculated": true
}
]
}
}
2.2 월별 손익계산서
GET /api/v1/income-statement/monthly
요청 파라미터 (Query String):
| 파라미터 | 타입 | 필수 | 설명 | 예시 |
|---|---|---|---|---|
year |
integer |
Y | 조회 연도 | 2026 |
unit |
string |
N | won(기본) / thousand / million |
won |
응답 예시:
{
"success": true,
"message": "조회되었습니다.",
"data": {
"year": 2026,
"fiscal_year": 2,
"fiscal_label": "제 2 기",
"unit": "won",
"months": [
{
"month": "01",
"label": "1월",
"sections": [
{
"code": "I",
"name": "매출액",
"current_amount": 5000000,
"previous_amount": 5000000,
"items": [
{ "code": "40400", "name": "용역매출", "current": 5000000, "previous": 5000000 }
],
"is_calculated": false
}
]
},
{
"month": "02",
"label": "2월",
"sections": []
}
]
}
}
참고: 미래 월은 응답에 포함되지 않는다. 월별 데이터에서
previous_amount와item.previous는current와 동일한 값 (월별 비교에서는 의미 없음).
3. TypeScript 인터페이스
// 기간별 손익계산서 응답
interface IncomeStatementResponse {
success: boolean;
message: string;
data: {
period: {
current: { start: string; end: string; label: string }; // "제 2 (당)기"
previous: { start: string; end: string; label: string }; // "제 1 (전)기"
};
unit: 'won' | 'thousand' | 'million';
sections: PLSection[];
};
}
// 월별 손익계산서 응답
interface MonthlyIncomeStatementResponse {
success: boolean;
message: string;
data: {
year: number;
fiscal_year: number;
fiscal_label: string; // "제 2 기"
unit: 'won' | 'thousand' | 'million';
months: MonthPL[];
};
}
interface MonthPL {
month: string; // "01", "02", ...
label: string; // "1월", "2월", ...
sections: PLSection[];
}
interface PLSection {
code: string; // "I", "II", "III", ... "X"
name: string; // "매출액", "매출원가", "매출총이익", ...
current_amount: number; // 당기 금액
previous_amount: number; // 전기 금액
items: PLItem[]; // 세부 계정과목 (계산 항목은 빈 배열)
is_calculated: boolean; // true = 계산 항목 (III, V, VIII, X)
}
interface PLItem {
code: string; // 계정코드 "40400"
name: string; // 계정명 "용역매출"
current: number; // 당기 금액
previous: number; // 전기 금액
}
4. 화면 구현 가이드
4.1 화면 구조
┌───────────────────────────────────────────────────┐
│ 📊 손익계산서 [인쇄] │
├───────────────────────────────────────────────────┤
│ [기간 보기] [월별 보기] [당기만] [당기+전기] │
│ 기간: [시작일]~[종료일] 단위: [원▾] [조회] │
├───────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 과 목 │ 제 2 (당)기 │ 제 1 (전)기│ │
│ │ │ 금 액 │ 금 액 │ │
│ ├─────────────────┼──────────────┼─────────────┤ │
│ │ I. 매출액 │ │ │ │
│ │ 용역매출 │ 50,000,000 │ │ │
│ │ │ │ 50,000,000 │ │
│ ├─────────────────┼──────────────┼─────────────┤ │
│ │ II. 매출원가 │ │ │ │
│ │ 서비스매출원가│ 12,000,000 │ │ │
│ │ 외주용역비 │ 8,000,000 │ │ │
│ │ │ │ 20,000,000 │ │
│ ├─────────────────┼──────────────┼─────────────┤ │
│ │ III. 매출총이익 │ │ 30,000,000 │ │ ← 강조 (연두)
│ │ ... │ │ │ │
│ │ X. 당기순이익 │ │ 25,000,000 │ │ ← 강조 (연두)
│ └─────────────────┴──────────────┴─────────────┘ │
│ (단위: 원) │
└───────────────────────────────────────────────────┘
4.2 보기 모드 전환
| 모드 | 필터 | API | 설명 |
|---|---|---|---|
| 기간 보기 | 시작일~종료일 + 단위 | GET /income-statement |
당기+전기 2열 비교 |
| 월별 보기 | 연도 + 단위 | GET /income-statement/monthly |
월별 비교 |
- 모드 전환 시 기존 데이터 초기화 후 새로 조회
- 기본: 기간 보기, 당해 1/1 ~ 12/31
4.3 기간 보기 테이블 (PeriodTable)
컬럼 구성:
| 상태 | 컬럼 |
|---|---|
당기만 |
과목 | 금액(세부) | 금액(소계) |
당기+전기 |
과목 | 당기(세부) | 당기(소계) | 전기(세부) | 전기(소계) |
행 유형:
| 행 유형 | 조건 | 스타일 | 금액 표시 |
|---|---|---|---|
| 섹션 헤더 | is_calculated === false |
굵은 글씨 | items 없으면 소계열에 금액, 있으면 빈칸 |
| 세부 항목 | items[] |
들여쓰기(pl-12), 일반 | 세부열에 금액, 마지막 항목의 소계열에 섹션 합계 |
| 계산 항목 | is_calculated === true |
강조 배경 | 소계열에만 금액 |
강조 표시 (emerald-50 배경):
- III (매출총이익), V (영업이익), VIII (법인세비용차감전순이익), X (당기순이익)
4.4 월별 보기 테이블 (MonthlyTable)
단일 월 선택: 기간 보기와 유사한 1열 테이블 전체 월 선택: 가로 스크롤 비교 테이블
┌──────────────┬──────┬──────┬──────┬─────┐
│ 과목 (sticky)│ 1월 │ 2월 │ 3월 │ ... │
├──────────────┼──────┼──────┼──────┼─────┤
│ I. 매출액 │ 5M │ 4M │ 6M │ ... │
│ 용역매출 │ 5M │ 4M │ 6M │ ... │
│ II. 매출원가 │ 2M │ 1M │ 3M │ ... │
│ III. 매출총이│ 3M │ 3M │ 3M │ ... │ ← 강조
│ ... │ │ │ │ │
└──────────────┴──────┴──────┴──────┴─────┘
- 과목 열:
sticky left-0(가로 스크롤 시 고정) - 최소 너비:
months.length * 110 + 200px
4.5 월 선택 버튼 (월별 보기)
[전체] [1월] [2월] [3월] ... [12월]
- 데이터가 있는 월만 버튼 표시 (미래 월은 API 응답에 없음)
전체선택 시 가로 스크롤 비교 테이블- 개별 월 선택 시 단일 열 테이블
4.6 숫자 포맷
const fmt = (n: number): string => {
if (n === 0 || n === null || n === undefined) return '';
if (n < 0) return '(' + Math.abs(n).toLocaleString() + ')';
return n.toLocaleString();
};
const UNIT_LABELS: Record<string, string> = {
won: '원',
thousand: '천원',
million: '백만원'
};
4.7 인쇄
window.print()사용- 조회 조건, 인쇄 버튼에
no-print클래스 - CSS:
@media print { .no-print { display: none !important; } }
4.8 기본값
| 항목 | 기본값 |
|---|---|
| 보기 모드 | 기간 보기 |
| 시작일 | 당해 1/1 |
| 종료일 | 당해 12/31 |
| 단위 | 원 (won) |
| 당기/전기 | 당기만 |
| 월 선택 | 전체 |
- 페이지 진입 시 기본값으로 자동 조회
5. 손익계산서 항목 구조
I. 매출액 ← 합계 항목 (세부 계정과목 표시)
II. 매출원가 ← 합계 항목
III. 매출총이익 = I - II ← 계산 항목 (is_calculated: true, 강조)
IV. 판매비와관리비 ← 합계 항목
V. 영업이익 = III - IV ← 계산 항목 (강조)
VI. 영업외수익 ← 합계 항목
VII. 영업외비용 ← 합계 항목
VIII.법인세비용차감전순이익 ← 계산 항목
IX. 법인세비용 ← 합계 항목
X. 당기순이익 = VIII - IX ← 계산 항목 (강조)
- 합계 항목:
items[]에 세부 계정과목 포함,current_amount/previous_amount는 합계 - 계산 항목:
items[]는 빈 배열,is_calculated: true, 금액은 공식으로 계산된 결과
6. MNG 참고 화면
MNG 개발서버:
https://admin.codebridge-x.com→ 회계/세무관리 > 손익계산서
| 파일 | 설명 |
|---|---|
mng/app/Http/Controllers/Finance/IncomeStatementController.php |
전체 로직 (PL_STRUCTURE, buildSections) |
mng/resources/views/finance/income-statement.blade.php |
React 컴포넌트 (PeriodTable, MonthlyTable) |
관련 문서
- dev/dev_plans/income-statement-service-migration-plan.md — 이관 기획서
- frontend/api-specs/account-ledger-service-api.md — 계정별원장 API 명세
- features/finance/README.md — 재무관리 기능 개요
최종 업데이트: 2026-03-20