@contrail/flexplm 1.1.12 → 1.1.14

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 (67) hide show
  1. package/.github/pull_request_template.md +30 -0
  2. package/.github/workflows/flexplm-lib.yml +27 -0
  3. package/lib/flexplm-utils.spec.d.ts +1 -0
  4. package/lib/flexplm-utils.spec.js +26 -0
  5. package/lib/publish/base-process-publish-assortment.js +2 -4
  6. package/lib/publish/base-process-publish-assortment.spec.d.ts +1 -0
  7. package/lib/publish/base-process-publish-assortment.spec.js +1053 -0
  8. package/lib/util/config-defaults.spec.d.ts +1 -0
  9. package/lib/util/config-defaults.spec.js +264 -0
  10. package/lib/util/data-converter.spec.d.ts +1 -0
  11. package/lib/util/data-converter.spec.js +591 -0
  12. package/lib/util/map-utils.d.ts +2 -2
  13. package/lib/util/map-utils.js +5 -28
  14. package/lib/util/map-utils.spec.d.ts +1 -0
  15. package/lib/util/map-utils.spec.js +89 -0
  16. package/lib/util/thumbnail-util.spec.d.ts +1 -0
  17. package/lib/util/thumbnail-util.spec.js +132 -0
  18. package/lib/util/type-conversion-utils-spec-mockData.js +21 -0
  19. package/lib/util/type-conversion-utils.d.ts +7 -0
  20. package/lib/util/type-conversion-utils.js +88 -4
  21. package/lib/util/type-conversion-utils.spec.d.ts +1 -0
  22. package/lib/util/type-conversion-utils.spec.js +547 -0
  23. package/lib/util/type-defaults.d.ts +5 -0
  24. package/lib/util/type-defaults.js +66 -0
  25. package/lib/util/type-defaults.spec.d.ts +1 -0
  26. package/lib/util/type-defaults.spec.js +460 -0
  27. package/lib/util/type-utils.spec.d.ts +1 -0
  28. package/lib/util/type-utils.spec.js +190 -0
  29. package/package.json +2 -2
  30. package/publish.bat +5 -0
  31. package/publish.sh +5 -0
  32. package/src/entity-processor/base-entity-processor.ts +183 -0
  33. package/src/flexplm-request.ts +28 -0
  34. package/src/flexplm-utils.spec.ts +27 -0
  35. package/src/flexplm-utils.ts +29 -0
  36. package/src/index.ts +20 -0
  37. package/src/interfaces/interfaces.ts +120 -0
  38. package/src/interfaces/item-family-changes.ts +67 -0
  39. package/src/interfaces/publish-change-data.ts +43 -0
  40. package/src/publish/base-process-publish-assortment-callback.ts +23 -0
  41. package/src/publish/base-process-publish-assortment.spec.ts +1239 -0
  42. package/src/publish/base-process-publish-assortment.ts +1024 -0
  43. package/src/publish/mockData.ts +4561 -0
  44. package/src/transform/identifier-conversion.ts +226 -0
  45. package/src/util/config-defaults.spec.ts +315 -0
  46. package/src/util/config-defaults.ts +79 -0
  47. package/src/util/data-converter-spec-mockData.ts +231 -0
  48. package/src/util/data-converter.spec.ts +872 -0
  49. package/src/util/data-converter.ts +389 -0
  50. package/src/util/federation.ts +172 -0
  51. package/src/util/flexplm-connect.ts +169 -0
  52. package/src/util/logger-config.ts +20 -0
  53. package/src/util/map-util-spec-mockData.ts +231 -0
  54. package/src/util/map-utils.spec.ts +103 -0
  55. package/src/util/map-utils.ts +40 -0
  56. package/src/util/mockData.ts +98 -0
  57. package/src/util/thumbnail-util.spec.ts +152 -0
  58. package/src/util/thumbnail-util.ts +128 -0
  59. package/src/util/type-conversion-utils-spec-mockData.ts +238 -0
  60. package/src/util/type-conversion-utils.spec.ts +601 -0
  61. package/src/util/type-conversion-utils.ts +345 -0
  62. package/src/util/type-defaults.spec.ts +592 -0
  63. package/src/util/type-defaults.ts +261 -0
  64. package/src/util/type-utils.spec.ts +227 -0
  65. package/src/util/type-utils.ts +124 -0
  66. package/tsconfig.json +27 -0
  67. package/tslint.json +57 -0
@@ -0,0 +1,226 @@
1
+ import { MapFileUtil } from "@contrail/transform-data";
2
+ import { ProductFederation, SeasonFederation, SeasonGroupFederation, SkuFederation } from "../interfaces/interfaces";
3
+ import { MapUtil } from "../util/map-utils";
4
+ import { TypeConversionUtils } from "../util/type-conversion-utils";
5
+ import { DataConverter } from "../util/data-converter";
6
+
7
+ export class IdentifierConversion {
8
+
9
+ /** Takes in an assortment and returns an object to query for an LCSSeason
10
+ * This will only return the identifier properties, and information properties if specified.
11
+ * @param transformMapFile
12
+ * @param mapFileUtil
13
+ * @param dc
14
+ * @param assortment
15
+ * @param includeInformationKeys defaults true
16
+ * @returns
17
+ */
18
+ static async getSeasonIdentityObject(transformMapFile: string, mapFileUtil: MapFileUtil, dc: DataConverter, assortment, includeInformationKeys = true): Promise<SeasonFederation>{
19
+ if(!assortment){
20
+ throw new Error('IdentifierConversion.getSeasonIdentityObject(): assortment must be provided.');
21
+ }
22
+ assortment['flex2vibeMapKeyRoot'] = 'LCSSeason';
23
+ const flexPLMTypePath = await TypeConversionUtils.getObjectTypePath(transformMapFile, mapFileUtil, assortment);
24
+
25
+ let seasonObj: any = {
26
+ entityReference: 'assortment:' + assortment?.id,
27
+ objectClass: 'LCSSeason' as const,
28
+ flexPLMTypePath
29
+ };
30
+
31
+ try{
32
+ const assortmentObj = await dc.getFlexPLMObjectData(assortment, [], true);
33
+ const identifierKeys: string[] = await TypeConversionUtils.getIdentifierProperties(transformMapFile, mapFileUtil, assortment);
34
+ for(const key of identifierKeys){
35
+ if(assortmentObj[key]){
36
+ seasonObj[key] = assortmentObj[key];
37
+ }
38
+ }
39
+ if(includeInformationKeys){
40
+ const informationKeys: string[] = await TypeConversionUtils
41
+ .getInformationalProperties(transformMapFile, mapFileUtil, assortment);
42
+ for(const key of informationKeys){
43
+ if(assortmentObj[key]){
44
+ seasonObj[key] = assortmentObj[key];
45
+ }
46
+ }
47
+ }
48
+
49
+ const objectKeys = Object.keys(seasonObj);
50
+ const hasAllIdentifiers = identifierKeys.every(key => objectKeys.includes(key));
51
+ if(!hasAllIdentifiers){
52
+ console.error('IdentifierConversion.getSeasonIdentityObject(): doesnt have all identifier properties - '+ identifierKeys);
53
+ console.error('assortment: ' + JSON.stringify(assortment));
54
+ }
55
+
56
+ const mapKey:string = await TypeConversionUtils
57
+ .getMapKey(transformMapFile, mapFileUtil, assortment, TypeConversionUtils.VIBE2FLEX_DIRECTION);
58
+ seasonObj = await MapUtil
59
+ .applyTransformMap(transformMapFile, mapFileUtil, seasonObj, mapKey, TypeConversionUtils.VIBE2FLEX_DIRECTION);
60
+ } finally {
61
+ delete assortment['flex2vibeMapKeyRoot'];
62
+ }
63
+
64
+ return seasonObj as SeasonFederation;
65
+ }
66
+
67
+ /** Takes in an assortment and returns an object to query for an SeasonGroup
68
+ * This will only return the identifier properties, and information properties if specified.
69
+ * @param transformMapFile
70
+ * @param mapFileUtil
71
+ * @param dc
72
+ * @param assortment
73
+ * @param includeInformationKeys defaults true
74
+ * @returns
75
+ */
76
+ static async getSeasonGroupIdentityObject(transformMapFile: string, mapFileUtil: MapFileUtil, dc: DataConverter, assortment, includeInformationKeys = true): Promise<SeasonGroupFederation> {
77
+ if(!assortment){
78
+ throw new Error('IdentifierConversion.getSeasonGroupIdentityObject(): assortment must be provided.');
79
+ }
80
+ assortment['flex2vibeMapKeyRoot'] = 'SeasonGroup';
81
+ const flexPLMTypePath = await TypeConversionUtils.getObjectTypePath(transformMapFile, mapFileUtil, assortment);
82
+
83
+ let seasonGroupObj = {
84
+ entityReference: 'assortment:' + assortment?.id,
85
+ objectClass: 'SeasonGroup' as const,
86
+ flexPLMTypePath
87
+ };
88
+
89
+ try {
90
+ const assortmentObj = await dc.getFlexPLMObjectData(assortment, [], true);
91
+
92
+ const identifierKeys: string[] = await TypeConversionUtils
93
+ .getIdentifierProperties(transformMapFile, mapFileUtil, assortment);
94
+ for (const key of identifierKeys) {
95
+ if (assortmentObj[key]) {
96
+ seasonGroupObj[key] = assortmentObj[key];
97
+ }
98
+ }
99
+
100
+ if(includeInformationKeys){
101
+ const informationKeys: string[] = await TypeConversionUtils
102
+ .getInformationalProperties(transformMapFile, mapFileUtil, assortment);
103
+ for (const key of informationKeys) {
104
+ if (assortmentObj[key]) {
105
+ seasonGroupObj[key] = assortmentObj[key];
106
+ }
107
+ }
108
+
109
+ }
110
+ const objectKeys = Object.keys(seasonGroupObj);
111
+ const hasAllIdentifiers = identifierKeys.every(key => objectKeys.includes(key));
112
+
113
+ if (!hasAllIdentifiers) {
114
+ console.error('IdentifierConversion.getSeasonGroupIdentityObject(): doesnt have all identifier properties - '+ identifierKeys);
115
+ console.error('assortment: ' + JSON.stringify(assortment));
116
+ }
117
+
118
+ const mapKey: string = await TypeConversionUtils.getMapKey(transformMapFile, mapFileUtil, assortment, TypeConversionUtils.VIBE2FLEX_DIRECTION);
119
+ seasonGroupObj = await MapUtil.applyTransformMap(transformMapFile, mapFileUtil, seasonGroupObj, mapKey, TypeConversionUtils.VIBE2FLEX_DIRECTION);
120
+
121
+ } finally {
122
+ delete assortment['flex2vibeMapKeyRoot'];
123
+ }
124
+ return seasonGroupObj;
125
+ }
126
+
127
+ /** Takes in an item and returns an object to query for an LCSProduct
128
+ * This will only return the identifier properties, and information properties if specified.
129
+ * @param transformMapFile
130
+ * @param mapFileUtil
131
+ * @param dc
132
+ * @param assortment
133
+ * @param includeInformationKeys defaults true
134
+ * @returns
135
+ */
136
+ static async getProductIdentityObject(transformMapFile: string, mapFileUtil: MapFileUtil, dc: DataConverter, itemFamilyObject, includeInformationKeys = true): Promise<ProductFederation> {
137
+ if(!itemFamilyObject){
138
+ throw new Error('IdentifierConversion.getProductIdentityObject(): itemFamilyObject must be provided.');
139
+ }
140
+ const itemObj = await dc.getFlexPLMObjectData(itemFamilyObject, [], true);
141
+ const flexPLMTypePath = await TypeConversionUtils.getObjectTypePath(transformMapFile, mapFileUtil, itemFamilyObject);
142
+ let prodObj: ProductFederation = {
143
+ entityReference: 'item:' + itemFamilyObject?.id,
144
+ objectClass: 'LCSProduct' as const,
145
+ flexPLMTypePath
146
+ };
147
+
148
+ const identifierKeys: string[] = await TypeConversionUtils
149
+ .getIdentifierProperties(transformMapFile, mapFileUtil, itemFamilyObject);
150
+ for (const key of identifierKeys) {
151
+ if (itemObj[key]) {
152
+ prodObj[key] = itemObj[key];
153
+ }
154
+ }
155
+
156
+ if(includeInformationKeys){
157
+ const informationKeys: string[] = await TypeConversionUtils
158
+ .getInformationalProperties(transformMapFile, mapFileUtil, itemFamilyObject);
159
+ for (const key of informationKeys) {
160
+ if (itemObj[key]) {
161
+ prodObj[key] = itemObj[key];
162
+ }
163
+ }
164
+ }
165
+
166
+ const vibeIQIdentifier = 'vibeIQIdentifier';
167
+ if (!prodObj[vibeIQIdentifier]) {
168
+ prodObj['vibeIQIdentifier'] = itemFamilyObject['identifier'] || itemFamilyObject['itemNumber'];
169
+ }
170
+
171
+ const mapKey: string = await TypeConversionUtils
172
+ .getMapKey(transformMapFile, mapFileUtil, itemFamilyObject, TypeConversionUtils.VIBE2FLEX_DIRECTION);
173
+ prodObj = await MapUtil
174
+ .applyTransformMap(transformMapFile, mapFileUtil, prodObj, mapKey, TypeConversionUtils.VIBE2FLEX_DIRECTION);
175
+
176
+ return prodObj as ProductFederation;
177
+ }
178
+
179
+ /** Takes in an item and returns an object to query for an LCSSKU
180
+ * This will only return the identifier properties, and information properties if specified.
181
+ * @param transformMapFile
182
+ * @param mapFileUtil
183
+ * @param dc
184
+ * @param assortment
185
+ * @param includeInformationKeys defaults true
186
+ * @returns
187
+ */
188
+ static async getSKUIdentityObject(transformMapFile: string, mapFileUtil: MapFileUtil, dc: DataConverter, itemObject, includeInformationKeys = true): Promise<SkuFederation> {
189
+ if(!itemObject){
190
+ throw new Error('IdentifierConversion.getSKUIdentityObject(): itemObject must be provided.');
191
+ }
192
+ const itemObj = await dc.getFlexPLMObjectData(itemObject, [], true);
193
+ const flexPLMTypePath = await TypeConversionUtils.getObjectTypePath(transformMapFile, mapFileUtil, itemObject);
194
+ let skuObj: SkuFederation = {
195
+ entityReference: 'item:' + itemObject?.id,
196
+ objectClass: 'LCSSKU' as const,
197
+ flexPLMTypePath
198
+ };
199
+
200
+ const identifierKeys: string[] = await TypeConversionUtils.getIdentifierProperties(transformMapFile, mapFileUtil, itemObject);
201
+ for (const key of identifierKeys) {
202
+ if (itemObj[key]) {
203
+ skuObj[key] = itemObj[key];
204
+ }
205
+ }
206
+
207
+ if(includeInformationKeys){
208
+ const informationKeys: string[] = await TypeConversionUtils.getInformationalProperties(transformMapFile, mapFileUtil, itemObject);
209
+ for (const key of informationKeys) {
210
+ if (itemObj[key]) {
211
+ skuObj[key] = itemObj[key];
212
+ }
213
+ }
214
+ }
215
+
216
+ const vibeIQIdentifier = 'vibeIQIdentifier';
217
+ if (!skuObj[vibeIQIdentifier]) {
218
+ skuObj['vibeIQIdentifier'] = itemObject['identifier'] || itemObject['itemNumber'];
219
+ }
220
+
221
+ const mapKey: string = await TypeConversionUtils.getMapKey(transformMapFile, mapFileUtil, itemObject, TypeConversionUtils.VIBE2FLEX_DIRECTION);
222
+ skuObj = await MapUtil.applyTransformMap(transformMapFile, mapFileUtil, skuObj, mapKey, TypeConversionUtils.VIBE2FLEX_DIRECTION);
223
+
224
+ return skuObj as SkuFederation;
225
+ }
226
+ }
@@ -0,0 +1,315 @@
1
+ import { ConfigDefaults } from './config-defaults';
2
+ import { FCConfig } from '../interfaces/interfaces';
3
+
4
+ let entityObject = {};
5
+ jest.mock('@contrail/sdk', () => {
6
+ return {
7
+ Entities: class {
8
+ get() {
9
+ return entityObject;
10
+ }
11
+ }
12
+ };
13
+ });
14
+
15
+ let fetchJson = {};
16
+ global.fetch = jest.fn().mockImplementation(() => {
17
+ return Promise.resolve({
18
+ json: () => Promise.resolve(fetchJson)
19
+ });
20
+
21
+ });
22
+
23
+ describe('all tests', () => {
24
+ describe('setConfigDefaults - required values', () => {
25
+ it('missing apiHost', async () => {
26
+ const config = {
27
+ //apiHost: 'http://test.com',
28
+ userName: 'vibeiq',
29
+ password: 'vibeiq',
30
+ plmEnviornment: 'SB'
31
+ };
32
+
33
+ try {
34
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
35
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(config);
36
+
37
+ } catch (e) {
38
+ expect(e.message).toEqual(ConfigDefaults.NEED_CONFIG_VALUES);
39
+ }
40
+ });
41
+ it('missing userName', async () => {
42
+ const config = {
43
+ apiHost: 'http://test.com',
44
+ //userName: 'vibeiq',
45
+ password: 'vibeiq',
46
+ plmEnviornment: 'SB'
47
+ };
48
+
49
+ try {
50
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
51
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(config);
52
+
53
+ } catch (e) {
54
+ expect(e.message).toEqual(ConfigDefaults.NEED_CONFIG_VALUES);
55
+ }
56
+ });
57
+
58
+ it('missing password', async () => {
59
+ const config = {
60
+ apiHost: 'http://test.com',
61
+ userName: 'vibeiq',
62
+ //password: 'vibeiq',
63
+ plmEnviornment: 'SB'
64
+ };
65
+
66
+ try {
67
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
68
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(config);
69
+
70
+ } catch (e) {
71
+ expect(e.message).toEqual(ConfigDefaults.NEED_CONFIG_VALUES);
72
+ }
73
+ });
74
+
75
+ it('missing plmEnviornment', async () => {
76
+ const config = {
77
+ apiHost: 'http://test.com',
78
+ userName: 'vibeiq',
79
+ password: 'vibeiq',
80
+ //plmEnviornment: 'SB'
81
+ };
82
+
83
+ try {
84
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
85
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(config);
86
+
87
+ } catch (e) {
88
+ expect(e.message).toEqual(ConfigDefaults.NEED_CONFIG_VALUES);
89
+ }
90
+ });
91
+
92
+ });
93
+
94
+ describe('userName & password as functions', () =>{
95
+ const config = {
96
+ apiHost: 'http://test.com',
97
+ userName: 'vibeiq',
98
+ password: 'vibeiq',
99
+ plmEnviornment: 'SB'
100
+ };
101
+ it('userName as function', async () =>{
102
+ const startConfig = Object.assign({}, config, { userName: 'newName' });
103
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
104
+ expect(fcConfig.userName()).toEqual('newName');
105
+
106
+ });
107
+ it('password as function', async () =>{
108
+ const startConfig = Object.assign({}, config, { password: 'strange' });
109
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
110
+ expect(fcConfig.password()).toEqual('strange');
111
+
112
+ });
113
+ });
114
+
115
+ describe('setConfigDefaults-setting defaults', () => {
116
+ const config = {
117
+ apiHost: 'http://test.com',
118
+ userName: 'vibeiq',
119
+ password: 'vibeiq',
120
+ plmEnviornment: 'SB'
121
+ };
122
+ it('urlContext-get default', async () => {
123
+ const startConfig = Object.assign({}, config);
124
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
125
+ expect(fcConfig.urlContext).toEqual('/Windchill');
126
+ });
127
+
128
+ it('urlContext-set value', async () => {
129
+ const startConfig = Object.assign({}, config);
130
+ startConfig['urlContext'] = '/FlexPLM';
131
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
132
+ expect(fcConfig.urlContext).toEqual('/FlexPLM');
133
+ });
134
+
135
+ it('sendMode-ASYNC_PUBLISH_SEASON-get default', async () => {
136
+ const startConfig = Object.assign({}, config);
137
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
138
+ expect(fcConfig['sendMode']['ASYNC_PUBLISH_SEASON']).toEqual('vibeiqfile');
139
+ });
140
+
141
+ it('sendMode-ASYNC_PUBLISH_SEASON-set value', async () => {
142
+ const startConfig = Object.assign({}, config);
143
+ startConfig['sendMode'] = { ASYNC_PUBLISH_SEASON: 'vibeiqfile-dontsendtoflexplm' };
144
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
145
+ expect(fcConfig['sendMode']['ASYNC_PUBLISH_SEASON']).toEqual('vibeiqfile-dontsendtoflexplm');
146
+ });
147
+
148
+ it('sendMode-NO_DEFAULT-get default', async () => {
149
+ const startConfig = Object.assign({}, config);
150
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
151
+ expect(fcConfig['sendMode']['NO_DEFAULT']).toBeUndefined();
152
+ });
153
+
154
+ it('sendMode-NO_DEFAULT-set value', async () => {
155
+ const startConfig = Object.assign({}, config);
156
+ startConfig['sendMode'] = { NO_DEFAULT: 'vibeiqfile-dontsendtoflexplm' };
157
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
158
+ expect(fcConfig['sendMode']['NO_DEFAULT']).toEqual('vibeiqfile-dontsendtoflexplm');
159
+ });
160
+
161
+ it('itemPreDevelopmentLifecycleStages-get default', async () => {
162
+ const startConfig = Object.assign({}, config);
163
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
164
+ expect(fcConfig['itemPreDevelopmentLifecycleStages']).toEqual(['concept']);
165
+ });
166
+
167
+ it('itemPreDevelopmentLifecycleStages-set value', async () => {
168
+ const startConfig = Object.assign({}, config);
169
+ const concept = 'concept';
170
+ const development = 'development';
171
+ startConfig['itemPreDevelopmentLifecycleStages'] = concept + ',' + development;
172
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
173
+ const itemPreDevelopmentLifecycleStages = fcConfig['itemPreDevelopmentLifecycleStages'];
174
+ expect(itemPreDevelopmentLifecycleStages instanceof Array).toBeTruthy();
175
+ expect(itemPreDevelopmentLifecycleStages.length).toBe(2);
176
+ expect(itemPreDevelopmentLifecycleStages.includes(concept));
177
+ expect(itemPreDevelopmentLifecycleStages.includes(development));
178
+ });
179
+
180
+ it('itemPreDevelopmentLifecycleStages-set value with space', async () => {
181
+ const startConfig = Object.assign({}, config);
182
+ const concept = 'concept';
183
+ const development = 'development';
184
+ startConfig['itemPreDevelopmentLifecycleStages'] = concept + ', ' + development;
185
+ const fcConfig: FCConfig = await ConfigDefaults.setConfigDefaults(startConfig);
186
+ const itemPreDevelopmentLifecycleStages = fcConfig['itemPreDevelopmentLifecycleStages'];
187
+ expect(itemPreDevelopmentLifecycleStages instanceof Array).toBeTruthy();
188
+ expect(itemPreDevelopmentLifecycleStages.length).toBe(2);
189
+ expect(itemPreDevelopmentLifecycleStages.includes(concept));
190
+ expect(itemPreDevelopmentLifecycleStages.includes(development));
191
+ });
192
+
193
+ it('identifierAtts-LCSProduct-get default', async () => {
194
+ const startConfig = Object.assign({}, config);
195
+ const objectClass = 'LCSProduct';
196
+ const expectedAtts = ['name'];
197
+
198
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
199
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
200
+ expect(identifierAtts instanceof Array).toBeTruthy();
201
+ expect(identifierAtts.length).toBe(expectedAtts.length);
202
+ for (const att of expectedAtts) {
203
+ expect(identifierAtts.includes(att));
204
+ }
205
+ });
206
+
207
+ it('identifierAtts-LCSProduct-set value', async () => {
208
+ const startConfig = Object.assign({}, config);
209
+ const objectClass = 'LCSProduct';
210
+ const expectedAtts = ['val1', 'val2'];
211
+ startConfig['identifierAtts'] = {};
212
+ startConfig['identifierAtts'][objectClass] = expectedAtts;
213
+
214
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
215
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
216
+ expect(identifierAtts instanceof Array).toBeTruthy();
217
+ expect(identifierAtts.length).toBe(expectedAtts.length);
218
+ for (const att of expectedAtts) {
219
+ expect(identifierAtts.includes(att));
220
+ }
221
+ });
222
+
223
+ it('identifierAtts-LCSSeason-get default', async () => {
224
+ const startConfig = Object.assign({}, config);
225
+ const objectClass = 'LCSSeason';
226
+ const expectedAtts = ['flexPLMSeasonName'];
227
+ // const expectedAtts =['seasonType', 'seasonYear'];
228
+
229
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
230
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
231
+ expect(identifierAtts instanceof Array).toBeTruthy();
232
+ expect(identifierAtts.length).toBe(expectedAtts.length);
233
+ for (const att of expectedAtts) {
234
+ expect(identifierAtts.includes(att));
235
+ }
236
+ });
237
+
238
+ it('identifierAtts-LCSSeason-set value', async () => {
239
+ const startConfig = Object.assign({}, config);
240
+ const objectClass = 'LCSSeason';
241
+ const expectedAtts = ['val1', 'val2'];
242
+ startConfig['identifierAtts'] = {};
243
+ startConfig['identifierAtts'][objectClass] = expectedAtts;
244
+
245
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
246
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
247
+ expect(identifierAtts instanceof Array).toBeTruthy();
248
+ expect(identifierAtts.length).toBe(expectedAtts.length);
249
+ for (const att of expectedAtts) {
250
+ expect(identifierAtts.includes(att));
251
+ }
252
+ });
253
+
254
+ it('identifierAtts-LCSSKU-get default', async () => {
255
+ const startConfig = Object.assign({}, config);
256
+ const objectClass = 'LCSSKU';
257
+ const expectedAtts = ['optionName'];
258
+
259
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
260
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
261
+ expect(identifierAtts instanceof Array).toBeTruthy();
262
+ expect(identifierAtts.length).toBe(expectedAtts.length);
263
+ for (const att of expectedAtts) {
264
+ expect(identifierAtts.includes(att));
265
+ }
266
+ });
267
+
268
+ it('identifierAtts-LCSSKU-set value', async () => {
269
+ const startConfig = Object.assign({}, config);
270
+ const objectClass = 'LCSSKU';
271
+ const expectedAtts = ['val1', 'val2'];
272
+ startConfig['identifierAtts'] = {};
273
+ startConfig['identifierAtts'][objectClass] = expectedAtts;
274
+
275
+ const fcConfig = await ConfigDefaults.setConfigDefaults(startConfig);
276
+ const identifierAtts = fcConfig.identifierAtts[objectClass];
277
+ expect(identifierAtts instanceof Array).toBeTruthy();
278
+ expect(identifierAtts.length).toBe(expectedAtts.length);
279
+ for (const att of expectedAtts) {
280
+ expect(identifierAtts.includes(att));
281
+ }
282
+ });
283
+
284
+ });
285
+
286
+ describe('getConfigFile', () => {
287
+ it('response has test var', async () => {
288
+ fetchJson = { testVar: true };
289
+ entityObject = { downloadUrl: 'http://sss.com' };
290
+
291
+ const config = await ConfigDefaults.getConfigFile('id-1');
292
+ expect(config).toBeDefined();
293
+ expect(config['testVar']).toBeTruthy();
294
+ });
295
+
296
+ it('undefined file object', async () => {
297
+ fetchJson = { testVar: true };
298
+ entityObject = undefined;
299
+
300
+ const config = await ConfigDefaults.getConfigFile('id-1');
301
+ expect(config).toBeDefined();
302
+ expect(Object.keys(config).length).toEqual(0);
303
+ });
304
+
305
+ it('response no downloadUrl', async () => {
306
+ fetchJson = { testVar: true };
307
+ entityObject = { };
308
+
309
+ const config = await ConfigDefaults.getConfigFile('id-1');
310
+ expect(config).toBeDefined();
311
+ expect(Object.keys(config).length).toEqual(0);
312
+ });
313
+
314
+ });
315
+ });
@@ -0,0 +1,79 @@
1
+ import { Entities } from '@contrail/sdk';
2
+ import { FCConfig } from '../interfaces/interfaces';
3
+ import { ObjectUtil } from '@contrail/util';
4
+
5
+ export class ConfigDefaults {
6
+ static NEED_CONFIG_VALUES = 'To connect to FlexPLM all these APP values need to be set apiHost, userName, and password';
7
+ static async setConfigDefaults(config): Promise<FCConfig> {
8
+ //Validate config
9
+ if (!config.apiHost || !config.userName || !config.password) {
10
+ throw new Error(ConfigDefaults.NEED_CONFIG_VALUES);
11
+ }
12
+
13
+ //List will be comma separated list in UI, so convert to array
14
+ if(config?.itemPreDevelopmentLifecycleStages && !(config?.itemPreDevelopmentLifecycleStages instanceof Array)){
15
+ config.itemPreDevelopmentLifecycleStages = config.itemPreDevelopmentLifecycleStages.split(',');
16
+ }
17
+
18
+ const defaultConfig = {
19
+ urlContext: '/Windchill',
20
+ sendMode: {
21
+ ASYNC_PUBLISH_SEASON: 'vibeiqfile'
22
+ },
23
+ itemPreDevelopmentLifecycleStages: ['concept'],
24
+ identifierAtts: {
25
+ LCSProduct: ['itemNumber'],
26
+ LCSSeason: ['flexPLMSeasonName'],
27
+ LCSSKU: ['itemNumber']
28
+ },
29
+ csrfEndpoint: '/servlet/rest/security/csrf',
30
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
31
+ payloadDefaultAsArray: true
32
+ };
33
+ const configArr = [defaultConfig];
34
+
35
+ if(config.configFile){
36
+ const fileConfig = await ConfigDefaults.getConfigFile(config.configFile);
37
+ configArr.push(fileConfig);
38
+ }
39
+ configArr.push(config);
40
+ const outputConfig = ObjectUtil.mergeDeep({}, ...configArr);
41
+ const uName = outputConfig.userName;
42
+ const pass = outputConfig.password;
43
+ outputConfig.userName = () => uName;
44
+ outputConfig.password = () => pass;
45
+
46
+ //Don't allow overwriting this.
47
+ outputConfig['OOBvibeEventEndpoint'] = '/rfa/vibeiq/vibeEvents';
48
+
49
+ console.log('outputConfig: ' + JSON.stringify(outputConfig));
50
+ return outputConfig as FCConfig;
51
+ }
52
+
53
+ static async getConfigFile(fileId: string) {
54
+ try {
55
+
56
+ const options = {
57
+ entityName: 'file',
58
+ id: fileId,
59
+ };
60
+ const file = await new Entities().get(options);
61
+ if (!file){
62
+ console.log('failed to find file with id: ' + fileId);
63
+ return {};
64
+ }
65
+ const downloadUrl = file['downloadUrl'];
66
+
67
+ if(!downloadUrl){
68
+ console.log('file didnt have downloadUrl. fileId: ' + fileId);
69
+ return {};
70
+ }
71
+ const response = await fetch(downloadUrl);
72
+ const config = await response.json();
73
+ return config ? config: {};
74
+ }catch(e){
75
+ console.log('Error getting config file: ' + fileId + '- ' +e.message);
76
+ return {};
77
+ }
78
+ }
79
+ }