feat(po): user-defined T&C categories + dynamic PO terms editor (#11 follow-up) #107

Merged
shad0w merged 1 commit from feat/terms-dynamic-editor into master 2026-06-23 23:27:48 +00:00
Owner

Follow-up to the merged #11 PR (#106), which shipped the enum-based T&C catalogue. This makes categories user-defined and the PO T&C a dynamic editor, per the review asks:

  1. Add new categories along with clauses — TermsCategory is now a TABLE, not an enum. In the admin Add/Edit clause form the category is a combobox; typing a new name creates the category.
  2. All PO T&Cs are catalogued — the migration moves every standard line into the catalogue: the named slots, the two previously-fixed boilerplate lines (under a new "General" category), and an empty "Others" bucket. isDefault clauses pre-fill new POs.
  3. PO form: "+ add a category and select a clause" — components/po/po-terms-editor.tsx is a dynamic list ("+ Add term" → category combobox + clause combobox, pick or type). Used by new / edit / manager-edit. New POs pre-fill from getDefaultPoTerms; editing loads po.terms, or maps legacy tc* + fixed lines for pre-feature POs.

Migration strategy (important)

The original 20260624140000_terms_conditions migration is already released on master, so it is left untouched. This PR adds a forward migration 20260624150000_terms_categories_table that:

  • renames the TermsCategory enum out of the way and creates the TermsCategory table (+ seeds the 7 categories);
  • adds categoryId / isDefault / sortOrder to TermsCondition and migrates the existing enum clauses onto category rows (DELIVERY → Delivery, …), marking the seeded standards as defaults;
  • drops the old enum column + type;
  • seeds the two fixed boilerplate lines under "General";
  • adds PurchaseOrder.terms (JSON snapshot that supersedes tc* for export/detail; old POs fall back to tc* + fixed lines).

Storage stays a point-in-time snapshot, so editing/removing a clause never rewrites historical POs.

Verification

  • Reset replays the enum migration → forward migration in sequence and lands on the table model with data migrated correctly (5 enum clauses → categories, + 2 General fixed lines, 7 defaults). CI builds a throwaway DB the same way.
  • Full integration suite green (265, incl. 9 rewritten terms tests covering on-the-fly category creation + catalogue/default helpers); tsc --noEmit clean.

🤖 Generated with Claude Code

Follow-up to the merged #11 PR (#106), which shipped the **enum-based** T&C catalogue. This makes categories **user-defined** and the PO T&C a **dynamic editor**, per the review asks: 1. **Add new categories along with clauses** — `TermsCategory` is now a TABLE, not an enum. In the admin Add/Edit clause form the category is a combobox; typing a new name **creates the category**. 2. **All PO T&Cs are catalogued** — the migration moves every standard line into the catalogue: the named slots, the two previously-**fixed** boilerplate lines (under a new **"General"** category), and an empty **"Others"** bucket. `isDefault` clauses pre-fill new POs. 3. **PO form: "+ add a category and select a clause"** — `components/po/po-terms-editor.tsx` is a dynamic list ("+ Add term" → category combobox + clause combobox, pick or type). Used by new / edit / manager-edit. New POs pre-fill from `getDefaultPoTerms`; editing loads `po.terms`, or maps legacy `tc*` + fixed lines for pre-feature POs. ## Migration strategy (important) The original `20260624140000_terms_conditions` migration is **already released on master**, so it is **left untouched**. This PR adds a **forward migration** `20260624150000_terms_categories_table` that: - renames the `TermsCategory` enum out of the way and creates the `TermsCategory` **table** (+ seeds the 7 categories); - adds `categoryId` / `isDefault` / `sortOrder` to `TermsCondition` and **migrates the existing enum clauses** onto category rows (`DELIVERY → Delivery`, …), marking the seeded standards as defaults; - drops the old enum column + type; - seeds the two fixed boilerplate lines under "General"; - adds `PurchaseOrder.terms` (JSON snapshot that supersedes `tc*` for export/detail; old POs fall back to `tc*` + fixed lines). Storage stays a point-in-time snapshot, so editing/removing a clause never rewrites historical POs. ## Verification - Reset replays the **enum migration → forward migration** in sequence and lands on the table model with data migrated correctly (5 enum clauses → categories, + 2 General fixed lines, 7 defaults). CI builds a throwaway DB the same way. - Full integration suite green (**265**, incl. 9 rewritten terms tests covering on-the-fly category creation + catalogue/default helpers); `tsc --noEmit` clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
shad0w added 1 commit 2026-06-23 23:14:06 +00:00
feat(po): user-defined T&C categories + dynamic PO terms editor (#11)
All checks were successful
PR checks / checks (pull_request) Successful in 45s
PR checks / integration (pull_request) Successful in 32s
3babfe26ef
Follow-up to the merged #11 PR (which shipped the enum-based catalogue): make
categories user-defined data and the PO T&C a dynamic editor.

- categories are a TermsCategory TABLE (not an enum) — admins add new ones;
- every PO T&C line is catalogued, incl. the previously-fixed boilerplate
  (seeded under a "General" category) and an "Others" bucket;
- the PO form is a dynamic editor: "+ Add term", pick a category, type/pick a
  clause (components/po/po-terms-editor.tsx), used by new/edit/manager-edit.

Migration: the already-released 20260624140000 migration is untouched; a new
20260624150000 FORWARD migration renames the enum, creates the table, migrates
existing enum clauses onto category rows, adds isDefault/sortOrder + the two
fixed lines under General, and adds PurchaseOrder.terms (JSON snapshot that
supersedes the legacy tc* columns for export/detail; old POs fall back to tc*).

Tests rewritten for category creation + catalogue/default helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shad0w merged commit 85805754b5 into master 2026-06-23 23:27:48 +00:00
Sign in to join this conversation.
No description provided.