@contrail/flexplm 1.1.42 → 1.1.44

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.
@@ -27,4 +27,5 @@ Describe the testing you added to this PR
27
27
 
28
28
 
29
29
  ## Link to Jira ticket(s)
30
+ https://vibe-team.atlassian.net/browse/TICKET_NUMBER_HERE
30
31
 
@@ -162,7 +162,8 @@ class BaseEntityProcessor {
162
162
  return flexResponse;
163
163
  }
164
164
  async getOutboundEntityUpdates(event, flexResponse) {
165
- const flexPayload = flexResponse?.data?.payload[0];
165
+ const payload = flexResponse?.data?.payload;
166
+ const flexPayload = (payload) ? payload[0] : undefined;
166
167
  let outboundEntityUpdates = undefined;
167
168
  if (flexPayload && 'OK' === flexPayload.status) {
168
169
  const inboundData = await this.getTransformedData(flexPayload);
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sdk_1 = require("@contrail/sdk");
4
+ const transform_data_1 = require("@contrail/transform-data");
5
+ const data_converter_1 = require("../util/data-converter");
6
+ const base_entity_processor_1 = require("./base-entity-processor");
7
+ class TestBaseEntityProcessor extends base_entity_processor_1.BaseEntityProcessor {
8
+ getIncomingEntity(event, inboundData) {
9
+ throw new Error("Method not implemented.");
10
+ }
11
+ getCreateEntity(inboundData) {
12
+ throw new Error("Method not implemented.");
13
+ }
14
+ getOutgoingUpsertPayload(entityType, event) {
15
+ throw new Error("Method not implemented.");
16
+ }
17
+ }
18
+ describe('BaseEntityProcessor', () => {
19
+ describe('getOutboundEntityUpdates', () => {
20
+ const config = {};
21
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
22
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
23
+ it('no payload', async () => {
24
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
25
+ const event = {};
26
+ const flexResponse = {};
27
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
28
+ expect(updates).toBeUndefined();
29
+ });
30
+ it('flexPayload.status === OK', async () => {
31
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
32
+ const event = {};
33
+ const flexResponse = {
34
+ data: {
35
+ payload: [
36
+ {
37
+ status: 'OK'
38
+ }
39
+ ]
40
+ }
41
+ };
42
+ const getTransformedDataSpy = jest.spyOn(btep, 'getTransformedData').mockReturnValue(Promise.resolve({}));
43
+ const returnValue = {
44
+ name: 'Test'
45
+ };
46
+ const getUpdatesForEntitySpy = jest.spyOn(btep, 'getUpdatesForEntity').mockReturnValue(Promise.resolve(returnValue));
47
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
48
+ expect(getTransformedDataSpy).toBeCalledTimes(1);
49
+ expect(getUpdatesForEntitySpy).toBeCalledTimes(1);
50
+ expect(updates).toBe(returnValue);
51
+ });
52
+ it('flexPayload.status === FAIL', async () => {
53
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
54
+ const event = {};
55
+ const flexResponse = {
56
+ data: {
57
+ payload: [
58
+ {
59
+ status: 'FAIL'
60
+ }
61
+ ]
62
+ }
63
+ };
64
+ const getTransformedDataSpy = jest.spyOn(btep, 'getTransformedData').mockReturnValue(Promise.resolve({}));
65
+ const returnValue = {
66
+ name: 'Test'
67
+ };
68
+ const getUpdatesForEntitySpy = jest.spyOn(btep, 'getUpdatesForEntity').mockReturnValue(Promise.resolve(returnValue));
69
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
70
+ expect(getTransformedDataSpy).toBeCalledTimes(0);
71
+ expect(getUpdatesForEntitySpy).toBeCalledTimes(0);
72
+ expect(updates).toBeUndefined();
73
+ });
74
+ });
75
+ });
@@ -92,7 +92,7 @@ class BaseProcessPublishAssortment {
92
92
  return 'unknown';
93
93
  }
94
94
  const createdOnDate = new Date(createdOnString);
95
- createdOnDate.setDate(createdOnDate.getDate() - 1);
95
+ createdOnDate.setMonth(createdOnDate.getMonth() - 1);
96
96
  const createdOnStringMinus1 = createdOnDate.toISOString();
97
97
  const createdOn = 'ISGREATERTHAN ' + createdOnStringMinus1;
98
98
  const snapshots = await new sdk_1.Entities().get({
@@ -108,11 +108,10 @@ class BaseProcessPublishAssortment {
108
108
  if (snapshot && snapshot.versionNumber) {
109
109
  snapshotVersion = snapshot.versionNumber;
110
110
  }
111
- else if (!snapshot) {
111
+ else if (!snapshot && snapshots.length > 0) {
112
112
  const createdOnTime = new Date(createdOnString).getTime();
113
113
  const lastSnapshot = snapshots[snapshots.length - 1];
114
- const lastSnapshotTime = new Date(lastSnapshot.createdOn).getTime();
115
- if (createdOnTime > lastSnapshotTime) {
114
+ if (lastSnapshot?.createdOn && createdOnTime > new Date(lastSnapshot.createdOn).getTime()) {
116
115
  snapshotVersion = 'after: ' + lastSnapshot.versionNumber;
117
116
  }
118
117
  }
@@ -364,6 +364,55 @@ describe('getSnapshotVersion', () => {
364
364
  expect(getOptionsObject['criteria']['entityReference']).toEqual(assortment.createdForReference);
365
365
  expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
366
366
  });
367
+ it('doesnt find snapshot version, no snapshots returned', async () => {
368
+ const assortment = {
369
+ id: 'rm35clTNxvS4wm6y',
370
+ name: 'VibeIQ Fall 2023',
371
+ createdForReference: 'plan:w23wre'
372
+ };
373
+ const assortmentChangeId = 'sJbGx1Fpq1v2MmcI';
374
+ const apc = {
375
+ id: assortmentChangeId,
376
+ versionName: 'Version 1',
377
+ versionComments: 'Some Comments',
378
+ createdOn: '2023-01-15T19:13:58.902Z'
379
+ };
380
+ const snapshots = [];
381
+ entityObject = snapshots;
382
+ const versionHistoryNumber = await ppa.getSnapshotVersion(assortment, apc);
383
+ expect(versionHistoryNumber).toEqual('unknown');
384
+ expect(getOptionsObject['entityName']).toEqual('entity-snapshot');
385
+ expect(getOptionsObject['criteria']['entityReference']).toEqual(assortment.createdForReference);
386
+ expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
387
+ });
388
+ it('doesnt find snapshot version, last snapshot no createdOn', async () => {
389
+ const assortment = {
390
+ id: 'rm35clTNxvS4wm6y',
391
+ name: 'VibeIQ Fall 2023',
392
+ createdForReference: 'plan:w23wre'
393
+ };
394
+ const assortmentChangeId = 'sJbGx1Fpq1v2MmcI';
395
+ const apc = {
396
+ id: assortmentChangeId,
397
+ versionName: 'Version 1',
398
+ versionComments: 'Some Comments',
399
+ createdOn: '2023-01-15T19:13:58.902Z'
400
+ };
401
+ const versionNumber = 1234;
402
+ const snapshots = [
403
+ {
404
+ id: 'qewrwer',
405
+ assortmentChangeId: 'bad-id',
406
+ versionNumber
407
+ }
408
+ ];
409
+ entityObject = snapshots;
410
+ const versionHistoryNumber = await ppa.getSnapshotVersion(assortment, apc);
411
+ expect(versionHistoryNumber).toEqual('unknown');
412
+ expect(getOptionsObject['entityName']).toEqual('entity-snapshot');
413
+ expect(getOptionsObject['criteria']['entityReference']).toEqual(assortment.createdForReference);
414
+ expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
415
+ });
367
416
  });
368
417
  describe('getSeasonFederation', () => {
369
418
  const config = {
@@ -1,6 +1,8 @@
1
1
  import { FCConfig } from '../interfaces/interfaces';
2
2
  export declare class ConfigDefaults {
3
3
  static NEED_CONFIG_VALUES: string;
4
+ static STATIC_CONFIG_CACHE: {};
4
5
  static setConfigDefaults(config: any): Promise<FCConfig>;
5
6
  static getConfigFile(fileId: string): Promise<any>;
7
+ static clearConfigCache(): void;
6
8
  }
@@ -46,6 +46,10 @@ class ConfigDefaults {
46
46
  }
47
47
  static async getConfigFile(fileId) {
48
48
  try {
49
+ if (ConfigDefaults.STATIC_CONFIG_CACHE[fileId]) {
50
+ console.debug('returning cached config file: ' + fileId);
51
+ return ConfigDefaults.STATIC_CONFIG_CACHE[fileId];
52
+ }
49
53
  const options = {
50
54
  entityName: 'file',
51
55
  id: fileId,
@@ -62,6 +66,9 @@ class ConfigDefaults {
62
66
  }
63
67
  const response = await fetch(downloadUrl);
64
68
  const config = await response.json();
69
+ if (config) {
70
+ ConfigDefaults.STATIC_CONFIG_CACHE[fileId] = config;
71
+ }
65
72
  return config ? config : {};
66
73
  }
67
74
  catch (e) {
@@ -69,6 +76,10 @@ class ConfigDefaults {
69
76
  return {};
70
77
  }
71
78
  }
79
+ static clearConfigCache() {
80
+ ConfigDefaults.STATIC_CONFIG_CACHE = {};
81
+ }
72
82
  }
73
83
  exports.ConfigDefaults = ConfigDefaults;
74
84
  ConfigDefaults.NEED_CONFIG_VALUES = 'To connect to FlexPLM all these APP values need to be set apiHost, userName, and password';
85
+ ConfigDefaults.STATIC_CONFIG_CACHE = {};
@@ -265,6 +265,9 @@ describe('all tests', () => {
265
265
  });
266
266
  });
267
267
  describe('getConfigFile', () => {
268
+ beforeEach(() => {
269
+ config_defaults_1.ConfigDefaults.clearConfigCache();
270
+ });
268
271
  it('response has test var', async () => {
269
272
  fetchJson = { testVar: true };
270
273
  entityObject = { downloadUrl: 'http://sss.com' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/flexplm",
3
- "version": "1.1.42",
3
+ "version": "1.1.44",
4
4
  "description": "Library used for integration with flexplm.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -41,7 +41,7 @@
41
41
  "dependencies": {
42
42
  "@contrail/app-framework": "^1.2.4",
43
43
  "@contrail/sdk": "^1.3.7",
44
- "@contrail/transform-data": "^1.0.15",
44
+ "@contrail/transform-data": "^1.1.1",
45
45
  "axios": "^1.4.0",
46
46
  "p-limit": "^3.1.0"
47
47
  }
@@ -0,0 +1,80 @@
1
+ import { Entities } from "@contrail/sdk";
2
+ import { MapFileUtil } from "@contrail/transform-data";
3
+ import { EntityPayloadType, FCConfig } from "../interfaces/interfaces";
4
+ import { DataConverter } from "../util/data-converter";
5
+ import { BaseEntityProcessor, IncomingEntityResponse } from "./base-entity-processor";
6
+
7
+ class TestBaseEntityProcessor extends BaseEntityProcessor {
8
+ protected getIncomingEntity(event: any, inboundData: any): Promise<IncomingEntityResponse> {
9
+ throw new Error("Method not implemented.");
10
+ }
11
+ protected getCreateEntity(inboundData: any): Promise<IncomingEntityResponse> {
12
+ throw new Error("Method not implemented.");
13
+ }
14
+ protected getOutgoingUpsertPayload(entityType: any, event: any): Promise<EntityPayloadType> {
15
+ throw new Error("Method not implemented.");
16
+ }
17
+
18
+ }
19
+ describe('BaseEntityProcessor', () =>{
20
+ describe('getOutboundEntityUpdates', () =>{
21
+
22
+ const config = {} as FCConfig;
23
+ const mapFileUtil = new MapFileUtil(new Entities());
24
+ const dc = new DataConverter(config, mapFileUtil);
25
+ it('no payload', async () =>{
26
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
27
+ const event = {};
28
+ const flexResponse = {};
29
+
30
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
31
+ expect(updates).toBeUndefined();
32
+ });
33
+
34
+ it('flexPayload.status === OK', async () =>{
35
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
36
+ const event = {};
37
+ const flexResponse = {
38
+ data: {
39
+ payload: [
40
+ {
41
+ status: 'OK'
42
+ }
43
+ ]
44
+ }
45
+ };
46
+ const getTransformedDataSpy = jest.spyOn(btep, 'getTransformedData').mockReturnValue(Promise.resolve({}));
47
+ const returnValue = {
48
+ name: 'Test'
49
+ };
50
+ const getUpdatesForEntitySpy = jest.spyOn(btep, 'getUpdatesForEntity').mockReturnValue(Promise.resolve(returnValue));
51
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
52
+ expect(getTransformedDataSpy).toBeCalledTimes(1);
53
+ expect(getUpdatesForEntitySpy).toBeCalledTimes(1);
54
+ expect(updates).toBe(returnValue);
55
+ });
56
+
57
+ it('flexPayload.status === FAIL', async () =>{
58
+ const btep = new TestBaseEntityProcessor(config, dc, mapFileUtil, 'test');
59
+ const event = {};
60
+ const flexResponse = {
61
+ data: {
62
+ payload: [
63
+ {
64
+ status: 'FAIL'
65
+ }
66
+ ]
67
+ }
68
+ };
69
+ const getTransformedDataSpy = jest.spyOn(btep, 'getTransformedData').mockReturnValue(Promise.resolve({}));
70
+ const returnValue = {
71
+ name: 'Test'
72
+ };
73
+ const getUpdatesForEntitySpy = jest.spyOn(btep, 'getUpdatesForEntity').mockReturnValue(Promise.resolve(returnValue));
74
+ const updates = await btep.getOutboundEntityUpdates(event, flexResponse);
75
+ expect(getTransformedDataSpy).toBeCalledTimes(0);
76
+ expect(getUpdatesForEntitySpy).toBeCalledTimes(0);
77
+ expect(updates).toBeUndefined();
78
+ });
79
+ });
80
+ });
@@ -210,7 +210,8 @@ export abstract class BaseEntityProcessor {
210
210
  }
211
211
 
212
212
  async getOutboundEntityUpdates(event, flexResponse): Promise<any> {
213
- const flexPayload = flexResponse?.data?.payload[0];
213
+ const payload = flexResponse?.data?.payload;
214
+ const flexPayload = (payload)? payload[0] : undefined;
214
215
  let outboundEntityUpdates = undefined;
215
216
  if(flexPayload && 'OK' === flexPayload.status) {
216
217
  const inboundData = await this.getTransformedData(flexPayload);
@@ -406,6 +406,66 @@ describe('getSnapshotVersion', () =>{
406
406
  expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
407
407
  });
408
408
 
409
+ it('doesnt find snapshot version, no snapshots returned', async () =>{
410
+ const assortment = {
411
+ id: 'rm35clTNxvS4wm6y',
412
+ name: 'VibeIQ Fall 2023',
413
+ createdForReference: 'plan:w23wre'
414
+ };
415
+ const assortmentChangeId = 'sJbGx1Fpq1v2MmcI';
416
+ const apc = {
417
+ id: assortmentChangeId,
418
+ versionName: 'Version 1',
419
+ versionComments: 'Some Comments',
420
+ createdOn: '2023-01-15T19:13:58.902Z'
421
+ };
422
+
423
+ const snapshots = [];
424
+
425
+ entityObject = snapshots;
426
+
427
+ const versionHistoryNumber = await ppa.getSnapshotVersion(assortment, apc);
428
+
429
+ expect(versionHistoryNumber).toEqual('unknown');
430
+ expect(getOptionsObject['entityName']).toEqual('entity-snapshot');
431
+ expect(getOptionsObject['criteria']['entityReference']).toEqual(assortment.createdForReference);
432
+ expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
433
+ });
434
+
435
+ it('doesnt find snapshot version, last snapshot no createdOn', async () =>{
436
+ const assortment = {
437
+ id: 'rm35clTNxvS4wm6y',
438
+ name: 'VibeIQ Fall 2023',
439
+ createdForReference: 'plan:w23wre'
440
+ };
441
+ const assortmentChangeId = 'sJbGx1Fpq1v2MmcI';
442
+ const apc = {
443
+ id: assortmentChangeId,
444
+ versionName: 'Version 1',
445
+ versionComments: 'Some Comments',
446
+ createdOn: '2023-01-15T19:13:58.902Z'
447
+ };
448
+
449
+ const versionNumber = 1234;
450
+ const snapshots = [
451
+ {
452
+ id: 'qewrwer',
453
+ assortmentChangeId: 'bad-id',
454
+ // createdOn: '2023-01-14T19:13:58.902Z',
455
+ versionNumber
456
+ }
457
+ ];
458
+
459
+ entityObject = snapshots;
460
+
461
+ const versionHistoryNumber = await ppa.getSnapshotVersion(assortment, apc);
462
+
463
+ expect(versionHistoryNumber).toEqual('unknown');
464
+ expect(getOptionsObject['entityName']).toEqual('entity-snapshot');
465
+ expect(getOptionsObject['criteria']['entityReference']).toEqual(assortment.createdForReference);
466
+ expect(getOptionsObject['criteria']['createdOn'].indexOf('ISGREATERTHAN')).toEqual(0);
467
+ });
468
+
409
469
  });
410
470
 
411
471
  describe('getSeasonFederation', () =>{
@@ -126,7 +126,7 @@ export class BaseProcessPublishAssortment {
126
126
  return 'unknown';
127
127
  }
128
128
  const createdOnDate = new Date(createdOnString);
129
- createdOnDate.setDate(createdOnDate.getDate() - 1);//subtract 1 day
129
+ createdOnDate.setMonth(createdOnDate.getMonth() - 1);//subtract 1 month
130
130
  const createdOnStringMinus1 = createdOnDate.toISOString();
131
131
  const createdOn = 'ISGREATERTHAN ' + createdOnStringMinus1;
132
132
 
@@ -143,11 +143,10 @@ export class BaseProcessPublishAssortment {
143
143
  let snapshotVersion = 'unknown';
144
144
  if(snapshot && snapshot.versionNumber){
145
145
  snapshotVersion = snapshot.versionNumber;
146
- } else if(!snapshot){
146
+ } else if(!snapshot && snapshots.length > 0){
147
147
  const createdOnTime = new Date(createdOnString).getTime();
148
148
  const lastSnapshot = snapshots[snapshots.length - 1];
149
- const lastSnapshotTime = new Date(lastSnapshot.createdOn).getTime();
150
- if(createdOnTime > lastSnapshotTime){
149
+ if(lastSnapshot?.createdOn && createdOnTime > new Date(lastSnapshot.createdOn).getTime()){
151
150
  snapshotVersion = 'after: ' + lastSnapshot.versionNumber;
152
151
  }
153
152
 
@@ -315,6 +315,10 @@ describe('all tests', () => {
315
315
  });
316
316
 
317
317
  describe('getConfigFile', () => {
318
+ beforeEach(() => {
319
+ ConfigDefaults.clearConfigCache();
320
+ });
321
+
318
322
  it('response has test var', async () => {
319
323
  fetchJson = { testVar: true };
320
324
  entityObject = { downloadUrl: 'http://sss.com' };
@@ -4,6 +4,7 @@ import { ObjectUtil } from '@contrail/util';
4
4
 
5
5
  export class ConfigDefaults {
6
6
  static NEED_CONFIG_VALUES = 'To connect to FlexPLM all these APP values need to be set apiHost, userName, and password';
7
+ static STATIC_CONFIG_CACHE = {};
7
8
  static async setConfigDefaults(config): Promise<FCConfig> {
8
9
  //Validate config
9
10
  if (!config.apiHost || !config.userName || !config.password) {
@@ -55,6 +56,10 @@ export class ConfigDefaults {
55
56
  static async getConfigFile(fileId: string) {
56
57
  try {
57
58
 
59
+ if(ConfigDefaults.STATIC_CONFIG_CACHE[fileId]){
60
+ console.debug('returning cached config file: ' + fileId);
61
+ return ConfigDefaults.STATIC_CONFIG_CACHE[fileId];
62
+ }
58
63
  const options = {
59
64
  entityName: 'file',
60
65
  id: fileId,
@@ -72,10 +77,17 @@ export class ConfigDefaults {
72
77
  }
73
78
  const response = await fetch(downloadUrl);
74
79
  const config = await response.json();
80
+ if(config){
81
+ ConfigDefaults.STATIC_CONFIG_CACHE[fileId] = config;
82
+ }
75
83
  return config ? config: {};
76
84
  }catch(e){
77
85
  console.log('Error getting config file: ' + fileId + '- ' +e.message);
78
86
  return {};
79
87
  }
80
88
  }
89
+
90
+ static clearConfigCache(){
91
+ ConfigDefaults.STATIC_CONFIG_CACHE = {};
92
+ }
81
93
  }