@contrail/flexplm 1.1.50 → 1.1.52

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.
@@ -18,10 +18,16 @@ export declare class BaseProcessPublishAssortment {
18
18
  process(event: any): Promise<{
19
19
  results: {
20
20
  message: any;
21
+ event: any;
21
22
  };
22
23
  skip_await: boolean;
23
24
  } | {
24
25
  results: any;
26
+ event: {
27
+ assortmentId: string;
28
+ assortmentPublishChangeId: string;
29
+ };
30
+ resultsCount: any;
25
31
  skip_await?: undefined;
26
32
  }>;
27
33
  getPublishInfo(assortmentId: string, assortmentPublishChangeId: string, apcHistory: any, publisher: any): Promise<any>;
@@ -50,12 +56,24 @@ export declare class BaseProcessPublishAssortment {
50
56
  processPublish(pcd: PublishChangeData, changeDetail: any, fullChange: any, deleteChanges: any): Promise<{
51
57
  results: {
52
58
  message: string;
59
+ event: {
60
+ assortmentId: string;
61
+ assortmentPublishChangeId: string;
62
+ };
53
63
  };
54
64
  skip_await: boolean;
65
+ event?: undefined;
66
+ resultsCount?: undefined;
55
67
  } | {
56
68
  results: any;
69
+ event: {
70
+ assortmentId: string;
71
+ assortmentPublishChangeId: string;
72
+ };
73
+ resultsCount: any;
57
74
  skip_await?: undefined;
58
75
  }>;
76
+ getResultsCount(events: any): any;
59
77
  private sendEvents;
60
78
  private sendToFlexPLM;
61
79
  private saveToLocalFile;
@@ -10,9 +10,17 @@ const type_conversion_utils_1 = require("../util/type-conversion-utils");
10
10
  const fsPromise = require("fs/promises");
11
11
  const path = require("path");
12
12
  const app_framework_1 = require("@contrail/app-framework");
13
+ var EventStatuses;
14
+ (function (EventStatuses) {
15
+ EventStatuses["NOT_PUBLISHABLE"] = "Not_Publishable";
16
+ EventStatuses["NO_FEDERATION_INFO"] = "No_Federation_Information";
17
+ EventStatuses["NO_EVENTS_TO_SEND"] = "No_Events_to_Send";
18
+ EventStatuses["FAILURE"] = "Failure";
19
+ EventStatuses["SUCCESS"] = "Success";
20
+ })(EventStatuses || (EventStatuses = {}));
13
21
  class BaseProcessPublishAssortment {
14
22
  constructor(_config, _dc, _mapFileUtil) {
15
- this.TTL = 7 * 24 * 60 * 60 * 1000;
23
+ this.TTL = 30 * 24 * 60 * 60 * 1000;
16
24
  this.cache = {
17
25
  carriedFromSeason: {}
18
26
  };
@@ -34,9 +42,15 @@ class BaseProcessPublishAssortment {
34
42
  }
35
43
  catch (e) {
36
44
  const message = e.message;
45
+ const eventStatus = (message.includes(BaseProcessPublishAssortment.ASSORTMENT_NOT_PUBLISHABLE)) ? EventStatuses.NOT_PUBLISHABLE :
46
+ (message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? EventStatuses.NO_FEDERATION_INFO :
47
+ EventStatuses.FAILURE;
48
+ const processStatus = 'BaseProcessPublishAssortment: ' + eventStatus
49
+ + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId;
50
+ console.log(JSON.stringify(processStatus));
37
51
  console.log(message);
38
52
  const output = {
39
- results: { message },
53
+ results: { message, event },
40
54
  skip_await: true
41
55
  };
42
56
  return output;
@@ -502,20 +516,44 @@ class BaseProcessPublishAssortment {
502
516
  }
503
517
  async processPublish(pcd, changeDetail, fullChange, deleteChanges) {
504
518
  console.info('processPublish-start');
519
+ const event = {
520
+ assortmentId: pcd.assortmentId,
521
+ assortmentPublishChangeId: pcd.assortmentPublishChangeId
522
+ };
505
523
  const assortmentItemFullChangeMap = this.getFullChangeAssortmentMap(fullChange);
506
524
  const assortmentItemDeleteMap = this.getDeleteChangesAssortmentMap(deleteChanges);
507
525
  pcd.itemFamilyChanges = this.getItemFamilyChanges(pcd, changeDetail, assortmentItemFullChangeMap, assortmentItemDeleteMap);
508
526
  const events = await this.getEventsForPublishChangeData(pcd);
509
527
  if (events.length === 0) {
528
+ const processStatus = 'BaseProcessPublishAssortment: ' + EventStatuses.NO_EVENTS_TO_SEND
529
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId;
530
+ console.log(processStatus);
510
531
  const message = 'No Events to Send; returning';
511
532
  console.log(message);
512
533
  return {
513
- results: { message },
534
+ results: { message, event },
514
535
  skip_await: true
515
536
  };
516
537
  }
517
538
  const results = await this.sendEvents(events);
518
- return { results };
539
+ const resultsCount = this.getResultsCount(events);
540
+ const processStatus = 'BaseProcessPublishAssortment: ' + EventStatuses.NO_EVENTS_TO_SEND
541
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
542
+ + ': resultsCount: ' + JSON.stringify(resultsCount);
543
+ console.log(processStatus);
544
+ return { results, event, resultsCount };
545
+ }
546
+ getResultsCount(events) {
547
+ return events.reduce((acc, event) => {
548
+ const objectClass = event?.objectClass;
549
+ if (objectClass === 'LCSProductSeasonLink') {
550
+ acc.productSeasons++;
551
+ }
552
+ else if (objectClass === 'LCSSKUSeasonLink') {
553
+ acc.colorwaySeasons++;
554
+ }
555
+ return acc;
556
+ }, { productSeasons: 0, colorwaySeasons: 0 });
519
557
  }
520
558
  async sendEvents(events) {
521
559
  console.info('sendEvents()');
@@ -9,6 +9,10 @@ export declare class DataConverter {
9
9
  private verboseDebug;
10
10
  private objRefCache;
11
11
  private userRefCache;
12
+ static staticUserCache: {};
13
+ static clearStaticUserCache(): void;
14
+ static getFromStaticCache(id: string): any;
15
+ static setToStaticCache(id: string, value: any): void;
12
16
  constructor(config: FCConfig, mapFileUtil: MapFileUtil);
13
17
  setVerboseDebug(val?: boolean): void;
14
18
  isVerboseDebugOn(): boolean;
@@ -8,6 +8,15 @@ 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
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
+ }
11
20
  constructor(config, mapFileUtil) {
12
21
  this.config = config;
13
22
  this.mapFileUtil = mapFileUtil;
@@ -460,17 +469,18 @@ class DataConverter {
460
469
  if (!nd?.email) {
461
470
  return "";
462
471
  }
463
- if (this.userRefCache[nd.email]) {
472
+ let cacheUser = DataConverter.getFromStaticCache(nd.email);
473
+ if (cacheUser) {
464
474
  if (app_framework_1.Logger.isDebugOn()) {
465
475
  console.debug('user cache hit: ' + nd.email);
466
476
  }
467
477
  await this.processGroupMemberCheck(prop, nd.email);
468
- return this.userRefCache[nd.email];
478
+ return cacheUser;
469
479
  }
470
480
  const user = await this.getUserByEmail(nd);
471
481
  const userId = (user) ? user.id : undefined;
472
482
  if (userId) {
473
- this.userRefCache[nd.email] = userId;
483
+ DataConverter.setToStaticCache(nd.email, userId);
474
484
  await this.processGroupMemberCheck(prop, nd.email);
475
485
  }
476
486
  return userId;
@@ -522,11 +532,12 @@ class DataConverter {
522
532
  if (!entityId) {
523
533
  return {};
524
534
  }
525
- if (this.userRefCache[entityId]) {
535
+ const cacheUser = DataConverter.getFromStaticCache(entityId);
536
+ if (cacheUser) {
526
537
  if (app_framework_1.Logger.isDebugOn()) {
527
538
  console.debug('user cache hit: ' + entityId);
528
539
  }
529
- return this.userRefCache[entityId];
540
+ return Object.assign({}, cacheUser);
530
541
  }
531
542
  const user = await this.getUserById(entityId);
532
543
  const value = (user) ? {
@@ -536,7 +547,7 @@ class DataConverter {
536
547
  isSsoUser: user.isSsoUser,
537
548
  } : undefined;
538
549
  if (value) {
539
- this.userRefCache[entityId] = value;
550
+ DataConverter.setToStaticCache(entityId, value);
540
551
  }
541
552
  return value;
542
553
  }
@@ -557,3 +568,4 @@ class DataConverter {
557
568
  }
558
569
  }
559
570
  exports.DataConverter = DataConverter;
571
+ DataConverter.staticUserCache = {};
@@ -652,3 +652,200 @@ describe('checkKeysAndValues', () => {
652
652
  expect(results.length).toBe(1);
653
653
  });
654
654
  });
655
+ describe('setUserListValue', () => {
656
+ const config = {
657
+ apiHost: 'host',
658
+ userName: () => 'user',
659
+ password: () => 'pass',
660
+ urlContext: 'xxx',
661
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
662
+ csrfEndpoint: '/servlet/rest/security/csrf',
663
+ itemPreDevelopmentLifecycleStages: ['concept']
664
+ };
665
+ const userListProp1 = {};
666
+ const userEmailMapping = [
667
+ {
668
+ id: "gxgr46kvdeEOn4cH",
669
+ email: "jessica.smith@vibeiq.com"
670
+ },
671
+ {
672
+ id: "Rl5D0sjuAwelScEK",
673
+ email: "adam.smith@vibeiq.com"
674
+ }
675
+ ];
676
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
677
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
678
+ let spyGetUserByEmail = jest.spyOn(dc, 'getUserByEmail')
679
+ .mockImplementation(async (nd) => {
680
+ let emaildInput = nd?.email.toLowerCase();
681
+ return userEmailMapping.find((user) => user.email === emaildInput);
682
+ });
683
+ let spyProcessGroupMemberCheck = jest.spyOn(dc, 'processGroupMemberCheck')
684
+ .mockImplementation(async (nd) => { return; });
685
+ afterEach(() => {
686
+ spyGetUserByEmail.mockClear();
687
+ spyProcessGroupMemberCheck.mockClear();
688
+ data_converter_1.DataConverter.clearStaticUserCache();
689
+ });
690
+ afterAll(() => {
691
+ spyGetUserByEmail.mockRestore();
692
+ spyProcessGroupMemberCheck.mockRestore();
693
+ });
694
+ it('no value', async () => {
695
+ const newData = {};
696
+ const returnValue = await dc.setUserListValue(userListProp1, newData);
697
+ expect(returnValue).toEqual('');
698
+ });
699
+ it('miss cache', async () => {
700
+ const newData = { email: 'adam.smith@vibeiq.com' };
701
+ const returnValue = await dc.setUserListValue(userListProp1, newData);
702
+ console.log('returnValue', JSON.stringify(returnValue));
703
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
704
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
705
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
706
+ });
707
+ it('miss cache - two different emails', async () => {
708
+ let newData = { email: 'adam.smith@vibeiq.com' };
709
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
710
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
711
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
712
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
713
+ newData = { email: 'jessica.smith@vibeiq.com' };
714
+ returnValue = await dc.setUserListValue(userListProp1, newData);
715
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(2);
716
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(2);
717
+ });
718
+ it('hit cache same email', async () => {
719
+ const newData = { email: 'adam.smith@vibeiq.com' };
720
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
721
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
722
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
723
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
724
+ returnValue = await dc.setUserListValue(userListProp1, newData);
725
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
726
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
727
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(2);
728
+ });
729
+ it('hit cache same email - new DataConverter entity', async () => {
730
+ const newData = { email: 'adam.smith@vibeiq.com' };
731
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
732
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
733
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
734
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
735
+ const dc2 = new data_converter_1.DataConverter(config, mapFileUtil);
736
+ let spyGetUserByEmail2 = jest.spyOn(dc2, 'getUserByEmail')
737
+ .mockImplementation(async (nd) => {
738
+ let emaildInput = nd?.email.toLowerCase();
739
+ return userEmailMapping.find((user) => user.email === emaildInput);
740
+ });
741
+ let spyProcessGroupMemberCheck2 = jest.spyOn(dc2, 'processGroupMemberCheck')
742
+ .mockImplementation(async (nd) => { return; });
743
+ returnValue = await dc2.setUserListValue(userListProp1, newData);
744
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
745
+ expect(spyGetUserByEmail2).toHaveBeenCalledTimes(0);
746
+ expect(spyProcessGroupMemberCheck2).toHaveBeenCalledTimes(1);
747
+ spyGetUserByEmail2.mockRestore();
748
+ spyProcessGroupMemberCheck2.mockRestore();
749
+ });
750
+ });
751
+ describe('getUserListValue', () => {
752
+ const config = {
753
+ apiHost: 'host',
754
+ userName: () => 'user',
755
+ password: () => 'pass',
756
+ urlContext: 'xxx',
757
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
758
+ csrfEndpoint: '/servlet/rest/security/csrf',
759
+ itemPreDevelopmentLifecycleStages: ['concept']
760
+ };
761
+ const userListProp1 = {
762
+ slug: 'userList1'
763
+ };
764
+ const userEmailMapping = [
765
+ {
766
+ id: "gxgr46kvdeEOn4cH",
767
+ email: "jessica.smith@vibeiq.com",
768
+ first: 'Jessica',
769
+ last: 'Smith'
770
+ },
771
+ {
772
+ id: "Rl5D0sjuAwelScEK",
773
+ email: "adam.smith@vibeiq.com",
774
+ first: 'Adam',
775
+ last: 'Smith'
776
+ }
777
+ ];
778
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
779
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
780
+ let spyGetUserById = jest.spyOn(dc, 'getUserById')
781
+ .mockImplementation(async (nd) => {
782
+ return userEmailMapping.find((user) => user.id === nd);
783
+ });
784
+ afterEach(() => {
785
+ spyGetUserById.mockClear();
786
+ data_converter_1.DataConverter.clearStaticUserCache();
787
+ });
788
+ afterAll(() => {
789
+ spyGetUserById.mockRestore();
790
+ });
791
+ it('no value', async () => {
792
+ const newData = {};
793
+ const returnValue = await dc.getUserListValue(userListProp1, newData);
794
+ expect(returnValue).toEqual({});
795
+ });
796
+ it('miss cache', async () => {
797
+ const newData = {
798
+ userList1Id: 'gxgr46kvdeEOn4cH'
799
+ };
800
+ const returnValue = await dc.getUserListValue(userListProp1, newData);
801
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
802
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
803
+ expect(returnValue.firstName).toEqual('Jessica');
804
+ expect(returnValue.lastName).toEqual('Smith');
805
+ });
806
+ it('miss cache - two different emails', async () => {
807
+ let newData = { userList1Id: 'gxgr46kvdeEOn4cH' };
808
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
809
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
810
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
811
+ expect(returnValue.firstName).toEqual('Jessica');
812
+ expect(returnValue.lastName).toEqual('Smith');
813
+ newData = { userList1Id: 'Rl5D0sjuAwelScEK' };
814
+ returnValue = await dc.getUserListValue(userListProp1, newData);
815
+ expect(spyGetUserById).toHaveBeenCalledTimes(2);
816
+ expect(returnValue.email).toEqual('adam.smith@vibeiq.com');
817
+ expect(returnValue.firstName).toEqual('Adam');
818
+ expect(returnValue.lastName).toEqual('Smith');
819
+ });
820
+ it('hit cache same email', async () => {
821
+ const newData = { userList1Id: 'gxgr46kvdeEOn4cH' };
822
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
823
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
824
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
825
+ expect(returnValue.firstName).toEqual('Jessica');
826
+ expect(returnValue.lastName).toEqual('Smith');
827
+ returnValue = await dc.getUserListValue(userListProp1, newData);
828
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
829
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
830
+ expect(returnValue.firstName).toEqual('Jessica');
831
+ expect(returnValue.lastName).toEqual('Smith');
832
+ });
833
+ it('hit cache same email - new DataConverter entity', async () => {
834
+ const newData = { userList1Id: 'gxgr46kvdeEOn4cH' };
835
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
836
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
837
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
838
+ expect(returnValue.firstName).toEqual('Jessica');
839
+ expect(returnValue.lastName).toEqual('Smith');
840
+ const dc2 = new data_converter_1.DataConverter(config, mapFileUtil);
841
+ let spyGetUserById2 = jest.spyOn(dc2, 'getUserById')
842
+ .mockImplementation(async (nd) => {
843
+ return userEmailMapping.find((user) => user.id === nd);
844
+ });
845
+ returnValue = await dc2.getUserListValue(userListProp1, newData);
846
+ expect(spyGetUserById2).toHaveBeenCalledTimes(0);
847
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
848
+ expect(returnValue.firstName).toEqual('Jessica');
849
+ expect(returnValue.lastName).toEqual('Smith');
850
+ });
851
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/flexplm",
3
- "version": "1.1.50",
3
+ "version": "1.1.52",
4
4
  "description": "Library used for integration with flexplm.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -12,9 +12,17 @@ import path = require('path');
12
12
  import { MapFileUtil } from '@contrail/transform-data';
13
13
  import { Logger } from '@contrail/app-framework';
14
14
 
15
+ enum EventStatuses {
16
+ NOT_PUBLISHABLE = 'Not_Publishable',
17
+ NO_FEDERATION_INFO = 'No_Federation_Information',
18
+ NO_EVENTS_TO_SEND = 'No_Events_to_Send',
19
+ FAILURE = 'Failure',
20
+ SUCCESS = 'Success',
21
+ }
22
+
15
23
  export class BaseProcessPublishAssortment {
16
24
 
17
- private TTL = 7 * 24 * 60 * 60 * 1_000; // 1 week
25
+ private TTL = 30 * 24 * 60 * 60 * 1_000; // 30 days
18
26
  static ASSORTMENT_NOT_PUBLISHABLE = 'Assortment isn\'t marked for publishing to FlexPLM';
19
27
  static ASSORTMENT_NO_FED_INFO = 'Assortment doesn\'t have all "identifier" properties, so there is no processing. Identifier properties: ';
20
28
  static NOT_ABLE_TO_PROCESS_DELETE_CHANGES = 'Error: Not able to process delete changes';
@@ -47,9 +55,16 @@ export class BaseProcessPublishAssortment {
47
55
  seasonFed = await this.getSeasonFederation(assortmentId);
48
56
  } catch (e) {
49
57
  const message = e.message;
58
+ const eventStatus =
59
+ (message.includes(BaseProcessPublishAssortment.ASSORTMENT_NOT_PUBLISHABLE)) ? EventStatuses.NOT_PUBLISHABLE :
60
+ (message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? EventStatuses.NO_FEDERATION_INFO :
61
+ EventStatuses.FAILURE;
62
+ const processStatus = 'BaseProcessPublishAssortment: ' + eventStatus
63
+ + ': assortmentId: ' + event.assortmentId + ': assortmentPublishChangeId: ' + event.assortmentPublishChangeId;
64
+ console.log(JSON.stringify(processStatus));
50
65
  console.log(message);
51
66
  const output = {
52
- results: { message },
67
+ results: { message, event },
53
68
  skip_await: true
54
69
  };
55
70
  return output;
@@ -607,6 +622,10 @@ export class BaseProcessPublishAssortment {
607
622
  }
608
623
  async processPublish(pcd: PublishChangeData, changeDetail, fullChange, deleteChanges) {
609
624
  console.info('processPublish-start');
625
+ const event = {
626
+ assortmentId: pcd.assortmentId,
627
+ assortmentPublishChangeId: pcd.assortmentPublishChangeId
628
+ };
610
629
 
611
630
  const assortmentItemFullChangeMap = this.getFullChangeAssortmentMap(fullChange);
612
631
  const assortmentItemDeleteMap = this.getDeleteChangesAssortmentMap(deleteChanges);
@@ -614,16 +633,39 @@ export class BaseProcessPublishAssortment {
614
633
 
615
634
  const events = await this.getEventsForPublishChangeData(pcd);
616
635
  if (events.length === 0) {
617
- const message = 'No Events to Send; returning';
618
- console.log(message);
619
- return {
620
- results: { message },
621
- skip_await: true
622
- };
636
+ const processStatus = 'BaseProcessPublishAssortment: ' + EventStatuses.NO_EVENTS_TO_SEND
637
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId;
638
+ console.log(processStatus);
639
+ const message = 'No Events to Send; returning';
640
+ console.log(message);
641
+ return {
642
+ results: { message, event },
643
+ skip_await: true
644
+ };
645
+
623
646
  }
624
647
 
625
648
  const results = await this.sendEvents(events);
626
- return { results };
649
+ const resultsCount = this.getResultsCount(events);
650
+ const processStatus = 'BaseProcessPublishAssortment: ' + EventStatuses.NO_EVENTS_TO_SEND
651
+ + ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
652
+ + ': resultsCount: ' + JSON.stringify(resultsCount);
653
+ console.log(processStatus);
654
+ return { results, event, resultsCount };
655
+
656
+ }
657
+
658
+ getResultsCount(events) {
659
+ return events.reduce((acc, event) => {
660
+ const objectClass = event?.objectClass;
661
+ if (objectClass === 'LCSProductSeasonLink') {
662
+ acc.productSeasons++;
663
+ }
664
+ else if (objectClass === 'LCSSKUSeasonLink') {
665
+ acc.colorwaySeasons++;
666
+ }
667
+ return acc;
668
+ }, { productSeasons: 0, colorwaySeasons: 0 });
627
669
  }
628
670
 
629
671
  private async sendEvents(events: SeasonalPayload[]): Promise<any> {
@@ -392,7 +392,7 @@ describe('getEnumerationValue multi_select', () => {
392
392
  ],
393
393
  };
394
394
 
395
-
395
+
396
396
  it('multi_select_null', async () => {
397
397
  const nd = null;
398
398
  const returnValue = await dc.getEnumerationValue(enumAtt, nd);
@@ -940,4 +940,241 @@ describe('checkKeysAndValues', () =>{
940
940
  expect(results.length).toBe(1);
941
941
  });
942
942
 
943
+ });
944
+
945
+ describe('setUserListValue', () =>{
946
+ const config: FCConfig = {
947
+ apiHost: 'host',
948
+ userName: () => 'user',
949
+ password: () => 'pass',
950
+ urlContext: 'xxx',
951
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
952
+ csrfEndpoint: '/servlet/rest/security/csrf',
953
+ itemPreDevelopmentLifecycleStages: ['concept']
954
+ };
955
+ const userListProp1 = {};
956
+ const userEmailMapping = [
957
+ {
958
+ id: "gxgr46kvdeEOn4cH",
959
+ email: "jessica.smith@vibeiq.com"
960
+ },
961
+
962
+ {
963
+ id: "Rl5D0sjuAwelScEK",
964
+ email: "adam.smith@vibeiq.com"
965
+ }
966
+ ];
967
+
968
+ const mapFileUtil = new MapFileUtil(new Entities());
969
+ const dc = new DataConverter(config, mapFileUtil);
970
+ let spyGetUserByEmail = jest.spyOn(dc, 'getUserByEmail')
971
+ .mockImplementation(async (nd) => {
972
+ let emaildInput = nd?.email.toLowerCase();
973
+ return userEmailMapping.find((user) => user.email === emaildInput);
974
+ });
975
+ let spyProcessGroupMemberCheck = jest.spyOn(dc, 'processGroupMemberCheck')
976
+ .mockImplementation(async (nd) => { return; });
977
+
978
+ afterEach(() => {
979
+ spyGetUserByEmail.mockClear();
980
+ spyProcessGroupMemberCheck.mockClear();
981
+ DataConverter.clearStaticUserCache();
982
+ });
983
+ afterAll(() => {
984
+ spyGetUserByEmail.mockRestore();
985
+ spyProcessGroupMemberCheck.mockRestore();
986
+ });
987
+
988
+ it('no value', async () =>{
989
+ const newData = {};
990
+ const returnValue = await dc.setUserListValue(userListProp1, newData);
991
+
992
+ expect(returnValue).toEqual('');
993
+ });
994
+
995
+ it('miss cache', async () =>{
996
+ const newData = {email: 'adam.smith@vibeiq.com'};
997
+ const returnValue = await dc.setUserListValue(userListProp1, newData);
998
+ console.log('returnValue', JSON.stringify(returnValue));
999
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1000
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
1001
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
1002
+ });
1003
+
1004
+ it('miss cache - two different emails', async () =>{
1005
+ let newData = {email: 'adam.smith@vibeiq.com'};
1006
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
1007
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1008
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
1009
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
1010
+
1011
+ newData = {email: 'jessica.smith@vibeiq.com'};
1012
+ returnValue = await dc.setUserListValue(userListProp1, newData);
1013
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(2);
1014
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(2);
1015
+ });
1016
+
1017
+ it('hit cache same email', async () =>{
1018
+ const newData = {email: 'adam.smith@vibeiq.com'};
1019
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
1020
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1021
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
1022
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
1023
+
1024
+ returnValue = await dc.setUserListValue(userListProp1, newData);
1025
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1026
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
1027
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(2);
1028
+ });
1029
+
1030
+ it('hit cache same email - new DataConverter entity', async () =>{
1031
+ const newData = {email: 'adam.smith@vibeiq.com'};
1032
+ let returnValue = await dc.setUserListValue(userListProp1, newData);
1033
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1034
+ expect(spyGetUserByEmail).toHaveBeenCalledTimes(1);
1035
+ expect(spyProcessGroupMemberCheck).toHaveBeenCalledTimes(1);
1036
+
1037
+ const dc2 = new DataConverter(config, mapFileUtil);
1038
+ let spyGetUserByEmail2 = jest.spyOn(dc2, 'getUserByEmail')
1039
+ .mockImplementation(async (nd) => {
1040
+ let emaildInput = nd?.email.toLowerCase();
1041
+ return userEmailMapping.find((user) => user.email === emaildInput);
1042
+ });
1043
+ let spyProcessGroupMemberCheck2 = jest.spyOn(dc2, 'processGroupMemberCheck')
1044
+ .mockImplementation(async (nd) => { return; });
1045
+
1046
+ returnValue = await dc2.setUserListValue(userListProp1, newData);
1047
+ expect(returnValue).toEqual('Rl5D0sjuAwelScEK');
1048
+ expect(spyGetUserByEmail2).toHaveBeenCalledTimes(0);
1049
+ expect(spyProcessGroupMemberCheck2).toHaveBeenCalledTimes(1);
1050
+
1051
+ spyGetUserByEmail2.mockRestore();
1052
+ spyProcessGroupMemberCheck2.mockRestore();
1053
+ });
1054
+
1055
+ });
1056
+
1057
+ describe('getUserListValue', () =>{
1058
+ const config: FCConfig = {
1059
+ apiHost: 'host',
1060
+ userName: () => 'user',
1061
+ password: () => 'pass',
1062
+ urlContext: 'xxx',
1063
+ vibeEventEndpoint: '/rfa/vibeiq/vibeEvents',
1064
+ csrfEndpoint: '/servlet/rest/security/csrf',
1065
+ itemPreDevelopmentLifecycleStages: ['concept']
1066
+ };
1067
+ const userListProp1 = {
1068
+ slug: 'userList1'
1069
+ };
1070
+ const userEmailMapping = [
1071
+ {
1072
+ id: "gxgr46kvdeEOn4cH",
1073
+ email: "jessica.smith@vibeiq.com",
1074
+ first: 'Jessica',
1075
+ last: 'Smith'
1076
+ },
1077
+
1078
+ {
1079
+ id: "Rl5D0sjuAwelScEK",
1080
+ email: "adam.smith@vibeiq.com",
1081
+ first: 'Adam',
1082
+ last: 'Smith'
1083
+ }
1084
+ ];
1085
+
1086
+ const mapFileUtil = new MapFileUtil(new Entities());
1087
+ const dc = new DataConverter(config, mapFileUtil);
1088
+
1089
+ //getUserById
1090
+ let spyGetUserById = jest.spyOn(dc, 'getUserById')
1091
+ .mockImplementation(async (nd) => {
1092
+ return userEmailMapping.find((user) => user.id === nd);
1093
+ });
1094
+
1095
+ afterEach(() => {
1096
+ spyGetUserById.mockClear();
1097
+ DataConverter.clearStaticUserCache();
1098
+ });
1099
+ afterAll(() => {
1100
+ spyGetUserById.mockRestore();
1101
+ });
1102
+
1103
+ it('no value', async () =>{
1104
+ const newData = {};
1105
+ const returnValue = await dc.getUserListValue(userListProp1, newData);
1106
+
1107
+ expect(returnValue).toEqual({});
1108
+ });
1109
+
1110
+ it('miss cache', async () =>{
1111
+ const newData = {
1112
+ userList1Id: 'gxgr46kvdeEOn4cH'
1113
+ };
1114
+
1115
+ const returnValue = await dc.getUserListValue(userListProp1, newData);
1116
+
1117
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
1118
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1119
+ expect(returnValue.firstName).toEqual('Jessica');
1120
+ expect(returnValue.lastName).toEqual('Smith');
1121
+
1122
+ });
1123
+
1124
+ it('miss cache - two different emails', async () =>{
1125
+ let newData = { userList1Id: 'gxgr46kvdeEOn4cH'};
1126
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
1127
+
1128
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
1129
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1130
+ expect(returnValue.firstName).toEqual('Jessica');
1131
+ expect(returnValue.lastName).toEqual('Smith');
1132
+
1133
+ newData = { userList1Id: 'Rl5D0sjuAwelScEK' };
1134
+ returnValue = await dc.getUserListValue(userListProp1, newData);
1135
+
1136
+ expect(spyGetUserById).toHaveBeenCalledTimes(2);
1137
+ expect(returnValue.email).toEqual('adam.smith@vibeiq.com');
1138
+ expect(returnValue.firstName).toEqual('Adam');
1139
+ expect(returnValue.lastName).toEqual('Smith');
1140
+ });
1141
+
1142
+ it('hit cache same email', async () =>{
1143
+ const newData = { userList1Id: 'gxgr46kvdeEOn4cH'};
1144
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
1145
+
1146
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
1147
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1148
+ expect(returnValue.firstName).toEqual('Jessica');
1149
+ expect(returnValue.lastName).toEqual('Smith');
1150
+
1151
+ returnValue = await dc.getUserListValue(userListProp1, newData);
1152
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
1153
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1154
+ expect(returnValue.firstName).toEqual('Jessica');
1155
+ expect(returnValue.lastName).toEqual('Smith');
1156
+ });
1157
+
1158
+ it('hit cache same email - new DataConverter entity', async () =>{
1159
+ const newData = { userList1Id: 'gxgr46kvdeEOn4cH'};
1160
+ let returnValue = await dc.getUserListValue(userListProp1, newData);
1161
+
1162
+ expect(spyGetUserById).toHaveBeenCalledTimes(1);
1163
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1164
+ expect(returnValue.firstName).toEqual('Jessica');
1165
+ expect(returnValue.lastName).toEqual('Smith');
1166
+
1167
+ const dc2 = new DataConverter(config, mapFileUtil);
1168
+ let spyGetUserById2 = jest.spyOn(dc2, 'getUserById')
1169
+ .mockImplementation(async (nd) => {
1170
+ return userEmailMapping.find((user) => user.id === nd);
1171
+ });
1172
+
1173
+ returnValue = await dc2.getUserListValue(userListProp1, newData);
1174
+ expect(spyGetUserById2).toHaveBeenCalledTimes(0);
1175
+ expect(returnValue.email).toEqual('jessica.smith@vibeiq.com');
1176
+ expect(returnValue.firstName).toEqual('Jessica');
1177
+ expect(returnValue.lastName).toEqual('Smith');
1178
+ });
1179
+
943
1180
  });
@@ -14,6 +14,17 @@ export class DataConverter {
14
14
  private verboseDebug = false;
15
15
  private objRefCache = {};
16
16
  private userRefCache = {};
17
+ static staticUserCache = {};
18
+ static clearStaticUserCache() {
19
+ DataConverter.staticUserCache = {};
20
+ }
21
+ static getFromStaticCache(id: string) {
22
+ return DataConverter.staticUserCache[id];
23
+ }
24
+ static setToStaticCache(id: string, value: any) {
25
+ DataConverter.staticUserCache[id] = value;
26
+ }
27
+
17
28
  constructor(private config: FCConfig, private mapFileUtil: MapFileUtil){
18
29
  this.typeUtils = new TypeUtils();
19
30
  this.transformMapFile = this.config['transformMapFile'];
@@ -575,21 +586,21 @@ export class DataConverter {
575
586
  if(!nd?.email) {
576
587
  return "";
577
588
  }
578
-
579
- if (this.userRefCache[nd.email]) {
589
+ let cacheUser = DataConverter.getFromStaticCache(nd.email);
590
+ if (cacheUser) {
580
591
  if (Logger.isDebugOn()) {
581
592
  console.debug('user cache hit: ' + nd.email);
582
593
  }
583
594
 
584
595
  await this.processGroupMemberCheck(prop, nd.email);
585
- return this.userRefCache[nd.email];
596
+ return cacheUser;
586
597
  }
587
598
 
588
599
  const user = await this.getUserByEmail(nd);
589
600
  const userId = (user)?user.id:undefined;
590
601
 
591
602
  if(userId) {
592
- this.userRefCache[nd.email] = userId;
603
+ DataConverter.setToStaticCache(nd.email, userId);
593
604
  await this.processGroupMemberCheck(prop, nd.email);
594
605
  }
595
606
 
@@ -671,11 +682,12 @@ export class DataConverter {
671
682
  return {};
672
683
  }
673
684
 
674
- if (this.userRefCache[entityId]) {
685
+ const cacheUser = DataConverter.getFromStaticCache(entityId);
686
+ if (cacheUser) {
675
687
  if (Logger.isDebugOn()) {
676
688
  console.debug('user cache hit: ' + entityId);
677
689
  }
678
- return this.userRefCache[entityId];
690
+ return Object.assign({}, cacheUser);
679
691
  }
680
692
 
681
693
  const user = await this.getUserById(entityId);
@@ -688,7 +700,7 @@ export class DataConverter {
688
700
  } : undefined;
689
701
 
690
702
  if(value) {
691
- this.userRefCache[entityId] = value;
703
+ DataConverter.setToStaticCache(entityId, value);
692
704
  }
693
705
 
694
706
  return value;