다크모드
관리비 고지서(invoice) — BE 참고 매뉴얼
독자: BE 개발자/AI. 고지서 VM 계약·표시 태그·청구액 정의·불변식. FE는 기존 컴포저블 재조립 + 표시집계 1개 신설(byNature). 정본 spec:
docs/superpowers/specs/2026-06-27-invoice-wiring-design.md· 항목별 영수증2026-06-27-invoice-itemized-receipt.md. as-built 2026-06-27.
1. 데이터 계약 — InvoiceVM
useInvoice.invoiceFor({axis,key}, asOf). 소스: useInvoicingDetail(당기·forward·VAT) + useAllocations.currentPeriodByNature(★신설) + useCollectingDetail(payable·선수금·연체료) + invoiceDisplayPreset(태그).
summary: { 세전부과원금, 부가세, 미납원금, 미납연체금, 합계, 선수금, 청구액 }
byTaxGroup: { 과세합계, 면세합계, 영세합계, 계산서비대상, 부가세 } // 의뢰서(Min)
lineItems: [{key,label,taxClass,amount}] ×26 // 영수증(Max)
forward: { 미납원금, 미납연체금 }
metering: { usage:[{utility,unitCode,당월지침,전월지침,전전월지침,당월사용,전월사용}], // 중간단 검침(수도). 수도 부과 없으면 null
comparison:[{utility,당월공급가,전월공급가,산정단가,지정단가}], unitPriceMode:'산정' }2. 청구액 정의 (권위)
청구액 = useCollectingDetail.totals.payable = max(0, (당기+이월 원금 + 연체료) − 선수금) (useCollectingDetail.js:114-116, periods=current+forwarded, 공급대가 기준). 재계산·분해식 금지 — payable 직접 사용.
- 7행 표시 분해:
세전부과원금(당기 공급가액) + 부가세 + 미납원금(forward 공급대가) + 미납연체금(연체료) = 합계,청구액 = max(0, 합계 − 선수금). billing time(당기 미수납)에 payable과 정합. 당기 부분수납 발생 시 분해 재검토 필요(BE 실엔진).
3. byNature 표시집계 (★신설)
componentOf(billingNature.js:99)가 매출 성격(관리비·수도료)을 과세원금/면세원금으로 붕괴 → byComponent엔 성격명 없음. 고지서 영수증 항목 매핑을 위해 useAllocations.lineTotalsByNature()(charge.nature 키 직접 집계) 신설. 불변식: Σ byNature(과세 성격) === byComponent.과세원금. byComponent→byNature 역매핑은 일반 불가(BE도 charge 레벨 보유 필요).
4. 표시 태그 — invoiceDisplayPreset
법정 표준 부과명세 26항목(STANDARD_DISPLAY_ITEMS, label·order=원본 템플릿 일치). 성격→표시항목 N:1 매핑(APARTMENT_NATURE_MAPPING). 세금구분 항목별 고정(Q-B). 표시계층 — 이름·재배열·합산만, 금액·세액 불변.
- 불변식:
Σ lineItems = 당기 부과원금 전체(과세+면세+영세+비매출, VAT 제외).Σ lineItems(과세) = byTaxGroup.과세합계. - ⚠ taxClass 잠정: 원본 템플릿은
보험료**(계산서비)만 마커,*(면세) 0개. 면세 6항목(수도료·난방 등)은 잠정·검증대기. 데모 확정: 수도료=면세(demoSeed taxCategory) · 장기수선비=비매출(billingNature group 부채) · 보험료=계산서비(원본 마커). 실데이터 연동 시 항목별 부가세 분류 확정 필요.
4-1. 항목별 영수증 — 구성내역 분해 (display-only) ✅as-built
영수증은 과세 관리비 통합 lump를 법정 비목으로 분해 공개한다. 데모는 표시계층 분해(expandComposition), 부과·청구·수납·이월은 통합 1줄 유지.
- 모델: 데모 단일 과세 charge(nature '관리비')는 실은 과세 관리비 비목 총괄.
GENERAL_FEE_COMPOSITION(비목 구성비 Σ=1)으로 세대 과세 관리비액을 pro-rata 분해. ⚠ "일반관리비(비목) 내부 구성"이 아니라 "과세 비목 총괄의 구성" — 비목≠총괄 혼동 주의. - 알고리즘: 최대잔여법(Hamilton) —
floor(lump×ratio)후 잔여 단위를 소수부 큰 순 +1. 객체 키순서 무관. - 불변식:
Σ(분해 비목) === 과세 관리비 lump(정확). 9 sub-nature 전부 과세 →byTaxClass.과세불변 →byTaxGroup.과세합계정합. - 전제조건(BE 계약 — 위반 시 silent 금액 drift): ① 구성비 입력은 Σ ratio = 1(정규화 또는 검증 강제) ② lump 정수 통화원(비정수면 분배 잔차 증발) ③ lump·ratio ≥ 0(음수면 음수 line-item). 데모는 정본 프리셋(테스트로 Σ=1 잠금)+정수 allocate로 충족.
- BE 이관: 실 BE는 구성비를 표시계층 프리셋이 아니라 charge/building config(또는 비목별 charge·composition 테이블)로 보유 → 동일 itemize 로직(
expandComposition)이 그대로 작동. 비목별 실 분개액을 보유하면 구성비 근사 불요(직접 byNature 비목 키로 제공).
4-2. 검침(수도 사용량) 부과·표시 ✅as-built
수도료(charge a1b1c2)를 chargeBasis '사용량'(검침)으로 부과. 부과액 = 단가 × q, q=basis.usage(검침 사용량 m³). 빌링코어 무편집 — 기존 useAllocations.basisQuantity('사용량')→basis.usage 경로 재사용. 데이터원: demoSeed.meterReadings(호별 누적지침 3개월) + 라인 basis.usage. 표시 컴포저블 useMetering.meteringFor(selection).
- 단가방식 2종: ① 산정단가(데모 기본) = 수도료 풀 ÷ Σ(사용량×일수비율) — 배분형(총액/q). ② 지정단가 = 고시단가(
WATER_DESIGNATED_UNIT_PRICE, ₩/m³) — 직접형. 어셈블 화면 per-line[산정단가|지정단가]Select 대응. 고지서 표시 = 산정 고정(지정 선택 시 총액이 풀과 무관히 변동 → 영수증 불일치하므로 표시면엔 산정만). - 불변식:
- I1 (풀 보존):
Σ(세대 수도료) === chargePrincipal.allocateDetailed마지막 라인 잔차흡수로 사용량 가중에도 구조적 보존(가중치 변경 무관). → aggregate 면세매출 불변. - I3 (지침 일관): 당월사용 = 당월지침−전월지침 = 라인
basis.usage. 전월사용 = 전월지침−전전월지침. ≥0(지침 단조증가). - I4 (reconcile):
meteringFor().comparison.당월공급가 === byNature 수도료 === 영수증 수도료 line. 4축(contract/unit/member) 실측 일치. - I5 (전월): 전월공급가 = 전월풀(=당월풀×
WATER_PREV_POOL_FACTOR) × selection 전월 가중share. 표시-추정(영수증 reconcile 대상 아님). per-selection 반올림 합이 전월풀과 ±1원 어긋날 수 있음(전월은 비교표시용 — 무영향).
- I1 (풀 보존):
- BE 이관 계약: 실 BE는 ① 호별 월별 검침 지침(누적 m³, ≥3개월) ② 수도료 풀(월별, 또는 단가×Σ사용량) ③ 고시단가/요율표(지정단가용)를 보유.
chargeBasis '사용량'+ 라인basis.usage(=당월 검침 사용량)를 주면 동일 배분/도출 자동 작동. 점유분할 세대는usage × 일수비율가중(엔진lineWeight). - 데모 범위: 수도 1개만 검침화(전기/난방/온수/가스 미모델 → 블록 해당 행 비노출). 빌딩유형 프리셋에서 확장.
5. BE 배선 대상 (현재 FE 데모)
- 고지서 = 불변 스냅샷(발행 시점 동결, 재발행=append) 모델 필요(
PROCESS-RECEIPTS-CANON"고지서 불변"). 현재 FE는 라이브 computed. - 사용량/지침: 수도는 실배선(검침시드
meterReadings, §4-2). 전기·난방·온수·할인감면·공지 = 데모 상수(블록). 실데이터 소스 BE 제공. - 인쇄/PDF·전송·세대 일괄 발행 = 미구현.
- 콘솔 미리보기 일원화(2026-06-29): BE 표면 변경 없음. service-charge 3개 콘솔 페이지 mock
InvoicePreviewArt를 정본InvoiceDynamicOrg임베드로 교체(FE 표시 일원화만 — InvoiceVM 계약·로직 무변경).
6. 불변식 테스트
__tests__/useInvoice.spec.js(청구액=payable·합계정합·byNature 교차검증·Σ영수증=부과원금·3축·비목 분해 Σ과세행=과세원금) · invoiceDisplayPreset.spec.js(26항목·매핑·N:1·세금구분 독립출처·구성비 Σ=1·전부 과세·expandComposition Σ보존) · useMetering.spec.js(I1 풀보존·I3 지침일관·I4 reconcile·I5 전월·산정/지정단가·결정성·범위경계) · blocks/__tests__/MeteringBlocks.spec.js(블록 실값렌더·999,999 폐기·빈상태).