|
|
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("客户不存在");
|
|
|
});
|
|
|
});
|