@contrail/flexplm 1.4.0 → 1.5.0-alpha.14a4f1b

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 (112) hide show
  1. package/lib/cli/commands/compile.d.ts +4 -0
  2. package/lib/cli/commands/compile.js +73 -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 +5 -0
  6. package/lib/cli/commands/create.js +77 -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 +17 -0
  10. package/lib/cli/commands/upload.js +228 -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 +5 -0
  14. package/lib/cli/index.js +70 -0
  15. package/lib/cli/index.spec.d.ts +1 -0
  16. package/lib/cli/index.spec.js +85 -0
  17. package/lib/cli/template/mapping-template.ts.template +62 -0
  18. package/lib/entity-processor/base-entity-processor.d.ts +65 -0
  19. package/lib/entity-processor/base-entity-processor.js +71 -0
  20. package/lib/entity-processor/base-entity-processor.spec.js +1 -0
  21. package/lib/index.d.ts +1 -0
  22. package/lib/index.js +1 -0
  23. package/lib/interfaces/mapping-file.d.ts +460 -0
  24. package/lib/interfaces/mapping-file.js +2 -0
  25. package/lib/publish/base-process-publish-assortment.d.ts +25 -0
  26. package/lib/publish/base-process-publish-assortment.js +60 -6
  27. package/lib/publish/base-process-publish-assortment.spec.js +22 -4
  28. package/lib/publish/mockData.js +5 -0
  29. package/lib/transform/identifier-conversion-spec-mockData.js +34 -6
  30. package/lib/transform/identifier-conversion.d.ts +36 -0
  31. package/lib/transform/identifier-conversion.js +37 -1
  32. package/lib/transform/identifier-conversion.spec.js +35 -0
  33. package/lib/util/config-defaults.d.ts +18 -0
  34. package/lib/util/config-defaults.js +25 -15
  35. package/lib/util/config-defaults.spec.js +56 -0
  36. package/lib/util/data-converter-spec-mockData.js +17 -3
  37. package/lib/util/data-converter.d.ts +102 -0
  38. package/lib/util/data-converter.js +195 -34
  39. package/lib/util/data-converter.spec.js +430 -0
  40. package/lib/util/error-response-object.d.ts +5 -0
  41. package/lib/util/error-response-object.js +7 -0
  42. package/lib/util/event-short-message-status.js +1 -0
  43. package/lib/util/federation.js +8 -0
  44. package/lib/util/flexplm-connect.d.ts +7 -0
  45. package/lib/util/flexplm-connect.js +14 -0
  46. package/lib/util/logger-config.js +1 -0
  47. package/lib/util/map-util-spec-mockData.js +17 -3
  48. package/lib/util/map-utils.d.ts +27 -0
  49. package/lib/util/map-utils.js +27 -0
  50. package/lib/util/thumbnail-util.d.ts +21 -0
  51. package/lib/util/thumbnail-util.js +28 -1
  52. package/lib/util/thumbnail-util.spec.js +6 -0
  53. package/lib/util/type-conversion-utils-spec-mockData.js +3 -3
  54. package/lib/util/type-conversion-utils.d.ts +151 -0
  55. package/lib/util/type-conversion-utils.js +154 -0
  56. package/lib/util/type-defaults.d.ts +69 -0
  57. package/lib/util/type-defaults.js +98 -4
  58. package/lib/util/type-defaults.spec.js +114 -4
  59. package/lib/util/type-utils.d.ts +21 -0
  60. package/lib/util/type-utils.js +23 -0
  61. package/lib/util/type-utils.spec.js +2 -0
  62. package/package.json +21 -6
  63. package/scripts/copy-template.js +10 -0
  64. package/.github/pull_request_template.md +0 -31
  65. package/.github/workflows/flexplm-lib.yml +0 -27
  66. package/.github/workflows/publish-to-npm.yml +0 -121
  67. package/CHANGELOG.md +0 -40
  68. package/publish.bat +0 -5
  69. package/publish.sh +0 -5
  70. package/src/entity-processor/base-entity-processor.spec.ts +0 -689
  71. package/src/entity-processor/base-entity-processor.ts +0 -583
  72. package/src/flexplm-request.ts +0 -28
  73. package/src/flexplm-utils.spec.ts +0 -27
  74. package/src/flexplm-utils.ts +0 -29
  75. package/src/index.ts +0 -22
  76. package/src/interfaces/interfaces.ts +0 -122
  77. package/src/interfaces/item-family-changes.ts +0 -67
  78. package/src/interfaces/publish-change-data.ts +0 -43
  79. package/src/publish/base-process-publish-assortment-callback.ts +0 -50
  80. package/src/publish/base-process-publish-assortment.spec.ts +0 -1992
  81. package/src/publish/base-process-publish-assortment.ts +0 -1134
  82. package/src/publish/mockData.ts +0 -4561
  83. package/src/transform/identifier-conversion-spec-mockData.ts +0 -496
  84. package/src/transform/identifier-conversion.spec.ts +0 -354
  85. package/src/transform/identifier-conversion.ts +0 -282
  86. package/src/util/config-defaults.spec.ts +0 -392
  87. package/src/util/config-defaults.ts +0 -97
  88. package/src/util/data-converter-spec-mockData.ts +0 -231
  89. package/src/util/data-converter.spec.ts +0 -1120
  90. package/src/util/data-converter.ts +0 -766
  91. package/src/util/error-response-object.spec.ts +0 -116
  92. package/src/util/error-response-object.ts +0 -50
  93. package/src/util/event-short-message-status.ts +0 -22
  94. package/src/util/federation.ts +0 -172
  95. package/src/util/flexplm-connect.spec.ts +0 -132
  96. package/src/util/flexplm-connect.ts +0 -208
  97. package/src/util/logger-config.ts +0 -20
  98. package/src/util/map-util-spec-mockData.ts +0 -231
  99. package/src/util/map-utils.spec.ts +0 -103
  100. package/src/util/map-utils.ts +0 -41
  101. package/src/util/mockData.ts +0 -101
  102. package/src/util/thumbnail-util.spec.ts +0 -508
  103. package/src/util/thumbnail-util.ts +0 -272
  104. package/src/util/type-conversion-utils-spec-mockData.ts +0 -272
  105. package/src/util/type-conversion-utils.spec.ts +0 -1031
  106. package/src/util/type-conversion-utils.ts +0 -490
  107. package/src/util/type-defaults.spec.ts +0 -669
  108. package/src/util/type-defaults.ts +0 -281
  109. package/src/util/type-utils.spec.ts +0 -227
  110. package/src/util/type-utils.ts +0 -144
  111. package/tsconfig.json +0 -24
  112. package/tslint.json +0 -57
@@ -31,12 +31,26 @@ exports.mapping = {
31
31
  }
32
32
  }
33
33
  }
34
+ // flex2vibe: {
35
+ // LCSRevisableEntity: {
36
+ // getMapKey: (object) =>{ return object;}
37
+ // },
38
+ // LCSLast: {
39
+ // getMapKey: (object) => {return object;}
40
+ // },
41
+ // LCSMaterial: {
42
+ // getMapKey: (object) =>{ return object;}
43
+ // },
44
+ // LCSBusinessObject: {
45
+ // getMapKey: (object) => {return object;}
46
+ // }
47
+ // },
34
48
  },
35
49
  LCSProduct: {
36
50
  vibeOwningKeys: ['itemNumber', 'lifecycleStage'],
37
51
  vibe2flex: {
38
52
  getClass: () => 'LCSProduct',
39
- getSoftType: (entity) => {
53
+ getSoftType: (entity /*, dependencies*/) => {
40
54
  const prodType = entity['prodType'];
41
55
  let val = '';
42
56
  switch (prodType) {
@@ -61,7 +75,7 @@ exports.mapping = {
61
75
  vibeIQIdentifier: 'itemNumber'
62
76
  },
63
77
  valueTransform: {
64
- transformEx: (row) => {
78
+ transformEx: (row /*, dependencies*/) => {
65
79
  return row['otherProp'] + 'xxx';
66
80
  }
67
81
  }
@@ -79,7 +93,7 @@ exports.mapping = {
79
93
  vibeOwningKeys: ['itemNumber', 'lifecycleStage'],
80
94
  vibe2flex: {
81
95
  getClass: () => 'LCSSKU',
82
- getSoftType: (entity) => {
96
+ getSoftType: (entity /*, dependencies*/) => {
83
97
  const prodType = entity['prodType'];
84
98
  let val = '';
85
99
  switch (prodType) {
@@ -19,21 +19,123 @@ export declare class DataConverter {
19
19
  getFlexPLMObjectDataFromEvent(event: any, dataToSkip: string[]): Promise<{}>;
20
20
  getFlexPLMObjectData(newData: any, dataToSkip: string[], inflateObjRef: boolean): Promise<{}>;
21
21
  getFlexPLMValue(prop: any, newData: any, inflateObjRef: boolean): Promise<any>;
22
+ /** Returns the display values for list properties (choice & multi_select)
23
+ *
24
+ * @param prop
25
+ * @param newData
26
+ * @returns
27
+ */
22
28
  getEnumerationValue(prop: any, nd: any): any;
23
29
  getObjectReferenceValue(prop: any, newData: any, inflateObjRef?: boolean): Promise<any>;
30
+ /** (Deprecated) Use TypeConversionUtils.getMapKey()
31
+ * Will return the class to use to get mapping.
32
+ * This is needed because mappings will be different for different sub types
33
+ * of custom-entity
34
+ *
35
+ * @param obj: Entity being checked
36
+ * @param mapping: The whole mapping file
37
+ */
24
38
  getMappingClass(entity: object, mapping: any): string;
39
+ /** Sets entity values from FlexPLM data passed in
40
+ * Assumes the entity has a VibeIQ typeId and 'roles' value to filter if necessary.
41
+ * @param entity the entity to update
42
+ * @param data the FlexPLM data
43
+ * @param keysToSkip properties to skip
44
+ * @returns the modified entity with VibeIQ values
45
+ */
25
46
  setEntityValues(entity: any, data: any, keysToSkip?: string[]): Promise<any>;
47
+ /** Gets the entity values from FlexPLM data
48
+ * Assumes there isn't a VibeIQ typeId, so uses FlexPLM data to determine type
49
+ * @param objectClass FlexPLM object class
50
+ * @param data object data
51
+ * @param keysToSkip type properties to not process
52
+ * @returns object with VibeIQ values
53
+ */
26
54
  getEntityValues(objectClass: string, data: any, keysToSkip?: string[]): Promise<{}>;
55
+ /** Gets the VibeIQ value for the property from data
56
+ *
57
+ * @param prop the VibeIQ property
58
+ * @param data the FlexPLM data
59
+ * @returns value to be set in VibeIQ
60
+ */
27
61
  getEntityValue(prop: any, data: any): Promise<any>;
28
62
  setEnumerationKeys(prop: any, nd: any, matchByDisplay: any): any;
63
+ /** Compares the potential changes to the entity and returns only the actual differences.
64
+ *
65
+ * @param entity the full entity
66
+ * @param changes the potential changes
67
+ * @returns only the change values that are different from the entity's value
68
+ */
29
69
  getPersistableChanges(entity: object, changes: object): object;
70
+ /** Sets object reference value from FlexPLM data passed in
71
+ *
72
+ * @param prop the VibeIQ property
73
+ * @param nd the VibeIQ data
74
+ * @returns the object reference id from VibeIQ
75
+ */
30
76
  setObjectReferenceValue(prop: any, nd: any): Promise<any>;
77
+ private applyInboundTransformMap;
78
+ private buildObjectReferenceContext;
79
+ private lookupObjectReferenceViaIdentityService;
80
+ private lookupObjectReferenceViaQuery;
81
+ private pickSingleResult;
82
+ /**
83
+ * Retrieves all object references of a specified entity type based on the provided criteria.
84
+ * This function handles pagination and asynchronously fetches object references until there are no more pages.
85
+ * @param {string} entityType - The type of entity for which object references are to be retrieved.
86
+ * @param {object} rootTypeCriteria - The criteria used to filter object references.
87
+ * @returns {Promise<Array>} A Promise that resolves to an array containing all object references.
88
+ */
31
89
  getAllObjectReferences(entityType: string, rootTypeCriteria: any, postProcessCriteria?: any): Promise<any[]>;
90
+ /**
91
+ * Checks if all keys and values of a given object are present in an array of objects.
92
+ * @param {Object} criteria - The object whose keys and values are to be checked in the array of objects.
93
+ * @param {Array<Object>} arrayOfObjects - The array of objects to be searched for matching keys and values.
94
+ * @param {string} entityTypePath - The type / subtype for the property; objects must be this type or a sub type of it.
95
+ * @returns {(Object|boolean)} Returns the array of objects that matches all keys and values of the provided object.
96
+ * If no match is found, returns empty array.
97
+ */
32
98
  checkKeysAndValues(criteria: any, arrayOfObjects: any, entityTypePath: any): any[];
99
+ /** Filters out archived and trashed entities from the provided array of entities.
100
+ *
101
+ * @param entities
102
+ * @returns
103
+ */
33
104
  filterOutArchivedAndTrashedEntities(entities: any[]): any[];
105
+ /** Sets userListId value from FlexPLM data passed in
106
+ *
107
+ * @param prop the VibeIQ property
108
+ * @param nd the VibeIQ data
109
+ * @returns the modified entity with FlexPLM values
110
+ */
34
111
  setUserListValue(prop: any, nd: any): Promise<any>;
112
+ /** Makes batch calls of 1000 of user-org entities until
113
+ * it find one with userEmail of passed in nd.email.
114
+ * Maxes out after querying for 15,000 user-org entities
115
+ *
116
+ * @param nd
117
+ * @returns
118
+ */
35
119
  getUserByEmail(nd: any): Promise<any>;
120
+ /** Shows warning if user email address not present in group associated to property
121
+ *
122
+ * @param prop the VibeIQ property
123
+ * @param userEmail user email address
124
+ */
36
125
  processGroupMemberCheck(prop: any, userEmail: any): Promise<void>;
126
+ /** Gets the VibeIQ value for the userList property from data
127
+ *
128
+ * @param prop the VibeIQ property
129
+ * @param newData the FlexPLM data
130
+ * @returns value to be set in VibeIQ
131
+ */
37
132
  getUserListValue(prop: any, newData: any): Promise<any>;
133
+ /** Makes batch calls of 1000 of user-org entities until
134
+ * it find one with user.id of passed in userId.
135
+ * Maxes out after querying for 15,000 user-org entities
136
+ *
137
+ * @param userId
138
+ * @returns
139
+ */
38
140
  getUserById(userId: any): Promise<any>;
39
141
  }
@@ -7,6 +7,7 @@ const app_framework_1 = require("@contrail/app-framework");
7
7
  const util_1 = require("@contrail/util");
8
8
  const type_conversion_utils_1 = require("./type-conversion-utils");
9
9
  const map_utils_1 = require("./map-utils");
10
+ const config_defaults_1 = require("./config-defaults");
10
11
  class DataConverter {
11
12
  static clearStaticUserCache() {
12
13
  DataConverter.staticUserCache = {};
@@ -44,16 +45,22 @@ class DataConverter {
44
45
  if (this.isVerboseDebugOn()) {
45
46
  console.debug('newData: ' + JSON.stringify(newData));
46
47
  }
48
+ //Using event to get propertyDiffs to find emptied values
49
+ //Add standard atts to skip
47
50
  dataToSkip = dataToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'workspaceId']);
51
+ // const oldData = event.oldData;
48
52
  const data = {};
49
53
  const typeId = newData?.typeId;
50
54
  if (!typeId) {
51
- return;
55
+ return; // Don't have a type; so can't process
52
56
  }
53
57
  data['typePath'] = newData['typePath'];
54
58
  const type = await this.typeUtils.getTypeById(typeId);
55
59
  const typeProps = this.typeUtils.filterTypeProperties(type, newData);
56
60
  for (const prop of typeProps) {
61
+ // if(this.logger.isTraceOn()){
62
+ // this.logger.log('prop: ' + JSON.stringify(prop));
63
+ // }
57
64
  const slug = prop['slug'];
58
65
  if (dataToSkip.includes(slug)) {
59
66
  continue;
@@ -69,6 +76,7 @@ class DataConverter {
69
76
  const propertyType = prop['propertyType'];
70
77
  const slug = prop['slug'];
71
78
  const nd = newData[slug];
79
+ // console.log('getFlexPLMValue: ' + propertyType + ', ' +slug + ', ' + nd + ', ' + od);
72
80
  let value;
73
81
  if (['string', 'text'].includes(propertyType)) {
74
82
  value = nd || '';
@@ -79,6 +87,10 @@ class DataConverter {
79
87
  else if ('date' === propertyType) {
80
88
  if (nd) {
81
89
  value = nd;
90
+ // const d = new Date(nd);
91
+ // console.log('Date.getTimezoneOffset(): ' + d.getTimezoneOffset());
92
+ // value = d.toISOString();
93
+ // console.log('date: ' + nd + ' -- ' + value);
82
94
  }
83
95
  else {
84
96
  value = null;
@@ -100,11 +112,13 @@ class DataConverter {
100
112
  }
101
113
  }
102
114
  else if ('image' === propertyType) {
115
+ // console.log('image-TODO');
103
116
  }
104
117
  else if ('formula' === propertyType) {
105
118
  value = nd;
106
119
  }
107
120
  else if ('json' === propertyType) {
121
+ // console.log('json-TODO');
108
122
  value = nd;
109
123
  }
110
124
  else if ('userList' === propertyType) {
@@ -115,6 +129,12 @@ class DataConverter {
115
129
  }
116
130
  return value;
117
131
  }
132
+ /** Returns the display values for list properties (choice & multi_select)
133
+ *
134
+ * @param prop
135
+ * @param newData
136
+ * @returns
137
+ */
118
138
  getEnumerationValue(prop, nd) {
119
139
  const propertyType = prop['propertyType'];
120
140
  let value;
@@ -198,6 +218,14 @@ class DataConverter {
198
218
  this.objRefCache[entityId] = value;
199
219
  return value;
200
220
  }
221
+ /** (Deprecated) Use TypeConversionUtils.getMapKey()
222
+ * Will return the class to use to get mapping.
223
+ * This is needed because mappings will be different for different sub types
224
+ * of custom-entity
225
+ *
226
+ * @param obj: Entity being checked
227
+ * @param mapping: The whole mapping file
228
+ */
201
229
  getMappingClass(entity, mapping) {
202
230
  const entityTypePath = entity['typePath'];
203
231
  const typeMapKey = mapping['typeMapKey'];
@@ -211,11 +239,22 @@ class DataConverter {
211
239
  }
212
240
  return objClass;
213
241
  }
242
+ /** Sets entity values from FlexPLM data passed in
243
+ * Assumes the entity has a VibeIQ typeId and 'roles' value to filter if necessary.
244
+ * @param entity the entity to update
245
+ * @param data the FlexPLM data
246
+ * @param keysToSkip properties to skip
247
+ * @returns the modified entity with VibeIQ values
248
+ */
214
249
  async setEntityValues(entity, data, keysToSkip = []) {
250
+ // this.logger.log('setEntityValues: ' + JSON.stringify(entity));
251
+ // this.logger.log('data: ' + JSON.stringify(data));
215
252
  const type = await this.typeUtils.getTypeById(entity.typeId);
216
253
  keysToSkip = keysToSkip.concat(['updatedOn', 'updatedById', 'createdOn', 'createdById', 'modifiedAt', 'orgId', 'createdAt', 'id', 'typeId', 'typePath', 'workspaceId']);
217
254
  let typeProps = this.typeUtils.filterTypeProperties(type, entity);
218
255
  typeProps = typeProps.filter(prop => !keysToSkip.includes(prop['slug']));
256
+ //Only process properties that had a value sent; to not accidentally clear out values
257
+ //for properties that weren't sent.
219
258
  const dataKeys = Object.getOwnPropertyNames(data);
220
259
  typeProps = typeProps.filter(prop => dataKeys.includes(prop['slug']));
221
260
  for (const prop of typeProps) {
@@ -226,16 +265,24 @@ class DataConverter {
226
265
  keyName = slug + 'Id';
227
266
  }
228
267
  entity[keyName] = await this.getEntityValue(prop, data);
268
+ // console.log('entity[slug]: ' + entity[slug]);
229
269
  }
230
270
  return entity;
231
271
  }
272
+ /** Gets the entity values from FlexPLM data
273
+ * Assumes there isn't a VibeIQ typeId, so uses FlexPLM data to determine type
274
+ * @param objectClass FlexPLM object class
275
+ * @param data object data
276
+ * @param keysToSkip type properties to not process
277
+ * @returns object with VibeIQ values
278
+ */
232
279
  async getEntityValues(objectClass, data, keysToSkip = []) {
233
280
  const entityValues = {};
234
281
  const tco = await this.typeUtils.getEntityTypeClientOptionsUsingMapping(this.transformMapFile, this.mapFileUtil, data);
235
282
  const type = await this.typeUtils.getByRootAndPath(tco);
236
283
  const typePath = type['typePath'];
237
284
  if (typePath && (typePath.startsWith('item') || typePath.startsWith('project-item'))) {
238
- if (['LCSProduct', 'LCSProductSeasonLink'].includes(objectClass)) {
285
+ if (['LCSProduct', 'LCSProductSeasonLink', 'LCSMaterial'].includes(objectClass)) {
239
286
  entityValues['roles'] = ['family'];
240
287
  }
241
288
  else {
@@ -253,10 +300,17 @@ class DataConverter {
253
300
  }
254
301
  return entityValues;
255
302
  }
303
+ /** Gets the VibeIQ value for the property from data
304
+ *
305
+ * @param prop the VibeIQ property
306
+ * @param data the FlexPLM data
307
+ * @returns value to be set in VibeIQ
308
+ */
256
309
  async getEntityValue(prop, data) {
257
310
  const propertyType = prop['propertyType'];
258
311
  const slug = prop['slug'];
259
312
  const nd = data[slug];
313
+ // this.logger.log('getValue: ' + propertyType + ', ' +slug + ', ' + nd);
260
314
  let value;
261
315
  if (['string', 'text'].includes(propertyType)) {
262
316
  value = nd;
@@ -266,6 +320,11 @@ class DataConverter {
266
320
  }
267
321
  else if ('date' === propertyType) {
268
322
  if (nd) {
323
+ // const offset = new Date(nd).getTimezoneOffset() * 60 * 1_000;
324
+ // this.logger.log('nd: ' + nd);
325
+ // this.logger.log(offset);
326
+ // this.logger.log('No Offset: ' + new Date(nd).toISOString());
327
+ // const d = new Date(nd + offset);// Take system Timezone into account.
269
328
  const d = new Date(nd);
270
329
  value = d.toISOString();
271
330
  }
@@ -286,10 +345,13 @@ class DataConverter {
286
345
  value = await this.setObjectReferenceValue(prop, nd);
287
346
  }
288
347
  else if ('image' === propertyType) {
348
+ // console.log('TODO-image');
289
349
  }
290
350
  else if ('formula' === propertyType) {
351
+ // console.log('TODO-formula');
291
352
  }
292
353
  else if ('json' === propertyType) {
354
+ // console.log('TODO-json');
293
355
  }
294
356
  else if ('userList' === propertyType) {
295
357
  value = await this.setUserListValue(prop, nd);
@@ -297,12 +359,14 @@ class DataConverter {
297
359
  else if ('size_range' === propertyType) {
298
360
  value = nd;
299
361
  }
362
+ // console.log(value);
300
363
  return value;
301
364
  }
302
365
  setEnumerationKeys(prop, nd, matchByDisplay) {
303
366
  const propertyType = prop['propertyType'];
304
367
  let value;
305
368
  if (['choice', 'multi_select'].includes(propertyType)) {
369
+ //If there are no options, use empty array to not error out and don't set anything
306
370
  const options = prop['options'] || [];
307
371
  if ('choice' === propertyType) {
308
372
  if (nd) {
@@ -332,6 +396,12 @@ class DataConverter {
332
396
  }
333
397
  return value;
334
398
  }
399
+ /** Compares the potential changes to the entity and returns only the actual differences.
400
+ *
401
+ * @param entity the full entity
402
+ * @param changes the potential changes
403
+ * @returns only the change values that are different from the entity's value
404
+ */
335
405
  getPersistableChanges(entity, changes) {
336
406
  const entityCompareValues = {};
337
407
  for (const key of (Object.getOwnPropertyNames(changes))) {
@@ -346,31 +416,58 @@ class DataConverter {
346
416
  }
347
417
  return diffValues;
348
418
  }
419
+ /** Sets object reference value from FlexPLM data passed in
420
+ *
421
+ * @param prop the VibeIQ property
422
+ * @param nd the VibeIQ data
423
+ * @returns the object reference id from VibeIQ
424
+ */
349
425
  async setObjectReferenceValue(prop, nd) {
350
- let objectReferenceId = "";
351
426
  if (!nd) {
352
- return objectReferenceId;
427
+ return "";
428
+ }
429
+ nd = await this.applyInboundTransformMap(nd);
430
+ const ctx = await this.buildObjectReferenceContext(prop, nd);
431
+ if (!ctx) {
432
+ return "";
433
+ }
434
+ if (this.objRefCache[ctx.cacheKey]) {
435
+ if (app_framework_1.Logger.isDebugOn()) {
436
+ console.debug(`object reference cache hit: ${ctx.cacheKey}`);
437
+ }
438
+ return this.objRefCache[ctx.cacheKey];
353
439
  }
354
- if (this.transformMapFile) {
355
- const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKeyFromObject(this.transformMapFile, this.mapFileUtil, nd, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
356
- nd = await map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, nd, mapKey, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
440
+ const objectReferenceId = ctx.useIdentityService
441
+ ? await this.lookupObjectReferenceViaIdentityService(ctx, nd)
442
+ : await this.lookupObjectReferenceViaQuery(ctx);
443
+ if (objectReferenceId) {
444
+ this.objRefCache[ctx.cacheKey] = objectReferenceId;
357
445
  }
446
+ return objectReferenceId;
447
+ }
448
+ async applyInboundTransformMap(nd) {
449
+ if (!this.transformMapFile) {
450
+ return nd;
451
+ }
452
+ const mapKey = await type_conversion_utils_1.TypeConversionUtils.getMapKeyFromObject(this.transformMapFile, this.mapFileUtil, nd, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
453
+ return map_utils_1.MapUtil.applyTransformMap(this.transformMapFile, this.mapFileUtil, nd, mapKey, type_conversion_utils_1.TypeConversionUtils.FLEX2VIBE_DIRECTION);
454
+ }
455
+ async buildObjectReferenceContext(prop, nd) {
358
456
  const entityType = prop['referencedTypeRootSlug'];
359
457
  const entityTypePath = prop['referencedTypePath'];
360
458
  const entityKeys = Object.keys(nd);
361
459
  const identifierKeys = await type_conversion_utils_1.TypeConversionUtils.getIdentifierPropertiesFromObject(this.transformMapFile, this.mapFileUtil, nd);
362
460
  const hasAllIdentifiers = identifierKeys.every(key => entityKeys.includes(key));
363
- if (identifierKeys.length == 0 || !hasAllIdentifiers) {
461
+ if (identifierKeys.length === 0 || !hasAllIdentifiers) {
364
462
  console.warn(`The inbound ${entityType} for prop '${prop['slug']}' doesnt have all "identifier" properties, so there is no processing. Identifier properties: ${identifierKeys}`);
365
- return objectReferenceId;
463
+ return null;
366
464
  }
367
465
  const rootType = await this.typeUtils.getByRootAndPath({ root: entityType });
368
466
  const rootTypeProps = this.typeUtils.filterTypeProperties(rootType, nd);
369
- let rootTypeCriteria = {};
370
- let typeCriteria = {};
467
+ const rootTypeCriteria = {};
468
+ const typeCriteria = {};
371
469
  identifierKeys.forEach(keyName => {
372
- const foundInObjects = rootTypeProps.some(obj => obj.slug === keyName);
373
- if (foundInObjects) {
470
+ if (rootTypeProps.some(obj => obj.slug === keyName)) {
374
471
  rootTypeCriteria[keyName] = nd[keyName];
375
472
  }
376
473
  else {
@@ -379,31 +476,51 @@ class DataConverter {
379
476
  });
380
477
  const combinedCriteria = { ...rootTypeCriteria, ...typeCriteria, typePath: entityTypePath };
381
478
  const cacheKey = Object.values(combinedCriteria).join('_');
382
- if (this.objRefCache[cacheKey]) {
383
- if (app_framework_1.Logger.isDebugOn()) {
384
- console.debug(`object reference cache hit: ${cacheKey}`);
385
- }
386
- return this.objRefCache[cacheKey];
387
- }
388
- let arrObjectReferences = await this.getAllObjectReferences(entityType, rootTypeCriteria);
389
- if (entityType !== entityTypePath) {
390
- arrObjectReferences = this.checkKeysAndValues(typeCriteria, arrObjectReferences, entityTypePath);
391
- }
392
- if (arrObjectReferences.length) {
393
- if (arrObjectReferences.length === 1) {
394
- objectReferenceId = arrObjectReferences[0].id;
395
- }
396
- else {
397
- console.warn(`The passed in object reference criteria has duplicate records found ${JSON.stringify(combinedCriteria)}.`);
398
- }
479
+ const rolesIsTypeDiscriminator = entityType === 'item' || entityType === 'project-item';
480
+ const identityLookupKeys = rolesIsTypeDiscriminator
481
+ ? identifierKeys.filter(key => key !== 'roles')
482
+ : identifierKeys;
483
+ const useIdentityService = config_defaults_1.ConfigDefaults.isPropertyTrue(this.config?.search?.[entityType]?.useIdentityServiceForInboundData)
484
+ && identityLookupKeys.length === 1;
485
+ return { entityType, entityTypePath, rootTypeCriteria, typeCriteria, combinedCriteria, cacheKey, useIdentityService, identityLookupKeys };
486
+ }
487
+ async lookupObjectReferenceViaIdentityService(ctx, nd) {
488
+ const propertyName = ctx.identityLookupKeys[0];
489
+ const propertyValue = nd[propertyName];
490
+ const poolKey = await type_conversion_utils_1.TypeConversionUtils.getUniquenessPoolKeyFromObject(this.transformMapFile, this.mapFileUtil, nd);
491
+ const identityResults = await new sdk_1.Entities().get({
492
+ entityName: 'identity',
493
+ criteria: { poolKey, propertyName, propertyValue }
494
+ }) ?? [];
495
+ const match = this.pickSingleResult(identityResults, ctx.combinedCriteria);
496
+ return match ? match.entityReference.split(':')[1] : "";
497
+ }
498
+ async lookupObjectReferenceViaQuery(ctx) {
499
+ let arrObjectReferences = await this.getAllObjectReferences(ctx.entityType, ctx.rootTypeCriteria);
500
+ if (ctx.entityType !== ctx.entityTypePath) {
501
+ arrObjectReferences = this.checkKeysAndValues(ctx.typeCriteria, arrObjectReferences, ctx.entityTypePath);
399
502
  }
400
- if (!objectReferenceId) {
503
+ const match = this.pickSingleResult(arrObjectReferences, ctx.combinedCriteria);
504
+ return match ? match.id : "";
505
+ }
506
+ pickSingleResult(results, combinedCriteria) {
507
+ if (!results.length) {
401
508
  console.warn(`The passed in object reference criteria ${JSON.stringify(combinedCriteria)} didn't match any entities.`);
402
- return objectReferenceId;
509
+ return undefined;
403
510
  }
404
- this.objRefCache[cacheKey] = objectReferenceId;
405
- return objectReferenceId;
511
+ if (results.length > 1) {
512
+ console.warn(`The passed in object reference criteria has duplicate records found ${JSON.stringify(combinedCriteria)}.`);
513
+ return undefined;
514
+ }
515
+ return results[0];
406
516
  }
517
+ /**
518
+ * Retrieves all object references of a specified entity type based on the provided criteria.
519
+ * This function handles pagination and asynchronously fetches object references until there are no more pages.
520
+ * @param {string} entityType - The type of entity for which object references are to be retrieved.
521
+ * @param {object} rootTypeCriteria - The criteria used to filter object references.
522
+ * @returns {Promise<Array>} A Promise that resolves to an array containing all object references.
523
+ */
407
524
  async getAllObjectReferences(entityType, rootTypeCriteria, postProcessCriteria = null) {
408
525
  const entities = new sdk_1.Entities();
409
526
  let loads = [];
@@ -459,6 +576,14 @@ class DataConverter {
459
576
  }
460
577
  return loads;
461
578
  }
579
+ /**
580
+ * Checks if all keys and values of a given object are present in an array of objects.
581
+ * @param {Object} criteria - The object whose keys and values are to be checked in the array of objects.
582
+ * @param {Array<Object>} arrayOfObjects - The array of objects to be searched for matching keys and values.
583
+ * @param {string} entityTypePath - The type / subtype for the property; objects must be this type or a sub type of it.
584
+ * @returns {(Object|boolean)} Returns the array of objects that matches all keys and values of the provided object.
585
+ * If no match is found, returns empty array.
586
+ */
462
587
  checkKeysAndValues(criteria, arrayOfObjects, entityTypePath) {
463
588
  let arrOfMatchObjects = [];
464
589
  for (let i = 0; i < arrayOfObjects.length; i++) {
@@ -482,6 +607,11 @@ class DataConverter {
482
607
  }
483
608
  return arrOfMatchObjects;
484
609
  }
610
+ /** Filters out archived and trashed entities from the provided array of entities.
611
+ *
612
+ * @param entities
613
+ * @returns
614
+ */
485
615
  filterOutArchivedAndTrashedEntities(entities) {
486
616
  if (!entities || !Array.isArray(entities) || entities.length === 0) {
487
617
  return [];
@@ -492,6 +622,12 @@ class DataConverter {
492
622
  return !isArchived && !isTrashed;
493
623
  });
494
624
  }
625
+ /** Sets userListId value from FlexPLM data passed in
626
+ *
627
+ * @param prop the VibeIQ property
628
+ * @param nd the VibeIQ data
629
+ * @returns the modified entity with FlexPLM values
630
+ */
495
631
  async setUserListValue(prop, nd) {
496
632
  if (!nd?.email) {
497
633
  return "";
@@ -512,6 +648,13 @@ class DataConverter {
512
648
  }
513
649
  return userId;
514
650
  }
651
+ /** Makes batch calls of 1000 of user-org entities until
652
+ * it find one with userEmail of passed in nd.email.
653
+ * Maxes out after querying for 15,000 user-org entities
654
+ *
655
+ * @param nd
656
+ * @returns
657
+ */
515
658
  async getUserByEmail(nd) {
516
659
  let userOrg = undefined;
517
660
  let count = 0;
@@ -528,6 +671,11 @@ class DataConverter {
528
671
  } while (!userOrg && size == getOptionsCriteria.take && count < 15);
529
672
  return userOrg?.user;
530
673
  }
674
+ /** Shows warning if user email address not present in group associated to property
675
+ *
676
+ * @param prop the VibeIQ property
677
+ * @param userEmail user email address
678
+ */
531
679
  async processGroupMemberCheck(prop, userEmail) {
532
680
  let arrUserList = [];
533
681
  if (this.userRefCache[prop.typePropertyUserListId]) {
@@ -550,6 +698,12 @@ class DataConverter {
550
698
  }
551
699
  }
552
700
  }
701
+ /** Gets the VibeIQ value for the userList property from data
702
+ *
703
+ * @param prop the VibeIQ property
704
+ * @param newData the FlexPLM data
705
+ * @returns value to be set in VibeIQ
706
+ */
553
707
  async getUserListValue(prop, newData) {
554
708
  const slug = prop['slug'];
555
709
  if (app_framework_1.Logger.isDebugOn()) {
@@ -578,6 +732,13 @@ class DataConverter {
578
732
  }
579
733
  return value;
580
734
  }
735
+ /** Makes batch calls of 1000 of user-org entities until
736
+ * it find one with user.id of passed in userId.
737
+ * Maxes out after querying for 15,000 user-org entities
738
+ *
739
+ * @param userId
740
+ * @returns
741
+ */
581
742
  async getUserById(userId) {
582
743
  let userOrg = undefined;
583
744
  let count = 0;