from __future__ import annotations import re from typing import Any EXPENSE_RULE_CODE_BLOCK_PATTERN = re.compile(r"```expense-rule\s*(\{.*?\})\s*```", re.DOTALL) DOCUMENT_TYPE_LABELS = { "flight_itinerary": "机票/航班行程单", "train_ticket": "火车/高铁票", "hotel_invoice": "酒店住宿票据", "taxi_receipt": "出租车/网约车票据", "parking_toll_receipt": "停车/通行费票据", "meal_receipt": "餐饮票据", "office_invoice": "办公用品票据", "meeting_invoice": "会议/会务票据", "training_invoice": "培训票据", "vat_invoice": "增值税发票", "receipt": "一般收据/凭证", "other": "其他单据", } SCENE_LABELS = { "travel": "差旅", "hotel": "住宿", "transport": "交通", "meal": "餐饮", "entertainment": "业务招待", "office": "办公", "meeting": "会务", "training": "培训", "communication": "通讯", "welfare": "福利", "other": "其他", } DEFAULT_SCENE_RULE_ASSET_CODE = "rule.expense.scene_submission_standard" DEFAULT_TRAVEL_RULE_ASSET_CODE = "rule.expense.travel_risk_control_standard" DEFAULT_SCENE_MATRIX_CONFIG: dict[str, Any] = { "kind": "scene_matrix", "version": 1, "scenes": { "travel": { "label": "差旅费", "location_required": True, "min_attachment_count": 1, "allowed_scene_codes": ["travel"], "allowed_document_types": ["flight_itinerary", "train_ticket"], "attachment_mismatch_severity": "high", }, "hotel": { "label": "住宿费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["hotel"], "allowed_document_types": ["hotel_invoice", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", }, "transport": { "label": "交通费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["transport"], "allowed_document_types": ["taxi_receipt", "parking_toll_receipt", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "item_amount_limit": { "scope": "item_amount", "warn_amount": "300.00", "block_amount": "800.00", "exception_keywords": ["跨城", "夜间", "应急", "无公共交通", "机场", "火车站", "超标说明"], "metric_label": "单笔交通金额", }, }, "meal": { "label": "餐费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["meal"], "allowed_document_types": ["meal_receipt", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "300.00", "block_amount": "800.00", "exception_keywords": ["客户接待", "团队活动", "加班", "展会", "超标说明"], "metric_label": "餐费合计", }, }, "entertainment": { "label": "业务招待费", "location_required": True, "min_attachment_count": 1, "allowed_scene_codes": ["meal"], "allowed_document_types": ["meal_receipt", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "2000.00", "block_amount": "5000.00", "exception_keywords": ["重要客户", "商务宴请", "项目签约", "超标说明"], "metric_label": "招待费合计", }, }, "office": { "label": "办公费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["office"], "allowed_document_types": ["office_invoice", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "1500.00", "block_amount": "5000.00", "exception_keywords": ["批量采购", "固定资产", "部门集中采购", "超标说明"], "metric_label": "办公费合计", }, }, "meeting": { "label": "会务费", "location_required": True, "min_attachment_count": 1, "allowed_scene_codes": ["meeting"], "allowed_document_types": ["meeting_invoice", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "5000.00", "block_amount": "30000.00", "exception_keywords": ["大型会议", "外部场地", "超标说明"], "metric_label": "会务费合计", }, }, "training": { "label": "培训费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["training"], "allowed_document_types": ["training_invoice", "vat_invoice", "receipt"], "attachment_mismatch_severity": "high", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "3000.00", "block_amount": "15000.00", "exception_keywords": ["认证考试", "外部培训", "超标说明"], "metric_label": "培训费合计", }, }, "communication": { "label": "通讯费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["other"], "allowed_document_types": ["vat_invoice", "receipt"], "attachment_mismatch_severity": "medium", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "300.00", "block_amount": "1000.00", "exception_keywords": ["国际漫游", "专项通信", "超标说明"], "metric_label": "通讯费合计", }, }, "welfare": { "label": "福利费", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["other"], "allowed_document_types": ["vat_invoice", "receipt"], "attachment_mismatch_severity": "medium", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "1000.00", "block_amount": "5000.00", "exception_keywords": ["节日福利", "团队活动", "员工关怀", "超标说明"], "metric_label": "福利费合计", }, }, "other": { "label": "其他费用", "location_required": False, "min_attachment_count": 1, "allowed_scene_codes": ["other"], "allowed_document_types": ["vat_invoice", "receipt"], "attachment_mismatch_severity": "medium", "always_warn": True, "always_warn_message": "其他费用默认进入人工重点复核,请补充清晰用途说明并由审批人重点确认。", "claim_amount_limit": { "scope": "claim_total", "warn_amount": "1000.00", "block_amount": "3000.00", "exception_keywords": ["特殊事项", "临时采购", "超标说明"], "metric_label": "其他费用合计", }, }, }, } DEFAULT_TRAVEL_POLICY_CONFIG: dict[str, Any] = { "kind": "travel_policy", "version": 1, "relevant_expense_types": ["travel", "hotel", "transport"], "long_distance_document_types": ["flight_itinerary", "train_ticket"], "route_exception_keywords": [ "中转", "转机", "经停", "改签", "多地出差", "多城市", "多站", "异地返程", "异地结束", "临时变更", "继续前往", "第二站", ], "standard_exception_keywords": [ "超标说明", "无直达", "展会高峰", "会议高峰", "协议酒店满房", "客户指定", "临时改签", "行程变更", "红眼航班", "晚到店", ], "band_labels": { "junior": "P1-P3", "mid": "P4-P5", "senior": "P6-P7", "manager": "M1-M2", "executive": "M3及以上 / D序列", }, "city_tiers": { "北京": "tier_1", "上海": "tier_1", "广州": "tier_1", "深圳": "tier_1", "杭州": "tier_2", "南京": "tier_2", "苏州": "tier_2", "武汉": "tier_2", "成都": "tier_2", "重庆": "tier_2", "西安": "tier_2", "天津": "tier_2", "宁波": "tier_2", "厦门": "tier_2", "青岛": "tier_2", "长沙": "tier_2", "郑州": "tier_2", "合肥": "tier_2", "济南": "tier_2", "沈阳": "tier_2", "大连": "tier_2", "福州": "tier_2", "昆明": "tier_2", "海口": "tier_2", "三亚": "tier_2", "无锡": "tier_2", "东莞": "tier_2", "佛山": "tier_2", }, "hotel_limits": { "junior": {"tier_1": "450.00", "tier_2": "380.00", "tier_3": "320.00"}, "mid": {"tier_1": "550.00", "tier_2": "480.00", "tier_3": "380.00"}, "senior": {"tier_1": "700.00", "tier_2": "620.00", "tier_3": "520.00"}, "manager": {"tier_1": "900.00", "tier_2": "820.00", "tier_3": "720.00"}, "executive": {"tier_1": "1200.00", "tier_2": "1000.00", "tier_3": "900.00"}, }, "transport_limits": { "junior": {"flight": 1, "train": 1}, "mid": {"flight": 1, "train": 1}, "senior": {"flight": 2, "train": 2}, "manager": {"flight": 3, "train": 3}, "executive": {"flight": 4, "train": 3}, }, "flight_classes": [ {"keyword": "头等舱", "level": 4}, {"keyword": "公务舱", "level": 3}, {"keyword": "商务舱", "level": 3}, {"keyword": "超级经济舱", "level": 2}, {"keyword": "高端经济舱", "level": 2}, {"keyword": "明珠经济舱", "level": 2}, {"keyword": "经济舱", "level": 1}, ], "train_classes": [ {"keyword": "商务座", "level": 3}, {"keyword": "一等座", "level": 2}, {"keyword": "软卧", "level": 2}, {"keyword": "二等座", "level": 1}, {"keyword": "二等卧", "level": 1}, {"keyword": "硬卧", "level": 1}, ], }