@veloceapps/sdk 11.0.0-11 → 11.0.0-13

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 (89) hide show
  1. package/cms/vendor-map.d.ts +7 -6
  2. package/core/modules/configuration/helpers.d.ts +2 -1
  3. package/core/modules/configuration/services/configuration-runtime.service.d.ts +1 -3
  4. package/core/modules/configuration/services/configuration-state.service.d.ts +7 -7
  5. package/core/modules/configuration/services/configuration.service.d.ts +5 -10
  6. package/core/modules/flow-configuration/services/flow-configuration.service.d.ts +11 -32
  7. package/core/services/catalog-products.service.d.ts +11 -0
  8. package/core/services/flow-info.service.d.ts +23 -10
  9. package/core/services/flow-state.service.d.ts +9 -12
  10. package/core/services/index.d.ts +2 -2
  11. package/core/services/quote-draft.service.d.ts +5 -5
  12. package/core/services/sales-transaction.service.d.ts +28 -0
  13. package/core/types/flow-state.types.d.ts +2 -2
  14. package/esm2020/cms/vendor-map.mjs +8 -7
  15. package/esm2020/core/core.module.mjs +7 -4
  16. package/esm2020/core/modules/configuration/helpers.mjs +11 -17
  17. package/esm2020/core/modules/configuration/services/configuration-runtime.service.mjs +8 -45
  18. package/esm2020/core/modules/configuration/services/configuration-state.service.mjs +46 -54
  19. package/esm2020/core/modules/configuration/services/configuration.service.mjs +21 -39
  20. package/esm2020/core/modules/flow-configuration/services/flow-configuration.service.mjs +34 -110
  21. package/esm2020/core/services/catalog-products.service.mjs +25 -0
  22. package/esm2020/core/services/flow-info.service.mjs +70 -28
  23. package/esm2020/core/services/flow-state.service.mjs +59 -133
  24. package/esm2020/core/services/index.mjs +3 -3
  25. package/esm2020/core/services/quote-draft.service.mjs +20 -38
  26. package/esm2020/core/services/sales-transaction.service.mjs +62 -0
  27. package/esm2020/core/types/flow-state.types.mjs +1 -1
  28. package/esm2020/src/components/flow-header/flow-header.component.mjs +3 -6
  29. package/esm2020/src/components/guided-selling/guided-selling.component.mjs +3 -6
  30. package/esm2020/src/flow-routing.module.mjs +5 -36
  31. package/esm2020/src/flow.component.mjs +5 -5
  32. package/esm2020/src/guards/flow.guard.mjs +10 -9
  33. package/esm2020/src/guards/product-unload.guard.mjs +5 -7
  34. package/esm2020/src/index.mjs +1 -2
  35. package/esm2020/src/pages/assets/assets.component.mjs +3 -3
  36. package/esm2020/src/pages/catalog/catalog.component.mjs +3 -3
  37. package/esm2020/src/pages/debug/debug.component.mjs +7 -11
  38. package/esm2020/src/pages/product/product.component.mjs +47 -67
  39. package/esm2020/src/pages/product/product.module.mjs +5 -5
  40. package/esm2020/src/pages/shopping-cart/shopping-cart.component.mjs +3 -3
  41. package/esm2020/src/resolvers/flow.resolver.mjs +10 -18
  42. package/esm2020/src/resolvers/quote.resolver.mjs +11 -11
  43. package/esm2020/src/services/flow-dialog.service.mjs +8 -8
  44. package/esm2020/src/services/flow-router.service.mjs +11 -21
  45. package/esm2020/src/services/flow.service.mjs +10 -43
  46. package/esm2020/src/utils/flow.utils.mjs +2 -13
  47. package/fesm2015/veloceapps-sdk-cms.mjs +7 -6
  48. package/fesm2015/veloceapps-sdk-cms.mjs.map +1 -1
  49. package/fesm2015/veloceapps-sdk-core.mjs +1483 -1636
  50. package/fesm2015/veloceapps-sdk-core.mjs.map +1 -1
  51. package/fesm2015/veloceapps-sdk.mjs +126 -672
  52. package/fesm2015/veloceapps-sdk.mjs.map +1 -1
  53. package/fesm2020/veloceapps-sdk-cms.mjs +7 -6
  54. package/fesm2020/veloceapps-sdk-cms.mjs.map +1 -1
  55. package/fesm2020/veloceapps-sdk-core.mjs +1515 -1707
  56. package/fesm2020/veloceapps-sdk-core.mjs.map +1 -1
  57. package/fesm2020/veloceapps-sdk.mjs +124 -667
  58. package/fesm2020/veloceapps-sdk.mjs.map +1 -1
  59. package/package.json +1 -1
  60. package/src/components/flow-header/flow-header.component.d.ts +1 -1
  61. package/src/components/guided-selling/guided-selling.component.d.ts +1 -1
  62. package/src/flow-routing.module.d.ts +1 -2
  63. package/src/flow.component.d.ts +2 -2
  64. package/src/guards/product-unload.guard.d.ts +4 -5
  65. package/src/index.d.ts +0 -1
  66. package/src/pages/assets/assets.component.d.ts +1 -1
  67. package/src/pages/catalog/catalog.component.d.ts +1 -1
  68. package/src/pages/debug/debug.component.d.ts +2 -3
  69. package/src/pages/product/product.component.d.ts +9 -10
  70. package/src/pages/product/product.module.d.ts +1 -1
  71. package/src/pages/shopping-cart/shopping-cart.component.d.ts +1 -1
  72. package/src/resolvers/flow.resolver.d.ts +5 -6
  73. package/src/resolvers/quote.resolver.d.ts +5 -6
  74. package/src/services/flow-dialog.service.d.ts +3 -3
  75. package/src/services/flow-router.service.d.ts +2 -4
  76. package/src/services/flow.service.d.ts +2 -6
  77. package/src/utils/flow.utils.d.ts +0 -7
  78. package/core/services/context.service.d.ts +0 -23
  79. package/esm2020/core/services/context.service.mjs +0 -91
  80. package/esm2020/src/guards/context.guard.mjs +0 -91
  81. package/esm2020/src/guards/index.mjs +0 -2
  82. package/esm2020/src/pages/remote/remote.component.mjs +0 -342
  83. package/esm2020/src/pages/remote/remote.module.mjs +0 -20
  84. package/esm2020/src/pages/remote/remote.types.mjs +0 -2
  85. package/src/guards/context.guard.d.ts +0 -19
  86. package/src/guards/index.d.ts +0 -1
  87. package/src/pages/remote/remote.component.d.ts +0 -46
  88. package/src/pages/remote/remote.module.d.ts +0 -10
  89. package/src/pages/remote/remote.types.d.ts +0 -4
@@ -1,16 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, InjectionToken, Optional, Inject, NgModule, inject, Directive, Input, LOCALE_ID, Pipe } from '@angular/core';
3
- import { UUID, ConfigurationContextMode, ConfigurationContext, UITemplateType, QuoteDraft, isDefined, ConfigurationProcessorTypes, EntityUtil, DEFAULT_CURRENCY_ISO_CODE, DEFAULT_CURRENCY_SYMBOL, validateDateFormat, DEFAULT_DATE_FORMAT, DEFAULT_DECIMALS_COUNT, getSupportedDateFormats, DEFAULT_DECIMAL_SEPARATOR, DEFAULT_THOUSANDS_SEPARATOR, DEFAULT_ACTION_CODE_LABELS, parseJsonSafely, ConfigurationMode, extractErrorDetails, ConfigurationTranslatorUtils, ChargeGroupUtils, RuntimeModel, isNotLegacyUIDefinition, SalesforceIdUtils, DEFAULT_TIME_FORMAT, formatNumber } from '@veloceapps/core';
2
+ import { InjectionToken, Injectable, Optional, Inject, NgModule, inject, Directive, Input, LOCALE_ID, Pipe } from '@angular/core';
3
+ import { UUID, ConfigurationContextMode, RuntimeModel, isNotLegacyUIDefinition, SalesforceIdUtils, DEFAULT_CURRENCY_ISO_CODE, DEFAULT_CURRENCY_SYMBOL, validateDateFormat, DEFAULT_DATE_FORMAT, DEFAULT_DECIMALS_COUNT, getSupportedDateFormats, DEFAULT_DECIMAL_SEPARATOR, DEFAULT_THOUSANDS_SEPARATOR, DEFAULT_ACTION_CODE_LABELS, parseJsonSafely, UITemplateType, ChargeGroupUtils, isDefined, ConfigurationProcessorTypes, EntityUtil, QuoteDraft, ConfigurationMode, extractErrorDetails, ConfigurationTranslatorUtils, DEFAULT_TIME_FORMAT, formatNumber } from '@veloceapps/core';
4
4
  import * as i1 from '@veloceapps/api';
5
5
  import { ApiModule } from '@veloceapps/api';
6
- import { BehaviorSubject, switchMap, map as map$1, tap as tap$1, noop, catchError, throwError, forkJoin, of, zip, combineLatest, Subject, filter as filter$1, shareReplay as shareReplay$1, finalize, takeUntil, buffer, debounceTime, share, take as take$1, distinctUntilChanged } from 'rxjs';
7
- import { map, filter, tap, switchMap as switchMap$1, skip, take, shareReplay, catchError as catchError$1, finalize as finalize$1, first } from 'rxjs/operators';
8
- import { merge, isEqual, cloneDeep, assign, flatten, entries, sortBy, map as map$2, uniqBy, omit, transform } from 'lodash';
6
+ import { map, first, tap, filter as filter$1, switchMap as switchMap$1, skip, take as take$1, shareReplay as shareReplay$1, catchError as catchError$1, finalize as finalize$1 } from 'rxjs/operators';
7
+ import { HttpErrorResponse } from '@angular/common/http';
9
8
  import * as i6 from '@veloceapps/components';
10
9
  import { ToastType, ConfirmationComponent, ConfirmationDialogModule } from '@veloceapps/components';
11
- import { HttpErrorResponse } from '@angular/common/http';
12
- import * as i5 from 'primeng/api';
13
- import * as i6$1 from 'primeng/dynamicdialog';
10
+ import { uniqBy, flatten, entries, sortBy, map as map$2, omit, cloneDeep, assign, isEqual, transform } from 'lodash';
11
+ import * as i4 from 'primeng/api';
12
+ import * as i5 from 'primeng/dynamicdialog';
13
+ import { BehaviorSubject, map as map$1, tap as tap$1, switchMap, of, forkJoin, Subject, noop, catchError, throwError, filter, shareReplay, combineLatest, finalize, buffer, debounceTime, share, take, distinctUntilChanged, zip, takeUntil } from 'rxjs';
14
+ import * as i2 from '@veloceapps/api/v2';
14
15
  import moment from 'moment';
15
16
  import { NgControl } from '@angular/forms';
16
17
  import 'primeng/calendar';
@@ -33,26 +34,20 @@ const getDefaultLineItem = (context, uiDefinitionProperties, qty = 1) => {
33
34
  ...(uiDefinitionProperties.offeringId ? { offeringId: uiDefinitionProperties.offeringId } : {}),
34
35
  };
35
36
  };
36
- const getGuidedSellingConfigurationRequest = (data, context) => {
37
- const _context = { ...context };
38
- delete _context.configurationToken;
39
- const properties = { ...context.properties };
40
- delete properties['ConfigurationToken'];
37
+ const generateEmptyContext = () => {
38
+ return {
39
+ headerId: '',
40
+ mode: ConfigurationContextMode.TEST,
41
+ properties: {},
42
+ configurationToken: '',
43
+ };
44
+ };
45
+ const getGuidedSellingConfigurationRequest = (data) => {
41
46
  return {
42
47
  mode: 'SEARCH',
43
48
  step: 'START',
44
49
  attributeDomainMode: 'ALL',
45
- context: {
46
- ..._context,
47
- mode: ConfigurationContextMode.TEST,
48
- properties: {
49
- ...properties,
50
- ModelId: data.modelId,
51
- Name: 'Veloce Guided Selling',
52
- PricingEnabled: 'false',
53
- RuntimeMode: 'TEST',
54
- },
55
- },
50
+ context: generateEmptyContext(),
56
51
  lineItem: {
57
52
  actionCode: 'ADD',
58
53
  cfgStatus: 'Default',
@@ -88,89 +83,6 @@ const generateConfigurationLineItem = (props, qty = 1) => {
88
83
  };
89
84
  };
90
85
 
91
- class ContextService {
92
- constructor(contextApiService) {
93
- this.contextApiService = contextApiService;
94
- this.context = new BehaviorSubject(null);
95
- }
96
- get isInitialized() {
97
- return Boolean(this.context.value);
98
- }
99
- get isInitialized$() {
100
- return this.context.pipe(map(Boolean));
101
- }
102
- get mode() {
103
- return this.resolve().properties['#mode'];
104
- }
105
- get isEditMode$() {
106
- return this.resolve$().pipe(map(() => this.isEditMode));
107
- }
108
- get isEditMode() {
109
- const context = this.resolve();
110
- if (context.properties['#mode'] === ConfigurationContextMode.ACCOUNT) {
111
- return true;
112
- }
113
- if (context.properties['#mode'] === ConfigurationContextMode.QUOTE) {
114
- return context.properties.Status === 'Draft';
115
- }
116
- return false;
117
- }
118
- resolve() {
119
- if (!this.context.value) {
120
- throw new Error('Context is not initialized yet!');
121
- }
122
- return { ...this.context.value };
123
- }
124
- resolve$() {
125
- return this.context.pipe(filter((ctx) => Boolean(ctx)));
126
- }
127
- create(headerId, mode) {
128
- return this.contextApiService.getContext(headerId, mode).pipe(tap(context => this.context.next(merge(new ConfigurationContext(headerId, mode), context))), map(() => this.resolve()));
129
- }
130
- initTestMode() {
131
- return this.create('TestId', ConfigurationContextMode.TEST).pipe(map(context => {
132
- return this.update({
133
- properties: {
134
- ...context.properties,
135
- RuntimeMode: ConfigurationContextMode.TEST,
136
- StartDate: new Date().toISOString().substring(0, 10),
137
- standalone: 'true',
138
- },
139
- });
140
- }));
141
- }
142
- update(partialContext) {
143
- const originalContext = this.resolve();
144
- const updatedContext = {
145
- ...originalContext,
146
- ...partialContext,
147
- properties: {
148
- ...originalContext.properties,
149
- ...partialContext.properties,
150
- },
151
- };
152
- this.context.next(updatedContext);
153
- return updatedContext;
154
- }
155
- set(context) {
156
- const originalContext = this.resolve();
157
- const updatedContext = {
158
- ...originalContext,
159
- ...context,
160
- };
161
- this.context.next(updatedContext);
162
- return updatedContext;
163
- }
164
- delete() {
165
- this.context.next(null);
166
- }
167
- }
168
- ContextService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ContextService, deps: [{ token: i1.ContextApiService }], target: i0.ɵɵFactoryTarget.Injectable });
169
- ContextService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ContextService });
170
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ContextService, decorators: [{
171
- type: Injectable
172
- }], ctorParameters: function () { return [{ type: i1.ContextApiService }]; } });
173
-
174
86
  const FLOW_CUSTOMIZATION = new InjectionToken('FLOW_CUSTOMIZATION');
175
87
 
176
88
  const FORMATTING_SETTINGS_TOKEN = new InjectionToken('Summary of formatting settings for variant types of data, e.g. numbers, text, dates, etc');
@@ -193,971 +105,521 @@ var RuntimeStep;
193
105
 
194
106
  const UI_DEFINITION_VERSION = 3;
195
107
 
196
- class FlowInfoService {
197
- get flow() {
198
- return this.flowSubj$.value;
199
- }
200
- set flow(value) {
201
- this.flowSubj$.next(value);
202
- }
203
- get isLegacy() {
204
- return !!this.flow && this.flow?.properties.stateful == null;
205
- }
206
- get isStateful() {
207
- return !!this.flow?.properties.stateful;
208
- }
209
- constructor(flowsApiService, templatesApiService, customizationService) {
210
- this.flowsApiService = flowsApiService;
211
- this.templatesApiService = templatesApiService;
212
- this.customizationService = customizationService;
213
- this.templates = {};
214
- this.defaultTemplates = {
215
- flowEngine: 'Flow Engine',
216
- };
217
- this.flowSubj$ = new BehaviorSubject(null);
218
- this.flow$ = this.flowSubj$.asObservable();
219
- }
220
- init$(flowId, routeQueryParams) {
221
- return this.flowsApiService.getFlow(flowId).pipe(switchMap(flow => this.initFlowTemplates$(flow).pipe(map$1(() => flow))), tap$1(flow => {
222
- this.params = { ...routeQueryParams, ...flow.properties.queryParams };
223
- this.flowSubj$.next(flow);
224
- }), map$1(noop), catchError(e => {
225
- this.flowSubj$.next(null);
226
- return throwError(() => e);
227
- }));
228
- }
229
- cleanup() {
230
- this.flowSubj$.next(null);
231
- this.params = undefined;
232
- this.templates = {};
108
+ class RuntimeContextService {
109
+ constructor(configurationApiService) {
110
+ this.configurationApiService = configurationApiService;
233
111
  }
234
- initFlowTemplates$(flow) {
235
- return forkJoin([
236
- this.templatesApiService.fetchTemplates$(),
237
- this.customizationService?.getTemplates?.() ?? of([]),
238
- ]).pipe(map$1(([templates, localTemplates]) => {
239
- Object.entries({ ...this.defaultTemplates, ...flow.properties.templates }).forEach(([key, name]) => {
240
- const type = this.remapTemplateName(key);
241
- if (type) {
242
- this.templates[type] =
243
- localTemplates.find(template => template.name === name && template.type === type) ??
244
- templates.find(template => template.name === name && template.type === type);
245
- }
246
- });
112
+ getRuntimeContext(productId, offeringId, defaultUIDefinitionId, requiredUIDefinitionId) {
113
+ return this.configurationApiService
114
+ .getRuntimeDataByProductId(productId, offeringId, defaultUIDefinitionId, requiredUIDefinitionId)
115
+ .pipe(map(runtimeData => {
116
+ const uiDefinitionContainer = this.getUIDefinitionContainer(runtimeData);
117
+ const runtimeModel = RuntimeModel.create(runtimeData.types, runtimeData.products);
118
+ const { productName, properties } = Array.from(runtimeModel.components.values()).find(c => c.productId === productId) ?? {};
119
+ const uiDefinitionProperties = uiDefinitionContainer?.source.properties;
120
+ return {
121
+ modelId: runtimeData.modelId,
122
+ uiDefinitionContainer: uiDefinitionContainer,
123
+ runtimeModel: runtimeModel,
124
+ runtimeMode: RuntimeMode.PROD,
125
+ productId: productId,
126
+ productType: properties?.['displayName'] || productName,
127
+ offeringId: offeringId,
128
+ properties: {
129
+ PricingEnabled: uiDefinitionProperties?.pricingEnabled ? 'true' : 'false',
130
+ PriceListId: uiDefinitionProperties?.priceList,
131
+ },
132
+ };
247
133
  }));
248
134
  }
249
- remapTemplateName(templateType) {
250
- switch (templateType) {
251
- case 'flowEngine':
252
- return UITemplateType.FLOW_ENGINE;
253
- default:
254
- break;
255
- }
256
- switch (templateType) {
257
- case 'assets':
258
- case 'shoppingCart':
259
- // No separate Assets template at the moment
260
- return UITemplateType.SHOPPING_CART;
261
- case 'catalog':
262
- return UITemplateType.CATALOG;
263
- case 'guidedSelling':
264
- return UITemplateType.GUIDED_SELLING;
265
- case 'flowHeader':
266
- return UITemplateType.FLOW_HEADER;
267
- default:
268
- break;
269
- }
270
- return undefined;
135
+ getUIDefinitionContainer(runtimeData) {
136
+ const containers = runtimeData.uiDefinitions.filter(container => isNotLegacyUIDefinition(container.source));
137
+ return containers.find(container => container.source.primary) ?? containers[0];
271
138
  }
272
139
  }
273
- FlowInfoService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService, deps: [{ token: i1.FlowsApiService }, { token: i1.UITemplatesApiService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
274
- FlowInfoService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService });
275
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService, decorators: [{
140
+ RuntimeContextService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, deps: [{ token: i1.ConfigurationApiService }], target: i0.ɵɵFactoryTarget.Injectable });
141
+ RuntimeContextService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService });
142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, decorators: [{
276
143
  type: Injectable
277
- }], ctorParameters: function () { return [{ type: i1.FlowsApiService }, { type: i1.UITemplatesApiService }, { type: undefined, decorators: [{
278
- type: Optional
279
- }, {
280
- type: Inject,
281
- args: [FLOW_CUSTOMIZATION]
282
- }] }]; } });
144
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }]; } });
283
145
 
284
- class QuoteDraftService {
285
- get isInitialized$() {
286
- return this.isInitializedSubj$.asObservable();
146
+ class ConfigurationRuntimeService {
147
+ constructor(apiService, runtimeContextService) {
148
+ this.apiService = apiService;
149
+ this.runtimeContextService = runtimeContextService;
150
+ this._isInitialized = false;
151
+ this.uiDefinitionProperties = {};
287
152
  }
288
- get isInitialized() {
289
- return this.isInitializedSubj$.getValue();
153
+ reset() {
154
+ this._isInitialized = false;
155
+ this._runtimeContext = undefined;
156
+ this.initializationProps = undefined;
157
+ this.uiDefinitionProperties = {};
290
158
  }
291
- set isInitialized(value) {
292
- if (this.isInitialized !== value) {
293
- this.isInitializedSubj$.next(value);
294
- }
159
+ initTestMode(uiDefinitionContainer) {
160
+ this.uiDefinitionProperties = uiDefinitionContainer.source.properties ?? {};
161
+ return this.apiService.getRuntimeDataByModelId(uiDefinitionContainer.modelId).pipe(first(), map(runtimeData => {
162
+ this._runtimeContext = {
163
+ modelId: uiDefinitionContainer.modelId,
164
+ runtimeModel: RuntimeModel.create(runtimeData.types, runtimeData.products),
165
+ runtimeMode: RuntimeMode.TEST,
166
+ uiDefinitionContainer,
167
+ };
168
+ return this._runtimeContext;
169
+ }), tap(() => (this._isInitialized = true)));
295
170
  }
296
- get hasUnsavedChanges() {
297
- return this._hasUnsavedChanges;
171
+ init(props) {
172
+ this.initializationProps = props;
173
+ return this.runtimeContextService
174
+ .getRuntimeContext(props.productId, props.offeringId, props.defaultUIDefinitionId, props.requiredUIDefinitionId)
175
+ .pipe(tap(runtimeContext => {
176
+ this.uiDefinitionProperties = runtimeContext.uiDefinitionContainer?.source.properties ?? {};
177
+ this.id15to18('AccountId', runtimeContext.properties);
178
+ this._runtimeContext = runtimeContext;
179
+ return this._runtimeContext;
180
+ }), tap(() => (this._isInitialized = true)));
298
181
  }
299
- set hasUnsavedChanges(value) {
300
- this._hasUnsavedChanges = value;
301
- if (!this._hasUnsavedChanges) {
302
- this.initialCurrentState = this.quoteDraft?.currentState ?? [];
182
+ overrideUIDefinition(uiDefinitionContainer) {
183
+ if (!this._runtimeContext) {
184
+ return;
303
185
  }
186
+ this._runtimeContext.uiDefinitionContainer = uiDefinitionContainer;
187
+ this.uiDefinitionProperties = uiDefinitionContainer.source.properties ?? {};
304
188
  }
305
- get hasProducts$() {
306
- return this.quoteSubj$.pipe(map(() => this.hasProducts));
189
+ id15to18(propertyName, source) {
190
+ if (!source) {
191
+ return;
192
+ }
193
+ const value = source[propertyName];
194
+ if (typeof value === 'string' && value.length === 15) {
195
+ source[propertyName] = SalesforceIdUtils.generateId18FromId15(value);
196
+ }
307
197
  }
308
- get hasProducts() {
309
- return Boolean(this.quoteSubj$.value?.currentState.length);
198
+ get isInitialized() {
199
+ return this._isInitialized;
310
200
  }
311
- get hasAssets$() {
312
- return this.assetsSubj$.pipe(map(() => this.hasAssets));
201
+ get runtimeModel() {
202
+ return this.runtimeContext?.runtimeModel;
313
203
  }
314
- get hasAssets() {
315
- return Boolean(this.assetsSubj$.value?.currentState.length);
204
+ get runtimeContext() {
205
+ return this._runtimeContext;
316
206
  }
317
- get assetsState() {
318
- return this.assetsSubj$.value;
207
+ }
208
+ ConfigurationRuntimeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, deps: [{ token: i1.ConfigurationApiService }, { token: RuntimeContextService }], target: i0.ɵɵFactoryTarget.Injectable });
209
+ ConfigurationRuntimeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService });
210
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, decorators: [{
211
+ type: Injectable
212
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }, { type: RuntimeContextService }]; } });
213
+
214
+ class RuntimeSettingsService {
215
+ constructor(configurationSettingsApiService) {
216
+ this.configurationSettingsApiService = configurationSettingsApiService;
217
+ this.configurationSettings$ = new BehaviorSubject({});
218
+ this.currencySettings$ = new BehaviorSubject({
219
+ iso: DEFAULT_CURRENCY_ISO_CODE,
220
+ symbol: DEFAULT_CURRENCY_SYMBOL,
221
+ });
222
+ this.shoppingCartSettings$ = new BehaviorSubject([]);
223
+ this.getCurrencySymbol = (locale, currency) => {
224
+ return (0)
225
+ .toLocaleString(locale, { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0 })
226
+ .replace(/\d/g, '')
227
+ .trim();
228
+ };
319
229
  }
320
- constructor(context, flowInfoService, accountApiService, quoteApiService) {
321
- this.context = context;
322
- this.flowInfoService = flowInfoService;
323
- this.accountApiService = accountApiService;
324
- this.quoteApiService = quoteApiService;
325
- this.quoteSubj$ = new BehaviorSubject(null);
326
- this.assetsSubj$ = new BehaviorSubject(null);
327
- this.resetSubj$ = new BehaviorSubject(true);
328
- this.isInitializedSubj$ = new BehaviorSubject(false);
329
- this.initialCurrentState = [];
330
- this._hasUnsavedChanges = false;
331
- this.reset$ = this.resetSubj$.asObservable();
332
- this.isInitializedSubj$
333
- .pipe(filter(isInitialized => isInitialized), switchMap$1(() => this.quoteSubj$.asObservable()), skip(1), tap(quote => this.markAsUpdated(quote)))
334
- .subscribe();
230
+ create() {
231
+ return this.configurationSettingsApiService.fetchSettings().pipe(map$1(settings => this.parseConfigurationSettings(settings)), tap$1(configurationSettings => {
232
+ this.configurationSettings$.next(configurationSettings);
233
+ this.addShoppingCartSettings(configurationSettings['shopping-cart'] ?? []);
234
+ this.formattingSettings = this.getFormattingSettings();
235
+ }), map$1(() => undefined));
335
236
  }
336
- reset() {
337
- this.resetSubj$.next(true);
338
- this.quoteSubj$.next(null);
339
- this.assetsSubj$.next(null);
340
- this.isInitialized = false;
341
- this.hasUnsavedChanges = false;
237
+ initCurrency(iso) {
238
+ if (iso) {
239
+ const symbol = this.getCurrencySymbol('en-US', iso);
240
+ this.currencySettings$.next({ iso, symbol });
241
+ if (this.formattingSettings) {
242
+ this.formattingSettings.currencySymbol = symbol;
243
+ }
244
+ }
342
245
  }
343
- init(headerId, params) {
344
- const ctx = this.context.resolve();
345
- const isAccountMode = this.context.mode === ConfigurationContextMode.ACCOUNT;
346
- const accountId = isAccountMode ? headerId : ctx.properties.AccountId;
347
- return zip(accountId ? this.accountApiService.getAssetsState(accountId, params) : of(null), isAccountMode
348
- ? of(QuoteDraft.emptyQuote(ConfigurationContextMode.ACCOUNT))
349
- : this.quoteApiService.getQuoteState(headerId, params)).pipe(tap(([assets, quote]) => {
350
- if (assets) {
351
- this.assetsSubj$.next(assets);
352
- }
353
- this.quoteSubj$.next(quote);
354
- if (assets && isAccountMode) {
355
- this.context.update(assets.context);
356
- }
357
- else {
358
- this.context.update(quote.context);
359
- }
360
- }), map(() => noop()), take(1));
246
+ getFormattingSettings() {
247
+ if (this.formattingSettings) {
248
+ return this.formattingSettings;
249
+ }
250
+ const shoppingCartSettings = this.getConfigurationSettings()['shopping-cart']?.reduce((acc, setting) => {
251
+ return { ...acc, [setting.id]: setting.properties };
252
+ }, {});
253
+ const currencySettings = this.getCurrencySettings();
254
+ const dateFormat = (validateDateFormat(shoppingCartSettings?.DATE_FORMAT ?? '') && shoppingCartSettings?.DATE_FORMAT) ||
255
+ DEFAULT_DATE_FORMAT;
256
+ const decimalSeparator = shoppingCartSettings?.DECIMAL_SEPARATOR;
257
+ const thousandsSeparator = shoppingCartSettings?.THOUSANDS_SEPARATOR;
258
+ // the number of decimal places can be 0
259
+ const priceScale = shoppingCartSettings?.PRICE_SCALE;
260
+ const decimalsCount = priceScale !== null && priceScale !== '' && !isNaN(Number(priceScale)) && Number(priceScale) >= 0
261
+ ? Number(priceScale)
262
+ : DEFAULT_DECIMALS_COUNT;
263
+ const actionCodeSettings = shoppingCartSettings?.STATUS_LABEL;
264
+ return {
265
+ currencySymbol: currencySettings.symbol,
266
+ dateFormats: getSupportedDateFormats(dateFormat),
267
+ decimalsCount,
268
+ decimalSeparator: decimalSeparator !== undefined && ['.', ','].includes(decimalSeparator)
269
+ ? decimalSeparator
270
+ : DEFAULT_DECIMAL_SEPARATOR,
271
+ // thousands separator can be a blank value, so it can also be null
272
+ thousandsSeparator: thousandsSeparator !== undefined && ['.', ',', '', null].includes(thousandsSeparator)
273
+ ? thousandsSeparator || ''
274
+ : DEFAULT_THOUSANDS_SEPARATOR,
275
+ actionCodeLabels: actionCodeSettings?.length
276
+ ? actionCodeSettings.reduce((result, setting) => ({ ...result, [setting.status_label]: setting.custom_label }), {})
277
+ : DEFAULT_ACTION_CODE_LABELS,
278
+ };
361
279
  }
362
- finalizeInit() {
363
- this.isInitialized = true;
364
- this.hasUnsavedChanges = false;
280
+ getConfigurationSettings() {
281
+ return this.configurationSettings$.value;
365
282
  }
366
- setCurrentLineItemState(lineItems) {
367
- const quoteDraft = this.quoteSubj$.value;
368
- if (!quoteDraft) {
369
- return;
370
- }
371
- this.quoteSubj$.next({
372
- ...quoteDraft,
373
- currentState: lineItems,
374
- });
283
+ getShoppingCartSettings() {
284
+ return this.shoppingCartSettings$.value;
375
285
  }
376
- updateQuoteDraft(update) {
377
- const quoteDraft = this.quoteSubj$.value;
378
- if (!quoteDraft) {
379
- return;
380
- }
381
- if (update.context) {
382
- this.context.set(update.context);
383
- }
384
- this.quoteSubj$.next({
385
- ...quoteDraft,
386
- ...update,
387
- });
286
+ getCurrencySettings() {
287
+ return this.currencySettings$.value;
388
288
  }
389
- updateByPriceSummary(priceSummary) {
390
- const quoteDraft = this.quoteSubj$.value;
391
- if (!quoteDraft) {
392
- return;
393
- }
394
- const updatedCurrentState = this.currentState.map(lineItem => {
395
- const updated = priceSummary.lineItems.find(li => li.id === lineItem.id);
396
- return updated ?? lineItem;
397
- });
398
- this.quoteSubj$.next({
399
- ...quoteDraft,
400
- currentState: updatedCurrentState,
401
- totalPrices: priceSummary.totalPrices,
402
- approvalItems: priceSummary.approvalItems,
403
- });
289
+ parseConfigurationSettings(settings) {
290
+ return settings.reduce((acc, setting) => {
291
+ switch (setting.key) {
292
+ case 'shopping-cart':
293
+ acc['shopping-cart'] = parseJsonSafely(setting.value, []);
294
+ break;
295
+ case 'navigation':
296
+ acc.navigation = parseJsonSafely(setting.value, {});
297
+ break;
298
+ case 'flows':
299
+ acc.flows = parseJsonSafely(setting.value, []);
300
+ break;
301
+ default:
302
+ acc[setting.key] = setting.value;
303
+ }
304
+ return acc;
305
+ }, {});
404
306
  }
405
- setAssetsState(assetsState) {
406
- this.assetsSubj$.next(assetsState);
307
+ addShoppingCartSettings(settings) {
308
+ // uniqBy removes items with the biggest index
309
+ const newSettings = uniqBy([...settings, ...this.shoppingCartSettings$.value], 'id');
310
+ this.shoppingCartSettings$.next(newSettings);
407
311
  }
408
- get quoteDraft$() {
409
- return combineLatest([this.quoteSubj$, this.context.resolve$()]).pipe(map(() => this.quoteDraft), filter((quote) => Boolean(quote)), shareReplay());
312
+ }
313
+ RuntimeSettingsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, deps: [{ token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
314
+ RuntimeSettingsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService });
315
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, decorators: [{
316
+ type: Injectable
317
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationSettingsApiService }]; } });
318
+
319
+ class FlowInfoService {
320
+ get flow() {
321
+ if (!this.flowSubj$.value) {
322
+ throw new Error(`Flow not initialized yet`);
323
+ }
324
+ return this.flowSubj$.value;
410
325
  }
411
- get quoteDraft() {
412
- const quote = this.quoteSubj$.value;
413
- if (!quote) {
414
- return null;
326
+ get isFlowInitialized() {
327
+ return Boolean(this.flowSubj$.value);
328
+ }
329
+ get context() {
330
+ if (!this.contextSubj$.value) {
331
+ throw new Error('Context is not initialized yet!');
415
332
  }
416
- return {
417
- ...quote,
418
- context: this.context.resolve(),
419
- };
333
+ return { ...this.contextSubj$.value };
420
334
  }
421
- get currentState$() {
422
- return this.quoteDraft$.pipe(map(quote => quote.currentState));
335
+ get templates() {
336
+ return this.templatesSubj$.value;
423
337
  }
424
- get currentState() {
425
- return this.quoteDraft?.currentState ?? [];
338
+ get isFlowEngineInitialized$() {
339
+ return this.templates$.pipe(map$1(v => Boolean(v.FLOW_ENGINE)));
426
340
  }
427
- get isStandalone() {
428
- return this.flowInfoService.flow?.properties.standalone ?? false;
341
+ get isStateful() {
342
+ return !!this.flow?.properties.stateful;
429
343
  }
430
- get isStandalone$() {
431
- return this.flowInfoService.flow$.pipe(map(() => this.isStandalone));
344
+ constructor(runtimeSettingsService, templatesApiService, customizationService) {
345
+ this.runtimeSettingsService = runtimeSettingsService;
346
+ this.templatesApiService = templatesApiService;
347
+ this.customizationService = customizationService;
348
+ this.defaultTemplates = {
349
+ flowEngine: 'Flow Engine',
350
+ };
351
+ this.flowSubj$ = new BehaviorSubject(null);
352
+ this.templatesSubj$ = new BehaviorSubject({});
353
+ this.contextSubj$ = new BehaviorSubject(null);
354
+ this.flow$ = this.flowSubj$.asObservable();
355
+ this.templates$ = this.templatesSubj$.asObservable();
432
356
  }
433
- getInitialCurrentState() {
434
- return this.initialCurrentState;
357
+ cleanup() {
358
+ this.flowSubj$.next(null);
359
+ this.templatesSubj$.next({});
360
+ this.contextSubj$.next(null);
435
361
  }
436
- isEditMode$() {
437
- return this.context.resolve$().pipe(map(() => this.isEditMode()));
362
+ init$(flowId, routeQueryParams) {
363
+ return this.initFlow$(flowId, routeQueryParams).pipe(switchMap(() => this.initFlowTemplates$()));
438
364
  }
439
- isEditMode() {
440
- const context = this.context.resolve();
441
- if (context.mode === ConfigurationContextMode.ACCOUNT) {
442
- return true;
365
+ initFlow$(flowId, routeQueryParams) {
366
+ const flow = this.runtimeSettingsService.getConfigurationSettings()['flows']?.find(({ id }) => flowId === id);
367
+ if (!flow) {
368
+ this.flowSubj$.next(null);
369
+ throw new Error(`Flow with flowId=${flowId} is not defined`);
443
370
  }
444
- if (context.mode === ConfigurationContextMode.QUOTE) {
445
- return context.properties.Status === 'Draft';
371
+ const headerId = routeQueryParams['headerId'];
372
+ if (typeof headerId !== 'string') {
373
+ throw new Error(`Please provide 'headerId'`);
446
374
  }
447
- return false;
375
+ const mode = this.getFlowContextMode(headerId);
376
+ // Restrict if mode is not defined
377
+ if (mode == null) {
378
+ throw new Error('Mode is undefined');
379
+ }
380
+ this.contextSubj$.next({
381
+ ...flow.properties.queryParams,
382
+ ...routeQueryParams,
383
+ mode,
384
+ });
385
+ this.flowSubj$.next(flow);
386
+ return of(undefined);
448
387
  }
449
- markAsUpdated(quote) {
450
- if (quote?.context.properties['#mode'] === ConfigurationContextMode.ACCOUNT) {
451
- this.hasUnsavedChanges = !!quote && !quote.currentState.every(li => li.actionCode === 'EXIST');
388
+ initFlowTemplates$() {
389
+ return forkJoin([
390
+ this.templatesApiService.fetchTemplates$(),
391
+ this.customizationService?.getTemplates?.() ?? of([]),
392
+ ]).pipe(map$1(([templates, localTemplates]) => {
393
+ const newValue = {};
394
+ Object.entries({ ...this.defaultTemplates, ...(this.flow?.properties.templates ?? {}) }).forEach(([key, name]) => {
395
+ const type = this.remapTemplateName(key);
396
+ if (type) {
397
+ newValue[type] =
398
+ localTemplates.find(template => template.name === name && template.type === type) ??
399
+ templates.find(template => template.name === name && template.type === type);
400
+ }
401
+ });
402
+ this.templatesSubj$.next(newValue);
403
+ }));
404
+ }
405
+ remapTemplateName(templateType) {
406
+ switch (templateType) {
407
+ case 'flowEngine':
408
+ return UITemplateType.FLOW_ENGINE;
409
+ default:
410
+ break;
452
411
  }
453
- else {
454
- this.hasUnsavedChanges = !isEqual(this.initialCurrentState, quote?.currentState);
412
+ switch (templateType) {
413
+ case 'assets':
414
+ case 'shoppingCart':
415
+ // No separate Assets template at the moment
416
+ return UITemplateType.SHOPPING_CART;
417
+ case 'catalog':
418
+ return UITemplateType.CATALOG;
419
+ case 'guidedSelling':
420
+ return UITemplateType.GUIDED_SELLING;
421
+ case 'flowHeader':
422
+ return UITemplateType.FLOW_HEADER;
423
+ default:
424
+ break;
425
+ }
426
+ return undefined;
427
+ }
428
+ getFlowContextMode(headerId) {
429
+ const objectName = SalesforceIdUtils.getSfObjectNameById(headerId);
430
+ if (!objectName) {
431
+ return;
455
432
  }
433
+ return objectName.toUpperCase();
456
434
  }
457
435
  }
458
- QuoteDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, deps: [{ token: ContextService }, { token: FlowInfoService }, { token: i1.AccountApiService }, { token: i1.QuoteApiService }], target: i0.ɵɵFactoryTarget.Injectable });
459
- QuoteDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService });
460
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, decorators: [{
436
+ FlowInfoService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService, deps: [{ token: RuntimeSettingsService }, { token: i2.UITemplatesApiService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
437
+ FlowInfoService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService });
438
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowInfoService, decorators: [{
461
439
  type: Injectable
462
- }], ctorParameters: function () { return [{ type: ContextService }, { type: FlowInfoService }, { type: i1.AccountApiService }, { type: i1.QuoteApiService }]; } });
440
+ }], ctorParameters: function () { return [{ type: RuntimeSettingsService }, { type: i2.UITemplatesApiService }, { type: undefined, decorators: [{
441
+ type: Optional
442
+ }, {
443
+ type: Inject,
444
+ args: [FLOW_CUSTOMIZATION]
445
+ }] }]; } });
463
446
 
464
- class FlowStateService {
465
- constructor(contextService, quoteDraftService, flowInfoService, flowConfiguration, processorsApiService, flowStateApiService, quoteApiService, toastService, customizationService) {
466
- this.contextService = contextService;
467
- this.quoteDraftService = quoteDraftService;
468
- this.flowInfoService = flowInfoService;
469
- this.flowConfiguration = flowConfiguration;
470
- this.processorsApiService = processorsApiService;
471
- this.flowStateApiService = flowStateApiService;
472
- this.quoteApiService = quoteApiService;
473
- this.toastService = toastService;
474
- this.customizationService = customizationService;
475
- this.NOT_INITIALIZED = Symbol();
476
- this.EXECUTION_BUFFER_TIME = 100;
477
- this.executedFunctions = {};
478
- this.stateId$ = new BehaviorSubject(null);
479
- this.initialStatefulData = {};
480
- this.trackedStatefulChangesMap = new Map();
481
- this.processors = {};
482
- this.subscriptions = {};
483
- this.flowStore = {};
484
- this.executionInProgress$ = new BehaviorSubject(false);
485
- this.statefulRequestStream$ = new Subject();
486
- this.cleanup$ = new Subject();
487
- this.statefulExecutionRequest$ = this.initBufferedRequest$();
488
- /*
489
- In stateless mode watch QuoteDraft changes and call executeRequest so that
490
- all subscriptions get their updates according to updated QuoteDraft
491
- */
492
- this.isInitialized$()
493
- .pipe(filter$1(Boolean), filter$1(() => !this.getFlowSafe().properties.stateful), switchMap(() => this.flowConfiguration.updated$), switchMap(() => this.executeRequest$({}, true)))
494
- .subscribe();
495
- this.charges$ = this.flowInfoService.flow$.pipe(filter$1(isDefined), switchMap(() => {
496
- if (this.flowInfoService.isLegacy) {
497
- return this.quoteDraftService.quoteDraft$.pipe(map$1(quoteDraft => quoteDraft.charges));
498
- }
499
- else {
500
- return this.subscribe$(UITemplateType.FLOW_ENGINE, 'CHARGES', null, {
501
- cold: true,
502
- }).pipe(map$1(response => (response.success ? response.result : {})));
503
- }
504
- }), shareReplay$1(1));
505
- this.charges$.subscribe();
506
- this.pricePlans$ = this.flowInfoService.flow$.pipe(filter$1(isDefined), switchMap(() => {
507
- if (this.flowInfoService.isLegacy) {
508
- return this.quoteDraftService.quoteDraft$.pipe(map$1(quoteDraft => quoteDraft.pricePlans));
509
- }
510
- else {
511
- return this.subscribe$(UITemplateType.FLOW_ENGINE, 'PRICE_PLANS', null, {
512
- cold: true,
513
- }).pipe(map$1(response => (response.success ? response.result : {})));
514
- }
515
- }), shareReplay$1(1));
516
- this.pricePlans$.subscribe();
517
- this.activeMetrics$ = this.flowInfoService.flow$.pipe(filter$1(isDefined), switchMap(() => {
518
- if (this.flowInfoService.isLegacy) {
519
- return this.quoteDraftService.quoteDraft$.pipe(map$1(quoteDraft => quoteDraft.activeMetrics));
520
- }
521
- else {
522
- return this.subscribe$(UITemplateType.FLOW_ENGINE, 'ACTIVE_METRICS', null, {
523
- cold: true,
524
- }).pipe(map$1(response => (response.success ? response.result : [])));
525
- }
526
- }), shareReplay$1(1));
527
- this.activeMetrics$.subscribe();
528
- this.isPriceListLocked$ = this.flowInfoService.flow$.pipe(filter$1(isDefined), switchMap(() => {
529
- if (this.flowInfoService.isLegacy) {
530
- return of(false);
531
- }
532
- else {
533
- return this.subscribe$(UITemplateType.FLOW_ENGINE, 'IS_PRICE_LIST_LOCKED', null, {
534
- cold: true,
535
- }).pipe(map$1(response => (response.success ? response.result : false)));
536
- }
537
- }), shareReplay$1(1));
538
- this.isPriceListLocked$.subscribe();
539
- }
540
- init$() {
541
- return this.initProcessors$().pipe(switchMap(() => {
542
- if (this.getFlowSafe().properties.stateful) {
543
- return this.initStateful$();
544
- }
545
- else {
546
- return this.initStateless$();
547
- }
548
- }));
549
- }
550
- cleanup() {
551
- Object.values(this.subscriptions).forEach(({ data$ }) => data$.complete());
552
- this.subscriptions = {};
553
- if (this.stateId$.value) {
554
- this.flowStateApiService.cancel(this.stateId$.value).subscribe();
555
- this.stateId$.next(null);
447
+ const findLineItem = (id, lineItems) => {
448
+ return findLineItemWithComparator(lineItems, (li) => li.id === id);
449
+ };
450
+ const findLineItemWithComparator = (lineItems, comparator) => {
451
+ let currentLevel = lineItems;
452
+ while (currentLevel.length) {
453
+ const found = currentLevel.find(comparator);
454
+ if (found) {
455
+ return found;
556
456
  }
557
- this.processors = {};
558
- this.flowStore = {};
559
- this.cleanup$.next();
560
- }
561
- get hasUnsavedChanges() {
562
- return this.getFlowSafe().properties.stateful
563
- ? Array.from(this.trackedStatefulChangesMap.values()).some(Boolean)
564
- : this.quoteDraftService.hasUnsavedChanges;
565
- }
566
- get stateId() {
567
- return this.stateId$.value;
568
- }
569
- get isExecutionInProgress$() {
570
- return this.executionInProgress$.asObservable();
571
- }
572
- isInitialized$() {
573
- return combineLatest([this.stateId$, this.quoteDraftService.isInitialized$]).pipe(map$1(values => values.some(Boolean)));
574
- }
575
- isInitialized() {
576
- return Boolean(this.stateId$.value) || this.quoteDraftService.isInitialized;
577
- }
578
- execute$(scope, exec) {
579
- const request = this.execToRequest(scope, exec);
580
- return this.executeRequest$(request).pipe(map$1(result => {
581
- // Keep only requested results
582
- const actualSelectors = Object.entries(result.selectors).reduce((trunk, [requestId, result]) => {
583
- if (exec.selectors?.[requestId]) {
584
- trunk[requestId] = result;
585
- }
586
- return trunk;
587
- }, {});
588
- return actualSelectors;
589
- }));
590
- }
591
- dispatch$(scope, action, inputData) {
592
- const exec = {
593
- actions: [{ name: action, inputData }],
594
- };
595
- const request = this.execToRequest(scope, exec);
596
- return this.executeRequest$(request).pipe(map$1(noop));
597
- }
598
- select$(scope, selectorName, inputData) {
599
- const requestId = this.generateRequestId(scope, selectorName, inputData);
600
- const request = this.execToRequest(scope, {
601
- selectors: {
602
- [requestId]: {
603
- name: selectorName,
604
- inputData,
605
- },
606
- },
607
- });
608
- return this.executeRequest$(request).pipe(map$1(response => response.selectors[requestId]));
457
+ currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
609
458
  }
610
- subscribe$(scope, selectorName, inputData, options) {
611
- const requestId = this.generateRequestId(scope, selectorName, inputData);
612
- let subscription = this.subscriptions[requestId];
613
- if (!subscription) {
614
- const request = this.execToRequest(scope, {
615
- selectors: {
616
- [requestId]: {
617
- name: selectorName,
618
- inputData,
619
- },
620
- },
621
- });
622
- subscription = {
623
- request,
624
- data$: new BehaviorSubject(this.NOT_INITIALIZED),
625
- };
626
- this.subscriptions[requestId] = subscription;
627
- if (options?.trackedChanges) {
628
- this.trackedStatefulChangesMap.set(requestId, false);
629
- }
630
- if (!options?.cold) {
631
- this.executeRequest$(request).subscribe();
632
- }
633
- }
634
- return subscription.data$.pipe(filter$1(data => data != this.NOT_INITIALIZED), map$1(data => data), finalize(() => {
635
- if (!this.subscriptions[requestId]?.data$.observed) {
636
- delete this.subscriptions[requestId];
459
+ return;
460
+ };
461
+ const insertLineItem = (lineItem, parentId, toInsert) => {
462
+ const insertData = lineItem.id === parentId ? [toInsert] : [];
463
+ return {
464
+ ...lineItem,
465
+ lineItems: [
466
+ ...insertData,
467
+ ...lineItem.lineItems.map(li => {
468
+ return insertLineItem(li, parentId, toInsert);
469
+ }),
470
+ ],
471
+ };
472
+ };
473
+ const removeLineItem = (lineItem, idToRemove) => {
474
+ return {
475
+ ...lineItem,
476
+ lineItems: lineItem.lineItems
477
+ .map(li => {
478
+ if (li.id === idToRemove) {
479
+ return;
637
480
  }
638
- }));
639
- }
640
- save$() {
641
- if (this.getFlowSafe().properties.stateful) {
642
- if (this.stateId$.value) {
643
- return this.flowStateApiService.save(this.stateId$.value).pipe(tap$1(() => {
644
- Array.from(this.trackedStatefulChangesMap.keys()).forEach(key => {
645
- this.trackedStatefulChangesMap.set(key, false);
646
- });
647
- }));
481
+ else if (li.lineItems.length) {
482
+ return removeLineItem(li, idToRemove);
648
483
  }
484
+ return li;
485
+ })
486
+ .filter(r => !!r),
487
+ };
488
+ };
489
+ const replaceLineItem = (lineItem, replaceTo, skipCardinalityCalculation = false) => {
490
+ if (lineItem.id === replaceTo.id) {
491
+ if (!skipCardinalityCalculation) {
492
+ return { ...recalculateCardinalityVariables(lineItem, replaceTo) };
649
493
  }
650
494
  else {
651
- const quoteDraft = this.quoteDraftService.quoteDraft;
652
- if (quoteDraft) {
653
- return this.quoteApiService.upsertQuote(quoteDraft).pipe(tap$1(({ versionId }) => {
654
- this.contextService.update({ properties: { VELOCE_PRISM__VersionId__c: versionId } });
655
- }));
656
- }
495
+ return { ...replaceTo };
657
496
  }
658
- return of({ quoteId: '' });
659
497
  }
660
- submit$() {
661
- if (this.getFlowSafe().properties.stateful) {
662
- if (this.stateId$.value) {
663
- return this.flowStateApiService.submit(this.stateId$.value);
664
- }
498
+ return {
499
+ ...lineItem,
500
+ lineItems: lineItem.lineItems.map(li => replaceLineItem(li, replaceTo, skipCardinalityCalculation)),
501
+ };
502
+ };
503
+ const collectCardinalityComputations = (portDomains) => {
504
+ const cardinalityComputations = new Map();
505
+ entries(portDomains).forEach(([key, portDomain]) => {
506
+ cardinalityComputations.set(key, portDomain.properties['cardinalityComputation'] === 'true');
507
+ });
508
+ return cardinalityComputations;
509
+ };
510
+ const calculateCardinalityVariables = (lineItems, cardinalityComputations) => {
511
+ const cardVars = new Map();
512
+ lineItems
513
+ .filter(({ port, type }) => !!port && !!type)
514
+ .forEach(li => {
515
+ if (cardinalityComputations.get(`${li.port}`)) {
516
+ const cardinalityVariableName = `#CV-${li.type}@${li.port}`;
517
+ cardVars.set(cardinalityVariableName, (cardVars.get(cardinalityVariableName) ?? 0) + li.qty);
665
518
  }
666
- else {
667
- const quoteDraft = this.quoteDraftService.quoteDraft;
668
- if (quoteDraft) {
669
- return this.quoteApiService.submitQuote(quoteDraft).pipe(tap$1(({ versionId }) => {
670
- this.contextService.update({ properties: { VELOCE_PRISM__VersionId__c: versionId } });
671
- }));
519
+ });
520
+ return cardVars;
521
+ };
522
+ const cardinalityRegexp = new RegExp('#CV-[a-zA-Z0-9_]+@(?<portName>[a-zA-Z0-9_]+)');
523
+ const recalculateCardinalityVariables = (original, updated) => {
524
+ const cardinalityComputations = collectCardinalityComputations(updated.portDomains ?? original.portDomains ?? {});
525
+ const cardinalityVariables = calculateCardinalityVariables(updated.lineItems, cardinalityComputations);
526
+ const originalCardinalityVariables = calculateCardinalityVariables(original.lineItems, cardinalityComputations);
527
+ originalCardinalityVariables.forEach((value, key) => {
528
+ const execArray = cardinalityRegexp.exec(key);
529
+ const portName = execArray?.groups?.['portName'];
530
+ if (!portName || cardinalityComputations.get(portName)) {
531
+ if (cardinalityVariables.get(key) === value) {
532
+ // no need to update cardinality if no changes
533
+ cardinalityVariables.delete(key);
534
+ }
535
+ else if (!cardinalityVariables.has(key)) {
536
+ // remove last item from port
537
+ cardinalityVariables.set(key, 0);
672
538
  }
673
539
  }
674
- return of({ quoteId: '' });
540
+ });
541
+ return {
542
+ ...updated,
543
+ attributes: upsertAttributes(updated.attributes, [...cardinalityVariables].map(([name, value]) => ({ name, value, cfgStatus: 'Changed' }))),
544
+ };
545
+ };
546
+ const mapAttributes = (attributes) => {
547
+ return attributes.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});
548
+ };
549
+ const getAttributes = (attributes, names = []) => {
550
+ const filtered = attributes.filter(({ name }) => names.includes(name));
551
+ return sortBy(filtered, [({ name }) => names.indexOf(name)]);
552
+ };
553
+ const upsertAttributes = (originalAttributes, attributesToUpsert) => {
554
+ return attributesToUpsert.reduce((acc, { name, value }) => {
555
+ const [origAttr] = getAttributes(acc, [name]);
556
+ return [
557
+ ...acc.filter(attr => attr.name !== name),
558
+ { ...(origAttr ?? { name, type: '' }), cfgStatus: origAttr ? 'Changed' : 'User', value },
559
+ ];
560
+ }, originalAttributes);
561
+ };
562
+ const patchAttributes = (rootLineItem, id, attrs, skipCardinalityCalculation = false) => {
563
+ const lineItem = findLineItem(id, [rootLineItem]);
564
+ if (!lineItem) {
565
+ return rootLineItem;
675
566
  }
676
- getFlowStore() {
677
- return this.flowStore;
567
+ const attributes = upsertAttributes(lineItem.attributes, attrs);
568
+ return replaceLineItem(rootLineItem, { ...lineItem, attributes }, skipCardinalityCalculation);
569
+ };
570
+ const getAttributeValue = (attributes, name) => attributes.find(attr => attr.name === name)?.value;
571
+ const generateLineItem = (port, type, parentId, attributes = [], lineItems = []) => {
572
+ return {
573
+ id: UUID.UUID(),
574
+ port,
575
+ type,
576
+ actionCode: 'ADD',
577
+ cfgStatus: 'New',
578
+ attributes: attributes.map(({ name, value }) => ({ cfgStatus: 'User', name, value })),
579
+ lineItems,
580
+ parentId,
581
+ qty: 1,
582
+ };
583
+ };
584
+ const getRecommendedPrices = (portDomain, type) => {
585
+ const domainType = portDomain.domainTypes.find(({ name }) => name === type);
586
+ const [net, list] = domainType?.recommendedPrices
587
+ ?.filter(({ chargeMethod }) => chargeMethod === 'ONE_TIME')
588
+ .reduce((acc, rp) => {
589
+ const [netPrice, listPrice] = acc;
590
+ return [netPrice + rp.netPrice, listPrice + rp.listPrice];
591
+ }, [0, 0]) ?? [0, 0];
592
+ return { net, list };
593
+ };
594
+ const getOriginParent = (lineItems, currentLineItem) => {
595
+ let target = currentLineItem;
596
+ while (target && target.rampInstanceId) {
597
+ target = lineItems.find(sub => sub.id === currentLineItem.rampInstanceId);
678
598
  }
679
- getOwnerIdByScope(scope) {
680
- const ownerId = this.flowInfoService.templates[scope]?.id;
681
- if (!ownerId) {
682
- throw `OwnerId is not found for scope ${scope}`;
683
- }
684
- return ownerId;
599
+ return target;
600
+ };
601
+ const assetPredicateFn = (lineItem, assetId) => {
602
+ if (!assetId) {
603
+ return false;
685
604
  }
686
- getScopeByOwnerId(id) {
687
- for (const template of Object.values(this.flowInfoService.templates)) {
688
- if (template.id === id) {
689
- return template.type;
690
- }
691
- }
692
- return;
693
- }
694
- execToRequest(scope, exec) {
695
- const ownerId = this.getOwnerIdByScope(scope);
696
- return {
697
- actions: exec.actions?.map(action => ({ apiName: action.name, ownerId, inputData: action.inputData ?? {} })),
698
- selectors: exec.selectors &&
699
- Object.entries(exec.selectors).reduce((trunk, [key, selector]) => ({
700
- ...trunk,
701
- [key]: { apiName: selector.name, ownerId, inputData: selector.inputData ?? {} },
702
- }), {}),
703
- };
704
- }
705
- executeRequest$(request, forceSubscriptions = false) {
706
- const fullRequest = cloneDeep(request);
707
- if (fullRequest.actions?.length || forceSubscriptions) {
708
- for (const subscription of Object.values(this.subscriptions)) {
709
- fullRequest.selectors = assign(fullRequest.selectors, subscription.request.selectors);
710
- }
711
- }
712
- const execution$ = this.getFlowSafe().properties.stateful
713
- ? this.executeStateful$(fullRequest)
714
- : this.executeStateless$(fullRequest);
715
- return execution$.pipe(tap$1(result => this.handleSelectorsResponse(result.selectors)));
716
- }
717
- handleSelectorsResponse(selectors) {
718
- Object.entries(selectors).forEach(([requestId, selectorResult]) => {
719
- if (!selectorResult.success) {
720
- this.toastService.add({ severity: ToastType.error, summary: selectorResult.errorMessage });
721
- }
722
- const subscription$ = this.subscriptions[requestId]?.data$;
723
- if (subscription$ && subscription$.value !== selectorResult) {
724
- this.checkStatefulChanges(requestId, selectorResult);
725
- subscription$.next(selectorResult);
726
- }
727
- });
728
- }
729
- initStateful$() {
730
- // Subscriptions
731
- this.subscribe$(UITemplateType.FLOW_ENGINE, 'CONTEXT', null, { cold: true })
732
- .pipe(tap$1(response => {
733
- if (response.success) {
734
- this.contextService.update(response.result);
735
- }
736
- }), takeUntil(this.cleanup$))
737
- .subscribe();
738
- const processorsList = flatten(Object.values(this.processors).map(ownerMap => Object.values(ownerMap ?? {})));
739
- const processors = processorsList.length ? processorsList : undefined;
740
- const selectors = Object.values(this.subscriptions)
741
- .map(({ request }) => request.selectors)
742
- .filter(isDefined)
743
- .reduce((trunk, selectors) => ({ ...trunk, ...selectors }), {});
744
- const request = this.getDefaultExecutionRequestDTO();
745
- return this.flowStateApiService
746
- .init({
747
- quoteId: this.contextService.resolve().headerId,
748
- params: this.flowInfoService.params ?? {},
749
- actionsOverride: processors?.filter(processor => processor.type === ConfigurationProcessorTypes.ACTION),
750
- selectorsOverride: processors?.filter(processor => processor.type === ConfigurationProcessorTypes.SELECTOR),
751
- selectors: { ...selectors, ...request.selectors },
752
- actions: request.actions,
753
- })
754
- .pipe(map$1(({ stateId, selectors }) => {
755
- this.handleSelectorsResponse(selectors);
756
- this.stateId$.next(stateId);
757
- }));
758
- }
759
- initBufferedRequest$() {
760
- return this.statefulRequestStream$.pipe(buffer(this.statefulRequestStream$.pipe(debounceTime(this.EXECUTION_BUFFER_TIME))), switchMap(requests => {
761
- if (!this.stateId$.value) {
762
- throw 'Stateful session is not initialized';
763
- }
764
- // merge buffered requests
765
- const request = {
766
- actions: requests.flatMap(({ actions }) => actions).filter(isDefined),
767
- selectors: requests
768
- .map(({ selectors }) => selectors)
769
- .filter(isDefined)
770
- .reduce((acc, selectorsMap) => Object.assign(acc, selectorsMap), {}),
771
- };
772
- this.executionInProgress$.next(true);
773
- return this.flowStateApiService.execute(this.stateId$.value, request);
774
- }), tap$1(({ stateId }) => this.stateId$.next(stateId)), share(), tap$1(() => this.executionInProgress$.next(false)), catchError(e => {
775
- this.executionInProgress$.next(false);
776
- return throwError(() => e);
777
- }));
778
- }
779
- executeStateful$(request) {
780
- return this.executionInProgress$.pipe(filter$1(inProgress => !inProgress), take$1(1), switchMap(() =>
781
- // make sure stream switches to statefulExecutionRequest$ before pushing an execution request
782
- combineLatest([
783
- this.statefulExecutionRequest$,
784
- of(undefined).pipe(tap$1(() => this.statefulRequestStream$.next(request))),
785
- ])), map$1(([response]) => response), take$1(1));
786
- }
787
- initStateless$() {
788
- const { headerId } = this.contextService.resolve();
789
- return this.quoteDraftService.init(headerId, this.flowInfoService.params ?? {}).pipe(tap$1(() => {
790
- const assets = this.quoteDraftService.assetsState;
791
- if (assets) {
792
- this.flowStore = { ...this.flowStore, assets };
793
- }
794
- }), switchMap(() => {
795
- if (this.flowInfoService.isLegacy) {
796
- return of(null);
797
- }
798
- return this.executeRequest$(this.getDefaultExecutionRequestDTO());
799
- }), switchMap(() => this.calculate$()), tap$1(() => this.quoteDraftService.finalizeInit()), map$1(noop));
800
- }
801
- calculate$() {
802
- const flowState = this.quoteDraftService.quoteDraft;
803
- if (!flowState) {
804
- return of(undefined);
805
- }
806
- /*
807
- Don't execute procedures when:
808
- * Initializing a standalone product configuration UI, as procedure is execute in /price call
809
- * Initializing an empty account (account with no assets)
810
- */
811
- const isEmptyAccountMode = this.contextService.mode === ConfigurationContextMode.ACCOUNT &&
812
- !this.quoteDraftService.hasProducts &&
813
- !this.quoteDraftService.hasAssets &&
814
- !this.quoteDraftService.quoteDraft?.initialState.length;
815
- if (this.quoteDraftService.isStandalone || isEmptyAccountMode) {
816
- return of(undefined);
817
- }
818
- return this.flowConfiguration.calculate$(flowState);
819
- }
820
- executeStateless$(request) {
821
- this.executionInProgress$.next(true);
822
- return of(undefined).pipe(tap$1(() => this.executeStatelessActions(request)), switchMap(() => {
823
- /*
824
- Skip price calculation in case
825
- 1. No actions in the request
826
- 2. Initialization process execution (state not initialized yet)
827
- */
828
- if (!request.actions?.length || !this.isInitialized()) {
829
- return of(undefined);
830
- }
831
- else {
832
- return this.calculate$();
833
- }
834
- }), map$1(() => this.executeStatelessSelectors(request)), tap$1(() => this.executionInProgress$.next(false)), catchError(e => {
835
- this.executionInProgress$.next(false);
836
- return throwError(() => e);
837
- }));
838
- }
839
- executeStatelessActions(request) {
840
- if (!this.quoteDraftService.quoteDraft || !request.actions?.length) {
841
- return;
842
- }
843
- let flowState = this.quoteDraftService.quoteDraft;
844
- request.actions.forEach(action => {
845
- try {
846
- flowState = this.executeActionScript(flowState, action) ?? flowState;
847
- }
848
- catch (e) {
849
- console.error(e);
850
- this.toastService.add({ severity: ToastType.error, summary: String(e) });
851
- throw e;
852
- }
853
- });
854
- this.quoteDraftService.updateQuoteDraft(flowState);
855
- }
856
- executeStatelessSelectors(request) {
857
- if (!this.quoteDraftService.quoteDraft) {
858
- throw 'QuoteDraft is not initialized';
859
- }
860
- const flowState = this.quoteDraftService.quoteDraft;
861
- return EntityUtil.entries(request.selectors ?? {}).reduce((result, [key, selector]) => {
862
- try {
863
- result.selectors[key] = {
864
- success: true,
865
- result: this.executeSelectorScript(flowState, selector),
866
- };
867
- }
868
- catch (e) {
869
- console.error(e);
870
- result.selectors[key] = {
871
- success: false,
872
- errorMessage: String(e),
873
- };
874
- }
875
- return result;
876
- }, { stateId: '', selectors: {} });
877
- }
878
- getFlowSafe() {
879
- if (!this.flowInfoService.flow) {
880
- throw 'Flow is not defined';
881
- }
882
- return this.flowInfoService.flow;
883
- }
884
- initProcessors$() {
885
- const hasOverrides = Boolean(this.customizationService?.getTemplateConfigurationProcessors);
886
- const flow = this.getFlowSafe();
887
- if (flow.properties.stateful && !hasOverrides) {
888
- // Skip initialization as backend will take processors from SF
889
- return of(undefined);
890
- }
891
- const owners$ = Object.values(this.flowInfoService.templates)
892
- .map(template => {
893
- if (!template) {
894
- return;
895
- }
896
- const localProcessors$ = this.customizationService?.getTemplateConfigurationProcessors?.(template.name) ?? of(null);
897
- return localProcessors$.pipe(switchMap(processors => processors ? of(processors) : this.processorsApiService.fetchConfigurationProcessors$(template.id)), tap$1(processors => {
898
- const processorsMap = processors.reduce((acc, p) => {
899
- acc[p.apiName] = p;
900
- return acc;
901
- }, {});
902
- this.processors[template.id] = processorsMap;
903
- }));
904
- })
905
- .filter(isDefined);
906
- if (!owners$.length) {
907
- return of(undefined);
908
- }
909
- return forkJoin(owners$).pipe(map$1(noop));
910
- }
911
- executeActionScript(request, executable) {
912
- const configurationProcessor = this.processors[executable.ownerId]?.[executable.apiName];
913
- if (!configurationProcessor?.script) {
914
- const scope = this.getScopeByOwnerId(executable.ownerId);
915
- const scopeText = scope ? ` in ${scope}` : '';
916
- throw `ConfigurationProcessor ${executable.apiName}${scopeText} not found`;
917
- }
918
- return this.executeProcessorScript(request, configurationProcessor, executable.inputData);
919
- }
920
- executeSelectorScript(request, executable) {
921
- const configurationProcessor = this.processors[executable.ownerId]?.[executable.apiName];
922
- if (!configurationProcessor?.script) {
923
- const scope = this.getScopeByOwnerId(executable.ownerId);
924
- const scopeText = scope ? ` in ${scope}` : '';
925
- throw `ConfigurationProcessor ${executable.apiName}${scopeText} not found`;
926
- }
927
- return this.executeProcessorScript(request, configurationProcessor, executable.inputData);
928
- }
929
- executeProcessorScript(request, configurationProcessor, inputData) {
930
- const scope = this.getScopeByOwnerId(configurationProcessor.ownerId ?? '');
931
- let functionToExecute = this.executedFunctions[scope + configurationProcessor.apiName];
932
- if (!functionToExecute) {
933
- const script = `${configurationProcessor.script}\nreturn transform;`;
934
- const sourceMap = `\n//# sourceURL=${scope ? scope + '/' : ''}${configurationProcessor.apiName}.js`;
935
- functionToExecute = new Function(script + sourceMap)();
936
- this.executedFunctions[scope + configurationProcessor.apiName] = functionToExecute;
937
- }
938
- return functionToExecute({
939
- request,
940
- inputData,
941
- flowStore: this.flowStore,
942
- });
943
- }
944
- generateRequestId(scope, selectorName, inputData) {
945
- const inputDataHash = UUID.hex(JSON.stringify(inputData) || '').slice(0, 8);
946
- return `${scope}/${selectorName}/${inputDataHash}`;
947
- }
948
- getDefaultExecutionRequestDTO() {
949
- const request = {
950
- actions: [],
951
- selectors: {},
952
- };
953
- if (this.getFlowSafe().properties.standalone) {
954
- return request;
955
- }
956
- const flowEngineTemplateId = this.getOwnerIdByScope(UITemplateType.FLOW_ENGINE);
957
- request.actions?.push({
958
- apiName: 'UPDATE_CONTEXT_PROPERTIES',
959
- ownerId: flowEngineTemplateId,
960
- inputData: this.contextService.resolve().properties,
605
+ return lineItem.assetId === assetId || lineItem.openOrderLineItemId === assetId;
606
+ };
607
+ const multiplyLineItems = (lineItem, qty, split) => {
608
+ if (split) {
609
+ const unifyIds = (lineItem) => ({
610
+ ...lineItem,
611
+ id: UUID.UUID(),
612
+ lineItems: lineItem.lineItems.map(unifyIds),
961
613
  });
962
- return request;
614
+ return map$2(new Array(qty), () => unifyIds(lineItem));
963
615
  }
964
- checkStatefulChanges(requestId, selectorResult) {
965
- if (this.trackedStatefulChangesMap.has(requestId)) {
966
- if (!this.initialStatefulData[requestId]) {
967
- this.initialStatefulData[requestId] = selectorResult;
968
- }
969
- const hasChanges = !isEqual(this.initialStatefulData[requestId], selectorResult);
970
- this.trackedStatefulChangesMap.set(requestId, hasChanges);
971
- }
972
- }
973
- }
974
- FlowStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService, deps: [{ token: ContextService }, { token: QuoteDraftService }, { token: FlowInfoService }, { token: FlowConfigurationService }, { token: i1.ConfigurationProcessorsApiService }, { token: i1.FlowStateApiService }, { token: i1.QuoteApiService }, { token: i6.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
975
- FlowStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService });
976
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService, decorators: [{
977
- type: Injectable
978
- }], ctorParameters: function () { return [{ type: ContextService }, { type: QuoteDraftService }, { type: FlowInfoService }, { type: FlowConfigurationService }, { type: i1.ConfigurationProcessorsApiService }, { type: i1.FlowStateApiService }, { type: i1.QuoteApiService }, { type: i6.ToastService }, { type: undefined, decorators: [{
979
- type: Optional
980
- }, {
981
- type: Inject,
982
- args: [FLOW_CUSTOMIZATION]
983
- }] }]; } });
984
-
985
- const findLineItem = (id, lineItems) => {
986
- return findLineItemWithComparator(lineItems, (li) => li.id === id);
987
- };
988
- const findLineItemWithComparator = (lineItems, comparator) => {
989
- let currentLevel = lineItems;
990
- while (currentLevel.length) {
991
- const found = currentLevel.find(comparator);
992
- if (found) {
993
- return found;
994
- }
995
- currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
996
- }
997
- return;
998
- };
999
- const insertLineItem = (lineItem, parentId, toInsert) => {
1000
- const insertData = lineItem.id === parentId ? [toInsert] : [];
1001
- return {
1002
- ...lineItem,
1003
- lineItems: [
1004
- ...insertData,
1005
- ...lineItem.lineItems.map(li => {
1006
- return insertLineItem(li, parentId, toInsert);
1007
- }),
1008
- ],
1009
- };
1010
- };
1011
- const removeLineItem = (lineItem, idToRemove) => {
1012
- return {
1013
- ...lineItem,
1014
- lineItems: lineItem.lineItems
1015
- .map(li => {
1016
- if (li.id === idToRemove) {
1017
- return;
1018
- }
1019
- else if (li.lineItems.length) {
1020
- return removeLineItem(li, idToRemove);
1021
- }
1022
- return li;
1023
- })
1024
- .filter(r => !!r),
1025
- };
1026
- };
1027
- const replaceLineItem = (lineItem, replaceTo, skipCardinalityCalculation = false) => {
1028
- if (lineItem.id === replaceTo.id) {
1029
- if (!skipCardinalityCalculation) {
1030
- return { ...recalculateCardinalityVariables(lineItem, replaceTo) };
1031
- }
1032
- else {
1033
- return { ...replaceTo };
1034
- }
1035
- }
1036
- return {
1037
- ...lineItem,
1038
- lineItems: lineItem.lineItems.map(li => replaceLineItem(li, replaceTo, skipCardinalityCalculation)),
1039
- };
1040
- };
1041
- const collectCardinalityComputations = (portDomains) => {
1042
- const cardinalityComputations = new Map();
1043
- entries(portDomains).forEach(([key, portDomain]) => {
1044
- cardinalityComputations.set(key, portDomain.properties['cardinalityComputation'] === 'true');
1045
- });
1046
- return cardinalityComputations;
1047
- };
1048
- const calculateCardinalityVariables = (lineItems, cardinalityComputations) => {
1049
- const cardVars = new Map();
1050
- lineItems
1051
- .filter(({ port, type }) => !!port && !!type)
1052
- .forEach(li => {
1053
- if (cardinalityComputations.get(`${li.port}`)) {
1054
- const cardinalityVariableName = `#CV-${li.type}@${li.port}`;
1055
- cardVars.set(cardinalityVariableName, (cardVars.get(cardinalityVariableName) ?? 0) + li.qty);
1056
- }
1057
- });
1058
- return cardVars;
1059
- };
1060
- const cardinalityRegexp = new RegExp('#CV-[a-zA-Z0-9_]+@(?<portName>[a-zA-Z0-9_]+)');
1061
- const recalculateCardinalityVariables = (original, updated) => {
1062
- const cardinalityComputations = collectCardinalityComputations(updated.portDomains ?? original.portDomains ?? {});
1063
- const cardinalityVariables = calculateCardinalityVariables(updated.lineItems, cardinalityComputations);
1064
- const originalCardinalityVariables = calculateCardinalityVariables(original.lineItems, cardinalityComputations);
1065
- originalCardinalityVariables.forEach((value, key) => {
1066
- const execArray = cardinalityRegexp.exec(key);
1067
- const portName = execArray?.groups?.['portName'];
1068
- if (!portName || cardinalityComputations.get(portName)) {
1069
- if (cardinalityVariables.get(key) === value) {
1070
- // no need to update cardinality if no changes
1071
- cardinalityVariables.delete(key);
1072
- }
1073
- else if (!cardinalityVariables.has(key)) {
1074
- // remove last item from port
1075
- cardinalityVariables.set(key, 0);
1076
- }
1077
- }
1078
- });
1079
- return {
1080
- ...updated,
1081
- attributes: upsertAttributes(updated.attributes, [...cardinalityVariables].map(([name, value]) => ({ name, value, cfgStatus: 'Changed' }))),
1082
- };
1083
- };
1084
- const mapAttributes = (attributes) => {
1085
- return attributes.reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {});
1086
- };
1087
- const getAttributes = (attributes, names = []) => {
1088
- const filtered = attributes.filter(({ name }) => names.includes(name));
1089
- return sortBy(filtered, [({ name }) => names.indexOf(name)]);
1090
- };
1091
- const upsertAttributes = (originalAttributes, attributesToUpsert) => {
1092
- return attributesToUpsert.reduce((acc, { name, value }) => {
1093
- const [origAttr] = getAttributes(acc, [name]);
1094
- return [
1095
- ...acc.filter(attr => attr.name !== name),
1096
- { ...(origAttr ?? { name, type: '' }), cfgStatus: origAttr ? 'Changed' : 'User', value },
1097
- ];
1098
- }, originalAttributes);
1099
- };
1100
- const patchAttributes = (rootLineItem, id, attrs, skipCardinalityCalculation = false) => {
1101
- const lineItem = findLineItem(id, [rootLineItem]);
1102
- if (!lineItem) {
1103
- return rootLineItem;
1104
- }
1105
- const attributes = upsertAttributes(lineItem.attributes, attrs);
1106
- return replaceLineItem(rootLineItem, { ...lineItem, attributes }, skipCardinalityCalculation);
1107
- };
1108
- const getAttributeValue = (attributes, name) => attributes.find(attr => attr.name === name)?.value;
1109
- const generateLineItem = (port, type, parentId, attributes = [], lineItems = []) => {
1110
- return {
1111
- id: UUID.UUID(),
1112
- port,
1113
- type,
1114
- actionCode: 'ADD',
1115
- cfgStatus: 'New',
1116
- attributes: attributes.map(({ name, value }) => ({ cfgStatus: 'User', name, value })),
1117
- lineItems,
1118
- parentId,
1119
- qty: 1,
1120
- };
1121
- };
1122
- const getRecommendedPrices = (portDomain, type) => {
1123
- const domainType = portDomain.domainTypes.find(({ name }) => name === type);
1124
- const [net, list] = domainType?.recommendedPrices
1125
- ?.filter(({ chargeMethod }) => chargeMethod === 'ONE_TIME')
1126
- .reduce((acc, rp) => {
1127
- const [netPrice, listPrice] = acc;
1128
- return [netPrice + rp.netPrice, listPrice + rp.listPrice];
1129
- }, [0, 0]) ?? [0, 0];
1130
- return { net, list };
1131
- };
1132
- const getOriginParent = (lineItems, currentLineItem) => {
1133
- let target = currentLineItem;
1134
- while (target && target.rampInstanceId) {
1135
- target = lineItems.find(sub => sub.id === currentLineItem.rampInstanceId);
1136
- }
1137
- return target;
1138
- };
1139
- const assetPredicateFn = (lineItem, assetId) => {
1140
- if (!assetId) {
1141
- return false;
1142
- }
1143
- return lineItem.assetId === assetId || lineItem.openOrderLineItemId === assetId;
1144
- };
1145
- const multiplyLineItems = (lineItem, qty, split) => {
1146
- if (split) {
1147
- const unifyIds = (lineItem) => ({
1148
- ...lineItem,
1149
- id: UUID.UUID(),
1150
- lineItems: lineItem.lineItems.map(unifyIds),
1151
- });
1152
- return map$2(new Array(qty), () => unifyIds(lineItem));
1153
- }
1154
- else {
1155
- return [
1156
- {
1157
- ...lineItem,
1158
- qty: qty,
1159
- },
1160
- ];
616
+ else {
617
+ return [
618
+ {
619
+ ...lineItem,
620
+ qty: qty,
621
+ },
622
+ ];
1161
623
  }
1162
624
  };
1163
625
  const isTechnicalAttribute = (name) => {
@@ -1188,392 +650,32 @@ var lineItem_utils = /*#__PURE__*/Object.freeze({
1188
650
  replaceLineItem: replaceLineItem,
1189
651
  upsertAttributes: upsertAttributes
1190
652
  });
1191
-
1192
- class RuntimeSettingsService {
1193
- constructor(configurationSettingsApiService) {
1194
- this.configurationSettingsApiService = configurationSettingsApiService;
1195
- this.configurationSettings$ = new BehaviorSubject({});
1196
- this.currencySettings$ = new BehaviorSubject({
1197
- iso: DEFAULT_CURRENCY_ISO_CODE,
1198
- symbol: DEFAULT_CURRENCY_SYMBOL,
1199
- });
1200
- this.shoppingCartSettings$ = new BehaviorSubject([]);
1201
- this.getCurrencySymbol = (locale, currency) => {
1202
- return (0)
1203
- .toLocaleString(locale, { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0 })
1204
- .replace(/\d/g, '')
1205
- .trim();
1206
- };
1207
- }
1208
- create() {
1209
- return this.configurationSettingsApiService.fetchSettings().pipe(map$1(settings => this.parseConfigurationSettings(settings)), tap$1(configurationSettings => {
1210
- this.configurationSettings$.next(configurationSettings);
1211
- this.addShoppingCartSettings(configurationSettings['shopping-cart'] ?? []);
1212
- this.formattingSettings = this.getFormattingSettings();
1213
- }), map$1(() => undefined));
1214
- }
1215
- initCurrency(iso) {
1216
- if (iso) {
1217
- const symbol = this.getCurrencySymbol('en-US', iso);
1218
- this.currencySettings$.next({ iso, symbol });
1219
- if (this.formattingSettings) {
1220
- this.formattingSettings.currencySymbol = symbol;
1221
- }
1222
- }
1223
- }
1224
- getFormattingSettings() {
1225
- if (this.formattingSettings) {
1226
- return this.formattingSettings;
1227
- }
1228
- const shoppingCartSettings = this.getConfigurationSettings()['shopping-cart']?.reduce((acc, setting) => {
1229
- return { ...acc, [setting.id]: setting.properties };
1230
- }, {});
1231
- const currencySettings = this.getCurrencySettings();
1232
- const dateFormat = (validateDateFormat(shoppingCartSettings?.DATE_FORMAT ?? '') && shoppingCartSettings?.DATE_FORMAT) ||
1233
- DEFAULT_DATE_FORMAT;
1234
- const decimalSeparator = shoppingCartSettings?.DECIMAL_SEPARATOR;
1235
- const thousandsSeparator = shoppingCartSettings?.THOUSANDS_SEPARATOR;
1236
- // the number of decimal places can be 0
1237
- const priceScale = shoppingCartSettings?.PRICE_SCALE;
1238
- const decimalsCount = priceScale !== null && priceScale !== '' && !isNaN(Number(priceScale)) && Number(priceScale) >= 0
1239
- ? Number(priceScale)
1240
- : DEFAULT_DECIMALS_COUNT;
1241
- const actionCodeSettings = shoppingCartSettings?.STATUS_LABEL;
1242
- return {
1243
- currencySymbol: currencySettings.symbol,
1244
- dateFormats: getSupportedDateFormats(dateFormat),
1245
- decimalsCount,
1246
- decimalSeparator: decimalSeparator !== undefined && ['.', ','].includes(decimalSeparator)
1247
- ? decimalSeparator
1248
- : DEFAULT_DECIMAL_SEPARATOR,
1249
- // thousands separator can be a blank value, so it can also be null
1250
- thousandsSeparator: thousandsSeparator !== undefined && ['.', ',', '', null].includes(thousandsSeparator)
1251
- ? thousandsSeparator || ''
1252
- : DEFAULT_THOUSANDS_SEPARATOR,
1253
- actionCodeLabels: actionCodeSettings?.length
1254
- ? actionCodeSettings.reduce((result, setting) => ({ ...result, [setting.status_label]: setting.custom_label }), {})
1255
- : DEFAULT_ACTION_CODE_LABELS,
1256
- };
1257
- }
1258
- getConfigurationSettings() {
1259
- return this.configurationSettings$.value;
1260
- }
1261
- getShoppingCartSettings() {
1262
- return this.shoppingCartSettings$.value;
1263
- }
1264
- getCurrencySettings() {
1265
- return this.currencySettings$.value;
1266
- }
1267
- parseConfigurationSettings(settings) {
1268
- return settings.reduce((acc, setting) => {
1269
- switch (setting.key) {
1270
- case 'shopping-cart':
1271
- acc['shopping-cart'] = parseJsonSafely(setting.value, []);
1272
- break;
1273
- case 'navigation':
1274
- acc.navigation = parseJsonSafely(setting.value, {});
1275
- break;
1276
- case 'flows':
1277
- acc.flows = parseJsonSafely(setting.value, []);
1278
- break;
1279
- default:
1280
- acc[setting.key] = setting.value;
1281
- }
1282
- return acc;
1283
- }, {});
1284
- }
1285
- addShoppingCartSettings(settings) {
1286
- // uniqBy removes items with the biggest index
1287
- const newSettings = uniqBy([...settings, ...this.shoppingCartSettings$.value], 'id');
1288
- this.shoppingCartSettings$.next(newSettings);
1289
- }
1290
- }
1291
- RuntimeSettingsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, deps: [{ token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1292
- RuntimeSettingsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService });
1293
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, decorators: [{
1294
- type: Injectable
1295
- }], ctorParameters: function () { return [{ type: i1.ConfigurationSettingsApiService }]; } });
1296
-
1297
- class LineItemWorker {
1298
- constructor(src) {
1299
- this.li = { ...src };
1300
- }
1301
- insert(parentId, toInsert) {
1302
- return new LineItemWorker(insertLineItem(this.li, parentId, toInsert));
1303
- }
1304
- remove(id) {
1305
- return new LineItemWorker(removeLineItem(this.li, id));
1306
- }
1307
- replace(toReplace, skipCardinalityCalculation = false) {
1308
- return new LineItemWorker(replaceLineItem(this.li, toReplace, skipCardinalityCalculation));
1309
- }
1310
- patchAttribute(attrs, id, skipCardinalityCalculation = false) {
1311
- return new LineItemWorker(patchAttributes(this.li, id ?? this.li.id, attrs, skipCardinalityCalculation));
1312
- }
1313
- }
1314
-
1315
- function extractMetadata(uiDefinition) {
1316
- return omit(uiDefinition, [
1317
- 'children',
1318
- 'pages',
1319
- 'components',
1320
- ]);
1321
- }
1322
-
1323
- class ConfigurationService {
1324
- constructor(quoteDraftService, runtimeService, contextService, configurationApiService, messageService, dialogService, runtimeSettings, flowInfoService) {
1325
- this.quoteDraftService = quoteDraftService;
1326
- this.runtimeService = runtimeService;
1327
- this.contextService = contextService;
1328
- this.configurationApiService = configurationApiService;
1329
- this.messageService = messageService;
1330
- this.dialogService = dialogService;
1331
- this.runtimeSettings = runtimeSettings;
1332
- this.flowInfoService = flowInfoService;
1333
- this.mode = ConfigurationMode.SEARCH;
1334
- this.configurationState = new BehaviorSubject(null);
1335
- this.previousConfigurationState = new BehaviorSubject(null);
1336
- this.isLoadingSubj$ = new BehaviorSubject(false);
1337
- this.isLoading$ = this.isLoadingSubj$.asObservable();
1338
- this.hasUnsavedChanges = false;
1339
- }
1340
- reset() {
1341
- this.hasUnsavedChanges = false;
1342
- this.runtimeService.reset();
1343
- this.configurableRamp = undefined;
1344
- this.configurationState.next(null);
1345
- this.previousConfigurationState.next(null);
1346
- }
1347
- patch$(lineItem, options) {
1348
- const source = this.getSnapshot();
1349
- if (!source) {
1350
- return throwError(() => new Error(`Source LineItem not found`));
1351
- }
1352
- const skipCardinalityCalculation = options?.skipCardinalityCalculation || this.contextSnapshot.properties['#skipCardinalityCalculation'] === 'true';
1353
- this.configurableRamp = new LineItemWorker(source).replace(lineItem, skipCardinalityCalculation).li;
1354
- return this.configure().pipe(catchError$1(error => {
1355
- console.error(error);
1356
- if (!this.runtimeService.uiDefinitionProperties.suppressToastMessages) {
1357
- this.messageService.add({ severity: 'error', summary: error });
1358
- }
1359
- // bounce back if configuration call has failed
1360
- const prevState = this.configurationState.value;
1361
- this.configurationState.next(prevState ? { ...prevState } : null);
1362
- return throwError(() => error);
1363
- }), tap(() => {
1364
- if (!this.hasUnsavedChanges) {
1365
- this.hasUnsavedChanges = true;
1366
- }
1367
- }));
1368
- }
1369
- patch(lineItem, options) {
1370
- this.patch$(lineItem, options).subscribe();
1371
- }
1372
- setConfigurableRamp(lineItem) {
1373
- this.configurableRamp = lineItem;
1374
- }
1375
- get() {
1376
- return this.configurationState.pipe(map(state => state?.lineItem), shareReplay$1());
1377
- }
1378
- getSnapshot() {
1379
- return this.configurationState.value?.lineItem ? { ...this.configurationState.value?.lineItem } : undefined;
1380
- }
1381
- getRuntimeModel() {
1382
- const runtimeModel = this.runtimeService.runtimeModel;
1383
- if (!runtimeModel) {
1384
- throw new Error('Runtime model not initialized');
1385
- }
1386
- return runtimeModel;
1387
- }
1388
- getRuntimeContext() {
1389
- const runtimeContext = this.runtimeService.runtimeContext;
1390
- if (!runtimeContext) {
1391
- throw new Error('Runtime context not initialized');
1392
- }
1393
- return runtimeContext;
1394
- }
1395
- get state$() {
1396
- return this.configurationState.asObservable();
1397
- }
1398
- get stateSnapshot() {
1399
- return this.configurationState.value;
1400
- }
1401
- get previousStateSnapshot() {
1402
- return this.previousConfigurationState.value;
1403
- }
1404
- get contextSnapshot() {
1405
- return this.contextService.resolve();
1406
- }
1407
- get context$() {
1408
- return this.contextService.resolve$();
1409
- }
1410
- get charges$() {
1411
- return this.configurationState.pipe(map(state => state?.charges ?? {}));
1412
- }
1413
- get chargesSnapshot() {
1414
- return this.configurationState.value?.charges ?? {};
1415
- }
1416
- get pricePlans$() {
1417
- return this.configurationState.pipe(map(state => state?.pricePlans ?? {}));
1418
- }
1419
- get pricePlansSnapshot() {
1420
- return this.configurationState.value?.pricePlans ?? {};
1421
- }
1422
- get procedureContext$() {
1423
- return this.configurationState.pipe(map(state => state?.procedureContext ?? {}));
1424
- }
1425
- get procedureContextSnapshot() {
1426
- return this.configurationState.value?.procedureContext ?? {};
1427
- }
1428
- configure() {
1429
- return this.configureRequest$(this.generateRequest());
1430
- }
1431
- configureRequest$(configurationRequest) {
1432
- const runtimeContext = this.getRuntimeContext();
1433
- const runtimeModel = this.getRuntimeModel();
1434
- const uiDefinitionProperties = this.getUIDefinitionProperties();
1435
- const mainPricingEnabled = runtimeContext.properties?.PricingEnabled;
1436
- const pricingEnabled = mainPricingEnabled ? mainPricingEnabled === 'true' : uiDefinitionProperties.pricingEnabled;
1437
- const customPriceApi = this.runtimeSettings.getConfigurationSettings()['CUSTOM_PRICE_API'];
1438
- this.isLoadingSubj$.next(true);
1439
- const configure$ = pricingEnabled && customPriceApi
1440
- ? this.configurationApiService.customConfigurePrice({
1441
- url: customPriceApi,
1442
- configurationRequest: this.extendConfigurationRequest(configurationRequest),
1443
- runtimeModel,
1444
- })
1445
- : this.extendedConfigureLineItem$({
1446
- configurationRequest,
1447
- runtimeModel,
1448
- pricingEnabled,
1449
- });
1450
- return configure$.pipe(tap(result => {
1451
- this.contextService.update(result.context);
1452
- this.configurationState.next(result);
1453
- this.previousConfigurationState.next(cloneDeep(result));
1454
- if (result.deletedLineItems?.length) {
1455
- this.showInactiveProductsConfirmation();
1456
- }
1457
- this.configurableRamp = result.lineItem;
1458
- }), map(({ lineItem }) => lineItem), catchError$1(error => throwError(() => {
1459
- const resetState = this.previousConfigurationState.value;
1460
- if (resetState) {
1461
- this.previousConfigurationState.next(cloneDeep(resetState));
1462
- this.configurationState.next(resetState);
1463
- }
1464
- if (error.error) {
1465
- return extractErrorDetails(error.error).join('. ');
1466
- }
1467
- return error.message || JSON.stringify(error);
1468
- })), finalize$1(() => this.isLoadingSubj$.next(false)));
1469
- }
1470
- configureExternal$(props) {
1471
- return this.runtimeService
1472
- .init({ productId: props.productId, defaultQty: props.qty, attributesMap: props.attributesMap })
1473
- .pipe(switchMap$1(() => this.configure()), first(), catchError$1(error => {
1474
- this.messageService.add({ severity: ToastType.error, summary: error });
1475
- throw error;
1476
- }), finalize$1(() => this.reset()));
1477
- }
1478
- configureGuidedSelling$(data) {
1479
- return this.extendedConfigureLineItem$({
1480
- configurationRequest: getGuidedSellingConfigurationRequest(data, this.contextService.resolve()),
1481
- }).pipe(catchError$1(error => {
1482
- if (error instanceof HttpErrorResponse) {
1483
- this.messageService.add({ severity: ToastType.error, summary: error.error.message || error.error });
1484
- }
1485
- throw error;
1486
- }));
1487
- }
1488
- generateRequest(lightMode = true) {
1489
- const lineItem = this.generateLineItem();
1490
- let request = {
1491
- lineItem,
1492
- mode: this.mode,
1493
- step: !this.configurationState.value?.lineItem ? RuntimeStep.START : RuntimeStep.UPDATE,
1494
- attributeDomainMode: 'ALL',
1495
- context: this.contextService.resolve(),
1496
- lineItems: this.quoteDraftService.quoteDraft?.currentState || [],
1497
- asset: this.getAsset(),
1498
- };
1499
- if (lightMode) {
1500
- request = ConfigurationTranslatorUtils.lightenConfigurationRequest(request);
1501
- }
1502
- return request;
1503
- }
1504
- generateLineItem() {
1505
- const runtimeContext = this.getRuntimeContext();
1506
- const uiDefinitionProperties = this.getUIDefinitionProperties();
1507
- let lineItem = this.configurableRamp;
1508
- if (!lineItem) {
1509
- const { initializationProps } = this.runtimeService ?? {};
1510
- lineItem = getDefaultLineItem(runtimeContext, uiDefinitionProperties, initializationProps?.defaultQty);
1511
- // Set default attributes
1512
- if (initializationProps?.attributesMap) {
1513
- const attributes = transform(initializationProps?.attributesMap, (acc, value, name) => acc.push({ name, value }), []);
1514
- lineItem = new LineItemWorker(lineItem).patchAttribute(attributes).li;
1515
- }
1516
- }
1517
- return lineItem;
1518
- }
1519
- getAsset() {
1520
- const lineItem = this.configurableRamp;
1521
- if (!lineItem) {
1522
- return;
1523
- }
1524
- const assetId = lineItem.assetId ?? lineItem.openOrderLineItemId;
1525
- return this.quoteDraftService.assetsState?.initialState.find(li => assetPredicateFn(li, assetId));
1526
- }
1527
- getUIDefinitionProperties() {
1528
- return {
1529
- ...(this.getRuntimeContext().uiDefinitionContainer?.source.properties ?? {}),
1530
- ...(this.runtimeService.uiDefinitionProperties ?? {}),
1531
- };
1532
- }
1533
- showInactiveProductsConfirmation() {
1534
- const confirmationConfig = {
1535
- title: ' ',
1536
- description: 'This quote contains inactive products. Do you want to remove them?',
1537
- primaryButtonLabel: 'Remove products',
1538
- secondaryButtonLabel: 'Back to Quote',
1539
- };
1540
- this.dialogService
1541
- .open(ConfirmationComponent, {
1542
- dismissableMask: false,
1543
- closeOnEscape: false,
1544
- closable: false,
1545
- showHeader: true,
1546
- header: `Inactive Products in Quote`,
1547
- width: '440px',
1548
- data: { confirmationConfig },
1549
- })
1550
- .onClose.subscribe(result => {
1551
- if (!result) {
1552
- const context = this.contextService.resolve();
1553
- window['VELO_BACK_FN'].apply(null, [context.headerId]);
1554
- }
1555
- });
653
+
654
+ class LineItemWorker {
655
+ constructor(src) {
656
+ this.li = { ...src };
1556
657
  }
1557
- extendedConfigureLineItem$({ configurationRequest, runtimeModel, pricingEnabled, }) {
1558
- return this.configurationApiService.configureLineItem({
1559
- configurationRequest: this.extendConfigurationRequest(configurationRequest),
1560
- runtimeModel,
1561
- pricingEnabled,
1562
- });
658
+ insert(parentId, toInsert) {
659
+ return new LineItemWorker(insertLineItem(this.li, parentId, toInsert));
1563
660
  }
1564
- extendConfigurationRequest(configurationRequest) {
1565
- const procedureName = this.flowInfoService.flow?.properties.procedureName;
1566
- return {
1567
- ...configurationRequest,
1568
- ...(procedureName ? { procedureName } : {}),
1569
- };
661
+ remove(id) {
662
+ return new LineItemWorker(removeLineItem(this.li, id));
663
+ }
664
+ replace(toReplace, skipCardinalityCalculation = false) {
665
+ return new LineItemWorker(replaceLineItem(this.li, toReplace, skipCardinalityCalculation));
666
+ }
667
+ patchAttribute(attrs, id, skipCardinalityCalculation = false) {
668
+ return new LineItemWorker(patchAttributes(this.li, id ?? this.li.id, attrs, skipCardinalityCalculation));
1570
669
  }
1571
670
  }
1572
- ConfigurationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService, deps: [{ token: QuoteDraftService }, { token: ConfigurationRuntimeService }, { token: ContextService }, { token: i1.ConfigurationApiService }, { token: i5.MessageService }, { token: i6$1.DialogService }, { token: RuntimeSettingsService }, { token: FlowInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
1573
- ConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService });
1574
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService, decorators: [{
1575
- type: Injectable
1576
- }], ctorParameters: function () { return [{ type: QuoteDraftService }, { type: ConfigurationRuntimeService }, { type: ContextService }, { type: i1.ConfigurationApiService }, { type: i5.MessageService }, { type: i6$1.DialogService }, { type: RuntimeSettingsService }, { type: FlowInfoService }]; } });
671
+
672
+ function extractMetadata(uiDefinition) {
673
+ return omit(uiDefinition, [
674
+ 'children',
675
+ 'pages',
676
+ 'components',
677
+ ]);
678
+ }
1577
679
 
1578
680
  class FlowUpdateService {
1579
681
  update(rootLineItems, updates, charges) {
@@ -1708,164 +810,594 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
1708
810
  }] });
1709
811
 
1710
812
  class FlowConfigurationService {
1711
- constructor(proceduresApiService, contextService, quoteDraftService, updateService, configurationService, flowInfoService) {
813
+ constructor(proceduresApiService,
814
+ // private quoteDraftService: QuoteDraftService,
815
+ salesTransactionService, updateService, configurationService, flowInfoService) {
1712
816
  this.proceduresApiService = proceduresApiService;
1713
- this.contextService = contextService;
1714
- this.quoteDraftService = quoteDraftService;
817
+ this.salesTransactionService = salesTransactionService;
1715
818
  this.updateService = updateService;
1716
819
  this.configurationService = configurationService;
1717
820
  this.flowInfoService = flowInfoService;
1718
821
  this.updatedSubj$ = new Subject();
1719
822
  this.updated$ = this.updatedSubj$.asObservable();
1720
823
  }
1721
- calculate$(quoteDraft) {
1722
- return this.extendedApply$(quoteDraft).pipe(tap$1(result => {
1723
- // sort the result current state based on the quote draft initial state
1724
- const initialStateIds = quoteDraft.initialState.map(lineItem => lineItem.integrationId);
1725
- result.currentState = result.currentState
1726
- .slice()
1727
- .sort((a, b) => initialStateIds.indexOf(a.integrationId) - initialStateIds.indexOf(b.integrationId));
1728
- this.quoteDraftService.updateQuoteDraft(result);
1729
- }), map$1(noop));
1730
- }
1731
- calculate(quoteDraft) {
1732
- this.calculate$(quoteDraft).subscribe();
1733
- }
1734
- update$(updates) {
1735
- const quoteDraft = this.quoteDraftService.quoteDraft;
1736
- if (!quoteDraft) {
1737
- return of(null);
824
+ calculate$(state) {
825
+ return this.proceduresApiService.apply$({ salesTransaction: state }).pipe(tap$1(result => this.salesTransactionService.setState(result.salesTransaction)), map$1(noop));
826
+ }
827
+ calculate(state) {
828
+ this.calculate$(state).subscribe();
829
+ }
830
+ revert$(lineItemId) {
831
+ const state = this.salesTransactionService.state;
832
+ const initialCurrentState = this.salesTransactionService.getInitialCurrentState();
833
+ const currentState = state?.salesTransactionItems ?? [];
834
+ const currentLineItemIndex = currentState.findIndex(({ id }) => id === lineItemId);
835
+ const currentLineItem = currentState[currentLineItemIndex];
836
+ const initialLineItem = initialCurrentState.find(({ integrationId }) => integrationId === currentLineItem?.integrationId);
837
+ if (!state || !currentLineItem || !initialLineItem) {
838
+ return of(null);
839
+ }
840
+ const updatedState = cloneDeep(currentState);
841
+ updatedState.splice(currentLineItemIndex, 1, initialLineItem);
842
+ return of([]).pipe(tap$1(() => {
843
+ this.salesTransactionService.setState({ ...state, salesTransactionItems: updatedState });
844
+ }), switchMap(() => this.calculate$({ ...state, salesTransactionItems: updatedState })), map$1(() => this.salesTransactionService.state), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
845
+ }
846
+ revert(lineItemId) {
847
+ this.revert$(lineItemId).subscribe();
848
+ }
849
+ delete$(ids) {
850
+ const state = this.salesTransactionService.state;
851
+ if (!state) {
852
+ return of(null);
853
+ }
854
+ return of([]).pipe(map$1(() => state.salesTransactionItems.filter(({ id }) => !ids.includes(id))), switchMap(updatedState => this.calculate$({ ...state, salesTransactionItems: updatedState })), map$1(() => this.salesTransactionService.state), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
855
+ }
856
+ delete(ids) {
857
+ this.delete$(ids).subscribe();
858
+ }
859
+ addTerm$(term) {
860
+ // TODO: implement
861
+ return of(this.salesTransactionService.state);
862
+ }
863
+ addToCart$(props) {
864
+ // TODO: implement
865
+ return of(this.salesTransactionService.state);
866
+ }
867
+ handleErrorAndBounceBack() {
868
+ return (source$) => {
869
+ return source$.pipe(catchError(error => {
870
+ console.error(error);
871
+ // bounce back if configuration call has failed
872
+ const state = this.salesTransactionService.state;
873
+ if (state) {
874
+ this.salesTransactionService.setState(state);
875
+ this.updatedSubj$.next();
876
+ }
877
+ return throwError(() => error);
878
+ }));
879
+ };
880
+ }
881
+ }
882
+ FlowConfigurationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, deps: [{ token: i2.ProceduresApiService }, { token: SalesTransactionService }, { token: FlowUpdateService }, { token: ConfigurationService }, { token: FlowInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
883
+ FlowConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService });
884
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, decorators: [{
885
+ type: Injectable
886
+ }], ctorParameters: function () { return [{ type: i2.ProceduresApiService }, { type: SalesTransactionService }, { type: FlowUpdateService }, { type: ConfigurationService }, { type: FlowInfoService }]; } });
887
+
888
+ class FlowConfigurationModule {
889
+ }
890
+ FlowConfigurationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
891
+ FlowConfigurationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, imports: [ApiModule] });
892
+ FlowConfigurationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, providers: [FlowConfigurationService, FlowUpdateService], imports: [ApiModule] });
893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, decorators: [{
894
+ type: NgModule,
895
+ args: [{
896
+ imports: [ApiModule],
897
+ providers: [FlowConfigurationService, FlowUpdateService],
898
+ }]
899
+ }] });
900
+
901
+ class SalesTransactionService {
902
+ get isInitialized$() {
903
+ return this.isInitializedSubj$.asObservable();
904
+ }
905
+ get isInitialized() {
906
+ return this.isInitializedSubj$.getValue();
907
+ }
908
+ set hasUnsavedChanges(value) {
909
+ this.hasUnsavedChangesSubj$.next(value);
910
+ if (!this.hasUnsavedChanges) {
911
+ this.initialCurrentState = this.state?.salesTransactionItems ?? [];
912
+ }
913
+ }
914
+ get hasUnsavedChanges() {
915
+ return this.hasUnsavedChangesSubj$.getValue();
916
+ }
917
+ get state() {
918
+ return this.stateSubj$.getValue();
919
+ }
920
+ constructor(flowInfoService, salesTransactionApiService) {
921
+ this.flowInfoService = flowInfoService;
922
+ this.salesTransactionApiService = salesTransactionApiService;
923
+ this.stateSubj$ = new BehaviorSubject(null);
924
+ this.isInitializedSubj$ = new BehaviorSubject(false);
925
+ this.hasUnsavedChangesSubj$ = new BehaviorSubject(false);
926
+ this.initialCurrentState = [];
927
+ this.hasUnsavedChanges$ = this.hasUnsavedChangesSubj$.asObservable();
928
+ this.state$ = this.stateSubj$.asObservable().pipe(filter(isDefined));
929
+ }
930
+ init(headerId, params) {
931
+ return this.salesTransactionApiService.getState(headerId, params).pipe(tap$1(res => this.stateSubj$.next(res)));
932
+ }
933
+ finalizeInit() {
934
+ this.isInitializedSubj$.next(true);
935
+ this.hasUnsavedChanges = false;
936
+ }
937
+ reset() {
938
+ this.stateSubj$.next(null);
939
+ this.isInitializedSubj$.next(false);
940
+ this.hasUnsavedChangesSubj$.next(false);
941
+ }
942
+ getInitialCurrentState() {
943
+ return this.initialCurrentState;
944
+ }
945
+ setState(state) {
946
+ this.stateSubj$.next(state);
947
+ }
948
+ }
949
+ SalesTransactionService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SalesTransactionService, deps: [{ token: FlowInfoService }, { token: i2.SalesTransactionApiService }], target: i0.ɵɵFactoryTarget.Injectable });
950
+ SalesTransactionService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SalesTransactionService });
951
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SalesTransactionService, decorators: [{
952
+ type: Injectable
953
+ }], ctorParameters: function () { return [{ type: FlowInfoService }, { type: i2.SalesTransactionApiService }]; } });
954
+
955
+ class FlowStateService {
956
+ constructor(salesTransactionService, flowInfoService, flowConfiguration, processorsApiService, flowStateApiService, salesTransactionApiService, toastService, customizationService) {
957
+ this.salesTransactionService = salesTransactionService;
958
+ this.flowInfoService = flowInfoService;
959
+ this.flowConfiguration = flowConfiguration;
960
+ this.processorsApiService = processorsApiService;
961
+ this.flowStateApiService = flowStateApiService;
962
+ this.salesTransactionApiService = salesTransactionApiService;
963
+ this.toastService = toastService;
964
+ this.customizationService = customizationService;
965
+ this.NOT_INITIALIZED = Symbol();
966
+ this.EXECUTION_BUFFER_TIME = 100;
967
+ this.executedFunctions = {};
968
+ this.stateId$ = new BehaviorSubject(null);
969
+ this.initialStatefulData = {};
970
+ this.trackedStatefulChangesMap = new Map();
971
+ this.processors = {};
972
+ this.subscriptions = {};
973
+ this.flowStore = {};
974
+ this.executionInProgress$ = new BehaviorSubject(false);
975
+ this.statefulRequestStream$ = new Subject();
976
+ this.cleanup$ = new Subject();
977
+ this.statefulExecutionRequest$ = this.initBufferedRequest$();
978
+ /*
979
+ In stateless mode watch QuoteDraft changes and call executeRequest so that
980
+ all subscriptions get their updates according to updated QuoteDraft
981
+ */
982
+ this.isInitialized$()
983
+ .pipe(filter(Boolean), filter(() => !this.getFlowSafe().properties.stateful), switchMap(() => this.flowConfiguration.updated$), switchMap(() => this.executeRequest$({}, true)))
984
+ .subscribe();
985
+ this.charges$ = this.flowInfoService.isFlowEngineInitialized$.pipe(filter(Boolean), switchMap(() => {
986
+ return this.subscribe$(UITemplateType.FLOW_ENGINE, 'CHARGES', null, {
987
+ cold: true,
988
+ }).pipe(map$1(response => (response.success ? response.result : {})));
989
+ }), shareReplay(1));
990
+ this.charges$.subscribe();
991
+ this.pricePlans$ = this.flowInfoService.isFlowEngineInitialized$.pipe(filter(Boolean), switchMap(() => {
992
+ return this.subscribe$(UITemplateType.FLOW_ENGINE, 'PRICE_PLANS', null, {
993
+ cold: true,
994
+ }).pipe(map$1(response => (response.success ? response.result : {})));
995
+ }), shareReplay(1));
996
+ this.pricePlans$.subscribe();
997
+ this.activeMetrics$ = this.flowInfoService.isFlowEngineInitialized$.pipe(filter(Boolean), switchMap(() => {
998
+ return this.subscribe$(UITemplateType.FLOW_ENGINE, 'ACTIVE_METRICS', null, {
999
+ cold: true,
1000
+ }).pipe(map$1(response => (response.success ? response.result : [])));
1001
+ }), shareReplay(1));
1002
+ this.activeMetrics$.subscribe();
1003
+ this.isPriceListLocked$ = this.flowInfoService.isFlowEngineInitialized$.pipe(filter(Boolean), switchMap(() => {
1004
+ return this.subscribe$(UITemplateType.FLOW_ENGINE, 'IS_PRICE_LIST_LOCKED', null, {
1005
+ cold: true,
1006
+ }).pipe(map$1(response => (response.success ? response.result : false)));
1007
+ }), shareReplay(1));
1008
+ this.isPriceListLocked$.subscribe();
1009
+ }
1010
+ init$() {
1011
+ return this.initProcessors$().pipe(switchMap(() => {
1012
+ if (this.getFlowSafe().properties.stateful) {
1013
+ return this.initStateful$();
1014
+ }
1015
+ else {
1016
+ return this.initStateless$();
1017
+ }
1018
+ }));
1019
+ }
1020
+ cleanup() {
1021
+ Object.values(this.subscriptions).forEach(({ data$ }) => data$.complete());
1022
+ this.subscriptions = {};
1023
+ if (this.stateId$.value) {
1024
+ this.flowStateApiService.cancel(this.stateId$.value).subscribe();
1025
+ this.stateId$.next(null);
1026
+ }
1027
+ this.processors = {};
1028
+ this.flowStore = {};
1029
+ this.cleanup$.next();
1030
+ }
1031
+ get hasUnsavedChanges() {
1032
+ return this.getFlowSafe().properties.stateful
1033
+ ? Array.from(this.trackedStatefulChangesMap.values()).some(Boolean)
1034
+ : this.salesTransactionService.hasUnsavedChanges;
1035
+ }
1036
+ get stateId() {
1037
+ return this.stateId$.value;
1038
+ }
1039
+ get isExecutionInProgress$() {
1040
+ return this.executionInProgress$.asObservable();
1041
+ }
1042
+ isInitialized$() {
1043
+ return combineLatest([this.stateId$, this.salesTransactionService.isInitialized$]).pipe(map$1(values => values.some(Boolean)));
1044
+ }
1045
+ isInitialized() {
1046
+ return Boolean(this.stateId$.value) || this.salesTransactionService.isInitialized;
1047
+ }
1048
+ execute$(scope, exec) {
1049
+ const request = this.execToRequest(scope, exec);
1050
+ return this.executeRequest$(request).pipe(map$1(result => {
1051
+ // Keep only requested results
1052
+ const actualSelectors = Object.entries(result.selectors).reduce((trunk, [requestId, result]) => {
1053
+ if (exec.selectors?.[requestId]) {
1054
+ trunk[requestId] = result;
1055
+ }
1056
+ return trunk;
1057
+ }, {});
1058
+ return actualSelectors;
1059
+ }));
1060
+ }
1061
+ dispatch$(scope, action, inputData) {
1062
+ const exec = {
1063
+ actions: [{ name: action, inputData }],
1064
+ };
1065
+ const request = this.execToRequest(scope, exec);
1066
+ return this.executeRequest$(request).pipe(map$1(noop));
1067
+ }
1068
+ select$(scope, selectorName, inputData) {
1069
+ const requestId = this.generateRequestId(scope, selectorName, inputData);
1070
+ const request = this.execToRequest(scope, {
1071
+ selectors: {
1072
+ [requestId]: {
1073
+ name: selectorName,
1074
+ inputData,
1075
+ },
1076
+ },
1077
+ });
1078
+ return this.executeRequest$(request).pipe(map$1(response => response.selectors[requestId]));
1079
+ }
1080
+ subscribe$(scope, selectorName, inputData, options) {
1081
+ const requestId = this.generateRequestId(scope, selectorName, inputData);
1082
+ let subscription = this.subscriptions[requestId];
1083
+ if (!subscription) {
1084
+ const request = this.execToRequest(scope, {
1085
+ selectors: {
1086
+ [requestId]: {
1087
+ name: selectorName,
1088
+ inputData,
1089
+ },
1090
+ },
1091
+ });
1092
+ subscription = {
1093
+ request,
1094
+ data$: new BehaviorSubject(this.NOT_INITIALIZED),
1095
+ };
1096
+ this.subscriptions[requestId] = subscription;
1097
+ if (options?.trackedChanges) {
1098
+ this.trackedStatefulChangesMap.set(requestId, false);
1099
+ }
1100
+ if (!options?.cold) {
1101
+ this.executeRequest$(request).subscribe();
1102
+ }
1103
+ }
1104
+ return subscription.data$.pipe(filter(data => data != this.NOT_INITIALIZED), map$1(data => data), finalize(() => {
1105
+ if (!this.subscriptions[requestId]?.data$.observed) {
1106
+ delete this.subscriptions[requestId];
1107
+ }
1108
+ }));
1109
+ }
1110
+ save$() {
1111
+ if (this.getFlowSafe().properties.stateful) {
1112
+ if (this.stateId$.value) {
1113
+ return this.flowStateApiService.save(this.stateId$.value).pipe(map$1(({ quoteId }) => ({ id: quoteId })), tap$1(() => {
1114
+ Array.from(this.trackedStatefulChangesMap.keys()).forEach(key => {
1115
+ this.trackedStatefulChangesMap.set(key, false);
1116
+ });
1117
+ }));
1118
+ }
1119
+ }
1120
+ else {
1121
+ const state = this.salesTransactionService.state;
1122
+ if (state) {
1123
+ return this.salesTransactionApiService.upsert(state);
1124
+ }
1125
+ }
1126
+ return of({ id: '' });
1127
+ }
1128
+ submit$() {
1129
+ if (this.getFlowSafe().properties.stateful) {
1130
+ if (this.stateId$.value) {
1131
+ return this.flowStateApiService.submit(this.stateId$.value).pipe(map$1(({ quoteId }) => ({ id: quoteId })));
1132
+ }
1133
+ }
1134
+ else {
1135
+ const state = this.salesTransactionService.state;
1136
+ if (state) {
1137
+ return this.salesTransactionApiService.submit(state);
1138
+ }
1738
1139
  }
1739
- return of([]).pipe(map$1(() => {
1740
- const updatedState = cloneDeep(quoteDraft.currentState);
1741
- this.updateService.update(updatedState, updates, quoteDraft.charges);
1742
- return updatedState;
1743
- }), switchMap(updatedState => this.calculate$({ ...quoteDraft, currentState: updatedState })), map$1(() => this.quoteDraftService.quoteDraft), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
1140
+ return of({ id: '' });
1744
1141
  }
1745
- update(updates) {
1746
- this.update$(updates).subscribe();
1142
+ getFlowStore() {
1143
+ return this.flowStore;
1747
1144
  }
1748
- revert$(lineItemId) {
1749
- const quoteDraft = this.quoteDraftService.quoteDraft;
1750
- const initialCurrentState = this.quoteDraftService.getInitialCurrentState();
1751
- const currentState = this.quoteDraftService.currentState;
1752
- const currentLineItemIndex = currentState.findIndex(({ id }) => id === lineItemId);
1753
- const currentLineItem = currentState[currentLineItemIndex];
1754
- const initialLineItem = initialCurrentState.find(({ integrationId }) => integrationId === currentLineItem?.integrationId);
1755
- if (!quoteDraft || !currentLineItem || !initialLineItem) {
1756
- return of(null);
1145
+ getOwnerIdByScope(scope) {
1146
+ const ownerId = this.flowInfoService.templates[scope]?.id;
1147
+ if (!ownerId) {
1148
+ throw `OwnerId is not found for scope ${scope}`;
1757
1149
  }
1758
- const updatedState = cloneDeep(currentState);
1759
- updatedState.splice(currentLineItemIndex, 1, initialLineItem);
1760
- return of([]).pipe(tap$1(() => {
1761
- this.quoteDraftService.setCurrentLineItemState(updatedState);
1762
- }), switchMap(() => this.calculate$({ ...quoteDraft, currentState: updatedState })), map$1(() => this.quoteDraftService.quoteDraft), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
1763
- }
1764
- revert(lineItemId) {
1765
- this.revert$(lineItemId).subscribe();
1150
+ return ownerId;
1766
1151
  }
1767
- delete$(ids) {
1768
- const quoteDraft = this.quoteDraftService.quoteDraft;
1769
- const currentState = this.quoteDraftService.currentState;
1770
- if (!quoteDraft) {
1771
- return of(null);
1152
+ getScopeByOwnerId(id) {
1153
+ for (const template of Object.values(this.flowInfoService.templates)) {
1154
+ if (template.id === id) {
1155
+ return template.type;
1156
+ }
1772
1157
  }
1773
- return of([]).pipe(map$1(() => ids.reduce((result, id) => this.updateService.delete(result, id), currentState)), switchMap(updatedState => this.calculate$({ ...quoteDraft, currentState: updatedState })), map$1(() => this.quoteDraftService.quoteDraft), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
1158
+ return;
1774
1159
  }
1775
- delete(ids) {
1776
- this.delete$(ids).subscribe();
1160
+ execToRequest(scope, exec) {
1161
+ const ownerId = this.getOwnerIdByScope(scope);
1162
+ return {
1163
+ actions: exec.actions?.map(action => ({ apiName: action.name, ownerId, inputData: action.inputData ?? {} })),
1164
+ selectors: exec.selectors &&
1165
+ Object.entries(exec.selectors).reduce((trunk, [key, selector]) => ({
1166
+ ...trunk,
1167
+ [key]: { apiName: selector.name, ownerId, inputData: selector.inputData ?? {} },
1168
+ }), {}),
1169
+ };
1777
1170
  }
1778
- addTerm$(term) {
1779
- const quoteDraft = this.quoteDraftService.quoteDraft;
1780
- if (!quoteDraft) {
1781
- return of(null);
1171
+ executeRequest$(request, forceSubscriptions = false) {
1172
+ const fullRequest = cloneDeep(request);
1173
+ if (fullRequest.actions?.length || forceSubscriptions) {
1174
+ for (const subscription of Object.values(this.subscriptions)) {
1175
+ fullRequest.selectors = assign(fullRequest.selectors, subscription.request.selectors);
1176
+ }
1782
1177
  }
1783
- const updatedState = [...quoteDraft.currentState, term];
1784
- return of([]).pipe(switchMap(() => this.calculate$({ ...quoteDraft, currentState: updatedState })), map$1(() => this.quoteDraftService.quoteDraft), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
1178
+ const execution$ = this.getFlowSafe().properties.stateful
1179
+ ? this.executeStateful$(fullRequest)
1180
+ : this.executeStateless$(fullRequest);
1181
+ return execution$.pipe(tap$1(result => this.handleSelectorsResponse(result.selectors)));
1785
1182
  }
1786
- addToCart$(props) {
1787
- const quoteDraft = this.quoteDraftService.quoteDraft;
1788
- if (!quoteDraft) {
1789
- return of(null);
1790
- }
1791
- return this.configurationService.configureExternal$(props).pipe(map$1(lineItem => {
1792
- const model = this.configurationService.getRuntimeModel();
1793
- const split = model?.types.find(type => type.name === lineItem.type)?.split ?? false;
1794
- const lineItems = multiplyLineItems(lineItem, props.qty ?? 1, split);
1795
- return [...quoteDraft.currentState, ...lineItems];
1796
- }), switchMap(updatedState => this.calculate$({ ...quoteDraft, currentState: updatedState })), map$1(() => this.quoteDraftService.quoteDraft), tap$1(() => this.updatedSubj$.next()), this.handleErrorAndBounceBack());
1183
+ handleSelectorsResponse(selectors) {
1184
+ Object.entries(selectors).forEach(([requestId, selectorResult]) => {
1185
+ if (!selectorResult.success) {
1186
+ this.toastService.add({ severity: ToastType.error, summary: selectorResult.errorMessage });
1187
+ }
1188
+ const subscription$ = this.subscriptions[requestId]?.data$;
1189
+ if (subscription$ && subscription$.value !== selectorResult) {
1190
+ this.checkStatefulChanges(requestId, selectorResult);
1191
+ subscription$.next(selectorResult);
1192
+ }
1193
+ });
1797
1194
  }
1798
- get() {
1799
- return this.quoteDraftService.quoteDraft$.pipe(map$1(() => this.quoteDraftService.currentState), shareReplay$1());
1195
+ initStateful$() {
1196
+ const processorsList = flatten(Object.values(this.processors).map(ownerMap => Object.values(ownerMap ?? {})));
1197
+ const processors = processorsList.length ? processorsList : undefined;
1198
+ const selectors = Object.values(this.subscriptions)
1199
+ .map(({ request }) => request.selectors)
1200
+ .filter(isDefined)
1201
+ .reduce((trunk, selectors) => ({ ...trunk, ...selectors }), {});
1202
+ return this.flowStateApiService
1203
+ .init({
1204
+ quoteId: this.flowInfoService.context.headerId,
1205
+ params: this.flowInfoService.context,
1206
+ actionsOverride: processors?.filter(processor => processor.type === ConfigurationProcessorTypes.ACTION),
1207
+ selectorsOverride: processors?.filter(processor => processor.type === ConfigurationProcessorTypes.SELECTOR),
1208
+ selectors: selectors,
1209
+ })
1210
+ .pipe(map$1(({ stateId, selectors }) => {
1211
+ this.handleSelectorsResponse(selectors);
1212
+ this.stateId$.next(stateId);
1213
+ }));
1800
1214
  }
1801
- getSnapshot() {
1802
- return this.quoteDraftService?.currentState.slice() ?? [];
1215
+ initBufferedRequest$() {
1216
+ return this.statefulRequestStream$.pipe(buffer(this.statefulRequestStream$.pipe(debounceTime(this.EXECUTION_BUFFER_TIME))), switchMap(requests => {
1217
+ if (!this.stateId$.value) {
1218
+ throw 'Stateful session is not initialized';
1219
+ }
1220
+ // merge buffered requests
1221
+ const request = {
1222
+ actions: requests.flatMap(({ actions }) => actions).filter(isDefined),
1223
+ selectors: requests
1224
+ .map(({ selectors }) => selectors)
1225
+ .filter(isDefined)
1226
+ .reduce((acc, selectorsMap) => Object.assign(acc, selectorsMap), {}),
1227
+ };
1228
+ this.executionInProgress$.next(true);
1229
+ return this.flowStateApiService.execute(this.stateId$.value, request);
1230
+ }), tap$1(({ stateId }) => this.stateId$.next(stateId)), share(), tap$1(() => this.executionInProgress$.next(false)), catchError(e => {
1231
+ this.executionInProgress$.next(false);
1232
+ return throwError(() => e);
1233
+ }));
1803
1234
  }
1804
- get charges$() {
1805
- return this.quoteDraftService.quoteDraft$.pipe(map$1(({ charges }) => charges));
1235
+ executeStateful$(request) {
1236
+ return this.executionInProgress$.pipe(filter(inProgress => !inProgress), take(1), switchMap(() =>
1237
+ // make sure stream switches to statefulExecutionRequest$ before pushing an execution request
1238
+ combineLatest([
1239
+ this.statefulExecutionRequest$,
1240
+ of(undefined).pipe(tap$1(() => this.statefulRequestStream$.next(request))),
1241
+ ])), map$1(([response]) => response), take(1));
1806
1242
  }
1807
- get pricePlans$() {
1808
- return this.quoteDraftService.quoteDraft$.pipe(map$1(({ pricePlans }) => pricePlans));
1243
+ initStateless$() {
1244
+ return this.salesTransactionService.init(this.flowInfoService.context.headerId, this.flowInfoService.context).pipe(tap$1(() => {
1245
+ const assets = this.salesTransactionService.state?.assets;
1246
+ if (assets) {
1247
+ this.flowStore = { ...this.flowStore, assets };
1248
+ }
1249
+ }), switchMap(state => this.flowConfiguration.calculate$(state)), tap$1(() => this.salesTransactionService.finalizeInit()), map$1(noop));
1809
1250
  }
1810
- get activeMetrics$() {
1811
- return this.quoteDraftService.quoteDraft$.pipe(map$1(({ activeMetrics }) => activeMetrics));
1251
+ executeStateless$(request) {
1252
+ this.executionInProgress$.next(true);
1253
+ return of(undefined).pipe(tap$1(() => this.executeStatelessActions(request)), switchMap(() => {
1254
+ /*
1255
+ Skip price calculation in case
1256
+ 1. No actions in the request
1257
+ 2. Initialization process execution (state not initialized yet)
1258
+ */
1259
+ const { state } = this.salesTransactionService;
1260
+ if (!state || !request.actions?.length || !this.isInitialized()) {
1261
+ return of(undefined);
1262
+ }
1263
+ else {
1264
+ return this.flowConfiguration.calculate$(state);
1265
+ }
1266
+ }), map$1(() => this.executeStatelessSelectors(request)), tap$1(() => this.executionInProgress$.next(false)), catchError(e => {
1267
+ this.executionInProgress$.next(false);
1268
+ return throwError(() => e);
1269
+ }));
1812
1270
  }
1813
- get chargesSnapshot() {
1814
- return this.quoteDraftService.quoteDraft?.charges ?? {};
1271
+ executeStatelessActions(request) {
1272
+ const state = this.salesTransactionService.state;
1273
+ if (!state || !request.actions?.length) {
1274
+ return;
1275
+ }
1276
+ let flowState = state;
1277
+ request.actions.forEach(action => {
1278
+ try {
1279
+ flowState = this.executeActionScript(flowState, action) ?? flowState;
1280
+ }
1281
+ catch (e) {
1282
+ console.error(e);
1283
+ this.toastService.add({ severity: ToastType.error, summary: String(e) });
1284
+ throw e;
1285
+ }
1286
+ });
1287
+ this.salesTransactionService.setState(flowState);
1815
1288
  }
1816
- get pricePlansSnapshot() {
1817
- return this.quoteDraftService.quoteDraft?.pricePlans ?? {};
1289
+ executeStatelessSelectors(request) {
1290
+ if (!this.salesTransactionService.state) {
1291
+ throw 'QuoteDraft is not initialized';
1292
+ }
1293
+ const flowState = this.salesTransactionService.state;
1294
+ return EntityUtil.entries(request.selectors ?? {}).reduce((result, [key, selector]) => {
1295
+ try {
1296
+ result.selectors[key] = {
1297
+ success: true,
1298
+ result: this.executeSelectorScript(flowState, selector),
1299
+ };
1300
+ }
1301
+ catch (e) {
1302
+ console.error(e);
1303
+ result.selectors[key] = {
1304
+ success: false,
1305
+ errorMessage: String(e),
1306
+ };
1307
+ }
1308
+ return result;
1309
+ }, { stateId: '', selectors: {} });
1310
+ }
1311
+ getFlowSafe() {
1312
+ if (!this.flowInfoService.flow) {
1313
+ throw 'Flow is not defined';
1314
+ }
1315
+ return this.flowInfoService.flow;
1316
+ }
1317
+ initProcessors$() {
1318
+ const hasOverrides = Boolean(this.customizationService?.getTemplateConfigurationProcessors);
1319
+ const flow = this.getFlowSafe();
1320
+ if (flow.properties.stateful && !hasOverrides) {
1321
+ // Skip initialization as backend will take processors from SF
1322
+ return of(undefined);
1323
+ }
1324
+ const owners$ = Object.values(this.flowInfoService.templates)
1325
+ .map(template => {
1326
+ if (!template) {
1327
+ return;
1328
+ }
1329
+ const localProcessors$ = this.customizationService?.getTemplateConfigurationProcessors?.(template.name) ?? of(null);
1330
+ return localProcessors$.pipe(switchMap(processors => processors ? of(processors) : this.processorsApiService.fetchConfigurationProcessors$(template.id)), tap$1(processors => {
1331
+ const processorsMap = processors.reduce((acc, p) => {
1332
+ acc[p.apiName] = p;
1333
+ return acc;
1334
+ }, {});
1335
+ this.processors[template.id] = processorsMap;
1336
+ }));
1337
+ })
1338
+ .filter(isDefined);
1339
+ if (!owners$.length) {
1340
+ return of(undefined);
1341
+ }
1342
+ return forkJoin(owners$).pipe(map$1(noop));
1818
1343
  }
1819
- get activeMetricsSnapshot() {
1820
- return this.quoteDraftService.quoteDraft?.activeMetrics ?? [];
1344
+ executeActionScript(request, executable) {
1345
+ const configurationProcessor = this.processors[executable.ownerId]?.[executable.apiName];
1346
+ if (!configurationProcessor?.script) {
1347
+ const scope = this.getScopeByOwnerId(executable.ownerId);
1348
+ const scopeText = scope ? ` in ${scope}` : '';
1349
+ throw `ConfigurationProcessor ${executable.apiName}${scopeText} not found`;
1350
+ }
1351
+ return this.executeProcessorScript(request, configurationProcessor, executable.inputData);
1821
1352
  }
1822
- get contextSnapshot() {
1823
- return this.contextService.resolve();
1353
+ executeSelectorScript(request, executable) {
1354
+ const configurationProcessor = this.processors[executable.ownerId]?.[executable.apiName];
1355
+ if (!configurationProcessor?.script) {
1356
+ const scope = this.getScopeByOwnerId(executable.ownerId);
1357
+ const scopeText = scope ? ` in ${scope}` : '';
1358
+ throw `ConfigurationProcessor ${executable.apiName}${scopeText} not found`;
1359
+ }
1360
+ return this.executeProcessorScript(request, configurationProcessor, executable.inputData);
1824
1361
  }
1825
- get context$() {
1826
- return this.contextService.resolve$();
1362
+ executeProcessorScript(request, configurationProcessor, inputData) {
1363
+ const scope = this.getScopeByOwnerId(configurationProcessor.ownerId ?? '');
1364
+ let functionToExecute = this.executedFunctions[scope + configurationProcessor.apiName];
1365
+ if (!functionToExecute) {
1366
+ const script = `${configurationProcessor.script}\nreturn transform;`;
1367
+ const sourceMap = `\n//# sourceURL=${scope ? scope + '/' : ''}${configurationProcessor.apiName}.js`;
1368
+ functionToExecute = new Function(script + sourceMap)();
1369
+ this.executedFunctions[scope + configurationProcessor.apiName] = functionToExecute;
1370
+ }
1371
+ return functionToExecute({
1372
+ request,
1373
+ inputData,
1374
+ flowStore: this.flowStore,
1375
+ });
1827
1376
  }
1828
- handleErrorAndBounceBack() {
1829
- return (source$) => {
1830
- return source$.pipe(catchError(error => {
1831
- console.error(error);
1832
- // bounce back if configuration call has failed
1833
- const quoteDraft = this.quoteDraftService.quoteDraft;
1834
- if (quoteDraft) {
1835
- this.quoteDraftService.updateQuoteDraft(quoteDraft);
1836
- this.updatedSubj$.next();
1837
- }
1838
- return throwError(() => error);
1839
- }));
1840
- };
1377
+ generateRequestId(scope, selectorName, inputData) {
1378
+ const inputDataHash = UUID.hex(JSON.stringify(inputData) || '').slice(0, 8);
1379
+ return `${scope}/${selectorName}/${inputDataHash}`;
1841
1380
  }
1842
- extendedApply$(quoteDraft) {
1843
- const request = { ...quoteDraft };
1844
- const procedureName = this.flowInfoService.flow?.properties.procedureName;
1845
- if (procedureName) {
1846
- request.procedureName = procedureName;
1381
+ checkStatefulChanges(requestId, selectorResult) {
1382
+ if (this.trackedStatefulChangesMap.has(requestId)) {
1383
+ if (!this.initialStatefulData[requestId]) {
1384
+ this.initialStatefulData[requestId] = selectorResult;
1385
+ }
1386
+ const hasChanges = !isEqual(this.initialStatefulData[requestId], selectorResult);
1387
+ this.trackedStatefulChangesMap.set(requestId, hasChanges);
1847
1388
  }
1848
- return this.proceduresApiService.apply$(request);
1849
1389
  }
1850
1390
  }
1851
- FlowConfigurationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, deps: [{ token: i1.ProceduresApiService }, { token: ContextService }, { token: QuoteDraftService }, { token: FlowUpdateService }, { token: ConfigurationService }, { token: FlowInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
1852
- FlowConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService });
1853
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, decorators: [{
1391
+ FlowStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService, deps: [{ token: SalesTransactionService }, { token: FlowInfoService }, { token: FlowConfigurationService }, { token: i2.ConfigurationProcessorsApiService }, { token: i1.FlowStateApiService }, { token: i2.SalesTransactionApiService }, { token: i6.ToastService }, { token: FLOW_CUSTOMIZATION, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
1392
+ FlowStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService });
1393
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowStateService, decorators: [{
1854
1394
  type: Injectable
1855
- }], ctorParameters: function () { return [{ type: i1.ProceduresApiService }, { type: ContextService }, { type: QuoteDraftService }, { type: FlowUpdateService }, { type: ConfigurationService }, { type: FlowInfoService }]; } });
1856
-
1857
- class FlowConfigurationModule {
1858
- }
1859
- FlowConfigurationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1860
- FlowConfigurationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, imports: [ApiModule] });
1861
- FlowConfigurationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, providers: [FlowConfigurationService, FlowUpdateService], imports: [ApiModule] });
1862
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationModule, decorators: [{
1863
- type: NgModule,
1864
- args: [{
1865
- imports: [ApiModule],
1866
- providers: [FlowConfigurationService, FlowUpdateService],
1867
- }]
1868
- }] });
1395
+ }], ctorParameters: function () { return [{ type: SalesTransactionService }, { type: FlowInfoService }, { type: FlowConfigurationService }, { type: i2.ConfigurationProcessorsApiService }, { type: i1.FlowStateApiService }, { type: i2.SalesTransactionApiService }, { type: i6.ToastService }, { type: undefined, decorators: [{
1396
+ type: Optional
1397
+ }, {
1398
+ type: Inject,
1399
+ args: [FLOW_CUSTOMIZATION]
1400
+ }] }]; } });
1869
1401
 
1870
1402
  class FlowStateConfigurationService {
1871
1403
  constructor(flowInfoService, flowConfigurationService, flowStateApiService, flowStateService) {
@@ -1926,7 +1458,7 @@ class IntegrationState {
1926
1458
  this.action$.next(action);
1927
1459
  }
1928
1460
  listen$(actionType) {
1929
- return this.action$.pipe(filter$1(action => action.type === actionType), map$1(action => action.payload));
1461
+ return this.action$.pipe(filter(action => action.type === actionType), map$1(action => action.payload));
1930
1462
  }
1931
1463
  listenAll$() {
1932
1464
  return this.action$.asObservable();
@@ -1959,164 +1491,431 @@ class ProductImagesService {
1959
1491
  .pipe(map$1(file => URL.createObjectURL(file)), catchError(() => of('')), tap$1(url => this.imagesMap$.next({ ...this.imagesMap$.value, [productId]: url })))
1960
1492
  .subscribe();
1961
1493
  }
1962
- }
1963
- ProductImagesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, deps: [{ token: i1.ProductApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1964
- ProductImagesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService });
1965
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, decorators: [{
1966
- type: Injectable
1967
- }], ctorParameters: function () { return [{ type: i1.ProductApiService }]; } });
1968
-
1969
- class RuntimeContextService {
1970
- constructor(configurationApiService) {
1971
- this.configurationApiService = configurationApiService;
1494
+ }
1495
+ ProductImagesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, deps: [{ token: i1.ProductApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1496
+ ProductImagesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService });
1497
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, decorators: [{
1498
+ type: Injectable
1499
+ }], ctorParameters: function () { return [{ type: i1.ProductApiService }]; } });
1500
+
1501
+ /**
1502
+ * @deprecated
1503
+ */
1504
+ class QuoteDraftService {
1505
+ get isInitialized$() {
1506
+ return this.isInitializedSubj$.asObservable();
1507
+ }
1508
+ get isInitialized() {
1509
+ return this.isInitializedSubj$.getValue();
1510
+ }
1511
+ set isInitialized(value) {
1512
+ if (this.isInitialized !== value) {
1513
+ this.isInitializedSubj$.next(value);
1514
+ }
1515
+ }
1516
+ get hasUnsavedChanges() {
1517
+ return this._hasUnsavedChanges;
1518
+ }
1519
+ set hasUnsavedChanges(value) {
1520
+ this._hasUnsavedChanges = value;
1521
+ if (!this._hasUnsavedChanges) {
1522
+ this.initialCurrentState = this.quoteDraft?.currentState ?? [];
1523
+ }
1524
+ }
1525
+ get hasProducts$() {
1526
+ return this.quoteSubj$.pipe(map(() => this.hasProducts));
1527
+ }
1528
+ get hasProducts() {
1529
+ return Boolean(this.quoteSubj$.value?.currentState.length);
1530
+ }
1531
+ get hasAssets$() {
1532
+ return this.assetsSubj$.pipe(map(() => this.hasAssets));
1533
+ }
1534
+ get hasAssets() {
1535
+ return Boolean(this.assetsSubj$.value?.currentState.length);
1536
+ }
1537
+ get assetsState() {
1538
+ return this.assetsSubj$.value;
1539
+ }
1540
+ constructor(flowInfoService, accountApiService) {
1541
+ this.flowInfoService = flowInfoService;
1542
+ this.accountApiService = accountApiService;
1543
+ this.quoteSubj$ = new BehaviorSubject(null);
1544
+ this.assetsSubj$ = new BehaviorSubject(null);
1545
+ this.resetSubj$ = new BehaviorSubject(true);
1546
+ this.isInitializedSubj$ = new BehaviorSubject(false);
1547
+ this.initialCurrentState = [];
1548
+ this._hasUnsavedChanges = false;
1549
+ this.reset$ = this.resetSubj$.asObservable();
1550
+ this.isInitializedSubj$
1551
+ .pipe(filter$1(isInitialized => isInitialized), switchMap$1(() => this.quoteSubj$.asObservable()), skip(1), tap(quote => this.markAsUpdated(quote)))
1552
+ .subscribe();
1553
+ }
1554
+ reset() {
1555
+ this.resetSubj$.next(true);
1556
+ this.quoteSubj$.next(null);
1557
+ this.assetsSubj$.next(null);
1558
+ this.isInitialized = false;
1559
+ this.hasUnsavedChanges = false;
1560
+ }
1561
+ init(headerId, params) {
1562
+ const isAccountMode = this.flowInfoService.context.mode === ConfigurationContextMode.ACCOUNT;
1563
+ const accountId = isAccountMode ? headerId : this.flowInfoService.context['accountId'];
1564
+ return zip(accountId ? this.accountApiService.getAssetsState(accountId, params) : of(null), isAccountMode
1565
+ ? of(QuoteDraft.emptyQuote(ConfigurationContextMode.ACCOUNT))
1566
+ : of(QuoteDraft.emptyQuote(ConfigurationContextMode.QUOTE))).pipe(tap(([assets, quote]) => {
1567
+ if (assets) {
1568
+ this.assetsSubj$.next(assets);
1569
+ }
1570
+ this.quoteSubj$.next(quote);
1571
+ }), map(() => noop()), take$1(1));
1572
+ }
1573
+ finalizeInit() {
1574
+ this.isInitialized = true;
1575
+ this.hasUnsavedChanges = false;
1576
+ }
1577
+ setCurrentLineItemState(lineItems) {
1578
+ const quoteDraft = this.quoteSubj$.value;
1579
+ if (!quoteDraft) {
1580
+ return;
1581
+ }
1582
+ this.quoteSubj$.next({
1583
+ ...quoteDraft,
1584
+ currentState: lineItems,
1585
+ });
1586
+ }
1587
+ updateQuoteDraft(update) {
1588
+ const quoteDraft = this.quoteSubj$.value;
1589
+ if (!quoteDraft) {
1590
+ return;
1591
+ }
1592
+ this.quoteSubj$.next({
1593
+ ...quoteDraft,
1594
+ ...update,
1595
+ });
1596
+ }
1597
+ updateByPriceSummary(priceSummary) {
1598
+ const quoteDraft = this.quoteSubj$.value;
1599
+ if (!quoteDraft) {
1600
+ return;
1601
+ }
1602
+ const updatedCurrentState = this.currentState.map(lineItem => {
1603
+ const updated = priceSummary.lineItems.find(li => li.id === lineItem.id);
1604
+ return updated ?? lineItem;
1605
+ });
1606
+ this.quoteSubj$.next({
1607
+ ...quoteDraft,
1608
+ currentState: updatedCurrentState,
1609
+ totalPrices: priceSummary.totalPrices,
1610
+ approvalItems: priceSummary.approvalItems,
1611
+ });
1612
+ }
1613
+ setAssetsState(assetsState) {
1614
+ this.assetsSubj$.next(assetsState);
1615
+ }
1616
+ get quoteDraft$() {
1617
+ return this.quoteSubj$.pipe(map(() => this.quoteDraft), filter$1((quote) => Boolean(quote)), shareReplay$1());
1618
+ }
1619
+ get quoteDraft() {
1620
+ return this.quoteSubj$.value;
1621
+ }
1622
+ get currentState$() {
1623
+ return this.quoteDraft$.pipe(map(quote => quote.currentState));
1624
+ }
1625
+ get currentState() {
1626
+ return this.quoteDraft?.currentState ?? [];
1627
+ }
1628
+ get isStandalone() {
1629
+ return this.flowInfoService.flow?.properties.standalone ?? false;
1630
+ }
1631
+ get isStandalone$() {
1632
+ return this.flowInfoService.flow$.pipe(map(() => this.isStandalone));
1633
+ }
1634
+ getInitialCurrentState() {
1635
+ return this.initialCurrentState;
1636
+ }
1637
+ isEditMode$() {
1638
+ return this.quoteDraft$.pipe(map(() => this.isEditMode()));
1639
+ }
1640
+ isEditMode() {
1641
+ const context = this.quoteDraft?.context;
1642
+ if (context?.mode === ConfigurationContextMode.ACCOUNT) {
1643
+ return true;
1644
+ }
1645
+ if (context?.mode === ConfigurationContextMode.QUOTE) {
1646
+ return context.properties.Status === 'Draft';
1647
+ }
1648
+ return false;
1649
+ }
1650
+ markAsUpdated(quote) {
1651
+ if (quote?.context.properties['#mode'] === ConfigurationContextMode.ACCOUNT) {
1652
+ this.hasUnsavedChanges = !!quote && !quote.currentState.every(li => li.actionCode === 'EXIST');
1653
+ }
1654
+ else {
1655
+ this.hasUnsavedChanges = !isEqual(this.initialCurrentState, quote?.currentState);
1656
+ }
1657
+ }
1658
+ }
1659
+ QuoteDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, deps: [{ token: FlowInfoService }, { token: i1.AccountApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1660
+ QuoteDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService });
1661
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, decorators: [{
1662
+ type: Injectable
1663
+ }], ctorParameters: function () { return [{ type: FlowInfoService }, { type: i1.AccountApiService }]; } });
1664
+
1665
+ class ConfigurationService {
1666
+ constructor(quoteDraftService, runtimeService, configurationApiService, messageService, dialogService, runtimeSettings, flowInfoService) {
1667
+ this.quoteDraftService = quoteDraftService;
1668
+ this.runtimeService = runtimeService;
1669
+ this.configurationApiService = configurationApiService;
1670
+ this.messageService = messageService;
1671
+ this.dialogService = dialogService;
1672
+ this.runtimeSettings = runtimeSettings;
1673
+ this.flowInfoService = flowInfoService;
1674
+ this.mode = ConfigurationMode.SEARCH;
1675
+ this.configurationState = new BehaviorSubject(null);
1676
+ this.previousConfigurationState = new BehaviorSubject(null);
1677
+ this.isLoadingSubj$ = new BehaviorSubject(false);
1678
+ this.isLoading$ = this.isLoadingSubj$.asObservable();
1679
+ this.hasUnsavedChanges = false;
1680
+ }
1681
+ reset() {
1682
+ this.hasUnsavedChanges = false;
1683
+ this.runtimeService.reset();
1684
+ this.configurableRamp = undefined;
1685
+ this.configurationState.next(null);
1686
+ this.previousConfigurationState.next(null);
1687
+ }
1688
+ patch$(lineItem) {
1689
+ const source = this.getSnapshot();
1690
+ if (!source) {
1691
+ return throwError(() => new Error(`Source LineItem not found`));
1692
+ }
1693
+ this.configurableRamp = new LineItemWorker(source).replace(lineItem).li;
1694
+ return this.configure().pipe(catchError$1(error => {
1695
+ console.error(error);
1696
+ if (!this.runtimeService.uiDefinitionProperties.suppressToastMessages) {
1697
+ this.messageService.add({ severity: 'error', summary: error });
1698
+ }
1699
+ // bounce back if configuration call has failed
1700
+ const prevState = this.configurationState.value;
1701
+ this.configurationState.next(prevState ? { ...prevState } : null);
1702
+ return throwError(() => error);
1703
+ }), tap(() => {
1704
+ if (!this.hasUnsavedChanges) {
1705
+ this.hasUnsavedChanges = true;
1706
+ }
1707
+ }));
1708
+ }
1709
+ patch(lineItem) {
1710
+ this.patch$(lineItem).subscribe();
1711
+ }
1712
+ setConfigurableRamp(lineItem) {
1713
+ this.configurableRamp = lineItem;
1714
+ }
1715
+ get() {
1716
+ return this.configurationState.pipe(map(state => state?.lineItem), shareReplay());
1717
+ }
1718
+ getSnapshot() {
1719
+ return this.configurationState.value?.lineItem ? { ...this.configurationState.value?.lineItem } : undefined;
1720
+ }
1721
+ getRuntimeModel() {
1722
+ const runtimeModel = this.runtimeService.runtimeModel;
1723
+ if (!runtimeModel) {
1724
+ throw new Error('Runtime model not initialized');
1725
+ }
1726
+ return runtimeModel;
1727
+ }
1728
+ getRuntimeContext() {
1729
+ const runtimeContext = this.runtimeService.runtimeContext;
1730
+ if (!runtimeContext) {
1731
+ throw new Error('Runtime context not initialized');
1732
+ }
1733
+ return runtimeContext;
1734
+ }
1735
+ get state$() {
1736
+ return this.configurationState.asObservable();
1737
+ }
1738
+ get stateSnapshot() {
1739
+ return this.configurationState.value;
1740
+ }
1741
+ get previousStateSnapshot() {
1742
+ return this.previousConfigurationState.value;
1743
+ }
1744
+ get charges$() {
1745
+ return this.configurationState.pipe(map(state => state?.charges ?? {}));
1972
1746
  }
1973
- getRuntimeContext(productId, offeringId, defaultUIDefinitionId, requiredUIDefinitionId) {
1974
- return this.configurationApiService
1975
- .getRuntimeDataByProductId(productId, offeringId, defaultUIDefinitionId, requiredUIDefinitionId)
1976
- .pipe(map(runtimeData => {
1977
- const uiDefinitionContainer = this.getUIDefinitionContainer(runtimeData);
1978
- const runtimeModel = RuntimeModel.create(runtimeData.types, runtimeData.products);
1979
- const { productName, properties } = Array.from(runtimeModel.components.values()).find(c => c.productId === productId) ?? {};
1980
- const uiDefinitionProperties = uiDefinitionContainer?.source.properties;
1981
- return {
1982
- modelId: runtimeData.modelId,
1983
- uiDefinitionContainer: uiDefinitionContainer,
1984
- runtimeModel: runtimeModel,
1985
- runtimeMode: RuntimeMode.PROD,
1986
- productId: productId,
1987
- productType: properties?.['displayName'] || productName,
1988
- offeringId: offeringId,
1989
- properties: {
1990
- PricingEnabled: uiDefinitionProperties?.pricingEnabled ? 'true' : 'false',
1991
- PriceListId: uiDefinitionProperties?.priceList,
1992
- },
1993
- };
1994
- }));
1747
+ get chargesSnapshot() {
1748
+ return this.configurationState.value?.charges ?? {};
1995
1749
  }
1996
- getUIDefinitionContainer(runtimeData) {
1997
- const containers = runtimeData.uiDefinitions.filter(container => isNotLegacyUIDefinition(container.source));
1998
- return containers.find(container => container.source.primary) ?? containers[0];
1750
+ get pricePlans$() {
1751
+ return this.configurationState.pipe(map(state => state?.pricePlans ?? {}));
1999
1752
  }
2000
- }
2001
- RuntimeContextService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, deps: [{ token: i1.ConfigurationApiService }], target: i0.ɵɵFactoryTarget.Injectable });
2002
- RuntimeContextService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService });
2003
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, decorators: [{
2004
- type: Injectable
2005
- }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }]; } });
2006
-
2007
- class ConfigurationRuntimeService {
2008
- constructor(apiService, contextService, runtimeContextService) {
2009
- this.apiService = apiService;
2010
- this.contextService = contextService;
2011
- this.runtimeContextService = runtimeContextService;
2012
- this._isInitialized = false;
2013
- this.uiDefinitionProperties = {};
1753
+ get pricePlansSnapshot() {
1754
+ return this.configurationState.value?.pricePlans ?? {};
2014
1755
  }
2015
- reset() {
2016
- this._isInitialized = false;
2017
- this._runtimeContext = undefined;
2018
- this.initializationProps = undefined;
2019
- this.uiDefinitionProperties = {};
1756
+ get procedureContext$() {
1757
+ return this.configurationState.pipe(map(state => state?.procedureContext ?? {}));
2020
1758
  }
2021
- initTestMode(uiDefinitionContainer) {
2022
- this.uiDefinitionProperties = uiDefinitionContainer.source.properties ?? {};
2023
- const uiDefinitionExternals = uiDefinitionContainer.source.externals ?? {};
2024
- return combineLatest([
2025
- this.apiService.getRuntimeDataByModelId(uiDefinitionContainer.modelId),
2026
- this.contextService.initTestMode(),
2027
- ]).pipe(first(), map(([runtimeData, context]) => {
2028
- this.contextService.update({
2029
- properties: {
2030
- ...this.runtimeContext?.properties,
2031
- ...context.properties,
2032
- ModelId: uiDefinitionContainer.modelId,
2033
- PricingEnabled: this.uiDefinitionProperties.pricingEnabled ? 'true' : 'false',
2034
- PriceListId: this.uiDefinitionProperties.priceList,
2035
- offeringId: this.uiDefinitionProperties.offeringId,
2036
- ...uiDefinitionExternals,
2037
- },
1759
+ get procedureContextSnapshot() {
1760
+ return this.configurationState.value?.procedureContext ?? {};
1761
+ }
1762
+ configure() {
1763
+ return this.configureRequest$(this.generateRequest());
1764
+ }
1765
+ configureRequest$(configurationRequest) {
1766
+ const runtimeContext = this.getRuntimeContext();
1767
+ const runtimeModel = this.getRuntimeModel();
1768
+ const uiDefinitionProperties = this.getUIDefinitionProperties();
1769
+ const mainPricingEnabled = runtimeContext.properties?.PricingEnabled;
1770
+ const pricingEnabled = mainPricingEnabled ? mainPricingEnabled === 'true' : uiDefinitionProperties.pricingEnabled;
1771
+ const customPriceApi = this.runtimeSettings.getConfigurationSettings()['CUSTOM_PRICE_API'];
1772
+ this.isLoadingSubj$.next(true);
1773
+ const configure$ = pricingEnabled && customPriceApi
1774
+ ? this.configurationApiService.customConfigurePrice({
1775
+ url: customPriceApi,
1776
+ configurationRequest,
1777
+ runtimeModel,
1778
+ })
1779
+ : this.extendedConfigureLineItem$({
1780
+ configurationRequest,
1781
+ runtimeModel,
1782
+ pricingEnabled,
2038
1783
  });
2039
- this._runtimeContext = {
2040
- modelId: uiDefinitionContainer.modelId,
2041
- runtimeModel: RuntimeModel.create(runtimeData.types, runtimeData.products),
2042
- runtimeMode: RuntimeMode.TEST,
2043
- uiDefinitionContainer,
2044
- };
2045
- return this._runtimeContext;
2046
- }), tap(() => (this._isInitialized = true)));
1784
+ return configure$.pipe(tap(result => {
1785
+ this.configurationState.next(result);
1786
+ this.previousConfigurationState.next(cloneDeep(result));
1787
+ if (result.deletedLineItems?.length) {
1788
+ this.showInactiveProductsConfirmation();
1789
+ }
1790
+ this.configurableRamp = result.lineItem;
1791
+ }), map(({ lineItem }) => lineItem), catchError$1(error => throwError(() => {
1792
+ const resetState = this.previousConfigurationState.value;
1793
+ if (resetState) {
1794
+ this.previousConfigurationState.next(cloneDeep(resetState));
1795
+ this.configurationState.next(resetState);
1796
+ }
1797
+ if (error.error) {
1798
+ return extractErrorDetails(error.error).join('. ');
1799
+ }
1800
+ return error.message || JSON.stringify(error);
1801
+ })), finalize$1(() => this.isLoadingSubj$.next(false)));
2047
1802
  }
2048
- init(props) {
2049
- this.initializationProps = props;
2050
- const context = this.contextService.resolve();
2051
- return this.runtimeContextService
2052
- .getRuntimeContext(props.productId, props.offeringId, props.defaultUIDefinitionId, props.requiredUIDefinitionId)
2053
- .pipe(tap(runtimeContext => {
2054
- this.uiDefinitionProperties = runtimeContext.uiDefinitionContainer?.source.properties ?? {};
2055
- const { PriceListId } = context.properties ?? {};
2056
- const mergeContext = {
2057
- ...runtimeContext,
2058
- properties: {
2059
- ...runtimeContext.properties,
2060
- ...context.properties,
2061
- PricingEnabled: PriceListId ? 'true' : 'false',
2062
- },
2063
- };
2064
- this.id15to18('AccountId', mergeContext.properties);
2065
- this._runtimeContext = mergeContext;
2066
- if (context.properties && this._runtimeContext.properties?.StartDate) {
2067
- this.contextService.update({
2068
- properties: {
2069
- ...this._runtimeContext.properties,
2070
- ...context.properties,
2071
- },
2072
- });
1803
+ configureExternal$(props) {
1804
+ return this.runtimeService
1805
+ .init({ productId: props.productId, defaultQty: props.qty, attributesMap: props.attributesMap })
1806
+ .pipe(switchMap$1(() => this.configure()), first(), catchError$1(error => {
1807
+ this.messageService.add({ severity: ToastType.error, summary: error });
1808
+ throw error;
1809
+ }), finalize$1(() => this.reset()));
1810
+ }
1811
+ configureGuidedSelling$(data) {
1812
+ return this.extendedConfigureLineItem$({
1813
+ configurationRequest: getGuidedSellingConfigurationRequest(data),
1814
+ }).pipe(catchError$1(error => {
1815
+ if (error instanceof HttpErrorResponse) {
1816
+ this.messageService.add({ severity: ToastType.error, summary: error.error.message || error.error });
2073
1817
  }
2074
- return this._runtimeContext;
2075
- }), tap(() => (this._isInitialized = true)));
1818
+ throw error;
1819
+ }));
2076
1820
  }
2077
- overrideUIDefinition(uiDefinitionContainer) {
2078
- if (!this._runtimeContext) {
2079
- return;
1821
+ generateRequest(lightMode = true) {
1822
+ const lineItem = this.generateLineItem();
1823
+ let request = {
1824
+ lineItem,
1825
+ mode: this.mode,
1826
+ step: !this.configurationState.value?.lineItem ? RuntimeStep.START : RuntimeStep.UPDATE,
1827
+ attributeDomainMode: 'ALL',
1828
+ context: this.quoteDraftService.quoteDraft?.context ?? generateEmptyContext(),
1829
+ lineItems: this.quoteDraftService.quoteDraft?.currentState || [],
1830
+ asset: this.getAsset(),
1831
+ };
1832
+ if (lightMode) {
1833
+ request = ConfigurationTranslatorUtils.lightenConfigurationRequest(request);
2080
1834
  }
2081
- this._runtimeContext.uiDefinitionContainer = uiDefinitionContainer;
2082
- this.uiDefinitionProperties = uiDefinitionContainer.source.properties ?? {};
1835
+ return request;
2083
1836
  }
2084
- id15to18(propertyName, source) {
2085
- if (!source) {
2086
- return;
1837
+ generateLineItem() {
1838
+ const runtimeContext = this.getRuntimeContext();
1839
+ const uiDefinitionProperties = this.getUIDefinitionProperties();
1840
+ let lineItem = this.configurableRamp;
1841
+ if (!lineItem) {
1842
+ const { initializationProps } = this.runtimeService ?? {};
1843
+ lineItem = getDefaultLineItem(runtimeContext, uiDefinitionProperties, initializationProps?.defaultQty);
1844
+ // Set default attributes
1845
+ if (initializationProps?.attributesMap) {
1846
+ const attributes = transform(initializationProps?.attributesMap, (acc, value, name) => acc.push({ name, value }), []);
1847
+ lineItem = new LineItemWorker(lineItem).patchAttribute(attributes).li;
1848
+ }
2087
1849
  }
2088
- const value = source[propertyName];
2089
- if (typeof value === 'string' && value.length === 15) {
2090
- source[propertyName] = SalesforceIdUtils.generateId18FromId15(value);
1850
+ return lineItem;
1851
+ }
1852
+ getAsset() {
1853
+ const lineItem = this.configurableRamp;
1854
+ if (!lineItem) {
1855
+ return;
2091
1856
  }
1857
+ const assetId = lineItem.assetId ?? lineItem.openOrderLineItemId;
1858
+ return this.quoteDraftService.assetsState?.initialState.find(li => assetPredicateFn(li, assetId));
2092
1859
  }
2093
- get isInitialized() {
2094
- return this._isInitialized;
1860
+ getUIDefinitionProperties() {
1861
+ return {
1862
+ ...(this.getRuntimeContext().uiDefinitionContainer?.source.properties ?? {}),
1863
+ ...(this.runtimeService.uiDefinitionProperties ?? {}),
1864
+ };
2095
1865
  }
2096
- get runtimeModel() {
2097
- return this.runtimeContext?.runtimeModel;
1866
+ showInactiveProductsConfirmation() {
1867
+ const confirmationConfig = {
1868
+ title: ' ',
1869
+ description: 'This quote contains inactive products. Do you want to remove them?',
1870
+ primaryButtonLabel: 'Remove products',
1871
+ secondaryButtonLabel: 'Back to Quote',
1872
+ };
1873
+ this.dialogService
1874
+ .open(ConfirmationComponent, {
1875
+ dismissableMask: false,
1876
+ closeOnEscape: false,
1877
+ closable: false,
1878
+ showHeader: true,
1879
+ header: `Inactive Products in Quote`,
1880
+ width: '440px',
1881
+ data: { confirmationConfig },
1882
+ })
1883
+ .onClose.subscribe(result => {
1884
+ if (!result) {
1885
+ const Id = this.quoteDraftService.quoteDraft?.context.properties.Id ?? '';
1886
+ window['VELO_BACK_FN'].apply(null, [Id]);
1887
+ }
1888
+ });
2098
1889
  }
2099
- get runtimeContext() {
2100
- return this._runtimeContext;
1890
+ extendedConfigureLineItem$({ configurationRequest, runtimeModel, pricingEnabled, }) {
1891
+ return this.configurationApiService.configureLineItem({
1892
+ configurationRequest: configurationRequest,
1893
+ runtimeModel,
1894
+ pricingEnabled,
1895
+ });
2101
1896
  }
2102
1897
  }
2103
- ConfigurationRuntimeService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, deps: [{ token: i1.ConfigurationApiService }, { token: ContextService }, { token: RuntimeContextService }], target: i0.ɵɵFactoryTarget.Injectable });
2104
- ConfigurationRuntimeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService });
2105
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, decorators: [{
1898
+ ConfigurationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService, deps: [{ token: QuoteDraftService }, { token: ConfigurationRuntimeService }, { token: i1.ConfigurationApiService }, { token: i4.MessageService }, { token: i5.DialogService }, { token: RuntimeSettingsService }, { token: FlowInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
1899
+ ConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService });
1900
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationService, decorators: [{
2106
1901
  type: Injectable
2107
- }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }, { type: ContextService }, { type: RuntimeContextService }]; } });
1902
+ }], ctorParameters: function () { return [{ type: QuoteDraftService }, { type: ConfigurationRuntimeService }, { type: i1.ConfigurationApiService }, { type: i4.MessageService }, { type: i5.DialogService }, { type: RuntimeSettingsService }, { type: FlowInfoService }]; } });
2108
1903
 
2109
1904
  class ConfigurationStateService {
2110
- constructor(configurationRuntimeService, configurationService, quoteDraftService, toastService, flowStateService, flowInfoService, flowConfigurationService, flowStateApiService, quoteApiService) {
1905
+ constructor(configurationRuntimeService, configurationService,
1906
+ // private quoteDraftService: QuoteDraftService,
1907
+ salesTransactionService, toastService, flowStateService, flowInfoService, flowConfigurationService, flowStateApiService,
1908
+ // private quoteApiService: QuoteApiService,
1909
+ salesTransactionApiService) {
2111
1910
  this.configurationRuntimeService = configurationRuntimeService;
2112
1911
  this.configurationService = configurationService;
2113
- this.quoteDraftService = quoteDraftService;
1912
+ this.salesTransactionService = salesTransactionService;
2114
1913
  this.toastService = toastService;
2115
1914
  this.flowStateService = flowStateService;
2116
1915
  this.flowInfoService = flowInfoService;
2117
1916
  this.flowConfigurationService = flowConfigurationService;
2118
1917
  this.flowStateApiService = flowStateApiService;
2119
- this.quoteApiService = quoteApiService;
1918
+ this.salesTransactionApiService = salesTransactionApiService;
2120
1919
  this.isInitialized$ = new BehaviorSubject(false);
2121
1920
  this.canceledConfiguration$ = new Subject();
2122
1921
  this.NOT_INITIALIZED = Symbol();
@@ -2140,9 +1939,9 @@ class ConfigurationStateService {
2140
1939
  request$ = this.initStateful$();
2141
1940
  }
2142
1941
  else {
2143
- request$ = this.initStateless$();
1942
+ request$ = of(undefined);
2144
1943
  }
2145
- return request$.pipe(finalize(() => {
1944
+ return request$.pipe(take(1), tap$1(() => {
2146
1945
  this.isInitialized$.next(true);
2147
1946
  this.canceledConfiguration$ = new Subject();
2148
1947
  }));
@@ -2181,7 +1980,7 @@ class ConfigurationStateService {
2181
1980
  }
2182
1981
  // prevent parallel configuration requests in stateless mode
2183
1982
  if (!this.statelessExecutionRequest$) {
2184
- this.statelessExecutionRequest$ = executionRequest$.pipe(shareReplay$1(), take$1(1), finalize(() => (this.statelessExecutionRequest$ = null)));
1983
+ this.statelessExecutionRequest$ = executionRequest$.pipe(shareReplay(), take(1), finalize(() => (this.statelessExecutionRequest$ = null)));
2185
1984
  }
2186
1985
  return this.statelessExecutionRequest$;
2187
1986
  }
@@ -2218,56 +2017,45 @@ class ConfigurationStateService {
2218
2017
  this.executeRequest$(request).subscribe();
2219
2018
  }
2220
2019
  }
2221
- return subscription.data$.pipe(filter$1(data => data != this.NOT_INITIALIZED), map$1(data => data), distinctUntilChanged(), finalize(() => {
2020
+ return subscription.data$.pipe(filter(data => data != this.NOT_INITIALIZED), map$1(data => data), distinctUntilChanged(), finalize(() => {
2222
2021
  if (!this.subscriptions[requestId]?.data$.observed) {
2223
2022
  delete this.subscriptions[requestId];
2224
2023
  }
2225
2024
  }), takeUntil(this.canceledConfiguration$));
2226
2025
  }
2227
- saveConfiguration(flow) {
2026
+ saveConfiguration() {
2228
2027
  if (this.isStatefulConfiguration) {
2229
- return this.flowStateApiService
2230
- .saveConfiguration(this.flowStateService.stateId ?? '', this.stateId ?? '')
2231
- .pipe(switchMap(r => this.flowStateService.executeRequest$({}, true).pipe(map$1(() => r))));
2232
- }
2233
- else {
2234
- if (!flow) {
2235
- const quoteDraft = this.quoteDraftService.quoteDraft;
2236
- if (!quoteDraft) {
2237
- return of({ quoteId: '' });
2238
- }
2239
- const rootLineItem = this.configurationService.getSnapshot();
2240
- const asset = this.configurationService.getAsset();
2241
- const currentState = rootLineItem ? [rootLineItem] : [];
2242
- const initialState = asset ? [asset] : [];
2243
- return this.quoteApiService.upsertQuote({ ...quoteDraft, currentState, initialState });
2244
- }
2245
- else {
2246
- const quoteDraft = this.quoteDraftService.quoteDraft;
2247
- const lineItem = this.configurationService.getSnapshot();
2248
- if (!quoteDraft || !lineItem) {
2249
- return of({ quoteId: '' });
2250
- }
2251
- const isNewLineItem = quoteDraft.currentState.every(li => li.id !== lineItem.id);
2252
- let currentState;
2253
- if (isNewLineItem) {
2254
- currentState = [...quoteDraft.currentState, lineItem];
2255
- }
2256
- else {
2257
- currentState = quoteDraft.currentState.map(li => (li.id === lineItem.id ? lineItem : li));
2258
- }
2259
- const asset = this.configurationService.getAsset();
2260
- const initialState = [...(this.quoteDraftService.quoteDraft?.initialState ?? [])];
2261
- if (asset) {
2262
- if (!initialState.some(li => li.id === asset.id)) {
2263
- initialState.push(asset);
2264
- }
2265
- }
2266
- return this.flowConfigurationService
2267
- .calculate$({ ...quoteDraft, currentState, initialState })
2268
- .pipe(map$1(() => ({ quoteId: '' })));
2269
- }
2270
- }
2028
+ return this.flowStateApiService.saveConfiguration(this.flowStateService.stateId ?? '', this.stateId ?? '').pipe(switchMap(r => this.flowStateService.executeRequest$({}, true).pipe(map$1(() => r))), map$1(r => ({ id: r.quoteId })));
2029
+ }
2030
+ const state = this.salesTransactionService.state;
2031
+ if (!state) {
2032
+ return of({ id: '' });
2033
+ }
2034
+ const { standalone } = this.flowInfoService.flow.properties;
2035
+ if (standalone) {
2036
+ return this.salesTransactionApiService.upsert(state);
2037
+ }
2038
+ // const lineItem = this.configurationService.getSnapshot();
2039
+ // if (!lineItem) {
2040
+ // return of({ id: '' });
2041
+ // }
2042
+ // const isNewLineItem = quoteDraft.currentState.every(li => li.id !== lineItem.id);
2043
+ // let currentState: LineItem[];
2044
+ // if (isNewLineItem) {
2045
+ // currentState = [...quoteDraft.currentState, lineItem];
2046
+ // } else {
2047
+ // currentState = quoteDraft.currentState.map(li => (li.id === lineItem.id ? lineItem : li));
2048
+ // }
2049
+ // const asset = this.configurationService.getAsset();
2050
+ // const initialState = [...(this.quoteDraftService.quoteDraft?.initialState ?? [])];
2051
+ // if (asset) {
2052
+ // if (!initialState.some(li => li.id === asset.id)) {
2053
+ // initialState.push(asset);
2054
+ // }
2055
+ // }
2056
+ // TODO: adjust the logic for ShoppingCart
2057
+ const newState = { ...state };
2058
+ return this.flowConfigurationService.calculate$(newState).pipe(map$1(() => ({ id: '' })));
2271
2059
  }
2272
2060
  cancelConfiguration() {
2273
2061
  if (!this.isInitialized$.value) {
@@ -2313,9 +2101,6 @@ class ConfigurationStateService {
2313
2101
  return undefined;
2314
2102
  }));
2315
2103
  }
2316
- initStateless$() {
2317
- return this.configurationService.configure().pipe(map$1(() => undefined));
2318
- }
2319
2104
  execToRequest(exec) {
2320
2105
  return {
2321
2106
  actions: exec.actions?.map(action => ({
@@ -2412,12 +2197,12 @@ class ConfigurationStateService {
2412
2197
  }));
2413
2198
  }
2414
2199
  executeStateful$(request) {
2415
- return this.executionInProgress$.pipe(filter$1(inProgress => !inProgress), take$1(1), switchMap(() =>
2200
+ return this.executionInProgress$.pipe(filter(inProgress => !inProgress), take(1), switchMap(() =>
2416
2201
  // make sure stream switches to statefulExecutionRequest$ before pushing an execution request
2417
2202
  combineLatest([
2418
2203
  this.statefulExecutionRequest$,
2419
2204
  of(undefined).pipe(tap$1(() => this.statefulRequestStream$.next(request))),
2420
- ])), map$1(([response]) => response), take$1(1));
2205
+ ])), map$1(([response]) => response), take(1));
2421
2206
  }
2422
2207
  executeActionScript(request, processor) {
2423
2208
  const { actions } = this.configurationRuntimeService.runtimeContext?.uiDefinitionContainer ?? {};
@@ -2469,11 +2254,11 @@ class ConfigurationStateService {
2469
2254
  }, { stateId: '', selectors: {} });
2470
2255
  }
2471
2256
  }
2472
- ConfigurationStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationStateService, deps: [{ token: ConfigurationRuntimeService }, { token: ConfigurationService }, { token: QuoteDraftService }, { token: i6.ToastService }, { token: FlowStateService }, { token: FlowInfoService }, { token: FlowConfigurationService }, { token: i1.FlowStateApiService }, { token: i1.QuoteApiService }], target: i0.ɵɵFactoryTarget.Injectable });
2257
+ ConfigurationStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationStateService, deps: [{ token: ConfigurationRuntimeService }, { token: ConfigurationService }, { token: SalesTransactionService }, { token: i6.ToastService }, { token: FlowStateService }, { token: FlowInfoService }, { token: FlowConfigurationService }, { token: i1.FlowStateApiService }, { token: i2.SalesTransactionApiService }], target: i0.ɵɵFactoryTarget.Injectable });
2473
2258
  ConfigurationStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationStateService });
2474
2259
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationStateService, decorators: [{
2475
2260
  type: Injectable
2476
- }], ctorParameters: function () { return [{ type: ConfigurationRuntimeService }, { type: ConfigurationService }, { type: QuoteDraftService }, { type: i6.ToastService }, { type: FlowStateService }, { type: FlowInfoService }, { type: FlowConfigurationService }, { type: i1.FlowStateApiService }, { type: i1.QuoteApiService }]; } });
2261
+ }], ctorParameters: function () { return [{ type: ConfigurationRuntimeService }, { type: ConfigurationService }, { type: SalesTransactionService }, { type: i6.ToastService }, { type: FlowStateService }, { type: FlowInfoService }, { type: FlowConfigurationService }, { type: i1.FlowStateApiService }, { type: i2.SalesTransactionApiService }]; } });
2477
2262
 
2478
2263
  class ConfigurationModule {
2479
2264
  }
@@ -2488,6 +2273,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
2488
2273
  }]
2489
2274
  }] });
2490
2275
 
2276
+ class CatalogProductsService {
2277
+ constructor() {
2278
+ this.stateSubj$ = new BehaviorSubject(null);
2279
+ this.state$ = this.stateSubj$.asObservable().pipe(filter(isDefined));
2280
+ }
2281
+ get state() {
2282
+ return this.stateSubj$.getValue();
2283
+ }
2284
+ reset() {
2285
+ this.stateSubj$.next(null);
2286
+ }
2287
+ setState(state) {
2288
+ this.stateSubj$.next(state);
2289
+ }
2290
+ }
2291
+ CatalogProductsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: CatalogProductsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2292
+ CatalogProductsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: CatalogProductsService });
2293
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: CatalogProductsService, decorators: [{
2294
+ type: Injectable
2295
+ }] });
2296
+
2491
2297
  const DEFAULT_FORMATTING_SETTINGS = {
2492
2298
  currencySymbol: DEFAULT_CURRENCY_SYMBOL,
2493
2299
  decimalsCount: DEFAULT_DECIMALS_COUNT,
@@ -2501,7 +2307,6 @@ class SdkCoreModule {
2501
2307
  SdkCoreModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SdkCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2502
2308
  SdkCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: SdkCoreModule, imports: [ConfigurationModule, FlowConfigurationModule] });
2503
2309
  SdkCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SdkCoreModule, providers: [
2504
- ContextService,
2505
2310
  FlowInfoService,
2506
2311
  QuoteDraftService,
2507
2312
  ProductImagesService,
@@ -2509,6 +2314,8 @@ SdkCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version:
2509
2314
  FlowStateService,
2510
2315
  FlowStateConfigurationService,
2511
2316
  RuntimeSettingsService,
2317
+ SalesTransactionService,
2318
+ CatalogProductsService,
2512
2319
  {
2513
2320
  provide: FORMATTING_SETTINGS_TOKEN,
2514
2321
  useExisting: RuntimeSettingsService,
@@ -2519,7 +2326,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
2519
2326
  args: [{
2520
2327
  imports: [ConfigurationModule, FlowConfigurationModule],
2521
2328
  providers: [
2522
- ContextService,
2523
2329
  FlowInfoService,
2524
2330
  QuoteDraftService,
2525
2331
  ProductImagesService,
@@ -2527,6 +2333,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
2527
2333
  FlowStateService,
2528
2334
  FlowStateConfigurationService,
2529
2335
  RuntimeSettingsService,
2336
+ SalesTransactionService,
2337
+ CatalogProductsService,
2530
2338
  {
2531
2339
  provide: FORMATTING_SETTINGS_TOKEN,
2532
2340
  useExisting: RuntimeSettingsService,
@@ -2701,5 +2509,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
2701
2509
  * Generated bundle index. Do not edit.
2702
2510
  */
2703
2511
 
2704
- export { ActionCodePipe, CalendarDirective, ConfigurationRuntimeService, ConfigurationService, ConfigurationStateService, ContextService, DEFAULT_FORMATTING_SETTINGS, DatePipe, FLOW_CUSTOMIZATION, FORMATTING_SETTINGS_TOKEN, FlowConfigurationModule, FlowConfigurationService, FlowInfoService, FlowStateConfigurationService, FlowStateService, FlowUpdateService, IntegrationState, LineItemWorker, NumberPipe, PricePipe, ProductImagesService, QuoteDraftService, RuntimeMode, RuntimeOperation, RuntimeSettingsService, RuntimeStep, SdkCoreModule, SdkDirectivesModule, SdkPipesModule, UI_DEFINITION_VERSION, assetPredicateFn, extractMetadata, filterOutTechnicalAttributes, findLineItem, findLineItemWithComparator, generateConfigurationLineItem, generateLineItem, getAttributeValue, getAttributes, getDefaultLineItem, getGuidedSellingConfigurationRequest, getOriginParent, getRecommendedPrices, insertLineItem, isTechnicalAttribute, lineItem_utils as lineItemUtils, mapAttributes, multiplyLineItems, patchAttributes, recalculateCardinalityVariables, removeLineItem, replaceLineItem, upsertAttributes };
2512
+ export { ActionCodePipe, CalendarDirective, ConfigurationRuntimeService, ConfigurationService, ConfigurationStateService, DEFAULT_FORMATTING_SETTINGS, DatePipe, FLOW_CUSTOMIZATION, FORMATTING_SETTINGS_TOKEN, FlowConfigurationModule, FlowConfigurationService, FlowInfoService, FlowStateConfigurationService, FlowStateService, FlowUpdateService, IntegrationState, LineItemWorker, NumberPipe, PricePipe, ProductImagesService, QuoteDraftService, RuntimeMode, RuntimeOperation, RuntimeSettingsService, RuntimeStep, SalesTransactionService, SdkCoreModule, SdkDirectivesModule, SdkPipesModule, UI_DEFINITION_VERSION, assetPredicateFn, extractMetadata, filterOutTechnicalAttributes, findLineItem, findLineItemWithComparator, generateConfigurationLineItem, generateEmptyContext, generateLineItem, getAttributeValue, getAttributes, getDefaultLineItem, getGuidedSellingConfigurationRequest, getOriginParent, getRecommendedPrices, insertLineItem, isTechnicalAttribute, lineItem_utils as lineItemUtils, mapAttributes, multiplyLineItems, patchAttributes, recalculateCardinalityVariables, removeLineItem, replaceLineItem, upsertAttributes };
2705
2513
  //# sourceMappingURL=veloceapps-sdk-core.mjs.map