@contrail/flexplm 1.7.4-alpha.ad2bc4e → 1.7.4-alpha.b0c1671
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/interfaces/item-family-changes.d.ts +0 -1
- package/lib/interfaces/item-family-changes.js +0 -2
- package/lib/publish/base-process-publish-assortment.js +47 -110
- package/lib/publish/base-process-publish-assortment.spec.js +0 -263
- package/lib/util/flexplm-connect.js +4 -2
- package/lib/util/flexplm-connect.spec.js +20 -0
- package/package.json +1 -1
|
@@ -12,7 +12,6 @@ export declare class ItemFamilyChanges {
|
|
|
12
12
|
colorDeletes: string[];
|
|
13
13
|
colorUpdates: string[];
|
|
14
14
|
colorUnchanged: string[];
|
|
15
|
-
colorSuppressed: string[];
|
|
16
15
|
assortmentItemFullChangeMap: Map<string, any>;
|
|
17
16
|
assortmentItemDeleteMap: Map<string, any>;
|
|
18
17
|
itemToFederatedIdMapping: Map<string, string>;
|
|
@@ -14,7 +14,6 @@ class ItemFamilyChanges {
|
|
|
14
14
|
this.colorDeletes = [];
|
|
15
15
|
this.colorUpdates = [];
|
|
16
16
|
this.colorUnchanged = [];
|
|
17
|
-
this.colorSuppressed = []; // changed this window, but excluded by the lifecycle filter
|
|
18
17
|
this.assortmentItemFullChangeMap = new Map();
|
|
19
18
|
this.assortmentItemDeleteMap = new Map();
|
|
20
19
|
this.itemToFederatedIdMapping = new Map();
|
|
@@ -33,7 +32,6 @@ class ItemFamilyChanges {
|
|
|
33
32
|
s += ' colorDeletes: [' + this.colorDeletes + ']\n';
|
|
34
33
|
s += ' colorUpdates: [' + this.colorUpdates + ']\n';
|
|
35
34
|
s += ' colorUnchanged: [' + this.colorUnchanged + ']\n';
|
|
36
|
-
s += ' colorSuppressed: [' + this.colorSuppressed + ']\n';
|
|
37
35
|
s += 'assortmentItemFullChangeMap:\n';
|
|
38
36
|
s += 'size: ' + this.assortmentItemFullChangeMap.size + '\n[';
|
|
39
37
|
for (const key of this.assortmentItemFullChangeMap.keys()) {
|
|
@@ -15,7 +15,7 @@ class BaseProcessPublishAssortment {
|
|
|
15
15
|
constructor(_config, _dc, _mapFileUtil) {
|
|
16
16
|
this.TTL = 30 * 24 * 60 * 60 * 1000; // 30 days
|
|
17
17
|
this.cache = {
|
|
18
|
-
carriedFromSeason: {}
|
|
18
|
+
carriedFromSeason: {}
|
|
19
19
|
};
|
|
20
20
|
this.config = _config;
|
|
21
21
|
this.dc = _dc;
|
|
@@ -46,13 +46,13 @@ class BaseProcessPublishAssortment {
|
|
|
46
46
|
console.log(message);
|
|
47
47
|
const output = {
|
|
48
48
|
results: { message, event },
|
|
49
|
-
skip_await: true
|
|
49
|
+
skip_await: true
|
|
50
50
|
};
|
|
51
51
|
return output;
|
|
52
52
|
}
|
|
53
53
|
apcHistory = await this.getApcHistory(assortmentId);
|
|
54
54
|
const sinceDate = await this.getSinceDate(assortmentId, assortmentPublishChangeId, apcHistory);
|
|
55
|
-
//
|
|
55
|
+
//Get detail information
|
|
56
56
|
const assortmentPublishChange = await this.downloadAssortmentPublishChange(assortmentId, assortmentPublishChangeId);
|
|
57
57
|
publisher = this.getPublisher(assortmentPublishChange);
|
|
58
58
|
const changeDetail = await this.downloadHydratedChangeDetail(assortmentPublishChange);
|
|
@@ -91,7 +91,7 @@ class BaseProcessPublishAssortment {
|
|
|
91
91
|
versionComments: apc?.versionComments,
|
|
92
92
|
publishDate: apc?.createdOn,
|
|
93
93
|
publisher,
|
|
94
|
-
versionHistoryNumber
|
|
94
|
+
versionHistoryNumber
|
|
95
95
|
};
|
|
96
96
|
return publishInfo;
|
|
97
97
|
}
|
|
@@ -111,15 +111,15 @@ class BaseProcessPublishAssortment {
|
|
|
111
111
|
return 'unknown';
|
|
112
112
|
}
|
|
113
113
|
const createdOnDate = new Date(createdOnString);
|
|
114
|
-
createdOnDate.setMonth(createdOnDate.getMonth() - 1); //
|
|
114
|
+
createdOnDate.setMonth(createdOnDate.getMonth() - 1); //subtract 1 month
|
|
115
115
|
const createdOnStringMinus1 = createdOnDate.toISOString();
|
|
116
116
|
const createdOn = 'ISGREATERTHAN ' + createdOnStringMinus1;
|
|
117
117
|
const snapshots = await new sdk_1.Entities().get({
|
|
118
118
|
entityName: 'entity-snapshot',
|
|
119
119
|
criteria: {
|
|
120
120
|
entityReference,
|
|
121
|
-
createdOn
|
|
122
|
-
}
|
|
121
|
+
createdOn
|
|
122
|
+
}
|
|
123
123
|
});
|
|
124
124
|
const assortmentPublishChangeId = apc?.id;
|
|
125
125
|
const snapshot = snapshots.find(snap => snap?.assortmentChangeId === assortmentPublishChangeId);
|
|
@@ -169,7 +169,7 @@ class BaseProcessPublishAssortment {
|
|
|
169
169
|
}
|
|
170
170
|
this.assortment = await new sdk_1.Entities().get({
|
|
171
171
|
entityName: 'assortment',
|
|
172
|
-
id: assortmentId
|
|
172
|
+
id: assortmentId
|
|
173
173
|
});
|
|
174
174
|
return this.assortment;
|
|
175
175
|
}
|
|
@@ -214,9 +214,9 @@ class BaseProcessPublishAssortment {
|
|
|
214
214
|
return sdk_1.Request.request(resource, {
|
|
215
215
|
method: 'GET',
|
|
216
216
|
headers: {
|
|
217
|
-
|
|
218
|
-
'Content-Type': 'application/json'
|
|
219
|
-
}
|
|
217
|
+
Accept: 'application/json',
|
|
218
|
+
'Content-Type': 'application/json'
|
|
219
|
+
}
|
|
220
220
|
});
|
|
221
221
|
}
|
|
222
222
|
updatedSinceDate(entity, sinceDate) {
|
|
@@ -287,7 +287,7 @@ class BaseProcessPublishAssortment {
|
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
|
-
dateArray.sort((a, b) => Date.parse(a) - Date.parse(b));
|
|
290
|
+
dateArray.sort((a, b) => { return Date.parse(a) - Date.parse(b); });
|
|
291
291
|
const arrIndex = (dateArray.length - pastPublishCount > 0) ? dateArray.length - pastPublishCount : 0;
|
|
292
292
|
sinceDate = dateArray[arrIndex];
|
|
293
293
|
return sinceDate;
|
|
@@ -308,9 +308,9 @@ class BaseProcessPublishAssortment {
|
|
|
308
308
|
return await sdk_1.Request.request(resourceString, {
|
|
309
309
|
method: 'GET',
|
|
310
310
|
Headers: {
|
|
311
|
-
|
|
312
|
-
'Content-Type': 'application/json'
|
|
313
|
-
}
|
|
311
|
+
Accept: 'application/json',
|
|
312
|
+
'Content-Type': 'application/json'
|
|
313
|
+
}
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
316
|
async downloadHydratedChangeDetail(assortmentPublishChange) {
|
|
@@ -358,7 +358,7 @@ class BaseProcessPublishAssortment {
|
|
|
358
358
|
console.info('sinceDateMilliseconds: ' + sinceDateMilliseconds);
|
|
359
359
|
console.info('apcDateMilliseconds: ' + previousApcDate);
|
|
360
360
|
}
|
|
361
|
-
//
|
|
361
|
+
//if only 1 apc, no processing needed
|
|
362
362
|
if (sinceDateMilliseconds !== previousApcDate) {
|
|
363
363
|
console.info('sinceDateMilliseconds !== apcDateMilliseconds');
|
|
364
364
|
const currentAssortmentItemIds = this.getBaselineItemIds(assortmentBaseline);
|
|
@@ -444,7 +444,7 @@ class BaseProcessPublishAssortment {
|
|
|
444
444
|
previousBaseline = await this.downloadAssortmentBaseline(previousApc);
|
|
445
445
|
}
|
|
446
446
|
const deleteIds = apc?.detail?.deletes.map(dItem => dItem?.id);
|
|
447
|
-
//
|
|
447
|
+
//building deletes based on previous baseline; because some APCs don't have delete data
|
|
448
448
|
const deleteArray = previousBaseline?.assortmentItems.filter(aItem => deleteIds.includes(aItem?.itemId));
|
|
449
449
|
console.info('deleteArray.length: ' + deleteArray.length);
|
|
450
450
|
return deleteArray;
|
|
@@ -495,18 +495,13 @@ class BaseProcessPublishAssortment {
|
|
|
495
495
|
const itemFamilyId = item?.itemFamilyId;
|
|
496
496
|
if (meetsCriteria) {
|
|
497
497
|
releasedForDevelopmentItemIds.push(itemId);
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
if (!itemFamilySet.has(itemFamilyId) && itemId !== itemFamilyId) {
|
|
503
|
-
const familyItem = item?.itemFamily;
|
|
504
|
-
if (familyItem) {
|
|
505
|
-
if (this.meetsCriteria({ item: familyItem })
|
|
506
|
-
&& !releasedForDevelopmentItemIds.includes(itemFamilyId)) {
|
|
498
|
+
if (!itemFamilySet.has(itemFamilyId) && itemId !== itemFamilyId) {
|
|
499
|
+
const familyItem = item?.itemFamily;
|
|
500
|
+
const familyItemMeetsCriteria = this.meetsCriteria({ item: familyItem });
|
|
501
|
+
if (familyItemMeetsCriteria) {
|
|
507
502
|
releasedForDevelopmentItemIds.push(itemFamilyId);
|
|
508
503
|
}
|
|
509
|
-
itemFamilySet.add(itemFamilyId);
|
|
504
|
+
itemFamilySet.add(itemFamilyId);
|
|
510
505
|
}
|
|
511
506
|
}
|
|
512
507
|
}
|
|
@@ -544,7 +539,7 @@ class BaseProcessPublishAssortment {
|
|
|
544
539
|
console.info('processPublish-start');
|
|
545
540
|
const event = {
|
|
546
541
|
assortmentId: pcd.assortmentId,
|
|
547
|
-
assortmentPublishChangeId: pcd.assortmentPublishChangeId
|
|
542
|
+
assortmentPublishChangeId: pcd.assortmentPublishChangeId
|
|
548
543
|
};
|
|
549
544
|
const assortmentItemFullChangeMap = this.getFullChangeAssortmentMap(fullChange);
|
|
550
545
|
const assortmentItemDeleteMap = this.getDeleteChangesAssortmentMap(deleteChanges);
|
|
@@ -559,7 +554,7 @@ class BaseProcessPublishAssortment {
|
|
|
559
554
|
console.log(message);
|
|
560
555
|
return {
|
|
561
556
|
results: { message, event },
|
|
562
|
-
skip_await: true
|
|
557
|
+
skip_await: true
|
|
563
558
|
};
|
|
564
559
|
}
|
|
565
560
|
const results = await this.sendEvents(events);
|
|
@@ -604,7 +599,7 @@ class BaseProcessPublishAssortment {
|
|
|
604
599
|
taskId: this.config.taskId,
|
|
605
600
|
eventType,
|
|
606
601
|
objectClass: 'LCSSeason',
|
|
607
|
-
events
|
|
602
|
+
events
|
|
608
603
|
};
|
|
609
604
|
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
610
605
|
const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
|
|
@@ -650,13 +645,13 @@ class BaseProcessPublishAssortment {
|
|
|
650
645
|
taskId: this.config.taskId,
|
|
651
646
|
eventType,
|
|
652
647
|
objectClass: 'LCSSeason',
|
|
653
|
-
events
|
|
648
|
+
events
|
|
654
649
|
};
|
|
655
650
|
await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
|
|
656
651
|
results = {
|
|
657
652
|
message: 'Successfully Saved File',
|
|
658
653
|
outboundPublishEvent,
|
|
659
|
-
fileLocation: dirName + fileName
|
|
654
|
+
fileLocation: dirName + fileName
|
|
660
655
|
};
|
|
661
656
|
}
|
|
662
657
|
catch (e) {
|
|
@@ -677,7 +672,7 @@ class BaseProcessPublishAssortment {
|
|
|
677
672
|
objectClass: 'LCSSeason',
|
|
678
673
|
eventsFileId: uploadFile.id,
|
|
679
674
|
eventsDownloadLink: uploadFile.downloadUrl,
|
|
680
|
-
eventsAdminDownloadLink: uploadFile.adminDownloadUrl
|
|
675
|
+
eventsAdminDownloadLink: uploadFile.adminDownloadUrl
|
|
681
676
|
};
|
|
682
677
|
if (sendMode === 'vibeiqfile') {
|
|
683
678
|
const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
|
|
@@ -691,7 +686,7 @@ class BaseProcessPublishAssortment {
|
|
|
691
686
|
await this.sendPublishPayloadEvent(outboundPublishEvent);
|
|
692
687
|
return {
|
|
693
688
|
message: 'Successfully Uploaded File.',
|
|
694
|
-
outboundPublishEvent
|
|
689
|
+
outboundPublishEvent
|
|
695
690
|
};
|
|
696
691
|
}
|
|
697
692
|
}
|
|
@@ -707,11 +702,11 @@ class BaseProcessPublishAssortment {
|
|
|
707
702
|
originSystemType: 'VibeIQ',
|
|
708
703
|
objectClass: 'AssortmentPublishedToFlexPLM',
|
|
709
704
|
outboundPublishEvent,
|
|
710
|
-
initialEvent
|
|
705
|
+
initialEvent
|
|
711
706
|
};
|
|
712
707
|
await new sdk_1.Entities().create({
|
|
713
708
|
entityName: 'external-event',
|
|
714
|
-
object: eventBody
|
|
709
|
+
object: eventBody
|
|
715
710
|
});
|
|
716
711
|
}
|
|
717
712
|
getCurrentDateString() {
|
|
@@ -735,7 +730,7 @@ class BaseProcessPublishAssortment {
|
|
|
735
730
|
for (const [itemId, aItem] of assortmentItemFullChangeMap) {
|
|
736
731
|
const projectItem = aItem?.projectItem;
|
|
737
732
|
const itemFamilyId = aItem?.item?.itemFamilyId;
|
|
738
|
-
if (!pcd.releasedForDevelopmentItemIds.includes(itemFamilyId)) {
|
|
733
|
+
if (!pcd.releasedForDevelopmentItemIds.includes(itemFamilyId) || !pcd.releasedForDevelopmentItemIds.includes(itemId)) {
|
|
739
734
|
continue;
|
|
740
735
|
}
|
|
741
736
|
const ifc = itemFamilyChanges.get(itemFamilyId) || new item_family_changes_1.ItemFamilyChanges(itemFamilyId, pcd.sinceDate);
|
|
@@ -747,20 +742,6 @@ class BaseProcessPublishAssortment {
|
|
|
747
742
|
if (pcd.itemToFederatedIdMapping.has(itemId)) {
|
|
748
743
|
ifc.itemToFederatedIdMapping.set(itemId, pcd.itemToFederatedIdMapping.get(itemId));
|
|
749
744
|
}
|
|
750
|
-
// ---- NEW Step to enable ItemFamily publish ET-243: option is pre-development. It must not produce an
|
|
751
|
-
// LCSSKUSeasonLink, but a change to it still makes the family publishable. ----
|
|
752
|
-
if (!pcd.releasedForDevelopmentItemIds.includes(itemId)) {
|
|
753
|
-
const changedInWindow = addIds.includes(itemId)
|
|
754
|
-
|| deleteIds.includes(itemId)
|
|
755
|
-
|| updateIds.includes(itemId)
|
|
756
|
-
|| this.updatedSinceDate(projectItem, pcd.sinceDate)
|
|
757
|
-
|| this.updatedSinceDate(aItem?.item, pcd.sinceDate);
|
|
758
|
-
if (changedInWindow) {
|
|
759
|
-
ifc.colorSuppressed.push(itemId);
|
|
760
|
-
}
|
|
761
|
-
continue;
|
|
762
|
-
}
|
|
763
|
-
// NEW Step - ends
|
|
764
745
|
if (itemId === itemFamilyId) {
|
|
765
746
|
if (addIds.includes(itemId))
|
|
766
747
|
ifc.familyAdd = true;
|
|
@@ -776,12 +757,6 @@ class BaseProcessPublishAssortment {
|
|
|
776
757
|
ifc.familyUpdate = true;
|
|
777
758
|
}
|
|
778
759
|
}
|
|
779
|
-
// NEW Step to enable ItemFamily publish ET-243: item-level edits (incl. lifecycleStage) must publish
|
|
780
|
-
// the family. Guarded so the "first option added" flow stays suppressed. ----
|
|
781
|
-
if (!ifc.familyItemRemoved && this.updatedSinceDate(aItem?.item, pcd.sinceDate)) {
|
|
782
|
-
ifc.familyUpdate = true;
|
|
783
|
-
}
|
|
784
|
-
// NEW Step - ends
|
|
785
760
|
if (projectItem && !projectItem?.roles && aItem?.item?.roles) {
|
|
786
761
|
projectItem.roles = aItem?.item?.roles;
|
|
787
762
|
}
|
|
@@ -838,41 +813,7 @@ class BaseProcessPublishAssortment {
|
|
|
838
813
|
else {
|
|
839
814
|
ifc.colorDeletes.push(itemId);
|
|
840
815
|
}
|
|
841
|
-
} //
|
|
842
|
-
// ---- ET-243: the family's own row left the assortment while the family still has
|
|
843
|
-
// option rows. The platform reports this in changeDetail.familyItemsRemoved, and the
|
|
844
|
-
// row is in neither the baseline nor the delete-data file, so neither loop above can
|
|
845
|
-
// see it. `deletes` is folded in as a fallback in case a removal is ever classified
|
|
846
|
-
// there while still missing from the delete-data file. ----
|
|
847
|
-
for (const removedRow of [...familyItemsRemoved, ...deletes]) {
|
|
848
|
-
const itemId = removedRow?.itemId ?? removedRow?.id;
|
|
849
|
-
const item = removedRow?.item;
|
|
850
|
-
if (!itemId || !item)
|
|
851
|
-
continue;
|
|
852
|
-
const itemFamilyId = item?.itemFamilyId ?? itemId;
|
|
853
|
-
if (itemId !== itemFamilyId)
|
|
854
|
-
continue; // family rows only
|
|
855
|
-
if (assortmentItemFullChangeMap.has(itemId))
|
|
856
|
-
continue; // still in baseline -> loop 1
|
|
857
|
-
if (assortmentItemDeleteMap.has(itemId))
|
|
858
|
-
continue; // hard delete -> loop 2
|
|
859
|
-
if (!pcd.releasedForDevelopmentItemIds.includes(itemFamilyId))
|
|
860
|
-
continue;
|
|
861
|
-
if (!this.meetsCriteria(removedRow))
|
|
862
|
-
continue;
|
|
863
|
-
let ifc = itemFamilyChanges.get(itemFamilyId);
|
|
864
|
-
if (!ifc) {
|
|
865
|
-
ifc = new item_family_changes_1.ItemFamilyChanges(itemFamilyId, pcd.sinceDate);
|
|
866
|
-
itemFamilyChanges.set(itemFamilyId, ifc);
|
|
867
|
-
}
|
|
868
|
-
if (!ifc.itemFamilyObject) {
|
|
869
|
-
ifc.itemFamilyObject = item;
|
|
870
|
-
}
|
|
871
|
-
if (removedRow?.projectItem) {
|
|
872
|
-
ifc.assortmentItemFullChangeMap.set(itemId, removedRow);
|
|
873
|
-
}
|
|
874
|
-
ifc.familyItemRemoved = true;
|
|
875
|
-
}
|
|
816
|
+
} //End deletes for loop
|
|
876
817
|
if (app_framework_1.Logger.isDebugOn()) {
|
|
877
818
|
console.debug('returning size: ' + itemFamilyChanges.size);
|
|
878
819
|
for (const [key, value] of itemFamilyChanges) {
|
|
@@ -914,17 +855,13 @@ class BaseProcessPublishAssortment {
|
|
|
914
855
|
const LCSSeason = Object.assign({}, seasonFed);
|
|
915
856
|
const assortment = await this.getAssortment(assortmentId);
|
|
916
857
|
const projectItem = this.getProjectItem(itemFamilyChanges, itemFamilyChanges.itemFamilyId);
|
|
917
|
-
// ---- NEW Step to enable ItemFamily publish ET-243: added color suppressed length to existing condition and familyItemRemovedFlag
|
|
918
858
|
const familyAssortmentItem = itemFamilyChanges.familyAdd || itemFamilyChanges.familyUpdate || itemFamilyChanges.familyDelete
|
|
919
|
-
|| itemFamilyChanges.familyItemRemoved
|
|
920
859
|
|| itemFamilyChanges.colorAdds.length > 0 || itemFamilyChanges.colorUpdates.length > 0 || itemFamilyChanges.colorDeletes.length > 0
|
|
921
|
-
|| itemFamilyChanges.colorSuppressed.length > 0
|
|
922
860
|
|| (projectItem && this.updatedSinceDate(projectItem, itemFamilyChanges.sinceDate));
|
|
923
|
-
//
|
|
924
|
-
//
|
|
925
|
-
// LCSProductSeasonLink update and no LCSSKUSeasonLink.
|
|
861
|
+
//familyItemRemoved is used when adding the first option to an assortment
|
|
862
|
+
//and will have updates for the family item.
|
|
926
863
|
if (familyAssortmentItem) {
|
|
927
|
-
//
|
|
864
|
+
//Product-season add
|
|
928
865
|
const entityReference = itemFamilyChanges.itemFamilyId;
|
|
929
866
|
const prodEntityData = (itemFamilyChanges.assortmentItemFullChangeMap.has(entityReference))
|
|
930
867
|
? itemFamilyChanges.assortmentItemFullChangeMap.get(entityReference)?.item
|
|
@@ -940,7 +877,7 @@ class BaseProcessPublishAssortment {
|
|
|
940
877
|
entityReference: 'item:' + entityReference,
|
|
941
878
|
LCSSeason,
|
|
942
879
|
LCSProduct,
|
|
943
|
-
data: seasonalData
|
|
880
|
+
data: seasonalData
|
|
944
881
|
};
|
|
945
882
|
if ('ASSORTMENT' === projectItem.addedFromSource && projectItem.addedFromAssortment) {
|
|
946
883
|
const carriedFromSeason = await this.getCarriedFromSeason(projectItem);
|
|
@@ -950,9 +887,9 @@ class BaseProcessPublishAssortment {
|
|
|
950
887
|
}
|
|
951
888
|
events.push(psUpsert);
|
|
952
889
|
}
|
|
953
|
-
//
|
|
954
|
-
//
|
|
955
|
-
//
|
|
890
|
+
//colorway-season adds
|
|
891
|
+
//colorAdds
|
|
892
|
+
//colorUpdates
|
|
956
893
|
const colorwayChanges = [];
|
|
957
894
|
colorwayChanges.push(...itemFamilyChanges.colorAdds);
|
|
958
895
|
colorwayChanges.push(...itemFamilyChanges.colorUpdates);
|
|
@@ -975,7 +912,7 @@ class BaseProcessPublishAssortment {
|
|
|
975
912
|
entityReference: 'item:' + entityReference,
|
|
976
913
|
LCSSeason,
|
|
977
914
|
LCSSKU,
|
|
978
|
-
data: seasonalData
|
|
915
|
+
data: seasonalData
|
|
979
916
|
};
|
|
980
917
|
if ('ASSORTMENT' === projectItem.addedFromSource && projectItem.addedFromAssortment) {
|
|
981
918
|
const carriedFromSeason = await this.getCarriedFromSeason(projectItem);
|
|
@@ -991,10 +928,10 @@ class BaseProcessPublishAssortment {
|
|
|
991
928
|
let projectItem = {};
|
|
992
929
|
if (itemFamilyChanges?.assortmentItemFullChangeMap.has(id)) {
|
|
993
930
|
const aItem = itemFamilyChanges?.assortmentItemFullChangeMap.get(id);
|
|
994
|
-
projectItem = aItem?.projectItem
|
|
931
|
+
projectItem = aItem?.projectItem;
|
|
995
932
|
}
|
|
996
933
|
/////////////////////////////////////////////////////////////////////////////
|
|
997
|
-
//
|
|
934
|
+
//Get from option assortmentItem because family not in assortmentItemFullChangeMap:start
|
|
998
935
|
/////////////////////////////////////////////////////////////////////////////
|
|
999
936
|
if (id === itemFamilyChanges.itemFamilyId && Object.keys(projectItem).length == 0) {
|
|
1000
937
|
for (const asstItem of itemFamilyChanges.assortmentItemFullChangeMap.values()) {
|
|
@@ -1005,7 +942,7 @@ class BaseProcessPublishAssortment {
|
|
|
1005
942
|
}
|
|
1006
943
|
}
|
|
1007
944
|
/////////////////////////////////////////////////////////////////////////////
|
|
1008
|
-
//
|
|
945
|
+
//Get from option assortmentItem because family not in assortmentItemFullChangeMap:end
|
|
1009
946
|
/////////////////////////////////////////////////////////////////////////////
|
|
1010
947
|
return projectItem;
|
|
1011
948
|
}
|
|
@@ -1055,7 +992,7 @@ class BaseProcessPublishAssortment {
|
|
|
1055
992
|
if (this.cache.carriedFromSeason[addedFromAssortment]) {
|
|
1056
993
|
return this.cache.carriedFromSeason[addedFromAssortment];
|
|
1057
994
|
}
|
|
1058
|
-
let seasonFederation;
|
|
995
|
+
let seasonFederation = undefined;
|
|
1059
996
|
const assortmentEntity = await this.getAssormentEntityFromId(addedFromAssortment);
|
|
1060
997
|
if (assortmentEntity) {
|
|
1061
998
|
seasonFederation = await this.getSeasonFederationFromAssortment(assortmentEntity);
|
|
@@ -1068,7 +1005,7 @@ class BaseProcessPublishAssortment {
|
|
|
1068
1005
|
try {
|
|
1069
1006
|
assortment = await new sdk_1.Entities().get({
|
|
1070
1007
|
entityName: 'assortment',
|
|
1071
|
-
id: assortmentId
|
|
1008
|
+
id: assortmentId
|
|
1072
1009
|
});
|
|
1073
1010
|
}
|
|
1074
1011
|
catch (e) {
|
|
@@ -1082,7 +1019,7 @@ class BaseProcessPublishAssortment {
|
|
|
1082
1019
|
let seasonObj = {
|
|
1083
1020
|
entityReference: 'assortment:' + assortment.id,
|
|
1084
1021
|
objectClass: 'LCSSeason',
|
|
1085
|
-
flexPLMTypePath
|
|
1022
|
+
flexPLMTypePath
|
|
1086
1023
|
};
|
|
1087
1024
|
try {
|
|
1088
1025
|
const assortmentObj = await this.dc.getFlexPLMObjectData(assortment, [], true);
|
|
@@ -1337,176 +1337,6 @@ describe('getItemFamilyChanges', () => {
|
|
|
1337
1337
|
expect(ifc.colorDeletes.length).toEqual(1);
|
|
1338
1338
|
});
|
|
1339
1339
|
});
|
|
1340
|
-
describe('getItemFamilyChanges - lifecycle-suppressed options', () => {
|
|
1341
|
-
const familyId = 'AERfdvdAt1HHEVvQ';
|
|
1342
|
-
const maroonId = 'YwWKVoL_vGN8khLy';
|
|
1343
|
-
const limeId = 'rsmWhWiXRNv_XBJG';
|
|
1344
|
-
const sinceDate = new Date('2026-08-01T00:00:00.000Z');
|
|
1345
|
-
const afterSince = '2026-08-26T00:00:00.000Z';
|
|
1346
|
-
const beforeSince = '2026-05-11T00:00:00.000Z';
|
|
1347
|
-
const noDetailChanges = () => ({ adds: [], deletes: [], updates: [], familyItemsRemoved: [] });
|
|
1348
|
-
const buildPpa = () => {
|
|
1349
|
-
const config = { itemPreDevelopmentLifecycleStages: ['concept'] };
|
|
1350
|
-
const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
|
|
1351
|
-
const dc = new data_converter_1.DataConverter(config, mapFileUtil);
|
|
1352
|
-
return new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1353
|
-
};
|
|
1354
|
-
const buildPcd = (releasedIds) => {
|
|
1355
|
-
const seasonFed = {
|
|
1356
|
-
entityReference: 'assortment:11EZML5dMn3tREuT',
|
|
1357
|
-
objectClass: 'LCSSeason'
|
|
1358
|
-
};
|
|
1359
|
-
const pcd = new publish_change_data_1.PublishChangeData('11EZML5dMn3tREuT', seasonFed, 'Pg3y2x5IclYxk3hM', sinceDate);
|
|
1360
|
-
pcd.itemToFederatedIdMapping = new Map();
|
|
1361
|
-
releasedIds.forEach(id => pcd.releasedForDevelopmentItemIds.push(id));
|
|
1362
|
-
return pcd;
|
|
1363
|
-
};
|
|
1364
|
-
const familyItem = (updatedOn = beforeSince, lifecycleStage = 'released') => ({
|
|
1365
|
-
id: familyId, itemFamilyId: familyId, lifecycleStage, name: 'Sweatpant', updatedOn
|
|
1366
|
-
});
|
|
1367
|
-
const familyRow = (updatedOn = beforeSince, lifecycleStage = 'released') => ({
|
|
1368
|
-
itemId: familyId,
|
|
1369
|
-
item: familyItem(updatedOn, lifecycleStage),
|
|
1370
|
-
projectItem: { id: 'pi-' + familyId, updatedOn: beforeSince }
|
|
1371
|
-
});
|
|
1372
|
-
const optionRow = (id, updatedOn, lifecycleStage = 'concept') => ({
|
|
1373
|
-
itemId: id,
|
|
1374
|
-
item: { id, itemFamilyId: familyId, lifecycleStage, updatedOn, itemFamily: familyItem() },
|
|
1375
|
-
projectItem: { id: 'pi-' + id, updatedOn: beforeSince },
|
|
1376
|
-
familyProjectItem: { id: 'pi-' + familyId, updatedOn: beforeSince }
|
|
1377
|
-
});
|
|
1378
|
-
it('records changed concept options as suppressed, not as colour updates', () => {
|
|
1379
|
-
const ppa = buildPpa();
|
|
1380
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1381
|
-
assortmentItems: [familyRow(), optionRow(maroonId, afterSince), optionRow(limeId, afterSince)]
|
|
1382
|
-
});
|
|
1383
|
-
const pcd = buildPcd([familyId]);
|
|
1384
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1385
|
-
expect(pcd.itemFamilyChanges.size).toEqual(1);
|
|
1386
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1387
|
-
expect(ifc.colorSuppressed).toEqual([maroonId, limeId]);
|
|
1388
|
-
expect(ifc.colorAdds.length).toEqual(0);
|
|
1389
|
-
expect(ifc.colorUpdates.length).toEqual(0);
|
|
1390
|
-
expect(ifc.colorDeletes.length).toEqual(0);
|
|
1391
|
-
expect(ifc.familyUpdate).toBe(false); // family itself unchanged
|
|
1392
|
-
});
|
|
1393
|
-
it('keeps the family reachable when only concept option rows are in the baseline', () => {
|
|
1394
|
-
const ppa = buildPpa();
|
|
1395
|
-
const assortmentItems = [optionRow(maroonId, afterSince), optionRow(limeId, afterSince)];
|
|
1396
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({ assortmentItems });
|
|
1397
|
-
// derive the gate the way production does, rather than seeding it
|
|
1398
|
-
const releasedIds = ppa.getReleasedForDevelopmentItemAndFamilyIds({ assortmentItems }, []);
|
|
1399
|
-
expect(releasedIds).toEqual([familyId]);
|
|
1400
|
-
const pcd = buildPcd(releasedIds);
|
|
1401
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1402
|
-
expect(pcd.itemFamilyChanges.size).toEqual(1);
|
|
1403
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1404
|
-
expect(ifc.itemFamilyObject.id).toEqual(familyId);
|
|
1405
|
-
expect(ifc.colorSuppressed.length).toEqual(2);
|
|
1406
|
-
expect(ppa.getProjectItem(ifc, familyId)).toEqual({ id: 'pi-' + familyId, updatedOn: beforeSince });
|
|
1407
|
-
});
|
|
1408
|
-
it('does not suppress-record an unchanged concept option', () => {
|
|
1409
|
-
const ppa = buildPpa();
|
|
1410
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1411
|
-
assortmentItems: [familyRow(), optionRow(maroonId, beforeSince)]
|
|
1412
|
-
});
|
|
1413
|
-
const pcd = buildPcd([familyId]);
|
|
1414
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1415
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1416
|
-
expect(ifc.colorSuppressed.length).toEqual(0);
|
|
1417
|
-
});
|
|
1418
|
-
it('picks up a concept option listed in the change detail even when timestamps are stale', () => {
|
|
1419
|
-
const ppa = buildPpa();
|
|
1420
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1421
|
-
assortmentItems: [familyRow(), optionRow(maroonId, beforeSince)]
|
|
1422
|
-
});
|
|
1423
|
-
const details = noDetailChanges();
|
|
1424
|
-
details.updates = [{ id: maroonId }];
|
|
1425
|
-
const pcd = buildPcd([familyId]);
|
|
1426
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, details, fullChangeMap, new Map());
|
|
1427
|
-
expect(pcd.itemFamilyChanges.get(familyId).colorSuppressed).toEqual([maroonId]);
|
|
1428
|
-
});
|
|
1429
|
-
it('skips everything when the family itself is pre-development', () => {
|
|
1430
|
-
const ppa = buildPpa();
|
|
1431
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1432
|
-
assortmentItems: [familyRow(afterSince, 'concept'), optionRow(maroonId, afterSince)]
|
|
1433
|
-
});
|
|
1434
|
-
const pcd = buildPcd([]); // nothing released
|
|
1435
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1436
|
-
expect(pcd.itemFamilyChanges.size).toEqual(0);
|
|
1437
|
-
});
|
|
1438
|
-
it('still classifies released options normally', () => {
|
|
1439
|
-
const ppa = buildPpa();
|
|
1440
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1441
|
-
assortmentItems: [familyRow(), optionRow(maroonId, afterSince, 'released')]
|
|
1442
|
-
});
|
|
1443
|
-
const details = noDetailChanges();
|
|
1444
|
-
details.adds = [{ id: maroonId }];
|
|
1445
|
-
const pcd = buildPcd([familyId, maroonId]);
|
|
1446
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, details, fullChangeMap, new Map());
|
|
1447
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1448
|
-
expect(ifc.colorAdds).toEqual([maroonId]);
|
|
1449
|
-
expect(ifc.colorSuppressed.length).toEqual(0);
|
|
1450
|
-
});
|
|
1451
|
-
it('publishes a family-only row whose lifecycle just flipped (item-level edit)', () => {
|
|
1452
|
-
const ppa = buildPpa();
|
|
1453
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({
|
|
1454
|
-
assortmentItems: [familyRow(afterSince)] // item.updatedOn moved, projectItem did not
|
|
1455
|
-
});
|
|
1456
|
-
const pcd = buildPcd([familyId]);
|
|
1457
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1458
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1459
|
-
expect(ifc.familyUpdate).toBe(true); // fails without Step 3
|
|
1460
|
-
expect(ifc.colorSuppressed.length).toEqual(0);
|
|
1461
|
-
});
|
|
1462
|
-
it('leaves an unchanged family-only row with no flags', () => {
|
|
1463
|
-
const ppa = buildPpa();
|
|
1464
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({ assortmentItems: [familyRow()] });
|
|
1465
|
-
const pcd = buildPcd([familyId]);
|
|
1466
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, noDetailChanges(), fullChangeMap, new Map());
|
|
1467
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1468
|
-
expect(ifc.familyAdd).toBe(false);
|
|
1469
|
-
expect(ifc.familyUpdate).toBe(false);
|
|
1470
|
-
expect(ifc.familyDelete).toBe(false);
|
|
1471
|
-
expect(ifc.colorSuppressed.length).toEqual(0);
|
|
1472
|
-
});
|
|
1473
|
-
it('does not set familyUpdate when the family item was removed', () => {
|
|
1474
|
-
const ppa = buildPpa();
|
|
1475
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({ assortmentItems: [familyRow(afterSince)] });
|
|
1476
|
-
const details = noDetailChanges();
|
|
1477
|
-
details.familyItemsRemoved = [{ itemId: familyId }]; // note: itemId, not id
|
|
1478
|
-
const pcd = buildPcd([familyId]);
|
|
1479
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, details, fullChangeMap, new Map());
|
|
1480
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1481
|
-
expect(ifc.familyItemRemoved).toBe(true);
|
|
1482
|
-
expect(ifc.familyUpdate).toBe(false); // fails if the !familyItemRemoved guard is dropped
|
|
1483
|
-
expect(ifc.assortmentItemFullChangeMap.size).toEqual(1); // third pass must not re-insert the row
|
|
1484
|
-
});
|
|
1485
|
-
it('flags the family when its row is removed but option rows remain', () => {
|
|
1486
|
-
const ppa = buildPpa();
|
|
1487
|
-
const assortmentItems = [optionRow(maroonId, beforeSince), optionRow(limeId, beforeSince, 'released')];
|
|
1488
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({ assortmentItems });
|
|
1489
|
-
const details = { ...noDetailChanges(), familyItemsRemoved: [{ itemId: familyId, item: familyItem() }] };
|
|
1490
|
-
const pcd = buildPcd([familyId, limeId]);
|
|
1491
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, details, fullChangeMap, new Map());
|
|
1492
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1493
|
-
expect(ifc.familyItemRemoved).toBe(true); // false before the third pass
|
|
1494
|
-
expect(ifc.itemFamilyObject.id).toEqual(familyId);
|
|
1495
|
-
expect(ifc.colorDeletes.length).toEqual(0); // no SKU event should follow
|
|
1496
|
-
expect(ifc.assortmentItemFullChangeMap.has(familyId)).toBe(false); // removed row carries no projectItem
|
|
1497
|
-
});
|
|
1498
|
-
it('leaves a hard-deleted family row to the delete pass', () => {
|
|
1499
|
-
const ppa = buildPpa();
|
|
1500
|
-
const fullChangeMap = ppa.getFullChangeAssortmentMap({ assortmentItems: [] });
|
|
1501
|
-
const deleteMap = new Map([[familyId, familyRow()]]);
|
|
1502
|
-
const details = { ...noDetailChanges(), familyItemsRemoved: [{ itemId: familyId, item: familyItem() }] };
|
|
1503
|
-
const pcd = buildPcd([familyId]);
|
|
1504
|
-
pcd.itemFamilyChanges = ppa.getItemFamilyChanges(pcd, details, fullChangeMap, deleteMap);
|
|
1505
|
-
const ifc = pcd.itemFamilyChanges.get(familyId);
|
|
1506
|
-
expect(ifc.familyDelete).toBe(true); // set by the delete pass
|
|
1507
|
-
expect(ifc.familyItemRemoved).toBe(false); // third pass skipped it - no double handling
|
|
1508
|
-
});
|
|
1509
|
-
});
|
|
1510
1340
|
describe('getProjectItem', () => {
|
|
1511
1341
|
const config = {
|
|
1512
1342
|
identifierAtts: {
|
|
@@ -1670,70 +1500,6 @@ describe('meetsCriteria', () => {
|
|
|
1670
1500
|
expect(results).toBeTruthy();
|
|
1671
1501
|
});
|
|
1672
1502
|
});
|
|
1673
|
-
describe('getReleasedForDevelopmentItemAndFamilyIds', () => {
|
|
1674
|
-
const familyId = 'AERfdvdAt1HHEVvQ';
|
|
1675
|
-
const maroonId = 'YwWKVoL_vGN8khLy';
|
|
1676
|
-
const limeId = 'rsmWhWiXRNv_XBJG';
|
|
1677
|
-
const buildPpa = (preDev = ['concept']) => {
|
|
1678
|
-
const config = {
|
|
1679
|
-
identifierAtts: { LCSSeason: ['flexPLMSeasonName'] },
|
|
1680
|
-
itemPreDevelopmentLifecycleStages: preDev
|
|
1681
|
-
};
|
|
1682
|
-
const mapFileUtil = new transform_data_1.MapFileUtil(new sdk_1.Entities());
|
|
1683
|
-
const dc = new data_converter_1.DataConverter(config, mapFileUtil);
|
|
1684
|
-
return new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1685
|
-
};
|
|
1686
|
-
const familyItem = (lifecycleStage = 'released') => ({
|
|
1687
|
-
id: familyId, itemFamilyId: familyId, lifecycleStage, name: 'Sweatpant'
|
|
1688
|
-
});
|
|
1689
|
-
// option row as the hydrated baseline actually delivers it: itemFamily present
|
|
1690
|
-
const optionRow = (id, lifecycleStage = 'concept', family = familyItem()) => ({
|
|
1691
|
-
itemId: id,
|
|
1692
|
-
item: { id, itemFamilyId: familyId, lifecycleStage, itemFamily: family }
|
|
1693
|
-
});
|
|
1694
|
-
const familyRow = (lifecycleStage = 'released') => ({
|
|
1695
|
-
itemId: familyId,
|
|
1696
|
-
item: familyItem(lifecycleStage)
|
|
1697
|
-
});
|
|
1698
|
-
const run = (ppa, assortmentItems) => ppa.getReleasedForDevelopmentItemAndFamilyIds({ assortmentItems }, []);
|
|
1699
|
-
it('surfaces the family when every option is pre-development', () => {
|
|
1700
|
-
const ppa = buildPpa();
|
|
1701
|
-
expect(run(ppa, [optionRow(maroonId), optionRow(limeId)])).toEqual([familyId]);
|
|
1702
|
-
});
|
|
1703
|
-
it('does not duplicate the family id when a family row and a released option both exist', () => {
|
|
1704
|
-
const ppa = buildPpa();
|
|
1705
|
-
const ids = run(ppa, [familyRow(), optionRow(limeId, 'released')]);
|
|
1706
|
-
expect(ids.filter(id => id === familyId)).toHaveLength(1);
|
|
1707
|
-
});
|
|
1708
|
-
it('still resolves the family when an earlier row lacks itemFamily hydration', () => {
|
|
1709
|
-
const ppa = buildPpa();
|
|
1710
|
-
const noFamilyHydration = {
|
|
1711
|
-
itemId: maroonId,
|
|
1712
|
-
item: { id: maroonId, itemFamilyId: familyId, lifecycleStage: 'concept' }
|
|
1713
|
-
};
|
|
1714
|
-
expect(run(ppa, [noFamilyHydration, optionRow(limeId)])).toEqual([familyId]);
|
|
1715
|
-
});
|
|
1716
|
-
it('returns nothing when the family itself is pre-development', () => {
|
|
1717
|
-
const ppa = buildPpa();
|
|
1718
|
-
expect(run(ppa, [optionRow(maroonId, 'concept', familyItem('concept'))])).toEqual([]);
|
|
1719
|
-
});
|
|
1720
|
-
it('includes a family-only row exactly once', () => {
|
|
1721
|
-
const ppa = buildPpa();
|
|
1722
|
-
expect(run(ppa, [familyRow()])).toEqual([familyId]);
|
|
1723
|
-
});
|
|
1724
|
-
it('includes a released option and its family, excluding the concept option', () => {
|
|
1725
|
-
const ppa = buildPpa();
|
|
1726
|
-
const ids = run(ppa, [optionRow(maroonId, 'concept'), optionRow(limeId, 'released')]);
|
|
1727
|
-
expect(ids).toContain(familyId);
|
|
1728
|
-
expect(ids).toContain(limeId);
|
|
1729
|
-
expect(ids).not.toContain(maroonId);
|
|
1730
|
-
});
|
|
1731
|
-
it('treats the stage list as case-sensitive (documents the Concept vs concept trap)', () => {
|
|
1732
|
-
const ppa = buildPpa(['Concept']); // as mis-configured in praveen-dev-1
|
|
1733
|
-
const ids = run(ppa, [optionRow(maroonId), optionRow(limeId)]);
|
|
1734
|
-
expect(ids).toEqual([maroonId, familyId, limeId]); // filter inert: everything qualifies
|
|
1735
|
-
});
|
|
1736
|
-
});
|
|
1737
1503
|
describe('getEventsForItemFamilyChanges - conditional eventType', () => {
|
|
1738
1504
|
const config = {
|
|
1739
1505
|
identifierAtts: {
|
|
@@ -1939,35 +1705,6 @@ describe('getEventsForItemFamilyChanges - conditional eventType', () => {
|
|
|
1939
1705
|
// Verify SKU event called with assortment entity
|
|
1940
1706
|
expect(type_conversion_utils_1.TypeConversionUtils.isOutboundCreatableFromEntity).toHaveBeenNthCalledWith(2, undefined, mapFileUtil, colorProjectItem, { item: itemData, assortment });
|
|
1941
1707
|
});
|
|
1942
|
-
it('should emit only an LCSProductSeasonLink when the family row was removed', async () => {
|
|
1943
|
-
const bppa = new base_process_publish_assortment_1.BaseProcessPublishAssortment(config, dc, mapFileUtil);
|
|
1944
|
-
const itemFamilyId = 'AERfdvdAt1HHEVvQ';
|
|
1945
|
-
const prodEntityData = { id: itemFamilyId, identifier: 'FAM-11', itemNumber: 'FAM-11' };
|
|
1946
|
-
//const projectItem = { id: 'proj-fam', updatedOn: '2023-01-15T00:00:00.000Z' };
|
|
1947
|
-
const projectItem = { id: 'proj-fam', updatedOn: '2022-12-01T00:00:00.000Z' };
|
|
1948
|
-
const assortment = { id: 'assort123', name: 'Fall 2023 Assortment', publishToFlexPLM: true };
|
|
1949
|
-
const seasonFed = {
|
|
1950
|
-
entityReference: 'assortment:assort123',
|
|
1951
|
-
objectClass: 'LCSSeason',
|
|
1952
|
-
flexPLMSeasonName: 'Fall 2023'
|
|
1953
|
-
};
|
|
1954
|
-
const itemFamilyChanges = new item_family_changes_1.ItemFamilyChanges(itemFamilyId, new Date('2023-01-01T00:00:00.000Z'));
|
|
1955
|
-
itemFamilyChanges.familyItemRemoved = true; // the only trigger
|
|
1956
|
-
itemFamilyChanges.colorUnchanged.push('rsmWhWiXRNv_XBJG'); // surviving option must not emit
|
|
1957
|
-
itemFamilyChanges.itemFamilyObject = prodEntityData;
|
|
1958
|
-
jest.spyOn(bppa, 'getAssortment').mockResolvedValue(assortment);
|
|
1959
|
-
jest.spyOn(bppa, 'getProjectItem').mockReturnValue(projectItem);
|
|
1960
|
-
jest.spyOn(bppa, 'getSeasonalData').mockResolvedValue({ someData: 'value' });
|
|
1961
|
-
jest.spyOn(map_utils_1.MapUtil, 'applyTransformMap').mockResolvedValue({ transformedData: 'value' });
|
|
1962
|
-
jest.spyOn(type_conversion_utils_1.TypeConversionUtils, 'getIdentifierProperties').mockResolvedValue(['identifier']);
|
|
1963
|
-
jest.spyOn(type_conversion_utils_1.TypeConversionUtils, 'getInformationalProperties').mockResolvedValue([]);
|
|
1964
|
-
jest.spyOn(type_conversion_utils_1.TypeConversionUtils, 'isOutboundCreatableFromEntity').mockResolvedValue(false);
|
|
1965
|
-
const events = await bppa.getEventsForItemFamilyChanges(itemFamilyChanges, 'assort123', seasonFed, new Map());
|
|
1966
|
-
expect(events).toHaveLength(1);
|
|
1967
|
-
expect(events[0].objectClass).toBe('LCSProductSeasonLink');
|
|
1968
|
-
expect(events[0].eventType).toBe('UPDATE_ON_SEASON');
|
|
1969
|
-
expect(events[0].entityReference).toBe('item:' + itemFamilyId);
|
|
1970
|
-
});
|
|
1971
1708
|
});
|
|
1972
1709
|
describe('sendToFlexPLM / handleVibeIQFile / sendPublishPayloadEvent', () => {
|
|
1973
1710
|
const config = {
|
|
@@ -63,7 +63,6 @@ class FlexPLMConnect {
|
|
|
63
63
|
const nonce_key = body.items[0].attributes.nonce_key;
|
|
64
64
|
const nonce = body.items[0].attributes.nonce;
|
|
65
65
|
console.info('nonce_key: ' + nonce_key);
|
|
66
|
-
console.info('nonce: ' + nonce);
|
|
67
66
|
return {
|
|
68
67
|
nonce_key,
|
|
69
68
|
nonce
|
|
@@ -89,7 +88,10 @@ class FlexPLMConnect {
|
|
|
89
88
|
console.info('Request:');
|
|
90
89
|
console.info('vibeEventsURL: ' + vibeEventsURL);
|
|
91
90
|
const logOptions = JSON.parse(JSON.stringify(xferOptions));
|
|
92
|
-
|
|
91
|
+
if (logOptions?.headers?.Authorization)
|
|
92
|
+
logOptions.headers.Authorization = '***masked***';
|
|
93
|
+
if (csrf?.nonce_key)
|
|
94
|
+
logOptions.headers[csrf.nonce_key] = '***masked***';
|
|
93
95
|
console.info('csrfOptions: ' + JSON.stringify(logOptions));
|
|
94
96
|
console.info('Making call to xfer data to FlexPLM');
|
|
95
97
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const flexplm_connect_1 = require("./flexplm-connect");
|
|
4
|
+
const app_framework_1 = require("@contrail/app-framework");
|
|
4
5
|
const mockJsonData = { items: [{ id: '123', name: 'test' }] };
|
|
5
6
|
const mockResponse = (status, json = mockJsonData) => ({
|
|
6
7
|
status,
|
|
@@ -87,3 +88,22 @@ describe('FlexPLMConnect.getRequest', () => {
|
|
|
87
88
|
await expect(connect.getRequest()).rejects.toThrow('Error getting json data from FlexPLM: Invalid JSON');
|
|
88
89
|
});
|
|
89
90
|
});
|
|
91
|
+
describe('FlexPLMConnect.sendRequest', () => {
|
|
92
|
+
it('should mask csrf nonce value in logged request options', async () => {
|
|
93
|
+
const loggerIsInfoOnSpy = jest.spyOn(app_framework_1.Logger, 'isInfoOn').mockReturnValue(true);
|
|
94
|
+
const consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation();
|
|
95
|
+
const csrf = { nonce_key: 'CSRF_NONCE', nonce: 'raw-secret-nonce' };
|
|
96
|
+
const payload = { id: '123' };
|
|
97
|
+
const connect = new flexplm_connect_1.FlexPLMConnect(createConfig());
|
|
98
|
+
await connect.sendRequest(csrf, payload);
|
|
99
|
+
const csrfOptionsLogMessages = consoleInfoSpy.mock.calls
|
|
100
|
+
.map(([message]) => String(message ?? ''))
|
|
101
|
+
.filter(message => message.startsWith('csrfOptions: '));
|
|
102
|
+
const sendRequestOptionsLogMessage = csrfOptionsLogMessages.find(message => message.includes('"CSRF_NONCE":'));
|
|
103
|
+
expect(sendRequestOptionsLogMessage).toBeDefined();
|
|
104
|
+
expect(sendRequestOptionsLogMessage ?? '').not.toContain('raw-secret-nonce');
|
|
105
|
+
expect(sendRequestOptionsLogMessage ?? '').toContain('"CSRF_NONCE":"***masked***"');
|
|
106
|
+
loggerIsInfoOnSpy.mockRestore();
|
|
107
|
+
consoleInfoSpy.mockRestore();
|
|
108
|
+
});
|
|
109
|
+
});
|