• BobP
  • NEWBIE
  • 195 Points
  • Member since 2016

  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 71
    Questions
  • 101
    Replies
I've been looking around to try and find a solution to make my flow radio buttons render horizontally instead of vertically. 



I saw this article below, but it doesn't look like i can use this for my flow. If i could change this into a flow component that targets certain fields in custom objects that would be great but I don't have any idea how to do this change.  If anyone knows of a component already created for use with flows that would be great too



https://www.infallibletechie.com/2020/03/how-to-display-radio-group-horizontally.html
 
  • September 16, 2022
  • Like
  • 0
I have created a custom flow and used the subflow but I am getting the flowing error (Error element Get_Slots (FlowActionCall).
An Apex error occurred: FSL.Exceptions.GeneralException: Script-thrown exception)
When i view the debug log it appears everything is working, so i'm not sure what i am doing wrong. I am using the flow scheduler from this site below. https://unofficialsf.com/flow-scheduler-enable-self-service-scheduling-for-field-service/  


User-added image
Here is how I have the subflow setup
User-added image
  • August 01, 2022
  • Like
  • 0
I am receiving the following error with my screen flow that is updating a custom object record with an account fom a record collection.

Error element Update_Referral_with_Account (FlowRecordUpdate).
This error occurred when the flow tried to update records: If you use a record variable to update or delete records, the ID value in the variable must be populated


Get Record Element
Get Element
Select Account from Collection
User-added imageAssign Account to Referral
Assign Element

I tried updating the referral record two differnt way with no success

Update 1
User-added image
Update referral 2
User-added image
  • May 19, 2022
  • Like
  • 0
I have a lightning component that searches for accounts and on my list i have a checkbox with a strange output. This should just show nothing for false and a checkmark for true.  I was wondering if anyone had any idea how to fix this issue.

User-added image
  • May 17, 2022
  • Like
  • 0
I created this Account Search Lightning Component from a trailhead and I am wondering if there is a way to add some filter criteria to only find accounts that have a checkbox checked on the account record. I am looking for help to add this to the code below. 

Lightning Component:
<aura:component controller="AccountSearchController">
    <aura:registerEvent name="accountsLoaded" type="c:AccountsLoaded"/>
    <aura:handler name="init" value="{!this}" action="{!c.onInit}"/>
    <aura:attribute name="searchTerm" type="String" default="Cranston"/>
    <lightning:card title="Account Search" iconName="standard:search">
        <div class="slds-form slds-p-around_x-small">
            <lightning:input
                label="Search"
                variant="label-hidden"
                value="{!v.searchTerm}"
                placeholder="Search by name, phone, website, or address"
                onchange="{!c.onSearchTermChange}"/>
        </div>
    </lightning:card>
</aura:component>

Controller:
({
    onInit: function( component, event, helper ) {
        // proactively search on component initialization
        var searchTerm = component.get( "v.searchTerm" );
        helper.handleSearch( component, searchTerm );
    },
    onSearchTermChange: function( component, event, helper ) {
        // search anytime the term changes
        var searchTerm = component.get( "v.searchTerm" );
        // to improve performance, particularly for fast typers,
        // we wait a small delay to check when user is done typing
        var delayMillis = 500;
        // get timeout id of pending search action
        var timeoutId = component.get( "v.searchTimeoutId" );
        // cancel pending search action and reset timer
        clearTimeout( timeoutId );
        // delay doing search until user stops typing
        // this improves client-side and server-side performance
        timeoutId = setTimeout( $A.getCallback( function() {
            helper.handleSearch( component, searchTerm );
        }), delayMillis );
        component.set( "v.searchTimeoutId", timeoutId );
    }
})

Here is the Account List Code in case it is needed 
 
<aura:component>
    <aura:handler event="c:AccountsLoaded" action="{!c.onAccountsLoaded}"/>
    <lightning:navigation aura:id="navigation"/>
    <aura:attribute name="rows" type="Map[]"/>
    <aura:attribute name="cols" type="Map[]"/>
    <lightning:card title="Account List" iconName="standard:account">
        <lightning:datatable
            data="{!v.rows}"
            columns="{!v.cols}"
            keyField="Id"
            hideCheckboxColumn="true"
            showRowNumberColumn="true"
            onrowaction="{!c.onRowAction}"/>
    </lightning:card>
</aura:component>
 
({
    onAccountsLoaded: function( component, event, helper ) {
        var cols = [
            {
                'label': 'Name',
                'fieldName': 'Name',
                'type': 'text'
            },
            {
                'label': 'Phone',
                'fieldName': 'Phone',
                'type': 'phone'
            },
            {
                'label': 'Website',
                'fieldName': 'Website',
                'type': 'url'
            },
            {
                'label': 'Action',
                'type': 'button',
                'typeAttributes': {
                    'label': 'View details',
                    'name': 'view_details'
                }
            }
        ];
        component.set( 'v.cols', cols );
        component.set( 'v.rows', event.getParam( 'accounts' ) );
    },
    onRowAction: function( component, event, helper ) {
        var action = event.getParam( 'action' );
        var row = event.getParam( 'row' );
        if ( action.name == 'view_details' ) {
            var navigation = component.find( 'navigation' );
            navigation.navigate({
                'type': 'standard__recordPage',
                'attributes': {
                    'objectApiName': 'Account',
                    'recordId': row.Id,
                    'actionName': 'view'
                }
            });
        }
    }
})

 
  • May 16, 2022
  • Like
  • 0
I have a lightning component that shows a date picker. The arrows are not ailgn in the calendar. I was wondering if there is a wat to add style to the date picker so the two arrows are ailgned?

User-added image
  • May 11, 2022
  • Like
  • 0
I have a lightning component that i am trying to figure out how to add the a spinner to while waiting for appointment time slot to load. I am not sure where to add it with in the lightning component code.

 I believe i need it added to this section of code and probably the helper class to but I am not sure how to get this to work. 
 
<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>

Helper
({
    setToday : function(cmp) {
        var today = new Date();
        
        
        const tomorrow = new Date(Number(today));
        tomorrow.setDate(today.getDate() + 62);
        
        
        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();
        }
    }
})

 
  • May 04, 2022
  • Like
  • 0
I have a custom lightning component in my custom community that just keeps trying to load with the spinning icon and not get past that point.

User-added image
This same lightning component works in our sandbox so i'm not sure how to resolve this issue in my production org.
  • April 29, 2022
  • Like
  • 0
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?
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>


 
  • April 06, 2022
  • Like
  • 0
In the Field Service Settings under scheduling there is a setting entitled "Maximum days to get candidates or to book an appointment ". the number only extends to 31 days. My company's business process needs this number to be at least 60 days. How can I raise number to 60 or what customizations can I make so we can allow the Book Appointment feature or self scheduling on the community so users can schedule appointment more than 30 days out. Are there any solution already that will fit this need
  • March 30, 2022
  • Like
  • 0
I am looking at a lightning component that i didnt create but want to add a flow action(button) to the page. I'm not sure how to do this or if i can do this, but i want to add a flow that creates notes to the lightning component.  Below are schreenshots of where I need to the button and the code snippett where the other button reside.
User-added image

User-added imageUser-added image
  • March 21, 2022
  • Like
  • 0
I created a flow that should create a new note when I a custom the description field is populated with text. when i use the Note Object in my create element, it works by creating the note in the related list of an appointment. When i try it with the Content Note in my element nothing happens. 
 
How can I update my flow to make sure the note is created in the new note related list. See screenshot below

User-added imageUser-added image
  • March 11, 2022
  • Like
  • 0
I have a screen flow that is giving my a headache. No matter what i do to change the variable to set the account from a contact it is still giving me this error.
The flow failed to access the value for Get_Contact_Id.Account.Id because it hasn't been set or assigned.
I am trying to create a record from a contact record for a custom object but I cant figure out why it isnt setting the AccountId from my Get Contact Id element
User-added image
Create record element
User-added image

 
  • March 09, 2022
  • Like
  • 0
I have a date and time field that i am trying to just get the time from the that field. When I use this below format it gives me the time 5 hours ahead of EST. so the time in the field is 12:00pm it displays 5:00PM
(TIMEVALUE(SchedStartTime)

I guess i need to add the time zone to this formula on my time formula field but I am not sure how
  • February 28, 2022
  • Like
  • 0
I have a process builder workflow that i am trying to add a IsChanged criteria for a scheduled date field, but it doesn't allow me on a scheduled action.

Does anyone know if this is possible in a process builder work flow

User-added image
  • September 01, 2021
  • Like
  • 0
I have a flow that is working. It updates service appointments when a community user click a flow button and changes the dates on a flow screen and then clicks save.

It will generate a error often of "The flow tried to update these records: null. This error occurred: UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record. " 

I think my flow is created correctly, but i am wondering if there is something i can update to stop these errors.

Looking at this part of the error message "The flow tried to update these records: null." 
Why is it starting with a null while getting a record ID?
User-added image

Then it errors out on the service appointment update.
User-added image
 I beleieve the biggest issue with the update is the status field.

Is there a better way to set that value?  I'm just not sure why I am getting so many errors off of a simple flow.

 should i set specific fields in the get element for service appointments? 



 
  • August 19, 2021
  • Like
  • 0
I have a flow that is sometimes generating
the UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record.  I don't know if there is something I can update to my flow to ignore any apex batch jobs etc or to change my flow.  Below is the update that is throwing the error.

User-added image
  • August 17, 2021
  • Like
  • 0
I have a previously created lightning component that is currenty a single column and i would like to make it two columns. I attempted adding slds-size_1-of-2 to the following but it just shrunk the form
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <lightning:recordForm
                                          recordId="{!v.modalApptId}"
                                          objectApiName="ServiceAppointment"
                                          layoutType="Full"
                                          mode="edit"
                                          oncancel="{!c.closeModal}"
                                          onsuccess="{!c.toastToSave}"/>

What do i need to add to the below code to adjust it two a two column form? 
 
<aura:component controller="AcmeController" implements="flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes" access="global">
    <ltng:require styles="{!$Resource.AcmeEventCal + '/fullcalendar.min.css'}"/>
    <aura:attribute name="showModal" type="Boolean" default="false"/>
    <aura:attribute name="modalApptId" type="String" default=""/>
    <aura:attribute name="lastEdited" type="String" default=""/>
    
    
    <aura:attribute name="allEvents" type="Map"/>
    <aura:attribute name="objectLabel" type="String"/>
    <aura:attribute name="sObjectName" type="String"/>
    <aura:attribute name="titleField" type="String"/>
    <aura:attribute name="startDateTimeField" type="String"/>
    <aura:attribute name="endDateTimeField" type="String"/>
    <aura:attribute name="descriptionField" type="String"/>
    <aura:attribute name="userField" type="String"/>
    <aura:attribute name="calendarButtons" type="String"/>
    <aura:attribute name="weekends" type="Boolean"/>
    <aura:attribute name="eventBackgroundColor" type="String"/>
    <aura:attribute name="eventBorderColor" type="String"/>
    <aura:attribute name="eventTextColor" type="String"/>
    <aura:attribute name="idVal" type="String"/>
    <aura:attribute name="titleVal" type="String"/>
    <aura:attribute name="locationVal" type="String"/>
    <aura:attribute name="eventTypeVal" type="String"/>
    <aura:attribute name="descriptionVal" type="String"/>
    <aura:attribute name="startDateTimeVal" type="DateTime"/>
    <aura:attribute name="timeSlotNameVal" type="DateTime"/>
    <aura:attribute name="endDateTimeVal" type="DateTime"/>
    <aura:attribute name="newOrEdit" type="String" default="New"/>
    <aura:attribute name="calendar" type="Object"/>
    
    <aura:handler name="change" value="{!v.eventFilter}" action="{!c.renderCalendar}"/>
    <aura:handler name="change" value="{!v.allEvents}" action="{!c.renderCalendar}"/>
    
    <div id="calendar" class="anyCalendar"></div>
    
    
    <aura:if isTrue="{!v.showModal}">
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <header class="slds-modal__header">
           
                    <h2 id="modal-heading-01" class="slds-modal__title slds-hyphenate">Edit Service Appointment</h2>
                    <!--<p class="slds-m-top_x-small">
                        <a href="{!'../'+v.modalApptId}">View full record details</a>.</p>-->
                </header>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <lightning:recordForm
                                          recordId="{!v.modalApptId}"
                                          objectApiName="ServiceAppointment"
                                          layoutType="Full"
                                          mode="edit"
                                          oncancel="{!c.closeModal}"
                                          onsuccess="{!c.toastToSave}"/>
                </div>

            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
        
    </aura:if>
    
    

    
</aura:component>

 
  • August 17, 2021
  • Like
  • 0
I am trying to figure out how to get contact information from an account lookup field on a service appoinment. I need the contact info so i can send an email alert to the contractor when a new appointment is created.
I do have a flow already created that i might be able to use. 
I am trying to add the contact lookup component 
The Unofficial Lookup Component (Now called Quick Lookup)  (https://unofficialsf.com/lookup/)

But i only want this lookup to look at contacts that are related to the contractor on the service appointment. I have this setup below but it still find all contacts. 
User-added image


any help would be appreciated. 
  • July 28, 2021
  • Like
  • 0
I have created a flow that will allows a user to create a new note on a service appointment with a default Title. I am not sure what i am doing wrong. It seems like this should be simple but I am at a loss.  Any help would be greatly appreciated. I really just need a way to set a default Title for a customer note button, but that did not work either

User-added imageUser-added imageUser-added imageUser-added image
  • July 19, 2021
  • Like
  • 0
I have a extension contrlloer for a visualforce page that i need to create a simple text class, but i'm not sure how to accomplish this. Any help would be greatly appreciated. My apex controller is below.
 
Public Class AccountExtensionController{
   private Account acct;
   public List<Bids_Sent__c> bidsList {get;set;}
   public Map<String,List<Site_Bid_Details__c>>  bidsMap {get;set;}
   public AccountExtensionController(ApexPages.StandardController sc){
       acct = (Account)sc.getRecord();
       bidsList = new List<Bids_Sent__c>();
       bidsList = [SELECT Id,IsAddedToPDF__c,Customer__r.Service_Agreement_Verbiage__c,Site__c,Site__r.Contract_Start_Date__c,Site__r.Contract_End_Date__c,Site__r.Customer_Location_ID__c,Service_Year__c,Customer__r.Contract_Start_Date__c,Name,Customer__r.Contract_End_Date__c,Site__r.Name,Customer__r.Name,Primary_Contact__r.FirstName,Site__r.BillingCity,Site__r.BillingState,Site__r.BillingStreet,Site__r.BillingPostalCode  FROM Bids_Sent__c WHERE Awarded__c =: acct.Id AND IsAddedToPDF__c=true];
    
    Set<Id> bidId = new  Set<Id>();  
    for(Bids_Sent__c bs : bidsList){
     bidId.add(bs.Id);
    }
     
    bidsMap = new Map<String,List<Site_Bid_Details__c>> ();
    for(Site_Bid_Details__c bd : [SELECT Id, Bid_Name__r.Name,Site__c,Site__r.Customer_Location_ID__c,Cost__c,Increment__c,Total__c,Price__c,Scope__c,Bid_Name__r.Service_Type__c,Number_of_Months__c,Retainer_Fee__c,Monthly_Payment__c,UOM__c  FROM Site_Bid_Details__c WHERE Bid_Name__c IN : bidId]){
        
    if(bidsMap.containsKey(bd.Bid_Name__r.Name)){
    System.debug('CONTAINS KEY: ' + bd.Bid_Name__r.Name);
    bidsMap.get(bd.Bid_Name__r.Name).add(bd);
    } 
  
    else { 
    System.debug('CREATE: ' + bd.Bid_Name__r.Name);
    bidsMap.put(bd.Bid_Name__r.Name,new List<Site_Bid_Details__c>{bd}); 
   }
 } 

}

}

 
  • January 10, 2020
  • Like
  • 1
I have created a custom flow and used the subflow but I am getting the flowing error (Error element Get_Slots (FlowActionCall).
An Apex error occurred: FSL.Exceptions.GeneralException: Script-thrown exception)
When i view the debug log it appears everything is working, so i'm not sure what i am doing wrong. I am using the flow scheduler from this site below. https://unofficialsf.com/flow-scheduler-enable-self-service-scheduling-for-field-service/  


User-added image
Here is how I have the subflow setup
User-added image
  • August 01, 2022
  • Like
  • 0
I am receiving the following error with my screen flow that is updating a custom object record with an account fom a record collection.

Error element Update_Referral_with_Account (FlowRecordUpdate).
This error occurred when the flow tried to update records: If you use a record variable to update or delete records, the ID value in the variable must be populated


Get Record Element
Get Element
Select Account from Collection
User-added imageAssign Account to Referral
Assign Element

I tried updating the referral record two differnt way with no success

Update 1
User-added image
Update referral 2
User-added image
  • May 19, 2022
  • Like
  • 0
I have a lightning component that searches for accounts and on my list i have a checkbox with a strange output. This should just show nothing for false and a checkmark for true.  I was wondering if anyone had any idea how to fix this issue.

User-added image
  • May 17, 2022
  • Like
  • 0
I have a lightning component that i am trying to figure out how to add the a spinner to while waiting for appointment time slot to load. I am not sure where to add it with in the lightning component code.

 I believe i need it added to this section of code and probably the helper class to but I am not sure how to get this to work. 
 
<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>

Helper
({
    setToday : function(cmp) {
        var today = new Date();
        
        
        const tomorrow = new Date(Number(today));
        tomorrow.setDate(today.getDate() + 62);
        
        
        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();
        }
    }
})

 
  • May 04, 2022
  • Like
  • 0
I have a custom lightning component in my custom community that just keeps trying to load with the spinning icon and not get past that point.

User-added image
This same lightning component works in our sandbox so i'm not sure how to resolve this issue in my production org.
  • April 29, 2022
  • Like
  • 0
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?
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>


 
  • April 06, 2022
  • Like
  • 0
In the Field Service Settings under scheduling there is a setting entitled "Maximum days to get candidates or to book an appointment ". the number only extends to 31 days. My company's business process needs this number to be at least 60 days. How can I raise number to 60 or what customizations can I make so we can allow the Book Appointment feature or self scheduling on the community so users can schedule appointment more than 30 days out. Are there any solution already that will fit this need
  • March 30, 2022
  • Like
  • 0
I am looking at a lightning component that i didnt create but want to add a flow action(button) to the page. I'm not sure how to do this or if i can do this, but i want to add a flow that creates notes to the lightning component.  Below are schreenshots of where I need to the button and the code snippett where the other button reside.
User-added image

User-added imageUser-added image
  • March 21, 2022
  • Like
  • 0
I have a screen flow that is giving my a headache. No matter what i do to change the variable to set the account from a contact it is still giving me this error.
The flow failed to access the value for Get_Contact_Id.Account.Id because it hasn't been set or assigned.
I am trying to create a record from a contact record for a custom object but I cant figure out why it isnt setting the AccountId from my Get Contact Id element
User-added image
Create record element
User-added image

 
  • March 09, 2022
  • Like
  • 0
I have a date and time field that i am trying to just get the time from the that field. When I use this below format it gives me the time 5 hours ahead of EST. so the time in the field is 12:00pm it displays 5:00PM
(TIMEVALUE(SchedStartTime)

I guess i need to add the time zone to this formula on my time formula field but I am not sure how
  • February 28, 2022
  • Like
  • 0
I have a flow that is sometimes generating
the UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record.  I don't know if there is something I can update to my flow to ignore any apex batch jobs etc or to change my flow.  Below is the update that is throwing the error.

User-added image
  • August 17, 2021
  • Like
  • 0
I have a previously created lightning component that is currenty a single column and i would like to make it two columns. I attempted adding slds-size_1-of-2 to the following but it just shrunk the form
<div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <lightning:recordForm
                                          recordId="{!v.modalApptId}"
                                          objectApiName="ServiceAppointment"
                                          layoutType="Full"
                                          mode="edit"
                                          oncancel="{!c.closeModal}"
                                          onsuccess="{!c.toastToSave}"/>

What do i need to add to the below code to adjust it two a two column form? 
 
<aura:component controller="AcmeController" implements="flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes" access="global">
    <ltng:require styles="{!$Resource.AcmeEventCal + '/fullcalendar.min.css'}"/>
    <aura:attribute name="showModal" type="Boolean" default="false"/>
    <aura:attribute name="modalApptId" type="String" default=""/>
    <aura:attribute name="lastEdited" type="String" default=""/>
    
    
    <aura:attribute name="allEvents" type="Map"/>
    <aura:attribute name="objectLabel" type="String"/>
    <aura:attribute name="sObjectName" type="String"/>
    <aura:attribute name="titleField" type="String"/>
    <aura:attribute name="startDateTimeField" type="String"/>
    <aura:attribute name="endDateTimeField" type="String"/>
    <aura:attribute name="descriptionField" type="String"/>
    <aura:attribute name="userField" type="String"/>
    <aura:attribute name="calendarButtons" type="String"/>
    <aura:attribute name="weekends" type="Boolean"/>
    <aura:attribute name="eventBackgroundColor" type="String"/>
    <aura:attribute name="eventBorderColor" type="String"/>
    <aura:attribute name="eventTextColor" type="String"/>
    <aura:attribute name="idVal" type="String"/>
    <aura:attribute name="titleVal" type="String"/>
    <aura:attribute name="locationVal" type="String"/>
    <aura:attribute name="eventTypeVal" type="String"/>
    <aura:attribute name="descriptionVal" type="String"/>
    <aura:attribute name="startDateTimeVal" type="DateTime"/>
    <aura:attribute name="timeSlotNameVal" type="DateTime"/>
    <aura:attribute name="endDateTimeVal" type="DateTime"/>
    <aura:attribute name="newOrEdit" type="String" default="New"/>
    <aura:attribute name="calendar" type="Object"/>
    
    <aura:handler name="change" value="{!v.eventFilter}" action="{!c.renderCalendar}"/>
    <aura:handler name="change" value="{!v.allEvents}" action="{!c.renderCalendar}"/>
    
    <div id="calendar" class="anyCalendar"></div>
    
    
    <aura:if isTrue="{!v.showModal}">
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <header class="slds-modal__header">
           
                    <h2 id="modal-heading-01" class="slds-modal__title slds-hyphenate">Edit Service Appointment</h2>
                    <!--<p class="slds-m-top_x-small">
                        <a href="{!'../'+v.modalApptId}">View full record details</a>.</p>-->
                </header>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    <lightning:recordForm
                                          recordId="{!v.modalApptId}"
                                          objectApiName="ServiceAppointment"
                                          layoutType="Full"
                                          mode="edit"
                                          oncancel="{!c.closeModal}"
                                          onsuccess="{!c.toastToSave}"/>
                </div>

            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
        
    </aura:if>
    
    

    
</aura:component>

 
  • August 17, 2021
  • Like
  • 0
My company uses field service appointments and something unusual is happening.
when i click from list view to list view on the service appointments the last modified date and time changes to the current date and time. I can not find why this is happening or if there is a process running to tell me where the issue is.  I can not click on Where the Field is used because it is a standard field.   Does anyone know if there is a way I can find what is updating this field every second?
  • May 21, 2021
  • Like
  • 0
I created a visualforce and a apex class to display junction object child records on an account page. It is working as expected, but i was wonder how can update my apex class to allow the junction object child records to be updated from the account page? I'm not sure how to accomplish this so i am reaching out to the community to see if anyone could help me update my class to support this function. My VF page and class is below.

VF Page:
<apex:page standardController="Account" extensions="VF_SiteServicePartnerLandController" lightningStylesheets="true"  >


<style>
       th{ width: 50%;}       
   </style>
 
    <apex:form > 
  


     <apex:pageBlock >
    
        
        <apex:pageBlockTable cellpadding="5" width="100%" columns="2" value="{!sspList}" var="item">
 
           <apex:column >
           <apex:outputField value="{!item.Supported_Trade__c}"/><br></br>
           <apex:outputLabel value=""><b>Service Partner Assigned to Site</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Partner Primary Contact</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Primary_Field_Contact__c}"/><br></br>
                <apex:outputLabel value=""><b>Primary Field  Cell</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Primary_Field_Mobile__c}"/><br></br>
                <apex:outputLabel value=""><b>Primary Field Email</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Primary_Field_Email__c}"/><br></br>
                <apex:outputLabel value=""><b>Secondary Contact</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Secondary_Field_Contact__c}"/><br></br>
                <apex:outputLabel value=""><b>Secondary Cell</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Secondary_Field_Mobile__c}"/><br></br>
                <apex:outputField value="{!item.Secondary_Field_Email__c}"/>
            
            </apex:column>
           
           
           <apex:column >
           
           <apex:outputLabel value=""><b>Service Partner Owner</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_Owner__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Partner Owner Cell</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_Owner_Mobile__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Partner Main Phone</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_Main_Phone__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Partner Owner Email</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_Owner_Email__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Provider Start Date</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_Start_Date__c}"/><br></br>
                <apex:outputLabel value=""><b>Service Provider End Date</b></apex:outputLabel><br></br>
                <apex:outputField value="{!item.Service_Partner_End_Date__c}"/>
            
            </apex:column>
            
      </apex:pageBlockTable>
   </apex:pageBlock>
 </apex:form>   
 </apex:page>

Apex Class:
// Used on the account page updated 1-31-2020
Public Class VF_SiteServicePartnerLandController{
   private Account acc;
   public List<Site_Service_Partner__c> sspList {get;set;}
   
   public VF_SiteServicePartnerLandController(ApexPages.StandardController sp){
       acc = (Account)sp.getRecord();
       sspList = new List<Site_Service_Partner__c>();
       sspList = [SELECT Id,Name,Site_Account__c,Primary_Field_Contact__c,Service_Partner__c,
                  Service_Partner_Owner__c,Service_Partner_Owner_Mobile__c,Service_Partner_Owner_Email__c,
                  Primary_Field_Email__c,Primary_Field_Mobile__c,Service_Partner_Site_Status__c, 
                  Contracted_Services__c,Secondary_Field_Contact__c,Secondary_Field_Email__c,Secondary_Field_Mobile__c,
                  Service_Partner_Start_Date__c,Service_Partner_End_Date__c,Service_Partner_Main_Phone__c,Trade__c,Supported_Trade__c  FROM Site_Service_Partner__c WHERE Site_Account__c =: acc.Id AND Site_Account__r.Trade__c includes('Land') AND Service_Partner_Site_Status__c = 'Active' ];

    
    Set<Id> bidId = new  Set<Id>();  
    for(Site_Service_Partner__c bs:sspList){
       bidId.add(bs.Id);
    }
     
   }

}

 
  • February 05, 2020
  • Like
  • 0