feat: 选票自动生成报销明细并支持集中分类(08-29-reimbursement-expense-policy-invoice-guard)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-09-09 23:19:02 +08:00
父节点 b87cc55aca
当前提交 e5685f18b2
共修改 28 个文件,包含 1616 行新增和 121 行删除
@@ -0,0 +1,30 @@
const { mapInvoiceDocumentMeta } = require("./invoiceDocumentMeta");
const { buildBusinessValidationError } = require("../utils/businessValidationError");
function suggestInvoiceExpenseType(invoice, expenseTypes) {
const { documentCategory } = mapInvoiceDocumentMeta(invoice);
if (documentCategory !== "electronic_train_ticket") return null;
const expenseType = expenseTypes.find((type) => type.enabled === true && type.code === "travel_train");
if (!expenseType) return null;
return { expenseTypeId: expenseType.id, source: "document_category" };
}
function ensureClassifiedReimbursementItems(items) {
const itemIds = items
.filter((item) => !item.expense_type || item.expense_type.enabled === false)
.map((item) => item.id);
if (itemIds.length) {
throw buildBusinessValidationError("reimbursement.items_expense_type_required", { itemIds }, 400);
}
}
function ensureReimbursementItemDescriptions(items) {
const itemIds = items.filter((item) => !item.description?.trim()).map((item) => item.id);
if (itemIds.length) {
throw buildBusinessValidationError("reimbursement.items_description_required", { itemIds }, 400);
}
}
module.exports = { suggestInvoiceExpenseType, ensureClassifiedReimbursementItems, ensureReimbursementItemDescriptions };