@contrail/flexplm 1.8.1-alpha.85853aa → 2.0.0-alpha.c9d1df5
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/lib/__tests__/telemetry-test-utils.d.ts +8 -0
- package/lib/__tests__/telemetry-test-utils.js +30 -0
- package/lib/cli/commands/compile.js +17 -7
- package/lib/cli/commands/compile.spec.js +17 -7
- package/lib/cli/commands/create.js +17 -7
- package/lib/cli/commands/create.spec.js +17 -7
- package/lib/cli/commands/upload.js +17 -7
- package/lib/cli/index.js +2 -2
- package/lib/entity-processor/base-entity-processor.d.ts +29 -0
- package/lib/entity-processor/base-entity-processor.js +238 -143
- package/lib/entity-processor/base-entity-processor.spec.js +210 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/publish/base-process-publish-assortment-callback.js +30 -0
- package/lib/publish/base-process-publish-assortment-callback.spec.d.ts +1 -0
- package/lib/publish/base-process-publish-assortment-callback.spec.js +62 -0
- package/lib/publish/base-process-publish-assortment.d.ts +24 -0
- package/lib/publish/base-process-publish-assortment.js +238 -132
- package/lib/publish/base-process-publish-assortment.spec.js +188 -0
- package/lib/util/error-response-object.js +2 -0
- package/lib/util/event-short-message-status.js +1 -1
- package/lib/util/flexplm-connect.d.ts +4 -0
- package/lib/util/flexplm-connect.js +210 -145
- package/lib/util/flexplm-connect.telemetry.spec.d.ts +1 -0
- package/lib/util/flexplm-connect.telemetry.spec.js +212 -0
- package/lib/util/logger-config.js +1 -2
- package/lib/util/telemetry-attributes.d.ts +68 -0
- package/lib/util/telemetry-attributes.js +73 -0
- package/lib/util/telemetry-utils.d.ts +3 -0
- package/lib/util/telemetry-utils.js +10 -0
- package/lib/util/thumbnail-util.d.ts +2 -1
- package/lib/util/thumbnail-util.js +35 -7
- package/lib/util/thumbnail-util.spec.js +42 -0
- package/package.json +10 -3
|
@@ -11,6 +11,12 @@ const fsPromise = require("fs/promises");
|
|
|
11
11
|
const path = require("path");
|
|
12
12
|
const app_framework_1 = require("@contrail/app-framework");
|
|
13
13
|
const event_short_message_status_1 = require("../util/event-short-message-status");
|
|
14
|
+
const telemetry_1 = require("@contrail/telemetry");
|
|
15
|
+
const api_1 = require("@opentelemetry/api");
|
|
16
|
+
const telemetry_attributes_1 = require("../util/telemetry-attributes");
|
|
17
|
+
const telemetry_utils_1 = require("../util/telemetry-utils");
|
|
18
|
+
const PUBLISH_FILE_HYDRATED_DETAIL = 'hydrated_detail';
|
|
19
|
+
const PUBLISH_FILE_BASELINE = 'baseline';
|
|
14
20
|
class BaseProcessPublishAssortment {
|
|
15
21
|
constructor(_config, _dc, _mapFileUtil) {
|
|
16
22
|
this.TTL = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
@@ -24,61 +30,119 @@ class BaseProcessPublishAssortment {
|
|
|
24
30
|
this.orgSlug = this.config?.orgSlug || 'unset-orgSlug';
|
|
25
31
|
}
|
|
26
32
|
async process(event) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
return (0, telemetry_1.traceSection)('publish_assortment', {}, async (span) => {
|
|
34
|
+
const assortmentPublishChangeId = event.assortmentPublishChangeId;
|
|
35
|
+
let apcHistory;
|
|
36
|
+
let publisher;
|
|
37
|
+
const assortmentId = event.assortmentId;
|
|
38
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({
|
|
39
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_ASSORTMENT_ID]: assortmentId,
|
|
40
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGE_ID]: assortmentPublishChangeId,
|
|
41
|
+
});
|
|
35
42
|
try {
|
|
36
|
-
seasonFed
|
|
43
|
+
let seasonFed;
|
|
44
|
+
try {
|
|
45
|
+
seasonFed = await this.getSeasonFederation(assortmentId);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
const message = e.message;
|
|
49
|
+
const eventStatus = (message.includes(BaseProcessPublishAssortment.ASSORTMENT_NOT_PUBLISHABLE)) ? event_short_message_status_1.EventShortMessageStatus.NOT_PUBLISHABLE :
|
|
50
|
+
(message.startsWith(BaseProcessPublishAssortment.ASSORTMENT_NO_FED_INFO)) ? event_short_message_status_1.EventShortMessageStatus.NO_FEDERATION_INFO :
|
|
51
|
+
event_short_message_status_1.EventShortMessageStatus.FAILURE;
|
|
52
|
+
if (eventStatus === event_short_message_status_1.EventShortMessageStatus.FAILURE) {
|
|
53
|
+
span.recordException(e);
|
|
54
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message });
|
|
55
|
+
}
|
|
56
|
+
this.recordPublishStatus({
|
|
57
|
+
status: eventStatus,
|
|
58
|
+
assortmentId,
|
|
59
|
+
assortmentPublishChangeId,
|
|
60
|
+
message,
|
|
61
|
+
// Only an unexpected error is swallowed here; the other two are expected skips.
|
|
62
|
+
error: eventStatus === event_short_message_status_1.EventShortMessageStatus.FAILURE ? e : undefined,
|
|
63
|
+
});
|
|
64
|
+
const output = {
|
|
65
|
+
results: { message, event },
|
|
66
|
+
skip_await: true
|
|
67
|
+
};
|
|
68
|
+
return output;
|
|
69
|
+
}
|
|
70
|
+
apcHistory = await this.getApcHistory(assortmentId);
|
|
71
|
+
const sinceDate = await this.getSinceDate(assortmentId, assortmentPublishChangeId, apcHistory);
|
|
72
|
+
//Get detail information
|
|
73
|
+
const assortmentPublishChange = await this.downloadAssortmentPublishChange(assortmentId, assortmentPublishChangeId);
|
|
74
|
+
publisher = this.getPublisher(assortmentPublishChange);
|
|
75
|
+
const changeDetail = await this.downloadHydratedChangeDetail(assortmentPublishChange);
|
|
76
|
+
// Without the change detail the counts are unknown, not zero; failed_downloads says why.
|
|
77
|
+
if (changeDetail) {
|
|
78
|
+
span.setAttributes({
|
|
79
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_ADDED_COUNT]: changeDetail.adds?.length ?? 0,
|
|
80
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_REMOVED_COUNT]: changeDetail.deletes?.length ?? 0,
|
|
81
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGED_COUNT]: changeDetail.updates?.length ?? 0,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const assortmentBaseline = await this.downloadAssortmentBaseline(assortmentPublishChange);
|
|
85
|
+
const failedDownloads = [!changeDetail && PUBLISH_FILE_HYDRATED_DETAIL, !assortmentBaseline && PUBLISH_FILE_BASELINE].filter(Boolean);
|
|
86
|
+
if (failedDownloads.length > 0) {
|
|
87
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_FAILED_DOWNLOADS, failedDownloads);
|
|
88
|
+
}
|
|
89
|
+
const deleteChanges = await this.getDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate);
|
|
90
|
+
const releasedForDevelopmentItemIds = this.getReleasedForDevelopmentItemAndFamilyIds(assortmentBaseline, deleteChanges);
|
|
91
|
+
const itemToFederatedIdMapping = await this.getItemFederatedIds( /*allItemIds*/);
|
|
92
|
+
const pcd = new publish_change_data_1.PublishChangeData(assortmentId, seasonFed, assortmentPublishChangeId, sinceDate, publisher);
|
|
93
|
+
pcd.itemToFederatedIdMapping = itemToFederatedIdMapping;
|
|
94
|
+
pcd.releasedForDevelopmentItemIds = releasedForDevelopmentItemIds;
|
|
95
|
+
const output = await this.processPublish(pcd, changeDetail, assortmentBaseline, deleteChanges);
|
|
96
|
+
output['publishInfo'] = await this.getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher);
|
|
97
|
+
return output;
|
|
37
98
|
}
|
|
38
99
|
catch (e) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return output;
|
|
100
|
+
try {
|
|
101
|
+
const publishInfo = await this.getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher);
|
|
102
|
+
e.publishInfo = publishInfo;
|
|
103
|
+
}
|
|
104
|
+
catch (e2) {
|
|
105
|
+
telemetry_1.logger.error({ error: e2, assortment: { id: assortmentId, publish_change_id: assortmentPublishChangeId } }, 'getPublishInfo failed');
|
|
106
|
+
}
|
|
107
|
+
this.recordPublishStatus({
|
|
108
|
+
status: event_short_message_status_1.EventShortMessageStatus.FAILURE, assortmentId, assortmentPublishChangeId, error: e,
|
|
109
|
+
// sendAndRecordPublishEvent only sets this after FlexPLM accepted the publish.
|
|
110
|
+
sentUnrecorded: e?.sendPublishPayloadEventResult !== undefined,
|
|
111
|
+
});
|
|
112
|
+
throw e;
|
|
53
113
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Records the result of one assortment publish: attributes on the active span plus one structured log.
|
|
117
|
+
* Not_Publishable / No_Federation_Information are handled skips, so the span stays OK for them.
|
|
118
|
+
*/
|
|
119
|
+
recordPublishStatus(statusObject) {
|
|
120
|
+
const { status, assortmentId, assortmentPublishChangeId, resultsCount, message, error } = statusObject;
|
|
121
|
+
const sentUnrecorded = statusObject.sentUnrecorded || undefined;
|
|
122
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({
|
|
123
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_STATUS]: status,
|
|
124
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_ASSORTMENT_ID]: assortmentId,
|
|
125
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_CHANGE_ID]: assortmentPublishChangeId,
|
|
126
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_PRODUCT_SEASON_COUNT]: resultsCount?.productSeasons,
|
|
127
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_COLORWAY_SEASON_COUNT]: resultsCount?.colorwaySeasons,
|
|
128
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SENT_UNRECORDED]: sentUnrecorded,
|
|
129
|
+
});
|
|
130
|
+
const flexplm = {
|
|
131
|
+
direction: 'publish', status, assortment_id: assortmentId, publish_change_id: assortmentPublishChangeId,
|
|
132
|
+
product_season_count: resultsCount?.productSeasons, colorway_season_count: resultsCount?.colorwaySeasons, reason: message,
|
|
133
|
+
sent_unrecorded: sentUnrecorded,
|
|
134
|
+
};
|
|
135
|
+
if (sentUnrecorded) {
|
|
136
|
+
telemetry_1.logger.error({ error, flexplm }, 'FlexPLM assortment publish sent but not recorded');
|
|
71
137
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
console.error('process failed: assortmentId: ' + assortmentId + ': ' + e.message);
|
|
81
|
-
throw e;
|
|
138
|
+
else if (status === event_short_message_status_1.EventShortMessageStatus.FAILURE) {
|
|
139
|
+
telemetry_1.logger.error({ error, flexplm }, 'FlexPLM assortment publish failed');
|
|
140
|
+
}
|
|
141
|
+
else if (status === event_short_message_status_1.EventShortMessageStatus.NO_FEDERATION_INFO) {
|
|
142
|
+
telemetry_1.logger.warn({ flexplm }, 'FlexPLM assortment publish skipped');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
telemetry_1.logger.info({ flexplm }, 'FlexPLM assortment publish processed');
|
|
82
146
|
}
|
|
83
147
|
}
|
|
84
148
|
async getPublishInfo(assortmentId, assortmentPublishChangeId, apcHistory, publisher) {
|
|
@@ -211,13 +275,18 @@ class BaseProcessPublishAssortment {
|
|
|
211
275
|
return sinceDate;
|
|
212
276
|
}
|
|
213
277
|
async getApcHistory(assortmentId) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
278
|
+
return (0, telemetry_1.traceSection)('get_publish_history', {}, async (span) => {
|
|
279
|
+
const resource = `/assortments/${assortmentId}/history/`;
|
|
280
|
+
const history = await sdk_1.Request.request(resource, {
|
|
281
|
+
method: 'GET',
|
|
282
|
+
headers: {
|
|
283
|
+
Accept: 'application/json',
|
|
284
|
+
'Content-Type': 'application/json'
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
if (Array.isArray(history))
|
|
288
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_HISTORY_COUNT, history.length);
|
|
289
|
+
return history;
|
|
221
290
|
});
|
|
222
291
|
}
|
|
223
292
|
updatedSinceDate(entity, sinceDate) {
|
|
@@ -315,30 +384,42 @@ class BaseProcessPublishAssortment {
|
|
|
315
384
|
});
|
|
316
385
|
}
|
|
317
386
|
async downloadHydratedChangeDetail(assortmentPublishChange) {
|
|
318
|
-
|
|
319
|
-
const link = assortmentPublishChange?.hydratedDetailDownloadLink;
|
|
320
|
-
const response = await fetch(link);
|
|
321
|
-
const data = await response.json();
|
|
322
|
-
return data;
|
|
323
|
-
}
|
|
324
|
-
catch (e) {
|
|
325
|
-
console.error('Error hydratedDetailDownloadLink: ' + e.message);
|
|
326
|
-
}
|
|
327
|
-
return undefined;
|
|
387
|
+
return this.downloadPublishFile(assortmentPublishChange?.hydratedDetailDownloadLink, PUBLISH_FILE_HYDRATED_DETAIL);
|
|
328
388
|
}
|
|
329
389
|
async downloadAssortmentBaseline(assortmentPublishChange) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
390
|
+
return this.downloadPublishFile(assortmentPublishChange?.assortmentBaselineDownloadLink, PUBLISH_FILE_BASELINE);
|
|
391
|
+
}
|
|
392
|
+
/** Downloads one publish file as JSON. Returns undefined when it can't be read, so the publish continues without it;
|
|
393
|
+
* the span is marked ERROR here because nothing is thrown. The link is never recorded (it is a signed URL).
|
|
394
|
+
*/
|
|
395
|
+
async downloadPublishFile(link, file) {
|
|
396
|
+
return (0, telemetry_1.traceSection)('download_publish_file', { [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_FILE]: file }, async (span) => {
|
|
397
|
+
let httpStatus;
|
|
398
|
+
try {
|
|
399
|
+
const response = await fetch(link);
|
|
400
|
+
httpStatus = response.status;
|
|
401
|
+
span.setAttribute(telemetry_attributes_1.ATTR_HTTP_RESPONSE_STATUS_CODE, httpStatus);
|
|
402
|
+
if (!response.ok) {
|
|
403
|
+
throw new Error('Download failed: status: ' + httpStatus);
|
|
404
|
+
}
|
|
405
|
+
return await response.json();
|
|
406
|
+
}
|
|
407
|
+
catch (e) {
|
|
408
|
+
span.recordException(e);
|
|
409
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR, message: e?.message });
|
|
410
|
+
telemetry_1.logger.error({ error: e, flexplm: { direction: 'publish', publish_file: file, http_status: httpStatus } }, 'FlexPLM publish file download failed');
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
});
|
|
340
414
|
}
|
|
341
415
|
async getDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate) {
|
|
416
|
+
return (0, telemetry_1.traceSection)('get_delete_changes', {}, async (span) => {
|
|
417
|
+
const deleteChanges = await this.collectDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate);
|
|
418
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_DELETE_CHANGE_COUNT, deleteChanges?.length ?? 0);
|
|
419
|
+
return deleteChanges;
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
async collectDeleteChanges(assortmentPublishChange, apcHistory, assortmentBaseline, sinceDate) {
|
|
342
423
|
const currentAPCIndex = apcHistory.findIndex(pc => pc?.id === assortmentPublishChange?.id);
|
|
343
424
|
if (currentAPCIndex == 0) {
|
|
344
425
|
return [];
|
|
@@ -383,6 +464,7 @@ class BaseProcessPublishAssortment {
|
|
|
383
464
|
console.info('getDeleteChanges(): baselineItems: ' + currentAssortmentItemIds.length
|
|
384
465
|
+ ', scanned ' + scannedCount + ' historical delete changes, added ' + addedCount
|
|
385
466
|
+ ', deleteIds: ' + deleteIds.length);
|
|
467
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_HISTORICAL_DELETE_COUNT]: addedCount });
|
|
386
468
|
console.info('getDeleteChanges()-deleteIds: ' + deleteIds);
|
|
387
469
|
}
|
|
388
470
|
return apcDeletes;
|
|
@@ -559,12 +641,12 @@ class BaseProcessPublishAssortment {
|
|
|
559
641
|
pcd.itemFamilyChanges = this.getItemFamilyChanges(pcd, changeDetail, assortmentItemFullChangeMap, assortmentItemDeleteMap);
|
|
560
642
|
const events = await this.getEventsForPublishChangeData(pcd);
|
|
561
643
|
if (events.length === 0) {
|
|
562
|
-
const processStatus = 'BaseProcessPublishAssortment: ' + event_short_message_status_1.EventShortMessageStatus.NO_EVENTS_TO_SEND
|
|
563
|
-
+ ': assortmentId: ' + pcd.assortmentId + ': assortmentPublishChangeId: ' + pcd.assortmentPublishChangeId
|
|
564
|
-
+ ', orgSlug: ' + this.orgSlug;
|
|
565
|
-
console.log(processStatus);
|
|
566
644
|
const message = 'No Events to Send; returning';
|
|
567
|
-
|
|
645
|
+
this.recordPublishStatus({
|
|
646
|
+
status: event_short_message_status_1.EventShortMessageStatus.NO_EVENTS_TO_SEND,
|
|
647
|
+
assortmentId: pcd.assortmentId,
|
|
648
|
+
assortmentPublishChangeId: pcd.assortmentPublishChangeId,
|
|
649
|
+
});
|
|
568
650
|
return {
|
|
569
651
|
results: { message, event },
|
|
570
652
|
skip_await: true
|
|
@@ -572,11 +654,12 @@ class BaseProcessPublishAssortment {
|
|
|
572
654
|
}
|
|
573
655
|
const results = await this.sendEvents(events);
|
|
574
656
|
const resultsCount = this.getResultsCount(events);
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
657
|
+
this.recordPublishStatus({
|
|
658
|
+
status: event_short_message_status_1.EventShortMessageStatus.SENDING_EVENTS,
|
|
659
|
+
assortmentId: pcd.assortmentId,
|
|
660
|
+
assortmentPublishChangeId: pcd.assortmentPublishChangeId,
|
|
661
|
+
resultsCount,
|
|
662
|
+
});
|
|
580
663
|
return { results, event, resultsCount };
|
|
581
664
|
}
|
|
582
665
|
getResultsCount(events) {
|
|
@@ -595,6 +678,7 @@ class BaseProcessPublishAssortment {
|
|
|
595
678
|
console.info('sendEvents()');
|
|
596
679
|
const eventType = 'ASYNC_PUBLISH_SEASON';
|
|
597
680
|
const sendMode = (this.config?.sendMode[eventType] || '').toLowerCase();
|
|
681
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SEND_MODE]: sendMode });
|
|
598
682
|
switch (sendMode) {
|
|
599
683
|
case 'sendtoflexplm':
|
|
600
684
|
return this.sendToFlexPLM(events, eventType);
|
|
@@ -604,22 +688,25 @@ class BaseProcessPublishAssortment {
|
|
|
604
688
|
case 'vibeiqfile-dontsendtoflexplm':
|
|
605
689
|
return this.handleVibeIQFile(events, eventType, sendMode);
|
|
606
690
|
default:
|
|
691
|
+
telemetry_1.logger.warn({ flexplm: { direction: 'publish', send_mode: sendMode, payload_count: events?.length ?? 0 } }, 'Unknown FlexPLM publish sendMode; events not sent');
|
|
607
692
|
return {}; // Or handle other cases as required
|
|
608
693
|
}
|
|
609
694
|
}
|
|
610
695
|
async sendToFlexPLM(events, eventType) {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
696
|
+
return (0, telemetry_1.traceSection)('send_publish_batch', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, async () => {
|
|
697
|
+
const outboundPublishEvent = {
|
|
698
|
+
taskId: this.config.taskId,
|
|
699
|
+
eventType,
|
|
700
|
+
objectClass: 'LCSSeason',
|
|
701
|
+
events
|
|
702
|
+
};
|
|
703
|
+
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
704
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
705
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
706
|
+
return isResultObject
|
|
707
|
+
? { ...result, outboundPublishEvent }
|
|
708
|
+
: { result, outboundPublishEvent };
|
|
709
|
+
});
|
|
623
710
|
}
|
|
624
711
|
async sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent) {
|
|
625
712
|
let sendResult;
|
|
@@ -668,6 +755,7 @@ class BaseProcessPublishAssortment {
|
|
|
668
755
|
};
|
|
669
756
|
}
|
|
670
757
|
catch (e) {
|
|
758
|
+
telemetry_1.logger.error({ error: e, flexplm: { direction: 'publish', send_mode: 'localfile' } }, 'Saving FlexPLM publish events to a local file failed');
|
|
671
759
|
results['error'] = e.message;
|
|
672
760
|
}
|
|
673
761
|
finally {
|
|
@@ -678,7 +766,7 @@ class BaseProcessPublishAssortment {
|
|
|
678
766
|
async handleVibeIQFile(events, eventType, sendMode) {
|
|
679
767
|
const eventBuffer = Buffer.from(JSON.stringify(events), 'utf-8');
|
|
680
768
|
const fileName = 'ASYNC_PUBLISH_SEASON-events.json';
|
|
681
|
-
const uploadFile = await new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL);
|
|
769
|
+
const uploadFile = await (0, telemetry_1.traceSection)('upload_publish_events_file', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, () => new sdk_1.Files().createAndUploadFileFromBuffer(eventBuffer, 'application/json', fileName, null, this.TTL));
|
|
682
770
|
const outboundPublishEvent = {
|
|
683
771
|
taskId: this.config.taskId,
|
|
684
772
|
eventType,
|
|
@@ -688,12 +776,14 @@ class BaseProcessPublishAssortment {
|
|
|
688
776
|
eventsAdminDownloadLink: uploadFile.adminDownloadUrl
|
|
689
777
|
};
|
|
690
778
|
if (sendMode === 'vibeiqfile') {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
779
|
+
return (0, telemetry_1.traceSection)('send_publish_batch', { [telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT]: events?.length ?? 0 }, async () => {
|
|
780
|
+
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
781
|
+
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
782
|
+
const isResultObject = typeof result === 'object' && result !== null;
|
|
783
|
+
return isResultObject
|
|
784
|
+
? { ...result, outboundPublishEvent }
|
|
785
|
+
: { result, outboundPublishEvent };
|
|
786
|
+
});
|
|
697
787
|
}
|
|
698
788
|
else {
|
|
699
789
|
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
@@ -704,22 +794,24 @@ class BaseProcessPublishAssortment {
|
|
|
704
794
|
}
|
|
705
795
|
}
|
|
706
796
|
async sendPublishPayloadEvent(outboundPublishEvent) {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
797
|
+
return (0, telemetry_1.traceSection)('record_publish_event', {}, async () => {
|
|
798
|
+
console.info('sendPublishPayloadEvent()');
|
|
799
|
+
let initialEvent = {};
|
|
800
|
+
if (this.config?.event) {
|
|
801
|
+
initialEvent = (typeof this.config?.event === 'string')
|
|
802
|
+
? JSON.parse(this.config?.event)
|
|
803
|
+
: this.config?.event;
|
|
804
|
+
}
|
|
805
|
+
const eventBody = {
|
|
806
|
+
originSystemType: 'VibeIQ',
|
|
807
|
+
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
808
|
+
outboundPublishEvent,
|
|
809
|
+
initialEvent
|
|
810
|
+
};
|
|
811
|
+
await new sdk_1.Entities().create({
|
|
812
|
+
entityName: 'external-event',
|
|
813
|
+
object: eventBody
|
|
814
|
+
});
|
|
723
815
|
});
|
|
724
816
|
}
|
|
725
817
|
getCurrentDateString() {
|
|
@@ -812,6 +904,7 @@ class BaseProcessPublishAssortment {
|
|
|
812
904
|
}
|
|
813
905
|
}
|
|
814
906
|
}
|
|
907
|
+
const skippedDeletes = [];
|
|
815
908
|
for (const [itemId, delEntity] of assortmentItemDeleteMap) {
|
|
816
909
|
const itemFamilyId = delEntity?.item?.itemFamilyId;
|
|
817
910
|
const item = delEntity?.item;
|
|
@@ -823,7 +916,7 @@ class BaseProcessPublishAssortment {
|
|
|
823
916
|
}
|
|
824
917
|
else {
|
|
825
918
|
if (!item) {
|
|
826
|
-
|
|
919
|
+
skippedDeletes.push({ item_family_id: itemFamilyId, item_id: itemId });
|
|
827
920
|
continue;
|
|
828
921
|
}
|
|
829
922
|
}
|
|
@@ -855,6 +948,14 @@ class BaseProcessPublishAssortment {
|
|
|
855
948
|
ifc.colorDeletes.push(itemId);
|
|
856
949
|
}
|
|
857
950
|
} //End deletes for loop
|
|
951
|
+
if (skippedDeletes.length > 0) {
|
|
952
|
+
// These deletes are not sent to FlexPLM; one warning for the publish rather than one per item.
|
|
953
|
+
(0, telemetry_utils_1.setActiveSpanAttributes)({ [telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_SKIPPED_DELETE_COUNT]: skippedDeletes.length });
|
|
954
|
+
telemetry_1.logger.warn({ flexplm: {
|
|
955
|
+
direction: 'publish', assortment_id: pcd.assortmentId, publish_change_id: pcd.assortmentPublishChangeId,
|
|
956
|
+
skipped_delete_count: skippedDeletes.length, skipped_deletes: skippedDeletes,
|
|
957
|
+
} }, 'FlexPLM publish skipped deleted items with no item entity');
|
|
958
|
+
}
|
|
858
959
|
if (app_framework_1.Logger.isDebugOn()) {
|
|
859
960
|
console.debug('returning size: ' + itemFamilyChanges.size);
|
|
860
961
|
for (const [key, value] of itemFamilyChanges) {
|
|
@@ -864,16 +965,21 @@ class BaseProcessPublishAssortment {
|
|
|
864
965
|
return itemFamilyChanges;
|
|
865
966
|
}
|
|
866
967
|
async getEventsForPublishChangeData(publishChangeData) {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
968
|
+
return (0, telemetry_1.traceSection)('build_publish_events', {
|
|
969
|
+
[telemetry_attributes_1.ATTR_FLEXPLM_PUBLISH_ITEM_FAMILY_COUNT]: publishChangeData.itemFamilyChanges?.size ?? 0,
|
|
970
|
+
}, async (span) => {
|
|
971
|
+
const seasonalPayloads = [];
|
|
972
|
+
for (const itemFamilyChange of publishChangeData.itemFamilyChanges.values()) {
|
|
973
|
+
const events = await this.getEventsForItemFamilyChanges(itemFamilyChange, publishChangeData.assortmentId, publishChangeData.seasonFed, publishChangeData.itemToFederatedIdMapping);
|
|
974
|
+
if (events.length > 0) {
|
|
975
|
+
seasonalPayloads.push(...events);
|
|
976
|
+
}
|
|
872
977
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
978
|
+
console.info('getEventsForPublishChangeData: itemFamilies: '
|
|
979
|
+
+ publishChangeData.itemFamilyChanges.size + ', payloads: ' + seasonalPayloads.length);
|
|
980
|
+
span.setAttribute(telemetry_attributes_1.ATTR_FLEXPLM_PAYLOAD_COUNT, seasonalPayloads.length);
|
|
981
|
+
return seasonalPayloads;
|
|
982
|
+
});
|
|
877
983
|
}
|
|
878
984
|
/**Returns the events for a given ItemFamilyChanges object
|
|
879
985
|
*
|