实现报销费用政策与票据明细门禁(08-29-reimbursement-expense-policy-invoice-guard)

这个提交包含在:
2026-08-29 23:47:22 +08:00
父节点 9e2aea5f70
当前提交 6e999d5bf9
共修改 34 个文件,包含 1458 行新增和 92 行删除
+63 -40
查看文件
@@ -3,54 +3,69 @@ require("dotenv/config");
const { createPrismaClient } = require("../prismaClient");
const ENABLED_EXPENSE_TYPES = [
{ code: "travel_airfare", name: "机票", category: "travel" },
{ code: "travel_train", name: "火车票", category: "travel" },
{ code: "travel_taxi", name: "打车费", category: "travel" },
{ code: "travel_hotel", name: "住宿费", category: "travel" },
{ code: "travel_bus", name: "大巴车票", category: "travel" },
{ code: "travel_meal", name: "伙食补助费", category: "travel" },
{ code: "travel_airfare", name: "机票", category: "travel", description: "出差乘坐飞机发生的费用;请上传正式票据并填写对应行程。" },
{ code: "travel_train", name: "火车票", category: "travel", description: "出差乘坐火车发生的费用;请上传正式票据并填写对应行程。" },
{ code: "travel_taxi", name: "打车费", category: "travel", description: "出差期间必要的出租车或网约车费用;请上传正式票据并说明行程。" },
{ code: "travel_hotel", name: "住宿费", category: "travel", description: "出差住宿费用;请上传正式票据并填写住宿日期。" },
{ code: "travel_bus", name: "大巴车票", category: "travel", description: "出差乘坐城际大巴或客车发生的费用;请上传正式票据并填写对应行程。" },
{ code: "travel_meal", name: "伙食补助费", category: "travel", description: "按符合条件的出差天数计算,无需发票;说明中填写日期范围、天数、标准和算式。", requiresInvoice: false },
{
code: "travel_local_transport_allowance",
name: "市内交通补助费",
category: "travel",
description: "按符合条件的出差天数计算,无需发票;说明中填写日期范围、天数、标准和算式。",
requiresInvoice: false,
},
{ code: "travel_fuel", name: "油费", category: "travel" },
{ code: "travel_toll", name: "过路费", category: "travel" },
{ code: "travel_parking", name: "停车费", category: "travel" },
{ code: "travel_visa", name: "签证费", category: "travel" },
{ code: "rd_materials", name: "研发材料", category: "rd" },
{ code: "rd_testing", name: "测试费用", category: "rd" },
{ code: "rd_prototype", name: "样机制作", category: "rd" },
{ code: "rd_software", name: "软件订阅", category: "rd" },
{ code: "rd_external_service", name: "外部技术服务", category: "rd" },
{ code: "production_raw_material", name: "生产原材料", category: "production" },
{ code: "production_processing", name: "加工费", category: "production" },
{ code: "production_quality", name: "质量检测", category: "production" },
{ code: "production_maintenance", name: "设备维护", category: "production" },
{ code: "production_energy", name: "生产能耗", category: "production" },
{ code: "office_stationery", name: "文具耗材", category: "office" },
{ code: "office_supplies", name: "办公用品", category: "office" },
{ code: "office_property_fee", name: "物业费用", category: "office" },
{ code: "office_communication", name: "通讯费用", category: "office" },
{ code: "office_postal", name: "邮寄快递", category: "office" },
{ code: "office_cleaning", name: "保洁服务", category: "office" },
{ code: "business_client_meal", name: "客户招待", category: "business" },
{ code: "business_gift", name: "商务礼品", category: "business" },
{ code: "business_event", name: "活动执行", category: "business" },
{ code: "business_marketing", name: "营销投放", category: "business" },
{ code: "business_training", name: "培训会议", category: "business" },
{ code: "assets_equipment", name: "设备采购", category: "assets" },
{ code: "assets_furniture", name: "家具采购", category: "assets" },
{ code: "assets_it_hardware", name: "IT 硬件", category: "assets" },
{ code: "utilities", name: "水电费", category: "other" },
{ code: "rent", name: "房租租赁费", category: "other" },
{ code: "other_misc", name: "其他杂项", category: "other" },
{ code: "travel_fuel", name: "油费", category: "travel", description: "经批准自驾或公务用车发生的燃油费用;请上传正式票据并说明行程。" },
{ code: "travel_toll", name: "过路费", category: "travel", description: "经批准自驾或公务用车发生的通行费用;请上传正式票据并说明行程。" },
{ code: "travel_parking", name: "停车费", category: "travel", description: "出差或公务期间发生的停车费用;请上传正式票据并说明事由。" },
{ code: "travel_visa", name: "签证费", category: "travel", description: "经批准的出境公务签证费用;请上传正式票据并说明对应事项。" },
{ code: "rd_materials", name: "研发材料", category: "rd", description: "研发活动直接使用的材料费用;请上传正式票据并说明项目和用途。" },
{ code: "rd_testing", name: "测试费用", category: "rd", description: "研发测试、检验或认证费用;请上传正式票据并说明项目和测试内容。" },
{ code: "rd_prototype", name: "样机制作", category: "rd", description: "研发样机、试制件制作费用;请上传正式票据并说明项目和用途。" },
{ code: "rd_software", name: "软件订阅", category: "rd", description: "研发使用的软件许可或订阅费用;请上传正式票据并说明使用期限和用途。" },
{ code: "rd_external_service", name: "外部技术服务", category: "rd", description: "研发相关的外部技术服务费用;请上传正式票据并说明项目、服务内容和验收依据。" },
{ code: "production_raw_material", name: "生产原材料", category: "production", description: "生产直接使用的原材料费用;请上传正式票据并说明用途。" },
{ code: "production_processing", name: "加工费", category: "production", description: "委外加工或生产工序费用;请上传正式票据并说明加工内容。" },
{ code: "production_quality", name: "质量检测", category: "production", description: "生产质量检测、检验或认证费用;请上传正式票据并说明检测对象。" },
{ code: "production_maintenance", name: "设备维护", category: "production", description: "生产设备维修、保养或维护费用;请上传正式票据并说明设备和事项。" },
{ code: "production_energy", name: "生产能耗", category: "production", description: "可归属生产活动的能源费用;请上传正式票据并说明期间和用途。" },
{ code: "office_stationery", name: "文具耗材", category: "office", description: "日常办公文具和消耗品;请上传正式票据并说明用途。" },
{
code: "office_supplies",
name: "办公用品",
category: "office",
description: "单条明细金额低于 2,000 元的办公用品或低值配件;多件同类物品请分开记载。2,000 元及以上通常选择办公电子设备。",
},
{ code: "office_property_fee", name: "物业费用", category: "office", description: "办公场所物业管理等费用;请上传正式票据并说明费用期间。" },
{ code: "office_communication", name: "通讯费用", category: "office", description: "经批准的办公通讯费用;请上传正式票据并说明使用人和期间。" },
{ code: "office_postal", name: "邮寄快递", category: "office", description: "公务文件或物品的邮寄快递费用;请上传正式票据并说明寄送事项。" },
{ code: "office_cleaning", name: "保洁服务", category: "office", description: "办公场所保洁服务费用;请上传正式票据并说明服务期间。" },
{ code: "business_client_meal", name: "业务招待费", category: "business", description: "因业务接洽发生的招待费用;请上传正式票据并说明事由和参与对象。" },
{ code: "business_gift", name: "商务礼品", category: "business", description: "经事前批准的商务礼品费用;请上传正式票据并说明用途和对象。" },
{ code: "business_event", name: "活动执行", category: "business", description: "经批准的业务活动执行费用;请上传正式票据并说明活动和用途。" },
{ code: "business_marketing", name: "营销投放", category: "business", description: "经批准的营销推广或广告投放费用;请上传正式票据并说明渠道和期间。" },
{ code: "business_meeting", name: "会议费", category: "business", description: "经批准举办或参加会议发生的费用;请上传正式票据并说明会议事项。" },
{ code: "business_training_fee", name: "培训费", category: "business", description: "经批准参加或组织培训发生的费用;请上传正式票据并说明培训事项。" },
{ code: "assets_equipment", name: "设备采购", category: "assets", description: "经事前批准由个人垫付的通用设备采购;请填写批准人、批准时间和可核验依据。" },
{ code: "assets_furniture", name: "家具采购", category: "assets", description: "经事前批准由个人垫付的办公家具采购;请填写批准人、批准时间和可核验依据。" },
{
code: "assets_office_electronics",
name: "办公电子设备",
category: "assets",
description: "单条明细金额达到 2,000 元的办公电子设备通常选择本类型,并填写事前批准依据。该门槛不等同于会计固定资产确认标准。",
},
{ code: "utilities", name: "水电费", category: "other", description: "办公或生产经营相关的水电费用;请上传正式票据并说明费用期间。" },
{ code: "rent", name: "房租租赁费", category: "other", description: "经批准的场地、设备或其他租赁费用;请上传正式票据并说明租赁事项和期间。" },
{ code: "other_misc", name: "其他杂项", category: "other", description: "仅用于无法归入现有类型的必要支出;请上传正式票据并完整说明事由。" },
];
const DISABLED_LEGACY_EXPENSE_TYPES = [
{ code: "transport", name: "legacy-交通费", category: "travel" },
{ code: "meal", name: "legacy-餐费", category: "business" },
{ code: "rd", name: "legacy-研发费", category: "rd" },
{ code: "business_training", name: "培训会议", category: "business" },
{ code: "assets_it_hardware", name: "IT 硬件", category: "assets" },
];
const DEFAULT_APPROVAL_RULES = [
@@ -281,6 +296,13 @@ const DEFAULT_FEATURE_FLAGS = [
department_ids: [],
note: "bootstrap default: force_off",
},
{
flag_key: "reimbursement_invoice_guard_v1",
override_mode: "force_off",
rollout_type: "global",
department_ids: [],
note: "bootstrap default: force_off",
},
{
flag_key: "payment_batch_v1",
override_mode: "force_on",
@@ -540,10 +562,10 @@ async function seedExpenseTypes(prisma) {
where: { code: item.code },
update: {
name: item.name,
description: null,
description: item.description ?? null,
category: item.category,
sort_order: index + 1,
account_code_default: null,
requires_invoice: item.requiresInvoice ?? true,
is_system_default: true,
enabled: item.enabled,
updated_at: now,
@@ -552,10 +574,11 @@ async function seedExpenseTypes(prisma) {
create: {
code: item.code,
name: item.name,
description: null,
description: item.description ?? null,
category: item.category,
sort_order: index + 1,
account_code_default: null,
requires_invoice: item.requiresInvoice ?? true,
is_system_default: true,
enabled: item.enabled,
created_at: now,