Add toasts, Settings tabs, Clients page and item presets (Phase E1)
- Global Carbon toast stack replaces scattered inline notices; errors persist until closed. - Settings is split into eight tabs with one Save and a remembered last tab; Numbering embeds the series settings. - New Clients page with a DataTable, shared add/edit modal, structured addresses, GST category (informational), per-client notes and payment terms. The composed address string is kept for back-compat. Deleting a client warns about invoice count; issued invoices keep their own snapshot. - Migration M7 adds the client columns and item_presets; existing clients with a GSTIN are backfilled to registered_regular. - New invoice form: client ComboBox with type-ahead and inline create, client defaults applied on selection, and an Add from preset control. - Rust tests for M7 (fresh and v6 upgrade), client validation and CRUD, presets CRUD; vitest for the toast store and new helpers. PDF output and fingerprint goldens are unchanged. The new UI has not been run in a webview yet.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { composeAddress, pincodeError, splitLegacyAddress } from "./clientAddress";
|
||||
|
||||
describe("composeAddress", () => {
|
||||
it("joins lines and the city/state/pincode line", () => {
|
||||
expect(
|
||||
composeAddress({ line1: "12 MG Road", line2: "Floor 2", city: "Bengaluru", stateCode: "29", pincode: "560001" }),
|
||||
).toBe("12 MG Road\nFloor 2\nBengaluru, Karnataka - 560001");
|
||||
});
|
||||
it("skips empty parts", () => {
|
||||
expect(composeAddress({ line1: " A ", line2: "", city: "", stateCode: "", pincode: "560001" })).toBe("A\n560001");
|
||||
expect(composeAddress({ line1: "", line2: "", city: "Pune", stateCode: "", pincode: "" })).toBe("Pune");
|
||||
expect(composeAddress({ line1: "", line2: "", city: "", stateCode: "29", pincode: "" })).toBe("Karnataka");
|
||||
expect(composeAddress({ line1: "", line2: "", city: "", stateCode: "", pincode: "" })).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("splitLegacyAddress", () => {
|
||||
it("puts the first line in line1 and the rest in line2", () => {
|
||||
expect(splitLegacyAddress("Old style\nfree text\r\nBangalore")).toEqual({
|
||||
line1: "Old style",
|
||||
line2: "free text, Bangalore",
|
||||
});
|
||||
expect(splitLegacyAddress("")).toEqual({ line1: "", line2: "" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("pincodeError", () => {
|
||||
it("accepts empty and 6 digits only", () => {
|
||||
expect(pincodeError("")).toBeUndefined();
|
||||
expect(pincodeError("560001")).toBeUndefined();
|
||||
expect(pincodeError("56001")).toBeDefined();
|
||||
expect(pincodeError("56000A")).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user