219 lines
7.8 KiB
TypeScript
219 lines
7.8 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
|
|
import { mockApi, seedAuthenticatedState } from "./support/network.js";
|
|
import { isDesktopProject } from "./support/projects";
|
|
|
|
const json = (body: unknown, status = 200) => ({
|
|
status,
|
|
contentType: "application/json",
|
|
body: JSON.stringify(body),
|
|
});
|
|
|
|
const now = "2026-07-06 10:00:00";
|
|
|
|
const buildProduct = (product: Record<string, unknown>) => ({
|
|
description: "E2E product",
|
|
subscription_allowed: true,
|
|
category: 1,
|
|
piktogram: "truck",
|
|
economic_product_id: 0,
|
|
apply_category_discount: false,
|
|
requires_note: false,
|
|
created_at: now,
|
|
updated_at: now,
|
|
addons: [],
|
|
is_wash: true,
|
|
display_in_booking_form: true,
|
|
order_priority: 1,
|
|
...product,
|
|
});
|
|
|
|
test.describe("Superuser department custom-only pricing", () => {
|
|
test("toggles no-fallback pricing and shows 999999 for missing department prices", async ({ page }, testInfo) => {
|
|
test.skip(!isDesktopProject(testInfo), "Desktop only");
|
|
|
|
const customPricingOnlyByDepartment: Record<number, "0" | "1"> = {
|
|
42: "0",
|
|
43: "0",
|
|
};
|
|
let receivedToggleBody: Record<string, unknown> | null = null;
|
|
let receivedCustomerPricingBody: Record<string, unknown> | null = null;
|
|
|
|
const products = [
|
|
buildProduct({ id: 10, name: "Fallback Wash", price: 12345 }),
|
|
buildProduct({ id: 11, name: "Explicit Wash", price: 98765, order_priority: 2 }),
|
|
];
|
|
const customerPricingPayload = (overrides: Array<Record<string, unknown>> = []) => ({
|
|
department: {
|
|
id: 42,
|
|
name: "Custom Pricing Department",
|
|
description: "E2E department",
|
|
custom_pricing_only: customPricingOnlyByDepartment[42],
|
|
},
|
|
customer: {
|
|
id: 601,
|
|
customer_number: 6001,
|
|
display_name: "Acme Haulage",
|
|
},
|
|
overrides,
|
|
categories: [
|
|
{
|
|
id: 1,
|
|
name: "Wash",
|
|
description: "",
|
|
products: [
|
|
{
|
|
id: 11,
|
|
name: "Explicit Wash",
|
|
description: "E2E product",
|
|
category: 1,
|
|
apply_category_discount: true,
|
|
base_price: 98765,
|
|
department_price: 2222,
|
|
effective_price: overrides.length ? 1667 : 2222,
|
|
missing_department_price: false,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
});
|
|
|
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
await seedAuthenticatedState(page, "superuser-department-pricing-token");
|
|
await mockApi(page, {
|
|
authenticated: true,
|
|
permissions: [
|
|
"superuser",
|
|
"user",
|
|
"list_products",
|
|
"list_departments",
|
|
"edit_department",
|
|
"superuser_fetch_department",
|
|
"superuser_fetch_department_prices",
|
|
"superuser_set_department_prices",
|
|
"superuser_fetch_department_customer_pricing",
|
|
"superuser_set_department_customer_pricing",
|
|
],
|
|
sessionData: {
|
|
group_id: 1,
|
|
},
|
|
});
|
|
|
|
await page.route("**/api/products**", async (route) => {
|
|
await route.fulfill(json({ data: products }));
|
|
});
|
|
|
|
await page.route("**/api/superuser/department/prices**", async (route) => {
|
|
const departmentId = Number(new URL(route.request().url()).searchParams.get("department_id"));
|
|
await route.fulfill(
|
|
json({
|
|
data: departmentId === 42 ? [{ id: 100, department_id: 42, product_id: 11, price: 2222 }] : [],
|
|
})
|
|
);
|
|
});
|
|
|
|
await page.route(/\/api\/superuser\/department(?:\?.*)?$/i, async (route) => {
|
|
const departmentId = Number(new URL(route.request().url()).searchParams.get("department_id"));
|
|
await route.fulfill(
|
|
json({
|
|
data: {
|
|
id: departmentId,
|
|
name: departmentId === 43 ? "Fallback Pricing Department" : "Custom Pricing Department",
|
|
description: "E2E department",
|
|
custom_pricing_only: customPricingOnlyByDepartment[departmentId] ?? "0",
|
|
created_at: now,
|
|
updated_at: now,
|
|
},
|
|
})
|
|
);
|
|
});
|
|
|
|
await page.route("**/api/departments", async (route) => {
|
|
const request = route.request();
|
|
if (request.method() !== "PUT") {
|
|
await route.fallback();
|
|
return;
|
|
}
|
|
|
|
receivedToggleBody = request.postDataJSON() as Record<string, unknown>;
|
|
customPricingOnlyByDepartment[Number(receivedToggleBody.id)] = receivedToggleBody.custom_pricing_only ? "1" : "0";
|
|
await route.fulfill(json({ data: { message: "Department updated successfully" } }));
|
|
});
|
|
|
|
await page.route("**/api/superuser/department/customer-pricing**", async (route) => {
|
|
const request = route.request();
|
|
if (request.method() === "PUT") {
|
|
receivedCustomerPricingBody = request.postDataJSON() as Record<string, unknown>;
|
|
await route.fulfill(
|
|
json({
|
|
data: customerPricingPayload([
|
|
{
|
|
is_category: false,
|
|
product_or_category_id: 11,
|
|
percentage: 25,
|
|
fixed_price: null,
|
|
},
|
|
]),
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
await route.fulfill(json({ data: customerPricingPayload() }));
|
|
});
|
|
|
|
await page.goto("/superuser/departments/42/prices", { waitUntil: "domcontentloaded" });
|
|
|
|
await expect(page.getByRole("heading", { name: "Custom Pricing Department" })).toBeVisible();
|
|
await expect(page.getByTestId("department-custom-pricing-settings")).toBeVisible();
|
|
await expect(page.getByTestId("department-custom-pricing-only-toggle")).not.toBeChecked();
|
|
await expect(page.getByTestId("department-customer-pricing-link")).toHaveCount(0);
|
|
await expect(page.getByTestId("department-price-cell-10")).toContainText("-");
|
|
await expect(page.getByTestId("department-price-cell-11")).toContainText("2.222");
|
|
|
|
await page.locator('label[for="department-custom-pricing-only"]').click();
|
|
|
|
await expect(page.getByTestId("department-custom-pricing-only-toggle")).toBeChecked();
|
|
await expect(page.getByTestId("department-price-cell-10")).toContainText("999.999");
|
|
await expect(page.getByTestId("department-price-cell-11")).toContainText("2.222");
|
|
await expect(page.getByTestId("department-customer-pricing-link")).toBeVisible();
|
|
expect(receivedToggleBody).toMatchObject({
|
|
id: "42",
|
|
custom_pricing_only: true,
|
|
});
|
|
|
|
await page.getByTestId("department-customer-pricing-link").click();
|
|
await expect(page).toHaveURL(/\/superuser\/departments\/42\/customer-pricing$/);
|
|
await page.getByTestId("department-customer-pricing-customer-number").fill("6001");
|
|
await page.getByTestId("department-customer-pricing-load").click();
|
|
|
|
await expect(page.getByTestId("department-customer-pricing-customer")).toContainText("Acme Haulage");
|
|
await expect(page.getByTestId("department-customer-pricing-product-11")).toContainText("Explicit Wash");
|
|
|
|
await page.getByTestId("department-customer-pricing-item-discount-11").click();
|
|
await page.locator(".swal2-input").fill("25");
|
|
await page.locator(".swal2-confirm").click();
|
|
|
|
await expect(page.getByTestId("department-customer-pricing-item-discount-11")).toContainText("25%");
|
|
expect(receivedCustomerPricingBody).toMatchObject({
|
|
department_id: 42,
|
|
customer_number: 6001,
|
|
overrides: [
|
|
{
|
|
is_category: false,
|
|
product_or_category_id: 11,
|
|
percentage: 25,
|
|
fixed_price: null,
|
|
},
|
|
],
|
|
});
|
|
|
|
await page.goto("/superuser/departments/43/prices", { waitUntil: "domcontentloaded" });
|
|
|
|
await expect(page.getByRole("heading", { name: "Fallback Pricing Department" })).toBeVisible();
|
|
await expect(page.getByTestId("department-custom-pricing-only-toggle")).not.toBeChecked();
|
|
await expect(page.getByTestId("department-customer-pricing-link")).toHaveCount(0);
|
|
await expect(page.getByTestId("department-price-cell-10")).toContainText("-");
|
|
});
|
|
});
|