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
Bob 11Bob 11 

Update Apex class to add 60 days to slotStartDay > Date.today()

I was wondering if I can update this segment of code to look at a formula field that uses date & time thats adds at least 60 days or how i can update this piece of code like  if(slotStartDay > Date.today() +60?  I tried addDays(60) and Date.today() +60 and when i tried to search for avialable appointment slots nothing was displayed

 
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;
    }

 
AnkaiahAnkaiah (Salesforce Developers) 
Hi Bob,

Instead of date.today() you can use system.today() in the if condition.

Modify your if condition like below.
if(slotStartDay > (system.today()+60) )

If this helps, Please mark it as best answer.

Thanks!!​​​​​​​

 
Bob 11Bob 11
Hi Ankaiah,

Thank you for helping. I did add that if(slotStartDay > (system.today()+60) ) but it do what i wanted it to do. I got a service appointment apex class & custom lightning component that I'm trying to change to allow users to book appointments out 60-90 days.  I'm not sure you can help, but i posted the rest of the code below just in case. 

Lightning Component
<aura:component implements="flexipage:availableForAllPageTypes,forceCommunity:availableForAllPageTypes,force:hasRecordId,flexipage:availableForRecordHome" access="global"
                controller="acme_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.</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:Acme_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>

Helper Class
({
    setToday : function(cmp) {
        var today = new Date();
        
        
        const tomorrow = new Date(Number(today));
        tomorrow.setDate(today.getDate() + 1);
        
        
        var str = tomorrow.getFullYear() + '-' + String(tomorrow.getMonth() + 1).padStart(2, '0') + '-' + String(tomorrow.getDate()).padStart(2, '0');
        cmp.set("v.todayDate", str);
        cmp.set("v.selectedDate",str);
	},
    checkAccountEligibility : function(cmp) {
        console.log('Checking Account Eligibility');
        var action = cmp.get("c.checkAccountEligibility");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var eligibilityStatus = response.getReturnValue();
                console.log('@@@@ eligibilityStatus: ' + eligibilityStatus);
                cmp.set("v.loading", false);
                cmp.set("v.showSpinner",false);
                if(eligibilityStatus !== 'Eligible') {
                    cmp.set("v.isEligible", false);
                    cmp.set("v.showError", true);
                    cmp.set("v.errorMessage", eligibilityStatus);
                } else {
                    this.createWorkOrderAndServiceAppointment(cmp);
                }
            } else {
                let errors = response.getError();
                console.log('Error response: ' + response);
                console.log("Error message: " + errors[0].message);
            }
        });

        $A.enqueueAction(action);
    },
    createWorkOrderAndServiceAppointment : function(cmp) {
        //cmp.set("v.showSpinner", true);
          console.log('Getting appointments to create?');
        var action = cmp.get("c.createWorkOrderAndServiceAppointment");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var resp = response.getReturnValue();
                cmp.set("v.loading", false);
                cmp.set("v.isEligible", resp.isEligibleCustomer); //change to true from other cmp.resp.isEligibleCustomer
                if(resp.isEligibleCustomer) { //swith to true for testing resp.isEligibleCustomer
                    cmp.set("v.workOrderId", resp.workOrderId);
                    cmp.set("v.serviceAppointmentId", resp.serviceAppointmentId);
                    this.getApptSlots(cmp);
                }
            } else {
                let errors = response.getError();
                console.log('Error response: ' + response);
                console.log("Error message: " + errors[0].message);
            }
        });

        $A.enqueueAction(action);
    },
    getApptSlots : function(cmp){
        console.log('here is the callback function which is erroring out due to too much CPU time, but why?');
        var selectedDate = cmp.get("v.selectedDate");
        var workOrderId = cmp.get("v.workOrderId")
        var serviceAppointmentId = cmp.get("v.serviceAppointmentId");

        var action = cmp.get("c.getAppointmentSlots");
        action.setParams({
            workOrderId: workOrderId,
            serviceAppointmentId: serviceAppointmentId
        });
        action.setCallback(this, function(response) {
            cmp.set("v.showSpinner", false);
            var state = response.getState();
            if (state === "SUCCESS") {
                var resp = response.getReturnValue();
                console.log(resp);
                cmp.set("v.data",resp);
                cmp.set("v.slotList", resp.slots);
                cmp.set("v.allSlots", resp.slots);
                cmp.set("v.rowCount", 4);
            }
            else{
                let errors = response.getError();
                console.log('Error response: ' + response);
                console.log("Error message: " + errors[0].message);
            }
        });

        $A.enqueueAction(action);
    },
    getFilterApptSlots : function (cmp) {
        var allSlots = cmp.get("v.allSlots");
        var todayDate = cmp.get("v.todayDate");
        var selectedDate = cmp.get("v.selectedDate");
        var convertedSelectedDate = new Date(selectedDate);

        if(selectedDate >= todayDate) {
            var filteredSlots = [];
            // Filter the slots by Date
            allSlots.forEach(function (slot) {
                var convertedStartDate = new Date(slot.times.startDT);
                if(convertedStartDate >= convertedSelectedDate){
                    filteredSlots.push(slot) ;
                }
            });
            cmp.set("v.rowCount", 4);
            cmp.set("v.slotList", filteredSlots);
        } else {
            cmp.set("v.selectedDate", todayDate);
            var toastEvent = $A.get("e.force:showToast");
            toastEvent.setParams({
                "title": "Notice",
                "type":"warning",
                "message": "Appointments must be scheduled at least one day in advance.",
                "mode":'sticky'

            });
            toastEvent.fire();
        }
    }
})





Apex Class
public without sharing class 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;}
    }
}