@veloceapps/sdk 11.0.0-11 → 11.0.0-12

Sign up to get free protection for your applications and to get access to all the features.
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