import { describe, expect, it } from "vitest"; import { Business } from "@/lib/server/models/Business"; import { BranchPricing } from "@/lib/server/models/Product"; import * as prices from "@/app/api/branch-prices/route"; import * as products from "@/app/api/products/route"; import * as cash from "@/app/api/transactions/cash/route"; import { json, makeTenant, req, uuid, type Actor, type Tenant } from "./helpers"; const setPrice = (as: Actor, branchId: string, productId: string, unitPrice: number) => prices.PUT(req("PUT", "/api/branch-prices", { as, body: { branchId, productId, unitPrice } })); const tillPrice = async (as: Actor, productId: string) => { const { body } = await json(await products.GET(req("GET", "/api/products", { as }))); return body.products.find((p: any) => p._id === productId).unitPrice; }; describe("branch prices", () => { it("charges the branch's own price at that branch only, through the till and the sale", async () => { const t = await makeTenant(); expect((await setPrice(t.owner, t.branchA, t.water20, 180)).status).toBe(200); expect(await tillPrice(t.cashierA, t.water20)).toBe(180); expect(await tillPrice(t.cashierB, t.water20)).toBe(200); const sale = await json( await cash.POST(req("POST", "/x", { as: t.cashierA, body: { sales: [{ clientUuid: uuid(), lines: [{ productId: t.water20, quantity: 2 }] }] } })) ); expect(sale.body.results[0]).toMatchObject({ status: "saved", amountTotal: 360 }); }); it("lists default and branch prices, and the catalogue view keeps showing defaults", async () => { const t = await makeTenant(); await setPrice(t.owner, t.branchA, t.water20, 180); const { body } = await json(await prices.GET(req("GET", "/api/branch-prices?branchId=" + t.branchA, { as: t.owner }))); const row = body.prices.find((p: any) => p.productId === t.water20); expect(row).toMatchObject({ defaultPrice: 200, branchPrice: 180 }); expect(body.allowed).toBe(true); const catalogue = await json(await products.GET(req("GET", "/api/products?includeInactive=1", { as: t.managerA }))); expect(catalogue.body.products.find((p: any) => p._id === t.water20).unitPrice).toBe(200); }); it("removes the override when set back to the default, or reset", async () => { const t = await makeTenant(); await setPrice(t.owner, t.branchA, t.water20, 180); await setPrice(t.owner, t.branchA, t.water20, 200); expect(await BranchPricing.countDocuments({})).toBe(0); await setPrice(t.owner, t.branchA, t.water5, 55); const reset = await prices.DELETE( req("DELETE", `/api/branch-prices?branchId=${t.branchA}&productId=${t.water5}`, { as: t.owner }) ); expect(reset.status).toBe(200); expect(await tillPrice(t.cashierA, t.water5)).toBe(60); }); it("lets a manager see only their own branch's prices, and not change them", async () => { const t = await makeTenant(); const own = await json(await prices.GET(req("GET", "/api/branch-prices?branchId=" + t.branchB, { as: t.managerA }))); expect(own.body.branchId).toBe(t.branchA); // pinned to their branch expect((await setPrice(t.managerA, t.branchA, t.water20, 150)).status).toBe(403); expect((await prices.GET(req("GET", "/api/branch-prices", { as: t.cashierA }))).status).toBe(403); }); it("follows the plan: Growth and trials may set prices, a paid Starter may only reset them", async () => { const t: Tenant = await makeTenant(); await Business.updateOne({ _id: t.businessId }, { tier: "STARTER", subscriptionStatus: "TRIALING" }); expect((await setPrice(t.owner, t.branchA, t.water20, 180)).status).toBe(200); await Business.updateOne({ _id: t.businessId }, { tier: "STARTER", subscriptionStatus: "ACTIVE" }); expect((await setPrice(t.owner, t.branchA, t.water20, 170)).status).toBe(403); // Prices set during the trial keep applying until reset. expect(await tillPrice(t.cashierA, t.water20)).toBe(180); const reset = await prices.DELETE( req("DELETE", `/api/branch-prices?branchId=${t.branchA}&productId=${t.water20}`, { as: t.owner }) ); expect(reset.status).toBe(200); expect(await tillPrice(t.cashierA, t.water20)).toBe(200); }); it("rejects zero prices and another tenant's branch or product", async () => { const t = await makeTenant("Alpha"); const other = await makeTenant("Beta"); expect((await setPrice(t.owner, t.branchA, t.water20, 0)).status).toBe(400); expect((await setPrice(t.owner, other.branchA, t.water20, 150)).status).toBe(404); expect((await setPrice(t.owner, t.branchA, other.water20, 150)).status).toBe(404); expect((await prices.GET(req("GET", "/api/branch-prices?branchId=" + other.branchA, { as: t.owner }))).status).toBe(404); expect(await BranchPricing.countDocuments({})).toBe(0); }); });