Skip to content

부과항목 마스터 — BE 핸드오프

독자: BE 개발자/AI. 부과항목 정의 + 인스턴스 단일 캐논, active 전파 불변식, 분개 정합 제약, chargeCode 안정 키. 정본: src/composables/useCharges.js + src/composables/useAllocationBasisValues.js + src/composables/demoSeed.js. 구현 상태: ✅구현 (2026-06-29, worktree feat/invoicing-detail-axis-aggregate).


0. 핵심 원칙 — single-canon

useCharges.charges가 부과항목의 유일한 소스다. 별도 카탈로그 store·마스터 테이블 없음.

  • 설정>항목 화면 = 정의 필드(name/nature/taxCategory/taxInvoiceType/chargeBasis/active) 편집.
  • charging/assessment 화면 = 인스턴스 필드(금액: baseChargePrincipal 외) 편집.
  • charging/assessment의 항목명 드릴다운도 설정>항목과 같은 chargeCode 기반 정의·배분값 조회를 사용한다. 별도 assessment 전용 item-detail DTO를 만들지 않는다.
  • 두 화면이 같은 charge 객체의 다른 필드를 담당. sync 불필요.

1. 데이터 모델

1-1. charge 필드 분류

필드분류변경 가능 주체설명
chargeCode등록코드(§1-3)생성 시 자동, 이후 불변FK 안정 키. ci-N 시퀀스(데모). BE 실 구현 시 UUID 또는 도메인 코드.
name이름(명)설정>항목(updateChargeDef)표시명. 중복 허용.
nature정의설정>항목(updateChargeDef)BILLING_NATURE enum 값. 분개 라우팅 핵심(아래 §3).
taxCategory정의설정>항목(updateChargeDef)과세/면세/해당없음. VAT 계산 분기.
taxInvoiceType정의설정>항목(updateChargeDef)일반/계산서/없음. 세금계산서 발행 유형.
chargeBasis정의설정>항목(updateChargeDef)AREA_EXCLUSIVE/AREA_CONTRACT/USAGE/FIXED_SHARE/VARIABLE_SHARE. 배분 행렬 기준. FE 프로토타입은 기존 KO 값도 정규화한다.
active메타설정>항목(toggleActive)true = 부과 사슬 포함. false = 전 사슬 제외.
baseChargePrincipal인스턴스(금액)charging/assessment발생측·부과측 원금·할증·할인·조정. excl. VAT.
targetCount인스턴스charging배분 세대수.
chargeStatus인스턴스charging(라이프사이클)진행/완료.

1-2. 정의 필드 allowlist (DEF_FIELDS)

updateChargeDef(chargeCode, patch)는 아래 필드만 패치한다. 금액·chargeCode는 allowlist 외 → 불변 보장.

DEF_FIELDS = ['name', 'nature', 'taxCategory', 'taxInvoiceType', 'chargeBasis']

BE가 정의 수정 API를 구현할 때도 이 allowlist를 서버 측에서 동일하게 적용해야 한다.


2. active 전파 불변식

2-1. activeCharges 정의

activeCharges = charges.filter(c => c.active !== false)

active 필드가 없는 charge는 활성으로 취급(!== false). 기존 시드(active: true)는 영향 없음(회귀 0).

2-2. 부과 사슬 소비처

비활성 항목은 다음 소비처에서 자동 제외된다:

소비처역할비고
useAllocations.js세대별 배분 산정L21에서 activeCharges 소비
useInvoicingDetail.js청구 집계·이월 표시L17에서 activeCharges 소비
charging/assessment/blocks/DynamicTableOrg.vue부과 금액 편집 테이블activeCharges 소비

전파 경로: active=falseactiveCharges에서 제외 → 배분 산정 제외 → 청구 집계 제외 → 분개 제외 → 고지서 제외.

2-4. 배분기준 계약

정본은 src/composables/chargeBasis.js, 계산 소비처는 src/composables/useAllocations.js다.

API enumFE 호환 값원시수량
AREA_EXCLUSIVE전용호별 전용면적
AREA_CONTRACT계약호별 계약면적
USAGE사용량해당 항목·호의 당월 검침 사용량
FIXED_SHARE고정지분호별 고정지분
VARIABLE_SHARE가변지분해당 차수의 호별 가변지분

공식은 모든 방식이 동일하다.

lineWeight = basisQuantity(chargeBasis) × occupancyDays / monthDays
lineAmount = chargePrincipal × lineWeight / totalWeight
  • 면적 기준은 전용면적 또는 계약면적만 허용한다. 분양면적 enum·필드는 두지 않는다.
  • 계약면적은 allocation line의 basis.contractArea를 우선하고, 없으면 unit master의 contractArea, 구데이터는 마지막으로 basis.area를 사용한다.
  • totalWeight === 0이면 전액을 마지막 라인에 몰지 않고 unallocated = principal로 남긴다. 미배분이 있으면 부과 확정 hard-stop.

2-5. 항목별 호 배분값 저장 계약

호별 값의 저장 원천은 기준에 따라 분리한다.

기준읽기/쓰기 원천비고
전용면적unit.exclusiveArea프로퍼티 마스터 소유, 항목 화면은 읽기 전용
계약면적unit.contractArea프로퍼티 마스터 소유, 항목 화면은 읽기 전용
사용량(chargeCode, unitCode) 누적 지침UI의 당월 사용량은 currentMonth = prevMonth + usage로 저장
고정지분allocation line basis.fixedShare같은 chargeCode+unitCode의 모든 점유기간 라인에 동일 값
가변지분allocation line basis.variableShare차수 스냅샷 대상, 같은 호의 점유기간 라인에 동일 값

신규 항목 생성 시 현재 계약 원자(contractCode × unitCode × memberCode × 점유기간)를 항목의 allocation line으로 함께 생성한다. ensureChargeLines(chargeCode)는 멱등이며 이미 한 줄이라도 있으면 추가하지 않는다. 신규 고정지분·가변지분·사용량은 0으로 시작한다. 항목 삭제 시 해당 항목의 allocation line과 지침도 함께 삭제한다.

2-3. 시드 불변식

데모 시드(demoSeed.buildSeed().charges) = 전부 active: true. 기존 테스트(부과·배분·분개·고지서)가 active 전환 이전과 동일 결과. 시드 회귀 없음.


3. nature enum 제약 — 분개 정합

3-1. BILLING_NATURE

src/composables/billingNature.js export. 현재 허용 값:

nature분개 성격대변 계정
관리비과세/면세 용역 매출0412 용역매출 + VAT(과세만)
수도료면세 용역 매출0412 용역매출
장기수선충당금부채 적립(비매출)9112(공동주택) / 9113(집합건물)
예비비적립금부채 적립(비매출)9201

신규 항목의 nature가 BILLING_NATURE 외 값이면 useBillingJournal 분개 라우팅이 fallback 처리됨(분개 누락 또는 오류 계정). BE 실 구현 시 서버 측 enum 검증 필수.

3-2. nature 추가 절차

v1 범위 외. 신규 nature를 추가하려면: billingNature.js 등록 + useBillingJournal 분개 라우팅 확장 + 테스트 보완 후 BE 계정과목 매핑. 아무 화면에서나 자유 입력으로 nature를 추가하는 것은 분개 정합을 깰 수 있으므로 FE UI에서 enum select만 허용.


4. chargeCode 안정 키 정책 (코드체계 §1-3 등록코드)

속성
생성자동(addCharge 시 시퀀스 부여). 데모: ci-N. 실 API: UUID 또는 도메인 규칙.
변경불가(DEF_FIELDS 외). 설정>항목에서도 비노출(우측 상단 subtitle-sm 읽기 전용).
삭제removeCharge로 영구 삭제만 가능. 삭제 후 재사용 없음(시퀀스 continue).
FK 역할useAllocations·useInvoicingDetail·useBillingJournal 등이 chargeCode로 항목 참조. 변경 금지 이유.

5. 주요 API (현재 FE 구현, BE 배선 계약)

5-1. 항목 추가

POST /service-charge/charges
Body: { name, nature, taxCategory, taxInvoiceType, chargeBasis }
Response: { chargeCode }
  • active 기본값: true.
  • 금액 필드 기본값: 0.
  • chargeCode: 서버 자동 부여.
  • chargeBasis는 위 5개 enum만 허용. AREA_CONTRACT 사용 시 대상 호에 계약면적이 있어야 한다.

5-2. 항목 삭제

DELETE /service-charge/charges/{chargeCode}
  • 물리 삭제. 연결된 과거 분개 보호 여부는 BE 정책(데모는 물리 삭제).

5-3. 정의 필드 수정

PATCH /service-charge/charges/{chargeCode}
Body: { name?, nature?, taxCategory?, taxInvoiceType?, chargeBasis? }  // DEF_FIELDS 외 무시
  • 금액·chargeCode 패치 불가.
  • nature는 서버에서 BILLING_NATURE enum 검증.

5-4. 활성 토글

PATCH /service-charge/charges/{chargeCode}/active
Body: { active: boolean }
  • 비활성화 시 현재 진행 중인 청구 회차의 부과 데이터가 있다면 BE 정책 필요(데모는 즉시 제외).

5-5. 금액 편집 (charging 소관)

PATCH /service-charge/charges/{chargeCode}/amounts
Body: { baseChargePrincipal?, chargeSurcharge?, chargeDiscount?, chargeAdjustment?, ... }
  • 정의 필드와 분리된 별도 엔드포인트 권장. DEF_FIELDS 수정과 혼용 금지.

5-6. 호별 배분값 조회·저장

GET /service-charge/charges/{chargeCode}/basis-values
Response: {
  chargeCode,
  chargeBasis,
  rows: [{ unitCode, value }]
}

PUT /service-charge/charges/{chargeCode}/basis-values
Body: {
  chargeBasis,
  rows: [{ unitCode, value }]
}
  • 서버는 모든 value가 유한한 0 이상 수인지 검증한다.
  • 면적 기준 PUT은 허용하지 않고 프로퍼티 unit API로 유도한다.
  • 지분은 동일 호의 모든 유효 점유기간 라인에 반영하되, 월중 점유일수는 배분 공식에서 별도로 곱한다.
  • 사용량은 검침 원장에 저장하고 allocation line에 중복 원천을 만들지 않는다.
  • 진행 차수 저장은 트랜잭션으로 처리하고, 확정 차수 값은 수정하지 않는다.
  • 설정>항목과 부과산정 항목명 진입은 동일 엔드포인트를 소비한다. 진입 화면에 따라 복제 저장소나 별도 응답 스키마를 두지 않는다.

6. 엣지케이스 / 불변식

  1. 비활성 항목 + 기존 미수: 비활성화해도 이전 기간에 발생한 미수·분개는 그대로 유지. 부과 사슬에서 "신규 산정 대상에서 제외"될 뿐.
  2. 신규 항목 금액 0 + activeCharges 포함: 추가 즉시 activeCharges에 들어가지만 금액 0이므로 배분·분개·합계에 0원 라인으로 합산. 실질 영향 없음.
  3. chargeCode 충돌: FE 데모는 시퀀스 while loop으로 방지. BE는 unique constraint 필수.
  4. nature가 BILLING_NATURE 외: 현재 FE에서 enum select로 차단. BE도 서버 검증 필수.
  5. 단일 기간 데모: 현재 charges는 기간 독립 단일 배열. 다기간(월별 정의 변경 이력)은 v2 설계 필요.
  6. 배분기준 변경: 기준 변경 즉시 진행 중 차수의 배분 결과가 달라진다. 이미 확정된 차수는 effective-dated 정의 또는 스냅샷으로 보존해야 한다(BE 도입 시 필수).
  7. 기준값 0: 사용량·지분·면적 합계가 0이면 미배분으로 남겨야 하며 자동 균등 배분으로 폴백하지 않는다.
  8. 월중 입주자 변경: 한 호에 allocation line이 여러 개여도 사용자가 입력하는 값은 호당 하나다. 같은 호의 각 라인에 같은 기준값을 적용한 뒤 occupancyDays / monthDays로 분할한다.