# -*- 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