@contrail/flexplm 1.3.0 → 1.3.1-alpha.56221f6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/lib/cli/commands/compile.d.ts +1 -0
  2. package/lib/cli/commands/compile.js +71 -0
  3. package/lib/cli/commands/compile.spec.d.ts +1 -0
  4. package/lib/cli/commands/compile.spec.js +80 -0
  5. package/lib/cli/commands/create.d.ts +1 -0
  6. package/lib/cli/commands/create.js +75 -0
  7. package/lib/cli/commands/create.spec.d.ts +1 -0
  8. package/lib/cli/commands/create.spec.js +78 -0
  9. package/lib/cli/commands/upload.d.ts +10 -0
  10. package/lib/cli/commands/upload.js +219 -0
  11. package/lib/cli/commands/upload.spec.d.ts +1 -0
  12. package/lib/cli/commands/upload.spec.js +88 -0
  13. package/lib/cli/index.d.ts +2 -0
  14. package/lib/cli/index.js +64 -0
  15. package/lib/cli/index.spec.d.ts +1 -0
  16. package/lib/cli/index.spec.js +79 -0
  17. package/lib/cli/template/mapping-template.ts.template +18 -0
  18. package/lib/entity-processor/base-entity-processor.d.ts +89 -42
  19. package/lib/entity-processor/base-entity-processor.js +438 -385
  20. package/lib/entity-processor/base-entity-processor.spec.d.ts +1 -1
  21. package/lib/entity-processor/base-entity-processor.spec.js +398 -397
  22. package/lib/flexplm-request.d.ts +3 -3
  23. package/lib/flexplm-request.js +34 -34
  24. package/lib/flexplm-utils.d.ts +5 -5
  25. package/lib/flexplm-utils.js +33 -33
  26. package/lib/flexplm-utils.spec.d.ts +1 -1
  27. package/lib/flexplm-utils.spec.js +26 -26
  28. package/lib/index.d.ts +23 -22
  29. package/lib/index.js +39 -38
  30. package/lib/interfaces/interfaces.d.ts +105 -105
  31. package/lib/interfaces/interfaces.js +2 -2
  32. package/lib/interfaces/item-family-changes.d.ts +20 -20
  33. package/lib/interfaces/item-family-changes.js +56 -56
  34. package/lib/interfaces/mapping-file.d.ts +429 -0
  35. package/lib/interfaces/mapping-file.js +2 -0
  36. package/lib/interfaces/publish-change-data.d.ts +19 -19
  37. package/lib/interfaces/publish-change-data.js +32 -32
  38. package/lib/publish/base-process-publish-assortment-callback.d.ts +9 -9
  39. package/lib/publish/base-process-publish-assortment-callback.js +38 -38
  40. package/lib/publish/base-process-publish-assortment.d.ts +118 -93
  41. package/lib/publish/base-process-publish-assortment.js +998 -944
  42. package/lib/publish/base-process-publish-assortment.spec.d.ts +1 -1
  43. package/lib/publish/base-process-publish-assortment.spec.js +1688 -1670
  44. package/lib/publish/mockData.d.ts +1389 -1389
  45. package/lib/publish/mockData.js +4524 -4519
  46. package/lib/transform/identifier-conversion-spec-mockData.js +472 -444
  47. package/lib/transform/identifier-conversion.d.ts +51 -15
  48. package/lib/transform/identifier-conversion.js +248 -212
  49. package/lib/transform/identifier-conversion.spec.d.ts +1 -1
  50. package/lib/transform/identifier-conversion.spec.js +343 -339
  51. package/lib/util/config-defaults.d.ts +8 -8
  52. package/lib/util/config-defaults.js +88 -85
  53. package/lib/util/config-defaults.spec.d.ts +1 -1
  54. package/lib/util/config-defaults.spec.js +302 -293
  55. package/lib/util/data-converter-spec-mockData.js +219 -205
  56. package/lib/util/data-converter.d.ts +136 -39
  57. package/lib/util/data-converter.js +718 -592
  58. package/lib/util/data-converter.spec.d.ts +1 -1
  59. package/lib/util/data-converter.spec.js +906 -904
  60. package/lib/util/error-response-object.d.ts +9 -4
  61. package/lib/util/error-response-object.js +54 -47
  62. package/lib/util/error-response-object.spec.d.ts +1 -1
  63. package/lib/util/error-response-object.spec.js +99 -99
  64. package/lib/util/event-short-message-status.d.ts +19 -19
  65. package/lib/util/event-short-message-status.js +24 -23
  66. package/lib/util/federation.d.ts +15 -15
  67. package/lib/util/federation.js +157 -149
  68. package/lib/util/flexplm-connect.d.ts +29 -22
  69. package/lib/util/flexplm-connect.js +190 -176
  70. package/lib/util/flexplm-connect.spec.d.ts +1 -1
  71. package/lib/util/flexplm-connect.spec.js +88 -88
  72. package/lib/util/logger-config.d.ts +1 -1
  73. package/lib/util/logger-config.js +27 -26
  74. package/lib/util/map-util-spec-mockData.js +219 -205
  75. package/lib/util/map-utils.d.ts +33 -6
  76. package/lib/util/map-utils.js +42 -15
  77. package/lib/util/map-utils.spec.d.ts +1 -1
  78. package/lib/util/map-utils.spec.js +89 -89
  79. package/lib/util/mockData.d.ts +80 -80
  80. package/lib/util/mockData.js +103 -103
  81. package/lib/util/thumbnail-util.d.ts +55 -34
  82. package/lib/util/thumbnail-util.js +242 -215
  83. package/lib/util/thumbnail-util.spec.d.ts +1 -1
  84. package/lib/util/thumbnail-util.spec.js +440 -434
  85. package/lib/util/type-conversion-utils-spec-mockData.js +259 -259
  86. package/lib/util/type-conversion-utils.d.ts +163 -23
  87. package/lib/util/type-conversion-utils.js +408 -265
  88. package/lib/util/type-conversion-utils.spec.d.ts +1 -1
  89. package/lib/util/type-conversion-utils.spec.js +868 -868
  90. package/lib/util/type-defaults.d.ts +74 -16
  91. package/lib/util/type-defaults.js +279 -221
  92. package/lib/util/type-defaults.spec.d.ts +1 -1
  93. package/lib/util/type-defaults.spec.js +516 -516
  94. package/lib/util/type-utils.d.ts +34 -13
  95. package/lib/util/type-utils.js +137 -114
  96. package/lib/util/type-utils.spec.d.ts +1 -1
  97. package/lib/util/type-utils.spec.js +192 -190
  98. package/package.json +21 -6
  99. package/scripts/copy-template.js +10 -0
  100. package/.claude/settings.local.json +0 -8
  101. package/.github/pull_request_template.md +0 -31
  102. package/.github/workflows/flexplm-lib.yml +0 -27
  103. package/.github/workflows/publish-to-npm.yml +0 -124
  104. package/CHANGELOG.md +0 -32
  105. package/publish.bat +0 -5
  106. package/publish.sh +0 -5
  107. package/src/entity-processor/base-entity-processor.spec.ts +0 -460
  108. package/src/entity-processor/base-entity-processor.ts +0 -515
  109. package/src/flexplm-request.ts +0 -28
  110. package/src/flexplm-utils.spec.ts +0 -27
  111. package/src/flexplm-utils.ts +0 -29
  112. package/src/index.ts +0 -22
  113. package/src/interfaces/interfaces.ts +0 -122
  114. package/src/interfaces/item-family-changes.ts +0 -67
  115. package/src/interfaces/publish-change-data.ts +0 -43
  116. package/src/publish/base-process-publish-assortment-callback.ts +0 -50
  117. package/src/publish/base-process-publish-assortment.spec.ts +0 -1992
  118. package/src/publish/base-process-publish-assortment.ts +0 -1134
  119. package/src/publish/mockData.ts +0 -4561
  120. package/src/transform/identifier-conversion-spec-mockData.ts +0 -496
  121. package/src/transform/identifier-conversion.spec.ts +0 -354
  122. package/src/transform/identifier-conversion.ts +0 -282
  123. package/src/util/config-defaults.spec.ts +0 -350
  124. package/src/util/config-defaults.ts +0 -93
  125. package/src/util/data-converter-spec-mockData.ts +0 -231
  126. package/src/util/data-converter.spec.ts +0 -1041
  127. package/src/util/data-converter.ts +0 -762
  128. package/src/util/error-response-object.spec.ts +0 -116
  129. package/src/util/error-response-object.ts +0 -50
  130. package/src/util/event-short-message-status.ts +0 -22
  131. package/src/util/federation.ts +0 -172
  132. package/src/util/flexplm-connect.spec.ts +0 -132
  133. package/src/util/flexplm-connect.ts +0 -208
  134. package/src/util/logger-config.ts +0 -20
  135. package/src/util/map-util-spec-mockData.ts +0 -231
  136. package/src/util/map-utils.spec.ts +0 -103
  137. package/src/util/map-utils.ts +0 -41
  138. package/src/util/mockData.ts +0 -101
  139. package/src/util/thumbnail-util.spec.ts +0 -508
  140. package/src/util/thumbnail-util.ts +0 -272
  141. package/src/util/type-conversion-utils-spec-mockData.ts +0 -271
  142. package/src/util/type-conversion-utils.spec.ts +0 -968
  143. package/src/util/type-conversion-utils.ts +0 -460
  144. package/src/util/type-defaults.spec.ts +0 -669
  145. package/src/util/type-defaults.ts +0 -281
  146. package/src/util/type-utils.spec.ts +0 -227
  147. package/src/util/type-utils.ts +0 -144
  148. package/tsconfig.json +0 -29
  149. package/tslint.json +0 -57
@@ -1,592 +1,718 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DataConverter = void 0;
4
- const sdk_1 = require("@contrail/sdk");
5
- const type_utils_1 = require("./type-utils");
6
- const app_framework_1 = require("@contrail/app-framework");
7
- const util_1 = require("@contrail/util");
8
- const type_conversion_utils_1 = require("./type-conversion-utils");
9
- const map_utils_1 = require("./map-utils");
10
- class DataConverter {
11
- static clearStaticUserCache() {
12
- DataConverter.staticUserCache = {};
13
- }
14
- static getFromStaticCache(id) {
15
- return DataConverter.staticUserCache[id];
16
- }
17
- static setToStaticCache(id, value) {
18
- DataConverter.staticUserCache[id] = value;
19
- }
20
- constructor(config, mapFileUtil) {
21
- this.config = config;
22
- this.mapFileUtil = mapFileUtil;
23
- this.useDisplayForEnumerationMatching = false;
24
- this.verboseDebug = false;
25
- this.objRefCache = {};
26
- this.userRefCache = {};
27
- this.typeUtils = new type_utils_1.TypeUtils();
28
- this.transformMapFile = this.config['transformMapFile'];
29
- this.useDisplayForEnumerationMatching = this.config['dataConverter']
30
- && this.config['dataConverter']['useDisplayForEnumerationMatching'];
31
- this.verboseDebug = this.config['dataConverter']
32
- && this.config['dataConverter']['verboseDebug'];
33
- }
34
- setVerboseDebug(val = false) {
35
- this.verboseDebug = val;
36
- }
37
- isVerboseDebugOn() {
38
- return this.verboseDebug && app_framework_1.Logger.isDebugOn();
39
- }
40
- async getFlexPLMObjectDataFromEvent(event, dataToSkip) {
41
- return this.getFlexPLMObjectData(event.newData, dataToSkip, true);
42
- }
43
- async getFlexPLMObjectData(newData, dataToSkip, inflateObjRef) {
44
- if (this.isVerboseDebugOn()) {
45
- console.debug('newData: ' + JSON.stringify(newData));
46
- }
47
- dataToSkip = dataToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'workspaceId']);
48
- const data = {};
49
- const typeId = newData?.typeId;
50
- if (!typeId) {
51
- return;
52
- }
53
- data['typePath'] = newData['typePath'];
54
- const type = await this.typeUtils.getTypeById(typeId);
55
- const typeProps = this.typeUtils.filterTypeProperties(type, newData);
56
- for (const prop of typeProps) {
57
- const slug = prop['slug'];
58
- if (dataToSkip.includes(slug)) {
59
- continue;
60
- }
61
- data[slug] = await this.getFlexPLMValue(prop, newData, inflateObjRef);
62
- }
63
- if (this.isVerboseDebugOn()) {
64
- console.debug('getFlexPLMObjectData-data: ' + JSON.stringify(data));
65
- }
66
- return data;
67
- }
68
- async getFlexPLMValue(prop, newData, inflateObjRef) {
69
- const propertyType = prop['propertyType'];
70
- const slug = prop['slug'];
71
- const nd = newData[slug];
72
- let value;
73
- if (['string', 'text'].includes(propertyType)) {
74
- value = nd || '';
75
- }
76
- else if (['number', 'currency', 'percent', 'sequence'].includes(propertyType)) {
77
- value = nd || 0;
78
- }
79
- else if ('date' === propertyType) {
80
- if (nd) {
81
- value = nd;
82
- }
83
- else {
84
- value = null;
85
- }
86
- }
87
- else if ('boolean' === propertyType) {
88
- value = (nd) ? true : false;
89
- }
90
- else if ('choice' === propertyType) {
91
- value = this.getEnumerationValue(prop, nd);
92
- }
93
- else if ('multi_select' === propertyType) {
94
- value = this.getEnumerationValue(prop, nd);
95
- }
96
- else if ('object_reference' === propertyType) {
97
- value = await this.getObjectReferenceValue(prop, newData, inflateObjRef);
98
- if (this.isVerboseDebugOn()) {
99
- console.debug('object_reference: ' + JSON.stringify(value));
100
- }
101
- }
102
- else if ('image' === propertyType) {
103
- }
104
- else if ('formula' === propertyType) {
105
- value = nd;
106
- }
107
- else if ('json' === propertyType) {
108
- value = nd;
109
- }
110
- else if ('userList' === propertyType) {
111
- value = await this.getUserListValue(prop, newData);
112
- }
113
- return value;
114
- }
115
- getEnumerationValue(prop, nd) {
116
- const propertyType = prop['propertyType'];
117
- let value;
118
- if (['choice', 'multi_select'].includes(propertyType)) {
119
- const options = prop['options'] || [];
120
- if ('choice' === propertyType) {
121
- if (nd) {
122
- const option = options.find(option => option.value == nd);
123
- if (option) {
124
- value = Object.assign({}, option);
125
- }
126
- }
127
- if (!value) {
128
- value = {};
129
- }
130
- }
131
- else if ('multi_select' === propertyType) {
132
- value = [];
133
- if (nd instanceof Array) {
134
- nd.forEach(key => {
135
- const optionObject = options.find(option => option.value == key);
136
- if (optionObject) {
137
- const option = Object.assign({}, optionObject);
138
- value.push(option);
139
- }
140
- });
141
- }
142
- else if (typeof nd === 'string' && '' !== nd) {
143
- const optionObject = options.find(option => option.value == nd);
144
- if (optionObject) {
145
- const option = Object.assign({}, optionObject);
146
- value.push(option);
147
- }
148
- }
149
- }
150
- }
151
- return value;
152
- }
153
- async getObjectReferenceValue(prop, newData, inflateObjRef = false) {
154
- const slug = prop['slug'];
155
- if (app_framework_1.Logger.isDebugOn()) {
156
- console.debug('getObjectReferenceValue-prop: ' + slug);
157
- }
158
- let value = newData[slug];
159
- const entityType = prop['referencedTypeRootSlug'];
160
- const entityId = newData[slug + 'Id'];
161
- if ((!value || typeof value === 'string') && inflateObjRef) {
162
- if (entityId) {
163
- if (this.objRefCache[entityId]) {
164
- if (app_framework_1.Logger.isDebugOn()) {
165
- console.debug('cache hit: ' + entityId);
166
- }
167
- return this.objRefCache[entityId];
168
- }
169
- const criteria = {
170
- id: entityId
171
- };
172
- const entities = await new sdk_1.Entities().get({
173
- entityName: entityType,
174
- criteria
175
- });
176
- value = (entities && entities[0]) ? entities[0] : undefined;
177
- }
178
- }
179
- if (value && !(typeof value === 'string')) {
180
- const unprocessedValue = value;
181
- const objectClass = await type_conversion_utils_1.TypeConversionUtils.getObjectClass(this.transformMapFile, this.mapFileUtil, unprocessedValue);
182
- const flexPLMTypePath = await type_conversion_utils_1.TypeConversionUtils.getObjectTypePath(this.transformMapFile, this.mapFileUtil, unprocessedValue);
183
- value = await this.getFlexPLMObjectData(value, [], false);
184
- value['entityReference'] = entityType + ':' + entityId;
185
- value['objectClass'] = objectClass;
186
- value['flexPLMTypePath'] = flexPLMTypePath;
187
- if (this.transformMapFile) {
188
- const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKey(this.transformMapFile, this.mapFileUtil, unprocessedValue, type_conversion_utils_1.TypeConversionUtils.VIBE2FLEX_DIRECTION);
189
- value = await map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, value, mapKey, type_conversion_utils_1.TypeConversionUtils.VIBE2FLEX_DIRECTION);
190
- }
191
- }
192
- else {
193
- value = {};
194
- }
195
- this.objRefCache[entityId] = value;
196
- return value;
197
- }
198
- getMappingClass(entity, mapping) {
199
- const entityTypePath = entity['typePath'];
200
- const typeMapKey = mapping['typeMapKey'];
201
- let objClass = typeMapKey[entityTypePath];
202
- const entityType = entity['entityType'];
203
- if (!objClass) {
204
- objClass = this.typeUtils.getEventObjectClass(entityType, entity);
205
- }
206
- if (!objClass) {
207
- objClass = entityType;
208
- }
209
- return objClass;
210
- }
211
- async setEntityValues(entity, data, keysToSkip = []) {
212
- const type = await this.typeUtils.getTypeById(entity.typeId);
213
- keysToSkip = keysToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'typePath', 'workspaceId']);
214
- let typeProps = this.typeUtils.filterTypeProperties(type, entity);
215
- typeProps = typeProps.filter(prop => !keysToSkip.includes(prop['slug']));
216
- const dataKeys = Object.getOwnPropertyNames(data);
217
- typeProps = typeProps.filter(prop => dataKeys.includes(prop['slug']));
218
- for (const prop of typeProps) {
219
- const propertyType = prop['propertyType'];
220
- const slug = prop['slug'];
221
- let keyName = slug;
222
- if (propertyType === 'userList' || propertyType === 'object_reference') {
223
- keyName = slug + 'Id';
224
- }
225
- entity[keyName] = await this.getEntityValue(prop, data);
226
- }
227
- return entity;
228
- }
229
- async getEntityValues(objectClass, data, keysToSkip = []) {
230
- const entityValues = {};
231
- const tco = await this.typeUtils.getEntityTypeClientOptionsUsingMapping(this.transformMapFile, this.mapFileUtil, data);
232
- const type = await this.typeUtils.getByRootAndPath(tco);
233
- const typePath = type['typePath'];
234
- if (typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))) {
235
- if (['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)) {
236
- entityValues['roles'] = ['family'];
237
- }
238
- else {
239
- entityValues['roles'] = ['color', 'option'];
240
- }
241
- }
242
- let typeProps = this.typeUtils.filterTypeProperties(type, entityValues);
243
- typeProps = typeProps.filter(prop => !keysToSkip.includes(prop['slug']));
244
- for (const prop of typeProps) {
245
- const slug = prop['slug'];
246
- const value = await this.getEntityValue(prop, data);
247
- if (value) {
248
- entityValues[slug] = value;
249
- }
250
- }
251
- return entityValues;
252
- }
253
- async getEntityValue(prop, data) {
254
- const propertyType = prop['propertyType'];
255
- const slug = prop['slug'];
256
- const nd = data[slug];
257
- let value;
258
- if (['string', 'text'].includes(propertyType)) {
259
- value = nd;
260
- }
261
- else if (['number', 'currency', 'percent', 'sequence'].includes(propertyType)) {
262
- value = (null === nd) ? 0 : nd;
263
- }
264
- else if ('date' === propertyType) {
265
- if (nd) {
266
- const d = new Date(nd);
267
- value = d.toISOString();
268
- }
269
- else {
270
- value = null;
271
- }
272
- }
273
- else if ('boolean' === propertyType) {
274
- value = (nd) ? true : false;
275
- }
276
- else if ('choice' === propertyType) {
277
- value = this.setEnumerationKeys(prop, nd, this.useDisplayForEnumerationMatching);
278
- }
279
- else if ('multi_select' === propertyType) {
280
- value = this.setEnumerationKeys(prop, nd, this.useDisplayForEnumerationMatching);
281
- }
282
- else if ('object_reference' === propertyType) {
283
- value = await this.setObjectReferenceValue(prop, nd);
284
- }
285
- else if ('image' === propertyType) {
286
- }
287
- else if ('formula' === propertyType) {
288
- }
289
- else if ('json' === propertyType) {
290
- }
291
- else if ('userList' === propertyType) {
292
- value = await this.setUserListValue(prop, nd);
293
- }
294
- return value;
295
- }
296
- setEnumerationKeys(prop, nd, matchByDisplay) {
297
- const propertyType = prop['propertyType'];
298
- let value;
299
- if (['choice', 'multi_select'].includes(propertyType)) {
300
- const options = prop['options'] || [];
301
- if ('choice' === propertyType) {
302
- if (nd) {
303
- const matchKey = (matchByDisplay) ? 'display' : 'value';
304
- const option = options.find(option => option[matchKey] == nd[matchKey]);
305
- if (option) {
306
- value = option.value;
307
- }
308
- }
309
- else {
310
- value = undefined;
311
- }
312
- }
313
- else if ('multi_select' === propertyType) {
314
- value = [];
315
- const matchKey = (matchByDisplay) ? 'display' : 'value';
316
- if (nd instanceof Array) {
317
- nd.forEach(selectedOpt => {
318
- const optionObject = options.find(option => option[matchKey] == selectedOpt[matchKey]);
319
- if (optionObject) {
320
- const option = optionObject.value;
321
- value.push(option);
322
- }
323
- });
324
- }
325
- }
326
- }
327
- return value;
328
- }
329
- getPersistableChanges(entity, changes) {
330
- const entityCompareValues = {};
331
- for (const key of (Object.getOwnPropertyNames(changes))) {
332
- entityCompareValues[key] = entity[key];
333
- }
334
- const diffs = util_1.ObjectUtil.compareDeep(entityCompareValues, changes, '');
335
- const diffValues = {};
336
- if (diffs && diffs.length > 0) {
337
- for (const diff of diffs) {
338
- diffValues[diff.propertyName] = diff.newValue;
339
- }
340
- }
341
- return diffValues;
342
- }
343
- async setObjectReferenceValue(prop, nd) {
344
- let objectReferenceId = "";
345
- if (!nd) {
346
- return objectReferenceId;
347
- }
348
- if (this.transformMapFile) {
349
- const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKeyFromObject(this.transformMapFile, this.mapFileUtil, nd, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
350
- nd = await map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, nd, mapKey, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
351
- }
352
- const entityType = prop['referencedTypeRootSlug'];
353
- const entityTypePath = prop['referencedTypePath'];
354
- const entityKeys = Object.keys(nd);
355
- const identifierKeys = await type_conversion_utils_1.TypeConversionUtils.getIdentifierPropertiesFromObject(this.transformMapFile, this.mapFileUtil, nd);
356
- const hasAllIdentifiers = identifierKeys.every(key => entityKeys.includes(key));
357
- if (identifierKeys.length == 0 || !hasAllIdentifiers) {
358
- console.warn(`The inbound ${entityType} for prop '${prop['slug']}' doesnt have all "identifier" properties, so there is no processing. Identifier properties: ${identifierKeys}`);
359
- return objectReferenceId;
360
- }
361
- const rootType = await this.typeUtils.getByRootAndPath({ root: entityType });
362
- const rootTypeProps = this.typeUtils.filterTypeProperties(rootType, nd);
363
- let rootTypeCriteria = {};
364
- let typeCriteria = {};
365
- identifierKeys.forEach(keyName => {
366
- const foundInObjects = rootTypeProps.some(obj => obj.slug === keyName);
367
- if (foundInObjects) {
368
- rootTypeCriteria[keyName] = nd[keyName];
369
- }
370
- else {
371
- typeCriteria[keyName] = nd[keyName];
372
- }
373
- });
374
- const combinedCriteria = { ...rootTypeCriteria, ...typeCriteria, typePath: entityTypePath };
375
- const cacheKey = Object.values(combinedCriteria).join('_');
376
- if (this.objRefCache[cacheKey]) {
377
- if (app_framework_1.Logger.isDebugOn()) {
378
- console.debug(`object reference cache hit: ${cacheKey}`);
379
- }
380
- return this.objRefCache[cacheKey];
381
- }
382
- let arrObjectReferences = await this.getAllObjectReferences(entityType, rootTypeCriteria);
383
- if (entityType !== entityTypePath) {
384
- arrObjectReferences = this.checkKeysAndValues(typeCriteria, arrObjectReferences, entityTypePath);
385
- }
386
- if (arrObjectReferences.length) {
387
- if (arrObjectReferences.length === 1) {
388
- objectReferenceId = arrObjectReferences[0].id;
389
- }
390
- else {
391
- console.warn(`The passed in object reference criteria has duplicate records found ${JSON.stringify(combinedCriteria)}.`);
392
- }
393
- }
394
- if (!objectReferenceId) {
395
- console.warn(`The passed in object reference criteria ${JSON.stringify(combinedCriteria)} didn't match any entities.`);
396
- return objectReferenceId;
397
- }
398
- this.objRefCache[cacheKey] = objectReferenceId;
399
- return objectReferenceId;
400
- }
401
- async getAllObjectReferences(entityType, rootTypeCriteria, postProcessCriteria = null) {
402
- const entities = new sdk_1.Entities();
403
- let loads = [];
404
- let nextPageKey;
405
- let usedV2 = false;
406
- do {
407
- const take = 1000;
408
- const loadPage = await entities.get({
409
- entityName: entityType,
410
- criteria: rootTypeCriteria,
411
- apiVersion: sdk_1.API_VERSION.V2,
412
- take,
413
- nextPageKey,
414
- });
415
- nextPageKey = loadPage?.nextPageKey;
416
- if (Object.keys(loadPage).includes('results')) {
417
- usedV2 = true;
418
- let postProcessedResults = this.filterOutArchivedAndTrashedEntities(loadPage?.results);
419
- if (postProcessedResults?.length > 0 && postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
420
- const subEntityTypePath = rootTypeCriteria.typePath || entityType;
421
- postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
422
- }
423
- loads.push(...postProcessedResults);
424
- }
425
- else {
426
- nextPageKey = null;
427
- }
428
- } while (nextPageKey);
429
- if (!usedV2) {
430
- const take = 1000;
431
- let skip = 0;
432
- let done = false;
433
- while (!done) {
434
- const loadPage = await entities.get({
435
- entityName: entityType,
436
- criteria: rootTypeCriteria,
437
- take,
438
- skip,
439
- });
440
- let postProcessedResults = this.filterOutArchivedAndTrashedEntities(loadPage);
441
- if (postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
442
- const subEntityTypePath = rootTypeCriteria.typePath || entityType;
443
- postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
444
- }
445
- loads.push(...postProcessedResults);
446
- if (loadPage.length !== take) {
447
- done = true;
448
- }
449
- else {
450
- skip += take;
451
- }
452
- }
453
- }
454
- return loads;
455
- }
456
- checkKeysAndValues(criteria, arrayOfObjects, entityTypePath) {
457
- let arrOfMatchObjects = [];
458
- for (let i = 0; i < arrayOfObjects.length; i++) {
459
- const currentObj = arrayOfObjects[i];
460
- let found = true;
461
- if (entityTypePath && currentObj['typePath']) {
462
- const currentObjPath = '' + currentObj['typePath'];
463
- if (!currentObjPath.startsWith(entityTypePath)) {
464
- found = false;
465
- }
466
- }
467
- for (const key in criteria) {
468
- if (!(key in currentObj) || currentObj[key] !== criteria[key]) {
469
- found = false;
470
- break;
471
- }
472
- }
473
- if (found) {
474
- arrOfMatchObjects.push(currentObj);
475
- }
476
- }
477
- return arrOfMatchObjects;
478
- }
479
- filterOutArchivedAndTrashedEntities(entities) {
480
- if (!entities || !Array.isArray(entities) || entities.length === 0) {
481
- return [];
482
- }
483
- return entities.filter(entity => {
484
- const isArchived = entity?.isArchived;
485
- const isTrashed = entity?.isTrashed;
486
- return !isArchived && !isTrashed;
487
- });
488
- }
489
- async setUserListValue(prop, nd) {
490
- if (!nd?.email) {
491
- return "";
492
- }
493
- let cacheUser = DataConverter.getFromStaticCache(nd.email);
494
- if (cacheUser) {
495
- if (app_framework_1.Logger.isDebugOn()) {
496
- console.debug('user cache hit: ' + nd.email);
497
- }
498
- await this.processGroupMemberCheck(prop, nd.email);
499
- return cacheUser;
500
- }
501
- const user = await this.getUserByEmail(nd);
502
- const userId = (user) ? user.id : undefined;
503
- if (userId) {
504
- DataConverter.setToStaticCache(nd.email, userId);
505
- await this.processGroupMemberCheck(prop, nd.email);
506
- }
507
- return userId;
508
- }
509
- async getUserByEmail(nd) {
510
- let userOrg = undefined;
511
- let count = 0;
512
- let size = 0;
513
- let emailInput = nd?.email.toLowerCase();
514
- const entities = new sdk_1.Entities();
515
- const getOptionsCriteria = {
516
- entityName: 'user-org',
517
- take: 1000
518
- };
519
- do {
520
- const userBatch = await entities.get(getOptionsCriteria);
521
- userOrg = userBatch.find(uo => uo?.userEmail.toLowerCase() === emailInput);
522
- } while (!userOrg && size == getOptionsCriteria.take && count < 15);
523
- return userOrg?.user;
524
- }
525
- async processGroupMemberCheck(prop, userEmail) {
526
- let arrUserList = [];
527
- if (this.userRefCache[prop.typePropertyUserListId]) {
528
- arrUserList = this.userRefCache[prop.typePropertyUserListId];
529
- }
530
- else {
531
- const userListResult = await new sdk_1.Entities().get({
532
- entityName: 'user-list',
533
- id: prop.typePropertyUserListId
534
- });
535
- if (userListResult && Object.keys(userListResult).length) {
536
- arrUserList = userListResult.userList;
537
- this.userRefCache[prop.typePropertyUserListId] = arrUserList;
538
- }
539
- }
540
- if (arrUserList.length) {
541
- const result = arrUserList.find(element => element['display'] === userEmail);
542
- if (!result) {
543
- console.warn(`The passed in user ${userEmail} in property slug ${prop.slug} should be a member of the group associated with the property 'typePropertyUserListId'`);
544
- }
545
- }
546
- }
547
- async getUserListValue(prop, newData) {
548
- const slug = prop['slug'];
549
- if (app_framework_1.Logger.isDebugOn()) {
550
- console.debug('getUserListValue-prop: ' + slug);
551
- }
552
- const entityId = newData[slug + 'Id'];
553
- if (!entityId) {
554
- return {};
555
- }
556
- const cacheUser = DataConverter.getFromStaticCache(entityId);
557
- if (cacheUser) {
558
- if (app_framework_1.Logger.isDebugOn()) {
559
- console.debug('user cache hit: ' + entityId);
560
- }
561
- return Object.assign({}, cacheUser);
562
- }
563
- const user = await this.getUserById(entityId);
564
- const value = (user) ? {
565
- email: user.email,
566
- firstName: user.first,
567
- lastName: user.last,
568
- isSsoUser: user.isSsoUser,
569
- } : undefined;
570
- if (value) {
571
- DataConverter.setToStaticCache(entityId, value);
572
- }
573
- return value;
574
- }
575
- async getUserById(userId) {
576
- let userOrg = undefined;
577
- let count = 0;
578
- let size = 0;
579
- const entities = new sdk_1.Entities();
580
- const getOptionsCriteria = {
581
- entityName: 'user-org',
582
- take: 1000
583
- };
584
- do {
585
- const userBatch = await entities.get(getOptionsCriteria);
586
- userOrg = userBatch.find(uo => uo?.user?.id === userId);
587
- } while (!userOrg && size == getOptionsCriteria.take && count < 15);
588
- return userOrg?.user;
589
- }
590
- }
591
- exports.DataConverter = DataConverter;
592
- DataConverter.staticUserCache = {};
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataConverter = void 0;
4
+ const sdk_1 = require("@contrail/sdk");
5
+ const type_utils_1 = require("./type-utils");
6
+ const app_framework_1 = require("@contrail/app-framework");
7
+ const util_1 = require("@contrail/util");
8
+ const type_conversion_utils_1 = require("./type-conversion-utils");
9
+ const map_utils_1 = require("./map-utils");
10
+ class DataConverter {
11
+ static clearStaticUserCache() {
12
+ DataConverter.staticUserCache = {};
13
+ }
14
+ static getFromStaticCache(id) {
15
+ return DataConverter.staticUserCache[id];
16
+ }
17
+ static setToStaticCache(id, value) {
18
+ DataConverter.staticUserCache[id] = value;
19
+ }
20
+ constructor(config, mapFileUtil) {
21
+ this.config = config;
22
+ this.mapFileUtil = mapFileUtil;
23
+ this.useDisplayForEnumerationMatching = false;
24
+ this.verboseDebug = false;
25
+ this.objRefCache = {};
26
+ this.userRefCache = {};
27
+ this.typeUtils = new type_utils_1.TypeUtils();
28
+ this.transformMapFile = this.config['transformMapFile'];
29
+ this.useDisplayForEnumerationMatching = this.config['dataConverter']
30
+ && this.config['dataConverter']['useDisplayForEnumerationMatching'];
31
+ this.verboseDebug = this.config['dataConverter']
32
+ && this.config['dataConverter']['verboseDebug'];
33
+ }
34
+ setVerboseDebug(val = false) {
35
+ this.verboseDebug = val;
36
+ }
37
+ isVerboseDebugOn() {
38
+ return this.verboseDebug && app_framework_1.Logger.isDebugOn();
39
+ }
40
+ async getFlexPLMObjectDataFromEvent(event, dataToSkip) {
41
+ return this.getFlexPLMObjectData(event.newData, dataToSkip, true);
42
+ }
43
+ async getFlexPLMObjectData(newData, dataToSkip, inflateObjRef) {
44
+ if (this.isVerboseDebugOn()) {
45
+ console.debug('newData: ' + JSON.stringify(newData));
46
+ }
47
+ //Using event to get propertyDiffs to find emptied values
48
+ //Add standard atts to skip
49
+ dataToSkip = dataToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'workspaceId']);
50
+ // const oldData = event.oldData;
51
+ const data = {};
52
+ const typeId = newData?.typeId;
53
+ if (!typeId) {
54
+ return; // Don't have a type; so can't process
55
+ }
56
+ data['typePath'] = newData['typePath'];
57
+ const type = await this.typeUtils.getTypeById(typeId);
58
+ const typeProps = this.typeUtils.filterTypeProperties(type, newData);
59
+ for (const prop of typeProps) {
60
+ // if(this.logger.isTraceOn()){
61
+ // this.logger.log('prop: ' + JSON.stringify(prop));
62
+ // }
63
+ const slug = prop['slug'];
64
+ if (dataToSkip.includes(slug)) {
65
+ continue;
66
+ }
67
+ data[slug] = await this.getFlexPLMValue(prop, newData, inflateObjRef);
68
+ }
69
+ if (this.isVerboseDebugOn()) {
70
+ console.debug('getFlexPLMObjectData-data: ' + JSON.stringify(data));
71
+ }
72
+ return data;
73
+ }
74
+ async getFlexPLMValue(prop, newData, inflateObjRef) {
75
+ const propertyType = prop['propertyType'];
76
+ const slug = prop['slug'];
77
+ const nd = newData[slug];
78
+ // console.log('getFlexPLMValue: ' + propertyType + ', ' +slug + ', ' + nd + ', ' + od);
79
+ let value;
80
+ if (['string', 'text'].includes(propertyType)) {
81
+ value = nd || '';
82
+ }
83
+ else if (['number', 'currency', 'percent', 'sequence'].includes(propertyType)) {
84
+ value = nd || 0;
85
+ }
86
+ else if ('date' === propertyType) {
87
+ if (nd) {
88
+ value = nd;
89
+ // const d = new Date(nd);
90
+ // console.log('Date.getTimezoneOffset(): ' + d.getTimezoneOffset());
91
+ // value = d.toISOString();
92
+ // console.log('date: ' + nd + ' -- ' + value);
93
+ }
94
+ else {
95
+ value = null;
96
+ }
97
+ }
98
+ else if ('boolean' === propertyType) {
99
+ value = (nd) ? true : false;
100
+ }
101
+ else if ('choice' === propertyType) {
102
+ value = this.getEnumerationValue(prop, nd);
103
+ }
104
+ else if ('multi_select' === propertyType) {
105
+ value = this.getEnumerationValue(prop, nd);
106
+ }
107
+ else if ('object_reference' === propertyType) {
108
+ value = await this.getObjectReferenceValue(prop, newData, inflateObjRef);
109
+ if (this.isVerboseDebugOn()) {
110
+ console.debug('object_reference: ' + JSON.stringify(value));
111
+ }
112
+ }
113
+ else if ('image' === propertyType) {
114
+ // console.log('image-TODO');
115
+ }
116
+ else if ('formula' === propertyType) {
117
+ value = nd;
118
+ }
119
+ else if ('json' === propertyType) {
120
+ // console.log('json-TODO');
121
+ value = nd;
122
+ }
123
+ else if ('userList' === propertyType) {
124
+ value = await this.getUserListValue(prop, newData);
125
+ }
126
+ return value;
127
+ }
128
+ /** Returns the display values for list properties (choice & multi_select)
129
+ *
130
+ * @param prop
131
+ * @param newData
132
+ * @returns
133
+ */
134
+ getEnumerationValue(prop, nd) {
135
+ const propertyType = prop['propertyType'];
136
+ let value;
137
+ if (['choice', 'multi_select'].includes(propertyType)) {
138
+ const options = prop['options'] || [];
139
+ if ('choice' === propertyType) {
140
+ if (nd) {
141
+ const option = options.find(option => option.value == nd);
142
+ if (option) {
143
+ value = Object.assign({}, option);
144
+ }
145
+ }
146
+ if (!value) {
147
+ value = {};
148
+ }
149
+ }
150
+ else if ('multi_select' === propertyType) {
151
+ value = [];
152
+ if (nd instanceof Array) {
153
+ nd.forEach(key => {
154
+ const optionObject = options.find(option => option.value == key);
155
+ if (optionObject) {
156
+ const option = Object.assign({}, optionObject);
157
+ value.push(option);
158
+ }
159
+ });
160
+ }
161
+ else if (typeof nd === 'string' && '' !== nd) {
162
+ const optionObject = options.find(option => option.value == nd);
163
+ if (optionObject) {
164
+ const option = Object.assign({}, optionObject);
165
+ value.push(option);
166
+ }
167
+ }
168
+ }
169
+ }
170
+ return value;
171
+ }
172
+ async getObjectReferenceValue(prop, newData, inflateObjRef = false) {
173
+ const slug = prop['slug'];
174
+ if (app_framework_1.Logger.isDebugOn()) {
175
+ console.debug('getObjectReferenceValue-prop: ' + slug);
176
+ }
177
+ let value = newData[slug];
178
+ const entityType = prop['referencedTypeRootSlug'];
179
+ const entityId = newData[slug + 'Id'];
180
+ if ((!value || typeof value === 'string') && inflateObjRef) {
181
+ if (entityId) {
182
+ if (this.objRefCache[entityId]) {
183
+ if (app_framework_1.Logger.isDebugOn()) {
184
+ console.debug('cache hit: ' + entityId);
185
+ }
186
+ return this.objRefCache[entityId];
187
+ }
188
+ const criteria = {
189
+ id: entityId
190
+ };
191
+ const entities = await new sdk_1.Entities().get({
192
+ entityName: entityType,
193
+ criteria
194
+ });
195
+ value = (entities && entities[0]) ? entities[0] : undefined;
196
+ }
197
+ }
198
+ if (value && !(typeof value === 'string')) {
199
+ const unprocessedValue = value;
200
+ const objectClass = await type_conversion_utils_1.TypeConversionUtils.getObjectClass(this.transformMapFile, this.mapFileUtil, unprocessedValue);
201
+ const flexPLMTypePath = await type_conversion_utils_1.TypeConversionUtils.getObjectTypePath(this.transformMapFile, this.mapFileUtil, unprocessedValue);
202
+ value = await this.getFlexPLMObjectData(value, [], false);
203
+ value['entityReference'] = entityType + ':' + entityId;
204
+ value['objectClass'] = objectClass;
205
+ value['flexPLMTypePath'] = flexPLMTypePath;
206
+ if (this.transformMapFile) {
207
+ const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKey(this.transformMapFile, this.mapFileUtil, unprocessedValue, type_conversion_utils_1.TypeConversionUtils.VIBE2FLEX_DIRECTION);
208
+ value = await map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, value, mapKey, type_conversion_utils_1.TypeConversionUtils.VIBE2FLEX_DIRECTION);
209
+ }
210
+ }
211
+ else {
212
+ value = {};
213
+ }
214
+ this.objRefCache[entityId] = value;
215
+ return value;
216
+ }
217
+ /** (Deprecated) Use TypeConversionUtils.getMapKey()
218
+ * Will return the class to use to get mapping.
219
+ * This is needed because mappings will be different for different sub types
220
+ * of custom-entity
221
+ *
222
+ * @param obj: Entity being checked
223
+ * @param mapping: The whole mapping file
224
+ */
225
+ getMappingClass(entity, mapping) {
226
+ const entityTypePath = entity['typePath'];
227
+ const typeMapKey = mapping['typeMapKey'];
228
+ let objClass = typeMapKey[entityTypePath];
229
+ const entityType = entity['entityType'];
230
+ if (!objClass) {
231
+ objClass = this.typeUtils.getEventObjectClass(entityType, entity);
232
+ }
233
+ if (!objClass) {
234
+ objClass = entityType;
235
+ }
236
+ return objClass;
237
+ }
238
+ /** Sets entity values from FlexPLM data passed in
239
+ * Assumes the entity has a VibeIQ typeId and 'roles' value to filter if necessary.
240
+ * @param entity the entity to update
241
+ * @param data the FlexPLM data
242
+ * @param keysToSkip properties to skip
243
+ * @returns the modified entity with VibeIQ values
244
+ */
245
+ async setEntityValues(entity, data, keysToSkip = []) {
246
+ // this.logger.log('setEntityValues: ' + JSON.stringify(entity));
247
+ // this.logger.log('data: ' + JSON.stringify(data));
248
+ const type = await this.typeUtils.getTypeById(entity.typeId);
249
+ keysToSkip = keysToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'typePath', 'workspaceId']);
250
+ let typeProps = this.typeUtils.filterTypeProperties(type, entity);
251
+ typeProps = typeProps.filter(prop => !keysToSkip.includes(prop['slug']));
252
+ //Only process properties that had a value sent; to not accidentally clear out values
253
+ //for properties that weren't sent.
254
+ const dataKeys = Object.getOwnPropertyNames(data);
255
+ typeProps = typeProps.filter(prop => dataKeys.includes(prop['slug']));
256
+ for (const prop of typeProps) {
257
+ const propertyType = prop['propertyType'];
258
+ const slug = prop['slug'];
259
+ let keyName = slug;
260
+ if (propertyType === 'userList' || propertyType === 'object_reference') {
261
+ keyName = slug + 'Id';
262
+ }
263
+ entity[keyName] = await this.getEntityValue(prop, data);
264
+ // console.log('entity[slug]: ' + entity[slug]);
265
+ }
266
+ return entity;
267
+ }
268
+ /** Gets the entity values from FlexPLM data
269
+ * Assumes there isn't a VibeIQ typeId, so uses FlexPLM data to determine type
270
+ * @param objectClass FlexPLM object class
271
+ * @param data object data
272
+ * @param keysToSkip type properties to not process
273
+ * @returns object with VibeIQ values
274
+ */
275
+ async getEntityValues(objectClass, data, keysToSkip = []) {
276
+ const entityValues = {};
277
+ const tco = await this.typeUtils.getEntityTypeClientOptionsUsingMapping(this.transformMapFile, this.mapFileUtil, data);
278
+ const type = await this.typeUtils.getByRootAndPath(tco);
279
+ const typePath = type['typePath'];
280
+ if (typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))) {
281
+ if (['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)) {
282
+ entityValues['roles'] = ['family'];
283
+ }
284
+ else {
285
+ entityValues['roles'] = ['color', 'option'];
286
+ }
287
+ }
288
+ let typeProps = this.typeUtils.filterTypeProperties(type, entityValues);
289
+ typeProps = typeProps.filter(prop => !keysToSkip.includes(prop['slug']));
290
+ for (const prop of typeProps) {
291
+ const slug = prop['slug'];
292
+ const value = await this.getEntityValue(prop, data);
293
+ if (value) {
294
+ entityValues[slug] = value;
295
+ }
296
+ }
297
+ return entityValues;
298
+ }
299
+ /** Gets the VibeIQ value for the property from data
300
+ *
301
+ * @param prop the VibeIQ property
302
+ * @param data the FlexPLM data
303
+ * @returns value to be set in VibeIQ
304
+ */
305
+ async getEntityValue(prop, data) {
306
+ const propertyType = prop['propertyType'];
307
+ const slug = prop['slug'];
308
+ const nd = data[slug];
309
+ // this.logger.log('getValue: ' + propertyType + ', ' +slug + ', ' + nd);
310
+ let value;
311
+ if (['string', 'text'].includes(propertyType)) {
312
+ value = nd;
313
+ }
314
+ else if (['number', 'currency', 'percent', 'sequence'].includes(propertyType)) {
315
+ value = (null === nd) ? 0 : nd;
316
+ }
317
+ else if ('date' === propertyType) {
318
+ if (nd) {
319
+ // const offset = new Date(nd).getTimezoneOffset() * 60 * 1_000;
320
+ // this.logger.log('nd: ' + nd);
321
+ // this.logger.log(offset);
322
+ // this.logger.log('No Offset: ' + new Date(nd).toISOString());
323
+ // const d = new Date(nd + offset);// Take system Timezone into account.
324
+ const d = new Date(nd);
325
+ value = d.toISOString();
326
+ }
327
+ else {
328
+ value = null;
329
+ }
330
+ }
331
+ else if ('boolean' === propertyType) {
332
+ value = (nd) ? true : false;
333
+ }
334
+ else if ('choice' === propertyType) {
335
+ value = this.setEnumerationKeys(prop, nd, this.useDisplayForEnumerationMatching);
336
+ }
337
+ else if ('multi_select' === propertyType) {
338
+ value = this.setEnumerationKeys(prop, nd, this.useDisplayForEnumerationMatching);
339
+ }
340
+ else if ('object_reference' === propertyType) {
341
+ value = await this.setObjectReferenceValue(prop, nd);
342
+ }
343
+ else if ('image' === propertyType) {
344
+ // console.log('TODO-image');
345
+ }
346
+ else if ('formula' === propertyType) {
347
+ // console.log('TODO-formula');
348
+ }
349
+ else if ('json' === propertyType) {
350
+ // console.log('TODO-json');
351
+ }
352
+ else if ('userList' === propertyType) {
353
+ value = await this.setUserListValue(prop, nd);
354
+ }
355
+ // console.log(value);
356
+ return value;
357
+ }
358
+ setEnumerationKeys(prop, nd, matchByDisplay) {
359
+ const propertyType = prop['propertyType'];
360
+ let value;
361
+ if (['choice', 'multi_select'].includes(propertyType)) {
362
+ //If there are no options, use empty array to not error out and don't set anything
363
+ const options = prop['options'] || [];
364
+ if ('choice' === propertyType) {
365
+ if (nd) {
366
+ const matchKey = (matchByDisplay) ? 'display' : 'value';
367
+ const option = options.find(option => option[matchKey] == nd[matchKey]);
368
+ if (option) {
369
+ value = option.value;
370
+ }
371
+ }
372
+ else {
373
+ value = undefined;
374
+ }
375
+ }
376
+ else if ('multi_select' === propertyType) {
377
+ value = [];
378
+ const matchKey = (matchByDisplay) ? 'display' : 'value';
379
+ if (nd instanceof Array) {
380
+ nd.forEach(selectedOpt => {
381
+ const optionObject = options.find(option => option[matchKey] == selectedOpt[matchKey]);
382
+ if (optionObject) {
383
+ const option = optionObject.value;
384
+ value.push(option);
385
+ }
386
+ });
387
+ }
388
+ }
389
+ }
390
+ return value;
391
+ }
392
+ /** Compares the potential changes to the entity and returns only the actual differences.
393
+ *
394
+ * @param entity the full entity
395
+ * @param changes the potential changes
396
+ * @returns only the change values that are different from the entity's value
397
+ */
398
+ getPersistableChanges(entity, changes) {
399
+ const entityCompareValues = {};
400
+ for (const key of (Object.getOwnPropertyNames(changes))) {
401
+ entityCompareValues[key] = entity[key];
402
+ }
403
+ const diffs = util_1.ObjectUtil.compareDeep(entityCompareValues, changes, '');
404
+ const diffValues = {};
405
+ if (diffs && diffs.length > 0) {
406
+ for (const diff of diffs) {
407
+ diffValues[diff.propertyName] = diff.newValue;
408
+ }
409
+ }
410
+ return diffValues;
411
+ }
412
+ /** Sets object reference value from FlexPLM data passed in
413
+ *
414
+ * @param prop the VibeIQ property
415
+ * @param nd the VibeIQ data
416
+ * @returns the object reference id from VibeIQ
417
+ */
418
+ async setObjectReferenceValue(prop, nd) {
419
+ let objectReferenceId = "";
420
+ if (!nd) {
421
+ return objectReferenceId;
422
+ }
423
+ if (this.transformMapFile) {
424
+ const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKeyFromObject(this.transformMapFile, this.mapFileUtil, nd, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
425
+ nd = await map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, nd, mapKey, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
426
+ }
427
+ const entityType = prop['referencedTypeRootSlug'];
428
+ const entityTypePath = prop['referencedTypePath'];
429
+ const entityKeys = Object.keys(nd);
430
+ const identifierKeys = await type_conversion_utils_1.TypeConversionUtils.getIdentifierPropertiesFromObject(this.transformMapFile, this.mapFileUtil, nd);
431
+ const hasAllIdentifiers = identifierKeys.every(key => entityKeys.includes(key));
432
+ if (identifierKeys.length == 0 || !hasAllIdentifiers) {
433
+ console.warn(`The inbound ${entityType} for prop '${prop['slug']}' doesnt have all "identifier" properties, so there is no processing. Identifier properties: ${identifierKeys}`);
434
+ return objectReferenceId;
435
+ }
436
+ const rootType = await this.typeUtils.getByRootAndPath({ root: entityType });
437
+ const rootTypeProps = this.typeUtils.filterTypeProperties(rootType, nd);
438
+ let rootTypeCriteria = {};
439
+ let typeCriteria = {};
440
+ identifierKeys.forEach(keyName => {
441
+ const foundInObjects = rootTypeProps.some(obj => obj.slug === keyName);
442
+ if (foundInObjects) {
443
+ rootTypeCriteria[keyName] = nd[keyName];
444
+ }
445
+ else {
446
+ typeCriteria[keyName] = nd[keyName];
447
+ }
448
+ });
449
+ const combinedCriteria = { ...rootTypeCriteria, ...typeCriteria, typePath: entityTypePath };
450
+ const cacheKey = Object.values(combinedCriteria).join('_');
451
+ if (this.objRefCache[cacheKey]) {
452
+ if (app_framework_1.Logger.isDebugOn()) {
453
+ console.debug(`object reference cache hit: ${cacheKey}`);
454
+ }
455
+ return this.objRefCache[cacheKey];
456
+ }
457
+ let arrObjectReferences = await this.getAllObjectReferences(entityType, rootTypeCriteria);
458
+ if (entityType !== entityTypePath) {
459
+ arrObjectReferences = this.checkKeysAndValues(typeCriteria, arrObjectReferences, entityTypePath);
460
+ }
461
+ if (arrObjectReferences.length) {
462
+ if (arrObjectReferences.length === 1) {
463
+ objectReferenceId = arrObjectReferences[0].id;
464
+ }
465
+ else {
466
+ console.warn(`The passed in object reference criteria has duplicate records found ${JSON.stringify(combinedCriteria)}.`);
467
+ }
468
+ }
469
+ if (!objectReferenceId) {
470
+ console.warn(`The passed in object reference criteria ${JSON.stringify(combinedCriteria)} didn't match any entities.`);
471
+ return objectReferenceId;
472
+ }
473
+ this.objRefCache[cacheKey] = objectReferenceId;
474
+ return objectReferenceId;
475
+ }
476
+ /**
477
+ * Retrieves all object references of a specified entity type based on the provided criteria.
478
+ * This function handles pagination and asynchronously fetches object references until there are no more pages.
479
+ * @param {string} entityType - The type of entity for which object references are to be retrieved.
480
+ * @param {object} rootTypeCriteria - The criteria used to filter object references.
481
+ * @returns {Promise<Array>} A Promise that resolves to an array containing all object references.
482
+ */
483
+ async getAllObjectReferences(entityType, rootTypeCriteria, postProcessCriteria = null) {
484
+ const entities = new sdk_1.Entities();
485
+ let loads = [];
486
+ let nextPageKey;
487
+ let usedV2 = false;
488
+ do {
489
+ const take = 1000;
490
+ const loadPage = await entities.get({
491
+ entityName: entityType,
492
+ criteria: rootTypeCriteria,
493
+ apiVersion: sdk_1.API_VERSION.V2,
494
+ take,
495
+ nextPageKey,
496
+ });
497
+ nextPageKey = loadPage?.nextPageKey;
498
+ if (Object.keys(loadPage).includes('results')) {
499
+ usedV2 = true;
500
+ let postProcessedResults = this.filterOutArchivedAndTrashedEntities(loadPage?.results);
501
+ if (postProcessedResults?.length > 0 && postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
502
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
503
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
504
+ }
505
+ loads.push(...postProcessedResults);
506
+ }
507
+ else {
508
+ nextPageKey = null;
509
+ }
510
+ } while (nextPageKey);
511
+ if (!usedV2) {
512
+ const take = 1000;
513
+ let skip = 0;
514
+ let done = false;
515
+ while (!done) {
516
+ const loadPage = await entities.get({
517
+ entityName: entityType,
518
+ criteria: rootTypeCriteria,
519
+ take,
520
+ skip,
521
+ });
522
+ let postProcessedResults = this.filterOutArchivedAndTrashedEntities(loadPage);
523
+ if (postProcessCriteria && Object.keys(postProcessCriteria).length !== 0) {
524
+ const subEntityTypePath = rootTypeCriteria.typePath || entityType;
525
+ postProcessedResults = this.checkKeysAndValues(postProcessCriteria, postProcessedResults, subEntityTypePath);
526
+ }
527
+ loads.push(...postProcessedResults);
528
+ if (loadPage.length !== take) {
529
+ done = true;
530
+ }
531
+ else {
532
+ skip += take;
533
+ }
534
+ }
535
+ }
536
+ return loads;
537
+ }
538
+ /**
539
+ * Checks if all keys and values of a given object are present in an array of objects.
540
+ * @param {Object} criteria - The object whose keys and values are to be checked in the array of objects.
541
+ * @param {Array<Object>} arrayOfObjects - The array of objects to be searched for matching keys and values.
542
+ * @param {string} entityTypePath - The type / subtype for the property; objects must be this type or a sub type of it.
543
+ * @returns {(Object|boolean)} Returns the array of objects that matches all keys and values of the provided object.
544
+ * If no match is found, returns empty array.
545
+ */
546
+ checkKeysAndValues(criteria, arrayOfObjects, entityTypePath) {
547
+ let arrOfMatchObjects = [];
548
+ for (let i = 0; i < arrayOfObjects.length; i++) {
549
+ const currentObj = arrayOfObjects[i];
550
+ let found = true;
551
+ if (entityTypePath && currentObj['typePath']) {
552
+ const currentObjPath = '' + currentObj['typePath'];
553
+ if (!currentObjPath.startsWith(entityTypePath)) {
554
+ found = false;
555
+ }
556
+ }
557
+ for (const key in criteria) {
558
+ if (!(key in currentObj) || currentObj[key] !== criteria[key]) {
559
+ found = false;
560
+ break;
561
+ }
562
+ }
563
+ if (found) {
564
+ arrOfMatchObjects.push(currentObj);
565
+ }
566
+ }
567
+ return arrOfMatchObjects;
568
+ }
569
+ /** Filters out archived and trashed entities from the provided array of entities.
570
+ *
571
+ * @param entities
572
+ * @returns
573
+ */
574
+ filterOutArchivedAndTrashedEntities(entities) {
575
+ if (!entities || !Array.isArray(entities) || entities.length === 0) {
576
+ return [];
577
+ }
578
+ return entities.filter(entity => {
579
+ const isArchived = entity?.isArchived;
580
+ const isTrashed = entity?.isTrashed;
581
+ return !isArchived && !isTrashed;
582
+ });
583
+ }
584
+ /** Sets userListId value from FlexPLM data passed in
585
+ *
586
+ * @param prop the VibeIQ property
587
+ * @param nd the VibeIQ data
588
+ * @returns the modified entity with FlexPLM values
589
+ */
590
+ async setUserListValue(prop, nd) {
591
+ if (!nd?.email) {
592
+ return "";
593
+ }
594
+ let cacheUser = DataConverter.getFromStaticCache(nd.email);
595
+ if (cacheUser) {
596
+ if (app_framework_1.Logger.isDebugOn()) {
597
+ console.debug('user cache hit: ' + nd.email);
598
+ }
599
+ await this.processGroupMemberCheck(prop, nd.email);
600
+ return cacheUser;
601
+ }
602
+ const user = await this.getUserByEmail(nd);
603
+ const userId = (user) ? user.id : undefined;
604
+ if (userId) {
605
+ DataConverter.setToStaticCache(nd.email, userId);
606
+ await this.processGroupMemberCheck(prop, nd.email);
607
+ }
608
+ return userId;
609
+ }
610
+ /** Makes batch calls of 1000 of user-org entities until
611
+ * it find one with userEmail of passed in nd.email.
612
+ * Maxes out after querying for 15,000 user-org entities
613
+ *
614
+ * @param nd
615
+ * @returns
616
+ */
617
+ async getUserByEmail(nd) {
618
+ let userOrg = undefined;
619
+ let count = 0;
620
+ let size = 0;
621
+ let emailInput = nd?.email.toLowerCase();
622
+ const entities = new sdk_1.Entities();
623
+ const getOptionsCriteria = {
624
+ entityName: 'user-org',
625
+ take: 1000
626
+ };
627
+ do {
628
+ const userBatch = await entities.get(getOptionsCriteria);
629
+ userOrg = userBatch.find(uo => uo?.userEmail.toLowerCase() === emailInput);
630
+ } while (!userOrg && size == getOptionsCriteria.take && count < 15);
631
+ return userOrg?.user;
632
+ }
633
+ /** Shows warning if user email address not present in group associated to property
634
+ *
635
+ * @param prop the VibeIQ property
636
+ * @param userEmail user email address
637
+ */
638
+ async processGroupMemberCheck(prop, userEmail) {
639
+ let arrUserList = [];
640
+ if (this.userRefCache[prop.typePropertyUserListId]) {
641
+ arrUserList = this.userRefCache[prop.typePropertyUserListId];
642
+ }
643
+ else {
644
+ const userListResult = await new sdk_1.Entities().get({
645
+ entityName: 'user-list',
646
+ id: prop.typePropertyUserListId
647
+ });
648
+ if (userListResult && Object.keys(userListResult).length) {
649
+ arrUserList = userListResult.userList;
650
+ this.userRefCache[prop.typePropertyUserListId] = arrUserList;
651
+ }
652
+ }
653
+ if (arrUserList.length) {
654
+ const result = arrUserList.find(element => element['display'] === userEmail);
655
+ if (!result) {
656
+ console.warn(`The passed in user ${userEmail} in property slug ${prop.slug} should be a member of the group associated with the property 'typePropertyUserListId'`);
657
+ }
658
+ }
659
+ }
660
+ /** Gets the VibeIQ value for the userList property from data
661
+ *
662
+ * @param prop the VibeIQ property
663
+ * @param newData the FlexPLM data
664
+ * @returns value to be set in VibeIQ
665
+ */
666
+ async getUserListValue(prop, newData) {
667
+ const slug = prop['slug'];
668
+ if (app_framework_1.Logger.isDebugOn()) {
669
+ console.debug('getUserListValue-prop: ' + slug);
670
+ }
671
+ const entityId = newData[slug + 'Id'];
672
+ if (!entityId) {
673
+ return {};
674
+ }
675
+ const cacheUser = DataConverter.getFromStaticCache(entityId);
676
+ if (cacheUser) {
677
+ if (app_framework_1.Logger.isDebugOn()) {
678
+ console.debug('user cache hit: ' + entityId);
679
+ }
680
+ return Object.assign({}, cacheUser);
681
+ }
682
+ const user = await this.getUserById(entityId);
683
+ const value = (user) ? {
684
+ email: user.email,
685
+ firstName: user.first,
686
+ lastName: user.last,
687
+ isSsoUser: user.isSsoUser,
688
+ } : undefined;
689
+ if (value) {
690
+ DataConverter.setToStaticCache(entityId, value);
691
+ }
692
+ return value;
693
+ }
694
+ /** Makes batch calls of 1000 of user-org entities until
695
+ * it find one with user.id of passed in userId.
696
+ * Maxes out after querying for 15,000 user-org entities
697
+ *
698
+ * @param userId
699
+ * @returns
700
+ */
701
+ async getUserById(userId) {
702
+ let userOrg = undefined;
703
+ let count = 0;
704
+ let size = 0;
705
+ const entities = new sdk_1.Entities();
706
+ const getOptionsCriteria = {
707
+ entityName: 'user-org',
708
+ take: 1000
709
+ };
710
+ do {
711
+ const userBatch = await entities.get(getOptionsCriteria);
712
+ userOrg = userBatch.find(uo => uo?.user?.id === userId);
713
+ } while (!userOrg && size == getOptionsCriteria.take && count < 15);
714
+ return userOrg?.user;
715
+ }
716
+ }
717
+ exports.DataConverter = DataConverter;
718
+ DataConverter.staticUserCache = {};