Files
ga-commission-system/docs/시나리오_E2E_보험인입_수수료정산.md
GA Pro 3d50286f4a test: E2E 수수료 정산 시나리오 테스트 + 엑셀업로드/분급 버그 수정
- 시나리오 문서: 보험 인입→수수료 지급 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>
2026-06-03 10:02:55 +09:00

7.9 KiB
Raw Permalink Blame History

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.