@contrail/flexplm 1.5.0 → 1.5.1-alpha.2e74ff1
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 +4 -0
- package/lib/publish/base-process-publish-assortment.d.ts +2 -0
- package/lib/publish/base-process-publish-assortment.js +62 -7
- package/lib/publish/base-process-publish-assortment.spec.js +212 -0
- package/package.json +1 -1
- package/src/publish/base-process-publish-assortment.spec.ts +254 -1
- package/src/publish/base-process-publish-assortment.ts +75 -8
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.
|
|
@@ -77,8 +77,10 @@ export declare class BaseProcessPublishAssortment {
|
|
|
77
77
|
getResultsCount(events: any): any;
|
|
78
78
|
private sendEvents;
|
|
79
79
|
private sendToFlexPLM;
|
|
80
|
+
private buildPublishError;
|
|
80
81
|
private saveToLocalFile;
|
|
81
82
|
private handleVibeIQFile;
|
|
83
|
+
private sendPublishPayloadEvent;
|
|
82
84
|
private getCurrentDateString;
|
|
83
85
|
getItemFamilyChanges(pcd: PublishChangeData, changeDetail: any, assortmentItemFullChangeMap: Map<string, any>, assortmentItemDeleteMap: Map<string, any>): Map<string, ItemFamilyChanges>;
|
|
84
86
|
getEventsForPublishChangeData(publishChangeData: PublishChangeData): Promise<SeasonalPayload[]>;
|
|
@@ -569,14 +569,37 @@ class BaseProcessPublishAssortment {
|
|
|
569
569
|
}
|
|
570
570
|
}
|
|
571
571
|
async sendToFlexPLM(events, eventType) {
|
|
572
|
-
const
|
|
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
|
-
|
|
579
|
+
const [sendResult, eventResult] = await Promise.allSettled([
|
|
580
|
+
flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
|
|
581
|
+
this.sendPublishPayloadEvent(outboundPublishEvent)
|
|
582
|
+
]);
|
|
583
|
+
if (sendResult.status === 'rejected' || eventResult.status === 'rejected') {
|
|
584
|
+
throw this.buildPublishError(sendResult, eventResult, outboundPublishEvent);
|
|
585
|
+
}
|
|
586
|
+
const result = sendResult.value;
|
|
587
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
588
|
+
return isResultObject
|
|
589
|
+
? { ...result, outboundPublishEvent }
|
|
590
|
+
: { result, outboundPublishEvent };
|
|
591
|
+
}
|
|
592
|
+
buildPublishError(sendResult, eventResult, outboundPublishEvent) {
|
|
593
|
+
const baseReason = sendResult.status === 'rejected' ? sendResult.reason : eventResult.reason;
|
|
594
|
+
const error = baseReason instanceof Error ? baseReason : new Error(String(baseReason));
|
|
595
|
+
error.outboundPublishEvent = outboundPublishEvent;
|
|
596
|
+
error.sendToFlexPLMResult = sendResult.status === 'fulfilled'
|
|
597
|
+
? sendResult.value
|
|
598
|
+
: { error: sendResult.reason?.message ?? String(sendResult.reason) };
|
|
599
|
+
error.sendPublishPayloadEventResult = eventResult.status === 'fulfilled'
|
|
600
|
+
? eventResult.value
|
|
601
|
+
: { error: eventResult.reason?.message ?? String(eventResult.reason) };
|
|
602
|
+
return error;
|
|
580
603
|
}
|
|
581
604
|
async saveToLocalFile(events, eventType) {
|
|
582
605
|
let results = {};
|
|
@@ -588,15 +611,16 @@ class BaseProcessPublishAssortment {
|
|
|
588
611
|
const eventDirName = 'events-output';
|
|
589
612
|
const fileName = `${path.sep}${eventDirName}${path.sep}events-${dateString}.json`;
|
|
590
613
|
fileHandle = await fsPromise.open('.' + fileName, 'a');
|
|
591
|
-
const
|
|
614
|
+
const outboundPublishEvent = {
|
|
592
615
|
taskId: this.config.taskId,
|
|
593
616
|
eventType,
|
|
594
617
|
objectClass: 'LCSSeason',
|
|
595
618
|
events
|
|
596
619
|
};
|
|
597
|
-
await fileHandle.writeFile(JSON.stringify(
|
|
620
|
+
await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
|
|
598
621
|
results = {
|
|
599
622
|
message: 'Successfully Saved File',
|
|
623
|
+
outboundPublishEvent,
|
|
600
624
|
fileLocation: dirName + fileName
|
|
601
625
|
};
|
|
602
626
|
}
|
|
@@ -612,7 +636,7 @@ class BaseProcessPublishAssortment {
|
|
|
612
636
|
const eventBuffer = Buffer.from(JSON.stringify(events), 'utf-8');
|
|
613
637
|
const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
|
|
614
638
|
const uploadFile = await new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
|
|
615
|
-
const
|
|
639
|
+
const outboundPublishEvent = {
|
|
616
640
|
taskId: this.config.taskId,
|
|
617
641
|
eventType,
|
|
618
642
|
objectClass: 'LCSSeason',
|
|
@@ -622,15 +646,46 @@ class BaseProcessPublishAssortment {
|
|
|
622
646
|
};
|
|
623
647
|
if (sendMode === 'vibeiqfile') {
|
|
624
648
|
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
625
|
-
|
|
649
|
+
const [sendResult, eventResult] = await Promise.allSettled([
|
|
650
|
+
flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
|
|
651
|
+
this.sendPublishPayloadEvent(outboundPublishEvent)
|
|
652
|
+
]);
|
|
653
|
+
if (sendResult.status === 'rejected' || eventResult.status === 'rejected') {
|
|
654
|
+
throw this.buildPublishError(sendResult, eventResult, outboundPublishEvent);
|
|
655
|
+
}
|
|
656
|
+
const result = sendResult.value;
|
|
657
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
658
|
+
return isResultObject
|
|
659
|
+
? { ...result, outboundPublishEvent }
|
|
660
|
+
: { result, outboundPublishEvent };
|
|
626
661
|
}
|
|
627
662
|
else {
|
|
663
|
+
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
628
664
|
return {
|
|
629
665
|
message: 'Successfully Uploaded File.',
|
|
630
|
-
|
|
666
|
+
outboundPublishEvent
|
|
631
667
|
};
|
|
632
668
|
}
|
|
633
669
|
}
|
|
670
|
+
async sendPublishPayloadEvent(outboundPublishEvent) {
|
|
671
|
+
console.info('sendPublishPayloadEvent()');
|
|
672
|
+
let initialEvent = {};
|
|
673
|
+
if (this.config?.event) {
|
|
674
|
+
initialEvent = (typeof this.config?.event === 'string')
|
|
675
|
+
? JSON.parse(this.config?.event)
|
|
676
|
+
: this.config?.event;
|
|
677
|
+
}
|
|
678
|
+
const eventBody = {
|
|
679
|
+
originSystemType: 'VibeIQ',
|
|
680
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
681
|
+
outboundPublishEvent,
|
|
682
|
+
initialEvent
|
|
683
|
+
};
|
|
684
|
+
await new sdk_1.Entities().create({
|
|
685
|
+
entityName: 'external-event',
|
|
686
|
+
object: eventBody
|
|
687
|
+
});
|
|
688
|
+
}
|
|
634
689
|
getCurrentDateString() {
|
|
635
690
|
const d = new Date();
|
|
636
691
|
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,195 @@ 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('should merge outboundPublishEvent into result and call 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('sendToFlexPLM throws when flexPLMConnect.sendToFlexPLM fails, attaching outboundPublishEvent and both results', async () => {
|
|
1742
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1743
|
+
const flexError = new Error('flex failed');
|
|
1744
|
+
const eventResponse = { eventOk: true };
|
|
1745
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1746
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockResolvedValue(eventResponse);
|
|
1747
|
+
await expect(bppa.sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
1748
|
+
message: 'flex failed',
|
|
1749
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType, objectClass: 'LCSSeason', events }),
|
|
1750
|
+
sendToFlexPLMResult: { error: 'flex failed' },
|
|
1751
|
+
sendPublishPayloadEventResult: eventResponse
|
|
1752
|
+
});
|
|
1753
|
+
});
|
|
1754
|
+
it('sendToFlexPLM throws when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
1755
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1756
|
+
const flexResponse = { status: 200 };
|
|
1757
|
+
const eventError = new Error('event failed');
|
|
1758
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse);
|
|
1759
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1760
|
+
await expect(bppa.sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
1761
|
+
message: 'event failed',
|
|
1762
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType }),
|
|
1763
|
+
sendToFlexPLMResult: flexResponse,
|
|
1764
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
1765
|
+
});
|
|
1766
|
+
});
|
|
1767
|
+
it('sendToFlexPLM throws the flexPLMConnect error when both fail', async () => {
|
|
1768
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1769
|
+
const flexError = new Error('flex failed');
|
|
1770
|
+
const eventError = new Error('event failed');
|
|
1771
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1772
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1773
|
+
await expect(bppa.sendToFlexPLM(events, eventType)).rejects.toBe(flexError);
|
|
1774
|
+
expect(flexError.outboundPublishEvent).toBeDefined();
|
|
1775
|
+
expect(flexError.sendToFlexPLMResult).toEqual({ error: 'flex failed' });
|
|
1776
|
+
expect(flexError.sendPublishPayloadEventResult).toEqual({ error: 'event failed' });
|
|
1777
|
+
});
|
|
1778
|
+
it('handleVibeIQFile (vibeiqfile) throws when flexPLMConnect.sendToFlexPLM fails, with both results attached', async () => {
|
|
1779
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1780
|
+
const flexError = new Error('flex failed');
|
|
1781
|
+
const eventResponse = { eventOk: true };
|
|
1782
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1783
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockResolvedValue(eventResponse);
|
|
1784
|
+
await expect(bppa.handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
1785
|
+
message: 'flex failed',
|
|
1786
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
1787
|
+
sendToFlexPLMResult: { error: 'flex failed' },
|
|
1788
|
+
sendPublishPayloadEventResult: eventResponse
|
|
1789
|
+
});
|
|
1790
|
+
});
|
|
1791
|
+
it('handleVibeIQFile (vibeiqfile) throws when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
1792
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1793
|
+
const flexResponse = { status: 200 };
|
|
1794
|
+
const eventError = new Error('event failed');
|
|
1795
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse);
|
|
1796
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1797
|
+
await expect(bppa.handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
1798
|
+
message: 'event failed',
|
|
1799
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
1800
|
+
sendToFlexPLMResult: flexResponse,
|
|
1801
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
1802
|
+
});
|
|
1803
|
+
});
|
|
1804
|
+
it('handleVibeIQFile (vibeiqfile) throws the flexPLMConnect error when both fail', async () => {
|
|
1805
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1806
|
+
const flexError = new Error('flex failed');
|
|
1807
|
+
const eventError = new Error('event failed');
|
|
1808
|
+
jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
1809
|
+
jest.spyOn(bppa, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
1810
|
+
await expect(bppa.handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toBe(flexError);
|
|
1811
|
+
expect(flexError.sendToFlexPLMResult).toEqual({ error: 'flex failed' });
|
|
1812
|
+
expect(flexError.sendPublishPayloadEventResult).toEqual({ error: 'event failed' });
|
|
1813
|
+
});
|
|
1814
|
+
it('should merge outboundPublishEvent into FlexPLM result and call sendPublishPayloadEvent when mode is vibeiqfile', async () => {
|
|
1815
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1816
|
+
const flexResponse = { status: 200, data: { ok: true } };
|
|
1817
|
+
const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
1818
|
+
.mockResolvedValue(flexResponse);
|
|
1819
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
|
|
1820
|
+
.mockResolvedValue(undefined);
|
|
1821
|
+
const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile');
|
|
1822
|
+
expect(fileUploadCalls).toHaveLength(1);
|
|
1823
|
+
expect(fileUploadCalls[0].fileName).toBe('ASYNC_PUBLISH_SEASON-events.json');
|
|
1824
|
+
expect(fileUploadCalls[0].mimeType).toBe('application/json');
|
|
1825
|
+
const passedOutboundPublishEvent = spyFlex.mock.calls[0][0];
|
|
1826
|
+
expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
|
|
1827
|
+
expect(passedOutboundPublishEvent.eventType).toBe(eventType);
|
|
1828
|
+
expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
|
|
1829
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
1830
|
+
expect(passedOutboundPublishEvent.eventsDownloadLink).toBe('https://download.url');
|
|
1831
|
+
expect(passedOutboundPublishEvent.eventsAdminDownloadLink).toBe('https://admin.download.url');
|
|
1832
|
+
expect(spyFlex).toHaveBeenCalledTimes(1);
|
|
1833
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
1834
|
+
expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
|
|
1835
|
+
expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
|
|
1836
|
+
});
|
|
1837
|
+
it('should skip FlexPLM but still call sendPublishPayloadEvent when mode is vibeiqfile-dontsendtoflexplm', async () => {
|
|
1838
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1839
|
+
const spyFlex = jest.spyOn(flexplm_connect_1.FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
1840
|
+
.mockResolvedValue({});
|
|
1841
|
+
const spyEvent = jest.spyOn(bppa, 'sendPublishPayloadEvent')
|
|
1842
|
+
.mockResolvedValue(undefined);
|
|
1843
|
+
const result = await bppa.handleVibeIQFile(events, eventType, 'vibeiqfile-dontsendtoflexplm');
|
|
1844
|
+
expect(spyFlex).not.toHaveBeenCalled();
|
|
1845
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
1846
|
+
const passedOutboundPublishEvent = spyEvent.mock.calls[0][0];
|
|
1847
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
1848
|
+
expect(result).toEqual({
|
|
1849
|
+
message: 'Successfully Uploaded File.',
|
|
1850
|
+
outboundPublishEvent: passedOutboundPublishEvent
|
|
1851
|
+
});
|
|
1852
|
+
});
|
|
1853
|
+
it('should create an external-event with initialEvent parsed from config', async () => {
|
|
1854
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1855
|
+
const outboundPublishEvent = { foo: 'bar' };
|
|
1856
|
+
await bppa.sendPublishPayloadEvent(outboundPublishEvent);
|
|
1857
|
+
expect(createCallArg).toEqual({
|
|
1858
|
+
entityName: 'external-event',
|
|
1859
|
+
object: {
|
|
1860
|
+
originSystemType: 'VibeIQ',
|
|
1861
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
1862
|
+
outboundPublishEvent,
|
|
1863
|
+
initialEvent: { sourceEventId: 'src-1' }
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
});
|
|
1867
|
+
it('should default initialEvent to {} when config has no event', async () => {
|
|
1868
|
+
const bareConfig = { taskId: 'task-x' };
|
|
1869
|
+
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(bareConfig, dc, mapFileUtil);
|
|
1870
|
+
const outboundPublishEvent = { hello: 'world' };
|
|
1871
|
+
await bppa.sendPublishPayloadEvent(outboundPublishEvent);
|
|
1872
|
+
expect(createCallArg).toEqual({
|
|
1873
|
+
entityName: 'external-event',
|
|
1874
|
+
object: {
|
|
1875
|
+
originSystemType: 'VibeIQ',
|
|
1876
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
1877
|
+
outboundPublishEvent,
|
|
1878
|
+
initialEvent: {}
|
|
1879
|
+
}
|
|
1880
|
+
});
|
|
1881
|
+
});
|
|
1882
|
+
});
|
package/package.json
CHANGED
|
@@ -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,238 @@ 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('should merge outboundPublishEvent into result and call 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 as any, '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('sendToFlexPLM throws when flexPLMConnect.sendToFlexPLM fails, attaching outboundPublishEvent and both results', async () => {
|
|
2071
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2072
|
+
const flexError = new Error('flex failed');
|
|
2073
|
+
const eventResponse = { eventOk: true };
|
|
2074
|
+
|
|
2075
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
2076
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockResolvedValue(eventResponse as any);
|
|
2077
|
+
|
|
2078
|
+
await expect((bppa as any).sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
2079
|
+
message: 'flex failed',
|
|
2080
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType, objectClass: 'LCSSeason', events }),
|
|
2081
|
+
sendToFlexPLMResult: { error: 'flex failed' },
|
|
2082
|
+
sendPublishPayloadEventResult: eventResponse
|
|
2083
|
+
});
|
|
2084
|
+
});
|
|
2085
|
+
|
|
2086
|
+
it('sendToFlexPLM throws when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
2087
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2088
|
+
const flexResponse = { status: 200 };
|
|
2089
|
+
const eventError = new Error('event failed');
|
|
2090
|
+
|
|
2091
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse as any);
|
|
2092
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
2093
|
+
|
|
2094
|
+
await expect((bppa as any).sendToFlexPLM(events, eventType)).rejects.toMatchObject({
|
|
2095
|
+
message: 'event failed',
|
|
2096
|
+
outboundPublishEvent: expect.objectContaining({ taskId: 'task-abc', eventType }),
|
|
2097
|
+
sendToFlexPLMResult: flexResponse,
|
|
2098
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
2099
|
+
});
|
|
2100
|
+
});
|
|
2101
|
+
|
|
2102
|
+
it('sendToFlexPLM throws the flexPLMConnect error when both fail', async () => {
|
|
2103
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2104
|
+
const flexError = new Error('flex failed');
|
|
2105
|
+
const eventError = new Error('event failed');
|
|
2106
|
+
|
|
2107
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
2108
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
2109
|
+
|
|
2110
|
+
await expect((bppa as any).sendToFlexPLM(events, eventType)).rejects.toBe(flexError);
|
|
2111
|
+
expect((flexError as any).outboundPublishEvent).toBeDefined();
|
|
2112
|
+
expect((flexError as any).sendToFlexPLMResult).toEqual({ error: 'flex failed' });
|
|
2113
|
+
expect((flexError as any).sendPublishPayloadEventResult).toEqual({ error: 'event failed' });
|
|
2114
|
+
});
|
|
2115
|
+
|
|
2116
|
+
it('handleVibeIQFile (vibeiqfile) throws when flexPLMConnect.sendToFlexPLM fails, with both results attached', async () => {
|
|
2117
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2118
|
+
const flexError = new Error('flex failed');
|
|
2119
|
+
const eventResponse = { eventOk: true };
|
|
2120
|
+
|
|
2121
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
2122
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockResolvedValue(eventResponse as any);
|
|
2123
|
+
|
|
2124
|
+
await expect((bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
2125
|
+
message: 'flex failed',
|
|
2126
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
2127
|
+
sendToFlexPLMResult: { error: 'flex failed' },
|
|
2128
|
+
sendPublishPayloadEventResult: eventResponse
|
|
2129
|
+
});
|
|
2130
|
+
});
|
|
2131
|
+
|
|
2132
|
+
it('handleVibeIQFile (vibeiqfile) throws when sendPublishPayloadEvent fails, with flex result attached', async () => {
|
|
2133
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2134
|
+
const flexResponse = { status: 200 };
|
|
2135
|
+
const eventError = new Error('event failed');
|
|
2136
|
+
|
|
2137
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockResolvedValue(flexResponse as any);
|
|
2138
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
2139
|
+
|
|
2140
|
+
await expect((bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toMatchObject({
|
|
2141
|
+
message: 'event failed',
|
|
2142
|
+
outboundPublishEvent: expect.objectContaining({ eventsFileId: 'file-123' }),
|
|
2143
|
+
sendToFlexPLMResult: flexResponse,
|
|
2144
|
+
sendPublishPayloadEventResult: { error: 'event failed' }
|
|
2145
|
+
});
|
|
2146
|
+
});
|
|
2147
|
+
|
|
2148
|
+
it('handleVibeIQFile (vibeiqfile) throws the flexPLMConnect error when both fail', async () => {
|
|
2149
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2150
|
+
const flexError = new Error('flex failed');
|
|
2151
|
+
const eventError = new Error('event failed');
|
|
2152
|
+
|
|
2153
|
+
jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM').mockRejectedValue(flexError);
|
|
2154
|
+
jest.spyOn(bppa as any, 'sendPublishPayloadEvent').mockRejectedValue(eventError);
|
|
2155
|
+
|
|
2156
|
+
await expect((bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile')).rejects.toBe(flexError);
|
|
2157
|
+
expect((flexError as any).sendToFlexPLMResult).toEqual({ error: 'flex failed' });
|
|
2158
|
+
expect((flexError as any).sendPublishPayloadEventResult).toEqual({ error: 'event failed' });
|
|
2159
|
+
});
|
|
2160
|
+
|
|
2161
|
+
it('should merge outboundPublishEvent into FlexPLM result and call sendPublishPayloadEvent when mode is vibeiqfile', async () => {
|
|
2162
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2163
|
+
const flexResponse = { status: 200, data: { ok: true } };
|
|
2164
|
+
|
|
2165
|
+
const spyFlex = jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
2166
|
+
.mockResolvedValue(flexResponse as any);
|
|
2167
|
+
const spyEvent = jest.spyOn(bppa as any, 'sendPublishPayloadEvent')
|
|
2168
|
+
.mockResolvedValue(undefined as any);
|
|
2169
|
+
|
|
2170
|
+
const result = await (bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile');
|
|
2171
|
+
|
|
2172
|
+
expect(fileUploadCalls).toHaveLength(1);
|
|
2173
|
+
expect(fileUploadCalls[0].fileName).toBe('ASYNC_PUBLISH_SEASON-events.json');
|
|
2174
|
+
expect(fileUploadCalls[0].mimeType).toBe('application/json');
|
|
2175
|
+
|
|
2176
|
+
const passedOutboundPublishEvent = spyFlex.mock.calls[0][0] as any;
|
|
2177
|
+
expect(passedOutboundPublishEvent.taskId).toBe('task-abc');
|
|
2178
|
+
expect(passedOutboundPublishEvent.eventType).toBe(eventType);
|
|
2179
|
+
expect(passedOutboundPublishEvent.objectClass).toBe('LCSSeason');
|
|
2180
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
2181
|
+
expect(passedOutboundPublishEvent.eventsDownloadLink).toBe('https://download.url');
|
|
2182
|
+
expect(passedOutboundPublishEvent.eventsAdminDownloadLink).toBe('https://admin.download.url');
|
|
2183
|
+
|
|
2184
|
+
expect(spyFlex).toHaveBeenCalledTimes(1);
|
|
2185
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
2186
|
+
expect(spyEvent).toHaveBeenCalledWith(passedOutboundPublishEvent);
|
|
2187
|
+
expect(result).toEqual({ ...flexResponse, outboundPublishEvent: passedOutboundPublishEvent });
|
|
2188
|
+
});
|
|
2189
|
+
|
|
2190
|
+
it('should skip FlexPLM but still call sendPublishPayloadEvent when mode is vibeiqfile-dontsendtoflexplm', async () => {
|
|
2191
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2192
|
+
|
|
2193
|
+
const spyFlex = jest.spyOn(FlexPLMConnect.prototype, 'sendToFlexPLM')
|
|
2194
|
+
.mockResolvedValue({} as any);
|
|
2195
|
+
const spyEvent = jest.spyOn(bppa as any, 'sendPublishPayloadEvent')
|
|
2196
|
+
.mockResolvedValue(undefined as any);
|
|
2197
|
+
|
|
2198
|
+
const result = await (bppa as any).handleVibeIQFile(events, eventType, 'vibeiqfile-dontsendtoflexplm');
|
|
2199
|
+
|
|
2200
|
+
expect(spyFlex).not.toHaveBeenCalled();
|
|
2201
|
+
expect(spyEvent).toHaveBeenCalledTimes(1);
|
|
2202
|
+
|
|
2203
|
+
const passedOutboundPublishEvent = spyEvent.mock.calls[0][0] as any;
|
|
2204
|
+
expect(passedOutboundPublishEvent.eventsFileId).toBe('file-123');
|
|
2205
|
+
expect(result).toEqual({
|
|
2206
|
+
message: 'Successfully Uploaded File.',
|
|
2207
|
+
outboundPublishEvent: passedOutboundPublishEvent
|
|
2208
|
+
});
|
|
2209
|
+
});
|
|
2210
|
+
|
|
2211
|
+
it('should create an external-event with initialEvent parsed from config', async () => {
|
|
2212
|
+
const bppa = new BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
2213
|
+
const outboundPublishEvent = { foo: 'bar' };
|
|
2214
|
+
|
|
2215
|
+
await (bppa as any).sendPublishPayloadEvent(outboundPublishEvent);
|
|
2216
|
+
|
|
2217
|
+
expect(createCallArg).toEqual({
|
|
2218
|
+
entityName: 'external-event',
|
|
2219
|
+
object: {
|
|
2220
|
+
originSystemType: 'VibeIQ',
|
|
2221
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
2222
|
+
outboundPublishEvent,
|
|
2223
|
+
initialEvent: { sourceEventId: 'src-1' }
|
|
2224
|
+
}
|
|
2225
|
+
});
|
|
2226
|
+
});
|
|
2227
|
+
|
|
2228
|
+
it('should default initialEvent to {} when config has no event', async () => {
|
|
2229
|
+
const bareConfig = { taskId: 'task-x' } as unknown as FCConfig;
|
|
2230
|
+
const bppa = new BaseProcessPublishAssortment(bareConfig, dc, mapFileUtil);
|
|
2231
|
+
const outboundPublishEvent = { hello: 'world' };
|
|
2232
|
+
|
|
2233
|
+
await (bppa as any).sendPublishPayloadEvent(outboundPublishEvent);
|
|
2234
|
+
|
|
2235
|
+
expect(createCallArg).toEqual({
|
|
2236
|
+
entityName: 'external-event',
|
|
2237
|
+
object: {
|
|
2238
|
+
originSystemType: 'VibeIQ',
|
|
2239
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
2240
|
+
outboundPublishEvent,
|
|
2241
|
+
initialEvent: {}
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
});
|
|
1992
2245
|
});
|
|
@@ -685,7 +685,7 @@ export class BaseProcessPublishAssortment {
|
|
|
685
685
|
}
|
|
686
686
|
|
|
687
687
|
private async sendToFlexPLM(events: SeasonalPayload[], eventType: string) {
|
|
688
|
-
const
|
|
688
|
+
const outboundPublishEvent: AsyncEventsPayloadType = {
|
|
689
689
|
taskId: this.config.taskId,
|
|
690
690
|
eventType,
|
|
691
691
|
objectClass: 'LCSSeason',
|
|
@@ -693,7 +693,37 @@ export class BaseProcessPublishAssortment {
|
|
|
693
693
|
};
|
|
694
694
|
|
|
695
695
|
const flexPLMConnect = new FlexPLMConnect(this.config);
|
|
696
|
-
|
|
696
|
+
const [sendResult, eventResult] = await Promise.allSettled([
|
|
697
|
+
flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
|
|
698
|
+
this.sendPublishPayloadEvent(outboundPublishEvent)
|
|
699
|
+
]);
|
|
700
|
+
|
|
701
|
+
if (sendResult.status === 'rejected' || eventResult.status === 'rejected') {
|
|
702
|
+
throw this.buildPublishError(sendResult, eventResult, outboundPublishEvent);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const result = sendResult.value;
|
|
706
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
707
|
+
return isResultObject
|
|
708
|
+
? { ...result, outboundPublishEvent }
|
|
709
|
+
: { result, outboundPublishEvent };
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private buildPublishError(
|
|
713
|
+
sendResult: PromiseSettledResult<any>,
|
|
714
|
+
eventResult: PromiseSettledResult<any>,
|
|
715
|
+
outboundPublishEvent: AsyncEventsPayloadType
|
|
716
|
+
): Error {
|
|
717
|
+
const baseReason = sendResult.status === 'rejected' ? sendResult.reason : (eventResult as PromiseRejectedResult).reason;
|
|
718
|
+
const error: any = baseReason instanceof Error ? baseReason : new Error(String(baseReason));
|
|
719
|
+
error.outboundPublishEvent = outboundPublishEvent;
|
|
720
|
+
error.sendToFlexPLMResult = sendResult.status === 'fulfilled'
|
|
721
|
+
? sendResult.value
|
|
722
|
+
: { error: sendResult.reason?.message ?? String(sendResult.reason) };
|
|
723
|
+
error.sendPublishPayloadEventResult = eventResult.status === 'fulfilled'
|
|
724
|
+
? eventResult.value
|
|
725
|
+
: { error: eventResult.reason?.message ?? String(eventResult.reason) };
|
|
726
|
+
return error;
|
|
697
727
|
}
|
|
698
728
|
|
|
699
729
|
private async saveToLocalFile(events: SeasonalPayload[], eventType: string) {
|
|
@@ -708,17 +738,18 @@ export class BaseProcessPublishAssortment {
|
|
|
708
738
|
const fileName = `${path.sep}${eventDirName}${path.sep}events-${dateString}.json`;
|
|
709
739
|
fileHandle = await fsPromise.open('.' + fileName, 'a');
|
|
710
740
|
|
|
711
|
-
const
|
|
741
|
+
const outboundPublishEvent: AsyncEventsPayloadType = {
|
|
712
742
|
taskId: this.config.taskId,
|
|
713
743
|
eventType,
|
|
714
744
|
objectClass: 'LCSSeason',
|
|
715
745
|
events
|
|
716
746
|
};
|
|
717
747
|
|
|
718
|
-
await fileHandle.writeFile(JSON.stringify(
|
|
748
|
+
await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
|
|
719
749
|
|
|
720
750
|
results = {
|
|
721
751
|
message: 'Successfully Saved File',
|
|
752
|
+
outboundPublishEvent,
|
|
722
753
|
fileLocation: dirName + fileName
|
|
723
754
|
};
|
|
724
755
|
} catch (e) {
|
|
@@ -735,26 +766,62 @@ export class BaseProcessPublishAssortment {
|
|
|
735
766
|
const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
|
|
736
767
|
const uploadFile = await new Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
|
|
737
768
|
|
|
738
|
-
const
|
|
769
|
+
const outboundPublishEvent: AsyncEventsPayloadType = {
|
|
739
770
|
taskId: this.config.taskId,
|
|
740
771
|
eventType,
|
|
741
772
|
objectClass: 'LCSSeason',
|
|
742
773
|
eventsFileId: uploadFile.id,
|
|
743
774
|
eventsDownloadLink: uploadFile.downloadUrl,
|
|
744
775
|
eventsAdminDownloadLink: uploadFile.adminDownloadUrl
|
|
745
|
-
};
|
|
776
|
+
};
|
|
746
777
|
|
|
747
778
|
if (sendMode === 'vibeiqfile') {
|
|
748
779
|
const flexPLMConnect = new FlexPLMConnect(this.config);
|
|
749
|
-
|
|
780
|
+
const [sendResult, eventResult] = await Promise.allSettled([
|
|
781
|
+
flexPLMConnect.sendToFlexPLM(outboundPublishEvent),
|
|
782
|
+
this.sendPublishPayloadEvent(outboundPublishEvent)
|
|
783
|
+
]);
|
|
784
|
+
|
|
785
|
+
if (sendResult.status === 'rejected' || eventResult.status === 'rejected') {
|
|
786
|
+
throw this.buildPublishError(sendResult, eventResult, outboundPublishEvent);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const result = sendResult.value;
|
|
790
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
791
|
+
return isResultObject
|
|
792
|
+
? { ...result, outboundPublishEvent }
|
|
793
|
+
: { result, outboundPublishEvent };
|
|
750
794
|
} else {
|
|
795
|
+
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
751
796
|
return {
|
|
752
797
|
message: 'Successfully Uploaded File.',
|
|
753
|
-
|
|
798
|
+
outboundPublishEvent
|
|
754
799
|
};
|
|
755
800
|
}
|
|
756
801
|
}
|
|
757
802
|
|
|
803
|
+
private async sendPublishPayloadEvent(outboundPublishEvent: AsyncEventsPayloadType){
|
|
804
|
+
console.info('sendPublishPayloadEvent()');
|
|
805
|
+
let initialEvent = {};
|
|
806
|
+
if (this.config?.event){
|
|
807
|
+
initialEvent = (typeof this.config?.event === 'string')
|
|
808
|
+
? JSON.parse(this.config?.event)
|
|
809
|
+
: this.config?.event;
|
|
810
|
+
}
|
|
811
|
+
const eventBody = {
|
|
812
|
+
originSystemType: 'VibeIQ',
|
|
813
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
814
|
+
outboundPublishEvent,
|
|
815
|
+
initialEvent
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
await new Entities().create({
|
|
819
|
+
entityName: 'external-event',
|
|
820
|
+
object: eventBody
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
|
|
758
825
|
private getCurrentDateString() {
|
|
759
826
|
const d = new Date();
|
|
760
827
|
return '' + d.getUTCFullYear()
|