function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
yearzeroyearzero 

Trigger on OpportunitySplit when Deleted

Still pretty new to coding so please excuse me if my questions are rudimentary :)

I'd like to keep an audit of our OpportunitySplits. For each Opportunity that has been deleted, I would like to create a record of a custom object I created called "Opportunity Split History" that retains the history of the Opportunity Split that was deleted. I wrote some code to do this but my test class is giving me the following error message: System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Missing value for required field(s): U#239.14ff (Opportunity): []. Based on the error message, I'm assuming that there is a field that is missing on the Opportunity but I can't seem to figure out which field it is. I've been looking at this for hours and I have no idea what is wrong. Any help would be appreciated. 

Here is my Test Class
@isTest(seeAllData = True)
public class OpportunitySplit_Trigger_Test {

    @isTest
	public static void Test_createOpportunitySplitHistoryDelete() {
        
		// Data setup
        User u = [SELECT Id FROM User WHERE Profile.Name = 'System Administrator' AND isActive = True Limit 1];
        User u2 = [SELECT Id FROM User WHERE Profile.Name = 'Nativo Standard User' AND isActive = True Limit 1];
		
        Id acctholdingCoRT = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Holding Company').getRecordTypeId();
        Id acctClientRT = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Client').getRecordTypeId();
        Id acctAgencyRT = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Agency').getRecordTypeId();
        
        Id oppManagedRT = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('Managed Service').getRecordTypeId();
        
        OpportunitySplitType oppSplitType1 = [SELECT ID FROM OpportunitySplitType WHERE DeveloperName = 'Revenue' Limit 1];
        
        List <OpportunitySplit> oppSplitList = new List<OpportunitySplit>();
        
		Account acc1 = new Account();
        acc1.Name = 'Nike';
        acc1.BillingState = 'CA';
        acc1.BillingCountry = 'US';
        acc1.RecordTypeId = acctClientRt;
        acc1.Credit_Status__c = 'Approved';
        insert acc1;
        
        Account holdingco1 = new Account();
        holdingco1.Name = 'WPP';
        holdingco1.BillingState = 'NY';
        holdingco1.BillingCountry = 'US';
        holdingco1.RecordTypeId = acctHoldingCoRT;
        holdingco1.Credit_Status__c = 'Approved';
        insert holdingco1;
        
        Account agcypar = new Account();
        agcypar.Name = 'OMG';
        agcypar.BillingState = 'NY';
        agcypar.BillingCountry = 'US';
        agcypar.RecordTypeId = acctAgencyRT;
        agcypar.Credit_Status__c = 'Approved';
        agcypar.Is_Parent_Agency__c = True;
        agcypar.Holding_Company__c = holdingco1.id;
        insert agcypar;
        
        Account agcy1 = new Account();
        agcy1.Name = 'Client Direct Child';
        agcy1.BillingState = 'NY';
        agcy1.BillingCountry = 'US';
        agcy1.RecordTypeId = acctAgencyRT;
        agcy1.ParentId = agcypar.id;
        agcy1.Holding_Company__c = holdingco1.id;
        agcy1.Credit_Status__c = 'Approved';
        insert agcy1;
        
        Opportunity opp1 = new Opportunity();
        opp1.Account = acc1;
        opp1.Agency__c = agcy1.id;
        opp1.Parent_Account__c = agcypar.id;
        opp1.Holding_Company__c = holdingco1.id;
        opp1.Agency_Credit_Status__c = agcy1.Credit_Status__c;
        opp1.Advertiser_Credit_Status__c = acc1.Credit_Status__c;
        opp1.Credit_Status__c = 'Approved';
        opp1.Amount = 100000;
        opp1.LeadSource = 'Cold Email';
        opp1.CloseDate = Date.today();
        opp1.Contract_End_Date__c = system.date.today().addMonths(2);
        opp1.StageName = 'Prospecting';
        opp1.Name = 'Nike Opportunity 07-31-2020';
        opp1.Type = 'New Business';
        opp1.RecordTypeId = [SELECT Id FROM RecordType WHERE Name = 'Managed Service' AND sObjectType = 'Opportunity' LIMIT 1].id;

        insert opp1;
        
        OpportunitySplit oppSplit1 = new OpportunitySplit();
        oppSplit1.Opportunity = opp1;
        oppSplit1.SplitPercentage = 50;
        oppSplit1.SplitOwnerId = u.id;
        oppSplit1.SplitTypeId = oppSplitType1.id;
        oppSplit1.SplitNote = 'Blah';
        
        
        OpportunitySplit oppSplit2 = new OpportunitySplit();
        oppSplit2.Opportunity = opp1;
        oppSplit2.SplitPercentage = 25;
        oppSplit2.SplitTypeId = oppSplitType1.id;
        oppSplit2.SplitNote = 'Blah Blah';
        
        OpportunitySplit oppSplit3 = new OpportunitySplit();
        oppSplit3.Opportunity = opp1;
        oppSplit3.SplitPercentage = 25;
        oppSplit3.SplitOwnerId = u2.id;
        oppSplit3.SplitTypeId = oppSplitType1.id;
        oppSplit3.SplitNote = 'Blah Blah Blah';
        

        oppSplitList.add(oppSplit1);
        oppSplitList.add(oppSplit2);
        oppSplitList.add(oppSplit3);
        
        insert oppSplitList;
        
		// Run the code
		Test.startTest();
        delete oppSplit3;
        oppSplit1.SplitPercentage = 75;
        update oppSplit1;
		
        List<Opportunity_Split_History__c> oppSplitHistList = new List<Opportunity_Split_History__c>();
        Opportunity_Split_History__c oppSplitHist1 = new Opportunity_Split_History__c();
        oppSplitHist1.Previous_Split__c = 25;
        oppSplitHist1.Previous_Split_Amount__c = 25000;
        oppSplitHist1.Previous_Split_Member__c = 'Mike Crowley';
        oppSplitHistList.add(oppSplitHist1);
        insert oppSplitHistList;
		Test.stopTest();
		
        System.assertEquals(oppSplitHistList.size(), 1);

	}
    
}
Here is my Handler Class
public class OpportunitySplit_Handler {
	
    public static void createOpportunitySplitHistoryDel(List<OpportunitySplit> oldList) {
        List<Opportunity_Split_History__c> oppSplitHistoryList = new List<Opportunity_Split_History__c>();
        for (OpportunitySplit oppSplit : oldList) {
            Opportunity_Split_History__c oppSplitHistory = new Opportunity_Split_History__c();
            oppSplitHistory.Previous_Split__c = oppSplit.SplitPercentage;
            oppSplitHistory.Previous_Split_Amount__c = oppSplit.SplitAmount;
            oppSplitHistory.Previous_Split_Member__c = oppSplit.SplitOwner.Name;
            oppSplitHistory.Date__c = Date.today();
            oppSplitHistory.Opportunity__c = oppSplit.OpportunityId;
            oppSplitHistory.History_Type__c = 'Delete';
			
            oppSplitHistoryList.add(oppSplitHistory);
            
        }
        
        if(oppSplitHistoryList.size()>0){           
    }
        insert oppSplitHistoryList;
}
    public static void createOpportunitySplitHistoryNew(List<OpportunitySplit> oldList){
        
    }
}

Here is my trigger
trigger OpportunitySplit_Trigger on OpportunitySplit (after delete) {    
    
    if (Trigger.isAfter && Trigger.isDelete) {
        OpportunitySplit_Handler.createOpportunitySplitHistoryDel(Trigger.old);
    }
    
    
}


 
ANUTEJANUTEJ (Salesforce Developers) 
Hi Yearzero,

You can try seeing the below links to fetch all the records by running the code in the anonymous window, also I would suggest you to check out the Object from the setup if there are any such fields that you might be missing.

>> https://developer.salesforce.com/forums/?id=906F00000008qYdIAI

>> https://www.forcetalks.com/salesforce-topic/how-to-find-all-required-field-of-sobject-in-salesforce/

In case if this comes handy can you please choose this as best answer so that it can be used by others in the future.

For quick reference the code in the above mentioned link is:
 
Schema.DescribeSObjectResult r = systemObjectType.getDescribe();
            Map<String,Schema.SObjectField> M = r.fields.getMap();
            for(String fieldName : M.keySet())
            { 
                Schema.SObjectField field = M.get(fieldName);
                Schema.DescribeFieldResult F = field.getDescribe();
               //A nillable field can have empty content. A isNillable Boolean non-nillable field must have a value for the object to be                       //created or saved. 
              // if F.isNillable() is false then field is mandatory
              Boolean isFieldreq  = F.isNillable()

Regards,
Anutej
yearzeroyearzero
Thanks Anutej. The code worked to get the required fields but since I'm working off of the Opportunity, there are a lot of fields that are system-generated like "IsSplit" that are required but still writeable. There are also other formula field that come up as being "required" when I use the code and with the volume of fields that are required, it's very difficult to determine what value is missing from my code. 

What's also strange is that the line of code that the error message is referencing is line 102 in my test class which is when I try to insert the list of OpportunitySplits. Do you think that there's something required on the Opportunity Split and not the Opportunity?