Deleting the original record after successfully cloning it can be accomplished with a combination of Apex, a custom field, a Process Builder, and Super Clone Pro configurations. This sounds like a lot, but I promise that it will be easy. These directions will give you the Apex code that lets a Process Builder delete records, and they will illustrate all of the other settings you’ll need.
Fist we will get the hard part out of the way first. We will need to deploy some Apex code. Process Builder does not have a feature that lets you delete records. It will let you call an Apex class that can delete records, and that is what we are doing here. The only thing that may need adjustment is the test class. This test class creates accounts in the test. It may need to be changed if your environment has additional requirements to create an account. If not, you should be good to go.
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ public with sharing class PbDeleteRecords { @InvocableVariable( Label='Record Id' Description='Record Id of an object' Required=false) public String RecordId; @InvocableMethod(Label='Delete Record' Description='Deletes records for Ids passed into the method') public static void deleteRecords(list<PbDeleteRecords> pfDeleteRecordsList) { map<Id, sObject> deleteMap = new map<Id, sObject>(); set<Id> idSet = new set<Id>(); for (PbDeleteRecords dlt : pfDeleteRecordsList) { // skip if blank if (String.isBlank(dlt.RecordId)) continue; // convert to Id type Id recId; try { recId = dlt.RecordId; } catch (exception e) { system.debug('Id exception: ' + e.getMessage()); continue; } // create sObject for deletion sObject sObj = recId.getSObjectType().newSObject(recId); // put in map to prevent duplicates deleteMap.put(sObj.Id, sObj); } if (!deleteMap.isEmpty()) { // allOrNone=false, so delete errors do not stop the processing. list<Database.DeleteResult> drList = database.delete(deleteMap.values(), false); for (Database.DeleteResult dr : drList) { if (dr.isSuccess()) { System.debug('Deleted Record Id: ' + dr.getId()); } else { for(Database.Error err : dr.getErrors()) { System.debug('Delete failure: ' + err.getStatusCode() + ' : ' + err.getMessage()); } } } } } }
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @isTest private class PbDeleteRecordsTest { @testSetup static void setup() { // Create common test accounts List<Account> acctList = new List<Account>(); for(Integer i=1;i<=4;i++) acctList.add(new Account(Name = 'TestAcct ('+i+')')); insert acctList; } @isTest static void testDelete1() { list<PbDeleteRecords> pbList = new list<PbDeleteRecords>(); // retrieve 3 of the 4 accounts to delete for (Account acc : [SELECT Id FROM Account LIMIT 3]) { PbDeleteRecords pb = new PbDeleteRecords(); pb.RecordId = acc.Id; pbList.add(pb); } // run the delete method test.startTest(); PbDeleteRecords.deleteRecords(pbList); test.stopTest(); system.assertEquals(1, [SELECT Id FROM Account].size()); } @isTest static void testDelete2() { list<PbDeleteRecords> pbList = new list<PbDeleteRecords>(); PbDeleteRecords pb; // test with deleted record id Account deleteAccount = [SELECT Id FROM Account LIMIT 1]; pb = new PbDeleteRecords(); pb.RecordId = deleteAccount.Id; pbList.add(pb); delete deleteAccount; // test with non-id value pb = new PbDeleteRecords(); pb.RecordId = 'NotAnId'; pbList.add(pb); // run the delete method test.startTest(); PbDeleteRecords.deleteRecords(pbList); test.stopTest(); system.assertEquals(3, [SELECT Id FROM Account].size()); } }
Next, lets create a custom field on the object that we will be deleting. Users should have Edit permission to the field, so Super Clone Pro can assign a value to the field. However, this field should not be displayed on any page layouts.
Now we will create a Process Builder flow to run the Apex class we deployed. The Process Builder logic will be set to only run on Insert to prevent the delete logic from running if someone accidentally enters a value into the field at a later date.
We are almost there. Now we need to set the Clone configuration to put the original record’s Id into the “Delete Source Id” custom field, so it is there for the Process Builder.
That’s it! That wasn’t too hard after we got the Apex class out of the way. Now the next time you clone, the original record will be deleted when the new record is inserted.
* Here is the disclaimer. The code comes with no warranty. I think it’s pretty good, but I’m bias because I wrote it. However, every Salesforce environment has a unique setup with different objects and custom logic, so there are bound to be instances where things don’t run as expected. This logic will delete records. Please test, test, and test some more before deploying any new logic.