@campfire-interactive/master-data-client 4.3.0 → 4.8.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.
Files changed (75) hide show
  1. package/dist/companies.d.ts +5 -1
  2. package/dist/companies.d.ts.map +1 -1
  3. package/dist/companies.js +16 -0
  4. package/dist/companies.js.map +1 -1
  5. package/dist/engineeringChanges.d.ts +8 -6
  6. package/dist/engineeringChanges.d.ts.map +1 -1
  7. package/dist/engineeringChanges.js +8 -6
  8. package/dist/engineeringChanges.js.map +1 -1
  9. package/dist/equipment.d.ts +5 -1
  10. package/dist/equipment.d.ts.map +1 -1
  11. package/dist/equipment.js +18 -2
  12. package/dist/equipment.js.map +1 -1
  13. package/dist/exchangeRates.d.ts +6 -1
  14. package/dist/exchangeRates.d.ts.map +1 -1
  15. package/dist/exchangeRates.js +11 -0
  16. package/dist/exchangeRates.js.map +1 -1
  17. package/dist/imports.d.ts +7 -1
  18. package/dist/imports.d.ts.map +1 -1
  19. package/dist/imports.js +9 -0
  20. package/dist/imports.js.map +1 -1
  21. package/dist/index.d.ts +3 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -1
  24. package/dist/index.js.map +1 -1
  25. package/dist/materials.d.ts +5 -1
  26. package/dist/materials.d.ts.map +1 -1
  27. package/dist/materials.js +16 -0
  28. package/dist/materials.js.map +1 -1
  29. package/dist/partAttributes.d.ts +7 -1
  30. package/dist/partAttributes.d.ts.map +1 -1
  31. package/dist/partAttributes.js +18 -0
  32. package/dist/partAttributes.js.map +1 -1
  33. package/dist/partCategories.d.ts +7 -1
  34. package/dist/partCategories.d.ts.map +1 -1
  35. package/dist/partCategories.js +18 -0
  36. package/dist/partCategories.js.map +1 -1
  37. package/dist/partTypes.d.ts +6 -1
  38. package/dist/partTypes.d.ts.map +1 -1
  39. package/dist/partTypes.js +17 -0
  40. package/dist/partTypes.js.map +1 -1
  41. package/dist/parts.d.ts +5 -1
  42. package/dist/parts.d.ts.map +1 -1
  43. package/dist/parts.js +16 -0
  44. package/dist/parts.js.map +1 -1
  45. package/dist/plants.d.ts +8 -1
  46. package/dist/plants.d.ts.map +1 -1
  47. package/dist/plants.js +21 -2
  48. package/dist/plants.js.map +1 -1
  49. package/dist/processFamilies.d.ts +6 -2
  50. package/dist/processFamilies.d.ts.map +1 -1
  51. package/dist/processFamilies.js +18 -2
  52. package/dist/processFamilies.js.map +1 -1
  53. package/dist/programs.d.ts +5 -1
  54. package/dist/programs.d.ts.map +1 -1
  55. package/dist/programs.js +16 -0
  56. package/dist/programs.js.map +1 -1
  57. package/dist/quotes.d.ts +9 -1
  58. package/dist/quotes.d.ts.map +1 -1
  59. package/dist/quotes.js +14 -0
  60. package/dist/quotes.js.map +1 -1
  61. package/dist/rateCatalog.d.ts +46 -1
  62. package/dist/rateCatalog.d.ts.map +1 -1
  63. package/dist/rateCatalog.js +73 -6
  64. package/dist/rateCatalog.js.map +1 -1
  65. package/dist/schedulePeriods.d.ts +16 -0
  66. package/dist/schedulePeriods.d.ts.map +1 -0
  67. package/dist/schedulePeriods.js +81 -0
  68. package/dist/schedulePeriods.js.map +1 -0
  69. package/dist/types.d.ts +159 -6
  70. package/dist/types.d.ts.map +1 -1
  71. package/package.json +1 -1
  72. package/dist/suppliers.d.ts +0 -14
  73. package/dist/suppliers.d.ts.map +0 -1
  74. package/dist/suppliers.js +0 -84
  75. package/dist/suppliers.js.map +0 -1
@@ -6,10 +6,14 @@ class UomResource {
6
6
  constructor(http) {
7
7
  this.http = http;
8
8
  }
9
+ /** Bug fix: this previously sent an `active` boolean param the backend
10
+ * never read (listUoms had no status concept at all) — the Archived/All
11
+ * filter silently no-opped. Now sends `status`, matching every other
12
+ * entity's convention, paired with Uom's newly-added soft archive. */
9
13
  async list(options) {
10
14
  const query = {};
11
- if (options?.active !== undefined)
12
- query.active = String(options.active);
15
+ if (options?.status)
16
+ query.status = options.status;
13
17
  return this.http.request({
14
18
  method: 'GET',
15
19
  path: '/v1/rate-catalog/uoms',
@@ -30,24 +34,46 @@ class UomResource {
30
34
  body: input,
31
35
  });
32
36
  }
37
+ /** Hard delete. Prefer {@link batchArchive} for reversible removal. */
33
38
  async remove(id) {
34
39
  await this.http.request({
35
40
  method: 'DELETE',
36
41
  path: `/v1/rate-catalog/uoms/${encodeURIComponent(id)}`,
37
42
  });
38
43
  }
44
+ /** Archive many UoMs in one call (soft, flips `active`; distinct from the
45
+ * hard {@link remove} above — new capability). Reversible via
46
+ * {@link batchRestore}. */
47
+ async batchArchive(ids) {
48
+ return this.http.request({
49
+ method: 'POST',
50
+ path: '/v1/rate-catalog/uoms/batch-archive',
51
+ body: { ids },
52
+ });
53
+ }
54
+ /** Restore (un-archive) many UoMs in one call. */
55
+ async batchRestore(ids) {
56
+ return this.http.request({
57
+ method: 'POST',
58
+ path: '/v1/rate-catalog/uoms/batch-restore',
59
+ body: { ids },
60
+ });
61
+ }
39
62
  }
40
63
  class RateLineResource {
41
64
  http;
42
65
  constructor(http) {
43
66
  this.http = http;
44
67
  }
68
+ /** Bug fix: this previously sent an `active` boolean param the backend
69
+ * never read (it reads `status`) — the Archived/All filter silently
70
+ * no-opped. Now sends `status`, matching every other entity. */
45
71
  async list(options) {
46
72
  const query = {};
47
73
  if (options?.binding)
48
74
  query.binding = options.binding;
49
- if (options?.active !== undefined)
50
- query.active = String(options.active);
75
+ if (options?.status)
76
+ query.status = options.status;
51
77
  return this.http.request({
52
78
  method: 'GET',
53
79
  path: '/v1/rate-catalog/lines',
@@ -68,22 +94,44 @@ class RateLineResource {
68
94
  body: input,
69
95
  });
70
96
  }
97
+ /** Hard delete. 2026-07-24: previously soft-archived (matched Archive), which made
98
+ * the two indistinguishable; now really deletes. Prefer {@link batchArchive}
99
+ * for reversible removal. */
71
100
  async remove(id) {
72
101
  await this.http.request({
73
102
  method: 'DELETE',
74
103
  path: `/v1/rate-catalog/lines/${encodeURIComponent(id)}`,
75
104
  });
76
105
  }
106
+ /** Archive many rate lines in one call. Reversible via {@link batchRestore}. */
107
+ async batchArchive(ids) {
108
+ return this.http.request({
109
+ method: 'POST',
110
+ path: '/v1/rate-catalog/lines/batch-archive',
111
+ body: { ids },
112
+ });
113
+ }
114
+ /** Restore (un-archive) many rate lines in one call. */
115
+ async batchRestore(ids) {
116
+ return this.http.request({
117
+ method: 'POST',
118
+ path: '/v1/rate-catalog/lines/batch-restore',
119
+ body: { ids },
120
+ });
121
+ }
77
122
  }
78
123
  class RateGradeResource {
79
124
  http;
80
125
  constructor(http) {
81
126
  this.http = http;
82
127
  }
128
+ /** Bug fix: this previously sent an `active` boolean param the backend
129
+ * never read (it reads `status`) — the Archived/All filter silently
130
+ * no-opped. Now sends `status`, matching every other entity. */
83
131
  async list(options) {
84
132
  const query = {};
85
- if (options?.active !== undefined)
86
- query.active = String(options.active);
133
+ if (options?.status)
134
+ query.status = options.status;
87
135
  return this.http.request({
88
136
  method: 'GET',
89
137
  path: '/v1/rate-catalog/grades',
@@ -104,12 +152,31 @@ class RateGradeResource {
104
152
  body: input,
105
153
  });
106
154
  }
155
+ /** Hard delete. 2026-07-24: previously soft-archived (matched Archive), which made
156
+ * the two indistinguishable; now really deletes. Prefer {@link batchArchive}
157
+ * for reversible removal. */
107
158
  async remove(id) {
108
159
  await this.http.request({
109
160
  method: 'DELETE',
110
161
  path: `/v1/rate-catalog/grades/${encodeURIComponent(id)}`,
111
162
  });
112
163
  }
164
+ /** Archive many rate grades in one call. Reversible via {@link batchRestore}. */
165
+ async batchArchive(ids) {
166
+ return this.http.request({
167
+ method: 'POST',
168
+ path: '/v1/rate-catalog/grades/batch-archive',
169
+ body: { ids },
170
+ });
171
+ }
172
+ /** Restore (un-archive) many rate grades in one call. */
173
+ async batchRestore(ids) {
174
+ return this.http.request({
175
+ method: 'POST',
176
+ path: '/v1/rate-catalog/grades/batch-restore',
177
+ body: { ids },
178
+ });
179
+ }
113
180
  }
114
181
  /**
115
182
  * Rate reference catalogs (UoM / RateLine / RateGrade) — the vocabulary a rate
@@ -1 +1 @@
1
- {"version":3,"file":"rateCatalog.js","sourceRoot":"","sources":["../src/rateCatalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rateCatalog.js","sourceRoot":"","sources":["../src/rateCatalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { SchedulePeriod } from './types';
2
+ /** The recognisable shapes a span can take. `custom` = anything else. */
3
+ export type SchedulePeriodGranularity = 'year' | 'quarter' | 'month' | 'fiscal-year' | 'custom';
4
+ /**
5
+ * Classify a span by its shape. A period is only a `year` / `quarter` / `month`
6
+ * if it covers exactly that unit — a stretch that merely starts on Jan 1 but
7
+ * ends in November is `custom`, not a year, because calling it "2027" would
8
+ * overstate what the customer committed to.
9
+ */
10
+ export declare function schedulePeriodGranularity(period: SchedulePeriod): SchedulePeriodGranularity;
11
+ /**
12
+ * Human label for a span: `2027`, `Q2 2027`, `Mar 2027`, `FY 2026-27`, or a raw
13
+ * `2027-03-15 – 2027-04-28` range when the span matches no convention.
14
+ */
15
+ export declare function formatSchedulePeriod(period: SchedulePeriod): string;
16
+ //# sourceMappingURL=schedulePeriods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedulePeriods.d.ts","sourceRoot":"","sources":["../src/schedulePeriods.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAoB9C,yEAAyE;AACzE,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;AAmBhG;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,cAAc,GAAG,yBAAyB,CAmB3F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAiBnE"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schedulePeriodGranularity = schedulePeriodGranularity;
4
+ exports.formatSchedulePeriod = formatSchedulePeriod;
5
+ /**
6
+ * Display helpers for arbitrary-period schedules (`effectiveVolumesByPeriod` /
7
+ * `effectivePricesByPeriod`).
8
+ *
9
+ * Granularity is NOT stored on a schedule point — it's derivable from the span,
10
+ * and a stored label can contradict the dates. It lives here rather than in each
11
+ * consumer so every app labels the same span identically.
12
+ *
13
+ * Note there is deliberately no rollup helper here: the yearly rollup CPQ costs
14
+ * against is computed server-side at write time, so there is exactly one
15
+ * implementation of it and clients can't disagree with the stored column.
16
+ */
17
+ const MONTHS = [
18
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
19
+ 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
20
+ ];
21
+ function parts(iso) {
22
+ const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso);
23
+ if (!m)
24
+ return null;
25
+ return { year: Number(m[1]), month: Number(m[2]), day: Number(m[3]) };
26
+ }
27
+ function lastDayOfMonth(year, month) {
28
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
29
+ }
30
+ /**
31
+ * Classify a span by its shape. A period is only a `year` / `quarter` / `month`
32
+ * if it covers exactly that unit — a stretch that merely starts on Jan 1 but
33
+ * ends in November is `custom`, not a year, because calling it "2027" would
34
+ * overstate what the customer committed to.
35
+ */
36
+ function schedulePeriodGranularity(period) {
37
+ const start = parts(period.periodStart);
38
+ const end = parts(period.periodEnd);
39
+ if (!start || !end)
40
+ return 'custom';
41
+ const endsMonth = end.day === lastDayOfMonth(end.year, end.month);
42
+ if (start.day !== 1 || !endsMonth)
43
+ return 'custom';
44
+ if (start.year === end.year) {
45
+ if (start.month === 1 && end.month === 12)
46
+ return 'year';
47
+ if (start.month === end.month)
48
+ return 'month';
49
+ // Calendar quarters only — Feb-Apr is a 3-month custom block, not "Q1".
50
+ if (end.month - start.month === 2 && (start.month - 1) % 3 === 0)
51
+ return 'quarter';
52
+ return 'custom';
53
+ }
54
+ // A 12-month span crossing exactly one year boundary reads as a fiscal year.
55
+ if (end.year === start.year + 1 && end.month === start.month - 1)
56
+ return 'fiscal-year';
57
+ return 'custom';
58
+ }
59
+ /**
60
+ * Human label for a span: `2027`, `Q2 2027`, `Mar 2027`, `FY 2026-27`, or a raw
61
+ * `2027-03-15 – 2027-04-28` range when the span matches no convention.
62
+ */
63
+ function formatSchedulePeriod(period) {
64
+ const start = parts(period.periodStart);
65
+ const end = parts(period.periodEnd);
66
+ if (!start || !end)
67
+ return `${period.periodStart} – ${period.periodEnd}`;
68
+ switch (schedulePeriodGranularity(period)) {
69
+ case 'year':
70
+ return String(start.year);
71
+ case 'quarter':
72
+ return `Q${Math.floor((start.month - 1) / 3) + 1} ${start.year}`;
73
+ case 'month':
74
+ return `${MONTHS[start.month - 1]} ${start.year}`;
75
+ case 'fiscal-year':
76
+ return `FY ${start.year}-${String(end.year % 100).padStart(2, '0')}`;
77
+ default:
78
+ return `${period.periodStart} – ${period.periodEnd}`;
79
+ }
80
+ }
81
+ //# sourceMappingURL=schedulePeriods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedulePeriods.js","sourceRoot":"","sources":["../src/schedulePeriods.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -194,6 +194,9 @@ export interface Quote {
194
194
  * — the figure CPQ costs against. Seeded from OMSF's vehicle→part conversion
195
195
  * (VI vehicle × take rate), then the rep's edit over it. Independent of
196
196
  * {@link effectiveVolumesByYear}; neither is auto-derived from the other.
197
+ *
198
+ * **Unless {@link effectiveVolumesByPeriod} is set**, in which case this is
199
+ * DERIVED from it (the mean of the rolled-up years) and writing it is a 422.
197
200
  */
198
201
  effectiveAnnualVolume: number | null;
199
202
  /**
@@ -201,8 +204,36 @@ export interface Quote {
201
204
  * NOT vehicle/program) — the primary figure CPQ costs against. Stored as
202
205
  * JSONB; shape pinned here and at the API boundary. Seeded from OMSF's
203
206
  * vehicle→part conversion at quote creation, then refined by the rep.
207
+ *
208
+ * **Unless {@link effectiveVolumesByPeriod} is set**, in which case this is
209
+ * DERIVED from it at write time (day-count pro-rated for spans that straddle a
210
+ * year) and writing it is a 422. Readers need no change either way — this
211
+ * column stays the canonical yearly curve.
204
212
  */
205
213
  effectiveVolumesByYear: EffectiveVolumeByYear[] | null;
214
+ /**
215
+ * Customer-committed PART volume on ARBITRARY periods — the general form of
216
+ * {@link effectiveVolumesByYear}, for deals tracked at a granularity the year
217
+ * key can't express (monthly launch ramp with annual out-years, fiscal years,
218
+ * irregular blocks). When non-empty it is AUTHORITATIVE and the two fields
219
+ * above are derived from it.
220
+ *
221
+ * Independent of {@link effectivePricesByPeriod}: no point pairs with a price
222
+ * point, either may exist alone, and the two period grids may disagree.
223
+ * Overlapping periods within this series are rejected (422). (4.8.0)
224
+ */
225
+ effectiveVolumesByPeriod: EffectiveVolumeByPeriod[] | null;
226
+ /**
227
+ * Customer-committed unit price on ARBITRARY periods — the price walk / LTA
228
+ * step-down the customer agreed to.
229
+ *
230
+ * **Derives nothing.** {@link effectiveUnitPrice} keeps its adapter-written
231
+ * provenance (`effectivePriceSource` / `effectivePricedAt` / …) and is
232
+ * untouched by this field, so no margin figure moves when a schedule is
233
+ * imported. Readers wanting one headline number from this series must decide
234
+ * how to weight it (volume-weighted, not a mean). (4.8.0)
235
+ */
236
+ effectivePricesByPeriod: EffectivePriceByPeriod[] | null;
206
237
  status: QuoteStatus;
207
238
  /** rfq | eco — see {@link QuoteType}. Immutable post-create. (3.0.2) */
208
239
  quoteType: QuoteType;
@@ -231,6 +262,28 @@ export interface EffectiveVolumeByYear {
231
262
  year: number;
232
263
  effectiveVolume: number;
233
264
  }
265
+ /**
266
+ * One inclusive period in an arbitrary-period schedule. Every granularity is a
267
+ * span, so yearly (`2027-01-01`→`2027-12-31`), quarterly, monthly, fiscal
268
+ * (`2026-07-01`→`2027-06-30`) and irregular stretches are all the same shape,
269
+ * and a single quote may mix them. Granularity is deliberately not stored —
270
+ * derive it from the span (see `formatSchedulePeriod`). (4.8.0)
271
+ */
272
+ export interface SchedulePeriod {
273
+ /** ISO date, inclusive. */
274
+ periodStart: string;
275
+ /** ISO date, inclusive. */
276
+ periodEnd: string;
277
+ }
278
+ /** Row inside {@link Quote.effectiveVolumesByPeriod}. (4.8.0) */
279
+ export interface EffectiveVolumeByPeriod extends SchedulePeriod {
280
+ effectiveVolume: number;
281
+ }
282
+ /** Row inside {@link Quote.effectivePricesByPeriod}. Decimal-as-string, like
283
+ * {@link Quote.targetPrice}. (4.8.0) */
284
+ export interface EffectivePriceByPeriod extends SchedulePeriod {
285
+ effectiveUnitPrice: string;
286
+ }
234
287
  export interface SetEffectiveCostInput {
235
288
  unitCost: number;
236
289
  /** 'cpq' | 'manual' | 'external' — declared by the adapter. */
@@ -285,6 +338,11 @@ export interface CreateQuoteInput {
285
338
  eopPrecision?: SopEopPrecision;
286
339
  effectiveAnnualVolume?: number;
287
340
  effectiveVolumesByYear?: EffectiveVolumeByYear[];
341
+ /** Arbitrary-period committed volume. Non-empty makes the two fields above
342
+ * derived — passing either alongside it is a 422. (4.8.0) */
343
+ effectiveVolumesByPeriod?: EffectiveVolumeByPeriod[];
344
+ /** Arbitrary-period committed unit price. Storage only. (4.8.0) */
345
+ effectivePricesByPeriod?: EffectivePriceByPeriod[];
288
346
  /**
289
347
  * Quote type — defaults to 'rfq'. Immutable post-create. When 'eco',
290
348
  * `referenceQuoteId` becomes REQUIRED and must point to an in-tenant,
@@ -296,6 +354,8 @@ export interface CreateQuoteInput {
296
354
  baselineUnitPrice?: number | string;
297
355
  /** ECO-only (422 otherwise): frozen as-awarded unit cost. (3.0.2) */
298
356
  baselineUnitCost?: number | string;
357
+ /** Defaults to 'draft' (the model default) if omitted. */
358
+ quality?: 'draft' | 'verified';
299
359
  }
300
360
  /**
301
361
  * Non-status fields only. Status changes go through `transitionStatus(...)`
@@ -325,6 +385,13 @@ export interface UpdateQuoteInput {
325
385
  eopPrecision?: SopEopPrecision | null;
326
386
  effectiveAnnualVolume?: number | null;
327
387
  effectiveVolumesByYear?: EffectiveVolumeByYear[] | null;
388
+ /** Full replace. Non-empty makes the yearly fields derived (writing them is a
389
+ * 422); `null` or `[]` clears the schedule and hands them back. The last
390
+ * derived values are left in place — clearing stops maintaining them, it
391
+ * doesn't wipe the curve. (4.8.0) */
392
+ effectiveVolumesByPeriod?: EffectiveVolumeByPeriod[] | null;
393
+ /** Full replace. Storage only, independent of the volume schedule. (4.8.0) */
394
+ effectivePricesByPeriod?: EffectivePriceByPeriod[] | null;
328
395
  quality?: 'draft' | 'verified';
329
396
  }
330
397
  export interface TransitionQuoteStatusInput {
@@ -374,8 +441,48 @@ export interface GetQuoteOptions {
374
441
  export type EcStatus = 'requested' | 'triaged' | 'converted' | 'partially_applied' | 'applied' | 'cancelled';
375
442
  /** Engineering-change driver taxonomy — mirrors CPQ's EcChangeDriver (F6). */
376
443
  export type EcChangeDriver = 'material' | 'routing' | 'capital' | 'other';
377
- /** Which app is writing — gated per-endpoint server-side. */
378
- export type EcCallerRole = 'omsf' | 'cpq' | 'admin';
444
+ /** Which app is writing — gated per-endpoint server-side. `bom` and `omsf` are
445
+ * create-only intake sources; convert + status are `cpq`/`admin`. */
446
+ export type EcCallerRole = 'omsf' | 'bom' | 'cpq' | 'admin';
447
+ /** A part/assembly reference inside {@link EngineeringChangeDetail}. */
448
+ export interface EngineeringChangeDetailPartRef {
449
+ partId: string;
450
+ partNumber: string;
451
+ name: string;
452
+ }
453
+ /** Per-BOM impact inside {@link EngineeringChangeDetail}. */
454
+ export interface EngineeringChangeDetailBomImpact {
455
+ bomType: string;
456
+ bomVersionId: string;
457
+ partsAffectedCount: number;
458
+ costDeltaCents: number;
459
+ marginDeltaBps: number | null;
460
+ annualImpactCents: number;
461
+ summary: string;
462
+ }
463
+ /**
464
+ * Structured change detail authored by a rich intake source (BOM) so the EC is
465
+ * self-describing for CPQ + Program Management without reaching back into the
466
+ * originating app. Discriminated by `source`; validated server-side on write.
467
+ * Absent (null) for thin intake (OMSF sends free-text `description` only). See
468
+ * the BOM cutover plan bom/docs/plans/2026-07-23-bom-raises-engineering-change.md (D6).
469
+ */
470
+ export interface EngineeringChangeDetail {
471
+ /** The only rich shape defined in v1. */
472
+ source: 'bom';
473
+ changeType: string;
474
+ fromValue: string | null;
475
+ toValue: string | null;
476
+ reason: string | null;
477
+ affectedParts: EngineeringChangeDetailPartRef[];
478
+ affectedAssemblies: EngineeringChangeDetailPartRef[];
479
+ affectedBoms: EngineeringChangeDetailBomImpact[];
480
+ totals: {
481
+ partsAffectedCount: number;
482
+ subassembliesAffectedCount: number;
483
+ totalCostDeltaCents: number;
484
+ };
485
+ }
379
486
  /**
380
487
  * An engineering change — the grouping entity correlating the N member ECO
381
488
  * quotes one change fans out to. master-data owns this identity; OMSF and CPQ
@@ -404,6 +511,10 @@ export interface EngineeringChange {
404
511
  /** Stored, inert in v1 — effectivity semantics (phasing, per-part) are not
405
512
  * yet decided, so no consumer may compute off this. Date serialized as string. */
406
513
  effectiveDate: string | null;
514
+ /** Structured change detail (D6) authored by a rich intake source (BOM).
515
+ * Null for thin intake (OMSF). Descriptive metadata — not structural
516
+ * membership (that stays quote-grain via {@link memberQuoteIds}). */
517
+ changeDetail: EngineeringChangeDetail | null;
407
518
  createdAt: string;
408
519
  updatedAt: string;
409
520
  /** Member ECO quote ids (quote-grain membership). Populated on {@link get}. */
@@ -415,8 +526,11 @@ export interface CreateEngineeringChangeInput {
415
526
  description: string;
416
527
  requestedById: string;
417
528
  requestedByName: string;
418
- /** Gated server-side to 'omsf' | 'cpq'. */
529
+ /** Gated server-side to 'omsf' | 'bom' | 'cpq' | 'admin' (create is intake). */
419
530
  callerRole: EcCallerRole;
531
+ /** Optional structured change detail (D6). Validated server-side against the
532
+ * {@link EngineeringChangeDetail} shape; omit for thin intake (OMSF). */
533
+ changeDetail?: EngineeringChangeDetail;
420
534
  }
421
535
  /** Fan-out conversion — CPQ stamps number, title, driver, and members. */
422
536
  export interface ConvertEngineeringChangeInput {
@@ -558,6 +672,11 @@ export interface ListPlantsOptions {
558
672
  cursor?: string;
559
673
  sort?: string;
560
674
  q?: string;
675
+ status?: 'active' | 'archived' | 'all';
676
+ /** @deprecated Never actually reached the backend filter (it reads
677
+ * `status`, not `active`) — use `status` instead. Kept only so any
678
+ * existing caller that sets this doesn't hit a type error; has no
679
+ * effect. */
561
680
  active?: boolean;
562
681
  country?: string;
563
682
  region?: string;
@@ -965,6 +1084,10 @@ export interface ListEquipmentOptions {
965
1084
  q?: string;
966
1085
  plantId?: string;
967
1086
  processFamily?: string;
1087
+ status?: 'active' | 'archived' | 'all';
1088
+ /** @deprecated Never actually reached the backend filter (it reads
1089
+ * `status`, not `active`) — use `status` instead. Kept only so any
1090
+ * existing caller that sets this doesn't hit a type error; has no effect. */
968
1091
  active?: boolean;
969
1092
  }
970
1093
  export interface ProcessFamily {
@@ -1640,7 +1763,7 @@ export interface UpdateLocationInput {
1640
1763
  country?: string;
1641
1764
  }
1642
1765
  export type ImportStatus = 'pending_upload' | 'pending_parse' | 'pending_mapping' | 'pending_validation' | 'validated' | 'committed' | 'failed';
1643
- export type ImportEntityType = 'company' | 'contact' | 'location' | 'plant' | 'material' | 'rate_library' | 'rate_entries';
1766
+ export type ImportEntityType = 'company' | 'contact' | 'location' | 'plant' | 'material' | 'part' | 'part_category' | 'program' | 'rate_library' | 'rate_entries' | 'equipment' | 'process_family' | 'part_type' | 'exchange_rate' | 'quote' | 'part_attribute' | 'uom' | 'rate_line' | 'rate_grade';
1644
1767
  export type ImportSheetAssignment = ImportEntityType | 'skip';
1645
1768
  /** Identifies which app initiated an import session. Cross-app callers
1646
1769
  * (anything other than 'master-data') are limited to a subset of entity
@@ -1657,7 +1780,7 @@ export type SourceApp = 'master-data' | 'erfq' | 'cpq' | 'bom' | 'forecast' | 'o
1657
1780
  * "Empty" means SQL NULL only — a stored '', 0, false, or 0.0 counts as
1658
1781
  * populated and will not be overwritten by fill_empty. */
1659
1782
  export type MergePolicy = 'overwrite' | 'fill_empty';
1660
- export type ImportTargetField = 'name' | 'legalName' | 'code' | 'taxId' | 'dunsNumber' | 'website' | 'logoUrl' | 'roles' | 'email' | 'phone' | 'role' | 'type' | 'description' | 'street' | 'city' | 'stateProvince' | 'postalCode' | 'country' | 'category' | 'parent_company_ref' | 'companyCode' | 'locationCode' | 'region' | 'headcount' | 'annualCapacityHours' | 'currentUtilization' | 'riskLevel' | 'numShifts' | 'hoursPerShift' | 'workingDaysPerYear' | 'indirectHeadcountPct' | 'currency' | 'effectiveDate' | 'effectiveTo' | 'libraryCode' | 'kind' | 'plantCode' | 'skillTier' | 'materialCode' | 'regionCode' | 'lane' | 'rate' | 'unit' | 'sourcingMode' | 'indexRef' | 'notes';
1783
+ export type ImportTargetField = 'name' | 'legalName' | 'code' | 'taxId' | 'dunsNumber' | 'website' | 'logoUrl' | 'roles' | 'email' | 'phone' | 'role' | 'type' | 'description' | 'street' | 'city' | 'stateProvince' | 'postalCode' | 'country' | 'category' | 'parent_company_ref' | 'companyCode' | 'locationCode' | 'region' | 'headcount' | 'annualCapacityHours' | 'currentUtilization' | 'riskLevel' | 'numShifts' | 'hoursPerShift' | 'workingDaysPerYear' | 'indirectHeadcountPct' | 'currency' | 'effectiveDate' | 'effectiveTo' | 'libraryCode' | 'kind' | 'plantCode' | 'skillTier' | 'materialCode' | 'regionCode' | 'lane' | 'rate' | 'unit' | 'sourcingMode' | 'indexRef' | 'notes' | 'partNumber' | 'manufacturingPartNumber' | 'customerPartNumber' | 'partType' | 'manufacturer' | 'partCategoryCode' | 'quality' | 'revision' | 'uom' | 'weightPerUnit' | 'recycledPct' | 'pcfPerUnit' | 'releaseStatus' | 'leadTime' | 'customerCompanyCode' | 'customerCompanyName' | 'sopDate' | 'eopDate' | 'displayOrder' | 'label' | 'sortOrder' | 'processFamily' | 'capacityHoursPerYear' | 'cavities' | 'availabilityPct' | 'performancePct' | 'defaultHeadcount' | 'defaultAutomationPct' | 'defaultMachinesPerOperator' | 'defaultSetupCrew' | 'perUsd' | 'effectiveFrom' | 'quoteNumber' | 'programCode' | 'partId' | 'regionName' | 'annualVolume' | 'apw' | 'mpw' | 'targetPrice' | 'dueDate' | 'key' | 'dataType' | 'options' | 'group' | 'required' | 'min' | 'max' | 'regex' | 'precision' | 'basis' | 'bindings' | 'perBaseFactor' | 'needsDensity' | 'binding' | 'allowedUoms' | 'defaultUom' | 'escalationDefault' | 'density' | 'densityUnit';
1661
1784
  export interface ImportSession {
1662
1785
  id: string;
1663
1786
  tenantId: string;
@@ -1682,7 +1805,7 @@ export interface CreateImportInput {
1682
1805
  filename: string;
1683
1806
  /** Session root entity type. The workbook may contain other entity types in
1684
1807
  * additional sheets, but this names the "primary" import. */
1685
- entityType: 'company' | 'plant' | 'material' | 'rate_library';
1808
+ entityType: 'company' | 'plant' | 'material' | 'part' | 'part_category' | 'program' | 'rate_library' | 'equipment' | 'process_family' | 'part_type' | 'exchange_rate' | 'quote' | 'part_attribute' | 'uom';
1686
1809
  /** Which app is initiating this upload. Cross-app callers (non-'master-data')
1687
1810
  * are gated to a subset of entity types via the server's allowlist. Default
1688
1811
  * is 'master-data'. */
@@ -1895,6 +2018,10 @@ export interface ImportCommitResult {
1895
2018
  locations?: BatchCreateChildResult;
1896
2019
  plants?: BatchCreateChildResult;
1897
2020
  materials?: BatchCreateMaterialsResult;
2021
+ /** Parts share the material-style extended summary (mergedFields/untouched). */
2022
+ parts?: BatchCreateMaterialsResult;
2023
+ programs?: BatchCreateChildResult;
2024
+ partCategories?: BatchCreateChildResult;
1898
2025
  rateLibraries?: BatchCreateChildResult;
1899
2026
  rateEntries?: BatchCreateChildResult;
1900
2027
  /** Child rows skipped because their parent failed to commit (contacts /
@@ -1903,6 +2030,32 @@ export interface ImportCommitResult {
1903
2030
  * materialCode/regionCode didn't resolve). */
1904
2031
  orphansSkipped: number;
1905
2032
  }
2033
+ /** Downloadable blank import template. Served inline as base64 (no storage
2034
+ * round-trip; works identically in local dev and prod). The client decodes
2035
+ * `contentBase64` → Blob and triggers a browser download. */
2036
+ export interface TemplateDownload {
2037
+ filename: string;
2038
+ mimeType: string;
2039
+ contentBase64: string;
2040
+ }
2041
+ /** Result envelope for bulk archive / restore. `ok` counts rows whose status
2042
+ * flipped (or were already in the target state — idempotent). */
2043
+ export interface BulkArchiveResult {
2044
+ results: Array<{
2045
+ id: string;
2046
+ status: 'ok';
2047
+ } | {
2048
+ id: string;
2049
+ status: 'error';
2050
+ error: string;
2051
+ code: string;
2052
+ }>;
2053
+ summary: {
2054
+ total: number;
2055
+ ok: number;
2056
+ errors: number;
2057
+ };
2058
+ }
1906
2059
  export interface ApiMeta {
1907
2060
  requestId: string;
1908
2061
  timestamp: string;