LabHub
学习 学习路径 课程

保险领域进阶

从日期算出保单状态

在 LabHub 中继续学习

目标

不再从存储的列中读取保单状态,而是直接根据缴费历史和基准日期计算;并能用数据证明,为什么同一个查询会因基准日期和知悉日期不同而得出不同答案。

为什么重要

保险公司收到“保单失效处理没有完成”的反馈后,通常会先查看日志。但问题原因大多不在日志中。status 列只是昨夜批处理计算并写入的判断,事实存在于缴费历史中。两者出现分歧的地方,正是问题反馈发生的地方。

而且保单失效不是一个事件,而是计算结果。任何表中都没有“已失效”这条记录,失效日期由未缴期次和宽限规则推导得出。本练习采用以下规则。

납입기일        해당월 10일
유예 만료일     납입 해당월의 다음 달 말일   (2026-02 회차 → 2026-03-31)
실효일          유예 만료일 다음 날          (2026-04-01)

还要遵守两项优先级。解约和到期事件优先于未缴计算。已经终止的保单无需判断失效。并且只有复效后的期次才参与失效判断。复效并不表示补缴了欠款,而是重新经过复效申请和审核,因此复效之前的欠缴不再导致保单终止。

最后还有另一条时间轴。7 月 5 日收到的缴费更正会改变 6 月 30 日的状态。即使基准日期相同,答案也会因使用截至何时已知的事实进行计算而不同。

步骤

  1. 将右侧示例中的生成器保存为 /root/ins/make_policy.py,并执行 python3 make_policy.py。这会创建 40 份保单、480 个缴费期次、7 个保单事件和 3 条缴费更正。
  2. 对每份存在未缴期次的保单,计算最早未缴期次和失效日期,并写入 /root/ins/lapse_calc.csv,表头为 policy_no,first_unpaid_ym,due_date,grace_end,lapse_date
  3. 计算基准日期 2026-06-30 的保单状态,写入 /root/ins/status_20260630.csv,表头为 policy_no,calc_status。必须包含全部 40 份保单。
  4. 对比 policy.status 与第 3 步的计算结果,只将不一致的保单写入 /root/ins/mismatch.csv,表头为 policy_no,stored_status,calc_status
  5. 使用同一查询,以 2026-09-30 为基准日期再次执行,并在 /root/ins/drift.txt 中写五行:asof_20260630_normal=asof_20260630_lapsed=asof_20260930_normal=asof_20260930_lapsed=moved=
  6. 将基准日期固定为 2026-06-30,分别以 2026-06-302026-08-31 为知悉日期计算,并在 /root/ins/restate.txt 中写四行:known_20260630_lapsed=known_20260831_lapsed=restated=restated_policies=
  7. policy.db 中创建 status_snapshot(as_of_date, known_as_of, policy_no, calc_status) 表,将第 6 步的两组结果分别写入 40 行,共 80 行。
  8. /root/ins/policy_report.md 中按 ## 확인한 것## 상태가 어긋난 계약## 기준일과 인지일## 권고 四个章节编写报告。

参考

创建保单数据

将右侧示例中的生成器保存为 /root/ins/make_policy.py,并执行 python3 make_policy.py。这会创建 40 份保单、480 个缴费期次、7 个保单事件和 3 条缴费更正。

将练习说明中的生成器保存为 /root/ins/make_policy.py,并使用 python3 执行。手动修改会导致后续所有步骤的数值不一致。

计算宽限期和失效日期

对每份存在未缴期次的保单,计算最早未缴期次和失效日期,并写入 /root/ins/lapse_calc.csv,表头为 policy_no,first_unpaid_ym,due_date,grace_end,lapse_date

未缴期次是 paid_date 为 NULL 的行。宽限期届满日是该缴费月份的下一个月末,失效日为其后一天。尝试在 sqlite3 的 date() 函数中添加 '+2 months' 和 '-1 day'。

计算基准日期的保单状态

计算基准日期 2026-06-30 的保单状态,写入 /root/ins/status_20260630.csv,表头为 policy_no,calc_status。必须包含全部 40 份保单。

存在优先级:解约、到期等终止事件优先,其次才是因欠缴导致的失效。而且只有复效后的期次才参与失效判断。

找出与状态列不一致的保单

对比 policy.status 与第 3 步的计算结果,只将不一致的保单写入 /root/ins/mismatch.csv,表头为 policy_no,stored_status,calc_status

按保单编号对齐 policy.status 与上一步计算的状态,只保留不同的记录。请注意,不一致并非只有一个方向。

移动基准日期观察数字分化

使用同一查询,以 2026-09-30 为基准日期再次执行,并在 /root/ins/drift.txt 中写五行:asof_20260630_normal=asof_20260630_lapsed=asof_20260930_normal=asof_20260930_lapsed=moved=

原样使用第 3 步的查询,只更改日期。如果重新编写查询,就会在过程中隐藏拼写错误,而拼写错误总是在实际执行的版本中。

更改知悉日期以揭示追溯更正

将基准日期固定为 2026-06-30,分别以 2026-06-302026-08-31 为知悉日期计算,并在 /root/ins/restate.txt 中写四行:known_20260630_lapsed=known_20260831_lapsed=restated=restated_policies=

基准日期固定为 2026-06-30。知悉日期之后收到的更正在当时尚未知晓,因此必须恢复到 payment_correction 的 old_paid_date 后计算。

固化为可复现的快照

policy.db 中创建 status_snapshot(as_of_date, known_as_of, policy_no, calc_status) 表,将第 6 步的两组结果分别写入 40 行,共 80 行。

仅保存查询无法实现复现。应将计算结果连同基准日期和知悉日期一起写入表中。可以使用 sqlite3 的 .import 将 CSV 导入表。

编写供负责人阅读的报告

/root/ins/policy_report.md 中按 ## 확인한 것## 상태가 어긋난 계약## 기준일과 인지일## 권고 四个章节编写报告。

需要四个章节。不要手动抄写数字,应从前面步骤留下的文件中读取并填入。此外,该数据包含被保险人标识符。