- 시나리오 문서: 보험 인입→수수료 지급 8단계 (docs/시나리오_E2E_보험인입_수수료정산.md) - SettlementScenarioTest(9건): 계약1건 생애주기를 실제 계산기로 단계별 검증 - ExcelServiceImportTest(2건): 실 .xlsx 업로드 라운드트립 검증 - fix(CRITICAL): 엑셀 업로드 런타임 깨짐 — xlsx-streamer 2.2.0 ↔ poi 5.2.5 비호환(NoSuchMethodError). excel-streaming-reader 4.3.0(유지보수 fork)로 교체. 영향: ExcelService.importLargeExcel + UploadService(/api/upload 실엔드포인트) - fix: 분급 계획 반올림 잔차로 분급합계≠원금(정산 무결성 위반). 비율합 100% 정규스케줄일 때 마지막 회차가 잔차 흡수. ga-api/ga-batch 양쪽. - 전체 build+test GREEN: 148건 0실패 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.9 KiB
E2E 시나리오 — 보험이 어떻게 들어와서 수수료가 어떻게 나가는가
이 문서는 계약 1건이 인입되어 설계사 통장에 돈이 꽂힐 때까지의 전체 순서를 "등장인물 + 숫자"로 따라가는 시나리오입니다. 각 단계는 실제 계산 코드(
CommissionCalculator,RegulatoryLimitChecker,InstallmentPlanGenerator,ChargebackCalculator,TaxCalculator)와 1:1로 대응하며, 이 시나리오를 그대로 검증하는 단위테스트가SettlementScenarioTest입니다.
0. 등장인물 (이 시나리오의 테스트 데이터)
| 역할 | 식별자 | 속성 |
|---|---|---|
| 원 모집설계사 김설계 | agentId=10, gradeId=5 |
사업소득(BUSINESS_INCOME) · 과세사업자(TAXABLE) |
| 후임 승계설계사 박승계 | agentId=20, gradeId=3 |
(계약 승계 단계에서 등장) |
| 상위 직책자 이지점 | agentId=30 |
오버라이드 수령 |
| 상품 무배당 종신보험 | productId=1, WHOLE_LIFE, 카테고리 LIFE |
|
| 계약 | contractId=100, policyNo=POL-0001 |
연납보험료 1,000,000원, 계약일 2024-01-15 |
기준 룰(테스트에서 Mock으로 주입하는 데이터):
| 룰 | 값 |
|---|---|
| 보험사요율(company_rate) 1차년 | 60% |
| 보험사요율 2차년 | 10% |
| 지급률(payout_rate) 등급5·WHOLE_LIFE·1차년 | 75% |
| 지급률 등급5·2차년 | 50% |
| 지급률 등급3(후임)·2차년 | 40% |
| 분급 비율(7년) | 35 / 25 / 15 / 10 / 7 / 5 / 3 (%) |
| 차등환수 13~24개월 구간 | 50% |
| 1200% 한도(TOTAL_RATIO) | 12,000,000원 (연납 1,000,000 × 1200%) |
| 원천세 | 사업소득 3.3% · 지방세 = 소득세 10% · 부가세 10%(과세사업자) |
1. 한눈에 보는 순서
[보험사] 실적데이터 인입
│ (Step1 receive → Step2 transform → Step3 reconcile)
▼
① 모집수수료 원장 계산 (Step4 calcRecruit) ← premium × company_rate × payout_rate
│
② 1200% 룰 한도 체크 (RegulatoryLimitChecker) ← 누적이 한도를 넘으면 잘라냄
│
③ 분급(7년) 계획 생성 (InstallmentPlanGenerator) ← 큰 모집수수료를 7년에 나눠 지급
│
④ 유지수수료 원장 계산 (Step5 calcMaintain) ← 2차년 이후 매년
│ └ ⑤ 계약 승계 시 후임에게 귀속 전환 (모집은 원설계사 유지)
│
⑥ 오버라이드 계산 (Step7 calcOverride) ← 하위실적 × 율 (cap 제한)
│
⑦ 조기 해지 환수 (Step6 chargeback) ← 유지개월 짧을수록 많이 환수
│
⑧ 설계사×월 집계 (Step8 aggregate) ← gross 합산
│ └ 세금 원천징수 + 공제 차감 → net(실지급액)
▼
[설계사 통장] ← 펌뱅킹 이체(KFTC)
2. 단계별 숫자 (시나리오 본문)
① 모집수수료 원장 계산 — 보험이 "들어오는" 첫 돈
계약이 인입되면 설계사 김설계(등급5)의 모집수수료 원장 1줄이 생긴다.
① 보험사지급액 = 보험료 1,000,000 × 보험사요율 60% = 600,000
② 설계사수수료 = 600,000 × 지급률 75% = 450,000 ← gross
③ 원장 원천세 = 450,000 × 3.3% = 14,850
→ 원장: agent_id=10, commission_year=1, agent_amount=450,000, tax_amount=14,850
② 1200% 룰 한도 체크
초년도 모집수수료 누적이 연납보험료의 1200%(=12,000,000)를 넘으면 안 된다.
- 현재 누적 0 + 450,000 = 450,000 ≤ 12,000,000 → 통과
- 만약 추가분이 한도를 넘기면
ViolationResult.violated로 막고 초과분을 잘라낸다.
③ 분급(7년 분할) 계획 생성
모집수수료 450,000을 한 번에 안 주고 7년에 나눈다.
| 차년 | 비율 | 지급액 |
|---|---|---|
| 1 | 35% | 157,500 |
| 2 | 25% | 112,500 |
| 3 | 15% | 67,500 |
| 4 | 10% | 45,000 |
| 5 | 7% | 31,500 |
| 6 | 5% | 22,500 |
| 7 | 3% | 13,500 |
| 합 | 100% | 450,000 |
무결성 규칙: 분급액의 합은 원수수료와 정확히 같아야 한다. 금액이 딱 나눠떨어지지 않을 때(예: 435,150원) 회차별 반올림 잔차가 생기는데, 이때는 마지막 회차가 잔차를 흡수해서 합계를 원금에 맞춘다. (→ §4 보완)
④ 유지수수료 (2차년)
계약이 유지되면 2차년부터 유지수수료가 매년 발생한다.
보험사지급액 = 1,000,000 × 10%(2차년 요율) = 100,000
설계사수수료 = 100,000 × 50%(등급5 2차년) = 50,000
⑤ 계약 승계 (김설계 해촉 → 박승계 후임)
김설계가 해촉되면 그 계약의 유지수수료만 후임 박승계(등급3)에게 넘어간다.
유지수수료(후임) = 100,000 × 40%(등급3 2차년) = 40,000 → 원장 agent_id = 20(박승계)
- 모집수수료는 원 모집설계사 김설계(10)에게 그대로 남는다. (고아계약 승계 표준)
⑥ 오버라이드 (상위 직책자 이지점)
하위 김설계의 실적에 대해 상위 이지점이 받는 수당.
오버라이드 = 하위실적 2,000,000 × 4% = 80,000 (cap 100,000 미만이므로 그대로)
⑦ 조기 해지 환수 — 13개월차 해지
계약이 13개월차(2024-01-15 → 2025-02-15)에 깨지면 13~24개월 구간 환수율 50%.
환수액 = 기지급 모집수수료 450,000 × 50% = 225,000 ← 다음 정산에서 (−) 차감
⑧ 집계 → 세금 → 실지급액(net)
김설계 한 달치를 settle_master로 집계하고 세금·공제를 반영한다. 과세사업자(TAXABLE) gross 450,000 기준:
소득세 = 450,000 × 3.3% = 14,850
지방세 = 14,850 × 10% = 1,485
부가세 = 450,000 × 10% = 45,000 (과세사업자만 +)
실지급 = 450,000 − 14,850 − 1,485 + 45,000 = 478,665
- 여기에 가지급금 공제 100,000이 있으면 net = 478,665 − 100,000 = 378,665
- 비과세(NONE) 설계사는 부가세가 없어 net = 450,000 − 14,850 − 1,485 = 433,665
3. 시나리오 ↔ 코드 ↔ 테스트 대응표
| 단계 | 코드 | 테스트 메서드 |
|---|---|---|
| ① 모집수수료 | CommissionCalculator.calcRecruitLedger |
s1_보험인입_모집수수료_원장계산 |
| ② 1200% 룰 | BatchRegulatoryLimitChecker.checkContractTotal |
s2_규제_1200퍼센트_한도_통과및위반 |
| ③ 분급 7년 | BatchInstallmentPlanGenerator.generate |
s3_분급_7년_분할_합계100퍼센트 |
| ③ 분급 잔차 | 〃 | s3b_분급_라운딩_잔차_마지막회차_흡수 |
| ④ 유지수수료 | CommissionCalculator.calcMaintainLedger |
s4_유지수수료_2차년 |
| ⑤ 계약 승계 | CommissionCalculator.calcMaintainLedger(effectiveAgentId) |
s5_계약승계_유지수수료_후임귀속 |
| ⑦ 차등 환수 | BatchChargebackCalculator.calculate |
s6_조기해지_차등환수_13개월_50퍼센트 |
| ⑧ 세금/실지급 | BatchTaxCalculator.calculate |
s7_세금_실지급액_과세사업자 / s8_세금_비과세 |
4. 이 시나리오 작성 중 발견·보완한 사항
분급 계획 합계 불일치(반올림 잔차) — 수정함.
- 현상: 분급액을 회차별로
총액 × 비율 / 100으로 각각 반올림하면, 원금이 7로 나눠떨어지지 않을 때 분급 합계가 원금과 1~수원 어긋났다. (예: 435,150원 → 회차 합 435,153원, +3원 누수) - 영향: 분급 총합 ≠ 원 모집수수료 → 정산 무결성(합계 일치) 위반, 과/미지급.
- 수정: 비율 합이 정확히 100%인 정규 스케줄일 때 마지막 회차가
원금 − 직전 회차 합으로 잔차를 흡수하도록 보정. (비율 합이 100% 미만인 부분지급 스케줄은 기존 동작 유지 → 설계 의도 보존) - 대상:
InstallmentPlanGenerator(ga-api),BatchInstallmentPlanGenerator(ga-batch) 양쪽.
기준: schema v108, DOMAIN_KNOWLEDGE.md 7장 공식. 모든 금액 BigDecimal HALF_UP.