afv-library/skills/platform-data-manage/assets/cleanup/delete-by-created-date.apex

320 lines
16 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* ═══════════════════════════════════════════════════════════════════════════════
* DELETE RECORDS BY CREATED DATE
* Clean up test records created within a specific time window
* ═══════════════════════════════════════════════════════════════════════════════
*
* PURPOSE:
* Delete records created during a testing session or time period.
* Useful when you know the approximate time test data was created.
*
* ⚠️ WARNING:
* Always PREVIEW records before deleting!
* Be careful with date ranges - you might delete production data!
*
* ═══════════════════════════════════════════════════════════════════════════════
*/
// ═══════════════════════════════════════════════════════════════════════════════
// CONFIGURATION
// ═══════════════════════════════════════════════════════════════════════════════
// Time window for records to delete
DateTime startTime = DateTime.now().addHours(-2); // 2 hours ago
DateTime endTime = DateTime.now(); // Now
// Optional: Add name pattern for extra safety
String namePattern = 'Test%'; // Set to null to skip name filter
Boolean useNameFilter = true; // Set to false to delete ALL records in time window
Boolean previewOnly = true; // Set to false to actually delete
Integer maxRecords = 10000; // Safety limit per object
// ═══════════════════════════════════════════════════════════════════════════════
// BUILD DYNAMIC QUERY CONDITIONS
// ═══════════════════════════════════════════════════════════════════════════════
String dateCondition = 'CreatedDate >= :startTime AND CreatedDate <= :endTime';
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('DELETE BY CREATED DATE');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('Time Window:');
System.debug(' Start: ' + startTime.format('yyyy-MM-dd HH:mm:ss'));
System.debug(' End: ' + endTime.format('yyyy-MM-dd HH:mm:ss'));
if (useNameFilter) {
System.debug('Name Filter: ' + namePattern);
}
System.debug('Mode: ' + (previewOnly ? 'PREVIEW ONLY' : '⚠️ DELETE MODE'));
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 1: PREVIEW ACCOUNTS
// ═══════════════════════════════════════════════════════════════════════════════
List<Account> accountsToDelete;
if (useNameFilter) {
accountsToDelete = [
SELECT Id, Name, CreatedDate, CreatedBy.Name
FROM Account
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
AND Name LIKE :namePattern
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
} else {
accountsToDelete = [
SELECT Id, Name, CreatedDate, CreatedBy.Name
FROM Account
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
}
System.debug('📋 ACCOUNTS in time window: ' + accountsToDelete.size());
if (!accountsToDelete.isEmpty()) {
System.debug(' Records:');
for (Integer i = 0; i < Math.min(10, accountsToDelete.size()); i++) {
Account acc = accountsToDelete[i];
System.debug(' - ' + acc.Name + ' (Created: ' + acc.CreatedDate.format('HH:mm:ss') + ' by ' + acc.CreatedBy.Name + ')');
}
if (accountsToDelete.size() > 10) {
System.debug(' ... and ' + (accountsToDelete.size() - 10) + ' more');
}
}
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 2: PREVIEW CONTACTS
// ═══════════════════════════════════════════════════════════════════════════════
List<Contact> contactsToDelete;
if (useNameFilter) {
contactsToDelete = [
SELECT Id, FirstName, LastName, Account.Name, CreatedDate, CreatedBy.Name
FROM Contact
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
AND (LastName LIKE :namePattern OR Account.Name LIKE :namePattern)
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
} else {
contactsToDelete = [
SELECT Id, FirstName, LastName, Account.Name, CreatedDate, CreatedBy.Name
FROM Contact
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
}
System.debug('📋 CONTACTS in time window: ' + contactsToDelete.size());
if (!contactsToDelete.isEmpty()) {
System.debug(' Records:');
for (Integer i = 0; i < Math.min(5, contactsToDelete.size()); i++) {
Contact con = contactsToDelete[i];
System.debug(' - ' + con.FirstName + ' ' + con.LastName + ' (Created: ' + con.CreatedDate.format('HH:mm:ss') + ')');
}
}
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 3: PREVIEW OPPORTUNITIES
// ═══════════════════════════════════════════════════════════════════════════════
List<Opportunity> opportunitiesToDelete;
if (useNameFilter) {
opportunitiesToDelete = [
SELECT Id, Name, Account.Name, StageName, Amount, CreatedDate
FROM Opportunity
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
AND (Name LIKE :namePattern OR Account.Name LIKE :namePattern)
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
} else {
opportunitiesToDelete = [
SELECT Id, Name, Account.Name, StageName, Amount, CreatedDate
FROM Opportunity
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
}
System.debug('📋 OPPORTUNITIES in time window: ' + opportunitiesToDelete.size());
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 4: PREVIEW TASKS
// ═══════════════════════════════════════════════════════════════════════════════
List<Task> tasksToDelete;
if (useNameFilter) {
tasksToDelete = [
SELECT Id, Subject, Status, CreatedDate
FROM Task
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
AND Subject LIKE :namePattern
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
} else {
tasksToDelete = [
SELECT Id, Subject, Status, CreatedDate
FROM Task
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
}
System.debug('📋 TASKS in time window: ' + tasksToDelete.size());
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 5: PREVIEW LEADS
// ═══════════════════════════════════════════════════════════════════════════════
List<Lead> leadsToDelete;
if (useNameFilter) {
leadsToDelete = [
SELECT Id, FirstName, LastName, Company, Status, CreatedDate
FROM Lead
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
AND (LastName LIKE :namePattern OR Company LIKE :namePattern)
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
} else {
leadsToDelete = [
SELECT Id, FirstName, LastName, Company, Status, CreatedDate
FROM Lead
WHERE CreatedDate >= :startTime
AND CreatedDate <= :endTime
ORDER BY CreatedDate DESC
LIMIT :maxRecords
];
}
System.debug('📋 LEADS in time window: ' + leadsToDelete.size());
System.debug('');
// ═══════════════════════════════════════════════════════════════════════════════
// SUMMARY
// ═══════════════════════════════════════════════════════════════════════════════
Integer totalRecords = accountsToDelete.size() + contactsToDelete.size() +
opportunitiesToDelete.size() + tasksToDelete.size() +
leadsToDelete.size();
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('SUMMARY - Records in time window');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug(' Accounts: ' + accountsToDelete.size());
System.debug(' Contacts: ' + contactsToDelete.size());
System.debug(' Opportunities: ' + opportunitiesToDelete.size());
System.debug(' Tasks: ' + tasksToDelete.size());
System.debug(' Leads: ' + leadsToDelete.size());
System.debug(' ─────────────────────────────────');
System.debug(' TOTAL: ' + totalRecords);
System.debug('═══════════════════════════════════════════════════════════════');
// ═══════════════════════════════════════════════════════════════════════════════
// STEP 6: DELETE (if not preview mode)
// ═══════════════════════════════════════════════════════════════════════════════
if (!previewOnly && totalRecords > 0) {
System.debug('');
System.debug('⚠️ DELETING RECORDS...');
Integer deletedCount = 0;
// Delete in correct order (children first, then parents)
if (!tasksToDelete.isEmpty()) {
delete tasksToDelete;
deletedCount += tasksToDelete.size();
System.debug(' ✓ Deleted ' + tasksToDelete.size() + ' Tasks');
}
if (!opportunitiesToDelete.isEmpty()) {
delete opportunitiesToDelete;
deletedCount += opportunitiesToDelete.size();
System.debug(' ✓ Deleted ' + opportunitiesToDelete.size() + ' Opportunities');
}
if (!contactsToDelete.isEmpty()) {
delete contactsToDelete;
deletedCount += contactsToDelete.size();
System.debug(' ✓ Deleted ' + contactsToDelete.size() + ' Contacts');
}
if (!leadsToDelete.isEmpty()) {
delete leadsToDelete;
deletedCount += leadsToDelete.size();
System.debug(' ✓ Deleted ' + leadsToDelete.size() + ' Leads');
}
if (!accountsToDelete.isEmpty()) {
delete accountsToDelete;
deletedCount += accountsToDelete.size();
System.debug(' ✓ Deleted ' + accountsToDelete.size() + ' Accounts');
}
System.debug('');
System.debug('═══════════════════════════════════════════════════════════════');
System.debug('DELETE COMPLETE: ' + deletedCount + ' records moved to Recycle Bin');
System.debug('═══════════════════════════════════════════════════════════════');
} else if (previewOnly) {
System.debug('');
System.debug(' PREVIEW MODE - No records deleted');
System.debug(' To delete, set previewOnly = false and run again');
}
// ═══════════════════════════════════════════════════════════════════════════════
// SF CLI ALTERNATIVE WITH DATE LITERALS
// ═══════════════════════════════════════════════════════════════════════════════
/*
Using SOQL date literals:
# Records created today
sf data query \
--query "SELECT Id FROM Account WHERE CreatedDate = TODAY AND Name LIKE 'Test%'" \
--target-org myorg \
--result-format csv \
> delete-today.csv
# Records created in the last hour
sf data query \
--query "SELECT Id FROM Account WHERE CreatedDate = LAST_N_HOURS:1 AND Name LIKE 'Test%'" \
--target-org myorg \
--result-format csv \
> delete-lasthour.csv
# Records created this week
sf data query \
--query "SELECT Id FROM Account WHERE CreatedDate = THIS_WEEK AND Name LIKE 'Test%'" \
--target-org myorg \
--result-format csv \
> delete-thisweek.csv
# Then bulk delete
sf data delete bulk \
--file delete-today.csv \
--sobject Account \
--target-org myorg \
--wait 30
*/