# 계정별원장 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