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
l00p3yl00p3y 

Fresh Eyes, Would someone please assist with this issue.

I am receiving DML error "cannot_insert_update_activate_entity, CreateAssetonClosedWon Line 43 of testCreateAssetonClosedWon execution of BeforeUpdate" I thought the record was locked but I get the same error attempting to use AfterUpdate as well.

 

Test Class

@isTest 

private class testCreateAssetonClosedWon {
    
    static testMethod void testCreateAssetonClosedWon(){
    	System.debug('Alerting on --------> Starting the TestCreateAssetonClosedWon ');
        List<OpportunityLineItem> insertOl = new List<OpportunityLineItem>{};
        Account a = [select Id from Account limit 1];
        System.debug('Alerting on --------> Account a -'+a);
        PricebookEntry pbID = [select Id from PricebookEntry where isactive = true limit 1];
        System.debug('Alerting on --------> PricebookEntry a -'+pbID);
        List<Opportunity> opp = new List<Opportunity>{};
        
        for(Integer i=0;i<200;i++){
        	Opportunity o = new Opportunity();
        	o.AccountId = a.Id;
        	o.Name = 'test';
        	o.StageName = '0-Prospecting';
        	o.CloseDate = date.today();
        	opp.add(o);
       
        }
        	insert opp;
        	System.debug('Alerting on --------> Opportunity opp insert');
        	
        	for(Integer j=0;j<opp.size();j++){
        		OpportunityLineItem ol = new OpportunityLineItem();

			      	ol.OpportunityId = opp[j].Id;
      				ol.Quantity = 1;
       				ol.UnitPrice = 2.00;
	        		ol.PricebookEntryId = pbId.Id;
	        		insertOl.add(ol); 
        	}
        		insert insertOl;
        		System.debug('Alerting on --------> LineItem ol insert '+insertOl);
        	
        	for(Integer ou=0;ou <opp.size();ou++){
        		opp[ou].StageName = '8-Closed';
        		System.debug('Alerting on --------> Opportunity Stagel opp '+opp[ou].StageName+' - '+opp[ou].ID);
        	}
        	Test.startTest();
        	update opp;
        	Test.stopTest();

        
        //o.AccountId = a.Id;
        //o.Name = 'test';
        //o.StageName = '0-Prospecting';
        //o.CloseDate = date.today();
        //insert o;
        
//        ol.OpportunityId = o.Id;
//        ol.Quantity = 1;
//        ol.UnitPrice = 2.00;
//        ol.PricebookEntryId = pbId.Id;
        
//        insert ol;
        
//        o.StageName= '8-Closed';
//        update o;
        
       // delete ol;
        //delete o;
        
        
        
    }
    
    
}

 

Trigger:

trigger CreateAssetonClosedWon on Opportunity (after update) {
     Set<id> opSet = new Set<id>(); 
     for(Opportunity o:Trigger.new)
     	opSet.add(o.id); 
     	System.debug('Alerting on --------> Starting the CreateAssetonClosedWon Trigger');
     	Map<id, OpportunityLineItem> owners = new Map<id, OpportunityLineItem>([Select UnitPrice, Quantity, PricebookEntry.Product2Id, PricebookEntry.Product2.Name, Description, Converted_to_Asset__c  
                                      From OpportunityLineItem 
                                      where OpportunityId in :opSet  and Converted_to_Asset__c = false]);     	
     
 
     for(Opportunity o:Trigger.new)
      //if(o.isWon == true && o.HasOpportunityLineItem == true){
      if(Trigger.isUpdate){
      	if(o.stageName == '8-Closed' && o.HasOpportunityLineItem == true){
         Asset[] ast = new Asset[]{};
         Asset a = new Asset();
     //    for(OpportunityLineItem ol: OLI){
            a = new Asset();
            a.AccountId = o.AccountId;
            a.Product2Id = owners.get(o.Id).PricebookEntry.Product2Id; 
            a.Quantity = owners.get(o.Id).Quantity;
            a.Price =  owners.get(o.Id).UnitPrice;
            a.PurchaseDate = o.CloseDate;
            a.Status = 'Purchased';
            a.Description = owners.get(o.Id).Description;
            a.Name = owners.get(o.Id).PricebookEntry.Product2.Name;
            ast.add(a);
            owners.get(o.Id).Converted_to_Asset__c = true;
     //  }
      update owners.get(o.id); 
      insert ast;
     	}
      }
	}

 

Avidev9Avidev9

Do you have any trigger on Opp Line item that updates Opportunity ?

And also you seem to have DML inside for loop.

 

Ownes is a map OppLineItemId and OpplineItem if you do a get by O.Id I guess you will get null

 

Additionally try this

List<OpportunityLineItem> olis = new List<OpportunityLineItem>();
for(OpportunityLineItem ol: OLI){
a = new Asset(); a.AccountId = o.AccountId; a.Product2Id = owners.get(o.Id).PricebookEntry.Product2Id; a.Quantity = owners.get(o.Id).Quantity; a.Price = owners.get(o.Id).UnitPrice; a.PurchaseDate = o.CloseDate; a.Status = 'Purchased'; a.Description = owners.get(o.Id).Description; a.Name = owners.get(o.Id).PricebookEntry.Product2.Name; ast.add(a); owners.get(o.Id).Converted_to_Asset__c = true;
olis.add(owners.get(o.Id));
// }
update olis;
ryanjuptonryanjupton

I see a few immediate things. First none of the select statements in your test will return data since test methods don't have access to test data since version 24 of the API. You can either create a test account and pricebookentry or change your annotation to @isTest(SeeAllData=true). It's recommeded to create your own test classes though rather than select them.

Second, the way your trigger is structured all these statements

            a.Product2Id = owners.get(o.Id).PricebookEntry.Product2Id; 
            a.Quantity = owners.get(o.Id).Quantity;
            a.Price =  owners.get(o.Id).UnitPrice;
            a.Description = owners.get(o.Id).Description;
            a.Name = owners.get(o.Id).PricebookEntry.Product2.Name;

 will generate an error because owners is null at this point in your code.

Third, you have a nested SOQL query in your for loop which is asking for trouble once your recordset gets large. Hope that helps a bit.