@configura/web-api 2.0.0-alpha.18 → 2.0.0-alpha.20

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 (30) hide show
  1. package/dist/CatalogueAPI.d.ts +47 -17
  2. package/dist/CatalogueAPI.js +61 -6
  3. package/dist/CfgProduct.d.ts +17 -6
  4. package/dist/CfgProduct.js +55 -14
  5. package/dist/CfgReferencePathHelper.d.ts +3 -3
  6. package/dist/productConfiguration/CfgFeature.d.ts +6 -4
  7. package/dist/productConfiguration/CfgFeature.js +13 -6
  8. package/dist/productConfiguration/CfgOption.d.ts +3 -3
  9. package/dist/productConfiguration/CfgOption.js +5 -5
  10. package/dist/productConfiguration/CfgProductConfiguration.d.ts +16 -7
  11. package/dist/productConfiguration/CfgProductConfiguration.js +41 -14
  12. package/dist/productConfiguration/filters.d.ts +2 -2
  13. package/dist/productConfiguration/productParamsGenerator.d.ts +3 -3
  14. package/dist/productConfiguration/utilitiesProductConfiguration.d.ts +1 -1
  15. package/dist/productConfiguration/utilitiesProductConfiguration.js +11 -4
  16. package/dist/productLoader.d.ts +3 -3
  17. package/dist/syncGroups/SyncGroupsHandler.d.ts +4 -1
  18. package/dist/syncGroups/SyncGroupsHandler.js +6 -2
  19. package/dist/syncGroups/SyncGroupsTransaction.js +34 -21
  20. package/dist/tasks/TaskHandler.d.ts +2 -2
  21. package/dist/tests/testData/dummyProductForTest.d.ts +2 -2
  22. package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +1 -0
  23. package/dist/tests/testData/testDataCachedGetProduct.js +1 -0
  24. package/dist/tests/testData/testDataCachedPostValidate.js +1 -0
  25. package/dist/tests/testData/testDataProductAggregatedPrice.js +1 -0
  26. package/dist/tests/testData/testDataUpcharge.js +1 -0
  27. package/dist/utilitiesCatalogueData.d.ts +14 -9
  28. package/dist/utilitiesCatalogueData.js +7 -0
  29. package/dist/utilitiesCataloguePermission.d.ts +4 -4
  30. package/package.json +3 -3
@@ -44,22 +44,22 @@ export interface DtoCatalogueAPISession {
44
44
  features?: Array<string>;
45
45
  permissions?: Array<DtoCataloguePermission>;
46
46
  }
47
- /** CatalogueParams */
48
- export interface DtoCatalogueParams extends DtoCatalogueParamsWithoutCid {
49
- cid: number;
50
- }
51
- /** CatalogueParamsWithLang */
52
- export interface DtoCatalogueParamsWithLang extends DtoCatalogueParams {
53
- lang: string;
54
- }
55
- /** CatalogueParamsWithoutCid - To identify one catalogue the Portfolio ID CID is needed in addition to the parameters in this object. However as of now CID is not used in API calls and therefore this version without CID is needed. */
56
- export interface DtoCatalogueParamsWithoutCid {
47
+ /** CatalogueParams - To identify one catalogue the Portfolio ID CID is needed in addition to the parameters in this object. However as of now CID is not used in API calls and therefore this version without CID is needed. */
48
+ export interface DtoCatalogueParams {
57
49
  enterprise: string;
58
50
  prdCat: string;
59
51
  prdCatVersion: string;
60
52
  vendor: string;
61
53
  priceList: string;
62
54
  }
55
+ /** CatalogueParamsWithCid */
56
+ export interface DtoCatalogueParamsWithCid extends DtoCatalogueParams {
57
+ cid: number;
58
+ }
59
+ /** CatalogueParamsWithCidAndLang */
60
+ export interface DtoCatalogueParamsWithCidAndLang extends DtoCatalogueParamsWithCid {
61
+ lang: string;
62
+ }
63
63
  /** CataloguePermission */
64
64
  export interface DtoCataloguePermission {
65
65
  cid: number;
@@ -163,6 +163,16 @@ export interface DtoGetPriceListsParams {
163
163
  vendor: string;
164
164
  priceList: string;
165
165
  }
166
+ /** GetProductLegacyV2Params represents the URL parameters of getProductLegacyV2 */
167
+ export interface DtoGetProductLegacyV2Params {
168
+ lang: string;
169
+ enterprise: string;
170
+ prdCat: string;
171
+ prdCatVersion: string;
172
+ vendor: string;
173
+ priceList: string;
174
+ partNumber: string;
175
+ }
166
176
  /** GetProductParams represents the URL parameters of getProduct */
167
177
  export interface DtoGetProductParams {
168
178
  lang: string;
@@ -314,6 +324,16 @@ export interface DtoPostRenderParams {
314
324
  priceList: string;
315
325
  partNumber: string;
316
326
  }
327
+ /** PostValidateLegacyV1Params represents the URL parameters of postValidateLegacyV1 */
328
+ export interface DtoPostValidateLegacyV1Params {
329
+ lang: string;
330
+ enterprise: string;
331
+ prdCat: string;
332
+ prdCatVersion: string;
333
+ vendor: string;
334
+ priceList: string;
335
+ partNumber: string;
336
+ }
317
337
  /** PostValidateParams represents the URL parameters of postValidate */
318
338
  export interface DtoPostValidateParams {
319
339
  lang: string;
@@ -357,7 +377,7 @@ export interface DtoProductCatalogueInfo {
357
377
  export interface DtoProductConf {
358
378
  features?: Array<DtoFeatureConf>;
359
379
  additionalProducts?: Array<DtoAdditionalProductConf>;
360
- prodParams?: DtoProductParamsWithLang;
380
+ prodParams?: DtoProductParamsWithCidAndLang;
361
381
  }
362
382
  /** ProductData */
363
383
  export interface DtoProductData {
@@ -383,12 +403,12 @@ export interface DtoProductData {
383
403
  models?: Array<DtoModel>;
384
404
  partsData: DtoPartsData;
385
405
  }
386
- /** ProductParams */
387
- export interface DtoProductParams extends DtoCatalogueParams {
406
+ /** ProductParamsWithCid */
407
+ export interface DtoProductParamsWithCid extends DtoCatalogueParamsWithCid {
388
408
  partNumber: string;
389
409
  }
390
- /** ProductParamsWithLang */
391
- export interface DtoProductParamsWithLang extends DtoProductParams {
410
+ /** ProductParamsWithCidAndLang */
411
+ export interface DtoProductParamsWithCidAndLang extends DtoProductParamsWithCid {
392
412
  lang: string;
393
413
  }
394
414
  /** ProductRef */
@@ -489,11 +509,19 @@ export interface DtoTransform {
489
509
  rot: DtoOrientation;
490
510
  }
491
511
  /** ValidateRequest */
492
- export interface DtoValidateRequest {
512
+ export interface DtoValidateRequest extends DtoValidateRequestLegacyV1 {
513
+ knownFeatureCodes: Array<string>;
514
+ }
515
+ /** ValidateRequestLegacyV1 */
516
+ export interface DtoValidateRequestLegacyV1 {
493
517
  selOptions: Array<DtoSelectedOption>;
494
518
  }
495
519
  /** ValidateResponse */
496
- export interface DtoValidateResponse {
520
+ export interface DtoValidateResponse extends DtoValidateResponseLegacyV1 {
521
+ features: Array<DtoFeature>;
522
+ }
523
+ /** ValidateResponseLegacyV1 */
524
+ export interface DtoValidateResponseLegacyV1 {
497
525
  productData: DtoProductData;
498
526
  uuid: string;
499
527
  validated: boolean;
@@ -536,8 +564,10 @@ export declare class CatalogueAPI {
536
564
  getApplicationAreas(params: DtoGetApplicationAreasParams): Promise<DtoApplicationAreasResponse>;
537
565
  postExport(params: DtoPostExportParams, body: DtoExportRequest): Promise<DtoExportResponse>;
538
566
  getPriceLists(params: DtoGetPriceListsParams): Promise<DtoPriceListsResponse>;
567
+ getProductLegacyV2(params: DtoGetProductLegacyV2Params): Promise<DtoProductResponse>;
539
568
  getProduct(params: DtoGetProductParams): Promise<DtoProductResponse>;
540
569
  postRender(params: DtoPostRenderParams, body: DtoRenderRequest): Promise<DtoRenderResponse>;
570
+ postValidateLegacyV1(params: DtoPostValidateLegacyV1Params, body: DtoValidateRequestLegacyV1): Promise<DtoValidateResponseLegacyV1>;
541
571
  postValidate(params: DtoPostValidateParams, body: DtoValidateRequest): Promise<DtoValidateResponse>;
542
572
  getTocTree(params: DtoGetTocTreeParams): Promise<DtoTOCResponse>;
543
573
  getTocFlat(params: DtoGetTocFlatParams): Promise<DtoTOCResponse>;
@@ -9,10 +9,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  step((generator = generator.apply(thisArg, _arguments || [])).next());
10
10
  });
11
11
  };
12
- export const dtoExportFormatNames = ["glb", "gltf", "fbx", "dwg", "cmdrw", "cmfav", "cmsym"];
13
- export const dtoExportStatusStatusNames = ["pending", "running", "finished", "failed"];
12
+ export const dtoExportFormatNames = [
13
+ "glb",
14
+ "gltf",
15
+ "fbx",
16
+ "dwg",
17
+ "cmdrw",
18
+ "cmfav",
19
+ "cmsym",
20
+ ];
21
+ export const dtoExportStatusStatusNames = [
22
+ "pending",
23
+ "running",
24
+ "finished",
25
+ "failed",
26
+ ];
14
27
  export const dtoRenderFormatNames = ["jpg", "png"];
15
- export const dtoRenderStatusStatusNames = ["pending", "running", "finished", "failed"];
28
+ export const dtoRenderStatusStatusNames = [
29
+ "pending",
30
+ "running",
31
+ "finished",
32
+ "failed",
33
+ ];
16
34
  export const dtoSyncGroupMethodsNames = ["pull", "push", "twoWay"];
17
35
  export class DtoAPIError extends Error {
18
36
  }
@@ -31,7 +49,9 @@ export class CatalogueAPI {
31
49
  }
32
50
  }
33
51
  hasFeature(feature) {
34
- return this.auth !== undefined && this.auth.apiSession.features !== undefined && this.auth.apiSession.features.indexOf(feature) > -1;
52
+ return (this.auth !== undefined &&
53
+ this.auth.apiSession.features !== undefined &&
54
+ this.auth.apiSession.features.indexOf(feature) > -1);
35
55
  }
36
56
  fetch(url, options) {
37
57
  return __awaiter(this, void 0, void 0, function* () {
@@ -127,7 +147,7 @@ export class CatalogueAPI {
127
147
  return this.fetch(this.auth.endpoint + url, options);
128
148
  });
129
149
  }
130
- getProduct(params) {
150
+ getProductLegacyV2(params) {
131
151
  return __awaiter(this, void 0, void 0, function* () {
132
152
  if (this.auth === undefined) {
133
153
  throw new Error("missing auth");
@@ -143,6 +163,22 @@ export class CatalogueAPI {
143
163
  return this.fetch(this.auth.endpoint + url, options);
144
164
  });
145
165
  }
166
+ getProduct(params) {
167
+ return __awaiter(this, void 0, void 0, function* () {
168
+ if (this.auth === undefined) {
169
+ throw new Error("missing auth");
170
+ }
171
+ const url = `/v1/catalogue/${encodeURIComponent(params.lang)}/${encodeURIComponent(params.enterprise)}/${encodeURIComponent(params.prdCat)}/${encodeURIComponent(params.prdCatVersion)}/${encodeURIComponent(params.vendor)}/${encodeURIComponent(params.priceList)}/product-v3/${encodeURIComponent(params.partNumber)}`;
172
+ const options = {
173
+ method: "GET",
174
+ headers: { "X-API-Key": this.auth.secretToken || "" },
175
+ };
176
+ if (this._alternativeReferer) {
177
+ options.headers["Alternative-Referer"] = this._alternativeReferer;
178
+ }
179
+ return this.fetch(this.auth.endpoint + url, options);
180
+ });
181
+ }
146
182
  postRender(params, body) {
147
183
  return __awaiter(this, void 0, void 0, function* () {
148
184
  if (this.auth === undefined) {
@@ -160,7 +196,7 @@ export class CatalogueAPI {
160
196
  return this.fetch(this.auth.endpoint + url, options);
161
197
  });
162
198
  }
163
- postValidate(params, body) {
199
+ postValidateLegacyV1(params, body) {
164
200
  return __awaiter(this, void 0, void 0, function* () {
165
201
  if (this.auth === undefined) {
166
202
  throw new Error("missing auth");
@@ -177,6 +213,23 @@ export class CatalogueAPI {
177
213
  return this.fetch(this.auth.endpoint + url, options);
178
214
  });
179
215
  }
216
+ postValidate(params, body) {
217
+ return __awaiter(this, void 0, void 0, function* () {
218
+ if (this.auth === undefined) {
219
+ throw new Error("missing auth");
220
+ }
221
+ const url = `/v1/catalogue/${encodeURIComponent(params.lang)}/${encodeURIComponent(params.enterprise)}/${encodeURIComponent(params.prdCat)}/${encodeURIComponent(params.prdCatVersion)}/${encodeURIComponent(params.vendor)}/${encodeURIComponent(params.priceList)}/product/${encodeURIComponent(params.partNumber)}/validate-v2`;
222
+ const options = {
223
+ method: "POST",
224
+ headers: { "X-API-Key": this.auth.secretToken || "" },
225
+ body: JSON.stringify(body),
226
+ };
227
+ if (this._alternativeReferer) {
228
+ options.headers["Alternative-Referer"] = this._alternativeReferer;
229
+ }
230
+ return this.fetch(this.auth.endpoint + url, options);
231
+ });
232
+ }
180
233
  getTocTree(params) {
181
234
  return __awaiter(this, void 0, void 0, function* () {
182
235
  if (this.auth === undefined) {
@@ -263,8 +316,10 @@ export const DTO_OPERATION_ID_TO_DEBIT_GROUP = {
263
316
  getApplicationAreas: "base",
264
317
  postExport: "export",
265
318
  getPriceLists: "base",
319
+ getProductLegacyV2: "base",
266
320
  getProduct: "base",
267
321
  postRender: "render",
322
+ postValidateLegacyV1: "base",
268
323
  postValidate: "base",
269
324
  getTocTree: "base",
270
325
  getTocFlat: "base",
@@ -1,5 +1,5 @@
1
1
  import { AggregatedLoadingObservable, LengthUnit, Observable, SingleArgCallback } from "@configura/web-utilities";
2
- import { DtoAdditionalProductConfiguration, DtoAdditionalProductRef, DtoCatalogueParams, DtoMeasureParam, DtoMtrlApplication, DtoPrices, DtoProductConf, DtoProductParamsWithLang, DtoTransform } from "./CatalogueAPI.js";
2
+ import { DtoAdditionalProductConfiguration, DtoAdditionalProductRef, DtoCatalogueParamsWithCid, DtoMeasureParam, DtoMtrlApplication, DtoPrices, DtoProductConf, DtoProductParamsWithCidAndLang, DtoTransform } from "./CatalogueAPI.js";
3
3
  import { CfgMeasureDefinition } from "./CfgMeasure.js";
4
4
  import { _CfgFeatureInternal } from "./productConfiguration/CfgFeature.js";
5
5
  import { ProductConfigurationBubbleMode } from "./productConfiguration/CfgOption.js";
@@ -72,7 +72,7 @@ export declare type CfgPrice = {
72
72
  */
73
73
  export declare class _CfgProductInternal {
74
74
  readonly _productLoaderRaw: ProductLoader;
75
- readonly prodParams: DtoProductParamsWithLang;
75
+ readonly prodParams: DtoProductParamsWithCidAndLang;
76
76
  readonly settings: CfgProductSettings;
77
77
  readonly uuid: string;
78
78
  private readonly _rawUnit;
@@ -81,7 +81,8 @@ export declare class _CfgProductInternal {
81
81
  readonly parent: _CfgProductInternal | undefined;
82
82
  private _additionalProductRef;
83
83
  private readonly _syncGroupHandler;
84
- static make: (productLoaderRaw: ProductLoader, productLoaderForGroupedLoad: ProductLoader | undefined, prodParams: DtoProductParamsWithLang, settings: CfgProductSettings, optional: boolean, loadingObservable: AggregatedLoadingObservable, parent: _CfgProductInternal | undefined, root: _CfgProductInternal | undefined, additionalProductRef: DtoAdditionalProductRef | undefined) => Promise<_CfgProductInternal>;
84
+ static make: (productLoaderRaw: ProductLoader, productLoaderForGroupedLoad: ProductLoader | undefined, prodParams: DtoProductParamsWithCidAndLang, settings: CfgProductSettings, optional: boolean, loadingObservable: AggregatedLoadingObservable, parent: _CfgProductInternal | undefined, root: _CfgProductInternal | undefined, additionalProductRef: DtoAdditionalProductRef | undefined) => Promise<_CfgProductInternal>;
85
+ _initialClone: _CfgProductInternal | undefined;
85
86
  private constructor();
86
87
  readonly root: _CfgProductInternal;
87
88
  private _destroyed;
@@ -92,9 +93,19 @@ export declare class _CfgProductInternal {
92
93
  readonly changeObservable: Observable<CfgProductChangeNotification>;
93
94
  get selected(): boolean;
94
95
  readonly isAdditionalProduct: boolean;
96
+ /**
97
+ * Please note that cloning an additional product will make the clone believe is is
98
+ * an additional product, even if it has no parent and root.
99
+ * Providing the parent and root of what you clone as arguments is unwise as it will
100
+ * make changes you do on the clone be propagated up to the original non-clone root product.
101
+ */
95
102
  clone(parent?: _CfgProductInternal, root?: _CfgProductInternal): Promise<_CfgProductInternal>;
96
103
  /** Mark this and its descendants as destroyed and remove all listeners */
97
104
  destroy: () => void;
105
+ /**
106
+ * Reset will reset the product to its initial state
107
+ */
108
+ reset: () => Promise<void>;
98
109
  /**
99
110
  * Internal use. Used when this product is an additional product, and
100
111
  * changing a parent product has made the settings for this product
@@ -173,7 +184,7 @@ export declare class _CfgProductInternal {
173
184
  }
174
185
  export declare class CfgProduct {
175
186
  readonly _internal: _CfgProductInternal;
176
- static make(productLoader: ProductLoader, prodParams: DtoProductParamsWithLang, settings?: Partial<CfgProductSettings>): Promise<CfgProduct>;
187
+ static make(productLoader: ProductLoader, prodParams: DtoProductParamsWithCidAndLang, settings?: Partial<CfgProductSettings>): Promise<CfgProduct>;
177
188
  /**
178
189
  * Makes an object wrapping the passed object. This is not a clone method, it is a method to
179
190
  * make a new outer reference. Like a shallow copy. We use this to help frameworks that are
@@ -200,9 +211,9 @@ export declare class CfgProduct {
200
211
  * It will be unique amongst child products, but not globally unique.
201
212
  */
202
213
  get refKey(): string | undefined;
203
- get prodParams(): DtoProductParamsWithLang;
214
+ get prodParams(): DtoProductParamsWithCidAndLang;
204
215
  get lang(): string;
205
- get catId(): DtoCatalogueParams;
216
+ get catId(): DtoCatalogueParamsWithCid;
206
217
  get partNumber(): string;
207
218
  get isAdditionalProduct(): boolean;
208
219
  /** Only used when this product is an additional product. Root products are never optional. */
@@ -15,7 +15,7 @@ import { CfgProductConfiguration } from "./productConfiguration/CfgProductConfig
15
15
  import { collectAdditionalProductRefs } from "./productConfiguration/utilitiesProductConfiguration.js";
16
16
  import { wrapWithCache } from "./productLoader.js";
17
17
  import { SyncGroupsHandler } from "./syncGroups/SyncGroupsHandler.js";
18
- import { comparePricesObjects, correctDefaultsOnCatalogueParams, isSameCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
18
+ import { compareCfgProductData, comparePricesObjects, correctDefaultsOnCatalogueParams, isSameCatalogueParams, isSameProductRef, makeProductKey, } from "./utilitiesCatalogueData.js";
19
19
  function completeSettings(incompleteSettings) {
20
20
  var _a;
21
21
  return {
@@ -52,7 +52,7 @@ function isDescriptionMatch(l, r) {
52
52
  * the class that should be used and interacted with.
53
53
  */
54
54
  export class _CfgProductInternal {
55
- constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, allRawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
55
+ constructor(initSuccess, initFail, _productLoaderRaw, prodParams, settings, optional, selected, rootFeatureRefs, rawFeatures, uuid, _rawUnit, _rawProductData, apiSelection, loadingObservable, parent, root, _additionalProductRef, _syncGroupHandler) {
56
56
  var _a;
57
57
  this._productLoaderRaw = _productLoaderRaw;
58
58
  this.prodParams = prodParams;
@@ -77,6 +77,14 @@ export class _CfgProductInternal {
77
77
  additionalProduct.destroy();
78
78
  }
79
79
  };
80
+ /**
81
+ * Reset will reset the product to its initial state
82
+ */
83
+ this.reset = () => __awaiter(this, void 0, void 0, function* () {
84
+ if (this._initialClone !== undefined) {
85
+ yield this.copyFrom(this._initialClone, true);
86
+ }
87
+ });
80
88
  this._notifyAllOfChange = (bubbleMode, committed) => __awaiter(this, void 0, void 0, function* () {
81
89
  if (bubbleMode === CfgProductBubbleMode.Stop) {
82
90
  return;
@@ -183,9 +191,16 @@ export class _CfgProductInternal {
183
191
  productLoaderForGroupedLoad || wrapWithCache(this._productLoaderRaw);
184
192
  let change = false;
185
193
  if (sourceProduct !== undefined) {
186
- this._rawProductData = sourceProduct.rawProductData;
187
- this.configuration._internal.populateFeatures(sourceProduct.configuration.rootFeatureRefs);
188
- change = true; // We can not know if this is an actual change, so we assume it is
194
+ if (!compareCfgProductData(this._rawProductData, sourceProduct.rawProductData)) {
195
+ this._rawProductData = sourceProduct.rawProductData;
196
+ change = true;
197
+ }
198
+ if (this.configuration._internal.addRawFeatures(sourceProduct.configuration.rawFeatures, false)) {
199
+ change = true;
200
+ }
201
+ if (this.configuration._internal.populateFeatures(sourceProduct.configuration.rootFeatureRefs)) {
202
+ change = true;
203
+ }
189
204
  }
190
205
  const configurationChange = yield this.configuration._internal.setApiSelection(s.selOptions, false);
191
206
  if (configurationChange) {
@@ -314,7 +329,10 @@ export class _CfgProductInternal {
314
329
  const token = this.loadingObservable.startChildLoading();
315
330
  this._revalidateInProgressToken = token;
316
331
  try {
317
- const response = yield productLoader.postValidate(correctDefaultsOnCatalogueParams(this.prodParams), { selOptions: configuration._internal.getApiSelection() });
332
+ const response = yield productLoader.postValidate(correctDefaultsOnCatalogueParams(this.prodParams), {
333
+ selOptions: configuration._internal.getApiSelection(),
334
+ knownFeatureCodes: configuration.rawFeatures.map((f) => f.code),
335
+ });
318
336
  // The revalidateInProgressToken is used to know if some other revalidate
319
337
  // call has happened after this call, thereby making this call obsolete.
320
338
  // This is a bit crude in that it does not actually cancel previous validate
@@ -333,9 +351,10 @@ export class _CfgProductInternal {
333
351
  if (this._destroyed) {
334
352
  return false;
335
353
  }
336
- const { productData, rootFeatureRefs } = response;
354
+ const { productData, rootFeatureRefs, features } = response;
337
355
  const pricesUpdated = !comparePricesObjects(this.prices, productData.partsData.prices);
338
356
  this._rawProductData = productData;
357
+ configuration._internal.addRawFeatures(features, true);
339
358
  if (rootFeatureRefs !== undefined) {
340
359
  configuration._internal.populateFeatures(rootFeatureRefs);
341
360
  }
@@ -425,19 +444,25 @@ export class _CfgProductInternal {
425
444
  this.root = root !== null && root !== void 0 ? root : this;
426
445
  this.key = makeProductKey(Object.assign(Object.assign({}, prodParams), { partNumber: (_a = _additionalProductRef === null || _additionalProductRef === void 0 ? void 0 : _additionalProductRef.refKey) !== null && _a !== void 0 ? _a : prodParams.partNumber }));
427
446
  this._selected = optional ? selected : undefined;
428
- this.isAdditionalProduct = parent !== undefined;
429
- this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, allRawFeatures, apiSelection, this, this.root);
447
+ this.isAdditionalProduct = _additionalProductRef !== undefined;
448
+ this._configuration = CfgProductConfiguration.make(initSuccess, initFail, rootFeatureRefs, rawFeatures, apiSelection, this, this.root);
430
449
  }
431
450
  get selected() {
432
451
  return this._selected !== false;
433
452
  }
453
+ /**
454
+ * Please note that cloning an additional product will make the clone believe is is
455
+ * an additional product, even if it has no parent and root.
456
+ * Providing the parent and root of what you clone as arguments is unwise as it will
457
+ * make changes you do on the clone be propagated up to the original non-clone root product.
458
+ */
434
459
  clone(parent, root) {
435
460
  return __awaiter(this, void 0, void 0, function* () {
436
461
  const product = yield new Promise((initSuccess, initFail) => {
437
462
  var _a;
438
463
  const p = new _CfgProductInternal(() => {
439
464
  initSuccess(p);
440
- }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.allRawFeatures, this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
465
+ }, initFail, this._productLoaderRaw, this.prodParams, this.settings, this.optional, this.selected, this._configuration.rootFeatureRefs, this._configuration.rawFeatures, this.uuid, this._rawUnit, this._rawProductData, this.configuration._internal.getApiSelection(), new AggregatedLoadingObservable(), parent, root, this._additionalProductRef, (_a = this._syncGroupHandler) === null || _a === void 0 ? void 0 : _a.clone());
441
466
  });
442
467
  for (const additionalProduct of this.additionalProducts) {
443
468
  product.additionalProducts.push(CfgProduct._makeNewRefFrom(yield additionalProduct._internal.clone(product, root || product)));
@@ -543,7 +568,19 @@ export class _CfgProductInternal {
543
568
  if (this._selected === v) {
544
569
  return false;
545
570
  }
571
+ // Vitally important that this happens before the call to reset. An optional
572
+ // additional product is always deselected at start, so this way the reset won't cause
573
+ // infinite loops
546
574
  this._selected = v;
575
+ if (!v) {
576
+ yield this.reset();
577
+ }
578
+ if (v) {
579
+ const syncGroupHandler = this.syncGroupHandler;
580
+ if (syncGroupHandler !== undefined) {
581
+ yield syncGroupHandler.init(this.root, wrapWithCache(this._productLoaderRaw));
582
+ }
583
+ }
547
584
  yield this._notifyAllOfChange(bubbleMode, true);
548
585
  return true;
549
586
  });
@@ -607,18 +644,22 @@ prodParams, settings, optional, loadingObservable, parent, root, additionalProdu
607
644
  : undefined;
608
645
  try {
609
646
  const productResponse = yield productLoaderForGroupedLoad.getProduct(correctDefaultsOnCatalogueParams(prodParams));
610
- const { productData, rootFeatureRefs, features: allRawFeatures, uuid, unit, } = productResponse;
647
+ const { productData, rootFeatureRefs, features: rawFeatures, uuid, unit, } = productResponse;
611
648
  const product = yield new Promise((initSuccess, initFail) => {
649
+ var _a;
612
650
  const p = new _CfgProductInternal(() => {
613
651
  // We absolutely do not want anyone to assign to this._configuration. So we want that field private.
614
652
  // But we can not set the api selection synchronously. And the product configuration needs "this". So we use this callback.
615
653
  // Feel free to find a nicer more readable solution :)
616
654
  initSuccess(p);
617
- }, initFail, productLoaderRaw, prodParams, settings, optional, !optional, rootFeatureRefs, allRawFeatures, uuid, unit, productData, productData.partsData.selOptions || [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
655
+ }, initFail, productLoaderRaw, prodParams, settings, optional, !optional, rootFeatureRefs, rawFeatures, uuid, unit, productData, (_a = productData.partsData.selOptions) !== null && _a !== void 0 ? _a : [], loadingObservable, parent, root, additionalProductRef, syncGroupHandler);
618
656
  });
619
657
  yield product._syncAndLoadAdditionalProducts(productLoaderForGroupedLoad);
620
- // Product is guaranteed to be root
621
- yield (syncGroupHandler === null || syncGroupHandler === void 0 ? void 0 : syncGroupHandler.init(product, productLoaderForGroupedLoad));
658
+ product._initialClone = yield product.clone();
659
+ if (syncGroupHandler !== undefined) {
660
+ // As syncGroupHandler is only set for root product we know that we will init with root
661
+ yield syncGroupHandler.init(product, productLoaderForGroupedLoad);
662
+ }
622
663
  return product;
623
664
  }
624
665
  catch (e) {
@@ -1,4 +1,4 @@
1
- import { DtoCatalogueParamsWithLang, DtoProductParamsWithLang } from "./CatalogueAPI";
1
+ import { DtoCatalogueParamsWithCidAndLang, DtoProductParamsWithCidAndLang } from "./CatalogueAPI";
2
2
  /**
3
3
  * These methods aims to provide a default suggested way of building
4
4
  * URLs to Products and Catalogues. By using consistent URL:s copy-paste
@@ -14,7 +14,7 @@ export declare class CfgReferencePathHelper {
14
14
  * @param catParams What catalogue to generate URL for.
15
15
  * @returns An URL to a catalogue
16
16
  */
17
- static getCataloguePath: (browsingRootUrl: string, catParams: DtoCatalogueParamsWithLang) => string;
17
+ static getCataloguePath: (browsingRootUrl: string, catParams: DtoCatalogueParamsWithCidAndLang) => string;
18
18
  /**
19
19
  * Use to generate URLs in our reference format. This is the format Configura uses in our integrations.
20
20
  * @param browsingRootUrl The URL where Stage browsing begins
@@ -22,6 +22,6 @@ export declare class CfgReferencePathHelper {
22
22
  * @param separator Optional, defaults to "product", but can be changed to indicate another function.
23
23
  * @returns An URL to a product
24
24
  */
25
- static getProductPath: (browsingRootUrl: string, productParams: DtoProductParamsWithLang, separator?: string) => string;
25
+ static getProductPath: (browsingRootUrl: string, productParams: DtoProductParamsWithCidAndLang, separator?: string) => string;
26
26
  }
27
27
  //# sourceMappingURL=CfgReferencePathHelper.d.ts.map
@@ -32,13 +32,13 @@ export declare type FeatureChangeNotification = {
32
32
  */
33
33
  export declare class _CfgFeatureInternal {
34
34
  readonly rawFeature: DtoFeature;
35
- private readonly allRawFeatures;
36
- readonly key: string;
35
+ private readonly rawFeatures;
36
+ private _key;
37
37
  readonly parent: _CfgProductConfigurationInternal | _CfgOptionInternal;
38
38
  readonly parentConfiguration: _CfgProductConfigurationInternal;
39
39
  readonly parentProduct: _CfgProductInternal;
40
40
  readonly rootProduct: _CfgProductInternal;
41
- constructor(rawFeature: DtoFeature, allRawFeatures: DtoFeature[], key: string, // Unique amongst siblings
41
+ constructor(rawFeature: DtoFeature, rawFeatures: DtoFeature[], _key: string, // Unique amongst siblings
42
42
  parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
43
43
  readonly selectionType: SelectionType;
44
44
  private _options;
@@ -48,6 +48,8 @@ export declare class _CfgFeatureInternal {
48
48
  readonly changeObservable: Observable<FeatureChangeNotification>;
49
49
  get code(): string;
50
50
  get groupCode(): string | undefined;
51
+ get key(): string;
52
+ set key(k: string);
51
53
  get isUseNumericValue(): boolean;
52
54
  get numericValue(): number | undefined;
53
55
  setNumericValue: (val: number) => Promise<boolean>;
@@ -128,7 +130,7 @@ export declare class _CfgFeatureInternal {
128
130
  }
129
131
  export declare class CfgFeature {
130
132
  readonly _internal: _CfgFeatureInternal;
131
- static make(rawFeature: DtoFeature, allRawFeatures: DtoFeature[], key: string, parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgFeature;
133
+ static make(rawFeature: DtoFeature, rawFeatures: DtoFeature[], key: string, parent: _CfgProductConfigurationInternal | _CfgOptionInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgFeature;
132
134
  /**
133
135
  * Makes an object wrapping the passed object. This is not a clone method,
134
136
  * it is a method to make a new outer reference. Like a shallow copy.
@@ -62,11 +62,11 @@ function doFreshRefOption(options, optionInternal, committed, beforeNotify) {
62
62
  * should be used and interacted with.
63
63
  */
64
64
  export class _CfgFeatureInternal {
65
- constructor(rawFeature, allRawFeatures, key, // Unique amongst siblings
65
+ constructor(rawFeature, rawFeatures, _key, // Unique amongst siblings
66
66
  parent, parentConfiguration, parentProduct, rootProduct) {
67
67
  this.rawFeature = rawFeature;
68
- this.allRawFeatures = allRawFeatures;
69
- this.key = key;
68
+ this.rawFeatures = rawFeatures;
69
+ this._key = _key;
70
70
  this.parent = parent;
71
71
  this.parentConfiguration = parentConfiguration;
72
72
  this.parentProduct = parentProduct;
@@ -413,6 +413,12 @@ export class _CfgFeatureInternal {
413
413
  get groupCode() {
414
414
  return this.rawFeature.groupCode;
415
415
  }
416
+ get key() {
417
+ return this._key;
418
+ }
419
+ set key(k) {
420
+ this._key = k;
421
+ }
416
422
  get isUseNumericValue() {
417
423
  return this.rawFeature.numericOrder;
418
424
  }
@@ -518,7 +524,7 @@ export class _CfgFeatureInternal {
518
524
  const hasDuplicateDescription = someMatch(this.rawFeature.options, (l, r) => {
519
525
  return l.description.toLowerCase() === r.description.toLowerCase();
520
526
  });
521
- this._options = this.rawFeature.options.map((o) => CfgOption.make(o, this.allRawFeatures, hasDuplicateDescription, this, this.parentConfiguration, this.parentProduct, this.rootProduct));
527
+ this._options = this.rawFeature.options.map((o) => CfgOption.make(o, this.rawFeatures, hasDuplicateDescription, this, this.parentConfiguration, this.parentProduct, this.rootProduct));
522
528
  }
523
529
  return this._options;
524
530
  }
@@ -577,8 +583,8 @@ export class CfgFeature {
577
583
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
578
584
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
579
585
  }
580
- static make(rawFeature, allRawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct) {
581
- return new this(new _CfgFeatureInternal(rawFeature, allRawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
586
+ static make(rawFeature, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct) {
587
+ return new this(new _CfgFeatureInternal(rawFeature, rawFeatures, key, parent, parentConfiguration, parentProduct, rootProduct));
582
588
  }
583
589
  /**
584
590
  * Makes an object wrapping the passed object. This is not a clone method,
@@ -597,6 +603,7 @@ export class CfgFeature {
597
603
  get selectionType() {
598
604
  return this._internal.selectionType;
599
605
  }
606
+ // Unique amongst siblings. Can change. Only use for presentation layer i.e. React.
600
607
  get key() {
601
608
  return this._internal.key;
602
609
  }
@@ -60,12 +60,12 @@ export declare enum ProductConfigurationBubbleMode {
60
60
  */
61
61
  export declare class _CfgOptionInternal {
62
62
  readonly rawOption: DtoOption;
63
- private readonly allRawFeatures;
63
+ private readonly rawFeatures;
64
64
  readonly parent: _CfgFeatureInternal;
65
65
  readonly parentConfiguration: _CfgProductConfigurationInternal;
66
66
  readonly parentProduct: _CfgProductInternal;
67
67
  readonly rootProduct: _CfgProductInternal;
68
- constructor(rawOption: DtoOption, allRawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
68
+ constructor(rawOption: DtoOption, rawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal);
69
69
  private _features;
70
70
  private _mtrlApplications;
71
71
  readonly key: string;
@@ -99,7 +99,7 @@ export declare class _CfgOptionInternal {
99
99
  }
100
100
  export declare class CfgOption {
101
101
  readonly _internal: _CfgOptionInternal;
102
- static make(rawOption: DtoOption, allRawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgOption;
102
+ static make(rawOption: DtoOption, rawFeatures: DtoFeature[], siblingHasDuplicateDescription: boolean, parent: _CfgFeatureInternal, parentConfiguration: _CfgProductConfigurationInternal, parentProduct: _CfgProductInternal, rootProduct: _CfgProductInternal): CfgOption;
103
103
  /**
104
104
  * Makes an object wrapping the passed object. This is not a clone method,
105
105
  * it is a method to make a new outer reference. Like a shallow copy.
@@ -80,9 +80,9 @@ function doesChildrenShareOptionsCode(features) {
80
80
  * the class that should be used and interacted with.
81
81
  */
82
82
  export class _CfgOptionInternal {
83
- constructor(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
83
+ constructor(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
84
84
  this.rawOption = rawOption;
85
- this.allRawFeatures = allRawFeatures;
85
+ this.rawFeatures = rawFeatures;
86
86
  this.parent = parent;
87
87
  this.parentConfiguration = parentConfiguration;
88
88
  this.parentProduct = parentProduct;
@@ -310,7 +310,7 @@ export class _CfgOptionInternal {
310
310
  get features() {
311
311
  if (this._features === undefined) {
312
312
  const allRefs = this.rawOption.featureRefs || [];
313
- const features = syncCfgFeatures(allRefs, [], this.allRawFeatures, this, this.parentConfiguration, this.parentProduct, this.rootProduct);
313
+ const features = syncCfgFeatures(allRefs, [], this.rawFeatures, this, this.parentConfiguration, this.parentProduct, this.rootProduct);
314
314
  if (doesChildrenShareOptionsCode(features)) {
315
315
  throw new Error("Stage does not yet properly support Options that has multiple sub-features with overlapping option codes.");
316
316
  }
@@ -349,8 +349,8 @@ export class CfgOption {
349
349
  this.listenForChange = (l) => this._internal.changeObservable.listen(l);
350
350
  this.stopListenForChange = (l) => this._internal.changeObservable.stopListen(l);
351
351
  }
352
- static make(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
353
- return new this(new _CfgOptionInternal(rawOption, allRawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct));
352
+ static make(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct) {
353
+ return new this(new _CfgOptionInternal(rawOption, rawFeatures, siblingHasDuplicateDescription, parent, parentConfiguration, parentProduct, rootProduct));
354
354
  }
355
355
  /**
356
356
  * Makes an object wrapping the passed object. This is not a clone method,