# 04. 매출관리 이식 상세

> 원본: `/revenueMgmt/revenueList.do`
> JSP: `salesmgmt/salesMgmt/revenueMgmtList.jsp` (38KB)
> Controller: `SalesNcollectMgmtController` (line 103, 214)
> 대상: `app/(main)/COMPANY_16/sales/revenue/page.tsx` (신규)

## 1. 화면 구조 (wace_plm 원본)

판매관리에서 출하/판매 등록된 데이터를 **매출 관점**(마감일/세금계산서/원장)으로 조회·확정하는 화면. `revenueMode=Y` 플래그로 판매관리와 동일 폼/그리드를 다른 모드로 표시.

### 1.1 검색 폼 (판매와 유사하나 매출 항목 추가)

**활성 11개** (revenueMgmtList.jsp line 813~883):

| 필드 | name | 타입 | 비고 |
|---|---|---|---|
| 주문유형 | `orderType` | select2 | |
| 발주번호 | `poNo` | text | |
| 고객사 | `customer_objid` | select2 | |
| 제품구분 | `productType` | select2 | |
| 품번 | `search_partNo` | select2-part | |
| 품명 | `search_partName` | select2-part | |
| 국내/해외 | `nation` | select2 | |
| 시리얼 | `serialNo` | text | |
| **매출마감 기간** | `salesDeadlineFrom` / `salesDeadlineTo` | date_icon | |
| 발주일 from~to | `orderDateFrom` / `orderDateTo` | date_icon | |
| 출하일 from~to | `shippingDateFrom` / `shippingDateTo` | date_icon | |

**비활성 (JSP line 885~ `<!-- 주석처리된 검색필터 -->` 블록 안)** — 이식 대상 아님:

| 필드 | name |
|---|---|
| 유/무상 | `paymentType` |
| 수주상태 | `orderStatus` |
| 요청납기 from~to | `requestDateFrom` / `requestDateTo` |
| 출하상태 | `shippingStatus` |
| 출하방법 | `shippingMethod` |
| 담당자 | `manager` |
| 인도조건 | `incoterms` |

Hidden: `revenueMode=Y` (shipment_log 기반 조회 모드)

### 1.2 버튼

| 버튼 | id | 동작 |
|---|---|---|
| 조회 | `btnSearch` | `/revenueMgmt/revenueGridList.do` |
| 거래명세서 생성 | `btnTransactionStatement` | `/salesMgmt/transactionStatementForm.do` (판매관리 공유) |
| 마감정보입력 | `btnDeadlineInfo` | `/revenueMgmt/saveDeadlineInfo.do` (세금계산서/수출신고 등 입력) |
| 매출마감 | `btnDeadline` | `/salesNcollectMgmt/salesDeadlineConfirm.do` (마감 처리) |

### 1.3 그리드 컬럼 (`POST /revenueMgmt/revenueGridList.do`)

| # | 컬럼 | field | 비고 |
|---|---|---|---|
| 1 | 프로젝트번호 | PROJECT_NO | frozen |
| 2 | 주문유형 | ORDER_TYPE | |
| 3 | **매출마감일** | SALES_DEADLINE_DATE | |
| 4 | 발주일 | ORDER_DATE | |
| 5 | 발주번호 | PO_NO | |
| 6 | 고객사 | CUSTOMER | |
| 7 | 제품구분 | PRODUCT_TYPE | |
| 8 | 품명 | PRODUCT_NAME | |
| 9 | 수량 | SALES_QUANTITY | right |
| 10 | 단가 | SALES_UNIT_PRICE | right |
| 11 | 공급가액 | SALES_SUPPLY_PRICE | right |
| 12 | 부가세 | SALES_VAT | right |
| 13 | 총액 | SALES_TOTAL_AMOUNT | right |
| 14 | 원화총액 | SALES_TOTAL_AMOUNT_KRW | right |
| 15 | 출하일 | SHIPPING_DATE | |
| 16 | 국내/해외 | NATION | |
| 17 | 환종 | SALES_CURRENCY_NAME | |
| 18 | 환율 | SALES_EXCHANGE_RATE | right |
| 19 | S/N | SERIAL_NO | left |
| 20 | 분할S/N | SPLIT_SERIAL_NO | left |
| 21 | 품번 | PRODUCT_NO | |
| 22 | **과세구분** | TAX_TYPE_NAME | |
| 23 | **세금계산서발행일** | TAX_INVOICE_DATE | |
| 24 | **수출신고필증번호** | EXPORT_DECL_NO | |
| 25 | **선적일자** | LOADING_DATE | |

매출관리 추가 컬럼: 매출마감일, 과세구분, 세금계산서발행일, 수출신고필증번호, 선적일자.

## 2. 백엔드 endpoint 매핑

| wace_plm endpoint | 메서드 | 용도 | vexplor_rps 신규 endpoint |
|---|---|---|---|
| `/revenueMgmt/revenueList.do` | GET | 페이지 진입 | (Next.js page) |
| `/revenueMgmt/revenueGridList.do` | POST | 그리드 데이터 (shipment_log 기반) | `GET /api/sales/revenue/list?...` |
| `/revenueMgmt/getDeadlineInfo.do` | POST | 마감정보 조회 | `GET /api/sales/revenue/:id/deadline` |
| `/revenueMgmt/saveDeadlineInfo.do` | POST | 마감정보 저장 (세금계산서/수출신고/선적일자) | `PUT /api/sales/revenue/:id/deadline` |
| `/salesNcollectMgmt/salesDeadlineConfirm.do` | POST | 매출마감 확정 | `POST /api/sales/revenue/deadline-confirm` |
| `/salesMgmt/transactionStatementForm.do` | GET | 거래명세서 (판매와 공유) | `app/(pop)/sales/sale/transaction/page.tsx` |
| `/salesMgmt/getSavedTransactionStatement.do` | POST | 저장된 거래명세서 조회 | (판매와 공유) |

## 3. DB 테이블

> **2026-05-07 운영 DB 직접 확인 결과 정정**: `final_data`, `end_count`, `tax_invoice_*`, `transaction_statement_*`는 **존재하지 않음**. 매출 마감/세금계산서/수출신고 정보는 모두 **`shipment_log`의 컬럼**으로 저장됨.

| 테이블 | 역할 | DDL |
|---|---|---|
| `shipment_log` | 분할출하 이력 + **매출 마감 정보** (컬럼: `sales_deadline_date`, `tax_type`, `tax_invoice_date`, `export_decl_no`, `loading_date`, `sales_slip_date`, `sales_slip_menu_sq`) | [ddl-extracted/101_create_sales_registration.sql](./ddl-extracted/101_create_sales_registration.sql) |
| `sales_registration` | 판매 등록 헤더 (프로젝트당 1건, UNIQUE project_no) | 위 |
| `contract_mgmt` / `contract_item` | 수주 헤더/라인 (조인) | 기존 (db/dbexport.pgsql) |
| `mail_log` | 거래명세서 메일 발송 이력 (전 시스템 공용, 7,805건) | [ddl-extracted/102_create_mail_log.sql](./ddl-extracted/102_create_mail_log.sql) |

### 매출 컬럼 참조 (shipment_log)

```sql
sales_deadline_date  VARCHAR(10),  -- 매출 마감일
tax_type             VARCHAR(20),  -- 과세구분
tax_invoice_date     VARCHAR(10),  -- 세금계산서 발행일
export_decl_no       VARCHAR(100), -- 수출신고필증 번호
loading_date         VARCHAR(10),  -- 선적일자
sales_slip_date      VARCHAR(10),  -- 매출전표일
sales_slip_menu_sq   INTEGER,      -- 매출전표 menu_sq
```

→ 매출관리 화면의 "마감정보입력" / "매출마감"은 **`shipment_log` 행을 INSERT/UPDATE**.

## 4. 구현 순서

1. **운영 DB DDL 추출** (shipment_log, sales_registration, final_data, end_count) — 03-sale.md와 함께 진행
2. **마이그레이션 SQL**: `db/migrations/103_create_revenue_tables.sql` (또는 sale과 통합)
3. **백엔드**:
   - `backend-node/src/routes/revenueRoutes.ts`
   - `backend-node/src/services/revenueService.ts` (그리드 SQL은 shipment_log 또는 sales_registration JOIN)
   - 매출마감 트랜잭션 (다건 마감일 일괄 업데이트 + 마감 이력 기록)
4. **프론트엔드**:
   - `frontend/app/(main)/COMPANY_16/sales/revenue/page.tsx` (목록)
   - 마감정보 입력 Dialog (`components/sales/RevenueDeadlineInfoDialog.tsx`) — 세금계산서/수출신고/선적일자/과세구분
   - 매출마감 확정 모달

## 5. 주의사항

- **매출 vs 판매**: 같은 데이터(sales_registration / shipment_log)를 다른 시점/관점으로 봄.
  - 판매관리 = "출하 + 판매 등록까지의 진행 현황"
  - 매출관리 = "마감일/세금계산서/수출신고 등 회계·세무 처리"
- **`revenueMode=Y`**: 동일 컨트롤러(`SalesNcollectMgmtController`)가 판매/매출 두 화면을 분기. Next.js에선 그냥 별도 라우트.
- **세금계산서 연동**: 외부 시스템(국세청/이지로보) 연동 가능성 — 본 메뉴에선 단순 발행일·번호 기록만 우선 구현.
- **수출 케이스**: NATION='해외'일 때 수출신고필증번호/선적일자/통화/환율 별도. 환율 마스터 또는 외부 API 필요.
- **거래명세서 공유**: 판매관리(03-sale.md)와 동일한 화면을 호출. 한 곳에 구현 후 양쪽에서 호출.
- **매출마감 후 수정 잠금**: 마감 확정된 라인은 판매관리에서 수정 불가능해야 함 — 권한/상태 가드.
