LabHub
배우기 러닝패스 코스

Insurance Domain Deep Dive

How Much Does One Claim Get Paid?

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

약관의 보장 조건을 코드로 옮겨, 청구 한 건의 지급액과 그 근거를 내는 판정기를 만든다. 자기부담금·공동부담률·건당 한도·연간 한도를 정해진 순서로 적용하고, 면책기간과 보장 제외로 거절하고, 같은 사고의 복수 청구를 합산한 뒤, 청구 141건 전체를 판정해 집계와 보고서를 낸다.

왜 중요한가

약관은 말로 적혀 있고 순서를 명시하지 않는다. 공제를 먼저 하는지 비율을 먼저 곱하는지, 자기부담금이 청구마다인지 사고마다인지, 연간 한도를 사고일과 접수일 중 무엇으로 세는지에 따라 같은 청구의 지급액이 달라진다. 그런데 어느 쪽도 오류를 내지 않는다. 그래서 이 판정은 값이 맞느냐 이전에 설명할 수 있느냐 가 먼저다. 규칙 수치를 표로 빼고, 어떤 규칙이 얼마를 깎았는지 청구마다 남기면, 그 기록이 고객 안내문이자 회귀 시험의 기대값이 된다. 이 실습의 약관 수치(자기부담금 1만 원에서 3만 원, 공동부담 10%에서 20%, 건당 한도 30만 원에서 100만 원, 연간 한도 100만 원에서 500만 원, 면책기간 30·90·180일)는 실제 상품이 아니라 이 실습을 위해 지어낸 합성 표다. 채점기는 여러분의 판정 문구를 믿지 않는다. 임시 디렉터리에 채점기가 만든 약관·계약·청구를 차려 놓고 매번 다른 수치로 여러분의 판정기를 실제로 실행해, 지급액과 판정 근거를 채점기가 따로 계산한 값과 대조한다.

단계

  1. /root/coverage/gen_claims.py 를 만들어 실행해 /root/coverage/claims.db 를 만드세요. 약관 3종, 계약 12건, 보장 제외 5줄, 청구 141건입니다.
  2. 적용 순서 두 가지의 합계를 견주어 /root/coverage/order_compare.json 에 claims·order_a_total·order_b_total·difference 로 적으세요.
  3. /root/coverage/adjudicate.py 를 만들어 자기부담금 → 공동부담 → 건당 한도 순서로 깎고, 깎은 금액을 steps 로 남기세요.
  4. 보장기간 밖·면책기간 안·보장 제외 항목의 청구를 거절하세요. decision 은 denied, payable 은 0, reasons 에 사유를 모두 담습니다.
  5. 자기부담금을 사고 하나에 한 번만 쓰게 하세요. 같은 사고의 두 번째 청구는 남은 자기부담금만큼만 깎입니다.
  6. 연간 한도를 넣으세요. 계약마다 사고 연도 기준으로 쌓이고, 접수일 순서대로 소진되며, 해가 바뀌면 다시 살아납니다.
  7. 약관 수치를 표에서만 읽게 하고, 공동부담 계산의 반올림을 사사오입(ROUND_HALF_UP) 으로 못 박으세요.
  8. /root/coverage/make_payout.py 로 청구 141건을 모두 판정해 /root/coverage/payout.json/root/coverage/coverage_report.md 를 만드세요.

참고

약관표와 청구 스냅샷 만들기

/root/coverage/gen_claims.py 를 만들어 실행해 /root/coverage/claims.db 를 만드세요. 약관 3종, 계약 12건, 보장 제외 5줄, 청구 141건(복수 청구 사고 31건)입니다.

먼저 /root/coverage 를 만들고 그 안에서 python3 로 sqlite DB 를 만듭니다. 표는 plan, policy, exclusion, claim 넷입니다. 청구는 사고 100건에 붙어 있고, 사고 하나에 청구가 둘 이상인 경우가 31건입니다.

적용 순서가 합계를 얼마나 벌리나

/root/coverage/order_compare.json 에 claims·order_a_total·order_b_total·difference 를 적으세요. A 는 자기부담금을 먼저 빼고 공동부담률을 적용한 값의 합, B 는 공동부담률을 먼저 적용하고 자기부담금을 뺀 값의 합이며, 둘 다 청구 141건 전부를 대상으로 하고 음수는 0 으로 둡니다.

이 단계는 판정이 아니라 비교입니다. 한도·면책기간·보장 제외는 보지 않습니다. A 는 max(0, 청구액 - 자기부담금) 에서 공동부담분을 뺀 값이고, B 는 청구액에서 공동부담분을 뺀 뒤 자기부담금을 빼고 0 에서 끊은 값입니다. 공동부담분은 사사오입으로 원 단위 정수를 만듭니다.

공제 · 공동부담 · 건당 한도를 순서대로

/root/coverage/adjudicate.py 를 만들어 --claim 으로 받은 청구의 지급액을 자기부담금 → 공동부담 → 건당 한도 순서로 계산하고, 각 규칙이 깎은 금액을 steps 에 남기세요.

약관 수치는 plan 표에서 읽습니다. 자기부담금은 청구액보다 클 수 있으니 min 으로 끊고, 건당 한도는 넘는 만큼만 깎습니다. steps 의 각 원소는 rule·amount·after 세 키를 갖고, 마지막 after 가 payable 입니다.

보장기간 · 면책기간 · 제외 항목으로 거절하기

보장기간 밖의 사고, 면책기간 안의 사고, 보장 제외 항목의 청구를 거절하세요. decision 은 denied, payable 은 0, steps 는 빈 목록이고, reasons 에 out_of_period · waiting_period · excluded 중 해당하는 것을 모두 담습니다.

면책기간은 사고일과 계약 시작일 사이의 거리입니다. 접수일이 아닙니다. 날짜는 date.fromisoformat 과 timedelta 로 다루세요. 보장기간 밖이면 면책기간을 따질 것도 없지만, 제외 항목은 그와 별개로 함께 적힐 수 있습니다.

자기부담금은 사고 하나에 한 번

같은 accident_id 의 청구들이 자기부담금을 나눠 쓰게 하세요. 첫 청구가 다 쓰면 두 번째 청구의 deductible 단계는 0 이고, 첫 청구가 자기부담금보다 작으면 남은 몫을 다음 청구가 마저 씁니다.

사고별로 이미 쓴 자기부담금을 들고 다니면서, 남은 몫과 청구액 중 작은 쪽을 깎습니다. 청구를 접수일 순서로 처리해야 같은 답이 나옵니다 — 순서가 바뀌면 어느 청구가 자기부담금을 무는지가 달라집니다.

연간 한도를 소진시키기

연간 한도를 네 번째 규칙으로 넣으세요. 계약마다 사고 연도 기준으로 쌓이고, 남은 여유를 넘는 만큼만 깎이며, 해가 바뀌면 한도가 다시 살아납니다. steps 의 마지막은 annual_cap 입니다.

연간 한도는 그 계약의 앞선 청구들이 얼마를 썼는지에 달려 있습니다. 판정을 접수일 순서로 돌면서 (계약, 사고 연도)마다 쓴 금액을 누적하세요. 한도를 다 쓴 뒤의 청구는 지급액이 0 이지만 거절은 아닙니다 — decision 은 여전히 paid 이고 annual_cap 이 전액을 깎습니다.

수치는 표에, 반올림은 정책으로

약관 수치를 plan 표에서만 읽게 하고(코드에 값을 적어 두지 마세요), 공동부담 계산의 반올림을 사사오입(ROUND_HALF_UP) 으로 못 박으세요.

파이썬의 round() 와 decimal 의 기본값은 정확히 절반인 값을 짝수 쪽으로 붙입니다. 약관이 사사오입을 말한다면 Decimal 의 quantize 에 rounding 을 명시해야 합니다. 채점기는 표의 수치를 바꿔 넣고 판정이 따라오는지, 그리고 절반인 자리가 올라가는지를 봅니다.

전체 판정과 지급 보고서

/root/coverage/make_payout.py 로 청구 141건을 모두 판정해 /root/coverage/payout.json (claims·paid·denied·billed_total·payable_total·denied_by_reason·cut_by_rule)과 /root/coverage/coverage_report.md (## 무엇을 판정했나 ## 어떤 규칙이 얼마를 깎았나 ## 거절한 건과 이유 ## 남은 위험)를 만드세요.

판정기를 다시 구현하지 말고 --all 의 출력을 모으세요. cut_by_rule 은 steps 의 amount 를 규칙별로 더한 값이고, denied_by_reason 은 reasons 를 사유별로 센 값입니다. 사유가 둘인 청구는 두 사유에 각각 한 번씩 셉니다. 보고서에는 지급 합계를 숫자로 적으세요.