@contrail/flexplm 1.7.4-alpha.aaaa660 → 1.7.4-alpha.b088cfc

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.
@@ -12,6 +12,7 @@ export declare class ItemFamilyChanges {
12
12
  colorDeletes: string[];
13
13
  colorUpdates: string[];
14
14
  colorUnchanged: string[];
15
+ colorSuppressed: string[];
15
16
  assortmentItemFullChangeMap: Map<string, any>;
16
17
  assortmentItemDeleteMap: Map<string, any>;
17
18
  itemToFederatedIdMapping: Map<string, string>;
@@ -14,6 +14,7 @@ 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
17
18
  this.assortmentItemFullChangeMap = new Map();
18
19
  this.assortmentItemDeleteMap = new Map();
19
20
  this.itemToFederatedIdMapping = new Map();
@@ -32,6 +33,7 @@ class ItemFamilyChanges {
32
33
  s += ' colorDeletes: [' + this.colorDeletes + ']\n';
33
34
  s += ' colorUpdates: [' + this.colorUpdates + ']\n';
34
35
  s += ' colorUnchanged: [' + this.colorUnchanged + ']\n';
36
+ s += ' colorSuppressed: [' + this.colorSuppressed + ']\n';
35
37
  s += 'assortmentItemFullChangeMap:\n';
36
38
  s += 'size: ' + this.assortmentItemFullChangeMap.size + '\n[';
37
39
  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
- //Get detail information
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); //subtract 1 month
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
- Accept: 'application/json',
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) => { return Date.parse(a) - Date.parse(b); });
290
+ dateArray.sort((a, b) => 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
- Accept: 'application/json',
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
- //if only 1 apc, no processing needed
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);
@@ -391,6 +391,31 @@ class BaseProcessPublishAssortment {
391
391
  console.info('getDeleteChanges()-currentAssortmentItemIds: ' + currentAssortmentItemIds);
392
392
  console.info('getDeleteChanges()-deleteIds: ' + deleteIds);
393
393
  }
394
+ // ---- ET-243: a family row removed while the family still has option rows is reported
395
+ // in neither the delete data nor the publish-change detail. Derive it by diffing the
396
+ // baseline as of sinceDate against the current baseline. ----
397
+ const priorApc = apcHistory.find(apc => apc?.id !== assortmentPublishChange?.id
398
+ && Date.parse(apc?.createdOn) === sinceDateMilliseconds)
399
+ || apcHistory[previousApcIndex];
400
+ const priorBaseline = priorApc?.assortmentBaselineDownloadLink
401
+ ? await this.downloadAssortmentBaseline(priorApc)
402
+ : await this.downloadAssortmentBaseline(await this.downloadAssortmentPublishChange(priorApc?.assortmentId, priorApc?.id));
403
+ const currentItemIds = this.getBaselineItemIds(assortmentBaseline);
404
+ const collectedIds = apcDeletes.map(dItem => dItem?.itemId);
405
+ for (const aItem of priorBaseline?.assortmentItems || []) {
406
+ const itemId = aItem?.itemId;
407
+ const item = aItem?.item;
408
+ if (!itemId || !item)
409
+ continue;
410
+ if (itemId !== item?.itemFamilyId)
411
+ continue; // family rows only
412
+ if (currentItemIds.includes(itemId))
413
+ continue; // still in the assortment
414
+ if (collectedIds.includes(itemId))
415
+ continue; // already reported as a delete
416
+ console.info('getDeleteChanges(): adding removed family row: ' + itemId);
417
+ apcDeletes.push(aItem);
418
+ }
394
419
  return apcDeletes;
395
420
  }
396
421
  getBaselineItemIds(assortmentBaseline) {
@@ -444,7 +469,7 @@ class BaseProcessPublishAssortment {
444
469
  previousBaseline = await this.downloadAssortmentBaseline(previousApc);
445
470
  }
446
471
  const deleteIds = apc?.detail?.deletes.map(dItem => dItem?.id);
447
- //building deletes based on previous baseline; because some APCs don't have delete data
472
+ // building deletes based on previous baseline; because some APCs don't have delete data
448
473
  const deleteArray = previousBaseline?.assortmentItems.filter(aItem => deleteIds.includes(aItem?.itemId));
449
474
  console.info('deleteArray.length: ' + deleteArray.length);
450
475
  return deleteArray;
@@ -495,13 +520,18 @@ class BaseProcessPublishAssortment {
495
520
  const itemFamilyId = item?.itemFamilyId;
496
521
  if (meetsCriteria) {
497
522
  releasedForDevelopmentItemIds.push(itemId);
498
- if (!itemFamilySet.has(itemFamilyId) && itemId !== itemFamilyId) {
499
- const familyItem = item?.itemFamily;
500
- const familyItemMeetsCriteria = this.meetsCriteria({ item: familyItem });
501
- if (familyItemMeetsCriteria) {
523
+ }
524
+ // ---- NEW (Step 5): family resolution moved OUT of the meetsCriteria block.
525
+ // A family whose options are ALL pre-development has no other route into this
526
+ // list when it has no assortment-item row of its own. ----
527
+ if (!itemFamilySet.has(itemFamilyId) && itemId !== itemFamilyId) {
528
+ const familyItem = item?.itemFamily;
529
+ if (familyItem) {
530
+ if (this.meetsCriteria({ item: familyItem })
531
+ && !releasedForDevelopmentItemIds.includes(itemFamilyId)) {
502
532
  releasedForDevelopmentItemIds.push(itemFamilyId);
503
533
  }
504
- itemFamilySet.add(itemFamilyId);
534
+ itemFamilySet.add(itemFamilyId); // only mark resolved when we had data to judge
505
535
  }
506
536
  }
507
537
  }
@@ -539,7 +569,7 @@ class BaseProcessPublishAssortment {
539
569
  console.info('processPublish-start');
540
570
  const event = {
541
571
  assortmentId: pcd.assortmentId,
542
- assortmentPublishChangeId: pcd.assortmentPublishChangeId
572
+ assortmentPublishChangeId: pcd.assortmentPublishChangeId,
543
573
  };
544
574
  const assortmentItemFullChangeMap = this.getFullChangeAssortmentMap(fullChange);
545
575
  const assortmentItemDeleteMap = this.getDeleteChangesAssortmentMap(deleteChanges);
@@ -554,7 +584,7 @@ class BaseProcessPublishAssortment {
554
584
  console.log(message);
555
585
  return {
556
586
  results: { message, event },
557
- skip_await: true
587
+ skip_await: true,
558
588
  };
559
589
  }
560
590
  const results = await this.sendEvents(events);
@@ -599,7 +629,7 @@ class BaseProcessPublishAssortment {
599
629
  taskId: this.config.taskId,
600
630
  eventType,
601
631
  objectClass: 'LCSSeason',
602
- events
632
+ events,
603
633
  };
604
634
  const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
605
635
  const result = await this.sendAndRecordPublishEvent(flexPLMConnect, outboundPublishEvent);
@@ -645,13 +675,13 @@ class BaseProcessPublishAssortment {
645
675
  taskId: this.config.taskId,
646
676
  eventType,
647
677
  objectClass: 'LCSSeason',
648
- events
678
+ events,
649
679
  };
650
680
  await fileHandle.writeFile(JSON.stringify(outboundPublishEvent));
651
681
  results = {
652
682
  message: 'Successfully Saved File',
653
683
  outboundPublishEvent,
654
- fileLocation: dirName + fileName
684
+ fileLocation: dirName + fileName,
655
685
  };
656
686
  }
657
687
  catch (e) {
@@ -672,7 +702,7 @@ class BaseProcessPublishAssortment {
672
702
  objectClass: 'LCSSeason',
673
703
  eventsFileId: uploadFile.id,
674
704
  eventsDownloadLink: uploadFile.downloadUrl,
675
- eventsAdminDownloadLink: uploadFile.adminDownloadUrl
705
+ eventsAdminDownloadLink: uploadFile.adminDownloadUrl,
676
706
  };
677
707
  if (sendMode === 'vibeiqfile') {
678
708
  const flexPLMConnect = new flexplm_connect_1.FlexPLMConnect(this.config);
@@ -686,7 +716,7 @@ class BaseProcessPublishAssortment {
686
716
  await this.sendPublishPayloadEvent(outboundPublishEvent);
687
717
  return {
688
718
  message: 'Successfully Uploaded File.',
689
- outboundPublishEvent
719
+ outboundPublishEvent,
690
720
  };
691
721
  }
692
722
  }
@@ -702,11 +732,11 @@ class BaseProcessPublishAssortment {
702
732
  originSystemType: 'VibeIQ',
703
733
  objectClass: 'AssortmentPublishedToFlexPLM',
704
734
  outboundPublishEvent,
705
- initialEvent
735
+ initialEvent,
706
736
  };
707
737
  await new sdk_1.Entities().create({
708
738
  entityName: 'external-event',
709
- object: eventBody
739
+ object: eventBody,
710
740
  });
711
741
  }
712
742
  getCurrentDateString() {
@@ -730,7 +760,7 @@ class BaseProcessPublishAssortment {
730
760
  for (const [itemId, aItem] of assortmentItemFullChangeMap) {
731
761
  const projectItem = aItem?.projectItem;
732
762
  const itemFamilyId = aItem?.item?.itemFamilyId;
733
- if (!pcd.releasedForDevelopmentItemIds.includes(itemFamilyId) || !pcd.releasedForDevelopmentItemIds.includes(itemId)) {
763
+ if (!pcd.releasedForDevelopmentItemIds.includes(itemFamilyId)) {
734
764
  continue;
735
765
  }
736
766
  const ifc = itemFamilyChanges.get(itemFamilyId) || new item_family_changes_1.ItemFamilyChanges(itemFamilyId, pcd.sinceDate);
@@ -742,6 +772,20 @@ class BaseProcessPublishAssortment {
742
772
  if (pcd.itemToFederatedIdMapping.has(itemId)) {
743
773
  ifc.itemToFederatedIdMapping.set(itemId, pcd.itemToFederatedIdMapping.get(itemId));
744
774
  }
775
+ // ---- NEW Step to enable ItemFamily publish ET-243: option is pre-development. It must not produce an
776
+ // LCSSKUSeasonLink, but a change to it still makes the family publishable. ----
777
+ if (!pcd.releasedForDevelopmentItemIds.includes(itemId)) {
778
+ const changedInWindow = addIds.includes(itemId)
779
+ || deleteIds.includes(itemId)
780
+ || updateIds.includes(itemId)
781
+ || this.updatedSinceDate(projectItem, pcd.sinceDate)
782
+ || this.updatedSinceDate(aItem?.item, pcd.sinceDate);
783
+ if (changedInWindow) {
784
+ ifc.colorSuppressed.push(itemId);
785
+ }
786
+ continue;
787
+ }
788
+ // NEW Step - ends
745
789
  if (itemId === itemFamilyId) {
746
790
  if (addIds.includes(itemId))
747
791
  ifc.familyAdd = true;
@@ -757,6 +801,12 @@ class BaseProcessPublishAssortment {
757
801
  ifc.familyUpdate = true;
758
802
  }
759
803
  }
804
+ // NEW Step to enable ItemFamily publish ET-243: item-level edits (incl. lifecycleStage) must publish
805
+ // the family. Guarded so the "first option added" flow stays suppressed. ----
806
+ if (!ifc.familyItemRemoved && this.updatedSinceDate(aItem?.item, pcd.sinceDate)) {
807
+ ifc.familyUpdate = true;
808
+ }
809
+ // NEW Step - ends
760
810
  if (projectItem && !projectItem?.roles && aItem?.item?.roles) {
761
811
  projectItem.roles = aItem?.item?.roles;
762
812
  }
@@ -813,7 +863,7 @@ class BaseProcessPublishAssortment {
813
863
  else {
814
864
  ifc.colorDeletes.push(itemId);
815
865
  }
816
- } //End deletes for loop
866
+ } // End deletes for loop
817
867
  if (app_framework_1.Logger.isDebugOn()) {
818
868
  console.debug('returning size: ' + itemFamilyChanges.size);
819
869
  for (const [key, value] of itemFamilyChanges) {
@@ -855,13 +905,13 @@ class BaseProcessPublishAssortment {
855
905
  const LCSSeason = Object.assign({}, seasonFed);
856
906
  const assortment = await this.getAssortment(assortmentId);
857
907
  const projectItem = this.getProjectItem(itemFamilyChanges, itemFamilyChanges.itemFamilyId);
908
+ // ---- NEW Step to enable ItemFamily publish ET-243: added color suppressed length
858
909
  const familyAssortmentItem = itemFamilyChanges.familyAdd || itemFamilyChanges.familyUpdate || itemFamilyChanges.familyDelete
859
910
  || itemFamilyChanges.colorAdds.length > 0 || itemFamilyChanges.colorUpdates.length > 0 || itemFamilyChanges.colorDeletes.length > 0
911
+ || itemFamilyChanges.colorSuppressed.length > 0
860
912
  || (projectItem && this.updatedSinceDate(projectItem, itemFamilyChanges.sinceDate));
861
- //familyItemRemoved is used when adding the first option to an assortment
862
- //and will have updates for the family item.
863
913
  if (familyAssortmentItem) {
864
- //Product-season add
914
+ // Product-season add
865
915
  const entityReference = itemFamilyChanges.itemFamilyId;
866
916
  const prodEntityData = (itemFamilyChanges.assortmentItemFullChangeMap.has(entityReference))
867
917
  ? itemFamilyChanges.assortmentItemFullChangeMap.get(entityReference)?.item
@@ -877,7 +927,7 @@ class BaseProcessPublishAssortment {
877
927
  entityReference: 'item:' + entityReference,
878
928
  LCSSeason,
879
929
  LCSProduct,
880
- data: seasonalData
930
+ data: seasonalData,
881
931
  };
882
932
  if ('ASSORTMENT' === projectItem.addedFromSource && projectItem.addedFromAssortment) {
883
933
  const carriedFromSeason = await this.getCarriedFromSeason(projectItem);
@@ -887,9 +937,9 @@ class BaseProcessPublishAssortment {
887
937
  }
888
938
  events.push(psUpsert);
889
939
  }
890
- //colorway-season adds
891
- //colorAdds
892
- //colorUpdates
940
+ // colorway-season adds
941
+ // colorAdds
942
+ // colorUpdates
893
943
  const colorwayChanges = [];
894
944
  colorwayChanges.push(...itemFamilyChanges.colorAdds);
895
945
  colorwayChanges.push(...itemFamilyChanges.colorUpdates);
@@ -912,7 +962,7 @@ class BaseProcessPublishAssortment {
912
962
  entityReference: 'item:' + entityReference,
913
963
  LCSSeason,
914
964
  LCSSKU,
915
- data: seasonalData
965
+ data: seasonalData,
916
966
  };
917
967
  if ('ASSORTMENT' === projectItem.addedFromSource && projectItem.addedFromAssortment) {
918
968
  const carriedFromSeason = await this.getCarriedFromSeason(projectItem);
@@ -928,10 +978,10 @@ class BaseProcessPublishAssortment {
928
978
  let projectItem = {};
929
979
  if (itemFamilyChanges?.assortmentItemFullChangeMap.has(id)) {
930
980
  const aItem = itemFamilyChanges?.assortmentItemFullChangeMap.get(id);
931
- projectItem = aItem?.projectItem;
981
+ projectItem = aItem?.projectItem ?? {};
932
982
  }
933
983
  /////////////////////////////////////////////////////////////////////////////
934
- //Get from option assortmentItem because family not in assortmentItemFullChangeMap:start
984
+ // Get from option assortmentItem because family not in assortmentItemFullChangeMap:start
935
985
  /////////////////////////////////////////////////////////////////////////////
936
986
  if (id === itemFamilyChanges.itemFamilyId && Object.keys(projectItem).length == 0) {
937
987
  for (const asstItem of itemFamilyChanges.assortmentItemFullChangeMap.values()) {
@@ -942,7 +992,7 @@ class BaseProcessPublishAssortment {
942
992
  }
943
993
  }
944
994
  /////////////////////////////////////////////////////////////////////////////
945
- //Get from option assortmentItem because family not in assortmentItemFullChangeMap:end
995
+ // Get from option assortmentItem because family not in assortmentItemFullChangeMap:end
946
996
  /////////////////////////////////////////////////////////////////////////////
947
997
  return projectItem;
948
998
  }
@@ -992,7 +1042,7 @@ class BaseProcessPublishAssortment {
992
1042
  if (this.cache.carriedFromSeason[addedFromAssortment]) {
993
1043
  return this.cache.carriedFromSeason[addedFromAssortment];
994
1044
  }
995
- let seasonFederation = undefined;
1045
+ let seasonFederation;
996
1046
  const assortmentEntity = await this.getAssormentEntityFromId(addedFromAssortment);
997
1047
  if (assortmentEntity) {
998
1048
  seasonFederation = await this.getSeasonFederationFromAssortment(assortmentEntity);
@@ -1005,7 +1055,7 @@ class BaseProcessPublishAssortment {
1005
1055
  try {
1006
1056
  assortment = await new sdk_1.Entities().get({
1007
1057
  entityName: 'assortment',
1008
- id: assortmentId
1058
+ id: assortmentId,
1009
1059
  });
1010
1060
  }
1011
1061
  catch (e) {
@@ -1019,7 +1069,7 @@ class BaseProcessPublishAssortment {
1019
1069
  let seasonObj = {
1020
1070
  entityReference: 'assortment:' + assortment.id,
1021
1071
  objectClass: 'LCSSeason',
1022
- flexPLMTypePath
1072
+ flexPLMTypePath,
1023
1073
  };
1024
1074
  try {
1025
1075
  const assortmentObj = await this.dc.getFlexPLMObjectData(assortment, [], true);