punchout-simulator 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,8 +99,8 @@ Document-specific:
99
99
  | Document | Checks |
100
100
  |---|---|
101
101
  | **PunchOutSetupResponse** | `Status` present & `200`; valid `StartPage/URL` |
102
- | **PunchOutOrderMessage** (punchback) | `BuyerCookie` matches the session; header `Total`/`Money`+currency; each `ItemIn` has quantity, `SupplierPartID`, `UnitPrice`+currency, `Description`, `UnitOfMeasure`, `Classification`@domain; **Total consistency** (sum of line totals) |
103
- | **OrderRequest** | `orderID`/`orderDate`/`Total`; `ShipTo`/`BillTo`; each `ItemOut`; **attachment `cid:` resolution** (see below) |
102
+ | **PunchOutOrderMessage** (punchback) | `BuyerCookie` matches the session; header `Total`/`Money`+currency; each `ItemIn` has quantity, `SupplierPartID`, `UnitPrice`+currency, `Description`, `UnitOfMeasure`, `Classification`@domain; **single currency** (mixed-currency is an error unless the supplier allows it); **Total consistency** (sum of line totals) |
103
+ | **OrderRequest** | `orderID`/`orderDate`/`Total`; `ShipTo`/`BillTo`; each `ItemOut`; **single currency** (as above); **attachment `cid:` resolution** (see below) |
104
104
  | **OrderResponse** | `Status` code present / not an error |
105
105
 
106
106
  > Note: full cXML DTD validation would require a native validating XML parser,
@@ -167,7 +167,7 @@ backend, so there is no CORS between them).
167
167
  | XML parsing | `fast-xml-parser` |
168
168
  | cXML building | template literals (full control over shape/ordering/`xml:lang`) |
169
169
  | multipart/related | hand-assembled (`Buffer` + boundary) |
170
- | Storage | `lowdb` (`config.json`) for buyers/suppliers/connections/profiles · append-only JSONL per session for logs · separate files for attachments |
170
+ | Storage | `lowdb` (`config.json`) for buyers/suppliers/connections/product-lists/profiles · append-only JSONL per session for logs · separate files for attachments |
171
171
 
172
172
  ```
173
173
  src/
@@ -178,15 +178,41 @@ src/
178
178
 
179
179
  ### Data model
180
180
 
181
- The config is normalized into four entities:
181
+ The config is normalized into five entities:
182
182
 
183
183
  - **Buyer** — a reusable party holding its own cXML identity (the `From` credential) and an optional **platform profile** reference (see below).
184
- - **Supplier** — a reusable party holding its cXML identity (`To`) plus its **endpoints** (PunchOut URL, Order URL) and an optional mock catalog. Endpoints are intrinsic to the supplier — defined once, not per relationship.
185
- - **Connection** — the edge pairing one Buyer with one Supplier. It holds only what is specific to that pair: which side the tool simulates (`mode`), the `sharedSecret`, an optional per-pair Sender identity override (defaults to the buyer's identity), `authStyle`, `deploymentMode`, and `attachmentEncoding`.
184
+ - **Supplier** — a reusable party holding its cXML identity (`To`) plus its **endpoints** (PunchOut URL, Order URL) and the **product lists** it serves as its Mode-B catalog. Endpoints are intrinsic to the supplier — defined once, not per relationship. An optional `allowMixedCurrency` flag relaxes the multi-currency check for this supplier (see below).
185
+ - **Connection** — the edge pairing one Buyer with one Supplier. It holds only what is specific to that pair: which side the tool simulates (`mode`), the `sharedSecret`, an optional per-pair Sender identity override (defaults to the buyer's identity), `deploymentMode`, and `attachmentEncoding`.
186
+ - **Product List** — a reusable, named set of catalog products. Assigned to one or more Suppliers; each supplier serves the **union** of its lists as its mock catalog. See below.
186
187
  - **Profile** — a reusable **procurement-platform profile** (Ariba/Coupa/Jaggaer/…) referenced by a Buyer. See below.
187
188
 
188
189
  At send time: `From` = buyer identity, `To` = supplier identity, `Sender` = the connection's override (or the buyer), and the request targets the supplier's endpoints. The mock-supplier endpoints are keyed by supplier id (`/sim/<supplierId>/…`).
189
190
 
191
+ ### Product lists (Mode-B catalogs)
192
+
193
+ A **Product List** is a named set of catalog items, edited on its own and assigned to one or
194
+ more Suppliers from the **Products** tab. In Mode B a supplier serves the union of its assigned
195
+ lists; a supplier with no lists falls back to a small built-in demo catalog. A built-in
196
+ **Sample assortment** (~20 office/industrial items) ships out of the box and can be **loaded
197
+ into the editor** as a starting point. You can also **import a CSV** (a header row, any column
198
+ order; `SupplierPartID` required) to bulk-load a real catalog — a template is downloadable from
199
+ the editor. Recognized columns: `SupplierPartID`, `SupplierPartAuxiliaryID`, `Description`,
200
+ `UnitPrice`, `Currency`, `UoM`, `UNSPSC` (or a `Classifications` column as
201
+ `UNSPSC:31161500;eCl@ss:27-06`), `ManufacturerPartID`, `ManufacturerName`, `AllowFractional`.
202
+
203
+ Each product carries a `SupplierPartID`, an optional `SupplierPartAuxiliaryID`, description, unit
204
+ price + currency, unit of measure, manufacturer info, and **one or more `Classification`** entries
205
+ (each with its own `domain`, e.g. `UNSPSC` plus a supplier scheme like `eCl@ss`). A product may opt
206
+ into **fractional order quantities** (e.g. `1.5` m of cable) via its `allowFractional` flag — the
207
+ Mode-B catalog then accepts decimals for that item; all other items stay whole-number. These fields
208
+ flow through to the punchback (`ItemIn`) and the resulting OrderRequest (`ItemOut`).
209
+
210
+ **Currency.** A cXML `Total` is a single `Money`, so a document is expected to be single-currency.
211
+ If a cart/order spans more than one currency the mock supplier emits `Total` `0` (rather than a
212
+ meaningless cross-currency sum) and validation raises a `mixed-currency` **error**. A supplier that
213
+ genuinely handles multi-currency orders can set **`allowMixedCurrency`**, which downgrades that to a
214
+ non-blocking **warning** (the per-line `Money` currencies are always preserved either way).
215
+
190
216
  ### Simulating different procurement platforms (Buyer profiles)
191
217
 
192
218
  Real procurement systems emit cXML differently. A **Profile** captures a platform's
@@ -218,6 +244,7 @@ cxml-urlencoded) — i.e. the tool's original behavior.
218
244
 
219
245
  - `*/api/buyers`, `*/api/suppliers` — CRUD for the reusable parties
220
246
  - `*/api/profiles` — CRUD for procurement-platform profiles · `GET /api/profile-presets` — the built-in preset library
247
+ - `*/api/product-lists` — CRUD for product lists · `GET /api/product-list-presets` — the built-in sample library
221
248
  - `*/api/connections` — CRUD for connection edges (reference a buyer + supplier)
222
249
  - `GET /api/connections/:id/setup/preview` · `POST …/setup` — preview / send the SetupRequest
223
250
  - `POST /api/connections/:id/order/preview` · `POST …/order` — preview / send the OrderRequest (multipart if attachments)