You need to sign in to do that
Don't have an account?
Rachel Linder 20
Need Help Creating a Lightning Action to run an Apex Class
I am just a couple days on with this company. They have the following Apex Class that runs nightly through a batch. We would like the ability to create a Lightning Action/Quick Action to place on the page layout so that this can also be invoked at any time during the day if needed.
ContractRenewalManager
SendToOrderSubscriptions
How would we get started in creating a Lightning Action/Quick Action? Is this possible?
global class NightlyJobs Implements Schedulable { global void execute (SchedulableContext sc) { SendToOrder_Subscriptions runSendToOrder_Subscriptions = new SendToOrder_Subscriptions(); database.executebatch(runSendToOrder_Subscriptions,100); ContractRenewalManager runContractRenewalManager = new ContractRenewalManager(); database.executebatch(runContractRenewalManager,1); } }This seems to reference the following sets of Apex as well:
ContractRenewalManager
global class ContractRenewalManager implements Database.Batchable<sObject>, Database.Stateful { global Integer totalContractsUpdated = 0; global Database.QueryLocator start(Database.BatchableContext BC) { datetime eligibilityDate = system.now().addMonths(4); string eligibilityDateFormatted = eligibilityDate.format('yyyy-MM-dd'); // Build Contracts Dataset string queryContracts = 'SELECT id, SBQQ__RenewalForecast__c FROM Contract WHERE EndDate <= ' + eligibilityDateFormatted + ' AND SBQQ__RenewalForecast__c = false AND Disable_Renewal_Auto_Creation__c = false AND Status = \'Activated\''; return Database.getQueryLocator(queryContracts); } global void execute(Database.BatchableContext BC, List<Contract> scope) { // Vars List<Contract> listContractsToUpdate = new List<Contract>(); List<Exception__c> list_newExceptions = new List<Exception__c>(); // Loop through all Contracts for (Contract eachContract: scope) { eachContract.SBQQ__RenewalForecast__c = true; listContractsToUpdate.add(eachContract); } // UPDATE - Contract Records List<Database.SaveResult> listContractsToUpdate_SaveResults = database.update(listContractsToUpdate, false); // RESULTS for (Database.SaveResult eachResult: listContractsToUpdate_SaveResults) { // ON SUCCESS if (eachResult.isSuccess()) { System.debug('== DEBUG: Updated Contract Record ==>> ' + eachResult.getId()); totalContractsUpdated++; // ON FAIL } else { for (Database.Error eachError: eachResult.getErrors()) { Exception__c newException = new Exception__c(Purpose__c = 'Set Renewal Forecast to TRUE', Object__c = 'Contract (Update)', Process__c = 'ContractRenewalManager (Apex Class)', Details__c = eachError.getStatusCode() + ': ' + eachError.getMessage() + '\n' + '\n' + 'Field affected by the error: ' + eachError.getFields() + '\n' + '\n' + 'Note: This error is related to Contract ID: ' + eachResult.getId()); list_newExceptions.add(newException); } } } insert list_newExceptions; } global void finish(Database.BatchableContext BC) { system.debug('DEBUG ---->>>> Total Contracts Updated: ' + totalContractsUpdated); } }
SendToOrderSubscriptions
global class SendToOrder_Subscriptions implements Database.Batchable<sObject>, Database.Stateful { global Database.QueryLocator start(Database.BatchableContext BC) { string queryAccounts = 'SELECT id FROM Account WHERE id IN (SELECT SBQQ__Account__c FROM SBQQ__Subscription__c WHERE SBQQ__Quantity__c > 0 AND Send_To_Order__c = true AND Added_To_Order__c = false AND Status__c != \'Cancelled\')'; return Database.getQueryLocator(queryAccounts); } global void execute(Database.BatchableContext BC, List<Account> scope) { // Prepare data ---- List<Account> thisScopeAccounts = new List<Account>(); thisScopeAccounts.addAll(scope); id standardPricebookId; if (Test.isRunningTest()) { standardPricebookId = Test.getStandardPricebookId(); } else { standardPricebookId = [SELECT id FROM Pricebook2 WHERE isStandard = true].id; } List<PricebookEntry> listofPBEs = [SELECT id, Product2id, Pricebook2id FROM PricebookEntry WHERE Pricebook2id = :standardPricebookId]; Map<id,id> pricebookEntryids = new Map<id,id>(); List<Exception__c> newExceptions = new List<Exception__c>(); for (PricebookEntry eachPBE : listofPBEs) { pricebookEntryids.put(eachPBE.Product2id,eachPBE.id); } List<SBQQ__Subscription__c> thisScopeSubscriptions = [SELECT id, SBQQ__Account__c, Bill_To_Account__c, Business_Entity__c, Accounting_Quantity__c, SBQQ__Product__c, Display_Name__c, Product_Description__c, SBQQ__SubscriptionStartDate__c, SBQQ__SubscriptionEndDate__c, SBQQ__ListPrice__c, SBQQ__QuoteLine__c, SBQQ__NetPrice__c, Transaction_Number__c, Purchase_Order__c FROM SBQQ__Subscription__c WHERE SBQQ__Quantity__c > 0 AND Send_To_Order__c = true AND Added_To_Order__c = false AND Status__c != 'Cancelled' AND SBQQ__Account__c IN :thisScopeAccounts]; List<AggregateResult> aggregatedSubscriptions = [SELECT SBQQ__Account__c, Bill_To_Account__c, Business_Entity__c, Bill_To_Account__r.Billing_Contact__c, MIN(SBQQ__SubscriptionStartDate__c) StartDate, MAX(SBQQ__SubscriptionEndDate__c) EndDate FROM SBQQ__Subscription__c WHERE SBQQ__Account__c IN :thisScopeAccounts AND Send_To_Order__c = true AND Added_To_Order__c = false GROUP BY SBQQ__Account__c, Bill_To_Account__c, Business_Entity__c, Bill_To_Account__r.Billing_Contact__c]; List<Order> newOrders = new List<Order>(); // Create Orders for (AggregateResult eachNewOrder : aggregatedSubscriptions) { Order newOrder = new Order( Accountid = (id)eachNewOrder.get('SBQQ__Account__c'), Bill_To_Account__c = (id)eachNewOrder.get('Bill_To_Account__c'), Business_Entity__c = (id)eachNewOrder.get('Business_Entity__c'), BillToContactId = (id)eachNewOrder.get('Billing_Contact__c'), EffectiveDate = (date)eachNewOrder.get('StartDate'), EndDate = (date)eachNewOrder.get('EndDate'), Pricebook2id = standardPricebookId, Type = 'Subscription Order', Status = 'Draft' ); newOrders.add(newOrder); } // INSERT Orders from source record aggregate data List<Database.SaveResult> newOrders_SaveResults = database.insert(newOrders, false); integer orderInsertIndex = 0; // RESULTS for (Database.SaveResult eachResult : newOrders_SaveResults) { // ON SUCCESS if (eachResult.isSuccess()) { System.debug('== DEBUG: Inserted Order Record ==>> ' + eachResult.getId()); // ON FAIL } else { for (Database.Error eachError : eachResult.getErrors()) { Exception__c newException = new Exception__c(Purpose__c = 'Inserting Order records', Object__c = 'Order (Insert)', Process__c = 'SendToOrder_Subscriptions (Apex Class)', Details__c = eachError.getStatusCode() + ': ' + eachError.getMessage() + '\n' + '\n' + 'Field affected by the error: ' + eachError.getFields() + '\n' + '\n' + 'Note: This error is related to Account ID: ' + newOrders[orderInsertIndex].Accountid); newExceptions.add(newException); } } orderInsertIndex++; } // Create Order Lines List<OrderItem> newOrderLines = new List<OrderItem>(); for (Order eachOrder : newOrders) { for (SBQQ__Subscription__c eachSubscription : thisScopeSubscriptions) { if (eachOrder.AccountId == eachSubscription.SBQQ__Account__c && eachOrder.Bill_To_Account__c == eachSubscription.Bill_To_Account__c && eachOrder.Business_Entity__c == eachSubscription.Business_Entity__c) { OrderItem newOrderLine = new OrderItem( Orderid = eachOrder.id, SBQQ__Subscription__c = eachSubscription.id, Description = eachSubscription.Product_Description__c, Display_Name__c = eachSubscription.Display_Name__c, ServiceDate = eachSubscription.SBQQ__SubscriptionStartDate__c, EndDate = eachSubscription.SBQQ__SubscriptionEndDate__c, Quantity = eachSubscription.Accounting_Quantity__c, SBQQ__QuotedListPrice__c = eachSubscription.SBQQ__ListPrice__c, UnitPrice = eachSubscription.SBQQ__NetPrice__c, PricebookEntryid = pricebookEntryids.get(eachSubscription.SBQQ__Product__c), Transaction_Number__c = eachSubscription.Transaction_Number__c, Purchase_Order__c = eachSubscription.Purchase_Order__c ); newOrderLines.add(newOrderLine); } } } // INSERT OrderItem records from source records List<Database.SaveResult> newOrderLines_SaveResults = database.insert(newOrderLines, false); integer orderLinesInsertIndex = 0; // RESULTS for (Database.SaveResult eachResult : newOrderLines_SaveResults) { // ON SUCCESS if (eachResult.isSuccess()) { System.debug('== DEBUG: Inserted OrderItem Record ==>> ' + eachResult.getId()); // ON FAIL } else { for (Database.Error eachError : eachResult.getErrors()) { Exception__c newException = new Exception__c(Purpose__c = 'Inserting OrderItem records', Object__c = 'OrderItem (Insert)', Process__c = 'SendToOrder_Subscriptions (Apex Class)', Details__c = eachError.getStatusCode() + ': ' + eachError.getMessage() + '\n' + '\n' + 'Field affected by the error: ' + eachError.getFields() + '\n' + '\n' + 'Note: This error is related to Subscription ID: ' + newOrderLines[orderLinesInsertIndex].SBQQ__Subscription__c); newExceptions.add(newException); } } orderLinesInsertIndex++; } database.insert(newExceptions,false); } global void finish(Database.BatchableContext BC) { // Chain to SendToOrder_Assets Apex Class if (!Test.isRunningTest()) { SendToOrder_Assets runSendToOrder_Assets = new SendToOrder_Assets(); database.executebatch(runSendToOrder_Assets,100); } } }
How would we get started in creating a Lightning Action/Quick Action? Is this possible?
"static" is missing in the controller (mandatory here).
You can get the Ids of the launched batches for the alert (development) (useless in production)
All Answers
This code below should be sufficient on the server (callable from a lightning component as soon as there is the annotation @AuraEnabled) The ligthning component must implement="force:lightningQuickAction" and use the "controller" (apex class) above.
Component: quickLaunchBatch.cmp
Controller: quickLaunchBatch.js (verbose because of the return value from the server after the call of the method myExecuteBatch in the controller )
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_actions_call.htm
(not tested but that is the idea)
Then, I am assuming in the Developer Console I would then create a new Lightning Component and choose Lightning Quick Action. After that though how do I build the controller?
1) Developer Console: Menu: File > Open > Classes > button "Refresh" on the bottom right.
2) Using the Developer Console
The Developer Console provides tools for developing your Aura components and applications.
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/intro_devconsole.htm
You can see "COMPONENT" and "CONTROLLER" on the right panel..
You don't need to create quickLaunchBatch.cmp or quickLaunchBatch.js/
Just click on the submenus of the panel.
3) Quick Start: Aura Components
https://trailhead.salesforce.com/en/content/learn/projects/quickstart-lightning-components
For the Apex controller ( class DirectBatch ) there is no right panel.
Create an Aura Component
Create and Add an Aura Component to the Record Page
An Aura component is a combination of markup, JavaScript, and CSS. You first create a component bundle.
- Apex Class - DirectBatch.apxc - had to add a "get" infront of the myExecuteBatch for the public void
- Aura Component - quickLaunchBatch
- quickLaunchBatch.cmp
- Controller - quckLaunchBatchController.js
For the Controller, upon save I am getting the following error:This what i have for the controller:
1. DirectBatch.apxc
2. quickLaunchBatch
3. quickLaunchBatch.cmp
4. qyuckLaunchBatchController.js
"static" is missing in the controller (mandatory here).
You can get the Ids of the launched batches for the alert (development) (useless in production)