从日期算出保单状态
目标
不再从存储的列中读取保单状态,而是直接根据缴费历史和基准日期计算;并能用数据证明,为什么同一个查询会因基准日期和知悉日期不同而得出不同答案。
为什么重要
保险公司收到“保单失效处理没有完成”的反馈后,通常会先查看日志。但问题原因大多不在日志中。status 列只是昨夜批处理计算并写入的判断,事实存在于缴费历史中。两者出现分歧的地方,正是问题反馈发生的地方。
而且保单失效不是一个事件,而是计算结果。任何表中都没有“已失效”这条记录,失效日期由未缴期次和宽限规则推导得出。本练习采用以下规则。
납입기일 해당월 10일
유예 만료일 납입 해당월의 다음 달 말일 (2026-02 회차 → 2026-03-31)
실효일 유예 만료일 다음 날 (2026-04-01)
还要遵守两项优先级。解约和到期事件优先于未缴计算。已经终止的保单无需判断失效。并且只有复效后的期次才参与失效判断。复效并不表示补缴了欠款,而是重新经过复效申请和审核,因此复效之前的欠缴不再导致保单终止。
最后还有另一条时间轴。7 月 5 日收到的缴费更正会改变 6 月 30 日的状态。即使基准日期相同,答案也会因使用截至何时已知的事实进行计算而不同。
步骤
- 将右侧示例中的生成器保存为
/root/ins/make_policy.py,并执行python3 make_policy.py。这会创建 40 份保单、480 个缴费期次、7 个保单事件和 3 条缴费更正。 - 对每份存在未缴期次的保单,计算最早未缴期次和失效日期,并写入
/root/ins/lapse_calc.csv,表头为policy_no,first_unpaid_ym,due_date,grace_end,lapse_date。 - 计算基准日期
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。 - 使用同一查询,以
2026-09-30为基准日期再次执行,并在/root/ins/drift.txt中写五行:asof_20260630_normal=、asof_20260630_lapsed=、asof_20260930_normal=、asof_20260930_lapsed=、moved=。 - 将基准日期固定为
2026-06-30,分别以2026-06-30和2026-08-31为知悉日期计算,并在/root/ins/restate.txt中写四行:known_20260630_lapsed=、known_20260831_lapsed=、restated=、restated_policies=。 - 在
policy.db中创建status_snapshot(as_of_date, known_as_of, policy_no, calc_status)表,将第 6 步的两组结果分别写入 40 行,共 80 行。 - 在
/root/ins/policy_report.md中按## 확인한 것、## 상태가 어긋난 계약、## 기준일과 인지일、## 권고四个章节编写报告。
参考
- 使用
sqlite3 -readonly <파일> "<쿼리>"读取,可以防止误写。 - 月末通过
date('2026-02-01','+2 months','-1 day')计算。每个月的最后一天不同,请勿手动相加。 - 常见错误 1:使用
.mode csv输出时,韩文值会带双引号。使用.mode list和.separator ,可以得到更简洁的结果(评分器两者都接受)。 - 常见错误 2:将宽限期届满当天计为失效。基准日期为
2026-06-30时,宽限期届满日同为2026-06-30的保单仍属正常。 - 常见错误 3:将复效前的未缴期次也纳入失效判断。这样三份已复效保单都会被判为失效。
- 常见错误 4:第 8 步用眼睛查看数字后手动抄写。手动抄写的数字一定会有一位出错。
创建保单数据
将右侧示例中的生成器保存为 /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-30 和 2026-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 中按 ## 확인한 것、## 상태가 어긋난 계약、## 기준일과 인지일、## 권고 四个章节编写报告。
需要四个章节。不要手动抄写数字,应从前面步骤留下的文件中读取并填入。此外,该数据包含被保险人标识符。