R35-2 审批通知补结构化摘要
这个提交包含在:
@@ -21,6 +21,15 @@ describe('purchase submit side effects helper', () => {
|
||||
assigneeId: 'manager-1',
|
||||
assigneeRole: null,
|
||||
actorId: 'employee-1',
|
||||
loadSummary: vi.fn().mockResolvedValue({
|
||||
id: 'purchase-1',
|
||||
request_no: 'CG-20260324-001',
|
||||
total_amount: '5600.00',
|
||||
applicant: {
|
||||
id: 'employee-1',
|
||||
name: '李经理',
|
||||
},
|
||||
}),
|
||||
resolveRecipients: vi.fn().mockResolvedValue(['manager-1']),
|
||||
createAppNotifications: vi.fn().mockResolvedValue({ count: 1 }),
|
||||
enqueueIm: vi.fn().mockResolvedValue({
|
||||
@@ -99,4 +108,45 @@ describe('purchase submit side effects helper', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('builds structured purchase copy for app notification, IM and email', async () => {
|
||||
const createAppNotifications = vi.fn().mockResolvedValue({ count: 1 });
|
||||
const enqueueIm = vi.fn().mockResolvedValue({
|
||||
queued: 1,
|
||||
duplicated: 0,
|
||||
matchedChannels: [{ id: 'channel-1' }],
|
||||
});
|
||||
const sendEmailSafe = vi.fn().mockResolvedValue({
|
||||
email: { skipped: true, sent: 0, failed: 0 },
|
||||
});
|
||||
|
||||
await finalizePurchaseSubmitSideEffects(
|
||||
createParams({
|
||||
createAppNotifications,
|
||||
enqueueIm,
|
||||
sendEmailSafe,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createAppNotifications).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({
|
||||
title: '【待办】采购申请 CG-20260324-001 待审批',
|
||||
body: '申请人:李经理\n金额:5600.00\n单号:CG-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
expect(enqueueIm).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({
|
||||
title: '【待办】采购申请 CG-20260324-001 待审批',
|
||||
body: '申请人:李经理\n金额:5600.00\n单号:CG-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
expect(sendEmailSafe).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
subject: '【待办】采购申请 CG-20260324-001 待审批',
|
||||
body: '申请人:李经理\n金额:5600.00\n单号:CG-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,15 @@ describe('reimbursement submit side effects helper', () => {
|
||||
assigneeId: 'manager-1',
|
||||
assigneeRole: null,
|
||||
actorId: 'employee-1',
|
||||
loadSummary: vi.fn().mockResolvedValue({
|
||||
id: 'reimbursement-1',
|
||||
form_number: 'BX-20260324-001',
|
||||
total_amount: '1288.00',
|
||||
owner: {
|
||||
id: 'employee-1',
|
||||
name: '王小明',
|
||||
},
|
||||
}),
|
||||
resolveRecipients: vi.fn().mockResolvedValue(['manager-1']),
|
||||
createAppNotifications: vi.fn().mockResolvedValue({ count: 1 }),
|
||||
enqueueIm: vi.fn().mockResolvedValue({
|
||||
@@ -99,4 +108,45 @@ describe('reimbursement submit side effects helper', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('builds structured reimbursement copy for app notification, IM and email', async () => {
|
||||
const createAppNotifications = vi.fn().mockResolvedValue({ count: 1 });
|
||||
const enqueueIm = vi.fn().mockResolvedValue({
|
||||
queued: 1,
|
||||
duplicated: 0,
|
||||
matchedChannels: [{ id: 'channel-1' }],
|
||||
});
|
||||
const sendEmailSafe = vi.fn().mockResolvedValue({
|
||||
email: { skipped: true, sent: 0, failed: 0 },
|
||||
});
|
||||
|
||||
await finalizeReimbursementSubmitSideEffects(
|
||||
createParams({
|
||||
createAppNotifications,
|
||||
enqueueIm,
|
||||
sendEmailSafe,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(createAppNotifications).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({
|
||||
title: '【待办】报销单 BX-20260324-001 待审批',
|
||||
body: '申请人:王小明\n金额:1288.00\n单号:BX-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
expect(enqueueIm).toHaveBeenCalledWith(
|
||||
{},
|
||||
expect.objectContaining({
|
||||
title: '【待办】报销单 BX-20260324-001 待审批',
|
||||
body: '申请人:王小明\n金额:1288.00\n单号:BX-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
expect(sendEmailSafe).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
subject: '【待办】报销单 BX-20260324-001 待审批',
|
||||
body: '申请人:王小明\n金额:1288.00\n单号:BX-20260324-001\n动作:请及时处理审批任务。',
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,12 +2,25 @@ const { NOTIFICATION_TYPES } = require("../../../src/constants/notificationTypes
|
||||
const workflowRoutes = require("../../../src/routes/workflow");
|
||||
|
||||
describe("workflow travel helpers", () => {
|
||||
const { getWorkflowEntityMeta, resolveWorkflowOutcomeNotificationType } = workflowRoutes.__testables;
|
||||
const {
|
||||
buildApprovedCopy,
|
||||
buildPendingTaskCopy,
|
||||
buildRejectedCopy,
|
||||
buildReturnedCopy,
|
||||
buildWorkflowEntityMeta,
|
||||
resolveWorkflowOutcomeNotificationType,
|
||||
} = workflowRoutes.__testables;
|
||||
|
||||
it("builds travel entity meta with deep-link detail path", () => {
|
||||
const meta = getWorkflowEntityMeta(
|
||||
const meta = buildWorkflowEntityMeta(
|
||||
"travel_request",
|
||||
{ request_no: "CL-20260310-0001" },
|
||||
{
|
||||
request_no: "CL-20260310-0001",
|
||||
estimated_amount: "4200.00",
|
||||
applicant: {
|
||||
name: "张差旅",
|
||||
},
|
||||
},
|
||||
"11111111-1111-4111-8111-111111111111",
|
||||
);
|
||||
|
||||
@@ -19,6 +32,56 @@ describe("workflow travel helpers", () => {
|
||||
detailPath: "/travel-requests?id=11111111-1111-4111-8111-111111111111",
|
||||
}),
|
||||
);
|
||||
|
||||
const pendingCopy = buildPendingTaskCopy(meta);
|
||||
expect(pendingCopy).toEqual({
|
||||
title: "【待办】差旅申请 CL-20260310-0001 待审批",
|
||||
body: "申请人:张差旅\n预估金额:4200.00\n单号:CL-20260310-0001\n动作:请及时处理审批任务。",
|
||||
});
|
||||
});
|
||||
|
||||
it("builds structured workflow outcome copies for leave and reimbursement", () => {
|
||||
const leaveMeta = buildWorkflowEntityMeta(
|
||||
"leave",
|
||||
{
|
||||
start_date: new Date("2026-03-25T00:00:00.000Z"),
|
||||
end_date: new Date("2026-03-26T00:00:00.000Z"),
|
||||
requested_days: "1.5",
|
||||
leave_type: {
|
||||
name: "年假",
|
||||
},
|
||||
owner: {
|
||||
name: "王请假",
|
||||
},
|
||||
},
|
||||
"leave-1",
|
||||
);
|
||||
|
||||
expect(buildRejectedCopy(leaveMeta, "请补充交接安排")).toEqual({
|
||||
title: "【已驳回】请假单 2026-03-25 ~ 2026-03-26",
|
||||
body: "申请人:王请假\n假种:年假\n天数:1.5 天\n起止日期:2026-03-25 ~ 2026-03-26\n结果:已驳回:请补充交接安排",
|
||||
});
|
||||
|
||||
const reimbursementMeta = buildWorkflowEntityMeta(
|
||||
"reimbursement",
|
||||
{
|
||||
form_number: "BX-20260325-001",
|
||||
total_amount: "880.00",
|
||||
owner: {
|
||||
name: "刘报销",
|
||||
},
|
||||
},
|
||||
"reimbursement-1",
|
||||
);
|
||||
|
||||
expect(buildApprovedCopy(reimbursementMeta)).toEqual({
|
||||
title: "【已批准】报销单 BX-20260325-001",
|
||||
body: "申请人:刘报销\n金额:880.00\n单号:BX-20260325-001\n结果:已审批通过,等待财务付款。",
|
||||
});
|
||||
expect(buildReturnedCopy(reimbursementMeta, "请补发票")).toEqual({
|
||||
title: "【已退回】报销单 BX-20260325-001",
|
||||
body: "申请人:刘报销\n金额:880.00\n单号:BX-20260325-001\n结果:已退回:请补发票",
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves approved and rejected notification types for travel workflows", () => {
|
||||
|
||||
在新工单中引用
屏蔽一个用户