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
Rod Tyler 38Rod Tyler 38 

Trigger to turn OppLineItems to Account Assests

I am brand new to development so, please don't roll your eyes up too far... :p

I have this trigger I found that does exactly what I need (it appears). I understand everything it is doing except for the syntax here (for(OpportunityLineItem ol: OLI)) and the (update OLI) towards the end. 

Also, I know I need a test class but have no clue what I should test for and how to write it. Any brave soul able to help me out on this?
 
trigger CreateAssetonClosedWon on Opportunity (after insert, after update) {
    for(Opportunity o: trigger.new){
        //Check to see if the opportunity isWon and that it has line items
        if(o.isWon == true && o.HasOpportunityLineItems == true){
            String opptyId = o.id;

            //Query the opportunity line items
            OpportunityLineItem oli = [Select UnitPrice, Quantity, PricebookEntry, Product2Id, PricebookEntry, Product
                from OpportunityLineItem
                where OpportunityId = opptyId];
            
            //Assign values from query to new asset
            Asset ast = new Asset();
            for(OpportunityLineItem ol: OLI){
                a = new Asset();
            a.AccountId = o.AccountId;
                a.Product2Id = ol.PricebookEntry.Product2Id;
                a.Purchase_Opportunity__c = opptyId;
                a.Quantity = ol.Quantity;
                a.Price = ol.UnitPrice;
                a.PurchaseDate = o.CloseDate;
                a.Status = "Active";
                a.Description = oi.Description;
                a.Name = oi.PricebookEntry.Product2.Name;
                ast.add(a);
            }
        update OLI;
        //Creaet the record    
        insert ast;
        }
    }
}

 
ANUTEJANUTEJ (Salesforce Developers) 
Hi Rod,

So for the first part of the question regarding the for loop and update statement:

This is a variant of loop wherein the syntax is like for(item i : itemlist) where the item can be anything like Sobject or primitive datatypes and for every iteration, we access the constituents of the itemlist sequentially starting from the first and iterating till the end.

for more understanding of the loop, you can try checking this link: https://www.sfdc99.com/2013/10/06/loops-for-and-foreach-loops/

As you know salesforce is a multi tenant architecture so there are certain limits that are present on the orgs one such limit is the soql limit so to reduce the number of soqls executed what we do is instead of inserting every record in the for loop we would be adding the record to a list and then inserting/updating the whole list.

For the trigger class I would suggest changing the above one to the below one:
trigger CreateAssetonClosedWon on Opportunity (after insert, after update) {
    
    set<id> oid= new set<oid>();
    List<Opportunity> oplist =new List<Opportunity>();
    list<OpportunityLineItem> oli= new list<OpportunityLineItem>();
    list<Asset> ast = list<Asset>();
    
    for(Opportunity o: trigger.new){
        //Check to see if the opportunity isWon and that it has line items            
        if(o.isWon == true && o.HasOpportunityLineItems == true){
        oid.add(o.id)
        //Query the opportunity line items
        }}
    oplist = [select id,name,(Select UnitPrice, Quantity, PricebookEntry, Product2Id, PricebookEntry, Product
                              from OpportunityLineItem) from Opportunity
              where Id in :oid];
    map<id,list<OpportunityLineItem>> mapoppline = map<id,list<OpportunityLineItem>>();
    for(Opportunity o: oplist)
    {
        map.put(o.id , o.OpportunityLineItems);
    }
    for(Opportunity o: trigger.new)
    {
        oli=oplist.get(o.id);
        //Assign values from query to new asset         
        for(OpportunityLineItem ol: OLI){
            Asset a = new Asset();
            a.AccountId = o.AccountId;
            a.Product2Id = ol.PricebookEntry.Product2Id;
            a.Purchase_Opportunity__c = opptyId;
            a.Quantity = ol.Quantity;
            a.Price = ol.UnitPrice;
            a.PurchaseDate = o.CloseDate;
            a.Status = "Active";
            a.Description = oi.Description;
            a.Name = oi.PricebookEntry.Product2.Name;
            ast.add(a);
        }}
    update OLI;
    insert ast;
}
For test class you can try using the below code:
 
@isTest

public class setOpportunityOwner 

{

    public TestMethod static void setOpportunityOwner_Method()

    {

        Opportunity opp = New Opportunity();
        opp.name = ‘Hello’;
        opp.isWon = true;
        opp.HasOpportunityLineItems = true;

        opp.stageName = ‘Prospecting’;

        opp.CloseDate = Date.today();

        insert opp;

        OpportunityLineItem oline= new OpportunityLineItem();

        oline.OpportunityId =opp.id;
        //assign proper values to necessary fields to the above record
        insert oline;
        

    }

}
Also, can you mention why you are updating the oli in the above code I don't see any changes to the fields of oli record.

In case if no changes are done I don't think you would be needing the update oli statement in the trigger code.

Also, I would suggest having a look at https://salesforce.stackexchange.com/questions/10988/how-to-write-a-unit-test-test-class-for-trigger this would give a general idea of how they are written.

Let me know if it helps you and close your query by marking it as solved so that it can help others in the future.  

Thanks.