import { beforeEach, describe, expect, it, vi } from "vitest"; import { GET } from "@/app/api/admin/markup-configs/route"; import { PUT } from "@/app/api/admin/markup-configs/[customer_id]/route"; import { resetServiceTokenCache } from "@/modules/auth/service-token"; vi.mock("@/lib/prisma", () => ({ prisma: { markupConfig: { findMany: vi.fn(), findFirst: vi.fn(), create: vi.fn(), update: vi.fn(), }, hostCustomer: { findMany: vi.fn().mockResolvedValue([]), findFirst: vi.fn().mockResolvedValue(null), }, businessCustomer: { findMany: vi.fn().mockResolvedValue([]), findFirst: vi.fn().mockResolvedValue(null), count: vi.fn().mockResolvedValue(1), }, businessCustomerUser: { findMany: vi.fn().mockResolvedValue([]), }, auditLog: { create: vi.fn(), }, }, })); import { prisma } from "@/lib/prisma"; const ADMIN_HEADERS = { authorization: "Bearer admin-jwt", "x-auth-type": "admin", "x-user-id": "admin_demo", "x-user-role": "admin", }; describe("admin markup-configs API", () => { beforeEach(() => { vi.clearAllMocks(); resetServiceTokenCache(); process.env.HOST_SERVICE_TOKENS = JSON.stringify({ "demo-host-token": { customerId: "CUST_001", permissions: ["pricing:markup:write"], }, }); process.env.CUSTOMER_REGISTRY = "CUST_002,CUST_003"; }); it("GET 仅返回业务客户加价配置", async () => { process.env.HOST_SERVICE_TOKENS = JSON.stringify({ "demo-host-token": { customerId: "CUST_001", permissions: ["pricing:markup:write"], }, }); process.env.CUSTOMER_REGISTRY = ""; vi.mocked(prisma.businessCustomer.findMany).mockResolvedValue([ { customerId: "CUST_001", businessCustomerId: "BC_001", name: "客户A", externalCode: null, status: "active", remark: null, createdAt: new Date("2026-07-28T10:00:00Z"), updatedAt: new Date("2026-07-28T10:00:00Z"), _count: { users: 0 }, }, ] as never); vi.mocked(prisma.markupConfig.findMany).mockResolvedValue([ { customerId: "CUST_001", businessCustomerId: "BC_001", markupType: "percent", markupPercent: 10, markupFixedAmount: null, operatorId: "admin_demo", remark: null, updatedAt: new Date("2026-06-15T10:00:00Z"), }, ] as never); const res = await GET( new Request("http://localhost/api/admin/markup-configs?page=1&size=10", { headers: ADMIN_HEADERS, }), ); const body = await res.json(); expect(res.status).toBe(200); expect(body.code).toBe(0); expect(body.data.total).toBe(1); expect(body.data.list[0].customer_id).toBe("CUST_001"); expect(body.data.list[0].business_customer_id).toBe("BC_001"); expect(body.data.list[0].business_customer_name).toBe("客户A"); expect(body.data.list[0].markup_percent).toBe(10); }); it("GET keyword=客户代码 能命中(不因租户 ID 过滤丢结果)", async () => { process.env.HOST_SERVICE_TOKENS = JSON.stringify({ "demo-host-token": { customerId: "CUST_004", permissions: ["pricing:markup:write"], }, }); process.env.CUSTOMER_REGISTRY = ""; vi.mocked(prisma.businessCustomer.findMany).mockResolvedValue([ { customerId: "CUST_004", businessCustomerId: "29bb985b-54ae-4d89-a760-052ca9c09f1d", name: "STAR", externalCode: "SP012", status: "active", remark: null, createdAt: new Date("2026-07-28T10:00:00Z"), updatedAt: new Date("2026-07-28T10:00:00Z"), _count: { users: 1 }, }, ] as never); vi.mocked(prisma.markupConfig.findMany).mockResolvedValue([ { customerId: "CUST_004", businessCustomerId: "29bb985b-54ae-4d89-a760-052ca9c09f1d", markupType: "fixed", markupPercent: 0, markupFixedAmount: 3, operatorId: "admin_demo", remark: null, updatedAt: new Date("2026-07-30T10:00:00Z"), }, ] as never); const res = await GET( new Request( "http://localhost/api/admin/markup-configs?page=1&size=10&keyword=SP012", { headers: ADMIN_HEADERS }, ), ); const body = await res.json(); expect(res.status).toBe(200); expect(body.code).toBe(0); expect(body.data.total).toBe(1); expect(body.data.list[0].business_customer_code).toBe("SP012"); expect(body.data.list[0].markup_type).toBe("fixed"); expect(body.data.list[0].markup_fixed_amount).toBe(3); }); it("GET keyword=SPO(字母O)也能命中 SP012", async () => { process.env.HOST_SERVICE_TOKENS = JSON.stringify({ "demo-host-token": { customerId: "CUST_004", permissions: ["pricing:markup:write"], }, }); process.env.CUSTOMER_REGISTRY = ""; vi.mocked(prisma.businessCustomer.findMany).mockResolvedValue([ { customerId: "CUST_004", businessCustomerId: "29bb985b-54ae-4d89-a760-052ca9c09f1d", name: "STAR", externalCode: "SP012", status: "active", remark: null, createdAt: new Date("2026-07-28T10:00:00Z"), updatedAt: new Date("2026-07-28T10:00:00Z"), _count: { users: 1 }, }, ] as never); vi.mocked(prisma.markupConfig.findMany).mockResolvedValue([] as never); vi.mocked(prisma.businessCustomerUser.findMany).mockResolvedValue([] as never); const res = await GET( new Request( "http://localhost/api/admin/markup-configs?page=1&size=10&keyword=SPO", { headers: ADMIN_HEADERS }, ), ); const body = await res.json(); expect(body.code).toBe(0); expect(body.data.total).toBe(1); expect(body.data.list[0].business_customer_code).toBe("SP012"); }); it("PUT 拒绝租户级加价", async () => { const res = await PUT( new Request("http://localhost/api/admin/markup-configs/CUST_001", { method: "PUT", headers: { ...ADMIN_HEADERS, "Content-Type": "application/json" }, body: JSON.stringify({ markup_type: "fixed", markup_fixed_amount: 25, remark: "测试", }), }), { params: Promise.resolve({ customer_id: "CUST_001" }) }, ); const body = await res.json(); expect(res.status).toBe(400); expect(body.message).toBe("仅支持业务客户加价,租户不加价"); }); it("PUT 支持业务客户覆盖加价", async () => { vi.mocked(prisma.markupConfig.findFirst).mockResolvedValue(null as never); vi.mocked(prisma.markupConfig.create).mockResolvedValue({ customerId: "CUST_001", businessCustomerId: "BC_001", markupType: "percent", markupPercent: 12, markupFixedAmount: null, operatorId: "admin_demo", remark: "业务客户覆盖", updatedAt: new Date("2026-07-28T10:00:00Z"), } as never); vi.mocked(prisma.businessCustomer.findFirst).mockResolvedValue({ customerId: "CUST_001", businessCustomerId: "BC_001", name: "客户A", externalCode: "CODE_A", status: "active", remark: null, createdAt: new Date("2026-07-28T10:00:00Z"), updatedAt: new Date("2026-07-28T10:00:00Z"), } as never); const res = await PUT( new Request("http://localhost/api/admin/markup-configs/CUST_001", { method: "PUT", headers: { ...ADMIN_HEADERS, "Content-Type": "application/json" }, body: JSON.stringify({ business_customer_id: "BC_001", markup_percent: 12, remark: "业务客户覆盖", }), }), { params: Promise.resolve({ customer_id: "CUST_001" }) }, ); const body = await res.json(); expect(res.status).toBe(200); expect(body.data.business_customer_id).toBe("BC_001"); expect(body.data.business_customer_code).toBe("CODE_A"); expect(body.data.business_customer_name).toBe("客户A"); expect(body.data.markup_percent).toBe(12); }); it("PUT 未知客户 400", async () => { const res = await PUT( new Request("http://localhost/api/admin/markup-configs/CUST_999", { method: "PUT", headers: { ...ADMIN_HEADERS, "Content-Type": "application/json" }, body: JSON.stringify({ markup_percent: 5 }), }), { params: Promise.resolve({ customer_id: "CUST_999" }) }, ); const body = await res.json(); expect(res.status).toBe(400); expect(body.message).toBe("客户不存在"); }); });