@veloceapps/sdk 8.0.0-35 → 8.0.0-36

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InjectionToken, Injectable, NgModule, inject, Directive, Input, LOCALE_ID, Pipe } from '@angular/core';
3
- import { UUID, ConfigurationContextMode, ConfigurationContext, RuntimeModel, getUIDefinitionProperties, isLegacyUIDefinition, SalesforceIdUtils, ConfigurationMode, ConfigurationTranslatorUtils, EntityUtil, ChargeGroupUtils, DEFAULT_CURRENCY_ISO_CODE, DEFAULT_CURRENCY_SYMBOL, validateDateFormat, DEFAULT_DATE_FORMAT, DEFAULT_DECIMALS_COUNT, getSupportedDateFormats, DEFAULT_DECIMAL_SEPARATOR, DEFAULT_THOUSANDS_SEPARATOR, parseJsonSafely, formatNumber } from '@veloceapps/core';
4
- import { BehaviorSubject, combineLatest, zip, noop, throwError, shareReplay as shareReplay$1, switchMap as switchMap$1, of, tap as tap$1, map as map$2, catchError as catchError$1, Subject, take as take$1, distinctUntilChanged } from 'rxjs';
5
- import { filter, tap, map, first, switchMap, skip, take, shareReplay, catchError, finalize } from 'rxjs/operators';
3
+ import { UUID, ConfigurationContextMode, ConfigurationContext, ChargeGroupUtils, ConfigurationMode, ConfigurationTranslatorUtils, getUIDefinitionProperties, DEFAULT_CURRENCY_ISO_CODE, DEFAULT_CURRENCY_SYMBOL, validateDateFormat, DEFAULT_DATE_FORMAT, DEFAULT_DECIMALS_COUNT, getSupportedDateFormats, DEFAULT_DECIMAL_SEPARATOR, DEFAULT_THOUSANDS_SEPARATOR, parseJsonSafely, RuntimeModel, isLegacyUIDefinition, SalesforceIdUtils, EntityUtil, formatNumber } from '@veloceapps/core';
4
+ import { BehaviorSubject, zip, noop, combineLatest, throwError, shareReplay as shareReplay$1, tap as tap$1, map as map$2, of, switchMap as switchMap$1, catchError as catchError$1, Subject, take as take$1, distinctUntilChanged } from 'rxjs';
5
+ import { filter, tap, map, switchMap, skip, take, shareReplay, catchError, finalize, first } from 'rxjs/operators';
6
6
  import * as i1 from '@veloceapps/api';
7
7
  import { PriceApiService, ContextApiService, ProductModelApiService, ConfigurationApiService } from '@veloceapps/api';
8
- import { merge, flatten, sortBy, map as map$1, isEqual, transform, omit, cloneDeep, uniq } from 'lodash';
8
+ import { merge, isEqual, flatten, sortBy, map as map$1, omit, transform, cloneDeep, uniq } from 'lodash';
9
+ import moment from 'moment';
9
10
  import { HttpErrorResponse } from '@angular/common/http';
10
11
  import * as i4 from '@veloceapps/components';
11
12
  import { ToastType, ConfirmationComponent, ConfirmationDialogModule } from '@veloceapps/components';
12
13
  import * as i5 from 'primeng/api';
13
14
  import * as i6 from 'primeng/dynamicdialog';
14
- import moment from 'moment';
15
15
  import { NgControl } from '@angular/forms';
16
16
  import { DATE_PIPE_DEFAULT_OPTIONS, formatDate } from '@angular/common';
17
17
 
@@ -97,6 +97,13 @@ class ContextService {
97
97
  create(headerId, mode) {
98
98
  return this.contextApiService.getContext(headerId, mode).pipe(tap(context => this.context.next(merge(new ConfigurationContext(headerId, mode), context))), map(() => this.resolve()));
99
99
  }
100
+ initTestMode() {
101
+ return this.create('TestId', ConfigurationContextMode.TEST).pipe(map(context => {
102
+ return this.update({
103
+ properties: Object.assign(Object.assign({}, context.properties), { RuntimeMode: ConfigurationContextMode.TEST, StartDate: new Date().toISOString().substring(0, 10), standalone: 'true' }),
104
+ });
105
+ }));
106
+ }
100
107
  update(partialContext) {
101
108
  const originalContext = this.resolve();
102
109
  const updatedContext = Object.assign(Object.assign(Object.assign({}, originalContext), partialContext), { properties: Object.assign(Object.assign({}, originalContext.properties), partialContext.properties) });
@@ -120,154 +127,281 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
120
127
  args: [{ providedIn: 'root' }]
121
128
  }], ctorParameters: function () { return [{ type: i1.ContextApiService }]; } });
122
129
 
123
- class RuntimeContextService {
124
- constructor(configurationApiService) {
125
- this.configurationApiService = configurationApiService;
126
- }
127
- getRuntimeContext(productId, offeringId) {
128
- return this.configurationApiService.getRuntimeDataByProductId(productId, offeringId).pipe(map(runtimeData => {
129
- var _a;
130
- const uiDefinitionContainer = this.getUIDefinitionContainer(runtimeData);
131
- const runtimeModel = RuntimeModel.create(runtimeData.types, runtimeData.products);
132
- const { productName, properties } = (_a = Array.from(runtimeModel.components.values()).find(c => c.productId === productId)) !== null && _a !== void 0 ? _a : {};
133
- const uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
134
- return {
135
- modelId: runtimeData.modelId,
136
- uiDefinitionContainer: uiDefinitionContainer,
137
- runtimeModel: runtimeModel,
138
- runtimeMode: RuntimeMode.PROD,
139
- productId: productId,
140
- productType: (properties === null || properties === void 0 ? void 0 : properties['displayName']) || productName,
141
- offeringId: offeringId,
142
- properties: {
143
- PricingEnabled: uiDefinitionProperties.pricingEnabled ? 'true' : 'false',
144
- PriceListId: uiDefinitionProperties.priceList,
145
- },
146
- };
147
- }));
148
- }
149
- getUIDefinitionContainer(runtimeData) {
150
- var _a;
151
- const containers = runtimeData.uiDefinitions.filter(container => !isLegacyUIDefinition(container.source));
152
- return (_a = containers.find(container => container.source.primary)) !== null && _a !== void 0 ? _a : containers[0];
130
+ function calculateMetricByMethod(lineItems, metric, method) {
131
+ const items = getLineItemsByMethod(lineItems, method);
132
+ return items.reduce((acc, li) => {
133
+ let value = li.reduce((accProduct, item) => accProduct + ((item.totalMetrics && item.totalMetrics[metric]) || 0), 0);
134
+ if (method === 'avg' && li.length > 0) {
135
+ value /= li.length;
136
+ }
137
+ return acc + value;
138
+ }, 0);
139
+ }
140
+ function getLineItemsByMethod(lineItems, method) {
141
+ switch (method) {
142
+ case 'first': {
143
+ return lineItems.filter(li => !li.rampInstanceId).map(item => [item]);
144
+ }
145
+ case 'last': {
146
+ const rootTermItems = lineItems.filter(li => !li.rampInstanceId);
147
+ const products = rootTermItems.map(lineItem => [
148
+ lineItem,
149
+ ...lineItems.filter(li => li.rampInstanceId === lineItem.id),
150
+ ]);
151
+ return products
152
+ .map(items => [...items].sort((a, b) => getDateValue(a.endDate || '') - getDateValue(b.endDate || '')).pop())
153
+ .filter((li) => Boolean(li))
154
+ .map(item => [item]);
155
+ }
156
+ case 'avg': {
157
+ const rootTermItems = lineItems.filter(li => !li.rampInstanceId);
158
+ return rootTermItems.map(lineItem => [lineItem, ...lineItems.filter(li => li.rampInstanceId === lineItem.id)]);
159
+ }
160
+ case 'sum': {
161
+ return lineItems.map(item => [item]);
162
+ }
163
+ default: {
164
+ return lineItems.map(item => [item]);
165
+ }
153
166
  }
154
167
  }
155
- RuntimeContextService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, deps: [{ token: i1.ConfigurationApiService }], target: i0.ɵɵFactoryTarget.Injectable });
156
- RuntimeContextService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService });
157
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, decorators: [{
158
- type: Injectable
159
- }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }]; } });
168
+ function getDateValue(date) {
169
+ return date ? new Date(date).getTime() : 0;
170
+ }
160
171
 
161
- class ConfigurationRuntimeService {
162
- constructor(apiService, contextService, runtimeContextService) {
163
- this.apiService = apiService;
164
- this.contextService = contextService;
165
- this.runtimeContextService = runtimeContextService;
166
- this._isInitialized = false;
167
- this.uiDefinitionProperties = {};
172
+ class QuoteDraftService {
173
+ get isInitialized() {
174
+ return this.isInitializedSubj$.getValue();
168
175
  }
169
- reset() {
170
- this._isInitialized = false;
171
- this._runtimeContext = undefined;
172
- this.initializationProps = undefined;
173
- this.uiDefinitionProperties = {};
176
+ set isInitialized(value) {
177
+ if (this.isInitialized !== value) {
178
+ this.isInitializedSubj$.next(value);
179
+ }
174
180
  }
175
- initTestMode(uiDefinitionContainer) {
176
- var _a;
177
- this.uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
178
- const uiDefinitionExternals = (_a = uiDefinitionContainer.source.externals) !== null && _a !== void 0 ? _a : {};
179
- return combineLatest([
180
- this.apiService.getRuntimeDataByModelId(uiDefinitionContainer.modelId),
181
- this.contextService.create('TestId', ConfigurationContextMode.TEST),
182
- ]).pipe(first(), map(([runtimeData, context]) => {
183
- var _a;
184
- this.contextService.update({
185
- properties: Object.assign(Object.assign(Object.assign(Object.assign({}, (_a = this.runtimeContext) === null || _a === void 0 ? void 0 : _a.properties), context.properties), { ModelId: uiDefinitionContainer.modelId, RuntimeMode: ConfigurationContextMode.TEST, PricingEnabled: this.uiDefinitionProperties.pricingEnabled ? 'true' : 'false', StartDate: new Date().toISOString().substring(0, 10), PriceListId: this.uiDefinitionProperties.priceList, offeringId: this.uiDefinitionProperties.offeringId, standalone: 'true' }), uiDefinitionExternals),
186
- });
187
- this._runtimeContext = {
188
- modelId: uiDefinitionContainer.modelId,
189
- runtimeModel: RuntimeModel.create(runtimeData.types, runtimeData.products),
190
- runtimeMode: RuntimeMode.TEST,
191
- uiDefinitionContainer,
192
- };
193
- return this._runtimeContext;
194
- }), tap(() => (this._isInitialized = true)));
181
+ get hasUnsavedChanges() {
182
+ return this._hasUnsavedChanges;
195
183
  }
196
- init(props) {
197
- this.initializationProps = props;
198
- const context = this.contextService.resolve();
199
- return this.runtimeContextService.getRuntimeContext(props.productId, props.offeringId).pipe(tap(runtimeContext => {
200
- var _a, _b;
201
- this.uiDefinitionProperties = getUIDefinitionProperties(runtimeContext.uiDefinitionContainer);
202
- const { PriceListId } = (_a = context.properties) !== null && _a !== void 0 ? _a : {};
203
- const mergeContext = Object.assign(Object.assign({}, runtimeContext), { properties: Object.assign(Object.assign(Object.assign({}, runtimeContext.properties), context.properties), { PricingEnabled: PriceListId ? 'true' : 'false' }) });
204
- this.id15to18('AccountId', mergeContext.properties);
205
- this._runtimeContext = mergeContext;
206
- if (context.properties && ((_b = this._runtimeContext.properties) === null || _b === void 0 ? void 0 : _b.StartDate)) {
207
- this.contextService.update({
208
- properties: Object.assign(Object.assign({}, this._runtimeContext.properties), context.properties),
209
- });
210
- }
211
- return this._runtimeContext;
212
- }), tap(() => (this._isInitialized = true)));
184
+ set hasUnsavedChanges(value) {
185
+ var _a, _b;
186
+ this._hasUnsavedChanges = value;
187
+ if (!this._hasUnsavedChanges) {
188
+ this.initialCurrentState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
189
+ }
213
190
  }
214
- overrideUIDefinition(uiDefinitionContainer) {
215
- if (!this._runtimeContext) {
191
+ get hasProducts$() {
192
+ return this.quoteSubj$.pipe(map(() => this.hasProducts));
193
+ }
194
+ get hasProducts() {
195
+ const quoteDraft = this.quoteSubj$.value;
196
+ return Boolean(quoteDraft && quoteDraft.currentState.length > 0);
197
+ }
198
+ constructor(context, quoteApiService, priceApiService) {
199
+ this.context = context;
200
+ this.quoteApiService = quoteApiService;
201
+ this.priceApiService = priceApiService;
202
+ this.quoteSubj$ = new BehaviorSubject(null);
203
+ this.resetSubj$ = new BehaviorSubject(true);
204
+ this.isInitializedSubj$ = new BehaviorSubject(false);
205
+ this.initialCurrentState = [];
206
+ this._hasUnsavedChanges = false;
207
+ this.allPriceLists = [];
208
+ this.assetPriceLists = [];
209
+ this.reset$ = this.resetSubj$.asObservable();
210
+ this.activePriceList$ = this.context.resolve$().pipe(map(ctx => this.allPriceLists.find(priceList => priceList.id === ctx.properties.PriceListId)), map(priceList => priceList !== null && priceList !== void 0 ? priceList : null));
211
+ this.isInitializedSubj$
212
+ .pipe(filter(isInitialized => isInitialized), switchMap(() => this.quoteSubj$.asObservable()), skip(1), tap(quote => this.markAsUpdated(quote)))
213
+ .subscribe();
214
+ }
215
+ reset() {
216
+ this.resetSubj$.next(true);
217
+ this.quoteSubj$.next(null);
218
+ this.hasUnsavedChanges = false;
219
+ }
220
+ init(quoteId, params) {
221
+ return zip(this.quoteApiService.getQuoteDraft(quoteId, params), this.priceApiService.getPriceLists()).pipe(tap(([quote, allPriceLists]) => {
222
+ this.allPriceLists = allPriceLists;
223
+ this.quoteSubj$.next(quote);
224
+ this.context.update(quote.context);
225
+ this.populateActivePriceLists$();
226
+ }), map(() => noop()), take(1));
227
+ }
228
+ setCurrentLineItemState(lineItems) {
229
+ const quoteDraft = this.quoteSubj$.value;
230
+ if (!quoteDraft) {
216
231
  return;
217
232
  }
218
- this._runtimeContext.uiDefinitionContainer = uiDefinitionContainer;
219
- this.uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
233
+ this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), { currentState: lineItems }));
220
234
  }
221
- id15to18(propertyName, source) {
222
- if (!source) {
235
+ updateQuoteDraft(update) {
236
+ const quoteDraft = this.quoteSubj$.value;
237
+ if (!quoteDraft) {
223
238
  return;
224
239
  }
225
- const value = source[propertyName];
226
- if (typeof value === 'string' && value.length === 15) {
227
- source[propertyName] = SalesforceIdUtils.generateId18FromId15(value);
240
+ if (update.context) {
241
+ this.context.set(update.context);
228
242
  }
243
+ this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), update));
229
244
  }
230
- get isInitialized() {
231
- return this._isInitialized;
245
+ updateByPriceSummary(priceSummary) {
246
+ const quoteDraft = this.quoteSubj$.value;
247
+ if (!quoteDraft) {
248
+ return;
249
+ }
250
+ const updatedCurrentState = this.currentState.map(lineItem => {
251
+ const updated = priceSummary.lineItems.find(li => li.id === lineItem.id);
252
+ return updated !== null && updated !== void 0 ? updated : lineItem;
253
+ });
254
+ this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedCurrentState, totalPrices: priceSummary.totalPrices, approvalItems: priceSummary.approvalItems }));
232
255
  }
233
- get runtimeModel() {
234
- var _a;
235
- return (_a = this.runtimeContext) === null || _a === void 0 ? void 0 : _a.runtimeModel;
256
+ get quoteDraft$() {
257
+ return combineLatest([this.quoteSubj$, this.context.resolve$()]).pipe(map(() => this.quoteDraft), filter((quote) => Boolean(quote)), shareReplay());
236
258
  }
237
- get runtimeContext() {
238
- return this._runtimeContext;
259
+ get quoteDraft() {
260
+ const quote = this.quoteSubj$.value;
261
+ if (!quote) {
262
+ return null;
263
+ }
264
+ return Object.assign(Object.assign({}, quote), { context: this.context.resolve() });
239
265
  }
240
- }
241
- 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 });
242
- ConfigurationRuntimeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService });
243
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, decorators: [{
244
- type: Injectable
245
- }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }, { type: ContextService }, { type: RuntimeContextService }]; } });
246
-
247
- const findLineItem = (id, lineItems) => {
248
- return findLineItemWithComparator(lineItems, (li) => li.id === id);
249
- };
250
- const findLineItemWithComparator = (lineItems, comparator) => {
251
- let currentLevel = lineItems;
252
- while (currentLevel.length) {
253
- const found = currentLevel.find(comparator);
254
- if (found) {
255
- return found;
266
+ get quoteDraftForActivePriceList() {
267
+ const quoteDraft = this.quoteDraft;
268
+ if (!quoteDraft) {
269
+ return null;
256
270
  }
257
- currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
271
+ return Object.assign(Object.assign({}, quoteDraft), { initialState: this.filterByActivePriceList(quoteDraft.initialState), currentState: this.filterByActivePriceList(quoteDraft.currentState) });
258
272
  }
259
- return;
260
- };
261
- const insertLineItem = (lineItem, parentId, toInsert) => {
262
- const insertData = lineItem.id === parentId ? [toInsert] : [];
263
- return Object.assign(Object.assign({}, lineItem), { lineItems: [
264
- ...insertData,
265
- ...lineItem.lineItems.map(li => {
266
- return insertLineItem(li, parentId, toInsert);
267
- }),
268
- ] });
269
- };
270
- const removeLineItem = (lineItem, idToRemove) => {
273
+ get currentState$() {
274
+ return this.quoteDraft$.pipe(map(quote => quote.currentState));
275
+ }
276
+ get currentState() {
277
+ var _a, _b;
278
+ return (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
279
+ }
280
+ /**
281
+ * Stream of activeCurrentState
282
+ */
283
+ get activeCurrentState$() {
284
+ return this.quoteDraft$.pipe(map(() => this.activeCurrentState));
285
+ }
286
+ /**
287
+ * activeCurrentState is currentState passed through additional filters
288
+ */
289
+ get activeCurrentState() {
290
+ var _a, _b;
291
+ let currentState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
292
+ currentState = this.filterByActivePriceList(currentState);
293
+ return currentState;
294
+ }
295
+ /**
296
+ * Stream of activeInitialState
297
+ */
298
+ get activeInitialState$() {
299
+ return this.quoteDraft$.pipe(map(() => this.activeInitialState));
300
+ }
301
+ /**
302
+ * activeInitialState is initialState passed through additional filters
303
+ */
304
+ get activeInitialState() {
305
+ var _a, _b;
306
+ const ctx = this.context.resolve();
307
+ let initialState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.initialState) !== null && _b !== void 0 ? _b : [];
308
+ if (ctx.mode === ConfigurationContextMode.ACCOUNT) {
309
+ initialState = this.filterByActivePriceList(initialState);
310
+ }
311
+ return initialState;
312
+ }
313
+ get isStandalone() {
314
+ return this.context.resolve().properties.standalone === 'true';
315
+ }
316
+ get isStandalone$() {
317
+ return this.context.resolve$().pipe(map(() => this.isStandalone));
318
+ }
319
+ getInitialCurrentState() {
320
+ return this.initialCurrentState;
321
+ }
322
+ isEditMode$() {
323
+ return this.context.resolve$().pipe(map(() => this.isEditMode()));
324
+ }
325
+ isEditMode() {
326
+ const context = this.context.resolve();
327
+ if (context.mode === ConfigurationContextMode.ACCOUNT) {
328
+ return true;
329
+ }
330
+ if (context.mode === ConfigurationContextMode.QUOTE) {
331
+ return context.properties.Status === 'Draft';
332
+ }
333
+ return false;
334
+ }
335
+ updateActivePriceList(priceListId) {
336
+ this.context.update({ properties: { PriceListId: priceListId } });
337
+ }
338
+ populateActivePriceLists$() {
339
+ const ctx = this.context.resolve();
340
+ const quoteDraft = this.quoteDraft;
341
+ if (!quoteDraft) {
342
+ return;
343
+ }
344
+ // In ACCOUNT mode populate price lists from related assets
345
+ if (ctx.mode === ConfigurationContextMode.ACCOUNT) {
346
+ // Populate list of price lists
347
+ this.assetPriceLists = quoteDraft.currentState
348
+ .map(({ priceListId }) => priceListId)
349
+ .reduce((trunk, priceListId) => {
350
+ var _a, _b;
351
+ if (!priceListId || trunk.some(item => item.id === priceListId)) {
352
+ return trunk;
353
+ }
354
+ return [
355
+ ...trunk,
356
+ { id: priceListId, name: (_b = (_a = this.allPriceLists.find(item => item.id === priceListId)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '' },
357
+ ];
358
+ }, []);
359
+ }
360
+ }
361
+ filterByActivePriceList(lineItems) {
362
+ const ctx = this.context.resolve();
363
+ return lineItems.filter(li => !li.priceListId || li.priceListId === ctx.properties.PriceListId);
364
+ }
365
+ markAsUpdated(quote) {
366
+ if ((quote === null || quote === void 0 ? void 0 : quote.context.properties.mode) === ConfigurationContextMode.ACCOUNT) {
367
+ this.hasUnsavedChanges = !!quote && !quote.currentState.every(li => li.actionCode === 'EXIST');
368
+ }
369
+ else {
370
+ this.hasUnsavedChanges = !isEqual(this.initialCurrentState, quote === null || quote === void 0 ? void 0 : quote.currentState);
371
+ }
372
+ }
373
+ }
374
+ QuoteDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, deps: [{ token: ContextService }, { token: i1.QuoteApiService }, { token: i1.PriceApiService }], target: i0.ɵɵFactoryTarget.Injectable });
375
+ QuoteDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, providedIn: 'root' });
376
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, decorators: [{
377
+ type: Injectable,
378
+ args: [{ providedIn: 'root' }]
379
+ }], ctorParameters: function () { return [{ type: ContextService }, { type: i1.QuoteApiService }, { type: i1.PriceApiService }]; } });
380
+
381
+ const findLineItem = (id, lineItems) => {
382
+ return findLineItemWithComparator(lineItems, (li) => li.id === id);
383
+ };
384
+ const findLineItemWithComparator = (lineItems, comparator) => {
385
+ let currentLevel = lineItems;
386
+ while (currentLevel.length) {
387
+ const found = currentLevel.find(comparator);
388
+ if (found) {
389
+ return found;
390
+ }
391
+ currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
392
+ }
393
+ return;
394
+ };
395
+ const insertLineItem = (lineItem, parentId, toInsert) => {
396
+ const insertData = lineItem.id === parentId ? [toInsert] : [];
397
+ return Object.assign(Object.assign({}, lineItem), { lineItems: [
398
+ ...insertData,
399
+ ...lineItem.lineItems.map(li => {
400
+ return insertLineItem(li, parentId, toInsert);
401
+ }),
402
+ ] });
403
+ };
404
+ const removeLineItem = (lineItem, idToRemove) => {
271
405
  return Object.assign(Object.assign({}, lineItem), { lineItems: lineItem.lineItems
272
406
  .map(li => {
273
407
  if (li.id === idToRemove) {
@@ -452,214 +586,145 @@ class LineItemWorker {
452
586
  }
453
587
  }
454
588
 
455
- class QuoteDraftService {
456
- get isInitialized() {
457
- return this.isInitializedSubj$.getValue();
589
+ function extractMetadata(uiDefinition) {
590
+ return omit(uiDefinition, [
591
+ 'children',
592
+ 'pages',
593
+ 'components',
594
+ ]);
595
+ }
596
+
597
+ class FlowUpdateService {
598
+ update(rootLineItems, updates, charges) {
599
+ let remainingUpdates = [...updates];
600
+ let currentLevel = rootLineItems;
601
+ while (currentLevel.length && remainingUpdates.length) {
602
+ currentLevel.forEach(li => {
603
+ const unhandledUpdates = [];
604
+ remainingUpdates.forEach(update => {
605
+ let updated = false;
606
+ switch (update.dataType) {
607
+ case 'LINEITEM':
608
+ updated = this.applyLineItemUpdate(li, update, charges);
609
+ break;
610
+ case 'CHARGE':
611
+ updated = this.applyChargeUpdate(li, update);
612
+ break;
613
+ case 'GROUP_CHARGE':
614
+ updated = this.applyChargeGroupUpdate(li, update);
615
+ break;
616
+ default:
617
+ // Unknown dataType. Do not try to handle it anymore
618
+ updated = true;
619
+ }
620
+ if (!updated) {
621
+ unhandledUpdates.push(update);
622
+ }
623
+ });
624
+ remainingUpdates = unhandledUpdates;
625
+ });
626
+ currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
627
+ }
458
628
  }
459
- set isInitialized(value) {
460
- if (this.isInitialized !== value) {
461
- this.isInitializedSubj$.next(value);
629
+ delete(lineItems, id) {
630
+ const idsToRemove = [id];
631
+ const topLevelLineItem = lineItems.find(li => li.id === id);
632
+ if (topLevelLineItem) {
633
+ // find term-related line items (which are only top level)
634
+ // expired term line items won't be deleted
635
+ let foundTermLineItem = topLevelLineItem;
636
+ while (foundTermLineItem) {
637
+ foundTermLineItem = lineItems.find(li => foundTermLineItem && li.rampInstanceId === foundTermLineItem.id);
638
+ if (foundTermLineItem) {
639
+ idsToRemove.push(foundTermLineItem.id);
640
+ }
641
+ }
462
642
  }
643
+ const filtered = lineItems.filter(lineItem => !idsToRemove.includes(lineItem.id));
644
+ return filtered.map(lineItem => new LineItemWorker(lineItem).remove(id).li);
463
645
  }
464
- get hasUnsavedChanges() {
465
- return this._hasUnsavedChanges;
646
+ applyLineItemUpdate(lineItem, update, charges) {
647
+ if (lineItem.id !== update.id) {
648
+ return false;
649
+ }
650
+ switch (update.attributeType) {
651
+ case 'QTY':
652
+ lineItem.qty = update.newValue;
653
+ break;
654
+ case 'EFFECTIVE_START_DATE':
655
+ lineItem.properties['StartDate'] = moment(update.newValue).format('YYYY-MM-DD');
656
+ break;
657
+ case 'END_DATE':
658
+ lineItem.properties['EndDate'] = moment(update.newValue).format('YYYY-MM-DD');
659
+ break;
660
+ case 'PRICE_ADJUSTMENT':
661
+ {
662
+ const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
663
+ if (charge) {
664
+ charge.priceAdjustment = update.newValue;
665
+ }
666
+ }
667
+ break;
668
+ case 'LIST_PRICE_ADJUSTMENT':
669
+ case 'MARGIN_ADJUSTMENT':
670
+ {
671
+ const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
672
+ if (charge) {
673
+ charge.listPriceAdjustment = update.newValue;
674
+ }
675
+ }
676
+ break;
677
+ case 'COST_ADJUSTMENT':
678
+ {
679
+ const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
680
+ if (charge) {
681
+ charge.costAdjustment = update.newValue;
682
+ }
683
+ }
684
+ break;
685
+ default:
686
+ throw new Error(`Not suppored AttributeType for LineItem update: ${update.attributeType}`);
687
+ }
688
+ return true;
466
689
  }
467
- set hasUnsavedChanges(value) {
468
- var _a, _b;
469
- this._hasUnsavedChanges = value;
470
- if (!this._hasUnsavedChanges) {
471
- this.initialCurrentState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
690
+ applyChargeUpdate(lineItem, update) {
691
+ const foundCharge = lineItem.chargeItems.find(({ id }) => id === update.id);
692
+ if (!foundCharge) {
693
+ return false;
694
+ }
695
+ if (update.attributeType === 'PRICE_ADJUSTMENT') {
696
+ foundCharge.priceAdjustment = update.newValue;
697
+ }
698
+ else if (update.attributeType === 'LIST_PRICE_ADJUSTMENT') {
699
+ foundCharge.listPriceAdjustment = update.newValue;
472
700
  }
701
+ else {
702
+ throw new Error(`Not suppored AttributeType for Charge Item update: ${update.attributeType}`);
703
+ }
704
+ return true;
473
705
  }
474
- get hasProducts$() {
475
- return this.quoteSubj$.pipe(map(() => this.hasProducts));
476
- }
477
- get hasProducts() {
478
- const quoteDraft = this.quoteSubj$.value;
479
- return Boolean(quoteDraft && quoteDraft.currentState.length > 0);
480
- }
481
- constructor(context, quoteApiService, priceApiService) {
482
- this.context = context;
483
- this.quoteApiService = quoteApiService;
484
- this.priceApiService = priceApiService;
485
- this.quoteSubj$ = new BehaviorSubject(null);
486
- this.resetSubj$ = new BehaviorSubject(true);
487
- this.isInitializedSubj$ = new BehaviorSubject(false);
488
- this.initialCurrentState = [];
489
- this._hasUnsavedChanges = false;
490
- this.allPriceLists = [];
491
- this.assetPriceLists = [];
492
- this.reset$ = this.resetSubj$.asObservable();
493
- this.activePriceList$ = this.context.resolve$().pipe(map(ctx => this.allPriceLists.find(priceList => priceList.id === ctx.properties.PriceListId)), map(priceList => priceList !== null && priceList !== void 0 ? priceList : null));
494
- this.isInitializedSubj$
495
- .pipe(filter(isInitialized => isInitialized), switchMap(() => this.quoteSubj$.asObservable()), skip(1), tap(quote => this.markAsUpdated(quote)))
496
- .subscribe();
497
- }
498
- reset() {
499
- this.resetSubj$.next(true);
500
- this.quoteSubj$.next(null);
501
- this.hasUnsavedChanges = false;
502
- }
503
- init(quoteId, params) {
504
- return zip(this.quoteApiService.getQuoteDraft(quoteId, params), this.priceApiService.getPriceLists()).pipe(tap(([quote, allPriceLists]) => {
505
- this.allPriceLists = allPriceLists;
506
- this.quoteSubj$.next(quote);
507
- this.context.update(quote.context);
508
- this.populateActivePriceLists$();
509
- }), map(() => noop()), take(1));
510
- }
511
- setCurrentLineItemState(lineItems) {
512
- const quoteDraft = this.quoteSubj$.value;
513
- if (!quoteDraft) {
514
- return;
515
- }
516
- this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), { currentState: lineItems }));
517
- }
518
- updateQuoteDraft(update) {
519
- const quoteDraft = this.quoteSubj$.value;
520
- if (!quoteDraft) {
521
- return;
522
- }
523
- if (update.context) {
524
- this.context.set(update.context);
525
- }
526
- this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), update));
527
- }
528
- updateByPriceSummary(priceSummary) {
529
- const quoteDraft = this.quoteSubj$.value;
530
- if (!quoteDraft) {
531
- return;
532
- }
533
- const updatedCurrentState = this.currentState.map(lineItem => {
534
- const updated = priceSummary.lineItems.find(li => li.id === lineItem.id);
535
- return updated !== null && updated !== void 0 ? updated : lineItem;
536
- });
537
- this.quoteSubj$.next(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedCurrentState, totalPrices: priceSummary.totalPrices, approvalItems: priceSummary.approvalItems }));
538
- }
539
- get quoteDraft$() {
540
- return combineLatest([this.quoteSubj$, this.context.resolve$()]).pipe(map(() => this.quoteDraft), filter((quote) => Boolean(quote)), shareReplay());
541
- }
542
- get quoteDraft() {
543
- const quote = this.quoteSubj$.value;
544
- if (!quote) {
545
- return null;
546
- }
547
- return Object.assign(Object.assign({}, quote), { context: this.context.resolve() });
548
- }
549
- get quoteDraftForActivePriceList() {
550
- const quoteDraft = this.quoteDraft;
551
- if (!quoteDraft) {
552
- return null;
553
- }
554
- return Object.assign(Object.assign({}, quoteDraft), { initialState: this.filterByActivePriceList(quoteDraft.initialState), currentState: this.filterByActivePriceList(quoteDraft.currentState) });
555
- }
556
- get currentState$() {
557
- return this.quoteDraft$.pipe(map(quote => quote.currentState));
558
- }
559
- get currentState() {
560
- var _a, _b;
561
- return (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
562
- }
563
- /**
564
- * Stream of activeCurrentState
565
- */
566
- get activeCurrentState$() {
567
- return this.quoteDraft$.pipe(map(() => this.activeCurrentState));
568
- }
569
- /**
570
- * activeCurrentState is currentState passed through additional filters
571
- */
572
- get activeCurrentState() {
573
- var _a, _b;
574
- let currentState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.currentState) !== null && _b !== void 0 ? _b : [];
575
- currentState = this.filterByActivePriceList(currentState);
576
- return currentState;
577
- }
578
- /**
579
- * Stream of activeInitialState
580
- */
581
- get activeInitialState$() {
582
- return this.quoteDraft$.pipe(map(() => this.activeInitialState));
583
- }
584
- /**
585
- * activeInitialState is initialState passed through additional filters
586
- */
587
- get activeInitialState() {
588
- var _a, _b;
589
- const ctx = this.context.resolve();
590
- let initialState = (_b = (_a = this.quoteDraft) === null || _a === void 0 ? void 0 : _a.initialState) !== null && _b !== void 0 ? _b : [];
591
- if (ctx.mode === ConfigurationContextMode.ACCOUNT) {
592
- initialState = this.filterByActivePriceList(initialState);
593
- }
594
- return initialState;
595
- }
596
- get isStandalone() {
597
- return this.context.resolve().properties.standalone === 'true';
598
- }
599
- get isStandalone$() {
600
- return this.context.resolve$().pipe(map(() => this.isStandalone));
601
- }
602
- getInitialCurrentState() {
603
- return this.initialCurrentState;
604
- }
605
- isEditMode$() {
606
- return this.context.resolve$().pipe(map(() => this.isEditMode()));
607
- }
608
- isEditMode() {
609
- const context = this.context.resolve();
610
- if (context.mode === ConfigurationContextMode.ACCOUNT) {
611
- return true;
612
- }
613
- if (context.mode === ConfigurationContextMode.QUOTE) {
614
- return context.properties.Status === 'Draft';
615
- }
616
- return false;
617
- }
618
- updateActivePriceList(priceListId) {
619
- this.context.update({ properties: { PriceListId: priceListId } });
620
- }
621
- populateActivePriceLists$() {
622
- const ctx = this.context.resolve();
623
- const quoteDraft = this.quoteDraft;
624
- if (!quoteDraft) {
625
- return;
706
+ applyChargeGroupUpdate(lineItem, update) {
707
+ const foundChargeGroup = ChargeGroupUtils.findChargeGroupById(update.id, lineItem);
708
+ if (!foundChargeGroup) {
709
+ return false;
626
710
  }
627
- // In ACCOUNT mode populate price lists from related assets
628
- if (ctx.mode === ConfigurationContextMode.ACCOUNT) {
629
- // Populate list of price lists
630
- this.assetPriceLists = quoteDraft.currentState
631
- .map(({ priceListId }) => priceListId)
632
- .reduce((trunk, priceListId) => {
633
- var _a, _b;
634
- if (!priceListId || trunk.some(item => item.id === priceListId)) {
635
- return trunk;
636
- }
637
- return [
638
- ...trunk,
639
- { id: priceListId, name: (_b = (_a = this.allPriceLists.find(item => item.id === priceListId)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '' },
640
- ];
641
- }, []);
711
+ if (update.attributeType === 'PRICE_ADJUSTMENT') {
712
+ foundChargeGroup.priceAdjustment = update.newValue;
642
713
  }
643
- }
644
- filterByActivePriceList(lineItems) {
645
- const ctx = this.context.resolve();
646
- return lineItems.filter(li => !li.priceListId || li.priceListId === ctx.properties.PriceListId);
647
- }
648
- markAsUpdated(quote) {
649
- if ((quote === null || quote === void 0 ? void 0 : quote.context.properties.mode) === ConfigurationContextMode.ACCOUNT) {
650
- this.hasUnsavedChanges = !!quote && !quote.currentState.every(li => li.actionCode === 'EXIST');
714
+ else if (update.attributeType === 'LIST_PRICE_ADJUSTMENT') {
715
+ foundChargeGroup.listPriceAdjustment = update.newValue;
651
716
  }
652
717
  else {
653
- this.hasUnsavedChanges = !isEqual(this.initialCurrentState, quote === null || quote === void 0 ? void 0 : quote.currentState);
718
+ throw new Error(`Not suppored AttributeType for Charge Group Item update: ${update.attributeType}`);
654
719
  }
720
+ return true;
655
721
  }
656
722
  }
657
- QuoteDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, deps: [{ token: ContextService }, { token: i1.QuoteApiService }, { token: i1.PriceApiService }], target: i0.ɵɵFactoryTarget.Injectable });
658
- QuoteDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, providedIn: 'root' });
659
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: QuoteDraftService, decorators: [{
660
- type: Injectable,
661
- args: [{ providedIn: 'root' }]
662
- }], ctorParameters: function () { return [{ type: ContextService }, { type: i1.QuoteApiService }, { type: i1.PriceApiService }]; } });
723
+ FlowUpdateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
724
+ FlowUpdateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService });
725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService, decorators: [{
726
+ type: Injectable
727
+ }] });
663
728
 
664
729
  class ConfigurationService {
665
730
  constructor(quoteDraftService, runtimeService, contextService, configurationApiService, messageService, dialogService) {
@@ -870,417 +935,592 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
870
935
  type: Injectable
871
936
  }], ctorParameters: function () { return [{ type: QuoteDraftService }, { type: ConfigurationRuntimeService }, { type: ContextService }, { type: i1.ConfigurationApiService }, { type: i5.MessageService }, { type: i6.DialogService }]; } });
872
937
 
873
- class ConfigurationState {
874
- constructor(statefulConfigurationApiService, runtimeService, configurationService, toastService) {
875
- this.statefulConfigurationApiService = statefulConfigurationApiService;
876
- this.runtimeService = runtimeService;
938
+ class FlowConfigurationService {
939
+ constructor(proceduresApiService, contextService, quoteDraftService, updateService, configurationService) {
940
+ this.proceduresApiService = proceduresApiService;
941
+ this.contextService = contextService;
942
+ this.quoteDraftService = quoteDraftService;
943
+ this.updateService = updateService;
877
944
  this.configurationService = configurationService;
878
- this.toastService = toastService;
879
- this.stateSubj$ = new BehaviorSubject({});
880
- this.state$ = this.stateSubj$.asObservable();
881
- this.stateId = null;
882
945
  }
883
- init$() {
884
- return this.configurationService.configure().pipe(switchMap$1(() => {
885
- var _a, _b;
886
- if (!this.isStatefulConfiguration) {
887
- return of(undefined);
888
- }
889
- const { actions, selectors } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
890
- return this.statefulConfigurationApiService.init({
891
- request: this.configurationService.generateRequest(),
892
- actions: actions === null || actions === void 0 ? void 0 : actions.map(action => ({ name: action.apiName, script: action.script })),
893
- selectors: selectors === null || selectors === void 0 ? void 0 : selectors.map(selector => ({ name: selector.apiName, script: selector.script })),
894
- });
895
- }), tap$1(stateId => (this.stateId = stateId || null)), map$2(() => undefined));
946
+ calculate$(quoteDraft) {
947
+ return this.proceduresApiService.apply$(quoteDraft).pipe(tap$1(result => {
948
+ // sort the result current state based on the quote draft initial state
949
+ const initialStateIds = quoteDraft.initialState.map(lineItem => lineItem.integrationId);
950
+ result.currentState = result.currentState
951
+ .slice()
952
+ .sort((a, b) => initialStateIds.indexOf(a.integrationId) - initialStateIds.indexOf(b.integrationId));
953
+ this.quoteDraftService.updateQuoteDraft(result);
954
+ }), map$2(noop));
896
955
  }
897
- cleanup() {
898
- this.stateId = null;
899
- this.configurationService.reset();
900
- this.stateSubj$.next({});
956
+ calculate(quoteDraft) {
957
+ this.calculate$(quoteDraft).subscribe();
901
958
  }
902
- execute$(req) {
903
- if (this.isStatefulConfiguration) {
904
- return this.executeStateful$(req);
905
- }
906
- else {
907
- return this.executeStateless$(req);
959
+ update$(updates) {
960
+ const quoteDraft = this.quoteDraftService.quoteDraft;
961
+ if (!quoteDraft) {
962
+ return of(null);
908
963
  }
964
+ return of([]).pipe(map$2(() => {
965
+ const updatedState = cloneDeep(quoteDraft.currentState);
966
+ this.updateService.update(updatedState, updates, quoteDraft.charges);
967
+ return updatedState;
968
+ }), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
909
969
  }
910
- dispatch$(actionName, inputData) {
911
- return this.execute$({ actions: [{ name: actionName, inputData }] });
912
- }
913
- select$(selectorName, inputData) {
914
- const requestId = UUID.UUID();
915
- return this.execute$({
916
- selectors: {
917
- [requestId]: {
918
- name: selectorName,
919
- inputData,
920
- },
921
- },
922
- }).pipe(map$2(() => this.stateSubj$.value[requestId]), tap$1(() => this.stateSubj$.next(omit(this.stateSubj$.value, requestId))));
970
+ update(updates) {
971
+ this.update$(updates).subscribe();
923
972
  }
924
- get isStatefulConfiguration() {
925
- var _a;
926
- return (_a = this.runtimeService.uiDefinitionProperties.statefulConfigurationEnabled) !== null && _a !== void 0 ? _a : false;
973
+ revert$(lineItemId) {
974
+ const quoteDraft = this.quoteDraftService.quoteDraft;
975
+ const initialCurrentState = this.quoteDraftService.getInitialCurrentState();
976
+ const currentState = this.quoteDraftService.activeCurrentState;
977
+ const currentLineItemIndex = currentState.findIndex(({ id }) => id === lineItemId);
978
+ const currentLineItem = currentState[currentLineItemIndex];
979
+ const initialLineItem = initialCurrentState.find(({ integrationId }) => integrationId === (currentLineItem === null || currentLineItem === void 0 ? void 0 : currentLineItem.integrationId));
980
+ if (!quoteDraft || !currentLineItem || !initialLineItem) {
981
+ return of(null);
982
+ }
983
+ const updatedState = cloneDeep(currentState);
984
+ updatedState.splice(currentLineItemIndex, 1, initialLineItem);
985
+ return of([]).pipe(tap$1(() => {
986
+ this.quoteDraftService.setCurrentLineItemState(updatedState);
987
+ }), switchMap$1(() => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
927
988
  }
928
- executeStateless$(request) {
929
- return of(undefined).pipe(switchMap$1(() => {
930
- var _a;
931
- // Apply actions and execute configuration/price call
932
- // No need to run configuration if no actions in the request
933
- if (!((_a = request.actions) === null || _a === void 0 ? void 0 : _a.length)) {
934
- return of(undefined);
935
- }
936
- let configurationRequest = this.configurationService.generateRequest();
937
- request.actions.forEach(action => {
938
- var _a;
939
- configurationRequest = (_a = this.executeActionScript(configurationRequest, action)) !== null && _a !== void 0 ? _a : configurationRequest;
940
- });
941
- return this.configurationService.configureRequest$(configurationRequest);
942
- }), tap$1(() => {
943
- if (!request.selectors) {
944
- return;
945
- }
946
- // Run selectors and apply them to the state
947
- const finalConfigurationRequest = this.configurationService.generateRequest();
948
- const selectorsResult = EntityUtil.entries(request.selectors).reduce((trunk, [key, selector]) => {
949
- trunk[key] = this.executeSelectorScript(finalConfigurationRequest, selector);
950
- return trunk;
951
- }, {});
952
- this.stateSubj$.next(Object.assign(Object.assign({}, this.stateSubj$.value), selectorsResult));
953
- }), map$2(() => undefined));
989
+ revert(lineItemId) {
990
+ this.revert$(lineItemId).subscribe();
954
991
  }
955
- executeStateful$(request) {
956
- if (!this.stateId) {
957
- return of(undefined);
992
+ delete$(ids) {
993
+ const quoteDraft = this.quoteDraftService.quoteDraft;
994
+ const currentState = this.quoteDraftService.currentState;
995
+ if (!quoteDraft) {
996
+ return of(null);
958
997
  }
959
- return this.statefulConfigurationApiService.execute(this.stateId, request).pipe(tap$1(response => {
960
- this.stateId = response.stateId;
961
- const updatedState = this.stateSubj$.value;
962
- EntityUtil.entries(response.selectors).forEach(([key, value]) => {
963
- if (!value.success) {
964
- if (!this.runtimeService.uiDefinitionProperties.suppressToastMessages) {
965
- this.toastService.add({ summary: value.errorMessage, severity: ToastType.error });
966
- }
967
- return;
968
- }
969
- updatedState[key] = value.result;
970
- });
971
- this.stateSubj$.next(updatedState);
972
- }), map$2(() => undefined));
998
+ return of([]).pipe(map$2(() => ids.reduce((result, id) => this.updateService.delete(result, id), currentState)), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
973
999
  }
974
- executeActionScript(request, processor) {
975
- var _a, _b, _c;
976
- const { actions } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
977
- const script = (_c = actions === null || actions === void 0 ? void 0 : actions.find(action => action.apiName === processor.name)) === null || _c === void 0 ? void 0 : _c.script;
978
- if (!script) {
979
- return null;
1000
+ delete(ids) {
1001
+ this.delete$(ids).subscribe();
1002
+ }
1003
+ addTerm$(term) {
1004
+ const quoteDraft = this.quoteDraftService.quoteDraft;
1005
+ if (!quoteDraft) {
1006
+ return of(null);
980
1007
  }
981
- return this.executeProcessorScript(request, script, processor.inputData);
1008
+ const updatedState = [...quoteDraft.currentState, term];
1009
+ return of([]).pipe(switchMap$1(() => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
982
1010
  }
983
- executeSelectorScript(request, processor) {
984
- var _a, _b, _c;
985
- const { selectors } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
986
- const script = (_c = selectors === null || selectors === void 0 ? void 0 : selectors.find(selector => selector.apiName === processor.name)) === null || _c === void 0 ? void 0 : _c.script;
987
- if (!script) {
988
- return null;
1011
+ addToCart$(props) {
1012
+ const quoteDraft = this.quoteDraftService.quoteDraft;
1013
+ if (!quoteDraft) {
1014
+ return of(null);
989
1015
  }
990
- return this.executeProcessorScript(request, script, processor.inputData);
1016
+ return this.configurationService.configureExternal$(props).pipe(map$2(lineItem => {
1017
+ var _a, _b, _c;
1018
+ const model = this.configurationService.getRuntimeModel();
1019
+ const split = (_b = (_a = model === null || model === void 0 ? void 0 : model.types.find(type => type.name === lineItem.type)) === null || _a === void 0 ? void 0 : _a.split) !== null && _b !== void 0 ? _b : false;
1020
+ const lineItems = multiplyLineItems(lineItem, (_c = props.qty) !== null && _c !== void 0 ? _c : 1, split);
1021
+ return [...quoteDraft.currentState, ...lineItems];
1022
+ }), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
991
1023
  }
992
- executeProcessorScript(request, script, inputData) {
993
- return new Function(`${script}\nreturn transform;`)()({
994
- request,
995
- inputData: inputData,
996
- });
1024
+ get() {
1025
+ return this.quoteDraftService.quoteDraft$.pipe(map$2(() => this.quoteDraftService.activeCurrentState), shareReplay$1());
1026
+ }
1027
+ getSnapshot() {
1028
+ var _a, _b;
1029
+ return (_b = (_a = this.quoteDraftService) === null || _a === void 0 ? void 0 : _a.currentState.slice()) !== null && _b !== void 0 ? _b : [];
1030
+ }
1031
+ get charges$() {
1032
+ return this.quoteDraftService.quoteDraft$.pipe(map$2(({ charges }) => charges));
1033
+ }
1034
+ get pricePlans$() {
1035
+ return this.quoteDraftService.quoteDraft$.pipe(map$2(({ pricePlans }) => pricePlans));
1036
+ }
1037
+ get activeMetrics$() {
1038
+ return this.quoteDraftService.quoteDraft$.pipe(map$2(({ activeMetrics }) => activeMetrics));
1039
+ }
1040
+ get chargesSnapshot() {
1041
+ var _a, _b;
1042
+ return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.charges) !== null && _b !== void 0 ? _b : {};
1043
+ }
1044
+ get pricePlansSnapshot() {
1045
+ var _a, _b;
1046
+ return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.pricePlans) !== null && _b !== void 0 ? _b : {};
1047
+ }
1048
+ get activeMetricsSnapshot() {
1049
+ var _a, _b;
1050
+ return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.activeMetrics) !== null && _b !== void 0 ? _b : [];
1051
+ }
1052
+ get contextSnapshot() {
1053
+ return this.contextService.resolve();
1054
+ }
1055
+ get context$() {
1056
+ return this.contextService.resolve$();
1057
+ }
1058
+ handleErrorAndBounceBack() {
1059
+ return (source$) => {
1060
+ return source$.pipe(catchError$1(error => {
1061
+ console.error(error);
1062
+ // bounce back if configuration call has failed
1063
+ const quoteDraft = this.quoteDraftService.quoteDraft;
1064
+ if (quoteDraft) {
1065
+ this.quoteDraftService.updateQuoteDraft(quoteDraft);
1066
+ }
1067
+ return throwError(() => error);
1068
+ }));
1069
+ };
997
1070
  }
998
1071
  }
999
- ConfigurationState.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState, deps: [{ token: i1.StatefulConfigurationApiService }, { token: ConfigurationRuntimeService }, { token: ConfigurationService }, { token: i4.ToastService }], target: i0.ɵɵFactoryTarget.Injectable });
1000
- ConfigurationState.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState });
1001
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState, decorators: [{
1072
+ 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 }], target: i0.ɵɵFactoryTarget.Injectable });
1073
+ FlowConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService });
1074
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, decorators: [{
1002
1075
  type: Injectable
1003
- }], ctorParameters: function () { return [{ type: i1.StatefulConfigurationApiService }, { type: ConfigurationRuntimeService }, { type: ConfigurationService }, { type: i4.ToastService }]; } });
1004
-
1005
- function extractMetadata(uiDefinition) {
1006
- return omit(uiDefinition, [
1007
- 'children',
1008
- 'pages',
1009
- 'components',
1010
- ]);
1011
- }
1076
+ }], ctorParameters: function () { return [{ type: i1.ProceduresApiService }, { type: ContextService }, { type: QuoteDraftService }, { type: FlowUpdateService }, { type: ConfigurationService }]; } });
1012
1077
 
1013
- class FlowUpdateService {
1014
- update(rootLineItems, updates, charges) {
1015
- let remainingUpdates = [...updates];
1016
- let currentLevel = rootLineItems;
1017
- while (currentLevel.length && remainingUpdates.length) {
1018
- currentLevel.forEach(li => {
1019
- const unhandledUpdates = [];
1020
- remainingUpdates.forEach(update => {
1021
- let updated = false;
1022
- switch (update.dataType) {
1023
- case 'LINEITEM':
1024
- updated = this.applyLineItemUpdate(li, update, charges);
1025
- break;
1026
- case 'CHARGE':
1027
- updated = this.applyChargeUpdate(li, update);
1028
- break;
1029
- case 'GROUP_CHARGE':
1030
- updated = this.applyChargeGroupUpdate(li, update);
1031
- break;
1032
- default:
1033
- // Unknown dataType. Do not try to handle it anymore
1034
- updated = true;
1035
- }
1036
- if (!updated) {
1037
- unhandledUpdates.push(update);
1038
- }
1039
- });
1040
- remainingUpdates = unhandledUpdates;
1041
- });
1042
- currentLevel = flatten(currentLevel.map(parent => parent.lineItems));
1043
- }
1078
+ class MetricsCalculationService {
1079
+ get onMetricsUpdate$() {
1080
+ return this.metricsUpdated$.asObservable();
1044
1081
  }
1045
- delete(lineItems, id) {
1046
- const idsToRemove = [id];
1047
- const topLevelLineItem = lineItems.find(li => li.id === id);
1048
- if (topLevelLineItem) {
1049
- // find term-related line items (which are only top level)
1050
- // expired term line items won't be deleted
1051
- let foundTermLineItem = topLevelLineItem;
1052
- while (foundTermLineItem) {
1053
- foundTermLineItem = lineItems.find(li => foundTermLineItem && li.rampInstanceId === foundTermLineItem.id);
1054
- if (foundTermLineItem) {
1055
- idsToRemove.push(foundTermLineItem.id);
1056
- }
1082
+ constructor(quoteDraftService, flowConfiguration, settingsService) {
1083
+ this.quoteDraftService = quoteDraftService;
1084
+ this.flowConfiguration = flowConfiguration;
1085
+ this.settingsService = settingsService;
1086
+ this.metricsUpdated$ = new Subject();
1087
+ this.quoteMetricsSettings = {};
1088
+ this.metricsCalculationMethodMap = {};
1089
+ this.metricsData = {};
1090
+ this.activeMetricRules = [];
1091
+ this.activeMetricRules = this.flowConfiguration.activeMetricsSnapshot.filter(metricRule => metricRule.metrics.some(metric => !!metric.totalName));
1092
+ combineLatest([
1093
+ this.quoteDraftService.currentState$,
1094
+ this.settingsService.fetchSetting('QUOTE_LEVEL_METRIC_CALCULATION_METHOD').pipe(take$1(1)),
1095
+ ]).subscribe(([lineItems, setting]) => {
1096
+ let settingsData = {};
1097
+ try {
1098
+ settingsData = JSON.parse((setting === null || setting === void 0 ? void 0 : setting.value) || '{}');
1057
1099
  }
1058
- }
1059
- const filtered = lineItems.filter(lineItem => !idsToRemove.includes(lineItem.id));
1060
- return filtered.map(lineItem => new LineItemWorker(lineItem).remove(id).li);
1100
+ catch (error) {
1101
+ settingsData = {};
1102
+ }
1103
+ this.quoteMetricsSettings = settingsData;
1104
+ this.updateMetrics(lineItems);
1105
+ });
1061
1106
  }
1062
- applyLineItemUpdate(lineItem, update, charges) {
1063
- if (lineItem.id !== update.id) {
1064
- return false;
1065
- }
1066
- switch (update.attributeType) {
1067
- case 'QTY':
1068
- lineItem.qty = update.newValue;
1069
- break;
1070
- case 'EFFECTIVE_START_DATE':
1071
- lineItem.properties['StartDate'] = moment(update.newValue).format('YYYY-MM-DD');
1072
- break;
1073
- case 'END_DATE':
1074
- lineItem.properties['EndDate'] = moment(update.newValue).format('YYYY-MM-DD');
1075
- break;
1076
- case 'PRICE_ADJUSTMENT':
1077
- {
1078
- const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
1079
- if (charge) {
1080
- charge.priceAdjustment = update.newValue;
1081
- }
1082
- }
1083
- break;
1084
- case 'LIST_PRICE_ADJUSTMENT':
1085
- case 'MARGIN_ADJUSTMENT':
1086
- {
1087
- const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
1088
- if (charge) {
1089
- charge.listPriceAdjustment = update.newValue;
1090
- }
1091
- }
1092
- break;
1093
- case 'COST_ADJUSTMENT':
1094
- {
1095
- const charge = lineItem.chargeItems.find(charge => { var _a; return (_a = (charges || {})[charge.chargeId]) === null || _a === void 0 ? void 0 : _a.main; });
1096
- if (charge) {
1097
- charge.costAdjustment = update.newValue;
1098
- }
1099
- }
1100
- break;
1101
- default:
1102
- throw new Error(`Not suppored AttributeType for LineItem update: ${update.attributeType}`);
1103
- }
1104
- return true;
1107
+ getMetricValue(metric) {
1108
+ return this.metricsData[metric] || 0;
1105
1109
  }
1106
- applyChargeUpdate(lineItem, update) {
1107
- const foundCharge = lineItem.chargeItems.find(({ id }) => id === update.id);
1108
- if (!foundCharge) {
1109
- return false;
1110
+ updateMetrics(lineItems) {
1111
+ const metricKeys = this.collectMetricKeys(lineItems).filter(key => !key.includes('Effective_'));
1112
+ this.metricsCalculationMethodMap = this.buildMetricsCalculationMethods(metricKeys, this.metricsCalculationMethodMap);
1113
+ this.metricsData = metricKeys.reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: this.calculateMetric(lineItems, key) })), {});
1114
+ this.metricsUpdated$.next();
1115
+ }
1116
+ calculateMetric(lineItems, metric) {
1117
+ return calculateMetricByMethod(lineItems, metric, this.metricsCalculationMethodMap[metric] || 'sum');
1118
+ }
1119
+ buildMetricsCalculationMethods(metricKeys, initial) {
1120
+ return metricKeys.reduce((acc, name) => {
1121
+ var _a, _b;
1122
+ if (acc[name]) {
1123
+ return acc;
1124
+ }
1125
+ acc = Object.assign(Object.assign({}, acc), { [name]: 'sum' });
1126
+ const metricRule = this.getMetricRuleByTotalMetricName(name);
1127
+ const settingKey = ((_b = (_a = metricRule === null || metricRule === void 0 ? void 0 : metricRule.metrics) === null || _a === void 0 ? void 0 : _a.find(metric => metric.totalName === name)) === null || _b === void 0 ? void 0 : _b.name) || name;
1128
+ if (this.quoteMetricsSettings[settingKey]) {
1129
+ acc = Object.assign(Object.assign({}, acc), { [name]: this.quoteMetricsSettings[settingKey] });
1130
+ }
1131
+ return acc;
1132
+ }, initial);
1133
+ }
1134
+ collectMetricKeys(lineItems) {
1135
+ const keys = [];
1136
+ lineItems.forEach(lineItem => {
1137
+ keys.push(...Object.keys(lineItem.totalMetrics || {}));
1138
+ keys.push(...this.collectMetricKeys(lineItem.lineItems));
1139
+ });
1140
+ return uniq(keys);
1141
+ }
1142
+ getMetricRuleByTotalMetricName(name) {
1143
+ return this.activeMetricRules.find(metricRule => metricRule.metrics.find(metric => metric.totalName === name));
1144
+ }
1145
+ }
1146
+ MetricsCalculationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, deps: [{ token: QuoteDraftService }, { token: FlowConfigurationService }, { token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1147
+ MetricsCalculationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, providedIn: 'root' });
1148
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, decorators: [{
1149
+ type: Injectable,
1150
+ args: [{ providedIn: 'root' }]
1151
+ }], ctorParameters: function () { return [{ type: QuoteDraftService }, { type: FlowConfigurationService }, { type: i1.ConfigurationSettingsApiService }]; } });
1152
+
1153
+ class ProductImagesService {
1154
+ constructor(productApiService) {
1155
+ this.productApiService = productApiService;
1156
+ this.imagesMap$ = new BehaviorSubject({});
1157
+ }
1158
+ getImageUrl$(productId) {
1159
+ if (this.imagesMap$.value[productId] == null) {
1160
+ this.imagesMap$.next(Object.assign(Object.assign({}, this.imagesMap$.value), { [productId]: '' }));
1161
+ this.fetchProductImage(productId);
1110
1162
  }
1111
- if (update.attributeType === 'PRICE_ADJUSTMENT') {
1112
- foundCharge.priceAdjustment = update.newValue;
1163
+ return this.imagesMap$.pipe(map$2(imagesMap => imagesMap[productId]), distinctUntilChanged());
1164
+ }
1165
+ fetchProductImage(productId) {
1166
+ this.productApiService
1167
+ .fetchImage$(productId)
1168
+ .pipe(map$2(file => URL.createObjectURL(file)), catchError$1(() => of('')), tap$1(url => this.imagesMap$.next(Object.assign(Object.assign({}, this.imagesMap$.value), { [productId]: url }))))
1169
+ .subscribe();
1170
+ }
1171
+ }
1172
+ ProductImagesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, deps: [{ token: i1.ProductApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1173
+ ProductImagesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, providedIn: 'root' });
1174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, decorators: [{
1175
+ type: Injectable,
1176
+ args: [{ providedIn: 'root' }]
1177
+ }], ctorParameters: function () { return [{ type: i1.ProductApiService }]; } });
1178
+
1179
+ class RuntimeSettingsService {
1180
+ constructor(configurationSettingsApiService) {
1181
+ this.configurationSettingsApiService = configurationSettingsApiService;
1182
+ this.configurationSettings$ = new BehaviorSubject({});
1183
+ this.currencySettings$ = new BehaviorSubject({
1184
+ iso: DEFAULT_CURRENCY_ISO_CODE,
1185
+ symbol: DEFAULT_CURRENCY_SYMBOL,
1186
+ });
1187
+ this.getCurrencySymbol = (locale, currency) => {
1188
+ return (0)
1189
+ .toLocaleString(locale, { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0 })
1190
+ .replace(/\d/g, '')
1191
+ .trim();
1192
+ };
1193
+ }
1194
+ create() {
1195
+ return this.configurationSettingsApiService.fetchSettings().pipe(map$2(settings => this.parseConfigurationSettings(settings)), tap$1(configurationSettings => {
1196
+ this.configurationSettings$.next(configurationSettings);
1197
+ this.formattingSettings = this.getFormattingSettings();
1198
+ }), map$2(() => undefined));
1199
+ }
1200
+ initCurrency(iso) {
1201
+ if (iso) {
1202
+ const symbol = this.getCurrencySymbol('en-US', iso);
1203
+ this.currencySettings$.next({ iso, symbol });
1113
1204
  }
1114
- else if (update.attributeType === 'LIST_PRICE_ADJUSTMENT') {
1115
- foundCharge.listPriceAdjustment = update.newValue;
1205
+ }
1206
+ getFormattingSettings() {
1207
+ var _a, _b;
1208
+ if (this.formattingSettings) {
1209
+ return this.formattingSettings;
1116
1210
  }
1117
- else {
1118
- throw new Error(`Not suppored AttributeType for Charge Item update: ${update.attributeType}`);
1211
+ const shoppingCartSettings = (_a = this.getConfigurationSettings()['shopping-cart']) === null || _a === void 0 ? void 0 : _a.reduce((acc, setting) => {
1212
+ return Object.assign(Object.assign({}, acc), { [setting.id]: setting.properties });
1213
+ }, {});
1214
+ const currencySettings = this.getCurrencySettings();
1215
+ const dateFormat = (validateDateFormat((_b = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DATE_FORMAT) !== null && _b !== void 0 ? _b : '') && (shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DATE_FORMAT)) ||
1216
+ DEFAULT_DATE_FORMAT;
1217
+ const decimalSeparator = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DECIMAL_SEPARATOR;
1218
+ const thousandsSeparator = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.THOUSANDS_SEPARATOR;
1219
+ // the number of decimal places can be 0
1220
+ const priceScale = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.PRICE_SCALE;
1221
+ const decimalsCount = priceScale !== null && priceScale !== '' && !isNaN(Number(priceScale)) && Number(priceScale) >= 0
1222
+ ? Number(priceScale)
1223
+ : DEFAULT_DECIMALS_COUNT;
1224
+ return {
1225
+ currencySymbol: currencySettings.symbol,
1226
+ dateFormats: getSupportedDateFormats(dateFormat),
1227
+ decimalsCount,
1228
+ decimalSeparator: decimalSeparator !== undefined && ['.', ','].includes(decimalSeparator)
1229
+ ? decimalSeparator
1230
+ : DEFAULT_DECIMAL_SEPARATOR,
1231
+ // thousands separator can be a blank value, so it can also be null
1232
+ thousandsSeparator: thousandsSeparator !== undefined && ['.', ',', '', null].includes(thousandsSeparator)
1233
+ ? thousandsSeparator || ''
1234
+ : DEFAULT_THOUSANDS_SEPARATOR,
1235
+ };
1236
+ }
1237
+ getConfigurationSettings() {
1238
+ return this.configurationSettings$.value;
1239
+ }
1240
+ getCurrencySettings() {
1241
+ return this.currencySettings$.value;
1242
+ }
1243
+ parseConfigurationSettings(settings) {
1244
+ return settings.reduce((acc, setting) => {
1245
+ switch (setting.key) {
1246
+ case 'shopping-cart':
1247
+ acc['shopping-cart'] = parseJsonSafely(setting.value, []);
1248
+ break;
1249
+ case 'navigation':
1250
+ acc.navigation = parseJsonSafely(setting.value, {});
1251
+ break;
1252
+ case 'flows':
1253
+ acc.flows = parseJsonSafely(setting.value, []);
1254
+ break;
1255
+ default:
1256
+ acc[setting.key] = setting.value;
1257
+ }
1258
+ return acc;
1259
+ }, {});
1260
+ }
1261
+ }
1262
+ RuntimeSettingsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, deps: [{ token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1263
+ RuntimeSettingsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, providedIn: 'root' });
1264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, decorators: [{
1265
+ type: Injectable,
1266
+ args: [{ providedIn: 'root' }]
1267
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationSettingsApiService }]; } });
1268
+
1269
+ class RuntimeContextService {
1270
+ constructor(configurationApiService) {
1271
+ this.configurationApiService = configurationApiService;
1272
+ }
1273
+ getRuntimeContext(productId, offeringId) {
1274
+ return this.configurationApiService.getRuntimeDataByProductId(productId, offeringId).pipe(map(runtimeData => {
1275
+ var _a;
1276
+ const uiDefinitionContainer = this.getUIDefinitionContainer(runtimeData);
1277
+ const runtimeModel = RuntimeModel.create(runtimeData.types, runtimeData.products);
1278
+ const { productName, properties } = (_a = Array.from(runtimeModel.components.values()).find(c => c.productId === productId)) !== null && _a !== void 0 ? _a : {};
1279
+ const uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
1280
+ return {
1281
+ modelId: runtimeData.modelId,
1282
+ uiDefinitionContainer: uiDefinitionContainer,
1283
+ runtimeModel: runtimeModel,
1284
+ runtimeMode: RuntimeMode.PROD,
1285
+ productId: productId,
1286
+ productType: (properties === null || properties === void 0 ? void 0 : properties['displayName']) || productName,
1287
+ offeringId: offeringId,
1288
+ properties: {
1289
+ PricingEnabled: uiDefinitionProperties.pricingEnabled ? 'true' : 'false',
1290
+ PriceListId: uiDefinitionProperties.priceList,
1291
+ },
1292
+ };
1293
+ }));
1294
+ }
1295
+ getUIDefinitionContainer(runtimeData) {
1296
+ var _a;
1297
+ const containers = runtimeData.uiDefinitions.filter(container => !isLegacyUIDefinition(container.source));
1298
+ return (_a = containers.find(container => container.source.primary)) !== null && _a !== void 0 ? _a : containers[0];
1299
+ }
1300
+ }
1301
+ RuntimeContextService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, deps: [{ token: i1.ConfigurationApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1302
+ RuntimeContextService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService });
1303
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeContextService, decorators: [{
1304
+ type: Injectable
1305
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }]; } });
1306
+
1307
+ class ConfigurationRuntimeService {
1308
+ constructor(apiService, contextService, runtimeContextService) {
1309
+ this.apiService = apiService;
1310
+ this.contextService = contextService;
1311
+ this.runtimeContextService = runtimeContextService;
1312
+ this._isInitialized = false;
1313
+ this.uiDefinitionProperties = {};
1314
+ }
1315
+ reset() {
1316
+ this._isInitialized = false;
1317
+ this._runtimeContext = undefined;
1318
+ this.initializationProps = undefined;
1319
+ this.uiDefinitionProperties = {};
1320
+ }
1321
+ initTestMode(uiDefinitionContainer) {
1322
+ var _a;
1323
+ this.uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
1324
+ const uiDefinitionExternals = (_a = uiDefinitionContainer.source.externals) !== null && _a !== void 0 ? _a : {};
1325
+ return combineLatest([
1326
+ this.apiService.getRuntimeDataByModelId(uiDefinitionContainer.modelId),
1327
+ this.contextService.initTestMode(),
1328
+ ]).pipe(first(), map(([runtimeData, context]) => {
1329
+ var _a;
1330
+ this.contextService.update({
1331
+ properties: Object.assign(Object.assign(Object.assign(Object.assign({}, (_a = this.runtimeContext) === null || _a === void 0 ? void 0 : _a.properties), context.properties), { ModelId: uiDefinitionContainer.modelId, PricingEnabled: this.uiDefinitionProperties.pricingEnabled ? 'true' : 'false', PriceListId: this.uiDefinitionProperties.priceList, offeringId: this.uiDefinitionProperties.offeringId }), uiDefinitionExternals),
1332
+ });
1333
+ this._runtimeContext = {
1334
+ modelId: uiDefinitionContainer.modelId,
1335
+ runtimeModel: RuntimeModel.create(runtimeData.types, runtimeData.products),
1336
+ runtimeMode: RuntimeMode.TEST,
1337
+ uiDefinitionContainer,
1338
+ };
1339
+ return this._runtimeContext;
1340
+ }), tap(() => (this._isInitialized = true)));
1341
+ }
1342
+ init(props) {
1343
+ this.initializationProps = props;
1344
+ const context = this.contextService.resolve();
1345
+ return this.runtimeContextService.getRuntimeContext(props.productId, props.offeringId).pipe(tap(runtimeContext => {
1346
+ var _a, _b;
1347
+ this.uiDefinitionProperties = getUIDefinitionProperties(runtimeContext.uiDefinitionContainer);
1348
+ const { PriceListId } = (_a = context.properties) !== null && _a !== void 0 ? _a : {};
1349
+ const mergeContext = Object.assign(Object.assign({}, runtimeContext), { properties: Object.assign(Object.assign(Object.assign({}, runtimeContext.properties), context.properties), { PricingEnabled: PriceListId ? 'true' : 'false' }) });
1350
+ this.id15to18('AccountId', mergeContext.properties);
1351
+ this._runtimeContext = mergeContext;
1352
+ if (context.properties && ((_b = this._runtimeContext.properties) === null || _b === void 0 ? void 0 : _b.StartDate)) {
1353
+ this.contextService.update({
1354
+ properties: Object.assign(Object.assign({}, this._runtimeContext.properties), context.properties),
1355
+ });
1356
+ }
1357
+ return this._runtimeContext;
1358
+ }), tap(() => (this._isInitialized = true)));
1359
+ }
1360
+ overrideUIDefinition(uiDefinitionContainer) {
1361
+ if (!this._runtimeContext) {
1362
+ return;
1119
1363
  }
1120
- return true;
1364
+ this._runtimeContext.uiDefinitionContainer = uiDefinitionContainer;
1365
+ this.uiDefinitionProperties = getUIDefinitionProperties(uiDefinitionContainer);
1121
1366
  }
1122
- applyChargeGroupUpdate(lineItem, update) {
1123
- const foundChargeGroup = ChargeGroupUtils.findChargeGroupById(update.id, lineItem);
1124
- if (!foundChargeGroup) {
1125
- return false;
1126
- }
1127
- if (update.attributeType === 'PRICE_ADJUSTMENT') {
1128
- foundChargeGroup.priceAdjustment = update.newValue;
1129
- }
1130
- else if (update.attributeType === 'LIST_PRICE_ADJUSTMENT') {
1131
- foundChargeGroup.listPriceAdjustment = update.newValue;
1367
+ id15to18(propertyName, source) {
1368
+ if (!source) {
1369
+ return;
1132
1370
  }
1133
- else {
1134
- throw new Error(`Not suppored AttributeType for Charge Group Item update: ${update.attributeType}`);
1371
+ const value = source[propertyName];
1372
+ if (typeof value === 'string' && value.length === 15) {
1373
+ source[propertyName] = SalesforceIdUtils.generateId18FromId15(value);
1135
1374
  }
1136
- return true;
1375
+ }
1376
+ get isInitialized() {
1377
+ return this._isInitialized;
1378
+ }
1379
+ get runtimeModel() {
1380
+ var _a;
1381
+ return (_a = this.runtimeContext) === null || _a === void 0 ? void 0 : _a.runtimeModel;
1382
+ }
1383
+ get runtimeContext() {
1384
+ return this._runtimeContext;
1137
1385
  }
1138
1386
  }
1139
- FlowUpdateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1140
- FlowUpdateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService });
1141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowUpdateService, decorators: [{
1387
+ 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 });
1388
+ ConfigurationRuntimeService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService });
1389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationRuntimeService, decorators: [{
1142
1390
  type: Injectable
1143
- }] });
1391
+ }], ctorParameters: function () { return [{ type: i1.ConfigurationApiService }, { type: ContextService }, { type: RuntimeContextService }]; } });
1144
1392
 
1145
- class FlowConfigurationService {
1146
- constructor(proceduresApiService, contextService, quoteDraftService, updateService, configurationService) {
1147
- this.proceduresApiService = proceduresApiService;
1148
- this.contextService = contextService;
1149
- this.quoteDraftService = quoteDraftService;
1150
- this.updateService = updateService;
1393
+ class ConfigurationState {
1394
+ constructor(statefulConfigurationApiService, runtimeService, configurationService, toastService) {
1395
+ this.statefulConfigurationApiService = statefulConfigurationApiService;
1396
+ this.runtimeService = runtimeService;
1151
1397
  this.configurationService = configurationService;
1398
+ this.toastService = toastService;
1399
+ this.stateSubj$ = new BehaviorSubject({});
1400
+ this.state$ = this.stateSubj$.asObservable();
1401
+ this.stateId = null;
1152
1402
  }
1153
- calculate$(quoteDraft) {
1154
- return this.proceduresApiService.apply$(quoteDraft).pipe(tap$1(result => {
1155
- // sort the result current state based on the quote draft initial state
1156
- const initialStateIds = quoteDraft.initialState.map(lineItem => lineItem.integrationId);
1157
- result.currentState = result.currentState
1158
- .slice()
1159
- .sort((a, b) => initialStateIds.indexOf(a.integrationId) - initialStateIds.indexOf(b.integrationId));
1160
- this.quoteDraftService.updateQuoteDraft(result);
1161
- }), map$2(noop));
1403
+ init$() {
1404
+ return this.configurationService.configure().pipe(switchMap$1(() => {
1405
+ var _a, _b;
1406
+ if (!this.isStatefulConfiguration) {
1407
+ return of(undefined);
1408
+ }
1409
+ const { actions, selectors } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
1410
+ return this.statefulConfigurationApiService.init({
1411
+ request: this.configurationService.generateRequest(),
1412
+ actions: actions === null || actions === void 0 ? void 0 : actions.map(action => ({ name: action.apiName, script: action.script })),
1413
+ selectors: selectors === null || selectors === void 0 ? void 0 : selectors.map(selector => ({ name: selector.apiName, script: selector.script })),
1414
+ });
1415
+ }), tap$1(stateId => (this.stateId = stateId || null)), map$2(() => undefined));
1162
1416
  }
1163
- calculate(quoteDraft) {
1164
- this.calculate$(quoteDraft).subscribe();
1417
+ cleanup() {
1418
+ this.stateId = null;
1419
+ this.configurationService.reset();
1420
+ this.stateSubj$.next({});
1165
1421
  }
1166
- update$(updates) {
1167
- const quoteDraft = this.quoteDraftService.quoteDraft;
1168
- if (!quoteDraft) {
1169
- return of(null);
1422
+ execute$(req) {
1423
+ if (this.isStatefulConfiguration) {
1424
+ return this.executeStateful$(req);
1170
1425
  }
1171
- return of([]).pipe(map$2(() => {
1172
- const updatedState = cloneDeep(quoteDraft.currentState);
1173
- this.updateService.update(updatedState, updates, quoteDraft.charges);
1174
- return updatedState;
1175
- }), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
1176
- }
1177
- update(updates) {
1178
- this.update$(updates).subscribe();
1179
- }
1180
- revert$(lineItemId) {
1181
- const quoteDraft = this.quoteDraftService.quoteDraft;
1182
- const initialCurrentState = this.quoteDraftService.getInitialCurrentState();
1183
- const currentState = this.quoteDraftService.activeCurrentState;
1184
- const currentLineItemIndex = currentState.findIndex(({ id }) => id === lineItemId);
1185
- const currentLineItem = currentState[currentLineItemIndex];
1186
- const initialLineItem = initialCurrentState.find(({ integrationId }) => integrationId === (currentLineItem === null || currentLineItem === void 0 ? void 0 : currentLineItem.integrationId));
1187
- if (!quoteDraft || !currentLineItem || !initialLineItem) {
1188
- return of(null);
1426
+ else {
1427
+ return this.executeStateless$(req);
1189
1428
  }
1190
- const updatedState = cloneDeep(currentState);
1191
- updatedState.splice(currentLineItemIndex, 1, initialLineItem);
1192
- return of([]).pipe(tap$1(() => {
1193
- this.quoteDraftService.setCurrentLineItemState(updatedState);
1194
- }), switchMap$1(() => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
1195
1429
  }
1196
- revert(lineItemId) {
1197
- this.revert$(lineItemId).subscribe();
1430
+ dispatch$(actionName, inputData) {
1431
+ return this.execute$({ actions: [{ name: actionName, inputData }] });
1198
1432
  }
1199
- delete$(ids) {
1200
- const quoteDraft = this.quoteDraftService.quoteDraft;
1201
- const currentState = this.quoteDraftService.currentState;
1202
- if (!quoteDraft) {
1203
- return of(null);
1204
- }
1205
- return of([]).pipe(map$2(() => ids.reduce((result, id) => this.updateService.delete(result, id), currentState)), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
1433
+ select$(selectorName, inputData) {
1434
+ const requestId = UUID.UUID();
1435
+ return this.execute$({
1436
+ selectors: {
1437
+ [requestId]: {
1438
+ name: selectorName,
1439
+ inputData,
1440
+ },
1441
+ },
1442
+ }).pipe(map$2(() => this.stateSubj$.value[requestId]), tap$1(() => this.stateSubj$.next(omit(this.stateSubj$.value, requestId))));
1206
1443
  }
1207
- delete(ids) {
1208
- this.delete$(ids).subscribe();
1444
+ get isStatefulConfiguration() {
1445
+ var _a;
1446
+ return (_a = this.runtimeService.uiDefinitionProperties.statefulConfigurationEnabled) !== null && _a !== void 0 ? _a : false;
1209
1447
  }
1210
- addTerm$(term) {
1211
- const quoteDraft = this.quoteDraftService.quoteDraft;
1212
- if (!quoteDraft) {
1213
- return of(null);
1214
- }
1215
- const updatedState = [...quoteDraft.currentState, term];
1216
- return of([]).pipe(switchMap$1(() => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
1448
+ executeStateless$(request) {
1449
+ return of(undefined).pipe(switchMap$1(() => {
1450
+ var _a;
1451
+ // Apply actions and execute configuration/price call
1452
+ // No need to run configuration if no actions in the request
1453
+ if (!((_a = request.actions) === null || _a === void 0 ? void 0 : _a.length)) {
1454
+ return of(undefined);
1455
+ }
1456
+ let configurationRequest = this.configurationService.generateRequest();
1457
+ request.actions.forEach(action => {
1458
+ var _a;
1459
+ configurationRequest = (_a = this.executeActionScript(configurationRequest, action)) !== null && _a !== void 0 ? _a : configurationRequest;
1460
+ });
1461
+ return this.configurationService.configureRequest$(configurationRequest);
1462
+ }), tap$1(() => {
1463
+ if (!request.selectors) {
1464
+ return;
1465
+ }
1466
+ // Run selectors and apply them to the state
1467
+ const finalConfigurationRequest = this.configurationService.generateRequest();
1468
+ const selectorsResult = EntityUtil.entries(request.selectors).reduce((trunk, [key, selector]) => {
1469
+ trunk[key] = this.executeSelectorScript(finalConfigurationRequest, selector);
1470
+ return trunk;
1471
+ }, {});
1472
+ this.stateSubj$.next(Object.assign(Object.assign({}, this.stateSubj$.value), selectorsResult));
1473
+ }), map$2(() => undefined));
1217
1474
  }
1218
- addToCart$(props) {
1219
- const quoteDraft = this.quoteDraftService.quoteDraft;
1220
- if (!quoteDraft) {
1221
- return of(null);
1475
+ executeStateful$(request) {
1476
+ if (!this.stateId) {
1477
+ return of(undefined);
1222
1478
  }
1223
- return this.configurationService.configureExternal$(props).pipe(map$2(lineItem => {
1224
- var _a, _b, _c;
1225
- const model = this.configurationService.getRuntimeModel();
1226
- const split = (_b = (_a = model === null || model === void 0 ? void 0 : model.types.find(type => type.name === lineItem.type)) === null || _a === void 0 ? void 0 : _a.split) !== null && _b !== void 0 ? _b : false;
1227
- const lineItems = multiplyLineItems(lineItem, (_c = props.qty) !== null && _c !== void 0 ? _c : 1, split);
1228
- return [...quoteDraft.currentState, ...lineItems];
1229
- }), switchMap$1(updatedState => this.calculate$(Object.assign(Object.assign({}, quoteDraft), { currentState: updatedState }))), map$2(() => this.quoteDraftService.quoteDraft), this.handleErrorAndBounceBack());
1230
- }
1231
- get() {
1232
- return this.quoteDraftService.quoteDraft$.pipe(map$2(() => this.quoteDraftService.activeCurrentState), shareReplay$1());
1233
- }
1234
- getSnapshot() {
1235
- var _a, _b;
1236
- return (_b = (_a = this.quoteDraftService) === null || _a === void 0 ? void 0 : _a.currentState.slice()) !== null && _b !== void 0 ? _b : [];
1237
- }
1238
- get charges$() {
1239
- return this.quoteDraftService.quoteDraft$.pipe(map$2(({ charges }) => charges));
1240
- }
1241
- get pricePlans$() {
1242
- return this.quoteDraftService.quoteDraft$.pipe(map$2(({ pricePlans }) => pricePlans));
1243
- }
1244
- get activeMetrics$() {
1245
- return this.quoteDraftService.quoteDraft$.pipe(map$2(({ activeMetrics }) => activeMetrics));
1246
- }
1247
- get chargesSnapshot() {
1248
- var _a, _b;
1249
- return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.charges) !== null && _b !== void 0 ? _b : {};
1250
- }
1251
- get pricePlansSnapshot() {
1252
- var _a, _b;
1253
- return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.pricePlans) !== null && _b !== void 0 ? _b : {};
1254
- }
1255
- get activeMetricsSnapshot() {
1256
- var _a, _b;
1257
- return (_b = (_a = this.quoteDraftService.quoteDraft) === null || _a === void 0 ? void 0 : _a.activeMetrics) !== null && _b !== void 0 ? _b : [];
1258
- }
1259
- get contextSnapshot() {
1260
- return this.contextService.resolve();
1261
- }
1262
- get context$() {
1263
- return this.contextService.resolve$();
1264
- }
1265
- handleErrorAndBounceBack() {
1266
- return (source$) => {
1267
- return source$.pipe(catchError$1(error => {
1268
- console.error(error);
1269
- // bounce back if configuration call has failed
1270
- const quoteDraft = this.quoteDraftService.quoteDraft;
1271
- if (quoteDraft) {
1272
- this.quoteDraftService.updateQuoteDraft(quoteDraft);
1479
+ return this.statefulConfigurationApiService.execute(this.stateId, request).pipe(tap$1(response => {
1480
+ this.stateId = response.stateId;
1481
+ const updatedState = this.stateSubj$.value;
1482
+ EntityUtil.entries(response.selectors).forEach(([key, value]) => {
1483
+ if (!value.success) {
1484
+ if (!this.runtimeService.uiDefinitionProperties.suppressToastMessages) {
1485
+ this.toastService.add({ summary: value.errorMessage, severity: ToastType.error });
1486
+ }
1487
+ return;
1273
1488
  }
1274
- return throwError(() => error);
1275
- }));
1276
- };
1489
+ updatedState[key] = value.result;
1490
+ });
1491
+ this.stateSubj$.next(updatedState);
1492
+ }), map$2(() => undefined));
1493
+ }
1494
+ executeActionScript(request, processor) {
1495
+ var _a, _b, _c;
1496
+ const { actions } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
1497
+ const script = (_c = actions === null || actions === void 0 ? void 0 : actions.find(action => action.apiName === processor.name)) === null || _c === void 0 ? void 0 : _c.script;
1498
+ if (!script) {
1499
+ return null;
1500
+ }
1501
+ return this.executeProcessorScript(request, script, processor.inputData);
1502
+ }
1503
+ executeSelectorScript(request, processor) {
1504
+ var _a, _b, _c;
1505
+ const { selectors } = (_b = (_a = this.runtimeService.runtimeContext) === null || _a === void 0 ? void 0 : _a.uiDefinitionContainer) !== null && _b !== void 0 ? _b : {};
1506
+ const script = (_c = selectors === null || selectors === void 0 ? void 0 : selectors.find(selector => selector.apiName === processor.name)) === null || _c === void 0 ? void 0 : _c.script;
1507
+ if (!script) {
1508
+ return null;
1509
+ }
1510
+ return this.executeProcessorScript(request, script, processor.inputData);
1511
+ }
1512
+ executeProcessorScript(request, script, inputData) {
1513
+ return new Function(`${script}\nreturn transform;`)()({
1514
+ request,
1515
+ inputData: inputData,
1516
+ });
1277
1517
  }
1278
1518
  }
1279
- 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 }], target: i0.ɵɵFactoryTarget.Injectable });
1280
- FlowConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService });
1281
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: FlowConfigurationService, decorators: [{
1519
+ ConfigurationState.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState, deps: [{ token: i1.StatefulConfigurationApiService }, { token: ConfigurationRuntimeService }, { token: ConfigurationService }, { token: i4.ToastService }], target: i0.ɵɵFactoryTarget.Injectable });
1520
+ ConfigurationState.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState });
1521
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ConfigurationState, decorators: [{
1282
1522
  type: Injectable
1283
- }], ctorParameters: function () { return [{ type: i1.ProceduresApiService }, { type: ContextService }, { type: QuoteDraftService }, { type: FlowUpdateService }, { type: ConfigurationService }]; } });
1523
+ }], ctorParameters: function () { return [{ type: i1.StatefulConfigurationApiService }, { type: ConfigurationRuntimeService }, { type: ConfigurationService }, { type: i4.ToastService }]; } });
1284
1524
 
1285
1525
  class FlowConfigurationModule {
1286
1526
  }
@@ -1324,239 +1564,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImpor
1324
1564
  }]
1325
1565
  }] });
1326
1566
 
1327
- function calculateMetricByMethod(lineItems, metric, method) {
1328
- const items = getLineItemsByMethod(lineItems, method);
1329
- return items.reduce((acc, li) => {
1330
- let value = li.reduce((accProduct, item) => accProduct + ((item.totalMetrics && item.totalMetrics[metric]) || 0), 0);
1331
- if (method === 'avg' && li.length > 0) {
1332
- value /= li.length;
1333
- }
1334
- return acc + value;
1335
- }, 0);
1336
- }
1337
- function getLineItemsByMethod(lineItems, method) {
1338
- switch (method) {
1339
- case 'first': {
1340
- return lineItems.filter(li => !li.rampInstanceId).map(item => [item]);
1341
- }
1342
- case 'last': {
1343
- const rootTermItems = lineItems.filter(li => !li.rampInstanceId);
1344
- const products = rootTermItems.map(lineItem => [
1345
- lineItem,
1346
- ...lineItems.filter(li => li.rampInstanceId === lineItem.id),
1347
- ]);
1348
- return products
1349
- .map(items => [...items].sort((a, b) => getDateValue(a.endDate || '') - getDateValue(b.endDate || '')).pop())
1350
- .filter((li) => Boolean(li))
1351
- .map(item => [item]);
1352
- }
1353
- case 'avg': {
1354
- const rootTermItems = lineItems.filter(li => !li.rampInstanceId);
1355
- return rootTermItems.map(lineItem => [lineItem, ...lineItems.filter(li => li.rampInstanceId === lineItem.id)]);
1356
- }
1357
- case 'sum': {
1358
- return lineItems.map(item => [item]);
1359
- }
1360
- default: {
1361
- return lineItems.map(item => [item]);
1362
- }
1363
- }
1364
- }
1365
- function getDateValue(date) {
1366
- return date ? new Date(date).getTime() : 0;
1367
- }
1368
-
1369
- class MetricsCalculationService {
1370
- get onMetricsUpdate$() {
1371
- return this.metricsUpdated$.asObservable();
1372
- }
1373
- constructor(quoteDraftService, flowConfiguration, settingsService) {
1374
- this.quoteDraftService = quoteDraftService;
1375
- this.flowConfiguration = flowConfiguration;
1376
- this.settingsService = settingsService;
1377
- this.metricsUpdated$ = new Subject();
1378
- this.quoteMetricsSettings = {};
1379
- this.metricsCalculationMethodMap = {};
1380
- this.metricsData = {};
1381
- this.activeMetricRules = [];
1382
- this.activeMetricRules = this.flowConfiguration.activeMetricsSnapshot.filter(metricRule => metricRule.metrics.some(metric => !!metric.totalName));
1383
- combineLatest([
1384
- this.quoteDraftService.currentState$,
1385
- this.settingsService.fetchSetting('QUOTE_LEVEL_METRIC_CALCULATION_METHOD').pipe(take$1(1)),
1386
- ]).subscribe(([lineItems, setting]) => {
1387
- let settingsData = {};
1388
- try {
1389
- settingsData = JSON.parse((setting === null || setting === void 0 ? void 0 : setting.value) || '{}');
1390
- }
1391
- catch (error) {
1392
- settingsData = {};
1393
- }
1394
- this.quoteMetricsSettings = settingsData;
1395
- this.updateMetrics(lineItems);
1396
- });
1397
- }
1398
- getMetricValue(metric) {
1399
- return this.metricsData[metric] || 0;
1400
- }
1401
- updateMetrics(lineItems) {
1402
- const metricKeys = this.collectMetricKeys(lineItems).filter(key => !key.includes('Effective_'));
1403
- this.metricsCalculationMethodMap = this.buildMetricsCalculationMethods(metricKeys, this.metricsCalculationMethodMap);
1404
- this.metricsData = metricKeys.reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: this.calculateMetric(lineItems, key) })), {});
1405
- this.metricsUpdated$.next();
1406
- }
1407
- calculateMetric(lineItems, metric) {
1408
- return calculateMetricByMethod(lineItems, metric, this.metricsCalculationMethodMap[metric] || 'sum');
1409
- }
1410
- buildMetricsCalculationMethods(metricKeys, initial) {
1411
- return metricKeys.reduce((acc, name) => {
1412
- var _a, _b;
1413
- if (acc[name]) {
1414
- return acc;
1415
- }
1416
- acc = Object.assign(Object.assign({}, acc), { [name]: 'sum' });
1417
- const metricRule = this.getMetricRuleByTotalMetricName(name);
1418
- const settingKey = ((_b = (_a = metricRule === null || metricRule === void 0 ? void 0 : metricRule.metrics) === null || _a === void 0 ? void 0 : _a.find(metric => metric.totalName === name)) === null || _b === void 0 ? void 0 : _b.name) || name;
1419
- if (this.quoteMetricsSettings[settingKey]) {
1420
- acc = Object.assign(Object.assign({}, acc), { [name]: this.quoteMetricsSettings[settingKey] });
1421
- }
1422
- return acc;
1423
- }, initial);
1424
- }
1425
- collectMetricKeys(lineItems) {
1426
- const keys = [];
1427
- lineItems.forEach(lineItem => {
1428
- keys.push(...Object.keys(lineItem.totalMetrics || {}));
1429
- keys.push(...this.collectMetricKeys(lineItem.lineItems));
1430
- });
1431
- return uniq(keys);
1432
- }
1433
- getMetricRuleByTotalMetricName(name) {
1434
- return this.activeMetricRules.find(metricRule => metricRule.metrics.find(metric => metric.totalName === name));
1435
- }
1436
- }
1437
- MetricsCalculationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, deps: [{ token: QuoteDraftService }, { token: FlowConfigurationService }, { token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1438
- MetricsCalculationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, providedIn: 'root' });
1439
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: MetricsCalculationService, decorators: [{
1440
- type: Injectable,
1441
- args: [{ providedIn: 'root' }]
1442
- }], ctorParameters: function () { return [{ type: QuoteDraftService }, { type: FlowConfigurationService }, { type: i1.ConfigurationSettingsApiService }]; } });
1443
-
1444
- class ProductImagesService {
1445
- constructor(productApiService) {
1446
- this.productApiService = productApiService;
1447
- this.imagesMap$ = new BehaviorSubject({});
1448
- }
1449
- getImageUrl$(productId) {
1450
- if (this.imagesMap$.value[productId] == null) {
1451
- this.imagesMap$.next(Object.assign(Object.assign({}, this.imagesMap$.value), { [productId]: '' }));
1452
- this.fetchProductImage(productId);
1453
- }
1454
- return this.imagesMap$.pipe(map$2(imagesMap => imagesMap[productId]), distinctUntilChanged());
1455
- }
1456
- fetchProductImage(productId) {
1457
- this.productApiService
1458
- .fetchImage$(productId)
1459
- .pipe(map$2(file => URL.createObjectURL(file)), catchError$1(() => of('')), tap$1(url => this.imagesMap$.next(Object.assign(Object.assign({}, this.imagesMap$.value), { [productId]: url }))))
1460
- .subscribe();
1461
- }
1462
- }
1463
- ProductImagesService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, deps: [{ token: i1.ProductApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1464
- ProductImagesService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, providedIn: 'root' });
1465
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ProductImagesService, decorators: [{
1466
- type: Injectable,
1467
- args: [{ providedIn: 'root' }]
1468
- }], ctorParameters: function () { return [{ type: i1.ProductApiService }]; } });
1469
-
1470
- class RuntimeSettingsService {
1471
- constructor(configurationSettingsApiService) {
1472
- this.configurationSettingsApiService = configurationSettingsApiService;
1473
- this.configurationSettings$ = new BehaviorSubject({});
1474
- this.currencySettings$ = new BehaviorSubject({
1475
- iso: DEFAULT_CURRENCY_ISO_CODE,
1476
- symbol: DEFAULT_CURRENCY_SYMBOL,
1477
- });
1478
- this.getCurrencySymbol = (locale, currency) => {
1479
- return (0)
1480
- .toLocaleString(locale, { style: 'currency', currency, minimumFractionDigits: 0, maximumFractionDigits: 0 })
1481
- .replace(/\d/g, '')
1482
- .trim();
1483
- };
1484
- }
1485
- create() {
1486
- return this.configurationSettingsApiService.fetchSettings().pipe(map$2(settings => this.parseConfigurationSettings(settings)), tap$1(configurationSettings => {
1487
- this.configurationSettings$.next(configurationSettings);
1488
- this.formattingSettings = this.getFormattingSettings();
1489
- }), map$2(() => undefined));
1490
- }
1491
- initCurrency(iso) {
1492
- if (iso) {
1493
- const symbol = this.getCurrencySymbol('en-US', iso);
1494
- this.currencySettings$.next({ iso, symbol });
1495
- }
1496
- }
1497
- getFormattingSettings() {
1498
- var _a, _b;
1499
- if (this.formattingSettings) {
1500
- return this.formattingSettings;
1501
- }
1502
- const shoppingCartSettings = (_a = this.getConfigurationSettings()['shopping-cart']) === null || _a === void 0 ? void 0 : _a.reduce((acc, setting) => {
1503
- return Object.assign(Object.assign({}, acc), { [setting.id]: setting.properties });
1504
- }, {});
1505
- const currencySettings = this.getCurrencySettings();
1506
- const dateFormat = (validateDateFormat((_b = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DATE_FORMAT) !== null && _b !== void 0 ? _b : '') && (shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DATE_FORMAT)) ||
1507
- DEFAULT_DATE_FORMAT;
1508
- const decimalSeparator = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.DECIMAL_SEPARATOR;
1509
- const thousandsSeparator = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.THOUSANDS_SEPARATOR;
1510
- // the number of decimal places can be 0
1511
- const priceScale = shoppingCartSettings === null || shoppingCartSettings === void 0 ? void 0 : shoppingCartSettings.PRICE_SCALE;
1512
- const decimalsCount = priceScale !== null && priceScale !== '' && !isNaN(Number(priceScale)) && Number(priceScale) >= 0
1513
- ? Number(priceScale)
1514
- : DEFAULT_DECIMALS_COUNT;
1515
- return {
1516
- currencySymbol: currencySettings.symbol,
1517
- dateFormats: getSupportedDateFormats(dateFormat),
1518
- decimalsCount,
1519
- decimalSeparator: decimalSeparator !== undefined && ['.', ','].includes(decimalSeparator)
1520
- ? decimalSeparator
1521
- : DEFAULT_DECIMAL_SEPARATOR,
1522
- // thousands separator can be a blank value, so it can also be null
1523
- thousandsSeparator: thousandsSeparator !== undefined && ['.', ',', '', null].includes(thousandsSeparator)
1524
- ? thousandsSeparator || ''
1525
- : DEFAULT_THOUSANDS_SEPARATOR,
1526
- };
1527
- }
1528
- getConfigurationSettings() {
1529
- return this.configurationSettings$.value;
1530
- }
1531
- getCurrencySettings() {
1532
- return this.currencySettings$.value;
1533
- }
1534
- parseConfigurationSettings(settings) {
1535
- return settings.reduce((acc, setting) => {
1536
- switch (setting.key) {
1537
- case 'shopping-cart':
1538
- acc['shopping-cart'] = parseJsonSafely(setting.value, []);
1539
- break;
1540
- case 'navigation':
1541
- acc.navigation = parseJsonSafely(setting.value, {});
1542
- break;
1543
- case 'flows':
1544
- acc.flows = parseJsonSafely(setting.value, []);
1545
- break;
1546
- default:
1547
- acc[setting.key] = setting.value;
1548
- }
1549
- return acc;
1550
- }, {});
1551
- }
1552
- }
1553
- RuntimeSettingsService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, deps: [{ token: i1.ConfigurationSettingsApiService }], target: i0.ɵɵFactoryTarget.Injectable });
1554
- RuntimeSettingsService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, providedIn: 'root' });
1555
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: RuntimeSettingsService, decorators: [{
1556
- type: Injectable,
1557
- args: [{ providedIn: 'root' }]
1558
- }], ctorParameters: function () { return [{ type: i1.ConfigurationSettingsApiService }]; } });
1559
-
1560
1567
  const DEFAULT_FORMATTING_SETTINGS = {
1561
1568
  currencySymbol: DEFAULT_CURRENCY_SYMBOL,
1562
1569
  decimalsCount: DEFAULT_DECIMALS_COUNT,