• Theodosia Tenia
  • NEWBIE
  • 0 Points
  • Member since 2015

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 3
    Questions
  • 4
    Replies

Hello,

I have a trigger that sets the revenue schedule for opportunity line items. It works fine for updaitng line items one at a time. But I have a few hundred opportunites that I have to migrate from and old SF org and when I try to add the products to these opportunites via the data loader I get an error that it is exceeding the amount of scheudles the trigger can perform at once.  I want to avoid doing this one by one and have been told that I just need to "bulkify" my trigger.  I am new apex so can someone help me understand how I would do that?  Is this a simple change?  And would it affect how the trigger fires when my seller's are adding new line items or updating exisitng ones for indivual opportunites?  

The trigger is included below:

trigger setRevenueSchedule on OpportunityLineItem (after insert, after update) {
    if(RecursionBlocker.flag){
                
        if (trigger.isAfter && trigger.isInsert){
            RevenueController.insertRevenue(trigger.new);
        }   
        
        if (trigger.isAfter && trigger.isUpdate){
            RevenueController.updateRevenue(trigger.newMap, trigger.oldMap);
        }     
    }//end of if recursionblocker is true.
    
}

Thanks in advance for any help!
 

Theo T

Hi, I currently have a trigger that sets the revenue schedule for opportunnity products.  Our SFDC is also integrated with an order management system (OMS) that has its own set of installed triggers which pushes back a revenue schedule once the order is sold and the opporutnity syncs with our OMS (note that this is propriatary and the company we use keeps the apex hidden so i have no insight into this code). We need both as our trigger allows us to flight revenue for the open pipeline and the OMS will update it to give us actual run revneue once a campaing is sold.  However, I am running into an issue where our revenue trigger is firing along with the trigger from our OMS whenever the OMS trys to adjust the schedule and it is causing revenue to be double counted. Since opportunites only sync to the OMS if the custom field i cerated is set to yes (it is a formula field that evaluates the sales stage and changes once it reaches 100%) I wuold like to amend our trigger to fire only the OMS_eligible__c field is set to "No".  If OMS_eligible__c is "Yes" then our trigger should just be ignored, allowing the OMS to make the update.

I have tried wrapping what we have in an if statement but when i test this i get the following error: 
'Apex trigger setRevenueSchedule caused an unexpected exception, contact your administrator: setRevenueSchedule: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.setRevenueSchedule: line 3, column 1 '

Here is the trigger:

trigger setRevenueSchedule on OpportunityLineItem (after insert, after update) {
   Opportunity o; { 
   if(o.OMS_Eligible__c=='No') {
    if(RecursionBlocker.flag){
                
        if (trigger.isAfter && trigger.isInsert){
            RevenueController.insertRevenue(trigger.new);
        }   
        
        if (trigger.isAfter && trigger.isUpdate){
            RevenueController.updateRevenue(trigger.newMap, trigger.oldMap);
        }     
    }//end of if recursionblocker is true.
  
} } 
}

Can someone help me understand what is going wrong?  Much appreciated.
 

Thanks!
 

Theo

I added the following apex classes and triggers to our Sandbox enviroment that worked fine but when I try to deploy it in production I got an error that apex classes need 75% coverge and triggerse need at least 1%.  Both are currently at 0%. How do I add code coverge in order to delpoy these?  Both classes and the trigger are included below:

SetRevenueSchedule
trigger setRevenueSchedule on OpportunityLineItem (after insert, after update) {
    if(RecursionBlocker.flag){
                
        if (trigger.isAfter && trigger.isInsert){
            RevenueController.insertRevenue(trigger.new);
        }   
        
        if (trigger.isAfter && trigger.isUpdate){
            RevenueController.updateRevenue(trigger.newMap, trigger.oldMap);
        }     
    }//end of if recursionblocker is true.
    
}


RecursionBlocker
public with sharing class RecursionBlocker {
  public static Boolean flag = true;
}

RevenueController
public class RevenueController
{   
    public static void insertRevenue(List<OpportunityLineItem> LI){
        List<OpportunityLineItemSchedule> oppLS = new List<OpportunityLineItemSchedule>();
        
        Date ServiceDate;
        Date EndDate;

        Decimal monthlyRevenue = 0, TotalPrice = 0, UnitPrice = 0;
    
        Integer NumberOfRevenueInstallments, numberOfDays;
        String RevenueInstallmentPeriod = 'Daily';
        String RevenueScheduleType = 'Divide';
               
        List<Id> oliIds = new List<Id>();
        for (OpportunityLineItem olit : LI){
            oliIds.add(olit.Id);
        }
        
        for (OpportunityLineItem item : [SELECT Id, ServiceDate, End_Date__c, UnitPrice, TotalPrice, PricebookEntryId FROM OpportunityLineItem WHERE Id IN :oliIds]) {
            
            ServiceDate = item.ServiceDate;
            EndDate = item.End_Date__c;
            TotalPrice = item.TotalPrice;
            UnitPrice = item.UnitPrice;
                    
            NumberOfRevenueInstallments = (((EndDate.year() * 12) + EndDate.MONTH()) - ((ServiceDate.year() * 12) + ServiceDate.month()));
            numberOfDays = ServiceDate.daysBetween(EndDate) + 1;
            
            monthlyRevenue = (TotalPrice / numberOfDays);
            
            Decimal computedRevenue = 0;
            for(Integer i=0; i<numberOfDays; i++){
                Date newDate = ServiceDate.addDays(i);
                computedRevenue = computedRevenue + monthlyRevenue;
                if(i == numberOfDays && (computedRevenue < TotalPrice || computedRevenue > TotalPrice)){
                    monthlyRevenue = (monthlyRevenue + (TotalPrice - computedRevenue)).abs();
                }
                if(i == numberOfDays && newDate > EndDate){
                    newDate = EndDate;
                }

            OpportunityLineItemSchedule opS = new OpportunityLineItemSchedule(OpportunityLineItemId = item.Id, Type='Revenue', Revenue = monthlyRevenue, ScheduleDate = newDate);
                oppLS.add(opS);
                                
            }
        }
                        
        RecursionBlocker.flag = false;
                                                
        try{
            insert oppLS;
            system.debug('#Success from insert :');
        } catch(system.DmlException e){
            system.debug('##Error OpportunityLineItemSchedule : ' + e.getMessage()); 
        }
    }   
        
    public static void updateRevenue(map<Id, OpportunityLineItem> newOppsMap, map<Id, OpportunityLineItem> oldOppsMap){
        
        List<OpportunityLineItemSchedule> oppLS = new List<OpportunityLineItemSchedule>();
        List<OpportunityLineItemSchedule> oldoppLS = new List<OpportunityLineItemSchedule>();
    
        list<OpportunityLineItem> newOppLiList = new list<OpportunityLineItem>();
        
        Date ServiceDate;
        Date EndDate;
        
        Decimal Revenue = 0, TotalPrice = 0;
    
        Integer NumberOfRevenueInstallments, numberOfDays;
        String RevenueInstallmentPeriod = 'Daily';
        String RevenueScheduleType = 'Divide';
        
        Set<Id> opportunityLineItemIds = new Set<Id>();
        Set<Id> newId = new Set<Id>();
        
        for(Id liId :newOppsMap.keySet()){
            opportunityLineItemIds.add(newOppsMap.get(liId).Id);
            OpportunityLineItem temp = new OpportunityLineItem();
            
            if((newOppsMap.get(liId).ServiceDate != oldOppsMap.get(liId).ServiceDate) || (newOppsMap.get(liId).End_Date__c != oldOppsMap.get(liId).End_Date__c)){
                newId.add(newOppsMap.get(liId).Id);
            }

            temp.OpportunityId = newOppsMap.get(liId).OpportunityId;
            newOppLiList.add(temp);
        }
        
        if(newId.size() > 0){
            for(OpportunityLineItemSchedule ps : [SELECT Id, OpportunityLineItemId From OpportunityLineItemSchedule Where OpportunityLineItemId IN :opportunityLineItemIds]){
                OpportunityLineItemSchedule tempS = new OpportunityLineItemSchedule();
                tempS.Id = ps.Id;
                oldoppLS.add(tempS);
            }
            
            for (OpportunityLineItem item : [SELECT Id, ServiceDate, End_Date__c, UnitPrice, TotalPrice, PricebookEntryId FROM OpportunityLineItem WHERE Id IN :opportunityLineItemIds]) {
                
                ServiceDate = item.ServiceDate;
                EndDate = item.End_Date__c;
                TotalPrice = item.UnitPrice;
                        
                NumberOfRevenueInstallments = (((EndDate.year() * 12) + EndDate.MONTH()) - ((ServiceDate.year() * 12) + ServiceDate.month()));
                numberOfDays = ServiceDate.daysBetween(EndDate);
                                
                Revenue = (TotalPrice / numberOfDays);
                
                Decimal computedRevenue = 0;
                for(Integer i=0; i<numberOfDays; i++){
                    Date newDate = ServiceDate.addDays(i);
                    computedRevenue = computedRevenue + Revenue;
                    if(i == numberOfDays && (computedRevenue < TotalPrice || computedRevenue > TotalPrice)){
                        Revenue = (Revenue + (TotalPrice - computedRevenue)).abs();
                    }
                    if(i == numberOfDays && newDate > EndDate){
                        newDate = EndDate;
                    }

                OpportunityLineItemSchedule opS = new OpportunityLineItemSchedule(OpportunityLineItemId = item.Id, Type='Revenue', Revenue = Revenue, ScheduleDate = newDate);
                    oppLS.add(opS);
                                    
                }
            }
                            
            RecursionBlocker.flag = false;
                                                            
            try{
                insert oppLS;
                system.debug('#Success insert oppLS : ' + oppLS.size());
            } catch(system.DmlException e){
                system.debug('##Error OpportunityLineItemSchedule : ' + e.getMessage()); 
            }
            
            try{
                delete oldoppLS;
                system.debug('#Success Delete oppLS');
            } catch(system.DmlException e){
                system.debug('##Error OpportunityLineItemSchedule : ' + e.getMessage()); 
            }   
        }
    }
}

Thanks!

Theo

Hello,

I have a trigger that sets the revenue schedule for opportunity line items. It works fine for updaitng line items one at a time. But I have a few hundred opportunites that I have to migrate from and old SF org and when I try to add the products to these opportunites via the data loader I get an error that it is exceeding the amount of scheudles the trigger can perform at once.  I want to avoid doing this one by one and have been told that I just need to "bulkify" my trigger.  I am new apex so can someone help me understand how I would do that?  Is this a simple change?  And would it affect how the trigger fires when my seller's are adding new line items or updating exisitng ones for indivual opportunites?  

The trigger is included below:

trigger setRevenueSchedule on OpportunityLineItem (after insert, after update) {
    if(RecursionBlocker.flag){
                
        if (trigger.isAfter && trigger.isInsert){
            RevenueController.insertRevenue(trigger.new);
        }   
        
        if (trigger.isAfter && trigger.isUpdate){
            RevenueController.updateRevenue(trigger.newMap, trigger.oldMap);
        }     
    }//end of if recursionblocker is true.
    
}

Thanks in advance for any help!
 

Theo T

Hi, I currently have a trigger that sets the revenue schedule for opportunnity products.  Our SFDC is also integrated with an order management system (OMS) that has its own set of installed triggers which pushes back a revenue schedule once the order is sold and the opporutnity syncs with our OMS (note that this is propriatary and the company we use keeps the apex hidden so i have no insight into this code). We need both as our trigger allows us to flight revenue for the open pipeline and the OMS will update it to give us actual run revneue once a campaing is sold.  However, I am running into an issue where our revenue trigger is firing along with the trigger from our OMS whenever the OMS trys to adjust the schedule and it is causing revenue to be double counted. Since opportunites only sync to the OMS if the custom field i cerated is set to yes (it is a formula field that evaluates the sales stage and changes once it reaches 100%) I wuold like to amend our trigger to fire only the OMS_eligible__c field is set to "No".  If OMS_eligible__c is "Yes" then our trigger should just be ignored, allowing the OMS to make the update.

I have tried wrapping what we have in an if statement but when i test this i get the following error: 
'Apex trigger setRevenueSchedule caused an unexpected exception, contact your administrator: setRevenueSchedule: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.setRevenueSchedule: line 3, column 1 '

Here is the trigger:

trigger setRevenueSchedule on OpportunityLineItem (after insert, after update) {
   Opportunity o; { 
   if(o.OMS_Eligible__c=='No') {
    if(RecursionBlocker.flag){
                
        if (trigger.isAfter && trigger.isInsert){
            RevenueController.insertRevenue(trigger.new);
        }   
        
        if (trigger.isAfter && trigger.isUpdate){
            RevenueController.updateRevenue(trigger.newMap, trigger.oldMap);
        }     
    }//end of if recursionblocker is true.
  
} } 
}

Can someone help me understand what is going wrong?  Much appreciated.
 

Thanks!
 

Theo