2026-05-26 09:15:14 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
|
|
|
|
from app.core.agent_enums import AgentAssetDomain
|
|
|
|
|
from app.services.expense_type_keywords import EXPENSE_TYPE_LABEL_BY_CODE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
|
|
|
class RiskRuleField:
|
|
|
|
|
key: str
|
|
|
|
|
label: str
|
|
|
|
|
field_type: str
|
|
|
|
|
source: str
|
|
|
|
|
aliases: tuple[str, ...]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BUSINESS_DOMAIN_LABELS: dict[str, str] = {
|
|
|
|
|
AgentAssetDomain.EXPENSE.value: "报销",
|
|
|
|
|
AgentAssetDomain.AR.value: "应收",
|
|
|
|
|
AgentAssetDomain.AP.value: "应付",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RISK_LEVEL_LABELS: dict[str, str] = {
|
|
|
|
|
"low": "低风险",
|
|
|
|
|
"medium": "中风险",
|
|
|
|
|
"high": "高风险",
|
|
|
|
|
"critical": "极高风险",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EXPENSE_RISK_CATEGORY_CODES: tuple[str, ...] = (
|
2026-06-01 17:07:14 +08:00
|
|
|
"all",
|
2026-05-26 09:15:14 +08:00
|
|
|
"travel",
|
|
|
|
|
"hotel",
|
|
|
|
|
"transport",
|
|
|
|
|
"meal",
|
|
|
|
|
"meeting",
|
|
|
|
|
"office",
|
|
|
|
|
"training",
|
|
|
|
|
"communication",
|
|
|
|
|
"welfare",
|
|
|
|
|
)
|
|
|
|
|
EXPENSE_RISK_CATEGORY_LABELS: dict[str, str] = {
|
2026-06-01 17:07:14 +08:00
|
|
|
"all": "全部",
|
|
|
|
|
**{
|
|
|
|
|
code: EXPENSE_TYPE_LABEL_BY_CODE[code]
|
|
|
|
|
for code in EXPENSE_RISK_CATEGORY_CODES
|
|
|
|
|
if code != "all"
|
|
|
|
|
},
|
2026-05-26 09:15:14 +08:00
|
|
|
}
|
|
|
|
|
EXPENSE_RISK_CATEGORY_ALIASES = {
|
2026-06-01 17:07:14 +08:00
|
|
|
"*": "all",
|
|
|
|
|
"overall": "all",
|
|
|
|
|
"general": "all",
|
|
|
|
|
"全部": "all",
|
|
|
|
|
"通用": "all",
|
2026-05-26 09:15:14 +08:00
|
|
|
"entertainment": "meal",
|
2026-06-01 17:07:14 +08:00
|
|
|
"business_meal": "meal",
|
|
|
|
|
"purchase": "office",
|
2026-05-26 09:15:14 +08:00
|
|
|
}
|
|
|
|
|
|
2026-05-26 12:16:20 +08:00
|
|
|
EXPENSE_BUSINESS_STAGE_LABELS: dict[str, str] = {
|
|
|
|
|
"expense_application": "费用申请",
|
|
|
|
|
"reimbursement": "费用报销",
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 09:15:14 +08:00
|
|
|
FIELD_ONTOLOGY: tuple[RiskRuleField, ...] = (
|
|
|
|
|
RiskRuleField("claim.reason", "报销事由", "text", "claim", ("事由", "说明", "理由", "用途")),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"claim.location",
|
|
|
|
|
"申报地点",
|
|
|
|
|
"text",
|
|
|
|
|
"claim",
|
|
|
|
|
("地点", "城市", "出差地", "申报地点", "申报目的地", "目的地"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"claim.trip_start_date",
|
|
|
|
|
"出差开始日期",
|
|
|
|
|
"date",
|
|
|
|
|
"claim",
|
|
|
|
|
("出差开始", "行程开始", "开始日期", "出差起始", "出发日期"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"claim.trip_end_date",
|
|
|
|
|
"出差结束日期",
|
|
|
|
|
"date",
|
|
|
|
|
"claim",
|
|
|
|
|
("出差结束", "行程结束", "结束日期", "返程日期", "返回日期"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField("claim.amount", "申报金额", "number", "claim", ("金额", "费用", "超额", "额度")),
|
2026-05-30 15:46:51 +08:00
|
|
|
RiskRuleField("claim.attendee_count", "参与人数", "number", "claim", ("人数", "参与人员数", "招待人数")),
|
|
|
|
|
RiskRuleField("claim.per_capita_amount", "人均金额", "number", "claim", ("人均", "人均金额", "人均招待")),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"budget.remaining_amount",
|
|
|
|
|
"预算可用余额",
|
|
|
|
|
"number",
|
|
|
|
|
"budget",
|
|
|
|
|
("预算余额", "可用预算", "可用余额", "剩余预算", "预算剩余"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"budget.limit_amount",
|
|
|
|
|
"预算额度",
|
|
|
|
|
"number",
|
|
|
|
|
"budget",
|
|
|
|
|
("预算额度", "预算上限", "预算阈值", "预算限额"),
|
|
|
|
|
),
|
2026-05-26 09:15:14 +08:00
|
|
|
RiskRuleField("claim.employee_name", "报销人", "text", "claim", ("报销人", "员工", "申请人")),
|
|
|
|
|
RiskRuleField("claim.department_name", "部门", "text", "claim", ("部门", "组织")),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"employee.location",
|
|
|
|
|
"员工常驻地",
|
|
|
|
|
"text",
|
|
|
|
|
"employee",
|
2026-06-03 15:46:56 +08:00
|
|
|
("常驻地", "办公地", "员工所在地", "所在城市"),
|
2026-05-26 09:15:14 +08:00
|
|
|
),
|
|
|
|
|
RiskRuleField("item.item_type", "费用类型", "enum", "item", ("费用类型", "科目", "类型")),
|
|
|
|
|
RiskRuleField("item.item_reason", "明细事由", "text", "item", ("明细事由", "明细说明")),
|
|
|
|
|
RiskRuleField("item.item_location", "明细地点", "text", "item", ("明细地点", "发生地点")),
|
|
|
|
|
RiskRuleField("item.item_date", "明细发生日期", "date", "item", ("明细日期", "发生日期", "费用日期")),
|
2026-05-30 15:46:51 +08:00
|
|
|
RiskRuleField("item.invoice_id", "明细附件编号", "text", "item", ("附件编号", "票据编号", "发票附件")),
|
2026-05-26 09:15:14 +08:00
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.invoice_no", "发票号码", "text", "attachment", ("发票号", "发票号码", "票号")
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.buyer_name", "购买方名称", "text", "attachment", ("抬头", "购买方", "开票单位")
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.goods_name",
|
|
|
|
|
"商品服务名称",
|
|
|
|
|
"text",
|
|
|
|
|
"attachment",
|
|
|
|
|
("品名", "商品", "服务名称", "摘要"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.issue_date",
|
|
|
|
|
"开票日期",
|
|
|
|
|
"date",
|
|
|
|
|
"attachment",
|
|
|
|
|
("开票日期", "发票日期", "票据日期"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.stay_start_date",
|
|
|
|
|
"住宿开始日期",
|
|
|
|
|
"date",
|
|
|
|
|
"attachment",
|
|
|
|
|
("入住日期", "住宿开始", "入住时间", "住宿开始日期"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.stay_end_date",
|
|
|
|
|
"住宿结束日期",
|
|
|
|
|
"date",
|
|
|
|
|
"attachment",
|
|
|
|
|
("离店日期", "退房日期", "住宿结束", "住宿结束日期"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.hotel_city",
|
|
|
|
|
"住宿城市",
|
|
|
|
|
"text",
|
|
|
|
|
"attachment",
|
|
|
|
|
("住宿城市", "酒店城市", "酒店地点", "酒店发票城市", "酒店票城市", "住宿发票城市"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.route_cities",
|
|
|
|
|
"行程城市",
|
|
|
|
|
"list",
|
|
|
|
|
"attachment",
|
|
|
|
|
("行程", "路线", "途经城市", "出差城市", "交通票行程", "交通票城市"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"attachment.ocr_text",
|
|
|
|
|
"票据全文",
|
|
|
|
|
"text",
|
|
|
|
|
"attachment",
|
|
|
|
|
("票据内容", "OCR", "全文", "关键字", "关键词"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"receivable.aging_days", "应收账龄", "number", "receivable", ("账龄", "逾期", "应收逾期")
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"receivable.amount_outstanding",
|
|
|
|
|
"应收未收金额",
|
|
|
|
|
"number",
|
|
|
|
|
"receivable",
|
|
|
|
|
("未收金额", "欠款", "应收余额"),
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"payable.vendor_name", "供应商名称", "text", "payable", ("供应商", "付款方", "往来单位")
|
|
|
|
|
),
|
|
|
|
|
RiskRuleField(
|
|
|
|
|
"payable.amount_outstanding", "应付未付金额", "number", "payable", ("未付金额", "应付余额")
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
DOMAIN_FIELD_PREFIXES: dict[str, tuple[str, ...]] = {
|
2026-05-30 15:46:51 +08:00
|
|
|
AgentAssetDomain.EXPENSE.value: ("claim.", "item.", "attachment.", "employee.", "budget."),
|
2026-05-26 09:15:14 +08:00
|
|
|
AgentAssetDomain.AR.value: ("receivable.",),
|
|
|
|
|
AgentAssetDomain.AP.value: ("payable.",),
|
|
|
|
|
}
|