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
Shawn Reichner 29Shawn Reichner 29 

Scheduled Apex Class Not Workign as expected

Hello Awesome Developers! 

I am hoping one of you heroes out there can help me with a requirmeent I have.  Let me be up front, I have not been developing in apex for long and have not had any other developign experience with code in any other language or platform, so in other words a newbie. :)

So here is the deal, I have a need to have opportnities created every night based upon another object having records created the previous day. This object is a Zuora application object called Subscriptions and a record would be created whenever a customer of ours would use our self servic eportal (outside of Salesforce) to perform an upgrade or downgrade of thier services.  This action by the customer will create a Subscription record in Salesforce and when those get created I need every night to create an Upgrade or downgrade Opportunity from those subscription records created. Also we need to batch the same customer so if they do 3 upgrades, we take the amount from all three subscription records and sum them so that we only create one opportunity per customer for upgrades and an opportunity for downgrades and then have the Amoutn field on th enewly created opp be the total sum of the Upgrade subscription records and if there are downgrades, the same would need to happen to sum all of those downgrade record amounts into one opp and the amount would be that SUM.  

Please see my attempt at this code below, where I am setting the class as a scheduled class, and when I run this in the Dev console no opps are bneing created even though I have subscription records I manually created for this test.  That is issue number one, gettign this to create opps, but I havent gotten as far to test if the Aggregate function being used will do the magic of SUMing thw amounts and only creating one opportunity per account for all upgrades and one opp for all downgrades for that account. 

I hope this makes sense, I am just tryign to once a night, grab all subscriptions created for that day (Actually this will run at 2AM so createddate would be the day before) and then rn though those Subscription records and create one opp per account and have the amoutn be the sum for both types (Upgrades and downgrades) 

Thank you very much for your help! 

Shawn
 
global class CreateUpgradeDowngradeOpportunities Implements Schedulable
{
     global void execute(SchedulableContext sc)
      {
            CreateOpportunities();
      }
      
      public void CreateOpportunities()
      {
         Date d1 = system.today()-1;
         List<Zuora__Subscription__c> SubsCreated = [SELECT Id, Name, Zuora__Account__c, Zuora__MRR__c, Zuora__Status__c FROM Zuora__Subscription__c WHERE CreatedDate =: d1];
          
          For(Zuora__Subscription__c z : SubsCreated){
              If(z.Zuora__Status__c == 'Cancelled'){
                  AggregateResult[] groupedResultsDown = [SELECT Zuora__Account__c , SUM(Zuora__MRR__C) FROM Zuora__Subscription__c WHERE ID IN: SubsCreated GROUP BY Zuora__Account__c];
                 //Create Downgrade Opp 
                 
                  List<Opportunity> downgradeOpps = new List<Opportunity>();
                 
                  For(AggregateResult ard : groupedResultsDown){
                   
                      Opportunity od = new Opportunity();
                      	od.RecordTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Downgrade').getRecordTypeId();
                      	od.OwnerId = z.Zuora__Account__r.OwnerId;
                      	od.Name = z.Zuora__Account__r.Name + ' - AMP';
                      	od.AccountId = z.Zuora__Account__r.Id;
                      	//od.Armor_Product_Category__c
                      	//od.Armor_Product__c	
                      	//od.Armor_Anywhere_Location__c
                      	od.Opportunity_Source__c = 'Portal';
                      	od.Type = 'Downgrade';
                      	od.Amount = z.Zuora__MRR__c * -1;
                      	od.CurrencyIsoCode = z.CurrencyIsoCode;
                      	od.CloseDate = d1;
                      	od.StageName = 'Cancelled';
                      
                      downgradeOpps.add(od);
                      //End of Creating Downgrade Opp
                  } // End of GroupedResultDown For Loop
                  
                  insert downgradeOpps;
                  
              }
              Else If(z.Zuora__Status__c == 'Active'){
                  AggregateResult[] groupedResultsUp = [SELECT Zuora__Account__c , SUM(Zuora__MRR__C) FROM Zuora__Subscription__c WHERE ID IN: SubsCreated GROUP BY Zuora__Account__c];
                 //Create Upgrade Opp 
                 
                 List<Opportunity> upgradeOpps = new List<Opportunity>();
                  For(AggregateResult aru : groupedResultsUp){
                    
                        
                      Opportunity ou = new Opportunity();
                     	ou.RecordTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Upgrade').getRecordTypeId();
                      	ou.OwnerId = z.Zuora__Account__r.OwnerId;
                      	ou.Name = z.Zuora__Account__r.Name + ' - AMP';
                      	ou.AccountId = z.Zuora__Account__r.Id;
                      	//ou.Armor_Product_Category__c
                      	//ou.Armor_Product__c	
                      	//ou.Armor_Anywhere_Location__c
                      	ou.Opportunity_Source__c = 'Portal';
                      	ou.Type = 'Existing Business';
                      	ou.Amount = z.Zuora__MRR__c;
                      	ou.CurrencyIsoCode = z.CurrencyIsoCode;
                      	ou.CloseDate = d1;
                      	ou.StageName = 'Closed Won';
                      
                      upgradeOpps.add(ou);
                      //End of Creating Upgrade Opp

                  } // End of GroupedResultUp For Loop
                 
                 insert upgradeOpps;
              }
              
          } // End of SubsCreated For Loop
         
          
      } //End of CreateOpportunities Method
} // End Of Class

 
Best Answer chosen by Shawn Reichner 29
Nayana KNayana K
// Your code is not bulkified. Below is the updated code
global class CreateUpgradeDowngradeOpportunities Implements Schedulable
{
    global void execute(SchedulableContext sc)
    {
        CreateOpportunities();
    }
      
    public void CreateOpportunities()
    {
        Date d1 = system.today()-1;
		List<Opportunity> lstOpp = new List<Opportunity>();
		Opportunity objOpp;
		Id idRecTypeDowngrade = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Downgrade').getRecordTypeId();
		Id idRecTypeUpgrade = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Upgrade').getRecordTypeId();
		Map<Id, Account> mapAcc = new Map<Id, Account>();
		Id idAcc;
		String strStatus;
		Decimal amt;
		Set<Id> setIdAcc = new Set<Id>();
		List<AggregateResult> lstAR = new List<AggregateResult>();
		
		// collect sum by account
		for(AggregateResult objAR : [SELECT Zuora__Account__c , Zuora__Status__c, SUM(Zuora__MRR__C) 
									FROM Zuora__Subscription__c 
									WHERE ID IN: SubsCreated 
										AND Zuora__Status__c IN ('Cancelled', 'Active')
										AND CreatedDate =: d1
										AND Zuora__Account__c != NULL
									GROUP BY ROLLUP(Zuora__Account__c, Zuora__Status__c)])
		{
			lstAR.add(objAR);
			setIdAcc.add((Id)objAR.get('Zuora__Account__c'));
		}
		
		// collect account infos
		if(!setIdAcc.isEmpty())
		{
			mapAcc = new Map<Id, Account>([SELECT Id, Name, OwnerId FROM Account WHERE Id IN: setIdAcc]);
		}
		
		// create opps
		for(AggregateResult objAR : lstAR)
		{
			idAcc = (Id)objAR.get('Zuora__Account__c');
			strStatus = (String)objAR.get('Zuora__Status__c');
			amt = (Decimal)objAR.get('expr0'));
			if(strStatus == 'Cancelled')
			{
				objOpp = new Opportunity();
				objOpp.RecordTypeId = idRecTypeDowngrade;
				objOpp.OwnerId = mapAcc.get(idAcc).OwnerId;
				objOpp.Name = mapAcc.get(idAcc).Name + ' - AMP';
				objOpp.AccountId = mapAcc.get(idAcc).Id;
				objOpp.Opportunity_Source__c = 'Portal';
				objOpp.Type = 'Downgrade';
				objOpp.Amount = amt * -1;
				objOpp.CloseDate = d1;
				objOpp.StageName = 'Cancelled';    
				lstOpp.add(objOpp);    
			}
			else if(strStatus == 'Active')
			{
				objOpp = new Opportunity();
				objOpp.RecordTypeId = idRecTypeUpgrade;
				objOpp.OwnerId = mapAcc.get(idAcc).OwnerId;
				objOpp.Name = mapAcc.get(idAcc).Name + ' - AMP';
				objOpp.AccountId = mapAcc.get(idAcc).Id;
				objOpp.Opportunity_Source__c = 'Portal';
				objOpp.Type = 'Existing Business';
				objOpp.Amount = amt;
				objOpp.CloseDate = d1;
				objOpp.StageName = 'Closed Won';
				lstOpp.add(objOpp);
			} 
		}

		if(!lstOpp.isEmpty())
		{
			insert lstOpp;
		}
    } 
}

 I have removed currecycode assignment. Because you are grouping by Account, what you want the currency code to be? Say, we have 3 Zuora__Subscription__c for 1 account, then which one you want to assign?

All Answers

Nayana KNayana K
// Your code is not bulkified. Below is the updated code
global class CreateUpgradeDowngradeOpportunities Implements Schedulable
{
    global void execute(SchedulableContext sc)
    {
        CreateOpportunities();
    }
      
    public void CreateOpportunities()
    {
        Date d1 = system.today()-1;
		List<Opportunity> lstOpp = new List<Opportunity>();
		Opportunity objOpp;
		Id idRecTypeDowngrade = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Downgrade').getRecordTypeId();
		Id idRecTypeUpgrade = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('AMP Upgrade').getRecordTypeId();
		Map<Id, Account> mapAcc = new Map<Id, Account>();
		Id idAcc;
		String strStatus;
		Decimal amt;
		Set<Id> setIdAcc = new Set<Id>();
		List<AggregateResult> lstAR = new List<AggregateResult>();
		
		// collect sum by account
		for(AggregateResult objAR : [SELECT Zuora__Account__c , Zuora__Status__c, SUM(Zuora__MRR__C) 
									FROM Zuora__Subscription__c 
									WHERE ID IN: SubsCreated 
										AND Zuora__Status__c IN ('Cancelled', 'Active')
										AND CreatedDate =: d1
										AND Zuora__Account__c != NULL
									GROUP BY ROLLUP(Zuora__Account__c, Zuora__Status__c)])
		{
			lstAR.add(objAR);
			setIdAcc.add((Id)objAR.get('Zuora__Account__c'));
		}
		
		// collect account infos
		if(!setIdAcc.isEmpty())
		{
			mapAcc = new Map<Id, Account>([SELECT Id, Name, OwnerId FROM Account WHERE Id IN: setIdAcc]);
		}
		
		// create opps
		for(AggregateResult objAR : lstAR)
		{
			idAcc = (Id)objAR.get('Zuora__Account__c');
			strStatus = (String)objAR.get('Zuora__Status__c');
			amt = (Decimal)objAR.get('expr0'));
			if(strStatus == 'Cancelled')
			{
				objOpp = new Opportunity();
				objOpp.RecordTypeId = idRecTypeDowngrade;
				objOpp.OwnerId = mapAcc.get(idAcc).OwnerId;
				objOpp.Name = mapAcc.get(idAcc).Name + ' - AMP';
				objOpp.AccountId = mapAcc.get(idAcc).Id;
				objOpp.Opportunity_Source__c = 'Portal';
				objOpp.Type = 'Downgrade';
				objOpp.Amount = amt * -1;
				objOpp.CloseDate = d1;
				objOpp.StageName = 'Cancelled';    
				lstOpp.add(objOpp);    
			}
			else if(strStatus == 'Active')
			{
				objOpp = new Opportunity();
				objOpp.RecordTypeId = idRecTypeUpgrade;
				objOpp.OwnerId = mapAcc.get(idAcc).OwnerId;
				objOpp.Name = mapAcc.get(idAcc).Name + ' - AMP';
				objOpp.AccountId = mapAcc.get(idAcc).Id;
				objOpp.Opportunity_Source__c = 'Portal';
				objOpp.Type = 'Existing Business';
				objOpp.Amount = amt;
				objOpp.CloseDate = d1;
				objOpp.StageName = 'Closed Won';
				lstOpp.add(objOpp);
			} 
		}

		if(!lstOpp.isEmpty())
		{
			insert lstOpp;
		}
    } 
}

 I have removed currecycode assignment. Because you are grouping by Account, what you want the currency code to be? Say, we have 3 Zuora__Subscription__c for 1 account, then which one you want to assign?
This was selected as the best answer
Shawn Reichner 29Shawn Reichner 29
Nayana,  Thank you for your example and explanation.  I had to tweak a few items because of some errors, but after some small tweaks, the code you provided did the trick!!!!  Thank you so much again!  Shawn
Nayana KNayana K
Great :)