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 

Apex class creating multiple records

I have this class below that create service appointments. It should allow a customer to find a appointment time slot and select it , then create the work order and servcie appointment,. But while the Lightning component is searching for aviable time slots this class will keep creating blank service appointments and work orders even beofre the customer selects an appointment time slot. Does anyone know what in this apex class is causing that to happen? 
 
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];
        
        //return account.Customer_Eligible__c;
        return true; //for testing only.
    }
    //new eligibility that we need to incoporate REMS-191
    @AuraEnabled
    public static String checkAccountEligibility() {
        String eligibilityStatus = '';
        Boolean codeStartsWithPp = false;
        User runningUser = getRunningUser();
        Contact cont = [SELECT Electric_Utility_Number__c, Gas_Utility_Number__c, How_do_you_heat_your_home__c, AccountId, Part_of_Condo_Association__c FROM Contact WHERE Id =: runningUser.ContactId];
        System.debug('@@@ cont.Gas_Utility_Number__c: ' + cont.Gas_Utility_Number__c);
        System.debug('@@@ cont.Electric_Utility_Number__c: ' + cont.Electric_Utility_Number__c);
        if(String.isBlank(cont.Gas_Utility_Number__c) && String.isBlank(cont.Electric_Utility_Number__c)) {
            Account account = [SELECT Eligible_Testing__c, Ineligible_Reason_Code__c, Square_Footage__c, Building_Type__c FROM Account WHERE Id = :cont.AccountId];
            System.debug('@@@ account: ' + account);
            codeStartsWithPp = checkIneligibleReasonCode(account.Ineligible_Reason_Code__c);
            if(account.Eligible_Testing__c == false) {
                //Need to display general ineligible code info
                if(account.Ineligible_Reason_Code__c == 'DISC'){
                    eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property. Please contact your local Community Action Partnership, or call our offices for more information.';
                }
                else if(account.Ineligible_Reason_Code__c == 'COM'){
                    eligibilityStatus = 'Please contact out office for further assistance at 401-000-0000';
                }
                else if(codeStartsWithPp){
                    eligibilityStatus = 'We are not able to schedule you  Thank you.';
                } else if(account.Ineligible_Reason_Code__c != 'DISC' || account.Ineligible_Reason_Code__c != 'COM' || !codeStartsWithPp){
                eligibilityStatus = 'thank you';
                } else{
                    eligibilityStatus = 'thank you';                    
                }
            } else if(account.Eligible_Testing__c == true && (cont.Part_of_Condo_Association__c == 'Yes' || account.Building_Type__c != 'Single-Family Home' || account.Square_Footage__c == '3000-3500 sq ft' || account.Square_Footage__c == '3500-6000 sq ft' || account.Square_Footage__c == '6000+ sq ft')){
                    eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance, please contact our offices.';                    
            } else {
                eligibilityStatus = 'Eligible';
                }}
        if(String.isNotBlank(cont.Gas_Utility_Number__c)) {
            Account gasAcc = [SELECT Eligible_Testing__c, Ineligible_Reason_Code__c, Building_Type__c, Square_Footage__c FROM Account WHERE Utility_Number__c =: cont.Gas_Utility_Number__c LIMIT 1];
            System.debug('@@@ gasAcc: ' + gasAcc);
            codeStartsWithPp = checkIneligibleReasonCode(gasAcc.Ineligible_Reason_Code__c);
            if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && gasAcc.Eligible_Testing__c == true && gasAcc.Ineligible_Reason_Code__c != 'DISC' && (cont.Part_of_Condo_Association__c == 'Yes' || gasAcc.Building_Type__c != 'Single-Family Home' || gasAcc.Square_Footage__c == '3000-3500 sq ft' || gasAcc.Square_Footage__c == '3500-6000 sq ft' || gasAcc.Square_Footage__c == '6000+ sq ft')){
                System.debug('@@@@ A');
                eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance, please contact our offices. ';
            }
            else if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && gasAcc.Eligible_Testing__c == true && gasAcc.Ineligible_Reason_Code__c != 'DISC'){
                System.debug('@@@@ B');
                eligibilityStatus = 'Eligible';
            }
            else if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && gasAcc.Ineligible_Reason_Code__c == 'DISC'){
                //Need to display DISC code info:
                System.debug('@@@@ C');
                eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.';
            } else if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && gasAcc.Eligible_Testing__c == false){
                //Need to display general ineligible code info
                System.debug('@@@@ D');
                if(gasAcc.Ineligible_Reason_Code__c == 'DISC'){
                    System.debug('@@@@ E');
                    eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.';
                }
                else if(gasAcc.Ineligible_Reason_Code__c == 'COM'){
                    System.debug('@@@@ F');
                    eligibilityStatus = 'Due';
                }
                else if(codeStartsWithPp){
                    System.debug('@@@@ G');
                    eligibilityStatus = 'We are not able to schedule you';
                } else{
                    System.debug('@@@@ H');
                    eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance, please contact our offices.';
                }} else {
                    if (cont.How_do_you_heat_your_home__c == 'None') {
                        System.debug('@@@@ I');
                        //Need to display general ineligible code info
                        if(gasAcc.Ineligible_Reason_Code__c == 'DISC'){
                            System.debug('@@@@ J');
                            eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.';
                        }
                        else if(gasAcc.Ineligible_Reason_Code__c == 'COM'){
                            System.debug('@@@@ K');
                            eligibilityStatus = 'Due to the commercial rate code on this property, we are not able to schedule a residential No-Cost Energy Assessment.';
                        }
                        else if(codeStartsWithPp){
                            System.debug('@@@@ L');
                            eligibilityStatus = 'We are not able to schedule you a No-Cost energy assessment due to the recent participation in the program.';
                        }
                        else{
                            System.debug('@@@@ M');
                            eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time.';
                        }}
                }
        }
        if(String.isNotBlank(cont.Electric_Utility_Number__c)) {
            Account elecAcc = [SELECT Eligible_Testing__c, Ineligible_Reason_Code__c, Building_Type__c, Square_Footage__c FROM Account WHERE Utility_Number__c =: cont.Electric_Utility_Number__c LIMIT 1];
            System.debug('@@@ elecAcc: ' + elecAcc);
            codeStartsWithPp = checkIneligibleReasonCode(elecAcc.Ineligible_Reason_Code__c);
            if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && elecAcc.Ineligible_Reason_Code__c != 'DISC' && (cont.Part_of_Condo_Association__c == 'Yes' || elecAcc.Building_Type__c != 'Single-Family Home' || elecAcc.Square_Footage__c == '3000-3500 sq ft' || elecAcc.Square_Footage__c == '3500-6000 sq ft' || elecAcc.Square_Footage__c == '6000+ sq ft')){
                eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance, please contact our offices.';
            }
            else if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && elecAcc.Ineligible_Reason_Code__c != 'DISC'){
                eligibilityStatus = 'Eligible';
            }
            else if(cont.How_do_you_heat_your_home__c == 'Natural Gas' && elecAcc.Ineligible_Reason_Code__c == 'DISC'){
                //Need to display DISC code info:
                eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.  Thank you.';
            } 
            else if(cont.How_do_you_heat_your_home__c != 'Natural Gas' && cont.How_do_You_heat_your_home__c != 'None' && elecAcc.Eligible_Testing__c == true && (cont.Part_of_Condo_Association__c == 'Yes' || elecAcc.Building_Type__c != 'Single-Family Home' || elecAcc.Square_Footage__c == '3000-3500 sq ft' || elecAcc.Square_Footage__c == '3500-6000 sq ft' || elecAcc.Square_Footage__c == '6000+ sq ft')){
                eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time.';
            }
            else  if(cont.How_do_you_heat_your_home__c != 'Natural Gas' && cont.How_do_you_heat_your_home__c != 'None' && elecAcc.Eligible_Testing__c == true){
                eligibilityStatus = 'Eligible';
            } else  if(cont.How_do_you_heat_your_home__c != 'Natural Gas' && cont.How_do_you_heat_your_home__c != 'None' && elecAcc.Eligible_Testing__c == false){
                //Need to display general ineligible code info
                if(elecAcc.Ineligible_Reason_Code__c == 'DISC'){
                    eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.  Thank you.';
                }
                else if(elecAcc.Ineligible_Reason_Code__c == 'COM'){
                    eligibilityStatus = 'Due to the commercial rate code on this property, we are not able to schedule a residential No-Cost Energy Assessment.';
                }
                else if(codeStartsWithPp){
                    eligibilityStatus = 'We are not able to schedule you a No-Cost energy assessment due to the recent participation in the program.. Thank you.';
                } else {
                    eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance,';
                }} else {
                    if (cont.How_do_you_heat_your_home__c == 'None') {
                        //Need to display general ineligible code info
                        if(elecAcc.Ineligible_Reason_Code__c == 'DISC'){
                            eligibilityStatus = 'Due to your utility service rate code, we are not able to service your property.  Thank you.';
                        }
                        else if(elecAcc.Ineligible_Reason_Code__c == 'COM'){
                            eligibilityStatus = 'Due to the commercial rate code on this property, we are not able to schedule a residential No-Cost Energy Assessment.';
                        }
                        else if(codeStartsWithPp){
                            eligibilityStatus = 'We are not able to schedule you a No-Cost energy assessment due to the recent participation in the program. For further assistance, please contact our offices. Thank you.';
                        }else{
                            eligibilityStatus = 'Thank you for your inquiry, we are unable to complete your request at this time. For further assistance, please contact our offices.';
                        }}
            }
        }

        System.debug('@@@@ eligibilityStatus: ' + eligibilityStatus);

        return eligibilityStatus;
    }

    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().addMonths(1), 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);
        //I'm thinking they may want these ordered by rank, but not 100% sure. If so, we can do that with the comparable interface:
        //https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_comparable.htm --Chuck
        
        //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;}
    }
}