const { personalNotificationText, loadPendingPaymentResponsibility } = require("../../../src/services/paymentResponsibility"); describe("payment responsibility and personal notification facts", () => { it.each([ ["wecom_app_sent", "success", "企微个人消息已发送(不代表已读)"], ["wecom_app_no_bound_recipients", "success", "企微个人消息未发送:接收人未绑定企微"], ["wecom_sent", "success", "仅有企微群通知记录,未确认个人消息送达"], ["mock_sent", "success", "仅有模拟通知记录,未发送企微个人消息"], ["wecom_app_invaliduser", "failed", "企微通知发送失败,请核对通知记录"], ])("projects %s without converting generic success into personal delivery", (result_code, status, message) => { expect(personalNotificationText([{ deliveries: [{ result_code, status }] }])).toBe(message); }); it("does not attribute one anchor delivery to every intended recipient", () => { expect(personalNotificationText([ { recipient_employee_id: "first", deliveries: [{ status: "success", result_code: "wecom_app_sent" }] }, { recipient_employee_id: "second", deliveries: [] }, ])).toBe("存在企微个人消息发送成功记录,接收范围需核对(不代表已读)"); }); it("does not infer delivery from a notification record alone", () => { expect(personalNotificationText([{ deliveries: [] }])).toBe("暂无企微个人消息发送成功记录"); }); it("separates eligible people from the selected notification recipient and omits disabled/self/admin", async () => { const person = (id, role, extra = {}) => ({ id, name: id, status: "active", archived_at: null, roles: [{ role_code: role }], ...extra }); const tx = { employee: { findMany: vi.fn(async () => [ person("maker", "ceo"), person("ceo", "ceo"), person("manager", "manager"), person("disabled", "manager", { status: "inactive" }), person("archived", "manager", { archived_at: new Date() }), person("admin", "admin"), ]) }, notification: { findMany: vi.fn(async () => [{ recipient: { name: "ceo" }, deliveries: [] }]) } }; const projection = await loadPendingPaymentResponsibility(tx, { id: "batch", status: "draft", created_by: "maker" }); expect(projection.actorName).toBe("可复核:ceo、manager"); expect(projection.detail).toBe("站内提醒对象:ceo;暂无企微个人消息发送成功记录"); expect(tx.notification.findMany.mock.calls[0][0].select).not.toHaveProperty("response_body"); }); it("does not replace actual completed reviewers with current role holders", async () => { const tx = { employee: { findMany: vi.fn() } }; expect(await loadPendingPaymentResponsibility(tx, { status: "executed" })).toBeNull(); expect(tx.employee.findMany).not.toHaveBeenCalled(); }); });