import { beforeEach, describe, expect, it, vi } from "vitest"; import { PROJECT_BRIEF_SELECT } from "../db/selects.js"; import { createAuditEntry } from "../lib/audit.js"; import { createCalculationRule, deleteCalculationRule, getCalculationRuleById, listActiveCalculationRules, listCalculationRules, updateCalculationRule, } from "../router/calculation-rule-procedure-support.js"; vi.mock("../lib/audit.js", () => ({ createAuditEntry: vi.fn(), })); function createContext(db: Record) { return { db: db as never, dbUser: { id: "user_mgr" }, }; } describe("calculation-rule-procedure-support", () => { beforeEach(() => { vi.clearAllMocks(); }); it("lists calculation rules with the expected project include", async () => { const findMany = vi.fn().mockResolvedValue([{ id: "calc_1" }]); const ctx = createContext({ calculationRule: { findMany }, }); const result = await listCalculationRules(ctx); expect(result).toEqual([{ id: "calc_1" }]); expect(findMany).toHaveBeenCalledWith({ orderBy: [{ priority: "desc" }, { name: "asc" }], include: { project: { select: PROJECT_BRIEF_SELECT } }, }); }); it("gets a rule by id with the expected project include", async () => { const findUnique = vi.fn().mockResolvedValue({ id: "calc_1", name: "Rush Fee" }); const ctx = createContext({ calculationRule: { findUnique }, }); const result = await getCalculationRuleById(ctx, { id: "calc_1" }); expect(result).toEqual({ id: "calc_1", name: "Rush Fee" }); expect(findUnique).toHaveBeenCalledWith({ where: { id: "calc_1" }, include: { project: { select: PROJECT_BRIEF_SELECT } }, }); }); it("lists only active rules for engine use", async () => { const findMany = vi.fn().mockResolvedValue([{ id: "calc_2", isActive: true }]); const ctx = createContext({ calculationRule: { findMany }, }); const result = await listActiveCalculationRules(ctx); expect(result).toEqual([{ id: "calc_2", isActive: true }]); expect(findMany).toHaveBeenCalledWith({ where: { isActive: true }, orderBy: [{ priority: "desc" }], }); }); it("creates a rule and records an audit entry", async () => { const created = { id: "calc_3", name: "Vacation Discount", triggerType: "VACATION", costEffect: "REDUCE", chargeabilityEffect: "COUNT", priority: 10, isActive: true, }; const create = vi.fn().mockResolvedValue(created); const ctx = createContext({ calculationRule: { create }, }); const result = await createCalculationRule(ctx, { name: "Vacation Discount", triggerType: "VACATION", costEffect: "REDUCE", chargeabilityEffect: "COUNT", priority: 10, isActive: true, }); expect(result).toBe(created); expect(create).toHaveBeenCalledWith({ data: { name: "Vacation Discount", triggerType: "VACATION", costEffect: "REDUCE", chargeabilityEffect: "COUNT", priority: 10, isActive: true, }, }); expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({ db: ctx.db, entityType: "CalculationRule", entityId: "calc_3", entityName: "Vacation Discount", action: "CREATE", userId: "user_mgr", after: created, source: "ui", })); }); it("updates a rule and records before/after audit snapshots", async () => { const before = { id: "calc_4", name: "Rush Fee", priority: 90, isActive: true, }; const after = { id: "calc_4", name: "Rush Fee", priority: 95, isActive: false, }; const findUnique = vi.fn().mockResolvedValue(before); const update = vi.fn().mockResolvedValue(after); const ctx = createContext({ calculationRule: { findUnique, update }, }); const result = await updateCalculationRule(ctx, { id: "calc_4", priority: 95, isActive: false, }); expect(result).toBe(after); expect(findUnique).toHaveBeenCalledWith({ where: { id: "calc_4" } }); expect(update).toHaveBeenCalledWith({ where: { id: "calc_4" }, data: { priority: 95, isActive: false, }, }); expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({ db: ctx.db, entityType: "CalculationRule", entityId: "calc_4", entityName: "Rush Fee", action: "UPDATE", userId: "user_mgr", before, after, source: "ui", })); }); it("deletes a rule and records a delete audit entry", async () => { const rule = { id: "calc_5", name: "Legacy Rule" }; const findUnique = vi.fn().mockResolvedValue(rule); const deleteFn = vi.fn().mockResolvedValue(rule); const ctx = createContext({ calculationRule: { findUnique, delete: deleteFn }, }); const result = await deleteCalculationRule(ctx, { id: "calc_5" }); expect(result).toEqual({ success: true }); expect(findUnique).toHaveBeenCalledWith({ where: { id: "calc_5" } }); expect(deleteFn).toHaveBeenCalledWith({ where: { id: "calc_5" } }); expect(createAuditEntry).toHaveBeenCalledWith(expect.objectContaining({ db: ctx.db, entityType: "CalculationRule", entityId: "calc_5", entityName: "Legacy Rule", action: "DELETE", userId: "user_mgr", before: rule, source: "ui", })); }); });