# 계정별원장 서비스 이관 기획서

> **작성일**: 2026-03-20
> **상태**: 기획 확정, API 완료
> **대상**: MNG → API + React (서비스 이관)
> **위치**: 서비스 > 회계관리 > 계정별원장

---

## 1. 개요

### 1.1 목적

MNG 백오피스의 계정별원장 조회 기능을 서비스(API + React)로 이관한다.
MNG는 Controller에서 직접 DB 조회 → API는 Service-First 패턴의 REST API + React 구조로 재구현한다.

### 1.2 배경

- MNG `회계/세무관리 > 계정별원장` 메뉴로 기존 구현 완료 (2026-03-19)
- API에 `AccountLedgerService` + `AccountLedgerController`가 기존에 존재하나, MNG 대비 기능이 부족
- MNG Controller에 카드거래 상세 조회, 분리전표(split) 필터링 등의 로직이 직접 구현됨
- API 보강 후 React에서 동일 기능을 구현할 수 있도록 한다

### 1.3 이관 범위

| 구분 | MNG (현재) | API + React (이관 후) |
|------|-----------|---------------------|
| **백엔드** | Controller 직접 DB 조회 | `AccountLedgerService` (보강 완료) |
| **프론트** | Blade + React (@verbatim) | React (Next.js) |
| **인증** | 세션 기반 (`session('selected_tenant_id')`) | Bearer 토큰 + `BelongsToTenant` |
| **API 문서** | 없음 | Swagger |

---

## 2. 현재 MNG 기능 분석

### 2.1 데이터 소스

계정별원장은 `journal_entries` + `journal_entry_lines` 테이블 기반으로 조회한다.
카드거래, 홈택스 분개 등은 이미 일반전표(journal)에 포함되어 있으므로 UNION 불필요.

```
journal_entry_lines (분개 행)
    ├── JOIN journal_entries (전표 마스터)
    ├── LEFT JOIN trading_partners (거래처 사업자번호)
    └── 추가 조회: barobill_card_transactions (카드 상세)
                   barobill_card_transaction_splits (분리 전표 유효성)
```

### 2.2 MNG 기능 목록

| 기능 | MNG 메서드 | API 대응 |
|------|-----------|---------|
| 페이지 렌더링 | `index()` | React 라우트 |
| 데이터 조회 | `list()` | `GET /api/v1/account-ledger` |
| 카드거래 상세 | `fetchCardTransactions()` (private) | Service 내부 메서드 |
| 이월잔액 계산 | `calculateCarryForward()` (private) | Service 내부 메서드 |
| 분리전표 필터링 | `list()` 내부 로직 | `filterSplitLines()` (private) |
| 전표 드릴다운 | 프론트에서 별도 API 호출 | `GET /api/v1/general-journal-entries/{id}` |
| 계정과목 목록 | MNG 내부 API | `GET /api/v1/account-subjects` |
| 인쇄 | `window.print()` | React에서 동일 |

### 2.3 MNG ↔ API 차이점 (보강 전/후)

| 항목 | MNG | API (보강 전) | API (보강 후) |
|------|-----|-------------|-------------|
| `source_type` | `COALESCE(je.source_type, 'journal')` | 하드코딩 `'journal'` | `COALESCE` 사용 |
| `source_key` | 응답에 포함 | 미포함 | 포함 |
| 카드거래 상세 (`card_tx`) | 포함 | 미포함 | 포함 |
| 분리전표 필터링 | 포함 | 미포함 | 포함 |
| 거래처명 카드 가맹점 대체 | 포함 | 미포함 | 포함 |

---

## 3. API 보강 내역 (완료)

### 3.1 수정 파일

| 파일 | 변경 내용 |
|------|----------|
| `api/app/Services/AccountLedgerService.php` | 4개 기능 추가 |

### 3.2 추가된 기능

**1) source_type 동적 조회**
```php
// 변경 전
DB::raw("'journal' as source_type")

// 변경 후
DB::raw("COALESCE(je.source_type, 'journal') as source_type")
```

**2) source_key 필드 추가**
- 쿼리 select에 `'je.source_key'` 추가
- 카드거래 매칭, 분리전표 판별에 사용

**3) 분리전표 필터링 (`filterSplitLines`)**
- `barobill_card_transaction_splits` 테이블에서 유효한 split ID만 조회
- 무효한 분리전표 행 제거
- 분리전표가 존재하는 원본 전표 행 제거

**4) 카드거래 상세 조회 (`fetchCardTransactions`)**
- `source_type === 'ecard_transaction'`인 행의 `source_key`를 파싱
- `barobill_card_transactions` 테이블에서 카드번호, 카드사, 가맹점, 공제/불공제 등 조회
- 카드 가맹점명이 있으면 `trading_partner_name` 대체

---

## 4. API 엔드포인트

### 4.1 계정별원장 조회

| Method | Path | 설명 |
|--------|------|------|
| `GET` | `/api/v1/account-ledger` | 계정별원장 데이터 조회 |

### 4.2 요청 파라미터

| 파라미터 | 타입 | 필수 | 설명 |
|---------|------|:----:|------|
| `start_date` | `string(date)` | Y | 조회 시작일 |
| `end_date` | `string(date)` | Y | 조회 종료일 |
| `account_code` | `string` | Y | 계정과목 코드 |

### 4.3 응답 구조

```typescript
interface AccountLedgerResponse {
  success: boolean;
  message: string;
  data: {
    account: {
      code: string;       // "81100"
      name: string;       // "복리후생비"
      category: string;   // "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;
  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;
  card_tx: CardTransaction | null;
}

interface CardTransaction {
  card_num: string;           // "1234567890123456"
  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;    // 승인금액
}
```

### 4.4 관련 API

| API | 용도 |
|-----|------|
| `GET /api/v1/account-subjects` | 계정과목 목록 (필터 드롭다운) |
| `GET /api/v1/account-subjects?selectable=true` | 입력 가능 계정과목만 (depth=3) |
| `GET /api/v1/general-journal-entries/{id}` | 전표 상세 (드릴다운) |

---

## 5. React 구현 요구사항

### 5.1 화면 구성

```
┌──────────────────────────────────────────────┐
│ 📖 계정별원장                          [인쇄] │
├──────────────────────────────────────────────┤
│ 조회기간: [시작일] ~ [종료일]                   │
│ 계정과목: [코드/이름 검색 드롭다운]    [조회]   │
├──────────────────────────────────────────────┤
│ 81100 복리후생비  (2026-01-01 ~ 2026-03-20)  │
├──────┬────────┬──────┬──────┬──────┬──────┬──────┤
│ 날짜 │ 적요   │거래처│사업자│ 차변 │ 대변 │ 잔액 │
├──────┼────────┼──────┼──────┼──────┼──────┼──────┤
│  -   │이월잔액│      │      │   0  │   0  │   0  │
├──────┼────────┼──────┼──────┼──────┼──────┼──────┤
│01-11 │복리후생│      │      │160000│      │160000│
│  ... │  ...   │      │      │  ... │  ... │ ...  │
├──────┼────────┼──────┼──────┼──────┼──────┼──────┤
│      │ 2026-01 계    │      │합계  │      │      │
│      │ 누 계         │      │합계  │      │      │
├──────┼────────┼──────┼──────┼──────┼──────┼──────┤
│      │ 총 합 계      │      │합계  │합계  │최종  │
└──────┴────────┴──────┴──────┴──────┴──────┴──────┘
```

### 5.2 핵심 기능

| 기능 | 설명 |
|------|------|
| **조회 필터** | 기간(date range) + 계정과목 검색 (코드/이름 자동완성) |
| **이월잔액** | 조회 시작일 이전 누적 잔액 (첫 행에 표시) |
| **월별 소계/누계** | 월이 바뀔 때마다 소계 행 + 누계 행 |
| **잔액 계산** | 자산/비용 = 차변-대변, 부채/자본/수익 = 대변-차변 |
| **카드거래 표시** | `card_tx` 있으면 카드 아이콘 + 공제/불공제 배지 + 카드사·끝4자리 |
| **드릴다운** | 행 클릭 → 전표 상세 모달 (journal/ecard_transaction/bank_transaction) |
| **인쇄** | CSS `@media print` 활용, 조회 조건 영역 숨김 |

### 5.3 잔액 계산 규칙

| 계정 카테고리 | 정상 방향 | 잔액 = |
|-------------|----------|--------|
| `asset` (자산) | 차변 | 차변 - 대변 |
| `expense` (비용) | 차변 | 차변 - 대변 |
| `liability` (부채) | 대변 | 대변 - 차변 |
| `capital` (자본) | 대변 | 대변 - 차변 |
| `revenue` (수익) | 대변 | 대변 - 차변 |

### 5.4 드릴다운 로직

```
행 클릭 시 source_type 기반 분기:
├── 'journal' | 'ecard_transaction' | 'bank_transaction'
│   → GET /api/v1/general-journal-entries/{source_id}
│   → 전표 상세 모달 (분개 라인 테이블 + 카드정보)
│
└── 'hometax'
    → 홈택스 세금계산서 상세 (별도 API 필요 시 추후 추가)
```

### 5.5 카드거래 표시 규격

`card_tx`가 존재하는 행은 다음과 같이 표시:

- **적요 셀**: 💳 아이콘 + 적요 텍스트 + `[공제]`/`[불공제]` 배지
- **적요 셀 하단**: `카드사명 ····끝4자리` (서브텍스트)
- **거래처 셀**: `card_tx.merchant_name` 우선 (없으면 `trading_partner_name`)
- **사업자번호 셀**: `card_tx.merchant_biz_num` 우선

---

## 6. MNG 참고 화면

MNG(백오피스)에 동일 기능이 구현되어 있다. 화면 레이아웃과 UX를 참고한다.

> MNG 개발서버: `https://admin.codebridge-x.com` → 회계/세무관리 > 계정별원장

### 6.1 MNG 소스 참고 파일

| 파일 | 설명 |
|------|------|
| `mng/app/Http/Controllers/Finance/AccountLedgerController.php` | 전체 로직 (카드, split 포함) |
| `mng/resources/views/finance/account-ledger.blade.php` | React 컴포넌트 (UI 참고) |

---

## 관련 문서

- [dev/dev_plans/account-ledger-income-statement-plan.md](account-ledger-income-statement-plan.md) — 원래 MNG 구현 기획서
- [frontend/api-specs/account-ledger-income-statement-api.md](../../frontend/api-specs/account-ledger-income-statement-api.md) — API 명세 (초기 버전)
- [frontend/api-specs/account-ledger-service-api.md](../../frontend/api-specs/account-ledger-service-api.md) — API 명세 (서비스 이관 버전, 최신)
- [features/finance/README.md](../../features/finance/README.md) — 재무관리 기능 개요

---

**최종 업데이트**: 2026-03-20
