Skip to content

Commit b8b5cd4

Browse files
Merge pull request #428 from sf-kishore-kurri/u/kkurri/W-19837693
fix: @W-19837693: Handling multiple versions migration and assessment for Omniscript/Flexcards
2 parents 96375ee + dd5889b commit b8b5cd4

File tree

7 files changed

+1732
-20
lines changed

7 files changed

+1732
-20
lines changed

messages/assess.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616
"couldNotTruncate": "We couldn't clear all %s records.",
1717
"couldNotTruncateOmnniProcess": "We couldn't clear all records of your %s because the %s is referenced in an Omniscript or a Flexcard.",
1818
"invalidOrRepeatingOmniscriptElementNames": "Omniscript with invalid or duplicate element names found. Rename your Omniscript elements and try again.",
19-
"duplicatedCardName": "Flexcard with duplicate name, type, subtype, or language found in this org. Modify your Flexcard and try again.",
19+
"duplicatedCardName": "Flexcard with duplicate name found in this org. Modify your Flexcard and try again.",
2020
"duplicatedDrName": "Data Mapper with duplicate name found in this org. Rename your Data Mapper and try again.",
2121
"duplicatedOSName": "Omniscript with duplicate name, type, subtype, or language found in this org. Modify your Omniscript and try again.",
22-
"duplicatedName": "Duplicated name",
22+
"duplicatedName": "Duplicated name %s",
23+
"lowerVersionDuplicateOmniscriptName": "A %s with name \"%s\" will not be migrated because lower version of same %s will be marked as duplicate, which could lead to conflicts during migration.",
2324
"errorWhileActivatingOs": "We couldn't activate your %s:",
2425
"errorWhileActivatingCard": "We couldn't activate your Flexcard:",
2526
"errorWhileUploadingCard": "We couldn't deploy your Flexcard to your org. Review these errors:",
@@ -38,10 +39,10 @@
3839
"processingDataRaptor": "Processing Data Mapper: %s",
3940
"processingOmniScript": "Processing Omniscript: %s",
4041
"foundDataRaptorsToAssess": "Found %s Data Mappers to assess.",
41-
"foundOmniScriptsToAssess": "Found %s Omniscripts to assess",
42+
"foundOmniScriptsToAssess": "Found %s %s to assess",
4243
"foundGlobalAutoNumbersToAssess": "Found %s Omni Global Auto Numbers to assess.",
4344
"startingDataRaptorAssessment": "Starting Data Mapper assessment",
44-
"startingOmniScriptAssessment": "Starting Omniscript assessment",
45+
"startingOmniScriptAssessment": "Starting %s assessment",
4546
"startingGlobalAutoNumberAssessment": "Starting Omni Global Auto Number assessment",
4647
"allVersionsInfo": "All versions: %s",
4748
"assessmentInitialization": "Assessment process started. Using namespace: %s",
@@ -97,6 +98,7 @@
9798
"integrationProcedureNameChangeMessage": "The Integration Procedure %s will be renamed to %s during migration.",
9899
"integrationProcedureManualUpdateMessage": "All references to %s in this Integration Procedure must be manually updated after migration.",
99100
"duplicateCardNameMessage": "A Flexcard with the same name \"%s\" already exists after name cleaning, which could lead to conflicts during migration.",
101+
"lowerVersionDuplicateCardNameMessage": "A Flexcard with the name \"%s\" will not be migrated because lower version of same card will be marked as duplicate, which could lead to conflicts during migration.",
100102
"startingCustomLabelAssessment": "Starting Custom Label assessment",
101103
"assessedCustomLabelsCount": "Found %s labels that need attention out of %s total",
102104
"customLabelAssessmentCompleted": "Custom Label assessment completed",

messages/migrate.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
"couldNotTruncate": "We couldn't clear all %s records.",
2020
"couldNotTruncateOmnniProcess": "We couldn't clear all records of your %s because the %s is referenced in an Omniscript or a Flexcard.",
2121
"invalidOrRepeatingOmniscriptElementNames": "Omniscript with invalid or duplicate element names found. Rename your Omniscript elements and try again.",
22-
"duplicatedCardName": "Flexcard with duplicate name, type, subtype, or language found in this org. Modify your Flexcard and try again.",
22+
"lowerVersionDuplicateCardName": "Flexcard with name %s can't be migrated because lower version of same card is probable duplicate. Rename your Flexcard and try again.",
23+
"duplicatedCardName": "Flexcard with duplicate name %s found in this org. Rename your Flexcard and try again.",
2324
"duplicatedDrName": "Data Mapper with duplicate name found in this org. Rename your Data Mapper and try again.",
2425
"duplicatedOSName": "Omniscript with duplicate name, type, subtype, or language found in this org. Modify your Omniscript and try again.",
26+
"lowerVersionDuplicateOSName": "%s with name %s can't be migrated because lower version of same %s is probable duplicate. Rename your %s and try again.",
2527
"errorWhileActivatingOs": "We couldn't activate your %s:",
2628
"errorWhileActivatingCard": "We couldn't activate your Flexcard:",
2729
"errorWhileUploadingCard": "We couldn't deploy your Flexcard to your org. Review these errors:",

src/migration/flexcard.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,12 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
165165
const progressBar = createProgressBar('Assessing', 'Flexcards');
166166
progressBar.start(flexCards.length, progressCounter);
167167
const uniqueNames = new Set<string>();
168+
const dupFlexCardNames: Map<string, string> = new Map<string, string>();
168169

169170
// Now process each OmniScript and its elements
170171
for (const flexCard of flexCards) {
171172
try {
172-
const flexCardAssessmentInfo = await this.processFlexCard(flexCard, uniqueNames);
173+
const flexCardAssessmentInfo = await this.processFlexCard(flexCard, uniqueNames, dupFlexCardNames);
173174
flexCardAssessmentInfos.push(flexCardAssessmentInfo);
174175
} catch (e) {
175176
flexCardAssessmentInfos.push({
@@ -196,7 +197,11 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
196197
return flexCardAssessmentInfos;
197198
}
198199

199-
private async processFlexCard(flexCard: AnyJson, uniqueNames: Set<string>): Promise<FlexCardAssessmentInfo> {
200+
private async processFlexCard(
201+
flexCard: AnyJson,
202+
uniqueNames: Set<string>,
203+
dupFlexCardNames: Map<string, string>
204+
): Promise<FlexCardAssessmentInfo> {
200205
const flexCardName = flexCard['Name'];
201206
Logger.info(this.messages.getMessage('processingFlexCard', [flexCardName]));
202207
const version = flexCard[this.namespacePrefix + CardMigrationTool.VERSION_PROP];
@@ -231,11 +236,29 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
231236

232237
// Check for duplicate names (include version when allVersions is true)
233238
const uniqueCleanedName = this.allVersions ? `${cleanedName}_${version}` : cleanedName;
239+
240+
// Check for exact duplicate (same name + same version)
234241
if (uniqueNames.has(uniqueCleanedName)) {
235242
flexCardAssessmentInfo.warnings.push(this.messages.getMessage('duplicateCardNameMessage', [uniqueCleanedName]));
236243
assessmentStatus = getUpdatedAssessmentStatus(assessmentStatus, 'Needs manual intervention');
237244
}
245+
// Check for naming conflict: different original names cleaning to same name
246+
else if (this.allVersions && dupFlexCardNames.has(cleanedName)) {
247+
const existingOriginalName = dupFlexCardNames.get(cleanedName);
248+
// Only flag if the original names are different (indicates a naming conflict)
249+
if (existingOriginalName !== originalName) {
250+
flexCardAssessmentInfo.warnings.push(
251+
this.messages.getMessage('lowerVersionDuplicateCardNameMessage', [uniqueCleanedName])
252+
);
253+
assessmentStatus = getUpdatedAssessmentStatus(assessmentStatus, 'Needs manual intervention');
254+
}
255+
}
256+
257+
// Add to tracking structures
238258
uniqueNames.add(uniqueCleanedName);
259+
if (this.allVersions && !dupFlexCardNames.has(cleanedName)) {
260+
dupFlexCardNames.set(cleanedName, originalName);
261+
}
239262

240263
// Check for author name changes
241264
const originalAuthor = flexCard[this.namespacePrefix + 'Author__c'];
@@ -721,11 +744,13 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
721744
const cardsUploadInfo = new Map<string, UploadRecordResult>();
722745
const originalRecords = new Map<string, any>();
723746
const uniqueNames = new Set<string>();
747+
// Map to track cleanedName -> originalName for duplicate detection
748+
const dupFlexCardNames: Map<string, string> = new Map<string, string>();
724749

725750
let progressCounter = 0;
726751
progressBar.start(cards.length, progressCounter);
727752
for (let card of cards) {
728-
await this.uploadCard(cards, card, cardsUploadInfo, originalRecords, uniqueNames);
753+
await this.uploadCard(cards, card, cardsUploadInfo, originalRecords, uniqueNames, dupFlexCardNames);
729754
progressBar.update(++progressCounter);
730755
}
731756

@@ -741,7 +766,8 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
741766
card: AnyJson,
742767
cardsUploadInfo: Map<string, UploadRecordResult>,
743768
originalRecords: Map<string, any>,
744-
uniqueNames: Set<string>
769+
uniqueNames: Set<string>,
770+
dupFlexCardNames: Map<string, string>
745771
) {
746772
const recordId = card['Id'];
747773

@@ -758,7 +784,7 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
758784
// Upload child cards
759785
const childCard = allCards.find((c) => c['Name'] === childCardName);
760786
if (childCard) {
761-
await this.uploadCard(allCards, childCard, cardsUploadInfo, originalRecords, uniqueNames);
787+
await this.uploadCard(allCards, childCard, cardsUploadInfo, originalRecords, uniqueNames, dupFlexCardNames);
762788
}
763789
}
764790

@@ -783,14 +809,31 @@ export class CardMigrationTool extends BaseMigrationTool implements MigrationToo
783809
? `${transformedCard['Name']}_${transformedCard['VersionNumber']}`
784810
: transformedCard['Name'];
785811

812+
const originalCardName = card['Name'];
813+
const cleanedCardName = transformedCard['Name'];
814+
815+
// Check for exact duplicate (same name + same version)
786816
if (uniqueNames.has(uniqueCheckName)) {
787817
this.setRecordErrors(card, this.messages.getMessage('duplicatedCardName', [uniqueCheckName]));
788818
originalRecords.set(recordId, card);
789819
return;
790820
}
821+
// Check for naming conflict: different original names cleaning to same name
822+
else if (this.allVersions && dupFlexCardNames.has(cleanedCardName)) {
823+
const existingOriginalName = dupFlexCardNames.get(cleanedCardName);
824+
// Only flag if the original names are different (indicates a naming conflict)
825+
if (existingOriginalName !== originalCardName) {
826+
this.setRecordErrors(card, this.messages.getMessage('lowerVersionDuplicateCardName', [uniqueCheckName]));
827+
originalRecords.set(recordId, card);
828+
return;
829+
}
830+
}
791831

792-
// Save the name for duplicated names check (with version if allVersions is true)
832+
// Add to tracking structures
793833
uniqueNames.add(uniqueCheckName);
834+
if (this.allVersions && !dupFlexCardNames.has(cleanedCardName)) {
835+
dupFlexCardNames.set(cleanedCardName, originalCardName);
836+
}
794837

795838
// Create a map of the original records
796839
originalRecords.set(recordId, card);

src/migration/omniscript.ts

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
238238
const ipAssessmentInfos: IPAssessmentInfo[] = [];
239239

240240
// Create a set to store existing OmniScript names and also extract DataRaptor and FlexCard names
241+
// Map to track cleanedName (without version) -> originalName (without version) for duplicate detection
242+
const duplicateOmniscriptNames: Map<string, string> = new Map<string, string>();
241243
const existingOmniscriptNames = new Set<string>();
242244
const existingDataRaptorNames = new Set(dataRaptorAssessmentInfos.map((info) => info.name));
243245
const existingFlexCardNames = new Set(flexCardAssessmentInfos.map((info) => info.name));
@@ -256,7 +258,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
256258
omniscript,
257259
existingOmniscriptNames,
258260
existingDataRaptorNames,
259-
existingFlexCardNames
261+
existingFlexCardNames,
262+
duplicateOmniscriptNames
260263
);
261264
} catch (e) {
262265
const omniProcessType = omniscript[this.namespacePrefix + 'IsProcedure__c']
@@ -356,7 +359,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
356359
omniscript: AnyJson,
357360
existingOmniscriptNames: Set<string>,
358361
existingDataRaptorNames: Set<string>,
359-
existingFlexCardNames: Set<string>
362+
existingFlexCardNames: Set<string>,
363+
duplicateOmniscriptNames: Map<string, string>
360364
): Promise<OSAssessmentInfo> {
361365
const elements = await this.getAllElementsForOmniScript(omniscript['Id']);
362366

@@ -504,6 +508,11 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
504508
? `${omniscript[this.namespacePrefix + 'Language__c']}`
505509
: '';
506510

511+
const recordNameWithoutVersion =
512+
`${newType}_` +
513+
`${newSubType}` +
514+
(omniscript[this.namespacePrefix + 'Language__c'] ? `_${omniscript[this.namespacePrefix + 'Language__c']}` : '');
515+
507516
const recordName =
508517
`${newType}_` +
509518
`${newSubType}` +
@@ -562,11 +571,43 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
562571
);
563572
assessmentStatus = 'Warnings';
564573
}
565-
if (existingOmniscriptNames.has(recordName)) {
566-
warnings.push(this.messages.getMessage('duplicatedName') + ' ' + recordName);
574+
// Duplicate check logic using Map to track originalName -> cleanedName
575+
// This allows us to detect both exact duplicates and name cleaning conflicts
576+
const nameToCheck = this.allVersions ? recordName : recordNameWithoutVersion;
577+
578+
// Get the original name parts (before cleaning)
579+
const originalType = omniscript[this.namespacePrefix + 'Type__c'];
580+
const originalSubType = omniscript[this.namespacePrefix + 'SubType__c'];
581+
const originalLanguage = omniscript[this.namespacePrefix + 'Language__c'] || '';
582+
const originalNameWithoutVersion = originalLanguage
583+
? `${originalType}_${originalSubType}_${originalLanguage}`
584+
: `${originalType}_${originalSubType}`;
585+
586+
// Check for exact duplicate (same name + version)
587+
if (existingOmniscriptNames.has(nameToCheck)) {
588+
warnings.push(this.messages.getMessage('duplicatedName', [recordName]));
567589
assessmentStatus = 'Needs manual intervention';
568-
} else {
569-
existingOmniscriptNames.add(recordName);
590+
}
591+
// Check for naming conflict: different original names cleaning to same name
592+
else if (this.allVersions && duplicateOmniscriptNames.has(recordNameWithoutVersion)) {
593+
const existingOriginalName = duplicateOmniscriptNames.get(recordNameWithoutVersion);
594+
// Only flag if the original names are different (indicates a naming conflict)
595+
if (existingOriginalName !== originalNameWithoutVersion) {
596+
warnings.push(
597+
this.messages.getMessage('lowerVersionDuplicateOmniscriptName', [
598+
this.getName(true),
599+
recordName,
600+
this.getName(true),
601+
])
602+
);
603+
assessmentStatus = 'Needs manual intervention';
604+
}
605+
}
606+
607+
// Add to tracking structures
608+
existingOmniscriptNames.add(nameToCheck);
609+
if (this.allVersions && !duplicateOmniscriptNames.has(recordNameWithoutVersion)) {
610+
duplicateOmniscriptNames.set(recordNameWithoutVersion, originalNameWithoutVersion);
570611
}
571612

572613
// Add warning for duplicate element names within the same OmniScript
@@ -692,6 +733,8 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
692733
populateRegexForFunctionMetadata(functionDefinitionMetadata);
693734

694735
const duplicatedNames = new Set<string>();
736+
// Map to track cleanedName (without version) -> originalName (without version) for duplicate detection
737+
const duplicateOmniscriptNames: Map<string, string> = new Map<string, string>();
695738

696739
// Variables to be returned After Migration
697740
let originalOsRecords = new Map<string, any>();
@@ -971,9 +1014,18 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
9711014
}
9721015

9731016
// Check duplicated name
974-
let mappedOsName;
1017+
let mappedOsName: string;
1018+
const mappedOsNameWithoutVersion =
1019+
mappedOmniScript[OmniScriptMappings.Type__c] +
1020+
'_' +
1021+
mappedOmniScript[OmniScriptMappings.SubType__c] +
1022+
(mappedOmniScript[OmniScriptMappings.Language__c]
1023+
? '_' + mappedOmniScript[OmniScriptMappings.Language__c]
1024+
: '');
1025+
9751026
if (this.allVersions) {
9761027
mappedOmniScript[OmniScriptMappings.Version__c] = omniscript[`${this.namespacePrefix}Version__c`];
1028+
9771029
mappedOsName =
9781030
mappedOmniScript[OmniScriptMappings.Type__c] +
9791031
'_' +
@@ -994,8 +1046,16 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
9941046
'_1';
9951047
}
9961048

1049+
// Get original name parts for tracking
1050+
const originalType = omniscript[this.namespacePrefix + 'Type__c'];
1051+
const originalSubType = omniscript[this.namespacePrefix + 'SubType__c'];
1052+
const originalLanguage = omniscript[this.namespacePrefix + 'Language__c'] || '';
1053+
const originalNameWithoutVersion = originalLanguage
1054+
? `${originalType}_${originalSubType}_${originalLanguage}`
1055+
: `${originalType}_${originalSubType}`;
1056+
1057+
// Check for exact duplicate (same name + same version)
9971058
if (duplicatedNames.has(mappedOsName)) {
998-
originalOsRecords.set(recordId, omniscript);
9991059
const warningMessage = this.messages.getMessage('duplicatedOSName', [this.getName(true), mappedOsName]);
10001060
const skippedResponse: UploadRecordResult = {
10011061
referenceId: recordId,
@@ -1008,8 +1068,35 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
10081068
skipped: true,
10091069
};
10101070
osUploadInfo.set(recordId, skippedResponse);
1071+
originalOsRecords.set(recordId, omniscript);
10111072
continue;
10121073
}
1074+
// Check for naming conflict: different original names cleaning to same name
1075+
else if (this.allVersions && duplicateOmniscriptNames.has(mappedOsNameWithoutVersion)) {
1076+
const existingOriginalName = duplicateOmniscriptNames.get(mappedOsNameWithoutVersion);
1077+
// Only flag if the original names are different (indicates a naming conflict)
1078+
if (existingOriginalName !== originalNameWithoutVersion) {
1079+
const warningMessage = this.messages.getMessage('lowerVersionDuplicateOSName', [
1080+
this.getName(true),
1081+
mappedOsName,
1082+
this.getName(true),
1083+
this.getName(true),
1084+
]);
1085+
const skippedResponse: UploadRecordResult = {
1086+
referenceId: recordId,
1087+
id: '',
1088+
success: false,
1089+
hasErrors: false,
1090+
errors: [],
1091+
warnings: [warningMessage],
1092+
newName: '',
1093+
skipped: true,
1094+
};
1095+
osUploadInfo.set(recordId, skippedResponse);
1096+
originalOsRecords.set(recordId, omniscript);
1097+
continue;
1098+
}
1099+
}
10131100

10141101
// Save the mapped record
10151102
mappedRecords.push(mappedOmniScript);
@@ -1059,8 +1146,14 @@ export class OmniScriptMigrationTool extends BaseMigrationTool implements Migrat
10591146
'_1';
10601147
}
10611148
// Always set the new name to show the migrated name
1062-
// Add the processednew name to the duplicated set
1149+
// Add the processed new name to the duplicated set
10631150
duplicatedNames.add(mappedOsName);
1151+
1152+
// Add to map for tracking naming conflicts (only when allVersions=true)
1153+
if (this.allVersions && !duplicateOmniscriptNames.has(mappedOsNameWithoutVersion)) {
1154+
duplicateOmniscriptNames.set(mappedOsNameWithoutVersion, originalNameWithoutVersion);
1155+
}
1156+
10641157
osUploadResponse.newName = mappedOsName;
10651158

10661159
// Only add warning if the name was actually modified

0 commit comments

Comments
 (0)