@configura/web-api 1.6.0-iotest.2 → 1.6.1-alpha.1
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/dist/CfgProduct.d.ts +29 -10
- package/dist/CfgProduct.js +82 -47
- package/dist/index.d.ts +2 -4
- package/dist/index.js +2 -4
- package/dist/productConfiguration/CfgFeature.d.ts +2 -1
- package/dist/productConfiguration/CfgFeature.js +27 -8
- package/dist/productConfiguration/CfgOption.d.ts +21 -8
- package/dist/productConfiguration/CfgOption.js +26 -18
- package/dist/productConfiguration/CfgProductConfiguration.d.ts +1 -2
- package/dist/productConfiguration/CfgProductConfiguration.js +9 -8
- package/dist/syncGroups/SyncGroupsApplier.d.ts +20 -0
- package/dist/syncGroups/SyncGroupsApplier.js +520 -0
- package/dist/syncGroups/SyncGroupsApplyMode.d.ts +21 -0
- package/dist/syncGroups/SyncGroupsApplyMode.js +21 -0
- package/dist/syncGroups/SyncGroupsHandler.d.ts +31 -0
- package/dist/syncGroups/SyncGroupsHandler.js +71 -0
- package/dist/syncGroups/SyncGroupsPathHelper.d.ts +27 -0
- package/dist/syncGroups/SyncGroupsPathHelper.js +89 -0
- package/dist/syncGroups/SyncGroupsState.d.ts +20 -0
- package/dist/syncGroups/SyncGroupsState.js +108 -0
- package/dist/syncGroups/SyncGroupsTransaction.d.ts +51 -0
- package/dist/syncGroups/SyncGroupsTransaction.js +100 -0
- package/dist/tests/testData/testDataAdditionalProductInAdditionalProductInProductForTest.js +24 -95
- package/dist/tests/testData/testDataCachedGetProduct.js +8 -19
- package/dist/tests/testData/testDataOptions.d.ts +13 -0
- package/dist/tests/testData/testDataOptions.js +60 -0
- package/dist/tests/testData/testDataProductAggregatedPrice.js +12 -23
- package/dist/tests/testData/testDataUpcharge.js +16 -48
- package/dist/utilitiesCatalogueData.d.ts +7 -1
- package/dist/utilitiesCatalogueData.js +105 -4
- package/package.json +3 -3
- package/dist/io/CfgHistoryManager.d.ts +0 -30
- package/dist/io/CfgHistoryManager.js +0 -62
- package/dist/io/CfgHistoryToProdConfConnector.d.ts +0 -10
- package/dist/io/CfgHistoryToProdConfConnector.js +0 -20
- package/dist/io/CfgIOManager.d.ts +0 -29
- package/dist/io/CfgIOManager.js +0 -89
- package/dist/io/CfgIOProdConfConnector.d.ts +0 -33
- package/dist/io/CfgIOProdConfConnector.js +0 -100
- package/dist/io/CfgWindowMessageManager.d.ts +0 -13
- package/dist/io/CfgWindowMessageManager.js +0 -28
- package/dist/io/CfgWindowMessageToProdConfConnector.d.ts +0 -13
- package/dist/io/CfgWindowMessageToProdConfConnector.js +0 -17
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { _CfgProductInternal } from "../CfgProduct.js";
|
|
2
|
+
import { _CfgFeatureInternal } from "../productConfiguration/CfgFeature.js";
|
|
3
|
+
import { _CfgOptionInternal } from "../productConfiguration/CfgOption.js";
|
|
4
|
+
import { _CfgProductConfigurationInternal } from "../productConfiguration/CfgProductConfiguration.js";
|
|
5
|
+
export declare type CfgPathSegment = string;
|
|
6
|
+
/**
|
|
7
|
+
* Represents the path to a node in the configuration tree.
|
|
8
|
+
*
|
|
9
|
+
* The format consists of a number of CfgPathSegments, each of which is currently a string. The
|
|
10
|
+
* exact meaning of the strings vary depending on where they are located in the path.
|
|
11
|
+
*
|
|
12
|
+
* @warning
|
|
13
|
+
* The format is strictly internal and can change in later versions of the SDK.
|
|
14
|
+
* Data stored in a CfgPath should be thus be considered transient and never stored or transmitted.
|
|
15
|
+
*/
|
|
16
|
+
export declare type CfgPath = CfgPathSegment[];
|
|
17
|
+
declare type PathItemType = _CfgProductInternal | _CfgProductConfigurationInternal | _CfgFeatureInternal | _CfgOptionInternal;
|
|
18
|
+
export declare class SyncGroupsPathHelper {
|
|
19
|
+
static getPath(item: PathItemType): CfgPath;
|
|
20
|
+
static getFromPath(path: CfgPath, root: PathItemType): PathItemType;
|
|
21
|
+
static getProductFromPath(path: CfgPath, item: _CfgProductInternal): _CfgProductInternal;
|
|
22
|
+
static getProductConfigurationFromPath(path: CfgPath, item: _CfgProductInternal): _CfgProductConfigurationInternal;
|
|
23
|
+
static getFeatureFromPath(path: CfgPath, item: PathItemType): _CfgFeatureInternal;
|
|
24
|
+
static getOptionFromPath(path: CfgPath, item: PathItemType): _CfgOptionInternal;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=SyncGroupsPathHelper.d.ts.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { assert, assertDefined } from "@configura/web-utilities";
|
|
2
|
+
import { _CfgProductInternal } from "../CfgProduct.js";
|
|
3
|
+
import { _CfgFeatureInternal } from "../productConfiguration/CfgFeature.js";
|
|
4
|
+
import { _CfgOptionInternal } from "../productConfiguration/CfgOption.js";
|
|
5
|
+
import { _CfgProductConfigurationInternal } from "../productConfiguration/CfgProductConfiguration.js";
|
|
6
|
+
export class SyncGroupsPathHelper {
|
|
7
|
+
static getPath(item) {
|
|
8
|
+
if (item instanceof _CfgProductInternal) {
|
|
9
|
+
const parent = item.parent;
|
|
10
|
+
const refKey = item.refKey;
|
|
11
|
+
if (parent === undefined || refKey === undefined) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
return [...this.getPath(parent), "p", refKey];
|
|
15
|
+
}
|
|
16
|
+
if (item instanceof _CfgProductConfigurationInternal) {
|
|
17
|
+
return [...this.getPath(item.parentProduct), "c"];
|
|
18
|
+
}
|
|
19
|
+
if (item instanceof _CfgFeatureInternal) {
|
|
20
|
+
return [...this.getPath(item.parent), item.code];
|
|
21
|
+
}
|
|
22
|
+
if (item instanceof _CfgOptionInternal) {
|
|
23
|
+
return [...this.getPath(item.parent), item.code];
|
|
24
|
+
}
|
|
25
|
+
throw new Error("This should not happen");
|
|
26
|
+
}
|
|
27
|
+
static getFromPath(path, root) {
|
|
28
|
+
path = path.slice();
|
|
29
|
+
let item = root;
|
|
30
|
+
while (path.length > 0) {
|
|
31
|
+
const segment = path.shift();
|
|
32
|
+
if (item instanceof _CfgProductInternal) {
|
|
33
|
+
switch (segment) {
|
|
34
|
+
case "p":
|
|
35
|
+
const refKey = path.shift();
|
|
36
|
+
const additional = item.additionalProducts.find((p) => p.refKey === refKey);
|
|
37
|
+
assertDefined(additional, `Additional product not found "p, ${refKey}, ${path.join(", ")}"`);
|
|
38
|
+
item = additional._internal;
|
|
39
|
+
break;
|
|
40
|
+
case "c":
|
|
41
|
+
assert(item instanceof _CfgProductInternal, "Was not product");
|
|
42
|
+
item = item.configuration._internal;
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
throw new Error(`Unexpected path segment ${segment}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (item instanceof _CfgProductConfigurationInternal) {
|
|
49
|
+
const feature = item.features.find((f) => f.code === segment);
|
|
50
|
+
assertDefined(feature, `Feature not found ${segment}, ${path.join(", ")}`);
|
|
51
|
+
item = feature._internal;
|
|
52
|
+
}
|
|
53
|
+
else if (item instanceof _CfgFeatureInternal) {
|
|
54
|
+
const option = item.options.find((o) => o.code === segment);
|
|
55
|
+
assertDefined(option, `Option not found ${segment}, ${path.join(", ")}`);
|
|
56
|
+
item = option._internal;
|
|
57
|
+
}
|
|
58
|
+
else if (item instanceof _CfgOptionInternal) {
|
|
59
|
+
const feature = item.features.find((o) => o.code === segment);
|
|
60
|
+
assertDefined(feature, `Feature not found ${segment}, ${path.join(", ")}`);
|
|
61
|
+
item = feature._internal;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
throw new Error("This should not happen (unexpected type)");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return item;
|
|
68
|
+
}
|
|
69
|
+
static getProductFromPath(path, item) {
|
|
70
|
+
const p = this.getFromPath(path, item);
|
|
71
|
+
assert(p instanceof _CfgProductInternal, `Path did not lead to a Product`);
|
|
72
|
+
return p;
|
|
73
|
+
}
|
|
74
|
+
static getProductConfigurationFromPath(path, item) {
|
|
75
|
+
const c = this.getFromPath(path, item);
|
|
76
|
+
assert(c instanceof _CfgProductConfigurationInternal, `Path did not lead to a ProductConfiguration"`);
|
|
77
|
+
return c;
|
|
78
|
+
}
|
|
79
|
+
static getFeatureFromPath(path, item) {
|
|
80
|
+
const f = this.getFromPath(path, item);
|
|
81
|
+
assert(f instanceof _CfgFeatureInternal, `Path did not lead to a Feature`);
|
|
82
|
+
return f;
|
|
83
|
+
}
|
|
84
|
+
static getOptionFromPath(path, item) {
|
|
85
|
+
const o = this.getFromPath(path, item);
|
|
86
|
+
assert(o instanceof _CfgOptionInternal, `Path did not lead to a Option`);
|
|
87
|
+
return o;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { OptionCode, SyncCode } from "./SyncGroupsHandler.js";
|
|
2
|
+
/**
|
|
3
|
+
* Is used to keep track of the current value of the SyncGroups. Is fully separated between
|
|
4
|
+
* SelectOne and SelectMany as Features of the two types are synced separately.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SyncGroupsState {
|
|
7
|
+
readonly _selectOne: Map<SyncCode, OptionCode>;
|
|
8
|
+
readonly _selectMany: Map<SyncCode, Map<OptionCode, boolean>>;
|
|
9
|
+
clone(): SyncGroupsState;
|
|
10
|
+
/**
|
|
11
|
+
* Replaces the current state
|
|
12
|
+
*/
|
|
13
|
+
setFrom(other: SyncGroupsState): void;
|
|
14
|
+
setForSelectOne(syncCode: SyncCode, optionCode: OptionCode): void;
|
|
15
|
+
setForSelectMany(syncCode: SyncCode, optionCode: OptionCode, selected: boolean): void;
|
|
16
|
+
getForSelectOne(syncCode: SyncCode): OptionCode | undefined;
|
|
17
|
+
getForSelectMany(syncCode: SyncCode, optionCode: OptionCode): boolean | undefined;
|
|
18
|
+
logDebug(group?: string, code?: string, selected?: boolean): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=SyncGroupsState.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is used to keep track of the current value of the SyncGroups. Is fully separated between
|
|
3
|
+
* SelectOne and SelectMany as Features of the two types are synced separately.
|
|
4
|
+
*/
|
|
5
|
+
export class SyncGroupsState {
|
|
6
|
+
constructor() {
|
|
7
|
+
this._selectOne = new Map();
|
|
8
|
+
this._selectMany = new Map();
|
|
9
|
+
}
|
|
10
|
+
clone() {
|
|
11
|
+
const result = new SyncGroupsState();
|
|
12
|
+
result.setFrom(this);
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Replaces the current state
|
|
17
|
+
*/
|
|
18
|
+
setFrom(other) {
|
|
19
|
+
this._selectOne.clear();
|
|
20
|
+
this._selectMany.clear();
|
|
21
|
+
for (const [k, v] of other._selectOne) {
|
|
22
|
+
this._selectOne.set(k, v);
|
|
23
|
+
}
|
|
24
|
+
for (const [sourceSyncCode, sourceOptionToSelected] of other._selectMany) {
|
|
25
|
+
const targetOptionToSelected = new Map();
|
|
26
|
+
for (const [sourceOptionCode, sourceIsSelected] of sourceOptionToSelected) {
|
|
27
|
+
targetOptionToSelected.set(sourceOptionCode, sourceIsSelected);
|
|
28
|
+
}
|
|
29
|
+
this._selectMany.set(sourceSyncCode, targetOptionToSelected);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
setForSelectOne(syncCode, optionCode) {
|
|
33
|
+
this._selectOne.set(syncCode, optionCode);
|
|
34
|
+
this.logDebug(syncCode, optionCode);
|
|
35
|
+
}
|
|
36
|
+
setForSelectMany(syncCode, optionCode, selected) {
|
|
37
|
+
let forSyncCode = this._selectMany.get(syncCode);
|
|
38
|
+
if (forSyncCode === undefined) {
|
|
39
|
+
forSyncCode = new Map();
|
|
40
|
+
this._selectMany.set(syncCode, forSyncCode);
|
|
41
|
+
}
|
|
42
|
+
forSyncCode.set(optionCode, selected);
|
|
43
|
+
this.logDebug(syncCode, optionCode, selected);
|
|
44
|
+
}
|
|
45
|
+
getForSelectOne(syncCode) {
|
|
46
|
+
return this._selectOne.get(syncCode);
|
|
47
|
+
}
|
|
48
|
+
getForSelectMany(syncCode, optionCode) {
|
|
49
|
+
var _a;
|
|
50
|
+
return (_a = this._selectMany.get(syncCode)) === null || _a === void 0 ? void 0 : _a.get(optionCode);
|
|
51
|
+
}
|
|
52
|
+
logDebug(group, code, selected) {
|
|
53
|
+
const isMany = selected !== undefined;
|
|
54
|
+
const selectOne = Array.from(this._selectOne.entries());
|
|
55
|
+
const selectMany = Array.from(this._selectMany.entries()).reduce((a, [groupCode, optionCodeToSelected]) => {
|
|
56
|
+
for (const [optionCode, selected] of optionCodeToSelected) {
|
|
57
|
+
a.push([groupCode, optionCode, selected]);
|
|
58
|
+
}
|
|
59
|
+
return a;
|
|
60
|
+
}, []);
|
|
61
|
+
let columnWidth = 1;
|
|
62
|
+
selectOne.forEach((e) => {
|
|
63
|
+
columnWidth = Math.max(columnWidth, e[0].length);
|
|
64
|
+
});
|
|
65
|
+
selectMany.forEach((e) => {
|
|
66
|
+
columnWidth = Math.max(columnWidth, e[0].length);
|
|
67
|
+
});
|
|
68
|
+
const padding = Array(columnWidth).join(" ");
|
|
69
|
+
const styleBold = "font-weight: bold";
|
|
70
|
+
const styleBoldThis = "color:blue; font-weight: bold";
|
|
71
|
+
const styleBoldOn = "color:green; font-weight: bold";
|
|
72
|
+
const styleBoldOff = "color:red; font-weight: bold";
|
|
73
|
+
const styleThis = "color:blue";
|
|
74
|
+
const styleOn = "color:green";
|
|
75
|
+
const styleOff = "color:red";
|
|
76
|
+
const output = [];
|
|
77
|
+
if (group === undefined) {
|
|
78
|
+
output.push("");
|
|
79
|
+
}
|
|
80
|
+
else if (isMany) {
|
|
81
|
+
output.push(...[
|
|
82
|
+
`%c${code} %cin %c${group} %cset to %c${selected ? "on" : "off"}\n`,
|
|
83
|
+
styleBoldThis,
|
|
84
|
+
"",
|
|
85
|
+
styleBoldThis,
|
|
86
|
+
"",
|
|
87
|
+
selected ? styleBoldOn : styleBoldOff,
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
output.push(...[`%c${group}%c set to %c${code}\n`, styleBoldThis, "", styleBoldThis]);
|
|
92
|
+
}
|
|
93
|
+
output[0] = output[0] + "%cSync State (single)";
|
|
94
|
+
output.push(styleBold);
|
|
95
|
+
selectOne.forEach((e) => {
|
|
96
|
+
output[0] = output[0] + `\n %c${(padding + e[0]).slice(-columnWidth)}: ${e[1]}`;
|
|
97
|
+
output.push(!isMany && group === e[0] ? styleThis : "");
|
|
98
|
+
});
|
|
99
|
+
output[0] = output[0] + "\n%cSync State (multi)";
|
|
100
|
+
output.push(styleBold);
|
|
101
|
+
selectMany.forEach((e) => {
|
|
102
|
+
output[0] = output[0] + `\n %c${(padding + e[0]).slice(-columnWidth)}: %c${e[1]}`;
|
|
103
|
+
output.push(isMany && group === e[0] ? styleThis : "");
|
|
104
|
+
output.push(e[2] === true ? styleOn : styleOff);
|
|
105
|
+
});
|
|
106
|
+
console.log(...output);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { _CfgProductInternal } from "../CfgProduct.js";
|
|
2
|
+
import { _CfgFeatureInternal } from "../productConfiguration/CfgFeature.js";
|
|
3
|
+
import { _CfgOptionInternal } from "../productConfiguration/CfgOption.js";
|
|
4
|
+
import { ProductLoader } from "../productLoader.js";
|
|
5
|
+
import { SyncGroupsApplyMode } from "./SyncGroupsApplyMode.js";
|
|
6
|
+
import { OptionCode, SyncCode } from "./SyncGroupsHandler.js";
|
|
7
|
+
import { CfgPath } from "./SyncGroupsPathHelper.js";
|
|
8
|
+
import { SyncGroupsState } from "./SyncGroupsState.js";
|
|
9
|
+
/**
|
|
10
|
+
* A transaction is normally limited to one user interaction. Like opening a product or
|
|
11
|
+
* selecting an option. This object is used to keep data for one transaction. In particular
|
|
12
|
+
* what Features and what SyncGroups have been affected in the transaction. This is a means
|
|
13
|
+
* to eliminate the risk of infinite loops.
|
|
14
|
+
*/
|
|
15
|
+
export declare class SyncGroupsTransaction {
|
|
16
|
+
readonly syncState: SyncGroupsState;
|
|
17
|
+
readonly updateMode: SyncGroupsApplyMode;
|
|
18
|
+
readonly productLoader: ProductLoader;
|
|
19
|
+
readonly original: _CfgProductInternal;
|
|
20
|
+
readonly target: _CfgProductInternal;
|
|
21
|
+
readonly initial: _CfgProductInternal | undefined;
|
|
22
|
+
static make(syncState: SyncGroupsState, updateMode: SyncGroupsApplyMode, product: _CfgProductInternal, productLoader: ProductLoader, assumeNoStartState: boolean): Promise<SyncGroupsTransaction>;
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param syncState A clone of the original syncState. Replaces the original syncState if nothing fails and the transaction doesn't get aborted
|
|
26
|
+
* @param updateMode
|
|
27
|
+
* @param productLoader
|
|
28
|
+
* @param original The product instance that this transaction will be applied on provided nothing fails and the transaction doesn't get aborted
|
|
29
|
+
* @param target A clone of the original product used to apply the configuration changes to
|
|
30
|
+
* @param initial A clone of the original product used to track what the original state was. As a safe measure we do not use originalProduct for this, as it might be changed by someone else
|
|
31
|
+
*/
|
|
32
|
+
private constructor();
|
|
33
|
+
private _aborted;
|
|
34
|
+
private affectedSelectOneFeatures;
|
|
35
|
+
private affectedSelectManyOptions;
|
|
36
|
+
private affectedSelectOneSyncGroups;
|
|
37
|
+
private affectedSelectManySyncGroupsAndOptions;
|
|
38
|
+
get isAborted(): boolean;
|
|
39
|
+
abort(): void;
|
|
40
|
+
init(): Promise<boolean>;
|
|
41
|
+
selectOption(optionPath: CfgPath, on: boolean): Promise<boolean>;
|
|
42
|
+
addSelectOneFeatureAffected(feature: _CfgFeatureInternal): void;
|
|
43
|
+
addSelectManyOptionAffected(option: _CfgOptionInternal): void;
|
|
44
|
+
hasSelectOneFeatureBeenAffected(feature: _CfgFeatureInternal): boolean;
|
|
45
|
+
hasSelectManyOptionBeenAffected(option: _CfgOptionInternal): boolean;
|
|
46
|
+
addSyncGroupAffectedForSelectOne(syncCode: SyncCode): void;
|
|
47
|
+
addSyncGroupAffectedForSelectMany(syncCode: SyncCode, optionCode: OptionCode): void;
|
|
48
|
+
isSyncGroupAffectedForSelectOne(syncCode: SyncCode): boolean;
|
|
49
|
+
isSyncGroupAffectedForSelectMany(syncCode: SyncCode, optionCode: OptionCode): boolean;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=SyncGroupsTransaction.d.ts.map
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { assert } from "@configura/web-utilities";
|
|
11
|
+
import { SelectionType } from "../productConfiguration/CfgFeature.js";
|
|
12
|
+
import { SyncGroupsApplier } from "./SyncGroupsApplier.js";
|
|
13
|
+
import { SyncGroupsPathHelper } from "./SyncGroupsPathHelper.js";
|
|
14
|
+
/**
|
|
15
|
+
* A transaction is normally limited to one user interaction. Like opening a product or
|
|
16
|
+
* selecting an option. This object is used to keep data for one transaction. In particular
|
|
17
|
+
* what Features and what SyncGroups have been affected in the transaction. This is a means
|
|
18
|
+
* to eliminate the risk of infinite loops.
|
|
19
|
+
*/
|
|
20
|
+
export class SyncGroupsTransaction {
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param syncState A clone of the original syncState. Replaces the original syncState if nothing fails and the transaction doesn't get aborted
|
|
24
|
+
* @param updateMode
|
|
25
|
+
* @param productLoader
|
|
26
|
+
* @param original The product instance that this transaction will be applied on provided nothing fails and the transaction doesn't get aborted
|
|
27
|
+
* @param target A clone of the original product used to apply the configuration changes to
|
|
28
|
+
* @param initial A clone of the original product used to track what the original state was. As a safe measure we do not use originalProduct for this, as it might be changed by someone else
|
|
29
|
+
*/
|
|
30
|
+
constructor(syncState, updateMode, productLoader, original, target, initial) {
|
|
31
|
+
this.syncState = syncState;
|
|
32
|
+
this.updateMode = updateMode;
|
|
33
|
+
this.productLoader = productLoader;
|
|
34
|
+
this.original = original;
|
|
35
|
+
this.target = target;
|
|
36
|
+
this.initial = initial;
|
|
37
|
+
this._aborted = false;
|
|
38
|
+
this.affectedSelectOneFeatures = new Set();
|
|
39
|
+
this.affectedSelectManyOptions = new Set();
|
|
40
|
+
this.affectedSelectOneSyncGroups = new Set();
|
|
41
|
+
this.affectedSelectManySyncGroupsAndOptions = new Map();
|
|
42
|
+
}
|
|
43
|
+
static make(syncState, updateMode, product, productLoader, assumeNoStartState) {
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const t = new this(syncState.clone(), updateMode, productLoader, product, yield product.clone(), assumeNoStartState ? undefined : yield product.clone());
|
|
46
|
+
return t;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
get isAborted() {
|
|
50
|
+
return this._aborted;
|
|
51
|
+
}
|
|
52
|
+
abort() {
|
|
53
|
+
this._aborted = true;
|
|
54
|
+
}
|
|
55
|
+
init() {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
return yield SyncGroupsApplier.init(this);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
selectOption(optionPath, on) {
|
|
61
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const targetOption = SyncGroupsPathHelper.getOptionFromPath(optionPath, this.target);
|
|
63
|
+
return yield SyncGroupsApplier.selectOption(this, targetOption, on);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
addSelectOneFeatureAffected(feature) {
|
|
67
|
+
assert(feature.selectionType === SelectionType.SelectOne, "Can only be used for SelectOne Feature");
|
|
68
|
+
this.affectedSelectOneFeatures.add(feature);
|
|
69
|
+
}
|
|
70
|
+
addSelectManyOptionAffected(option) {
|
|
71
|
+
assert(option.parent.selectionType === SelectionType.SelectMany, "Can only be used for option in SelectMany Feature");
|
|
72
|
+
this.affectedSelectManyOptions.add(option);
|
|
73
|
+
}
|
|
74
|
+
hasSelectOneFeatureBeenAffected(feature) {
|
|
75
|
+
assert(feature.selectionType === SelectionType.SelectOne, "Can only be used for SelectOne Feature");
|
|
76
|
+
return this.affectedSelectOneFeatures.has(feature);
|
|
77
|
+
}
|
|
78
|
+
hasSelectManyOptionBeenAffected(option) {
|
|
79
|
+
assert(option.parent.selectionType === SelectionType.SelectMany, "Can only be used for option in SelectMany Feature");
|
|
80
|
+
return this.affectedSelectManyOptions.has(option);
|
|
81
|
+
}
|
|
82
|
+
addSyncGroupAffectedForSelectOne(syncCode) {
|
|
83
|
+
this.affectedSelectOneSyncGroups.add(syncCode);
|
|
84
|
+
}
|
|
85
|
+
addSyncGroupAffectedForSelectMany(syncCode, optionCode) {
|
|
86
|
+
let forSyncCode = this.affectedSelectManySyncGroupsAndOptions.get(syncCode);
|
|
87
|
+
if (forSyncCode === undefined) {
|
|
88
|
+
forSyncCode = new Set();
|
|
89
|
+
this.affectedSelectManySyncGroupsAndOptions.set(syncCode, forSyncCode);
|
|
90
|
+
}
|
|
91
|
+
forSyncCode.add(optionCode);
|
|
92
|
+
}
|
|
93
|
+
isSyncGroupAffectedForSelectOne(syncCode) {
|
|
94
|
+
return this.affectedSelectOneSyncGroups.has(syncCode);
|
|
95
|
+
}
|
|
96
|
+
isSyncGroupAffectedForSelectMany(syncCode, optionCode) {
|
|
97
|
+
var _a;
|
|
98
|
+
return ((_a = this.affectedSelectManySyncGroupsAndOptions.get(syncCode)) === null || _a === void 0 ? void 0 : _a.has(optionCode)) === true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { CfgProduct } from "../../CfgProduct.js";
|
|
11
11
|
import { Collector } from "./collectorForTest.js";
|
|
12
12
|
import { dummyCatId } from "./dummyProductForTest.js";
|
|
13
|
+
import { letterOptionCodeA, letterOptionCodeB, letterOptionCodeC, letterOptions, } from "./testDataOptions.js";
|
|
13
14
|
const A = () => ({
|
|
14
15
|
uuid: "A",
|
|
15
16
|
unit: "m",
|
|
@@ -19,96 +20,37 @@ const A = () => ({
|
|
|
19
20
|
description: "",
|
|
20
21
|
numericOrder: false,
|
|
21
22
|
options: [
|
|
22
|
-
{
|
|
23
|
-
code: "optionA",
|
|
24
|
-
description: "",
|
|
25
|
-
additionalProductRefs: [
|
|
23
|
+
Object.assign(Object.assign({}, letterOptions[0]), { additionalProductRefs: [
|
|
26
24
|
{ refKey: "C_0", catId: dummyCatId, partNumber: "C" },
|
|
27
25
|
{ refKey: "B_0", catId: dummyCatId, partNumber: "B" },
|
|
28
|
-
],
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
code: "optionB",
|
|
32
|
-
description: "",
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
code: "optionC",
|
|
36
|
-
description: "",
|
|
37
|
-
additionalProductRefs: [{ refKey: "D", catId: dummyCatId, partNumber: "D" }],
|
|
38
|
-
},
|
|
26
|
+
] }),
|
|
27
|
+
letterOptions[1],
|
|
28
|
+
Object.assign(Object.assign({}, letterOptions[2]), { additionalProductRefs: [{ refKey: "D", catId: dummyCatId, partNumber: "D" }] }),
|
|
39
29
|
],
|
|
40
30
|
},
|
|
41
31
|
{
|
|
42
32
|
code: "featureX",
|
|
43
33
|
description: "",
|
|
44
34
|
numericOrder: false,
|
|
45
|
-
options: [
|
|
46
|
-
{
|
|
47
|
-
code: "optionA",
|
|
48
|
-
description: "",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
code: "optionB",
|
|
52
|
-
description: "",
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
code: "optionC",
|
|
56
|
-
description: "",
|
|
57
|
-
},
|
|
58
|
-
],
|
|
35
|
+
options: [...letterOptions],
|
|
59
36
|
},
|
|
60
37
|
{
|
|
61
38
|
code: "featureNotUsed",
|
|
62
39
|
description: "",
|
|
63
40
|
numericOrder: false,
|
|
64
|
-
options: [
|
|
65
|
-
{
|
|
66
|
-
code: "optionA",
|
|
67
|
-
description: "",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
code: "optionB",
|
|
71
|
-
description: "",
|
|
72
|
-
},
|
|
73
|
-
],
|
|
41
|
+
options: [...letterOptions],
|
|
74
42
|
},
|
|
75
43
|
{
|
|
76
44
|
code: "featureOptionCSelectedAtStart",
|
|
77
45
|
description: "",
|
|
78
46
|
numericOrder: false,
|
|
79
|
-
options: [
|
|
80
|
-
{
|
|
81
|
-
code: "optionA",
|
|
82
|
-
description: "",
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
code: "optionB",
|
|
86
|
-
description: "",
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
code: "optionC",
|
|
90
|
-
description: "",
|
|
91
|
-
},
|
|
92
|
-
],
|
|
47
|
+
options: [...letterOptions],
|
|
93
48
|
},
|
|
94
49
|
{
|
|
95
50
|
code: "featureSelectMany",
|
|
96
51
|
description: "",
|
|
97
52
|
numericOrder: false,
|
|
98
|
-
options: [
|
|
99
|
-
{
|
|
100
|
-
code: "optionA",
|
|
101
|
-
description: "",
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
code: "optionB",
|
|
105
|
-
description: "",
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
code: "optionC",
|
|
109
|
-
description: "",
|
|
110
|
-
},
|
|
111
|
-
],
|
|
53
|
+
options: [...letterOptions],
|
|
112
54
|
},
|
|
113
55
|
],
|
|
114
56
|
productData: {
|
|
@@ -123,24 +65,24 @@ const A = () => ({
|
|
|
123
65
|
{
|
|
124
66
|
code: "!~!",
|
|
125
67
|
next: {
|
|
126
|
-
|
|
127
|
-
code:
|
|
68
|
+
[letterOptionCodeA]: {
|
|
69
|
+
code: letterOptionCodeA,
|
|
128
70
|
},
|
|
129
71
|
},
|
|
130
72
|
},
|
|
131
73
|
{
|
|
132
74
|
code: "!~!",
|
|
133
75
|
next: {
|
|
134
|
-
|
|
135
|
-
code:
|
|
76
|
+
[letterOptionCodeB]: {
|
|
77
|
+
code: letterOptionCodeB,
|
|
136
78
|
},
|
|
137
79
|
},
|
|
138
80
|
},
|
|
139
81
|
{
|
|
140
82
|
code: "!~!",
|
|
141
83
|
next: {
|
|
142
|
-
|
|
143
|
-
code:
|
|
84
|
+
[letterOptionCodeC]: {
|
|
85
|
+
code: letterOptionCodeC,
|
|
144
86
|
},
|
|
145
87
|
},
|
|
146
88
|
},
|
|
@@ -219,20 +161,7 @@ const C = () => ({
|
|
|
219
161
|
code: "featureC",
|
|
220
162
|
description: "",
|
|
221
163
|
numericOrder: false,
|
|
222
|
-
options: [
|
|
223
|
-
{
|
|
224
|
-
code: "optionA",
|
|
225
|
-
description: "",
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
code: "optionB",
|
|
229
|
-
description: "",
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
code: "optionC",
|
|
233
|
-
description: "",
|
|
234
|
-
},
|
|
235
|
-
],
|
|
164
|
+
options: [...letterOptions],
|
|
236
165
|
},
|
|
237
166
|
],
|
|
238
167
|
productData: {
|
|
@@ -246,8 +175,8 @@ const C = () => ({
|
|
|
246
175
|
{
|
|
247
176
|
code: "!~!",
|
|
248
177
|
next: {
|
|
249
|
-
|
|
250
|
-
code:
|
|
178
|
+
[letterOptionCodeA]: {
|
|
179
|
+
code: letterOptionCodeA,
|
|
251
180
|
},
|
|
252
181
|
},
|
|
253
182
|
},
|
|
@@ -297,8 +226,8 @@ export const cfgProductTest = (testFunc, prepFunc) => __awaiter(void 0, void 0,
|
|
|
297
226
|
{
|
|
298
227
|
code: "!~!",
|
|
299
228
|
next: {
|
|
300
|
-
|
|
301
|
-
code:
|
|
229
|
+
[letterOptionCodeC]: {
|
|
230
|
+
code: letterOptionCodeC,
|
|
302
231
|
},
|
|
303
232
|
},
|
|
304
233
|
},
|
|
@@ -307,16 +236,16 @@ export const cfgProductTest = (testFunc, prepFunc) => __awaiter(void 0, void 0,
|
|
|
307
236
|
productData.partsData.selOptions.push({
|
|
308
237
|
code: "!~!",
|
|
309
238
|
next: {
|
|
310
|
-
|
|
311
|
-
code:
|
|
239
|
+
[letterOptionCodeC]: {
|
|
240
|
+
code: letterOptionCodeC,
|
|
312
241
|
},
|
|
313
242
|
},
|
|
314
243
|
});
|
|
315
244
|
productData.partsData.selOptions.push({
|
|
316
245
|
code: "!~!",
|
|
317
246
|
next: {
|
|
318
|
-
|
|
319
|
-
code:
|
|
247
|
+
[letterOptionCodeC]: {
|
|
248
|
+
code: letterOptionCodeC,
|
|
320
249
|
},
|
|
321
250
|
},
|
|
322
251
|
});
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
import { CfgProduct } from "../../CfgProduct.js";
|
|
11
11
|
import { wrapWithGetProductCache } from "../../productLoader.js";
|
|
12
12
|
import { dummyCatId } from "./dummyProductForTest.js";
|
|
13
|
+
import { letterOptionCodeA, letterOptions } from "./testDataOptions.js";
|
|
13
14
|
let prodKeyArray = [];
|
|
14
15
|
const A = () => ({
|
|
15
16
|
uuid: "A",
|
|
@@ -20,24 +21,12 @@ const A = () => ({
|
|
|
20
21
|
description: "",
|
|
21
22
|
numericOrder: false,
|
|
22
23
|
options: [
|
|
23
|
-
{
|
|
24
|
-
code: "optionA",
|
|
25
|
-
description: "",
|
|
26
|
-
additionalProductRefs: [
|
|
24
|
+
Object.assign(Object.assign({}, letterOptions[0]), { additionalProductRefs: [
|
|
27
25
|
{ refKey: "C_0", catId: dummyCatId, partNumber: "C" },
|
|
28
26
|
{ refKey: "B_0", catId: dummyCatId, partNumber: "B" },
|
|
29
|
-
],
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
code: "optionB",
|
|
33
|
-
description: "",
|
|
34
|
-
additionalProductRefs: [{ refKey: "E", catId: dummyCatId, partNumber: "E" }],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
code: "optionC",
|
|
38
|
-
description: "",
|
|
39
|
-
additionalProductRefs: [{ refKey: "D", catId: dummyCatId, partNumber: "D" }],
|
|
40
|
-
},
|
|
27
|
+
] }),
|
|
28
|
+
Object.assign(Object.assign({}, letterOptions[1]), { additionalProductRefs: [{ refKey: "E", catId: dummyCatId, partNumber: "E" }] }),
|
|
29
|
+
Object.assign(Object.assign({}, letterOptions[2]), { additionalProductRefs: [{ refKey: "D", catId: dummyCatId, partNumber: "D" }] }),
|
|
41
30
|
],
|
|
42
31
|
},
|
|
43
32
|
],
|
|
@@ -53,8 +42,8 @@ const A = () => ({
|
|
|
53
42
|
{
|
|
54
43
|
code: "!~!",
|
|
55
44
|
next: {
|
|
56
|
-
|
|
57
|
-
code:
|
|
45
|
+
[letterOptionCodeA]: {
|
|
46
|
+
code: letterOptionCodeA,
|
|
58
47
|
},
|
|
59
48
|
},
|
|
60
49
|
},
|
|
@@ -165,7 +154,7 @@ export const cachedProductLoaderTest = () => __awaiter(void 0, void 0, void 0, f
|
|
|
165
154
|
getProduct: getTestProduct,
|
|
166
155
|
postValidate: (params, _body) => __awaiter(void 0, void 0, void 0, function* () {
|
|
167
156
|
const productData = (yield getTestProduct(params, true)).productData;
|
|
168
|
-
let code =
|
|
157
|
+
let code = letterOptionCodeA;
|
|
169
158
|
for (let test in _body.selOptions[0].next) {
|
|
170
159
|
code = test;
|
|
171
160
|
break;
|