@contrail/flexplm 1.5.0 → 1.5.1-alpha.5843ce4

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.5.1] - 2026-05-14
11
+ ### Added
12
+ - Added sending an external event with the publish payload and trigger key of `VibeIQ|AssortmentPublishedToFlexPLM` to enable secondary events to run on the event / data which was generated. Also includes the payload in the data which can be passed to the next action.
13
+
10
14
  ## [1.5.0] - 2026-05-12
11
15
  ### Added
12
16
  - Added support for Inbound `LCSMaterial` to sync to the entity class `item` with type path `item:material` and `itemNumber` as identifier. This is controlled by an `LCSMaterial.processAsItem` (default `false`) config default.
@@ -79,6 +79,7 @@ export declare class BaseProcessPublishAssortment {
79
79
  private sendToFlexPLM;
80
80
  private saveToLocalFile;
81
81
  private handleVibeIQFile;
82
+ sendPublishPayloadEvent(outboundEvent: any): Promise<void>;
82
83
  private getCurrentDateString;
83
84
  getItemFamilyChanges(pcd: PublishChangeData, changeDetail: any, assortmentItemFullChangeMap: Map<string, any>, assortmentItemDeleteMap: Map<string, any>): Map<string, ItemFamilyChanges>;
84
85
  getEventsForPublishChangeData(publishChangeData: PublishChangeData): Promise<SeasonalPayload[]>;
@@ -569,14 +569,22 @@ class BaseProcessPublishAssortment {
569
569
  }
570
570
  }
571
571
  async sendToFlexPLM(events, eventType) {
572
- const asyncEvent = {
572
+ const outboundPublishEvent = {
573
573
  taskId: this.config.taskId,
574
574
  eventType,
575
575
  objectClass: 'LCSSeason',
576
576
  events
577
577
  };
578
578
  const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
579
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
579
+ const [result] = await Promise.all([
580
+ flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
581
+ this.sendPublishPayloadEvent(outboundPublishEvent)
582
+ ]);
583
+ const isResultObject = typeof result === 'object' && result !== null;
584
+ const resultWithOutboundPublishEvent = isResultObject
585
+ ? { ...result, outboundPublishEvent }
586
+ : { result, outboundPublishEvent };
587
+ return resultWithOutboundPublishEvent;
580
588
  }
581
589
  async saveToLocalFile(events, eventType) {
582
590
  let results = {};
@@ -588,15 +596,16 @@ class BaseProcessPublishAssortment {
588
596
  const eventDirName = 'events-output';
589
597
  const fileName = `${path.sep}${eventDirName}${path.sep}events-${dateString}.json`;
590
598
  fileHandle = await fsPromise.open('.' + fileName, 'a');
591
- const asyncEvent = {
599
+ const outboundPublishEvent = {
592
600
  taskId: this.config.taskId,
593
601
  eventType,
594
602
  objectClass: 'LCSSeason',
595
603
  events
596
604
  };
597
- await fileHandle.writeFile(JSON.stringify(asyncEvent));
605
+ await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
598
606
  results = {
599
607
  message: 'Successfully Saved File',
608
+ outboundPublishEvent,
600
609
  fileLocation: dirName + fileName
601
610
  };
602
611
  }
@@ -612,7 +621,7 @@ class BaseProcessPublishAssortment {
612
621
  const eventBuffer = Buffer.from(JSON.stringify(events), 'utf-8');
613
622
  const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
614
623
  const uploadFile = await new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
615
- const asyncEvent = {
624
+ const outboundPublishEvent = {
616
625
  taskId: this.config.taskId,
617
626
  eventType,
618
627
  objectClass: 'LCSSeason',
@@ -622,15 +631,39 @@ class BaseProcessPublishAssortment {
622
631
  };
623
632
  if (sendMode === 'vibeiqfile') {
624
633
  const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
625
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
634
+ const [result] = await Promise.all([
635
+ flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
636
+ this.sendPublishPayloadEvent(outboundPublishEvent)
637
+ ]);
638
+ return { ...result, outboundPublishEvent };
626
639
  }
627
640
  else {
641
+ await this.sendPublishPayloadEvent(outboundPublishEvent);
628
642
  return {
629
643
  message: 'Successfully Uploaded File.',
630
- asyncEvent
644
+ outboundPublishEvent
631
645
  };
632
646
  }
633
647
  }
648
+ async sendPublishPayloadEvent(outboundEvent) {
649
+ console.info('sendPublishPayloadEvent()');
650
+ let initialEvent = {};
651
+ if (this.config?.event) {
652
+ initialEvent = (typeof this.config?.event === 'string')
653
+ ? JSON.parse(this.config?.event)
654
+ : this.config?.event;
655
+ }
656
+ const eventBody = {
657
+ originSystemType: 'VibeIQ',
658
+ objectClass: 'AssortmentPublishedToFlexPLM',
659
+ outboundEvent,
660
+ initialEvent
661
+ };
662
+ await new sdk_1.Entities().create({
663
+ entityName: 'external-event',
664
+ object: eventBody
665
+ });
666
+ }
634
667
  getCurrentDateString() {
635
668
  const d = new Date();
636
669
  return '' + d.getUTCFullYear()
@@ -9,6 +9,7 @@ const sdk_1 = require("@contrail/sdk");
9
9
  const type_conversion_utils_1 = require("../util/type-conversion-utils");
10
10
  const map_utils_1 = require("../util/map-utils");
11
11
  const item_family_changes_1 = require("../interfaces/item-family-changes");
12
+ const flexplm_connect_1 = require("../util/flexplm-connect");
12
13
  let federatedId = '';
13
14
  jest.mock('../util/data-converter', () => {
14
15
  return {
@@ -30,6 +31,13 @@ jest.mock('../util/federation', () => {
30
31
  });
31
32
  let entityObject = {};
32
33
  let getOptionsObject = {};
34
+ let createCallArg = undefined;
35
+ let fileUploadCalls = [];
36
+ let fileUploadResult = {
37
+ id: 'file-123',
38
+ downloadUrl: 'https://download.url',
39
+ adminDownloadUrl: 'https://admin.download.url'
40
+ };
33
41
  jest.mock('@contrail/sdk', () => {
34
42
  return {
35
43
  Entities: class {
@@ -37,6 +45,18 @@ jest.mock('@contrail/sdk', () => {
37
45
  getOptionsObject = _getOtionsObject;
38
46
  return entityObject;
39
47
  }
48
+ create(arg) {
49
+ createCallArg = arg;
50
+ return Promise.resolve({});
51
+ }
52
+ },
53
+ Files: class {
54
+ createAndUploadFileFromBuffer(buffer, mimeType, fileName, _x, ttl) {
55
+ fileUploadCalls.push({ buffer, mimeType, fileName, ttl });
56
+ return Promise.resolve(fileUploadResult);
57
+ }
58
+ },
59
+ Request: class {
40
60
  }
41
61
  };
42
62
  });
@@ -1668,3 +1688,122 @@ describe('getEventsForItemFamilyChanges - conditional eventType', () => {
1668
1688
  expect(type_conversion_utils_1.TypeConversionUtils.isOutboundCreatableFromEntity).toHaveBeenNthCalledWith(2, undefined, mapFileUtil, colorProjectItem, { item: itemData, assortment });
1669
1689
  });
1670
1690
  });
1691
+ describe('sendToFlexPLM / handleVibeIQFile / sendPublishPayloadEvent', () => {
1692
+ const config = {
1693
+ taskId: 'task-abc',
1694
+ event: '{"sourceEventId":"src-1"}'
1695
+ };
1696
+ const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
1697
+ const dc = new data_converter_1.DataConverter(config, mapFileUtil);
1698
+ const events = [{ objectClass: 'LCSProductSeasonLink' }];
1699
+ const eventType = 'ASYNC_PUBLISH_SEASON';
1700
+ beforeEach(() => {
1701
+ createCallArg = undefined;
1702
+ fileUploadCalls = [];
1703
+ fileUploadResult = {
1704
+ id: 'file-123',
1705
+ downloadUrl: 'https://download.url',
1706
+ adminDownloadUrl: 'https://admin.download.url'
1707
+ };
1708
+ });
1709
+ afterEach(() => {
1710
+ jest.restoreAllMocks();
1711
+ });
1712
+ it('sendToFlexPLM merges outboundPublishEvent into result and calls sendPublishPayloadEvent in parallel', async () => {
1713
+ const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
1714
+ const flexResponse = { status: 200, data: { ok: true } };
1715
+ let flexResolved = false;
1716
+ let eventResolved = false;
1717
+ const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
1718
+ .mockImplementation(async () => {
1719
+ await new Promise(r => setTimeout(r, 5));
1720
+ flexResolved = true;
1721
+ return flexResponse;
1722
+ });
1723
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
1724
+ .mockImplementation(async () => {
1725
+ await new Promise(r => setTimeout(r, 5));
1726
+ eventResolved = true;
1727
+ });
1728
+ const result = await bppa.sendToFlexPLM(events, eventType);
1729
+ expect(spyFlex).toHaveBeenCalledTimes(1);
1730
+ expect(spyEvent).toHaveBeenCalledTimes(1);
1731
+ expect(flexResolved).toBe(true);
1732
+ expect(eventResolved).toBe(true);
1733
+ const passedOutboundPublishEvent = spyFlex.mock.calls[0][0];
1734
+ expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
1735
+ expect(passedOutboundPublishEvent.eventType).toBe(eventType);
1736
+ expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
1737
+ expect(passedOutboundPublishEvent.events).toBe(events);
1738
+ expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
1739
+ expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
1740
+ });
1741
+ it('handleVibeIQFile (vibeiqfile) merges outboundPublishEvent into FlexPLM result and calls sendPublishPayloadEvent', async () => {
1742
+ const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
1743
+ const flexResponse = { status: 200, data: { ok: true } };
1744
+ const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
1745
+ .mockResolvedValue(flexResponse);
1746
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
1747
+ .mockResolvedValue(undefined);
1748
+ const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile');
1749
+ expect(fileUploadCalls).toHaveLength(1);
1750
+ expect(fileUploadCalls[0].fileName).toBe('ASYNC_PUBLISH_SEASON-events.json');
1751
+ expect(fileUploadCalls[0].mimeType).toBe('application/json');
1752
+ const passedOutboundPublishEvent = spyFlex.mock.calls[0][0];
1753
+ expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
1754
+ expect(passedOutboundPublishEvent.eventType).toBe(eventType);
1755
+ expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
1756
+ expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
1757
+ expect(passedOutboundPublishEvent.eventsDownloadLink).toBe('https://download.url');
1758
+ expect(passedOutboundPublishEvent.eventsAdminDownloadLink).toBe('https://admin.download.url');
1759
+ expect(spyFlex).toHaveBeenCalledTimes(1);
1760
+ expect(spyEvent).toHaveBeenCalledTimes(1);
1761
+ expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
1762
+ expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
1763
+ });
1764
+ it('handleVibeIQFile (vibeiqfile-dontsendtoflexplm) skips FlexPLM but still calls sendPublishPayloadEvent', async () => {
1765
+ const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
1766
+ const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
1767
+ .mockResolvedValue({});
1768
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
1769
+ .mockResolvedValue(undefined);
1770
+ const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile-dontsendtoflexplm');
1771
+ expect(spyFlex).not.toHaveBeenCalled();
1772
+ expect(spyEvent).toHaveBeenCalledTimes(1);
1773
+ const passedOutboundPublishEvent = spyEvent.mock.calls[0][0];
1774
+ expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
1775
+ expect(result).toEqual({
1776
+ message: 'Successfully Uploaded File.',
1777
+ outboundPublishEvent: passedOutboundPublishEvent
1778
+ });
1779
+ });
1780
+ it('sendPublishPayloadEvent creates an external-event with initialEvent parsed from config', async () => {
1781
+ const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
1782
+ const outboundEvent = { foo: 'bar' };
1783
+ await bppa.sendPublishPayloadEvent(outboundEvent);
1784
+ expect(createCallArg).toEqual({
1785
+ entityName: 'external-event',
1786
+ object: {
1787
+ originSystemType: 'VibeIQ',
1788
+ objectClass: 'AssortmentPublishedToFlexPLM',
1789
+ outboundEvent,
1790
+ initialEvent: { sourceEventId: 'src-1' }
1791
+ }
1792
+ });
1793
+ });
1794
+ it('sendPublishPayloadEvent defaults initialEvent to {} when config has no event', async () => {
1795
+ const bareConfig = { taskId: 'task-x' };
1796
+ const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(bareConfig, dc, mapFileUtil);
1797
+ const outboundEvent = { hello: 'world' };
1798
+ await bppa.sendPublishPayloadEvent(outboundEvent);
1799
+ expect(createCallArg).toEqual({
1800
+ entityName: 'external-event',
1801
+ object: {
1802
+ originSystemType: 'VibeIQ',
1803
+ objectClass: 'AssortmentPublishedToFlexPLM',
1804
+ outboundEvent,
1805
+ initialEvent: {}
1806
+ }
1807
+ });
1808
+ });
1809
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/flexplm",
3
- "version": "1.5.0",
3
+ "version": "1.5.1-alpha.5843ce4",
4
4
  "description": "Library used for integration with flexplm.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -8,6 +8,7 @@ import { Entities } from '@contrail/sdk';
8
8
  import { TypeConversionUtils } from '../util/type-conversion-utils';
9
9
  import { MapUtil } from '../util/map-utils';
10
10
  import { ItemFamilyChanges } from '../interfaces/item-family-changes';
11
+ import { FlexPLMConnect } from '../util/flexplm-connect';
11
12
 
12
13
  let federatedId = '';
13
14
  jest.mock('../util/data-converter', () => {
@@ -32,6 +33,13 @@ jest.mock('../util/federation', () => {
32
33
  });
33
34
  let entityObject = {};
34
35
  let getOptionsObject = {};
36
+ let createCallArg: any = undefined;
37
+ let fileUploadCalls: any[] = [];
38
+ let fileUploadResult: any = {
39
+ id: 'file-123',
40
+ downloadUrl: 'https://download.url',
41
+ adminDownloadUrl: 'https://admin.download.url'
42
+ };
35
43
  jest.mock('@contrail/sdk', () => {
36
44
  return {
37
45
  Entities: class{
@@ -39,7 +47,18 @@ jest.mock('@contrail/sdk', () => {
39
47
  getOptionsObject = _getOtionsObject;
40
48
  return entityObject;
41
49
  }
42
- }
50
+ create(arg){
51
+ createCallArg = arg;
52
+ return Promise.resolve({});
53
+ }
54
+ },
55
+ Files: class{
56
+ createAndUploadFileFromBuffer(buffer, mimeType, fileName, _x, ttl){
57
+ fileUploadCalls.push({ buffer, mimeType, fileName, ttl });
58
+ return Promise.resolve(fileUploadResult);
59
+ }
60
+ },
61
+ Request: class{}
43
62
  };
44
63
  });
45
64
  describe('process publish assortment', () => {
@@ -1989,4 +2008,147 @@ describe('getEventsForItemFamilyChanges - conditional eventType', () => {
1989
2008
  );
1990
2009
  });
1991
2010
 
2011
+ });
2012
+
2013
+ describe('sendToFlexPLM / handleVibeIQFile / sendPublishPayloadEvent', () => {
2014
+ const config = {
2015
+ taskId: 'task-abc',
2016
+ event: '{"sourceEventId":"src-1"}'
2017
+ } as unknown as FCConfig;
2018
+ const mapFileUtil = new MapFileUtil(new Entities());
2019
+ const dc = new DataConverter(config, mapFileUtil);
2020
+ const events = [{ objectClass: 'LCSProductSeasonLink' }] as any;
2021
+ const eventType = 'ASYNC_PUBLISH_SEASON';
2022
+
2023
+ beforeEach(() => {
2024
+ createCallArg = undefined;
2025
+ fileUploadCalls = [];
2026
+ fileUploadResult = {
2027
+ id: 'file-123',
2028
+ downloadUrl: 'https://download.url',
2029
+ adminDownloadUrl: 'https://admin.download.url'
2030
+ };
2031
+ });
2032
+ afterEach(() => {
2033
+ jest.restoreAllMocks();
2034
+ });
2035
+
2036
+ it('sendToFlexPLM merges outboundPublishEvent into result and calls sendPublishPayloadEvent in parallel', async () => {
2037
+ const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
2038
+ const flexResponse = { status: 200, data: { ok: true } };
2039
+
2040
+ let flexResolved = false;
2041
+ let eventResolved = false;
2042
+ const spyFlex = jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM')
2043
+ .mockImplementation(async () => {
2044
+ await new Promise(r => setTimeout(r, 5));
2045
+ flexResolved = true;
2046
+ return flexResponse as any;
2047
+ });
2048
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
2049
+ .mockImplementation(async () => {
2050
+ await new Promise(r => setTimeout(r, 5));
2051
+ eventResolved = true;
2052
+ });
2053
+
2054
+ const result = await (bppa as any).sendToFlexPLM(events, eventType);
2055
+
2056
+ expect(spyFlex).toHaveBeenCalledTimes(1);
2057
+ expect(spyEvent).toHaveBeenCalledTimes(1);
2058
+ expect(flexResolved).toBe(true);
2059
+ expect(eventResolved).toBe(true);
2060
+
2061
+ const passedOutboundPublishEvent = spyFlex.mock.calls[0][0] as any;
2062
+ expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
2063
+ expect(passedOutboundPublishEvent.eventType).toBe(eventType);
2064
+ expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
2065
+ expect(passedOutboundPublishEvent.events).toBe(events);
2066
+ expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
2067
+ expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
2068
+ });
2069
+
2070
+ it('handleVibeIQFile (vibeiqfile) merges outboundPublishEvent into FlexPLM result and calls sendPublishPayloadEvent', async () => {
2071
+ const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
2072
+ const flexResponse = { status: 200, data: { ok: true } };
2073
+
2074
+ const spyFlex = jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM')
2075
+ .mockResolvedValue(flexResponse as any);
2076
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
2077
+ .mockResolvedValue(undefined as any);
2078
+
2079
+ const result = await (bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile');
2080
+
2081
+ expect(fileUploadCalls).toHaveLength(1);
2082
+ expect(fileUploadCalls[0].fileName).toBe('ASYNC_PUBLISH_SEASON-events.json');
2083
+ expect(fileUploadCalls[0].mimeType).toBe('application/json');
2084
+
2085
+ const passedOutboundPublishEvent = spyFlex.mock.calls[0][0] as any;
2086
+ expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
2087
+ expect(passedOutboundPublishEvent.eventType).toBe(eventType);
2088
+ expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
2089
+ expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
2090
+ expect(passedOutboundPublishEvent.eventsDownloadLink).toBe('https://download.url');
2091
+ expect(passedOutboundPublishEvent.eventsAdminDownloadLink).toBe('https://admin.download.url');
2092
+
2093
+ expect(spyFlex).toHaveBeenCalledTimes(1);
2094
+ expect(spyEvent).toHaveBeenCalledTimes(1);
2095
+ expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
2096
+ expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
2097
+ });
2098
+
2099
+ it('handleVibeIQFile (vibeiqfile-dontsendtoflexplm) skips FlexPLM but still calls sendPublishPayloadEvent', async () => {
2100
+ const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
2101
+
2102
+ const spyFlex = jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM')
2103
+ .mockResolvedValue({} as any);
2104
+ const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
2105
+ .mockResolvedValue(undefined as any);
2106
+
2107
+ const result = await (bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile-dontsendtoflexplm');
2108
+
2109
+ expect(spyFlex).not.toHaveBeenCalled();
2110
+ expect(spyEvent).toHaveBeenCalledTimes(1);
2111
+
2112
+ const passedOutboundPublishEvent = spyEvent.mock.calls[0][0] as any;
2113
+ expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
2114
+ expect(result).toEqual({
2115
+ message: 'Successfully Uploaded File.',
2116
+ outboundPublishEvent: passedOutboundPublishEvent
2117
+ });
2118
+ });
2119
+
2120
+ it('sendPublishPayloadEvent creates an external-event with initialEvent parsed from config', async () => {
2121
+ const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
2122
+ const outboundEvent = { foo: 'bar' };
2123
+
2124
+ await bppa.sendPublishPayloadEvent(outboundEvent);
2125
+
2126
+ expect(createCallArg).toEqual({
2127
+ entityName: 'external-event',
2128
+ object: {
2129
+ originSystemType: 'VibeIQ',
2130
+ objectClass: 'AssortmentPublishedToFlexPLM',
2131
+ outboundEvent,
2132
+ initialEvent: { sourceEventId: 'src-1' }
2133
+ }
2134
+ });
2135
+ });
2136
+
2137
+ it('sendPublishPayloadEvent defaults initialEvent to {} when config has no event', async () => {
2138
+ const bareConfig = { taskId: 'task-x' } as unknown as FCConfig;
2139
+ const bppa = new BaseProcessPublishAssortment(bareConfig, dc, mapFileUtil);
2140
+ const outboundEvent = { hello: 'world' };
2141
+
2142
+ await bppa.sendPublishPayloadEvent(outboundEvent);
2143
+
2144
+ expect(createCallArg).toEqual({
2145
+ entityName: 'external-event',
2146
+ object: {
2147
+ originSystemType: 'VibeIQ',
2148
+ objectClass: 'AssortmentPublishedToFlexPLM',
2149
+ outboundEvent,
2150
+ initialEvent: {}
2151
+ }
2152
+ });
2153
+ });
1992
2154
  });
@@ -685,7 +685,7 @@ export class BaseProcessPublishAssortment {
685
685
  }
686
686
 
687
687
  private async sendToFlexPLM(events: SeasonalPayload[], eventType: string) {
688
- const asyncEvent: AsyncEventsPayloadType = {
688
+ const outboundPublishEvent: AsyncEventsPayloadType = {
689
689
  taskId: this.config.taskId,
690
690
  eventType,
691
691
  objectClass: 'LCSSeason',
@@ -693,7 +693,16 @@ export class BaseProcessPublishAssortment {
693
693
  };
694
694
 
695
695
  const flexPLMConnect = new FlexPLMConnect(this.config);
696
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
696
+ const [result] = await Promise.all([
697
+ flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
698
+ this.sendPublishPayloadEvent(outboundPublishEvent)
699
+ ]);
700
+ const isResultObject = typeof result === 'object' && result !== null;
701
+ const resultWithOutboundPublishEvent = isResultObject
702
+ ? { ...result, outboundPublishEvent }
703
+ : { result, outboundPublishEvent };
704
+
705
+ return resultWithOutboundPublishEvent;
697
706
  }
698
707
 
699
708
  private async saveToLocalFile(events: SeasonalPayload[], eventType: string) {
@@ -708,17 +717,18 @@ export class BaseProcessPublishAssortment {
708
717
  const fileName = `${path.sep}${eventDirName}${path.sep}events-${dateString}.json`;
709
718
  fileHandle = await fsPromise.open('.' + fileName, 'a');
710
719
 
711
- const asyncEvent: AsyncEventsPayloadType = {
720
+ const outboundPublishEvent: AsyncEventsPayloadType = {
712
721
  taskId: this.config.taskId,
713
722
  eventType,
714
723
  objectClass: 'LCSSeason',
715
724
  events
716
725
  };
717
726
 
718
- await fileHandle.writeFile(JSON.stringify(asyncEvent));
727
+ await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
719
728
 
720
729
  results = {
721
730
  message: 'Successfully Saved File',
731
+ outboundPublishEvent,
722
732
  fileLocation: dirName + fileName
723
733
  };
724
734
  } catch (e) {
@@ -735,26 +745,53 @@ export class BaseProcessPublishAssortment {
735
745
  const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
736
746
  const uploadFile = await new Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
737
747
 
738
- const asyncEvent: AsyncEventsPayloadType = {
748
+ const outboundPublishEvent: AsyncEventsPayloadType = {
739
749
  taskId: this.config.taskId,
740
750
  eventType,
741
751
  objectClass: 'LCSSeason',
742
752
  eventsFileId: uploadFile.id,
743
753
  eventsDownloadLink: uploadFile.downloadUrl,
744
754
  eventsAdminDownloadLink: uploadFile.adminDownloadUrl
745
- };
755
+ };
746
756
 
747
757
  if (sendMode === 'vibeiqfile') {
748
758
  const flexPLMConnect = new FlexPLMConnect(this.config);
749
- return await flexPLMConnect.sendToFlexPLM(asyncEvent);
759
+ const [result] = await Promise.all([
760
+ flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
761
+ this.sendPublishPayloadEvent(outboundPublishEvent)
762
+ ]);
763
+ return { ...result, outboundPublishEvent };
750
764
  } else {
765
+ await this.sendPublishPayloadEvent(outboundPublishEvent);
751
766
  return {
752
767
  message: 'Successfully Uploaded File.',
753
- asyncEvent
768
+ outboundPublishEvent
754
769
  };
755
770
  }
756
771
  }
757
772
 
773
+ public async sendPublishPayloadEvent(outboundEvent: any){
774
+ console.info('sendPublishPayloadEvent()');
775
+ let initialEvent = {};
776
+ if(this.config?.event){
777
+ initialEvent = (typeof this.config?.event === 'string')
778
+ ? JSON.parse(this.config?.event)
779
+ : this.config?.event;
780
+ }
781
+ const eventBody = {
782
+ originSystemType: 'VibeIQ',
783
+ objectClass: 'AssortmentPublishedToFlexPLM',
784
+ outboundEvent,
785
+ initialEvent
786
+ };
787
+
788
+ await new Entities().create({
789
+ entityName: 'external-event',
790
+ object: eventBody
791
+ });
792
+ }
793
+
794
+
758
795
  private getCurrentDateString() {
759
796
  const d = new Date();
760
797
  return '' + d.getUTCFullYear()