2

I need to invoke my Apex Class whenever certain fields are changed on an Opportunity.

I'd rather change the method of the class to make it invocable - if possible - instead of modifying it's Trigger because frankly, I don't understand how the two sets of code relate to each other.

The Class can then be invoked by the Lightning Process Builder, which also gives me more flexibility if, for example, I want to redefine the fields that should invoke the Class when changed.

Here's the code (which I didn't write).

I've had to remove portions of the code in order to meet the maximum character limit for this post.

global class CP_MonthlyRevenueForecastController{

    webservice static string createMonthlyForecastRecords(String opportunityId){
        system.debug(opportunityId +' OPPID ');

        //Get active currency types
        final List<CurrencyType> currencyTypeList = [select IsoCode, ConversionRate
                                                     from CurrencyType
                                                     where IsActive = true];
        ID recordTypeId = [select id,Name from RecordType where Name='CP Non Disbursement' and SobjectType='Monthly_Revenue_Forecast__c'].Id; 
        /* Fetch current opportunity record Detail */
        Opportunity opportunity = [Select id,AccountId, etc where id=:opportunityId];
        system.debug(opportunity+'PPPPPPPPPPP');
        /* if(opportunity.Amount == null){
opportunity.Amount = 0.0;
} */
        system.debug(opportunity.Annual_Revenue__c+'AAAAAAA1');
        if(opportunity.Annual_Revenue__c == null){
            opportunity.Annual_Revenue__c = 0.0;
        }

        // Map holding string equivalent of months
        Map<Integer,String> monthName = new Map<Integer,String>{1 => 'January' , etc};


        final Set<String> mandatoryFieldsForProductVirtualPrepaidVE = new Set<String>(
            new String[] {
                'Card_Issue_Revenue__c',
                    'Monthly_Card_Revenue__c',
                    //etc
                    }
        );

        final Set<String> mandatoryFieldsForProductVirtualCredit = new Set<String>(
            new String[] {
                'Card_Issue_Revenue__c',
                    'Monthly_Card_Revenue__c',
                    //etc
                    }
        );
        final List<String> mandatoryFieldsThatAreNull = new List<String>();

                }
            }
        }
        else if(opportunity.Record_Type_Name__c == 'CP Virtual Credit'){
            for (String fieldName : mandatoryFieldsForProductVirtualCredit) {
                if (opportunity.get(fieldName) == null) {
                    //Mandatory field is null
                    mandatoryFieldsThatAreNull.add('Value for "' + fieldName + '" is required.');
                }
            }
        }

        if(!mandatoryFieldsThatAreNull.isEmpty()){

            String mandatoryValues = '';
            for(String str : mandatoryFieldsThatAreNull)
            {
                mandatoryValues = mandatoryValues+ '\n'+str;

            }

            return mandatoryValues;

        }
        /* Check wheather Monthly Revenue Forecast records are present for the Opportunity or not */
        List<Monthly_Revenue_Forecast__c> monthlyForecastRevenue = [Select id,Monthly_Revenue__c,Revenue_Date__c from Monthly_Revenue_Forecast__c where opportunity__c =:opportunityId];
        /* Assign Opportunity Record Type to String remove the prefix CP_ or CP */
        String str = opportunity.Record_Type_Name__c;//'CP_Virtual Credit';
        Integer i = str.length();
        String recordTypeName = str.substring(3,i);

        /* If there are no Monthly Forecast Revenue record */

        if(monthlyForecastRevenue.isEmpty()){           

            /* Fetch custom setting record(coefficients) for particular product */
            List<CP_Seasonality_Coefficient__c> seasonalityCoefficientRecord = [select id,Name,Jan__c, etc where Name =:recordTypeName LIMIT 1]; 
            system.debug(seasonalityCoefficientRecord + 'HHHHHH');

            if(seasonalityCoefficientRecord.isEmpty()){

                return 'No coefficients for this product';    

            }else{                

                monthlyForecastRevenue = new List<Monthly_Revenue_Forecast__c>();               

                Decimal annualRev = 0.0;
                List<Double> monthsVariables = new List<Double>{0.0,seasonalityCoefficientRecord[0].Jan__c, etc}; 
                    system.debug(monthsVariables+'MMMMMMMM');

                //Date d = Date.today();
                Integer yr = opportunity.Implementation_Revenue__c.year();                
                Integer mnt = opportunity.Implementation_Revenue__c.month();
                Date d2 = date.newinstance((yr+1),1,1);
                Date d = date.newinstance(yr,mnt,1);
                Decimal currentCoef = monthsVariables[mnt];
                /*Create Monthly Forecast Revenue Record for the remaing month of the year from current month */
                for(Integer mon = mnt;mon<13;mon++){


                    PopulateAllTheFields p = calculateMonthlyRevenue(opportunity,currentCoef,monthsVariables[mon],mon,yr);
                    Monthly_Revenue_Forecast__c monForecast = new Monthly_Revenue_Forecast__c();
                    monForecast.Opportunity__c  = opportunityId;  
                    monForecast.Account__c = opportunity.AccountId;
                    monForecast.Name = monthName.get(mon)+' '+String.valueOf(yr);

                    if(mon == opportunity.Implementation_Revenue__c.month()){
                        monForecast.Implementation_Fee__c = opportunity.Implementation__c;
                        monForecast.Monthly_Revenue__c = p.totalRev+opportunity.Implementation__c;                    
                    }else{
                        monForecast.Implementation_Fee__c = 0;
                        monForecast.Monthly_Revenue__c = p.totalRev; 

                    }
                    annualRev = annualRev + p.totalRev;
                    monForecast.RecordTypeId = recordTypeId;
                    //etc
                    monForecast.Revenue_Date__c = date.newinstance(d.year(),d.month(),returnMonthLastDate(d.month(),d.year()));
                    //monForecast.Revenue_Date__c = d;                    
                    monthlyForecastRevenue.add(monForecast);    
                    d = d.addMonths(1);

                }
                system.debug(monthlyForecastRevenue+'MONTHFFFFF');                 
                /* Create Monthly Forecast Revenue Record for next year from Jan to current month */
                for(Integer mon  = 1; mon<opportunity.Implementation_Revenue__c.month();mon++){

                    PopulateAllTheFields p = calculateMonthlyRevenue(opportunity,currentCoef,monthsVariables[d2.month()],d2.month(),d2.year());
                    Monthly_Revenue_Forecast__c monForecast = new Monthly_Revenue_Forecast__c();
                    monForecast.Opportunity__c  = opportunityId;  
                    monForecast.Account__c = opportunity.AccountId;
                    //etc
                    //monForecast.Revenue_Date__c = d2;
                    monForecast.Revenue_Date__c = date.newinstance(d2.year(),d2.month(),returnMonthLastDate(d2.month(),d2.year()));
                    monthlyForecastRevenue.add(monForecast);                   
                    d2 = d2.addMonths(1);
                }
                system.debug(monthlyForecastRevenue+'MFFFFF');  
                Savepoint sp = Database.setSavepoint();
                try{
                    /*Update Opportunity */
                    system.debug(opportunity+'TTTTTT');
                    opportunity.Annual_Revenue__c = annualRev + opportunity.Implementation__c;
                    Database.Update(opportunity);
                    /* Insert Monthly Forecast Revenue Record */
                    Database.insert(monthlyForecastRevenue);

                    //Convert Monthly Amount to GBP (new field)
                    convertToPounds(monthlyForecastRevenue);

                    return 'Success';
                }catch(Exception e){
                    Database.rollback(sp);
                    return 'Unable to insert Montly Forecast !!';
                }

            }           
        }
        else{
            /* If there are Monthly Forecast Revenue record then we have to update the records */

            /* Fetch custom setting record(coefficients) for particular product */
            List<CP_Seasonality_Coefficient__c> seasonalityCoefficientRecord = [select id,Name,Jan__c, etc from CP_Seasonality_Coefficient__c where Name =:recordTypeName LIMIT 1]; 
            system.debug(seasonalityCoefficientRecord + 'HHHHHH');

            if(seasonalityCoefficientRecord.isEmpty()){

                return 'No coefficients for this product';   
            }else{


                List<Double> monthsVariables = new List<Double>{0.0,seasonalityCoefficientRecord[0].Jan__c, etc}; 
                    system.debug(monthsVariables+'MMMMMMMM');



                //Date d = Date.today();

                Decimal tempOppRev = opportunity.Annual_Revenue__c;
                Decimal tempOppRev2 = 0.0;
                List<Monthly_Revenue_Forecast__c> tempMonthlyForecast = new List<Monthly_Revenue_Forecast__c>(); 
                /*
for(Monthly_Revenue_Forecast__c mn : monthlyForecastRevenue){

if(mn.Revenue_Date__c.year() <= date.today().year()){
if(!(mn.Revenue_Date__c.year() < date.today().year()) &&  (mn.Revenue_Date__c.month() >= date.today().month())){                        
tempMonthlyForecast.add(mn);
tempOppRev = tempOppRev+mn.Monthly_Revenue__c;
}
}else{
tempMonthlyForecast.add(mn);
tempOppRev = tempOppRev+mn.Monthly_Revenue__c;
}

tempMonthlyForecast.add(mn);

}*/
                system.debug(tempOppRev +'TTTTTTT1');
                system.debug(opportunity.Annual_Revenue__c +'RRRRRRRR1');
                system.debug(tempMonthlyForecast.size()+'LISTLISTLIST');
                /*Update Monthly Forecast Revenue Record for the remaing month of the year from current month */

                Integer yr = opportunity.Implementation_Revenue__c.year();                
                Integer mnt = opportunity.Implementation_Revenue__c.month();
                Date d2 = date.newinstance((yr+1),1,1);
                Date d = date.newinstance(yr,mnt,1);
                Decimal currentCoef = monthsVariables[mnt];
                Integer cnt = 0;
                for(Integer mon = mnt;mon<13;mon++){

                    PopulateAllTheFields p = calculateMonthlyRevenue(opportunity,currentCoef,monthsVariables[mon],mon,yr);

                    if(mon == opportunity.Implementation_Revenue__c.month()){
                        monthlyForecastRevenue[cnt].Implementation_Fee__c = opportunity.Implementation__c;
                        monthlyForecastRevenue[cnt].Monthly_Revenue__c = p.totalRev+opportunity.Implementation__c;                    
                    }else{
                        monthlyForecastRevenue[cnt].Implementation_Fee__c = 0;
                        monthlyForecastRevenue[cnt].Monthly_Revenue__c = p.totalRev; 

                    }
                    tempOppRev2 = tempOppRev2 + p.totalRev;
                    monthlyForecastRevenue[cnt].Name = monthName.get(mon)+' '+String.valueOf(yr);
                    monthlyForecastRevenue[cnt].RecordTypeId = recordTypeId;
                    //etc
                    monthlyForecastRevenue[cnt].Revenue_Date__c = date.newinstance(d.year(),d.month(),returnMonthLastDate(d.month(),d.year()));
                    d = d.addMonths(1); 
                    cnt++;
                }                
                /* Update Monthly Forecast Revenue Record for next year from Jan to current month */
                system.debug(cnt+'GGGGGGGG');
                system.debug(monthlyForecastRevenue.size()+'SIZESIZE');
                Integer test = 0;
                for(Integer mon  = cnt; mon<monthlyForecastRevenue.size();mon++){
                    PopulateAllTheFields p = calculateMonthlyRevenue(opportunity,currentCoef,monthsVariables[d2.month()],d2.month(),d2.year());// (opportunity.Amount)*monthsVariables[mon]; 
                    monthlyForecastRevenue[mon].Name = monthName.get(d2.month())+' '+String.valueOf(d2.year());
                    monthlyForecastRevenue[mon].RecordTypeId = recordTypeId;
                    tempOppRev2 = tempOppRev2 + p.totalRev;
                    //etc
                    monthlyForecastRevenue[mon].Revenue_Date__c = date.newinstance(d2.year(),d2.month(),returnMonthLastDate(d2.month(),d2.year()));
                    d2 = d2.addMonths(1);
                    test++;
                }
                system.debug(test+'TESTESTTEST');
                system.debug(monthlyForecastRevenue+'MOMOMOMOM');
                for(Monthly_Revenue_Forecast__c mn : monthlyForecastRevenue){
                    //tempMonthlyForecast.add(mn);

                    if(mn.Revenue_Date__c.year() > opportunity.Implementation_Revenue__c.year()){                        
                        tempMonthlyForecast.add(mn);

                    }else if(mn.Revenue_Date__c.year() == opportunity.Implementation_Revenue__c.year()){                        
                        if(mn.Revenue_Date__c.month() >= opportunity.Implementation_Revenue__c.month()){
                            tempMonthlyForecast.add(mn);

                        }
                    }


                }
                system.debug(tempMonthlyForecast+'MOMOMOMOM');
                //opportunity.Annual_Revenue__c = tempOppRev - tempOppRev2;
                Savepoint sp = Database.setSavepoint();
                try{
                    /*Update Opportunity */
                    system.debug(opportunity+'OPPPPPPPP'); 
                    opportunity.Annual_Revenue__c = tempOppRev2 + opportunity.Implementation__c;
                    Database.Update(opportunity);
                    /* Update Monthly Forecast Revenue Record */
                    Database.update(tempMonthlyForecast);

                    //Convert Monthly Amount to GBP (new field)
                    convertToPounds(monthlyForecastRevenue);

                    return 'Success';
                }catch(Exception e){
                    Database.rollback(sp);
                    return 'Unable to update Montly Forecast !!';
                }

            }

            system.debug('HERE LIST IS EMPTY'); 


        }
        return 'Unable to process!! ';
    } 

    public class PopulateAllTheFields{

        public Integer numberOfCard{get;set;}
        // etc

        public PopulateAllTheFields(Integer numCard, etc){
            numberOfCard = numCard;
        // etc

        }

        public PopulateAllTheFields(){}

    }




    public static PopulateAllTheFields calculateMonthlyRevenue(Opportunity opportunity,Decimal currentMonthCoeficient,Decimal yearmonthCoeficient,Integer yearMonth,Integer yr){
        /* Opportunity Fields recalculations start*/
        PopulateAllTheFields p;
        if(opportunity.Annual_Settlement_Value__c == null ) opportunity.Annual_Settlement_Value__c = 0;

        if(opportunity.Implementation_Revenue_as_a_of_FSR__c == null) opportunity.Implementation_Revenue_as_a_of_FSR__c = 0;
        Decimal impRevPercentage = opportunity.Implementation_Revenue_as_a_of_FSR__c/100;
        //etc

        }
        Decimal txnATM;
        try{
            txnATM =  settlmentATM.divide(opportunity.Average_transaction_Value_ATM__c,5) ;);
        }catch(Exception e){
            txnATM = 0.0;
        }
        Decimal monthlyTxnRevPOS = txnPOS*opportunity.Monthly_Txn_Revenue_POS__c;
        Decimal monthlyTxnRevATM = takeMaxOfMonthlyTxnRevenue(txnATM,opportunity.Monthly_Txn_Revenue_ATM_minimum_charge__c,opportunity.Average_transaction_Value_ATM__c,monthlyRevATMPer);


        Decimal FXonSpend = (fxOnSpnd * crossPer *(settlmentPOS+settlmentATM));
        Decimal interchageRate = interchageRatePer*settlmentPOS; 
        Decimal rebate = rebt*settlmentPOS;
        Decimal totalR = monthlyCardRevenue+cardIssueRev+LoadRennue+monthlyTxnRevPOS+monthlyTxnRevATM+FXonSpend+interchageRate;
        p = new PopulateAllTheFields(0,0,0,settlmentPOS,etc;
        system.debug(LoadRennue+'$$'+monthlyTxnRevPOS+'$$'+monthlyTxnRevATM+'$$'+FXonSpend+'$$'+interchageRate+'$$'+rebate+' $$'+yearMonth+'CHECKCHECK');
        system.debug(p+' $$ '+ yearMonth+ 'FTFTFTFTFT' );
        return p;//(monthlyCardRevenue+cardIssueRev+LoadRennue+monthlyTxnRevPOS+monthlyTxnRevATM+FXonSpend+interchageRate+rebate);
    } 



    /* Will Calculate Settlement POS value */
    public static Decimal calculateSettlementPOS(Date impRev, etc){

        Decimal settlPos = 0.0;

        if(impRev.year() == fullSerRev.year()){
            if(impRev.year() == yr){
                if(fullSerRev.month() < yearMon){
                    settlPos =  (annualSet/12)*yearmonthCoef;        
                }else If(fullSerRev.month() == yearMon){
                    settlPos = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If(fullSerRev.month() > yearMon){
                    if(impRev.month() < yearMon){
                        settlPos = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == yearMon){
                        settlPos = ((30.416 - impRev.day()+1)*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > yearMon){                   
                        settlPos = 0.0;
                    }

                } 
            }else{
                settlPos =  (annualSet/12)*yearmonthCoef;
            }
        }else if(fullSerRev.year() > impRev.year()){
            if(yr == impRev.year()){

                if((fullSerRev.month()+12) < yearMon){
                    settlPos =  (annualSet/12)*yearmonthCoef;        
                }else If((fullSerRev.month()+12) == yearMon){
                    settlPos = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If((fullSerRev.month()+12) > yearMon){
                    if(impRev.month() < yearMon){
                        settlPos = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == yearMon){
                        settlPos = ((30.416 - impRev.day()+1)*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > yearMon){                   
                        settlPos = 0.0;
                    }

                } 


            }else if(yr > impRev.year()){

                if((fullSerRev.month()+12) < (yearMon+12)){
                    settlPos =  (annualSet/12)*yearmonthCoef;        
                }else If((fullSerRev.month()+12) == (yearMon+12)){
                    settlPos = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If((fullSerRev.month()+12) > (yearMon+12)){
                    if(impRev.month() < (yearMon+12)){
                        settlPos = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == (yearMon+12)){
                        settlPos = ((30.416 - impRev.day()+1)*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > (yearMon+12)){                      
                        settlPos = 0.0;
                    }

                }


            }       


        }


        system.debug(settlPos*POSPercentage +'$$'+POSPercentage+ 'POPOPOPOPOP');
        return settlPos*POSPercentage;
    }

    /* Will Calculate Settlement ATM value */
    public static Decimal calculateSettlementATM(Date impRev, etc){
        Decimal settlATM = 0.0;

        Integer tempVar ;

        if(impRev.year() == fullSerRev.year()){
            //tempVar = fullSerRev.month() - impRev.month();    
            if(impRev.year() == yr){
                if(fullSerRev.month() < yearMon){
                    settlATM =  (annualSet/12)*yearmonthCoef;        
                }else If(fullSerRev.month() == yearMon){
                    settlATM = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If(fullSerRev.month() > yearMon){
                    if(impRev.month() < yearMon){
                        settlATM = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == yearMon){
                        settlATM = ((30.416 - impRev.day())*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > yearMon){
                        settlATM = 0.0;
                    }
                }
            }else{
                    settlATM =  (annualSet/12)*yearmonthCoef;           
            }
        }else if(fullSerRev.year() > impRev.year()){
            //tempVar = (fullSerRev.month()+(12*(fullSerRev.year() - impRev.year()))) - impRev.month();
            if(yr == impRev.year()){

                if((fullSerRev.month()+12) < yearMon){
                    settlATM =  (annualSet/12)*yearmonthCoef;        
                }else If((fullSerRev.month()+12) == yearMon){
                    settlATM = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If((fullSerRev.month()+12) > yearMon){
                    if(impRev.month() < yearMon){
                        settlATM = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == yearMon){
                        settlATM = ((30.416 - impRev.day())*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > yearMon){
                        settlATM = 0.0;
                    }
                }
            }else if(yr > impRev.year()){

                if((fullSerRev.month()+12) < (yearMon+12)){
                    settlATM =  (annualSet/12)*yearmonthCoef;        
                }else If((fullSerRev.month()+12) == (yearMon+12)){
                    settlATM = ((30.416 - fullSerRev.day())* (annualSet/365)*currentMonthCoef)+(fullSerRev.day()*(annualSet/365)*currentMonthCoef*impRevFSR);
                }else If((fullSerRev.month()+12) > (yearMon+12)){
                    if(impRev.month() < (yearMon+12)){
                        settlATM = (annualSet/12)*yearmonthCoef*impRevFSR;
                    }else If(impRev.month() == (yearMon+12)){
                        settlATM = ((30.416 - impRev.day())*((annualSet/365)*currentMonthCoef*impRevFSR));
                    }else If(impRev.month() > (yearMon+12)){
                        settlATM = 0.0;
                    }
                }
            }
        }


        system.debug(settlATM*ATMPercentage+'AOAOAOAOAOA');
        return settlATM*ATMPercentage;
        //return settlATM; 
    }




    /*
=IF(
(C49*$D$19)>(($D$35*$D$20)*C49)
,C49*$D$19,
(($D$35*$D$20)*C49)
)

*/
    //takeMaxOfMonthlyTxnRevenue(txnATM,etc){

        if((txnATM*monthlyTxnPrecentage) > ((avgATM*monthlyRevATM)*txnATM)){
            return (txnATM*monthlyTxnPrecentage);
        }else{
            return ((avgATM*monthlyRevATM)*txnATM);
        }

    }

    /**
* Converts the Monthly Revenue into User's default currency and put the value into a new field (Monthly_Revenue_converted__c)
*/
    private static void convertToPounds(final List<Monthly_Revenue_Forecast__c> monthlyForecastRevenueList) {


        //Get 'Monthly Revenue Forecast' Ids
        final Map<Id, String> convertedMonthlyRevenue = new Map<Id, String>();
        for (Monthly_Revenue_Forecast__c monthlyForecastRevenue : monthlyForecastRevenueList) {
            convertedMonthlyRevenue.put(monthlyForecastRevenue.Id, null);
        }

        //Query 'Monthly Revenue Forecast' and convert the Monthly Revenue into User's default currency
        for (Monthly_Revenue_Forecast__c monthlyForecastRevenue : [select Id, convertCurrency(Monthly_Revenue__c)
                                                                   from Monthly_Revenue_Forecast__c
                                                                   where Id IN :convertedMonthlyRevenue.keySet()]) {
                                                                       convertedMonthlyRevenue.put(monthlyForecastRevenue.Id, UserInfo.getDefaultCurrency() + ' ' + monthlyForecastRevenue.Monthly_Revenue__c.format());
                                                                   }

        //Set the Converted Monthly Revenue
        for (Monthly_Revenue_Forecast__c monthlyForecastRevenue : monthlyForecastRevenueList) {
            monthlyForecastRevenue.Monthly_Revenue_converted__c = convertedMonthlyRevenue.get(monthlyForecastRevenue.Id);
        }

        //Persist records
        update monthlyForecastRevenueList;
    }

    /* Get the last day of a month */
    public static Integer returnMonthLastDate(Integer mon,Integer yr){

        if(mon == 1 || etc
            return 31; 
        }else if(mon == 2){
            if(math.mod(yr, 4) == 0){
                return 29; // Leap year
            }else{      
                return 28;
            }

        }else{
            return 30;  
        }

    }
}

At the moment the code is triggered by the user using a JavaScript custom button.

Please do suggest any edits which I can make to reduce the size of the code, without removing any parts which may need to be taken into consideration

1

To make this callable from a Trigger, you need to remove any DML from the class. This is because triggers need to be 'Bulk-Safe' ie, able to handle multiple objects at once - therefore you need to do all your DML at one go, probably at the end of an execution context.

The trick is probably to abstract out the processing of the individual sObject and pass it back to the calling method. This way you can call it from your trigger or from your webservice.

So I'd have these classes:

  • OpportunityTrigger (normally I'd recommend a trigger handler, but we'll keep it simple for now)
  • CP_MonthlyRevenueForecastController
  • CP_MonthlyRevenueForecastProcessor.

I think you are dealing with an after trigger here, so you'd pass in your Opportunity Id and receive back a list of sObjects. If you are inserting more than one kind of sObject and need to evaluate the result of an insert/update, then you may need multiple methods to handle this, each taking an id/or object and outputting an object or list.

So your trigger will work like this: OpportunityTrigger->CP_MonthlyRevenueForecastProcessor (one or more methods).

Your web-service will work like this: CP_MonthlyRevenueForecastController->CP_MonthlyRevenueForecastProcessor and you will need to modify the controller object here also, to handle calling the processor with ids/objects and recieving lists or single objects back.

All DML needs to occur in the caller objects - (OpportunityTrigger and CP_MonthlyRevenueForecastController) and needs to operate on your returned lists.

Unfortunately, you code example is so big that I'm not going to be able to suggest specific examples, but hopefully this gives you the right idea.

EDIT Based on your comments, I see you really want advice about how to use the @InvokableMethod annotation. I think you still need something close to the structure described, as you will want to add the annotation to the CP_MonthlyRevenueForecastController. This will mean that the trigger can continue to call the Processor class, as triggers cannot call a method that is invokable.

Here is more information.

So in your processor class, you'd have something like:

global class CP_MonthlyRevenueForecastProcessor{

    public static Forecast__c[] generateMonthlyForecastRecords(String opportunityId){
        final List<CurrencyType> currencyTypeList = [select IsoCode, conversionRate
                                                 from CurrencyType
                                                 where IsActive = true];
        ID recordTypeId = [select id,Name from RecordType where Name='CP Non Disbursement' and SobjectType='Monthly_Revenue_Forecast__c'].Id; 
        Opportunity opportunity = [Select id,AccountId, etc where id=:opportunityId];
        ///ect. don't do any DML and return a forecast list
        ....
        return forecasts;

In the webservice class you'd call it like this:

global class CP_MonthlyRevenueForecastController{

    @InvocableMethod(label='Create Monthly Forecasts')
    webservice static string createMonthlyForecastRecords(String opportunityId){

        Forecast__c[] forecasts = CP_MonthlyRevenueForecastProcessor.generateMonthlyForecastRecords(opportunityId);
        insert forecasts;
    }

Good luck!

  • Thank you Casp, I hate to say this but I already have a Trigger (it's actually a Trigger Handler), Controller (that's the code that I've posted) and I'm not sure about the Processor but in any case, the code works and can be called by the Custom Button that I mentioned. My problem is that I can't use the Process Builder to call the Controller because it doesn't include an InvocableMethod. I could be missing something - as you know, I'm new to this - but I'm not sure that your answer explains how I can do that? – Alex S May 24 '15 at 23:50
  • I see - I've made some changes that will hopefully help – Caspar Harmer May 25 '15 at 0:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.