Catalog item units, measurements, and categories
New: Units, measurements, and quantity-calculation fields on catalog items
Catalog items now expose the same unit and measurement-driven quantity calculation available in the Coperniq UI.
GET/POST/PATCH /catalog-items responses and request bodies gain:
Notes
measurementIdsis replace-all onPATCH, not a merge: omit it to leave existing links unchanged, or pass[]to clear all links. There’s no way to append a single measurement without resending the full set.- A linked measurement can be a plain measurement (one or more, summed — all must share a unit or be unitless) or a single sub-calculation (“sub-measurement”), never both. Linking a sub-calculation alongside anything else returns
400.
New: List and get catalog units
Use these IDs when setting unitId on a catalog item. Every company starts with a seeded default set (Each, Square Feet, Linear Feet, etc.); isCustom distinguishes those from any additional units a company has added.
New: List and get measurements
Filter with ?type=MEASUREMENT or ?type=SUB_CALCULATION. Use these IDs when setting measurementIds on a catalog item. A sub-calculation’s read-only formula shows what it computes from, but formulas can only be authored in the Coperniq UI.
New: List catalog categories
GET /catalog-categories returns the valid category codes for catalog items, grouped by PRODUCT/SERVICE, plus the available tradeGroup values — everything needed to populate category and tradeGroup on POST/PATCH /catalog-items.
Changed: tradeGroup is derived from category when omitted
POST /catalog-items previously stored tradeGroup: "OTHER" whenever the field was omitted, even for a product category that clearly belongs to another group. It is now derived from the category — ROOF_COVERING resolves to ENVELOPE, PV_MODULE to ENERGY, and so on. Services and category OTHER still resolve to OTHER. Pass tradeGroup explicitly to keep full control.
Changed: PATCH /catalog-items/{catalog_item_id} validates the resulting item, not just the patch
A partial update is now merged over the stored item and the result checked before the write, so a patch can no longer leave an item in a state POST would have rejected — for example setting category to a code outside the item’s stored tradeGroup, or adding an sku to an item that is already a SERVICE. These return 400 with the offending field. Inconsistencies that already existed on the stored item are left alone, so unrelated edits to older items keep working.
Converting a PRODUCT that has an sku into a SERVICE is still allowed and does not require clearing the sku first — services have no sku, so it is dropped as part of the conversion. Sending sku: null during that conversion is accepted and has the same effect; for an item already stored as a SERVICE, a legacy sku cannot be cleared or changed by this API and the request returns 400.
