Python/票据理赔自动化/case.py

259 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""通用模块"""
from decimal import Decimal, ROUND_HALF_UP
from pathlib import Path
import sys
from typing import Any, Dict, List
from common import masterdata, rules_engine
sys.path.append(Path(__file__).parent.parent.as_posix())
from utils.html_render import HTMLRenderer
def case_adjust(dossier: Dict[str, Any]) -> None:
"""
理算赔案并整合至赔案档案
:param dossier: 赔案档案
:return: 无
"""
# 基于拒付决策规则评估
if not (result := rules_engine.evaluate(decision="拒付", inputs=dossier)):
raise RuntimeError("该保险分公司未配置拒付规则")
dossier["adjustment_layer"].update(
{
"conclusion": (conclusion := result["conclusion"]), # 理赔结论
"explanation": result["explanation"], # 结论说明
}
)
if conclusion == "拒付":
return
# 就票据层按照开票日期和票据号顺序排序
dossier["receipts_layer"].sort(key=lambda x: (x["date"], x["number"]))
# 遍历票据层内所有票据,票据理算并添加理算记录
for idx, receipt in enumerate(dossier["receipts_layer"]):
# 添加理算记录
dossier["receipts_layer"][idx]["adjustments"] = receipt_adjust(
receipt=receipt, liabilities=dossier["liabilities_layer"]
)
# 票据理算金额
dossier["receipts_layer"][idx]["adjustment_amount"] = Decimal(
sum(
[
adjustment["adjustment_amount"]
for adjustment in dossier["receipts_layer"][idx]["adjustments"]
]
)
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 赔案理算金额
dossier["adjustment_layer"]["adjustment_amount"] = Decimal(
sum(
[
adjustment["adjustment_amount"]
for receipt in dossier["receipts_layer"]
for adjustment in receipt["adjustments"]
]
)
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 实例化HTML渲染器
html_renderer = HTMLRenderer(template_path=Path(__file__).parent / "template.html")
# 根据赔案档案渲染HTML文档
html_renderer.render(
obj=dossier,
output_path=Path(__file__).parent
/ "dossiers"
/ f"{dossier["report_layer"]["case_number"]}.html",
)
def receipt_adjust(
receipt: Dict[str, Any], liabilities: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
"""
理算票据
:param receipt: 票据数据字典
:param liabilities: 理算责任
:return: 理算记录
"""
# 初始化理算记录
adjustments = []
# 初始化票据剩余理算金额
remaining_adjustment_amount = masterdata.query_remaining_adjustment_amount(
receipt_number=receipt["number"],
)
if remaining_adjustment_amount is None:
remaining_adjustment_amount = (
receipt["personal_self_payment"] # 个人自费金额
+ receipt["non_medical_payment"] # 个人自付金额
+ receipt["reasonable_amount"] # 合理金额
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 遍历所有理赔责任,根据出险人、理赔类型、查验状态和出险日期匹配理赔责任
for liability in liabilities:
if (
receipt["payer"]
in [liability["insured_person"] for liability in liabilities]
and receipt["accident"] == liability["accident"]
and receipt["verification"] in ["真票", "无法查验"]
and liability["commencement_date"]
<= receipt["date"]
<= liability["termination_date"]
):
# 个单剩余保额
remaining_coverage_amount = masterdata.query_after_change_amount(
person_policy_guid=liability["person_policy_guid"],
)
# 个人自费可理算金额
personal_self_adjustable_amount = (
receipt["personal_self_payment"] # 个人自费金额
* liability["personal_self_ratio"] # 个人自费理算比例
* Decimal("0.01")
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 个人自付可理算金额
non_medical_adjustable_amount = (
receipt["non_medical_payment"] # 个人自付金额
* liability["non_medical_ratio"] # 个人自付理算比例
* Decimal("0.01")
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 合理可理算金额
reasonable_adjustable_amount = (
receipt["reasonable_amount"] # 合理金额
* liability["reasonable_ratio"] # 合理理算比例
* Decimal("0.01")
).quantize(
exp=Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
# 理算金额
adjustment_amount = max(
Decimal("0.00"),
min(
remaining_adjustment_amount, # 剩余理算金额
remaining_coverage_amount, # 个单剩余保额
adjustable_amount := (
(
personal_self_adjustable_amount # 个人自费可理算金额
+ non_medical_adjustable_amount # 个人自付可理算金额
+ reasonable_adjustable_amount # 合理可理算金额
).quantize(
Decimal("0.00"),
rounding=ROUND_HALF_UP,
)
), # 可理算金额
),
)
# 若理算金额大于0则新增保额扣减记录
if adjustment_amount > Decimal("0.00"):
masterdata.add_coverage_change(
person_policy_guid=liability["person_policy_guid"],
before_change_amount=remaining_coverage_amount,
change_amount=adjustment_amount,
)
adjustments.append(
{
"group_policy": liability["group_policy"], # 团单号
"person_policy": liability["person_policy"], # 个单号
"liability": liability["liability"], # 理赔责任名称
"accident": liability["accident"], # 理赔类型
"personal_self_payment": receipt[
"personal_self_payment"
], # 个人自费金额
"personal_self_ratio": liability[
"personal_self_ratio"
], # 个人自费理算比例
"personal_self_adjustable_amount": personal_self_adjustable_amount, # 个人自费可理算金额
"non_medical_payment": receipt[
"non_medical_payment"
], # 个人自付金额
"non_medical_ratio": liability[
"non_medical_ratio"
], # 个人自付理算比例
"non_medical_adjustable_amount": non_medical_adjustable_amount, # 个人自付可理算金额
"reasonable_amount": receipt["reasonable_amount"], # 合理金额
"reasonable_ratio": liability["reasonable_ratio"], # 合理理算比例
"reasonable_adjustable_amount": reasonable_adjustable_amount, # 合理可理算金额
"remaining_adjustment_amount": remaining_adjustment_amount, # 剩余理算金额
"remaining_coverage_amount": remaining_coverage_amount, # 个单剩余保额
"adjustable_amount": adjustable_amount, # 可理算金额
"adjustment_amount": adjustment_amount, # 理算金额
"adjustment_explanation": f"""
1、剩余理算金额{remaining_adjustment_amount:.2f}
2、个单剩余保额{remaining_coverage_amount:.2f}
3、可理算金额{adjustable_amount:.2f},其中:
1个人自费可理算金额{personal_self_adjustable_amount:.2f}={receipt['personal_self_payment']:.2f}*{liability['personal_self_ratio']:.2f}%
2个人自付可理算金额{non_medical_adjustable_amount:.2f}={receipt['non_medical_payment']:.2f}*{liability['non_medical_ratio']:.2f}%
3合理部分可理算金额{reasonable_adjustable_amount:.2f}={receipt['reasonable_amount']:.2f}*{liability['reasonable_ratio']:.2f}%
4、理算金额{adjustment_amount:.2f},即上述应理算金额、个人余额和可理算金额的最小值。
""".replace(
"\n", ""
).replace(
" ", ""
), # 理算说明
}
)
remaining_adjustment_amount -= adjustment_amount
# 若剩余理算金额小于等于0则跳出循环
if remaining_adjustment_amount <= Decimal("0.00"):
break
if not adjustments:
adjustments.append(
{
"group_policy": None, # 团单号
"person_policy": None, # 个单号
"liability": None, # 理赔责任名称
"accident": None, # 理赔类型
"personal_self_payment": receipt[
"personal_self_payment"
], # 个人自费金额
"personal_self_ratio": None, # 个人自费理算比例
"personal_self_adjustable_amount": None, # 个人自费可理算金额
"non_medical_payment": receipt["non_medical_payment"], # 个人自付金额
"non_medical_ratio": None, # 个人自付理算比例
"non_medical_adjustable_amount": None, # 个人自付可理算金额
"reasonable_amount": receipt["reasonable_amount"], # 合理金额
"reasonable_ratio": None, # 合理理算比例
"reasonable_adjustable_amount": None, # 合理可理算金额
"remaining_adjustment_amount": remaining_adjustment_amount, # 剩余理算金额
"remaining_coverage_amount": None, # 个单剩余保额
"adjustable_amount": None, # 可理算金额
"adjustment_amount": Decimal("0.00"), # 理算金额
"adjustment_explanation": "票据不予理算", # 理算说明
}
)
# 新增理算记录
masterdata.add_ajustment(
receipt_number=receipt["number"],
remaining_adjustment_amount=remaining_adjustment_amount,
)
return adjustments