You need to sign in to do that
Don't have an account?

Salesforce Field Service Booking Appointments Duration 30 Days
I am trying to update functionality in my org to have customers self-schedule beyond 30 day limit. We hada customer lightning component and apex class built and I am trying to see if I can update the code to search from appointments beyond the 30 day limit. Does anyone know how I could update this code below to successfully search from appointment beyond 30 days? or is there any code out there that can override the saleforce default of 30 days?
Component:
public without sharing class advic_fsl_AppointmentBooking { @AuraEnabled public static CmpData createWorkOrderAndServiceAppointment() { CmpData retData = new CmpData(); User runningUser = getRunningUser(); system.debug('Who is the running user: '+runningUser.AccountId); retData.isEligibleCustomer = checkCustomerEligibility(runningUser.AccountId); if(retData.isEligibleCustomer) { retData.workOrderId = createWorkOrder(runningUser); retData.serviceAppointmentId = createServiceAppointment(runningUser, retData.workOrderId); } return retData; } @AuraEnabled public static CmpData getAppointmentSlots(Id workOrderId, Id serviceAppointmentId) { System.debug('@@@@ HERE'); CmpData retData = new CmpData(); retData.slots = getSlots(serviceAppointmentId); // We delete the created Work Order and Service Appointment in case the user quits the process before scheduling his/her appointment. // Once the user confirms their scheduled appointment, we will undelete the Work Order and Service Appointment. deleteWorkOrderAndServiceAppointment(workOrderId, serviceAppointmentId); System.debug('@@@@ retData: ' + retData); return retData; } @AuraEnabled public static void undeleteWorkOrderAndServiceAppointment(Id workOrderId, Id serviceAppointmentId) { List<WorkOrder> deletedWorkOrders = [SELECT Id FROM WorkOrder WHERE Id =: workOrderId ALL ROWS]; List<ServiceAppointment> deletedServiceAppointments = [SELECT Id FROM ServiceAppointment WHERE Id =: serviceAppointmentId ALL ROWS]; try { undelete deletedWorkOrders; undelete deletedServiceAppointments; } catch(DmlException e) { System.debug('Error in undeleteWorkOrderAndServiceAppointment: ' + e.getMessage()); } } @AuraEnabled public static void updateServiceAppointment(String slotJSON, Id serviceAppointmentId, String detailsAccount, String detailsServiceAppt) { System.debug(slotJSON); System.debug(serviceAppointmentId); System.debug(detailsAccount); System.debug(detailsServiceAppt); AppointmentBookingSlot slot = (AppointmentBookingSlot)JSON.deserialize(slotJSON, advic_fsl_AppointmentBooking.AppointmentBookingSlot.class); try{ ServiceAppointment serviceAppointment = [SELECT ArrivalWindowStartTime, ArrivalWindowEndTime, Status, Additional_Details__c FROM ServiceAppointment WHERE Id =: serviceAppointmentId]; serviceAppointment.ArrivalWindowStartTime = utcToUserTimezone(slot.times.startDT); serviceAppointment.ArrivalWindowEndTime = utcToUserTimezone(slot.times.endDT); serviceAppointment.Status = 'Scheduled'; ServiceAppointment.Additional_Details__c = detailsServiceAppt; User runningUser = getRunningUser(); system.debug('Who is the running user: '+runningUser.AccountId); Account account = [SELECT Additional_Details__c FROM Account WHERE Id =: runningUser.AccountId]; account.Additional_Details__c = detailsAccount; update serviceAppointment; update account; } catch(DmlException e) { System.debug('updateServiceAppointment: ' + serviceAppointmentId + ' Error: ' + + e.getMessage()); } } @AuraEnabled public static void scheduleServiceAppointment(Id serviceAppointmentId) { Id schedulingPolicyId = [SELECT Id, Name FROM FSL__Scheduling_Policy__c WHERE Name = 'Customer First' LIMIT 1].Id; //Schedules the service appointment in the best available slot. If there are no available slots, the appointment isn’t scheduled. FSL.ScheduleResult result = new FSL.ScheduleResult(); //Returns the result of the scheduling process. System.debug('svcApptId to Svc: '+ serviceAppointmentId); result = FSL.ScheduleService.schedule(schedulingPolicyId, serviceAppointmentId); try{ System.debug('FSL.ScheduleService result: ' + JSON.serializePretty(result)); } catch(Exception e){ System.debug('JSON ERROR. On: '+ result); } } private static Boolean checkCustomerEligibility(Id accountId) { Account account = [SELECT Customer_Eligible__c FROM Account WHERE Id =: accountId]; public static User getRunningUser() { Id runningUserId = UserInfo.getUserId(); return [SELECT AccountId, ContactId, Account.BillingStreet, Account.BillingCity, Account.BillingState, Account.BillingCountry, Account.BillingPostalCode FROM User WHERE Id =: runningUserId]; } public static Id createWorkOrder(User runningUser) { WorkType energyInHomeWt = [SELECT Id FROM WorkType WHERE Name = 'Energy Assessment - In Home' LIMIT 1]; WorkOrder workOrder = new WorkOrder(AccountId=runningUser.AccountId, ContactId=runningUser.ContactId, Street=runningUser.Account.BillingStreet, WorkTypeId=energyInHomeWt.Id, City=runningUser.Account.BillingCity, State=runningUser.Account.BillingState, Country=runningUser.Account.BillingCountry, PostalCode=runningUser.Account.BillingPostalCode); try { insert workOrder; } catch(DmlException e) { System.debug('Error in createWorkOrder: ' + e.getMessage()); } return workOrder.Id; } public static Id createServiceAppointment(User runningUser, Id workOrderId) { ServiceAppointment serviceAppointment = new ServiceAppointment(ContactId=runningUser.ContactId, ParentRecordId=workOrderId, EarliestStartTime=Datetime.now(), DueDate=Datetime.now().addMonths(1), Street=runningUser.Account.BillingStreet, City=runningUser.Account.BillingCity, State=runningUser.Account.BillingState, Country=runningUser.Account.BillingCountry, PostalCode=runningUser.Account.BillingPostalCode); try { insert serviceAppointment; } catch(DmlException e) { System.debug('Error in createServiceAppointment: ' + e.getMessage()); } return serviceAppointment.Id; } private static Boolean checkIneligibleReasonCode(String ineligibleReasonCode) { Boolean codeStartsWithPp = false; if(String.isNotBlank(ineligibleReasonCode)) { if(ineligibleReasonCode.startsWith('PP')) { codeStartsWithPp = true; } } return codeStartsWithPp; } private static void deleteWorkOrderAndServiceAppointment(Id workOrderId, Id serviceAppointmentId) { try { delete [SELECT Id FROM WorkOrder WHERE Id =: workOrderId]; delete [SELECT Id FROM ServiceAppointment WHERE Id =: serviceAppointmentId]; } catch(DmlException e) { System.debug('Error in deleteWorkOrderAndServiceAppointment: ' + e.getMessage()); } } /* * Appointment booking returns the available slots for a service appointment, while considering scheduling policies, work rules, and service objectives. * */ public static List<AppointmentBookingSlot> getSlots(Id serviceAppointmentId) { System.debug('@@@@ serviceAppointmentId: ' + serviceAppointmentId); ServiceAppointment serviceAppointment = [SELECT Id, AccountId, ContactId, EarliestStartTime, DueDate FROM ServiceAppointment WHERE Id =: serviceAppointmentId LIMIT 5]; Id schedulingPolicyId = [SELECT Id, Name FROM FSL__Scheduling_Policy__c LIMIT 1].Id; Id operatingHoursId = [SELECT Id, Name FROM OperatingHours WHERE Name = 'Energy Assessment Calendar' LIMIT 1].Id; Timezone tz = UserInfo.getTimeZone(); System.debug('getting slots with....'+ serviceAppointment.Id + '//'+schedulingPolicyId+ '//'+operatingHoursId+ '//'+tz) ; List<FSL.AppointmentBookingSlot> slots = FSL.AppointmentBookingService.GetSlots(serviceAppointment.Id, schedulingPolicyId, operatingHoursId, tz, false); System.debug('slots: ' + slots); List<AppointmentBookingSlot> slotList = new List<AppointmentBookingSlot>(); for(FSL.AppointmentBookingSlot slot : slots){ DateTime slotStartDT = slot.interval.start; DateTime slotFinishDT = slot.interval.finish; Date slotStartDay = slotStartDT.date(); if(slotStartDay > Date.today() ){ AppointmentBookingSlot newSlot = new AppointmentBookingSlot(); Interval times = new Interval(); times.startDT = slot.interval.start; times.endDT = slot.interval.finish; newSlot.grade = slot.grade; newSlot.times = times; slotList.add(newSlot); } } System.debug('slotList:: '+ slotList); //return setToTimeZone(slotList); return slotList; } public static DateTime utcToUserTimezone(DateTime utcDT){ DateTime userDT = utcDT; String utcDtString = utcDT.format('yyyy-MM-dd HH:mm:ss', 'UTC'); //String utcDtString = utcDT.format('yyyy-MM-dd hh:mm a', 'UTC'); System.debug('@@@@ str: '+utcDtString); userDT = DateTime.valueOf(utcDtString); System.debug('@@@@ DT: '+userDT); return userDT; } /*public static List<AppointmentBookingSlot> setToTimezone(List<AppointmentBookingSlot> slots){ if(slots.isEmpty()){ return slots; } String timeZone = UserInfo.getTimeZone().getID(); for(AppointmentBookingSlot slot: slots){ if(slot.times != NULL){ System.debug('~~~~~~'); System.debug('BEFORE: '+ slot.times.endDT); slot.times.startDT = Datetime.valueOf(slot.times.startDT); slot.times.endDT = Datetime.valueOf(slot.times.endDT); System.debug('AFTER: '+ slot.times.endDT.format()); } } return slots; }*/ public class CmpData { @AuraEnabled public Id workOrderId {get;set;} @AuraEnabled public Id serviceAppointmentId {get;set;} @AuraEnabled public List<AppointmentBookingSlot> slots {get;set;} @AuraEnabled public Boolean isEligibleCustomer {get;set;} } public class AppointmentBookingSlot { @AuraEnabled public Decimal grade {get;set;} @AuraEnabled public Interval times {get;set;} } public class Interval { @AuraEnabled public DateTime startDT {get;set;} @AuraEnabled public DateTime endDT {get;set;} } }
Component:
<aura:component implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes,force:hasRecordId,flexipage:availableForRecordHome" access="global" controller="advic_fsl_AppointmentBooking"> <aura:attribute name="debug" type="Boolean" default="false"/> <aura:attribute name="loading" type="Boolean" default="true"/> <aura:attribute name="showSpinner" type="Boolean" default="true"/> <aura:attribute name="isEligible" type="Boolean" default="true"/> <aura:attribute name="showError" type="Boolean" default="false"/> <aura:attribute name="errorMessage" type="String"/> <aura:attribute name="rowCount" type="Integer" default="4"/> <aura:attribute name="isOpen" type="boolean" default="false"/> <aura:attribute name="data" type="Object" default="{}"/> <aura:attribute name="slotList" type="List" default="[]"/> <aura:attribute name="allSlots" type="List" default="[]"/> <aura:attribute name="workOrderId" type="Id"/> <aura:attribute name="serviceAppointmentId" type="Id"/> <aura:attribute name="selectedDate" type="Date"/> <aura:attribute name="todayDate" type="Date"/> <aura:attribute name="currentUser" type="User"/> <force:recordData aura:id="recordLoader" recordId="{!$SObjectType.CurrentUser.Id}" fields="Account.BillingStreet, Account.BillingCity, Account.BillingState, Account.BillingCountry, Account.BillingPostalCode" targetFields="{!v.currentUser}"/> <aura:handler name="init" value="{!this}" action="{!c.initCmpData}"/> <aura:handler name="change" value="{!v.selectedDate}" action="{!c.getFilterApptSlots}"/> <aura:if isTrue="{!v.debug}"> Debug<br/> recId {!v.recordId}<br/> data {!v.data.slots.length}<br/> todayDate {!v.todayDate}<br/> selectedDate {!v.selectedDate}<br/> isEligible {!v.isEligible} <br/> </aura:if> <aura:if isTrue="{!v.loading}"> <aura:if isTrue="{!v.showSpinner}"> <lightning:spinner/> </aura:if> <aura:set attribute="else"> <aura:if isTrue="{!v.isEligible}"> <div class="cmpWrapper"> <lightning:layout multipleRows="true"> <lightning:layoutItem size="4" padding="around-small"> <span class="calWrapper"> <center> <c:DatePicker aura:id="closeDate" label="Select a preferred appointment date to view availability" placeholder="Date" value="{!v.selectedDate}" formatSpecifier="MM/dd/yyyy" /> </center> </span> <br/> <aura:if isTrue="{!v.isEligible}"> <center><br/> <div class="slds-float_leftX additionalOption slds-p-bottom_xx-small"> <h2> Not seeing any results or can’t find an appointment that fits your needs? Contact us at (800) 422-5365.</h2> </div> </center> <br/> </aura:if> <center> <!-- removing create a case access--> <!-- <a href="./contactsupport"> <lightning:button label="Create Case" variant="brand"/> </a> --> </center> </lightning:layoutItem> <lightning:layoutItem size="8" padding="around-small"> <span class="slotsWrapper"> <center> <aura:iteration items="{!v.slotList}" var="slot" indexVar="i"> <aura:if isTrue="{!(i > v.rowCount) == false}"> <c:AdVic_BookingSlot slot="{!slot}" workOrderId="{!v.workOrderId}" serviceAppointmentId="{!v.serviceAppointmentId}"/> </aura:if> </aura:iteration> <lightning:button label="Display Additional Appointments" onclick="{!c.showMore}" variant="brand"/> </center> </span> </lightning:layoutItem> </lightning:layout> </div> <aura:set attribute="else"> <lightning:icon iconName="utility:warning" alternativeText="Customer Not Eligible" variant="Warning" title="Not Eligible" class="notification-icon"/> <aura:if isTrue="{!v.showError}"> <div id="error"> <!-- <lightning:input value="{!v.errorMessage}" readonly="true"/>--> </div> <aura:set attribute="else"> <br/> </aura:set> </aura:if> <br/> <span>{!v.errorMessage}</span> </aura:set> </aura:if> </aura:set> </aura:if> <br/> <br/> </aura:component>
Kindly follow the below steps :-
1. Create one formula field which will calculate the no. of days (today - appoinment date)
2. Create an button on aura component and on click call the method.
3. Write a search method in apex class and in that query the record using the below sample query :-
SELECT Id FROM ServiceAppointment where formulafield > 30
If the above steps fix your issue, then kindly mark it as the best answer.
Thanl you
How would I create a the button in the aura component. I have limited ability with working with this type of code. I'm not sure wherei would add the search method in the apex class either.