357 lines
12 KiB
Markdown
357 lines
12 KiB
Markdown
# 계정별원장 API 명세 (서비스 이관)
|
|
|
|
> **작성일**: 2026-03-20
|
|
> **상태**: API 완료, React 구현 대기
|
|
> **대상**: React 프론트엔드 개발자
|
|
|
|
---
|
|
|
|
## 1. 개요
|
|
|
|
회계관리 메뉴에 **계정별원장** 화면을 구현한다.
|
|
선택한 계정과목의 기간별 거래 내역을 조회하고, 월별 소계/누계/잔액을 표시한다.
|
|
카드거래인 경우 카드사·가맹점 정보를 추가로 표시하고, 행 클릭 시 전표 상세를 모달로 보여준다.
|
|
|
|
### 메뉴 위치
|
|
|
|
```
|
|
회계관리
|
|
├── 일반전표입력 ← 기존
|
|
├── 계정별원장 ← 이 화면
|
|
├── 손익계산서 ← 기존
|
|
├── ...
|
|
```
|
|
|
|
---
|
|
|
|
## 2. API 엔드포인트
|
|
|
|
### 2.1 계정별원장 조회
|
|
|
|
```
|
|
GET /api/v1/account-ledger
|
|
```
|
|
|
|
**요청 파라미터** (Query String):
|
|
|
|
| 파라미터 | 타입 | 필수 | 설명 | 예시 |
|
|
|---------|------|:----:|------|------|
|
|
| `start_date` | `string(date)` | Y | 조회 시작일 | `2026-01-01` |
|
|
| `end_date` | `string(date)` | Y | 조회 종료일 | `2026-03-20` |
|
|
| `account_code` | `string` | Y | 계정과목 코드 | `81100` |
|
|
|
|
**응답 예시**:
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "조회되었습니다.",
|
|
"data": {
|
|
"account": {
|
|
"code": "81100",
|
|
"name": "복리후생비",
|
|
"category": "expense"
|
|
},
|
|
"period": {
|
|
"start_date": "2026-01-01",
|
|
"end_date": "2026-03-20"
|
|
},
|
|
"carry_forward": {
|
|
"debit": 0,
|
|
"credit": 0,
|
|
"balance": 0
|
|
},
|
|
"monthly_data": [
|
|
{
|
|
"month": "2026-01",
|
|
"items": [
|
|
{
|
|
"date": "2026-01-11",
|
|
"description": "복리후생비",
|
|
"trading_partner_name": "스타벅스 강남점",
|
|
"biz_no": "1234567890",
|
|
"debit_amount": 160000,
|
|
"credit_amount": 0,
|
|
"balance": 160000,
|
|
"source_type": "ecard_transaction",
|
|
"source_id": 45,
|
|
"card_tx": {
|
|
"card_num": "9411320012345678",
|
|
"card_company_name": "삼성카드",
|
|
"merchant_name": "스타벅스 강남점",
|
|
"merchant_biz_num": "1234567890",
|
|
"deduction_type": "deductible",
|
|
"supply_amount": 145455,
|
|
"tax_amount": 14545,
|
|
"approval_amount": 160000
|
|
}
|
|
},
|
|
{
|
|
"date": "2026-01-15",
|
|
"description": "직원 야근 식대",
|
|
"trading_partner_name": null,
|
|
"biz_no": null,
|
|
"debit_amount": 50000,
|
|
"credit_amount": 0,
|
|
"balance": 210000,
|
|
"source_type": "journal",
|
|
"source_id": 52,
|
|
"card_tx": null
|
|
}
|
|
],
|
|
"subtotal": { "debit": 210000, "credit": 0 },
|
|
"cumulative": { "debit": 210000, "credit": 0 }
|
|
}
|
|
],
|
|
"grand_total": {
|
|
"debit": 210000,
|
|
"credit": 0,
|
|
"balance": 210000
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2.2 관련 API
|
|
|
|
| API | 용도 | 비고 |
|
|
|-----|------|------|
|
|
| `GET /api/v1/account-subjects?selectable=true` | 계정과목 목록 (필터 드롭다운) | `selectable=true` → depth=3 입력 가능 계정만 |
|
|
| `GET /api/v1/general-journal-entries/{id}` | 전표 상세 (드릴다운 모달) | source_id로 조회 |
|
|
|
|
---
|
|
|
|
## 3. TypeScript 인터페이스
|
|
|
|
```typescript
|
|
// 계정별원장 응답
|
|
interface AccountLedgerResponse {
|
|
success: boolean;
|
|
message: string;
|
|
data: {
|
|
account: {
|
|
code: string;
|
|
name: string;
|
|
category: 'asset' | 'liability' | 'capital' | 'revenue' | 'expense';
|
|
} | null;
|
|
period: {
|
|
start_date: string;
|
|
end_date: string;
|
|
};
|
|
carry_forward: {
|
|
debit: number;
|
|
credit: number;
|
|
balance: number;
|
|
};
|
|
monthly_data: MonthlyData[];
|
|
grand_total: {
|
|
debit: number;
|
|
credit: number;
|
|
balance: number;
|
|
};
|
|
};
|
|
}
|
|
|
|
interface MonthlyData {
|
|
month: string; // "2026-03"
|
|
items: LedgerItem[];
|
|
subtotal: { debit: number; credit: number };
|
|
cumulative: { debit: number; credit: number };
|
|
}
|
|
|
|
interface LedgerItem {
|
|
date: string; // "2026-03-01"
|
|
description: string | null;
|
|
trading_partner_name: string | null; // 카드거래 시 가맹점명으로 대체됨
|
|
biz_no: string | null; // 카드거래 시 가맹점 사업자번호로 대체됨
|
|
debit_amount: number;
|
|
credit_amount: number;
|
|
balance: number; // 누적 잔액
|
|
source_type: string; // 'journal' | 'ecard_transaction' | 'bank_transaction' 등
|
|
source_id: number; // 전표 ID
|
|
card_tx: CardTransaction | null; // 카드거래 상세 (없으면 null)
|
|
}
|
|
|
|
interface CardTransaction {
|
|
card_num: string; // 카드번호 전체 (프론트에서 마스킹: ····끝4자리)
|
|
card_company_name: string; // "삼성카드"
|
|
merchant_name: string; // "스타벅스 강남점"
|
|
merchant_biz_num: string; // "1234567890"
|
|
deduction_type: string; // "deductible" | "non_deductible"
|
|
supply_amount: number; // 공급가액
|
|
tax_amount: number; // 세액
|
|
approval_amount: number; // 승인금액 (공급가 + 세액)
|
|
}
|
|
|
|
// 전표 상세 (드릴다운 모달용)
|
|
interface JournalEntryDetail {
|
|
id: number;
|
|
entry_no: string; // "JE-20260311-001"
|
|
entry_date: string;
|
|
entry_type: string;
|
|
description: string | null;
|
|
total_debit: number;
|
|
total_credit: number;
|
|
status: 'draft' | 'confirmed';
|
|
source_type: string | null;
|
|
created_by_name: string | null;
|
|
lines: JournalEntryLine[];
|
|
}
|
|
|
|
interface JournalEntryLine {
|
|
line_no: number;
|
|
dc_type: 'debit' | 'credit';
|
|
account_code: string;
|
|
account_name: string;
|
|
trading_partner_name: string | null;
|
|
debit_amount: number;
|
|
credit_amount: number;
|
|
description: string | null;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 화면 구현 가이드
|
|
|
|
### 4.1 화면 구조
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────┐
|
|
│ 📖 계정별원장 [인쇄] │
|
|
├──────────────────────────────────────────────────┤
|
|
│ 조회기간: [시작일] ~ [종료일] │
|
|
│ 계정과목: [코드/이름 자동완성 검색] [조회] │
|
|
├──────────────────────────────────────────────────┤
|
|
│ 81100 복리후생비 (2026-01-01 ~ 2026-03-20) │
|
|
├───────┬────────────────┬──────┬──────┬─────┬─────┬───────┤
|
|
│ 날짜 │ 적요 │거래처│사업자│차변 │대변 │ 잔액 │
|
|
├───────┼────────────────┼──────┼──────┼─────┼─────┼───────┤
|
|
│ - │ 이월잔액 │ │ │ 0 │ 0 │ 0 │
|
|
│01-11 │ 💳복리후생 [공제]│스타벅│12345 │160K │ │ 160K │
|
|
│ │ 삼성 ····5678 │ │ │ │ │ │
|
|
│01-15 │ 직원 야근 식대 │ │ │ 50K │ │ 210K │
|
|
│-------│--- 2026-01 계 ─│──────│──────│210K │ 0 │ │
|
|
│ │ 누 계 │ │ │210K │ 0 │ │
|
|
│02-03 │ ... │ │ │ │ │ │
|
|
│-------│--- 총 합 계 ────│──────│──────│합계 │합계 │최종잔│
|
|
└───────┴────────────────┴──────┴──────┴─────┴─────┴───────┘
|
|
```
|
|
|
|
### 4.2 조회 필터
|
|
|
|
**계정과목 검색 드롭다운**:
|
|
|
|
```
|
|
GET /api/v1/account-subjects?selectable=true
|
|
```
|
|
|
|
- 텍스트 입력 시 코드 + 이름으로 클라이언트 필터링
|
|
- 키보드 방향키(↑↓) + Enter로 선택 가능
|
|
- 최대 50개까지 드롭다운 표시
|
|
- 선택 후 `코드 이름` 형태로 입력창에 표시 (예: "81100 복리후생비")
|
|
|
|
**기간 기본값**: 당월 1일 ~ 오늘
|
|
|
|
### 4.3 테이블 행 유형
|
|
|
|
| 행 유형 | 조건 | 스타일 |
|
|
|---------|------|--------|
|
|
| **이월잔액** | `carry_forward.balance !== 0` | 노란 배경, 굵은 글씨 |
|
|
| **거래 행** | `items[]` | 일반 + hover 효과, 클릭 가능 |
|
|
| **카드거래 행** | `item.card_tx !== null` | 💳 아이콘 + 배지 + 서브텍스트 |
|
|
| **월 소계** | 매월 마지막 | 회색 배경, 굵은 글씨 |
|
|
| **누계** | 매월 마지막 | 회색 배경, 굵은 글씨 |
|
|
| **총합계** | 마지막 | 인디고 배경, 굵은 글씨 |
|
|
|
|
### 4.4 카드거래 행 표시
|
|
|
|
`card_tx !== null`인 행은 적요 셀에 추가 정보를 표시한다:
|
|
|
|
```
|
|
┌──────────────────────────────────────────────┐
|
|
│ 💳 복리후생비 ┌─────────┐ │
|
|
│ │ 공제 │ │ ← deduction_type === 'deductible'
|
|
│ 삼성카드 ····5678 └─────────┘ │ ← card_company_name + 끝4자리
|
|
└──────────────────────────────────────────────┘
|
|
```
|
|
|
|
- `deduction_type === 'deductible'` → 초록 배지 `[공제]`
|
|
- `deduction_type === 'non_deductible'` → 빨간 배지 `[불공제]`
|
|
- 카드번호 마스킹: `'····' + card_tx.card_num.slice(-4)`
|
|
|
|
### 4.5 드릴다운 (전표 상세 모달)
|
|
|
|
거래 행 클릭 시 `source_type`에 따라 전표 상세를 모달로 표시:
|
|
|
|
```javascript
|
|
const handleRowClick = async (item: LedgerItem) => {
|
|
if (['journal', 'ecard_transaction', 'bank_transaction'].includes(item.source_type)) {
|
|
const res = await authenticatedFetch(`/api/v1/general-journal-entries/${item.source_id}`);
|
|
// → 전표 상세 모달 오픈
|
|
// - 전표 헤더: 전표번호, 일자, 적요, 상태
|
|
// - 분개 라인 테이블: No, 차/대, 계정코드, 계정명, 거래처, 차변, 대변, 적요
|
|
// - 카드정보 (card_tx가 있으면): 카드번호, 카드사, 가맹점, 공급가, 세액
|
|
// - [원본 보기] 버튼: 일반전표 화면으로 이동
|
|
}
|
|
};
|
|
```
|
|
|
|
**모달 구성**:
|
|
|
|
| 섹션 | 내용 |
|
|
|------|------|
|
|
| **헤더** | 전표번호, 일자, [원본 보기] 버튼, [닫기] 버튼 |
|
|
| **전표 요약** | 전표번호, 일자, 적요, 작성자, 상태, 출처(source_type) |
|
|
| **카드정보** (card_tx 있을 때) | 카드번호(마스킹), 카드사, 가맹점, 사업자번호, 공급가, 세액, [공제]/[불공제] |
|
|
| **분개 테이블** | No, 구분(차/대), 계정코드, 계정명, 거래처, 차변, 대변, 적요 |
|
|
| **합계** | 차변 합계, 대변 합계 |
|
|
|
|
### 4.6 잔액 계산
|
|
|
|
서버에서 이미 계산된 `balance` 값을 사용한다. 프론트에서 별도 계산 불필요.
|
|
|
|
**음수 잔액 표시**: `(100,000)` 괄호 형식 또는 음수 표시
|
|
|
|
### 4.7 숫자 포맷
|
|
|
|
```typescript
|
|
const fmt = (n: number): string => {
|
|
if (n === 0 || n === null || n === undefined) return '';
|
|
if (n < 0) return '(' + Math.abs(n).toLocaleString() + ')';
|
|
return n.toLocaleString();
|
|
};
|
|
```
|
|
|
|
- 0은 빈 문자열로 표시 (공란)
|
|
- 음수는 괄호 표시
|
|
- 천 단위 콤마
|
|
|
|
### 4.8 인쇄
|
|
|
|
- `window.print()` 사용
|
|
- CSS `@media print { .no-print { display: none !important; } }`
|
|
- 조회 조건 패널, 인쇄 버튼에 `no-print` 클래스 적용
|
|
|
|
---
|
|
|
|
## 5. MNG 참고 화면
|
|
|
|
MNG 개발서버에서 동일 기능을 확인할 수 있다:
|
|
|
|
> `https://admin.codebridge-x.com` → 회계/세무관리 > 계정별원장
|
|
|
|
---
|
|
|
|
## 관련 문서
|
|
|
|
- [dev/dev_plans/account-ledger-service-migration-plan.md](../../dev/dev_plans/account-ledger-service-migration-plan.md) — 이관 기획서
|
|
- [features/finance/README.md](../../features/finance/README.md) — 재무관리 기능 개요
|
|
- [frontend/api-specs/barobill-api.md](barobill-api.md) — 바로빌 회계 API 명세
|
|
|
|
---
|
|
|
|
**최종 업데이트**: 2026-03-20
|