This commit is contained in:
parent
0110be4b16
commit
f30b837212
|
|
@ -1,4 +0,0 @@
|
|||
[settings]
|
||||
order_by_type = true
|
||||
multi_line_output = 3
|
||||
indent = " "
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"python.languageServer": "None"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
认证器
|
||||
认证器模块
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
|
|
|
|||
247
票据理赔自动化/case.py
247
票据理赔自动化/case.py
|
|
@ -1,10 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""通用模块"""
|
||||
|
||||
from typing import Any, Dict, List
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
from datetime import datetime
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import pandas
|
||||
|
||||
from common import masterdata, rules_engine
|
||||
|
||||
|
||||
|
|
@ -28,17 +31,75 @@ def case_adjust(dossier: Dict[str, Any]) -> None:
|
|||
return
|
||||
|
||||
# 赔案理算记录
|
||||
adjustments = (
|
||||
pandas.DataFrame(data=dossier["receipts_layer"]).assing(
|
||||
adjustments=lambda dataframe: dataframe.apply(
|
||||
receipts_adjustments = (
|
||||
(
|
||||
pandas.DataFrame(data=dossier["receipts_layer"]).assign(
|
||||
receipt_adjustments=lambda dataframe: dataframe.apply(
|
||||
lambda row: receipt_adjust(
|
||||
row=row, liabilities=dossier["liabilities_layer"]
|
||||
),
|
||||
axis="columns",
|
||||
) # 票据理算
|
||||
)
|
||||
).explode("adjustments", ignore_index=True)
|
||||
print(adjustments)
|
||||
)
|
||||
.explode(column="receipt_adjustments", ignore_index=True)
|
||||
.pipe(
|
||||
lambda dataframe: pandas.concat(
|
||||
[
|
||||
dataframe.drop(
|
||||
[
|
||||
"receipt_adjustments",
|
||||
],
|
||||
axis="columns",
|
||||
),
|
||||
pandas.json_normalize(dataframe["receipt_adjustments"]),
|
||||
],
|
||||
axis="columns",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
dossier["receipts_layer"] = receipts_adjustments.to_dict(orient="records")
|
||||
|
||||
print(dossier["receipts_layer"])
|
||||
|
||||
# 赔案理算金额
|
||||
dossier["adjustment_layer"].update(
|
||||
{
|
||||
"adjustment_amount": (
|
||||
receipts_adjustments["adjustment_amount"]
|
||||
.sum()
|
||||
.quantize(
|
||||
Decimal("0.00"),
|
||||
rounding=ROUND_HALF_UP,
|
||||
)
|
||||
), # 理算金额
|
||||
}
|
||||
)
|
||||
|
||||
# 实例化JINJA2
|
||||
environment = Environment(
|
||||
loader=FileSystemLoader(file_path := Path(__file__).parent)
|
||||
)
|
||||
# 添加过滤器
|
||||
environment.filters["DateTime"] = lambda i: (
|
||||
i.strftime("%Y-%m-%d") if i != datetime(9999, 12, 31) else "长期"
|
||||
)
|
||||
# 加载赔案档案模版
|
||||
template = environment.get_template("template.html")
|
||||
|
||||
with open(
|
||||
file_path / f"dossiers/{dossier["report_layer"]["case_number"]}.html",
|
||||
"w",
|
||||
encoding="utf-8",
|
||||
) as file:
|
||||
file.write(
|
||||
template.render(
|
||||
{
|
||||
"dossier": dossier,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def receipt_adjust(
|
||||
|
|
@ -46,72 +107,140 @@ def receipt_adjust(
|
|||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
理算票据
|
||||
:param row: 一张票据数据
|
||||
:param row: 票据数据
|
||||
:param liabilities: 理算责任
|
||||
:return: 理算记录
|
||||
"""
|
||||
# 初始化票据理算记录
|
||||
adjustments = []
|
||||
# 初始化剩余个人自费金额
|
||||
remaining_personal_self_payment = row["personal_self_payment"]
|
||||
# 初始化剩余个人自付金额
|
||||
remaining_non_medical_payment = row["non_medical_payment"]
|
||||
# 初始化剩余合理金额
|
||||
remaining_reasonable_amount = row["reasonable_amount"]
|
||||
receipt_adjustments = []
|
||||
|
||||
# 出险事故
|
||||
accident = row["accident"]
|
||||
# 出险人
|
||||
accident_person = row["payer"]
|
||||
# 出险日期
|
||||
accident_date = row["date"]
|
||||
|
||||
# 查验状态
|
||||
verification = row["verification"]
|
||||
|
||||
# 初始化理赔责任理算金额
|
||||
adjustment_amount = Decimal("0.00")
|
||||
# 初始化理赔责任理赔金额
|
||||
claim_amount = Decimal("0.00")
|
||||
|
||||
# 遍历所有理赔责任,根据出险事故、出险人、出险日期和查验状态匹配责任
|
||||
for liability in liabilities:
|
||||
if (
|
||||
accident == liability["accident"]
|
||||
and accident_person == liability["insured_person"]
|
||||
and liability["commencement_date"]
|
||||
<= accident_date
|
||||
<= liability["termination_date"]
|
||||
and verification == "真票"
|
||||
):
|
||||
# 理赔责任理算金额
|
||||
adjustment_amount = (
|
||||
# 初始化票据剩余可理算金额
|
||||
remaining_adjustable_amount = (
|
||||
row["personal_self_payment"]
|
||||
* liability["personal_self_ratio"] # 个人自费金额
|
||||
+ row["non_medical_payment"]
|
||||
* liability["non_medical_ratio"] # 个人自付金额
|
||||
+ row["reasonable_amount"] * liability["reasonable_ratio"] # 合理金额
|
||||
).quantize(
|
||||
+ row["reasonable_amount"]
|
||||
).quantize( # type: ignore[reportAttributeAccessIssue]
|
||||
Decimal("0.00"),
|
||||
rounding=ROUND_HALF_UP,
|
||||
)
|
||||
|
||||
# 据变动保单唯一标识查询最新一条保额变动记录的变动后金额(理赔责任的理赔保单余额)
|
||||
# 遍历所有理赔责任,根据出险人、出险事故、查验状态和出险日期匹配理赔责任
|
||||
for liability in liabilities:
|
||||
if (
|
||||
row["payer"] in [liability["insured_person"] for liability in liabilities]
|
||||
and row["accident"] == liability["accident"]
|
||||
and row["verification"] in ["真票", "无法查验"]
|
||||
and liability["commencement_date"]
|
||||
<= row["date"]
|
||||
<= liability["termination_date"]
|
||||
):
|
||||
# 个单余额
|
||||
remaining_amount = masterdata.query_remaining_amount(
|
||||
policy_guid=liability["policy_guid"],
|
||||
person_policy_guid=liability["person_policy_guid"],
|
||||
)
|
||||
# 理赔责任理赔金额
|
||||
claim_amount = min(
|
||||
|
||||
# 个人自费可理算金额
|
||||
personal_self_adjustable_amount = (
|
||||
row["personal_self_payment"]
|
||||
* liability["personal_self_ratio"]
|
||||
* Decimal("0.01")
|
||||
)
|
||||
# 个人自付可理算金额
|
||||
non_medical_adjustable_amount = (
|
||||
row["non_medical_payment"]
|
||||
* liability["non_medical_ratio"]
|
||||
* Decimal("0.01")
|
||||
)
|
||||
# 合理可理算金额
|
||||
reasonable_adjustable_amount = (
|
||||
row["reasonable_amount"]
|
||||
* liability["reasonable_ratio"]
|
||||
* Decimal("0.01")
|
||||
)
|
||||
|
||||
# 理算金额
|
||||
adjustment_amount = max(
|
||||
Decimal("0.00"),
|
||||
min(
|
||||
remaining_adjustable_amount,
|
||||
remaining_amount,
|
||||
adjustment_amount,
|
||||
adjustable_amount := (
|
||||
(
|
||||
personal_self_adjustable_amount
|
||||
+ non_medical_adjustable_amount
|
||||
+ reasonable_adjustable_amount
|
||||
).quantize(
|
||||
Decimal("0.00"),
|
||||
rounding=ROUND_HALF_UP,
|
||||
)
|
||||
), # 可理算金额
|
||||
),
|
||||
)
|
||||
|
||||
# 初始化票据理算记录
|
||||
adjustment = {
|
||||
"liability": liability["liability"], # 理赔责任名称
|
||||
"type": row["就诊类型"],
|
||||
"amount": row["合理金额"],
|
||||
"payable": 0.0,
|
||||
}
|
||||
# 若理算金额大于0则新增保额扣减记录
|
||||
if adjustment_amount > Decimal("0.00"):
|
||||
masterdata.add_coverage_change(
|
||||
person_policy_guid=liability["person_policy_guid"],
|
||||
before_change_amount=remaining_amount,
|
||||
change_amount=adjustment_amount,
|
||||
)
|
||||
|
||||
return adjustments
|
||||
receipt_adjustments.append(
|
||||
{
|
||||
"person_policy": liability["person_policy"], # 个单号
|
||||
"liability": liability["liability"], # 理赔责任名称
|
||||
"personal_self_payment": row[
|
||||
"personal_self_payment"
|
||||
], # 个人自费金额
|
||||
"personal_self_ratio": liability[
|
||||
"personal_self_ratio"
|
||||
], # 个人自费比例
|
||||
"personal_self_adjustable_amount": personal_self_adjustable_amount, # 个人自费可理算金额
|
||||
"non_medical_payment": row["non_medical_payment"], # 个人自付金额
|
||||
"non_medical_ratio": liability["non_medical_ratio"], # 个人自付比例
|
||||
"non_medical_adjustable_amount": non_medical_adjustable_amount, # 个人自付可理算金额
|
||||
"reasonable_amount": row["reasonable_amount"], # 合理可理算金额
|
||||
"reasonable_ratio": liability["reasonable_ratio"], # 合理部分比例
|
||||
"reasonable_adjustable_amount": reasonable_adjustable_amount, # 合理可理算金额
|
||||
"adjustment_amount": adjustment_amount, # 理算金额
|
||||
"adjustment_explanation": f"""
|
||||
1、应理算金额:{remaining_adjustable_amount:.2f};
|
||||
2、个单余额:{remaining_amount:.2f};
|
||||
3、可理算金额:{adjustable_amount:.2f},其中:
|
||||
1)个人自费可理算金额:{personal_self_adjustable_amount:.2f}={row['personal_self_payment']:.2f}*{liability['personal_self_ratio']:.2f}%;
|
||||
2)个人自付可理算金额:{non_medical_adjustable_amount:.2f}={row['non_medical_payment']:.2f}*{liability['non_medical_ratio']:.2f}%;
|
||||
3)合理部分可理算金额:{reasonable_adjustable_amount:.2f}={row['reasonable_amount']:.2f}*{liability['reasonable_ratio']:.2f}%;
|
||||
4、理算金额:{adjustment_amount:.2f},即上述应理算金额、个人余额和可理算金额的最小值。
|
||||
""".replace(
|
||||
"\n", ""
|
||||
).replace(
|
||||
" ", ""
|
||||
), # 理算说明
|
||||
}
|
||||
)
|
||||
|
||||
remaining_adjustable_amount -= adjustment_amount
|
||||
# 若剩余可理算金额小于等于0则跳出循环
|
||||
if remaining_adjustable_amount <= Decimal("0.00"):
|
||||
break
|
||||
|
||||
if not receipt_adjustments:
|
||||
receipt_adjustments.append(
|
||||
{
|
||||
"person_policy": None, # 个单号
|
||||
"liability": None, # 理赔责任名称
|
||||
"personal_self_payment": None, # 个人自费金额
|
||||
"personal_self_ratio": None, # 个人自费比例
|
||||
"personal_self_adjustable_amount": None, # 个人自费可理算金额
|
||||
"non_medical_payment": None, # 个人自付金额
|
||||
"non_medical_ratio": None, # 个人自付比例
|
||||
"non_medical_adjustable_amount": None, # 个人自付可理算金额
|
||||
"reasonable_amount": None, # 合理可理算金额
|
||||
"reasonable_ratio": None, # 合理部分比例
|
||||
"reasonable_adjustable_amount": None, # 合理可理算金额
|
||||
"adjustment_amount": Decimal("0.00"), # 理赔责任理算金额
|
||||
"adjustment_explanation": "票据不予理算", # 理算说明
|
||||
}
|
||||
)
|
||||
|
||||
return receipt_adjustments
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""通用模块"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from masterdata import MasterData
|
||||
|
||||
sys.path.append(Path(__file__).parent.parent.as_posix())
|
||||
from utils.rules_engine import RulesEngine
|
||||
|
||||
|
||||
# 实例化主数据
|
||||
masterdata = MasterData(database=Path(__file__).parent / "database.db")
|
||||
|
||||
|
|
|
|||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -3,27 +3,27 @@
|
|||
影像件处理模块
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from base64 import b64encode
|
||||
from datetime import datetime
|
||||
from decimal import ROUND_HALF_UP, Decimal
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from hashlib import md5
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy
|
||||
import pandas
|
||||
from common import masterdata, rules_engine
|
||||
from fuzzywuzzy import fuzz
|
||||
from jionlp import parse_location
|
||||
import numpy
|
||||
import pandas
|
||||
|
||||
from utils.authenticator import Authenticator
|
||||
from utils.request import Request
|
||||
from common import masterdata, rules_engine
|
||||
|
||||
sys.path.append(Path(__file__).parent.parent.as_posix())
|
||||
from utils.authenticator import Authenticator
|
||||
from utils.request import Request
|
||||
|
||||
|
||||
# 实例化认证器
|
||||
|
|
@ -139,12 +139,10 @@ def image_read(
|
|||
:return: 影像件图像数组
|
||||
"""
|
||||
try:
|
||||
with open(image_path, "rb") as file:
|
||||
image_bytes = file.read() # 读取影像件字节流
|
||||
|
||||
# 先将影像件字节流转为 numpy.ndarray 对象,再解码为单通道灰度图数组对象
|
||||
# 先使用读取影像件,再解码为单通道灰度图数组对象
|
||||
image_ndarray = cv2.imdecode(
|
||||
buf=numpy.frombuffer(image_bytes, numpy.uint8), flags=cv2.IMREAD_GRAYSCALE
|
||||
buf=numpy.fromfile(file=image_path, dtype=numpy.uint8),
|
||||
flags=cv2.IMREAD_GRAYSCALE,
|
||||
)
|
||||
if image_ndarray is None:
|
||||
raise RuntimeError(f"影像件不存在")
|
||||
|
|
@ -600,7 +598,9 @@ def receipt_recognize(
|
|||
"token": authenticator.get_token(servicer="szkt"), # 获取深圳快瞳访问令牌
|
||||
"imgBase64": f"data:image/{image["image_format"].lstrip(".")};base64,{image["image_base64"]}", # 将影像件格式和BASE64编码嵌入数据统一资源标识符
|
||||
},
|
||||
guid=md5(string=(url + image["image_guid"]).encode("utf-8")).hexdigest().upper(),
|
||||
guid=md5(string=(url + image["image_guid"]).encode("utf-8"))
|
||||
.hexdigest()
|
||||
.upper(),
|
||||
)
|
||||
# 若查验状态为真票或红票则直接整合至赔案档案
|
||||
if response.get("status") == 200 and response.get("code") == 10000:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ from pathlib import Path
|
|||
|
||||
from case import case_adjust
|
||||
from image import image_classify, image_recognize
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 初始化文件路径
|
||||
|
|
@ -20,27 +19,18 @@ if __name__ == "__main__":
|
|||
folder_path = file_path / "directory"
|
||||
folder_path.mkdir(parents=True, exist_ok=True) # 若文件夹路径不存在则创建
|
||||
|
||||
# 实例化JINJA2环境
|
||||
environment = Environment(loader=FileSystemLoader(file_path))
|
||||
# 添加DATE过滤器
|
||||
environment.filters["date"] = lambda date: (
|
||||
date.strftime("%Y-%m-%d") if date else "长期"
|
||||
)
|
||||
# 加载赔案档案模版
|
||||
template = environment.get_template("template.html")
|
||||
|
||||
# 遍历文件夹中赔案文件夹并创建赔案档案
|
||||
for case_path in [x for x in folder_path.iterdir() if x.is_dir()]:
|
||||
# 初始化赔案档案(推送至TPA时,保险公司会提保险分公司名称、报案时间和影像件等,TPA签收后生成赔案号)
|
||||
dossier = {
|
||||
"report_layer": {
|
||||
"report_time": datetime(
|
||||
2025, 7, 25, 12, 0, 0
|
||||
), # 指定报案时间,默认为 datetime对象
|
||||
"case_number": case_path.stem, # 默认为赔案文件夹名称
|
||||
"insurer_company": (
|
||||
insurer_company := "中银保险有限公司苏州分公司"
|
||||
), # 默认为中银保险有限公司苏州分公司
|
||||
"report_time": datetime(
|
||||
2025, 7, 25, 12, 0, 0
|
||||
), # 指定报案时间,默认为 datetime对象
|
||||
}, # 报案层
|
||||
"images_layer": [], # 影像件层
|
||||
"insured_person_layer": {}, # 出险人层
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
主数据模块
|
||||
"""
|
||||
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from decimal import ROUND_HALF_UP, Decimal
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from hashlib import md5
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
import sys
|
||||
from typing import Any, Dict, List
|
||||
|
||||
sys.path.append(Path(__file__).parent.parent.as_posix())
|
||||
from utils.sqlite import SQLite
|
||||
|
|
@ -104,8 +105,6 @@ class MasterData(SQLite):
|
|||
non_medical_ratio TEXT NOT NULL,
|
||||
--合理理算比例
|
||||
reasonable_ratio TEXT NOT NULL,
|
||||
--理赔保单唯一标识
|
||||
claim_policy_guid TEXT NOT NULL,
|
||||
--个单唯一标识
|
||||
person_policy_guid TEXT NOT NULL
|
||||
)
|
||||
|
|
@ -128,8 +127,8 @@ class MasterData(SQLite):
|
|||
after_change_amount TEXT NOT NULL,
|
||||
--变动时间
|
||||
change_time TEXT NOT NULL,
|
||||
--变动保单唯一标识
|
||||
change_policy_guid TEXT NOT NULL
|
||||
--个单唯一标识
|
||||
person_policy_guid TEXT NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
|
@ -200,7 +199,7 @@ class MasterData(SQLite):
|
|||
liabilities.personal_self_ratio,
|
||||
liabilities.non_medical_ratio,
|
||||
liabilities.reasonable_ratio,
|
||||
liabilities.claim_policy_guid
|
||||
liabilities.person_policy_guid
|
||||
FROM insured_persons
|
||||
INNER JOIN person_policies
|
||||
ON insured_persons.person_policy_guid = person_policies.guid
|
||||
|
|
@ -212,10 +211,10 @@ class MasterData(SQLite):
|
|||
INNER JOIN liabilities
|
||||
ON person_policies.guid = liabilities.person_policy_guid
|
||||
INNER JOIN coverage_changes
|
||||
ON liabilities.claim_policy_guid = coverage_changes.change_policy_guid
|
||||
ON liabilities.person_policy_guid = coverage_changes.person_policy_guid
|
||||
AND coverage_changes.change_time = (SELECT MAX(change_time)
|
||||
FROM coverage_changes
|
||||
WHERE liabilities.claim_policy_guid = change_policy_guid)
|
||||
WHERE liabilities.person_policy_guid = person_policy_guid)
|
||||
WHERE group_policies.insurer_company = ?
|
||||
AND insured_persons.insured_person = ?
|
||||
AND insured_persons.identity_type = ?
|
||||
|
|
@ -312,11 +311,11 @@ class MasterData(SQLite):
|
|||
|
||||
def query_remaining_amount(
|
||||
self,
|
||||
policy_guid: str,
|
||||
person_policy_guid: str,
|
||||
) -> Decimal:
|
||||
"""
|
||||
根据变动保单唯一标识查询最新一条保额变动记录的变动后金额
|
||||
:param policy_guid: 变动保单唯一标识
|
||||
根据个单唯一标识查询最新一条保额变动记录的变动后金额
|
||||
:param person_policy_guid: 个单唯一标识
|
||||
:return: 变动后金额
|
||||
"""
|
||||
try:
|
||||
|
|
@ -325,11 +324,11 @@ class MasterData(SQLite):
|
|||
sql="""
|
||||
SELECT after_change_amount
|
||||
FROM coverage_changes
|
||||
WHERE change_policy_guid = ?
|
||||
WHERE person_policy_guid = ?
|
||||
ORDER BY change_time DESC
|
||||
LIMIT 1;
|
||||
""",
|
||||
parameters=(policy_guid,),
|
||||
parameters=(person_policy_guid,),
|
||||
)
|
||||
if not result:
|
||||
raise RuntimeError("查无数据")
|
||||
|
|
@ -341,3 +340,63 @@ class MasterData(SQLite):
|
|||
|
||||
except Exception as exception:
|
||||
raise RuntimeError(f"{str(exception)}") from exception
|
||||
|
||||
def add_coverage_change(
|
||||
self,
|
||||
person_policy_guid: str,
|
||||
before_change_amount: Decimal,
|
||||
change_amount: Decimal,
|
||||
) -> None:
|
||||
"""
|
||||
新增保额扣减记录
|
||||
:param person_policy_guid: 个单唯一标识
|
||||
:param before_change_amount: 变动前金额
|
||||
:param change_amount: 变动金额
|
||||
:return: 无
|
||||
"""
|
||||
if before_change_amount != self.query_remaining_amount(
|
||||
person_policy_guid=person_policy_guid,
|
||||
):
|
||||
raise ValueError("变动前金额不等于最新一条保额变动记录的变动后金额")
|
||||
|
||||
# 变动后金额
|
||||
after_change_amount = (before_change_amount - change_amount).quantize(
|
||||
Decimal("0.00"),
|
||||
rounding=ROUND_HALF_UP,
|
||||
)
|
||||
if after_change_amount < Decimal("0.00"):
|
||||
raise ValueError("变动后金额小于0")
|
||||
|
||||
# 当前时间
|
||||
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
|
||||
# 构建保额变动唯一标识
|
||||
guid = (
|
||||
md5(
|
||||
string=f"{person_policy_guid} 保额扣减 {before_change_amount:.2f} {change_amount:.2f} {after_change_amount:.2f} {current_time}".encode(
|
||||
"utf-8"
|
||||
)
|
||||
)
|
||||
.hexdigest()
|
||||
.upper()
|
||||
)
|
||||
|
||||
with self:
|
||||
if not self.execute(
|
||||
sql="""
|
||||
INSERT INTO coverage_changes
|
||||
(guid, change_type, before_change_amount, change_amount, after_change_amount, change_time, person_policy_guid)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
parameters=(
|
||||
guid,
|
||||
"保额扣减",
|
||||
f"{before_change_amount:.2f}",
|
||||
f"{change_amount:.2f}",
|
||||
f"{after_change_amount:.2f}",
|
||||
current_time,
|
||||
person_policy_guid,
|
||||
),
|
||||
):
|
||||
raise RuntimeError("新增保额扣减记录发生异常")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>赔案档案</title>
|
||||
<style>
|
||||
:root {
|
||||
|
|
@ -70,11 +70,12 @@
|
|||
--color-text-secondary: var(--gray-8);
|
||||
--color-border: var(--gray-3);
|
||||
--color-bg: var(--gray-1);
|
||||
--color-bg-secondary: #FFFFFF;
|
||||
--color-bg-secondary: #ffffff;
|
||||
--border-radius-small: 4px;
|
||||
--border-radius-medium: 6px;
|
||||
--border-radius-large: 8px;
|
||||
--font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif;
|
||||
--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
--box-shadow: 0 4px 10px rgba(0, 0, 0, 0.04);
|
||||
--box-shadow-hover: 0 8px 20px rgba(0, 0, 0, 0.08);
|
||||
--spacing-xs: 4px;
|
||||
|
|
@ -263,12 +264,12 @@
|
|||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.invoice-examination {
|
||||
.invoice-verification {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.examination-tag {
|
||||
.verification-tag {
|
||||
padding: 6px 12px;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
|
|
@ -277,19 +278,19 @@
|
|||
border: 1px solid;
|
||||
}
|
||||
|
||||
.examination-tag.valid {
|
||||
.verification-tag.valid {
|
||||
background: var(--green-1);
|
||||
color: var(--green-7);
|
||||
border-color: var(--green-3);
|
||||
}
|
||||
|
||||
.examination-tag.suspicious {
|
||||
.verification-tag.suspicious {
|
||||
background: var(--orange-1);
|
||||
color: var(--orange-7);
|
||||
border-color: var(--orange-3);
|
||||
}
|
||||
|
||||
.examination-tag.invalid {
|
||||
.verification-tag.invalid {
|
||||
background: var(--red-1);
|
||||
color: var(--red-7);
|
||||
border-color: var(--red-3);
|
||||
|
|
@ -406,7 +407,11 @@
|
|||
<div>
|
||||
<h1>赔案档案</h1>
|
||||
<div class="header-info">
|
||||
<p>赔案编号: {{ dossier.赔案层.赔案编号 }} | 保险总公司: {{ dossier.赔案层.保险总公司 }}</p>
|
||||
<p>
|
||||
赔案编号: {{ dossier.report_layer.case_number }} | 保险分公司:
|
||||
{{ dossier.report_layer.insurer_company }} | 报案时间: {{
|
||||
dossier.report_layer.report_time | DateTime }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -417,21 +422,19 @@
|
|||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>影像件序号</th>
|
||||
<th>影像件唯一标识</th>
|
||||
<th>影像件编号</th>
|
||||
<th>影像件名称</th>
|
||||
<th>已分类(含旋正)</th>
|
||||
<th>影像件类型</th>
|
||||
<th>已识别</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for image in dossier.影像件层 %}
|
||||
{% for image in dossier.images_layer %}
|
||||
<tr>
|
||||
<td>{{ image.影像件序号 }}</td>
|
||||
<td>{{ image.影像件名称 }}</td>
|
||||
<td>{{ image.已分类 }}</td>
|
||||
<td>{{ image.影像件类型 }}</td>
|
||||
<td>{{ image.已识别 }}</td>
|
||||
<td>{{ image.image_guid }}</td>
|
||||
<td>{{ image.image_index }}</td>
|
||||
<td>{{ image.image_name }}</td>
|
||||
<td>{{ image.image_type }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
|
@ -442,154 +445,246 @@
|
|||
<h2>赔案层</h2>
|
||||
<div class="card-container">
|
||||
<div class="card">
|
||||
<h3>申请人信息</h3>
|
||||
<h3>出险人(被保险人)信息</h3>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">与被保险人关系</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.与被保险人关系 }}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">姓名</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.姓名 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.insured_person }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">证件类型</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.证件类型 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.identity_type }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">证件号码</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.证件号码 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.identity_number }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">证件有效期</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.证件有效期起 | date }} 至 {{
|
||||
dossier.赔案层.申请人信息.证件有效期止 | date }}
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.commencement_date | DateTime
|
||||
}} 至 {{ dossier.insured_person_layer.termination_date |
|
||||
DateTime }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">性别</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.性别 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.gender }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">出生</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.出生 | date }} | {{
|
||||
dossier.赔案层.申请人信息.年龄 }}岁
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.birth_date | DateTime }} | {{
|
||||
dossier.insured_person_layer.age }}岁
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">手机号</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.手机号 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.phone_number }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">住址</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.省 }} {{ dossier.赔案层.申请人信息.地 }} {{
|
||||
dossier.赔案层.申请人信息.县 }}
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.province }} {{
|
||||
dossier.insured_person_layer.city }} {{
|
||||
dossier.insured_person_layer.district }}
|
||||
</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.detailed_address }}
|
||||
</div>
|
||||
<div class="info-value">{{ dossier.赔案层.申请人信息.详细地址 }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>受益人信息</h3>
|
||||
<h3>领款信息</h3>
|
||||
<div class="info-grid">
|
||||
<div class="info-item">
|
||||
<div class="info-label">与被保险人关系</div>
|
||||
<div class="info-value">{{ dossier.赔案层.受益人信息.与被保险人关系 }}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">户名</div>
|
||||
<div class="info-value">{{ dossier.赔案层.受益人信息.户名 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.account }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">开户银行</div>
|
||||
<div class="info-value">{{ dossier.赔案层.受益人信息.开户银行 }}</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.account_bank }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-label">银行账号</div>
|
||||
<div class="info-value">{{ dossier.赔案层.受益人信息.银行账号 }}</div>
|
||||
</div>
|
||||
<div class="info-label">户号</div>
|
||||
<div class="info-value">
|
||||
{{ dossier.insured_person_layer.account_number }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>在保个单</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>团单号</th>
|
||||
<th>保险分公司名称</th>
|
||||
<th>被保险人姓名</th>
|
||||
<th>主被保险人</th>
|
||||
<th>与主被保险人关系</th>
|
||||
<th>保险期</th>
|
||||
<th>理赔责任名称</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for liability in dossier.liabilities_layer %}
|
||||
<tr>
|
||||
<td>{{ liability.group_policy }}</td>
|
||||
<td>{{ liability.insurer_company }}</td>
|
||||
<td>{{ liability.insured_person }}</td>
|
||||
<td>{{ liability.master_insured_person }}</td>
|
||||
<td>{{ liability.relationship }}</td>
|
||||
<td>
|
||||
{{ liability.commencement_date | DateTime }} 至 {{
|
||||
liability.termination_date | DateTime }}
|
||||
</td>
|
||||
<td>{{ liability.liability }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>发票层</h2>
|
||||
{% for invoice in dossier.发票层 %}
|
||||
<h2>票据层</h2>
|
||||
{% for receipt in dossier.receipts_layer %}
|
||||
<div class="invoice-card">
|
||||
<div class="invoice-header">
|
||||
<div class="invoice-number-container">
|
||||
<div class="invoice-number">{{ invoice.票据类型 }} | {{ invoice.票据号码 }}</div>
|
||||
<span class="invoice-reference">关联影像件序号: {{ invoice.关联影像件序号 }}</span>
|
||||
<div class="invoice-number">{{ receipt.receipt_number }}</div>
|
||||
<span class="invoice-reference"
|
||||
>关联影像件序号: {{ receipt.image_index }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="invoice-examination">
|
||||
{% if invoice.查验状态 == '真票' %}
|
||||
<span class="examination-tag valid">{{ invoice.查验状态 }}</span>
|
||||
{% elif invoice.查验状态 == '无法查验' %}
|
||||
<span class="examination-tag suspicious">{{ invoice.查验状态 }}</span>
|
||||
<div class="invoice-verification">
|
||||
{% if receipt.verification == '真票' %}
|
||||
<span class="verification-tag valid"
|
||||
>{{ receipt.verification }}</span
|
||||
>
|
||||
{% elif receipt.verification == '无法查验' %}
|
||||
<span class="verification-tag suspicious"
|
||||
>{{ receipt.verification }}</span
|
||||
>
|
||||
{% else %}
|
||||
<span class="examination-tag invalid">{{ invoice.查验状态 }}</span>
|
||||
<span class="verification-tag invalid"
|
||||
>{{ receipt.verification }}</span
|
||||
>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="invoice-details">
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">就诊人</div>
|
||||
<div class="detail-value">{{ invoice.就诊人 }}</div>
|
||||
<div class="detail-label">出险人</div>
|
||||
<div class="detail-value">{{ receipt.payer }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">票据代码</div>
|
||||
<div class="detail-value">{{ invoice.票据代码 }}</div>
|
||||
<div class="detail-value">{{ receipt.code }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">校验码后六位</div>
|
||||
<div class="detail-value">{{ invoice.校验码后六位 }}</div>
|
||||
<div class="detail-value">{{ receipt.verification_code }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">开票日期</div>
|
||||
<div class="detail-value">{{ invoice.开票日期 | date }}</div>
|
||||
<div class="detail-value">{{ receipt.date | DateTime }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">票据金额</div>
|
||||
<div class="detail-value">{{ invoice.票据金额 }}元</div>
|
||||
<div class="detail-value">{{ receipt.amount }}元</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">就诊类型</div>
|
||||
<div class="detail-value">{{ invoice.就诊类型 }}</div>
|
||||
<div class="detail-label">出险事故</div>
|
||||
<div class="detail-value">{{ receipt.accident }}</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">医药机构</div>
|
||||
<div class="detail-value">{{ invoice.医药机构 }}</div>
|
||||
<div class="detail-label">购药及就医机构</div>
|
||||
<div class="detail-value">
|
||||
{{ receipt.institution }} | {{ receipt.institution_type }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-item">
|
||||
<div class="detail-label">推定疾病</div>
|
||||
<div class="detail-value">{{ invoice.推定疾病 }}</div>
|
||||
<div class="detail-label">医疗诊断</div>
|
||||
<div class="detail-value">{{ receipt.diagnosis }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>大项</th>
|
||||
<th>小项</th>
|
||||
<th>类别</th>
|
||||
<th>药品/医疗服务</th>
|
||||
<th>数量</th>
|
||||
<th>金额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in invoice.项目 %}
|
||||
{% for item in receipt.items %}
|
||||
<tr>
|
||||
<td>{{ item.大项 }}</td>
|
||||
<td>{{ item.小项 }}</td>
|
||||
<td>{{ item.数量 }}</td>
|
||||
<td>{{ item.金额 }}元</td>
|
||||
<td>{{ item.category }}</td>
|
||||
<td>{{ item.medicine }}</td>
|
||||
<td>{{ item.quantity }}</td>
|
||||
<td>{{ item.amount }}元</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="amount-total">总金额: {{ invoice.票据金额 }}元</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>个人自费可理算金额</th>
|
||||
<th>个人自付可理算金额</th>
|
||||
<th>合理可理算金额</th>
|
||||
<th>理算金额</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for adjustment in receipt.adjustments %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ adjustment.personal_self_adjustable_amount }} = {{
|
||||
adjustment.personal_self_payment }} * {{
|
||||
adjustment.personal_self_ratio }} %
|
||||
</td>
|
||||
<td>
|
||||
{{ adjustment.non_medical_adjustable_amount }} = {{
|
||||
adjustment.non_medical_payment }} * {{
|
||||
adjustment.non_medical_ratio }} %
|
||||
</td>
|
||||
<td>
|
||||
{{ adjustment.reasonable_adjustable_amount }} = {{
|
||||
adjustment.reasonable_amount }} * {{
|
||||
adjustment.reasonable_ratio }} %
|
||||
</td>
|
||||
<td>{{ adjustment.adjustment_amount }}元</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="amount-total">总金额: {{ receipt.amount }}元</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue