public async Task <DoctorWorkingTime> GetAvailableWorkingTimeAsync(Guid id, DateTime date, FilterWorktime filter) { var doctorTime = await Context.Doctors .IncludeMultiple(x => x.Appointments, x => x.WorkingSchedules, x => x.NoAttendances) .Where(x => x.IsActive && x.Id == id) .Select(x => new DoctorTimeProjection { WorkingHoursInDay = x.WorkingSchedules .Where(ws => ws.IsActive && date.Date >= ws.FromDate.Date) .Select(ws => ws.Hours.ToWorkingTimes(date.DayOfWeek)) .FirstOrDefault(), TimeOffInDay = x.NoAttendances .Where(na => na.IsActive && date.IsBetween(na.FromDate.Date, na.ToDate.Date)) .Select(na => TimeRangeUtils.GetTimeRange(na.FromDate, na.ToDate, date)) .ToArray(), TimeBusyInDay = x.Appointments .Where(a => a.IsActive && a.Status != (int)AppointmentStatus.Cancelled && a.DoctorId == id && a.AppointmentDate.Date == date.Date) .Select(a => new TimeRange(a.AppointmentDate.TimeOfDay, a.AppointmentDate.AddMinutes(a.TotalMinutes).TimeOfDay)) .ToArray() }) .FirstOrDefaultAsync(); var result = new DoctorWorkingTime { DoctorId = id, WorkingTimes = doctorTime.WorkingHoursInDay .ConvertArray(wh => TimeRangeUtils.GetTimeFrame(wh, doctorTime.TimeOffInDay, doctorTime.TimeBusyInDay, new TimeRange(filter.TimeFrom ?? new TimeSpan(0, 0, 0), new TimeSpan(23, 59, 59)))) .ToSingleArray() }; if (filter.ServiceDuration.GetValueOrDefault() > 0) { result.WorkingTimes = result.WorkingTimes.Where(worktime => TimeRangeUtils.IsServiceTime(worktime, filter.ServiceDuration.Value, result.WorkingTimes)).ToArray(); } return(result); }
protected static FR_L5S_SUSfP_1708 Execute(DbConnection Connection, DbTransaction Transaction, P_L5S_SUSfP_1708 Parameter, CSV2Core.SessionSecurity.SessionSecurityTicket securityTicket = null) { //Leave UserCode region to enable user code saving #region UserCode var returnValue = new FR_L5S_SUSfP_1708(); //ucitati sve potrebne podatke L5ATW_ANfTID_1855[] appointmnetTypesDB = null; L5TE_GNWTfOID_1506[] officeNonWorkingTimes = null; L5TE_GSHfOID_1540[] officeStandardHours = null; L5TE_GSAfT_1645[] allEmployeesDB = null; L5TE_GTEFAS_1440[] allStaffExceptions = null; L5TE_GDAfT_1844[] devices = null; ORM_HEC_Doctor[] hecDoctorsDB = null; ORM_HEC_Doctor_AssignableAppointmentType[] hecDoctor2ATDB = null; ORM_PPS_TSK_Task_Template_OrganizationalUnitAvailability[] ppsTaskTemplate2Office = null; L5BTS_GBSfPID_1141[] slotsAndCombinationForPractice = null; L3P_GPfT_1537[] professionsForTenant = null; //Parallel.Invoke( // () => // { // appointmnetTypesDB = cls_Get_AppointmentTypeWeb_Name_for_TenantID.Invoke(Transaction.Connection.ConnectionString, securityTicket).Result; // }, // () => // { // officeNonWorkingTimes = cls_Get_NonWorkingTimesforOfficeID.Invoke(Transaction.Connection.ConnectionString, new P_L5TE_GNWTfOID_1506() { OfficeID = Parameter.PracticeID }, securityTicket).Result; // }, // () => // { // officeStandardHours = cls_Get_StandardHours_for_OfficeID.Invoke(Transaction.Connection.ConnectionString, new P_L5TE_GSHfOID_1540() { OfficeID = Parameter.PracticeID }, securityTicket).Result; // } // , // () => // { // allEmployeesDB = cls_Get_Staff_with_Availability_for_TenantID.Invoke(Transaction.Connection.ConnectionString, securityTicket).Result; // }, // () => // { // allStaffExceptions = cls_Get_TimeExceptionsForAllStaff.Invoke(Transaction.Connection.ConnectionString, securityTicket).Result; // }, // () => // { // devices = cls_Get_Devices_Availability_for_TenantID.Invoke(Transaction.Connection.ConnectionString, securityTicket).Result; // }, // () => // { // hecDoctorsDB = ORM_HEC_Doctor.Query.Search(Transaction.Connection.ConnectionString, new ORM_HEC_Doctor.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false }).ToArray(); // }, // () => // { // hecDoctor2ATDB = ORM_HEC_Doctor_AssignableAppointmentType.Query.Search(Transaction.Connection.ConnectionString, new ORM_HEC_Doctor_AssignableAppointmentType.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false }).ToArray(); // }, // () => // { // ppsTaskTemplate2Office = ORM_PPS_TSK_Task_Template_OrganizationalUnitAvailability.Query.Search(Transaction.Connection.ConnectionString, new ORM_PPS_TSK_Task_Template_OrganizationalUnitAvailability.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false, CMN_STR_Office_RefID = Parameter.PracticeID }).ToArray(); // }, // () => // { // slotsAndCombinationForPractice = cls_Get_BookableSlots_for_PracticeID.Invoke(Transaction.Connection.ConnectionString, new P_L5BTS_GBSfPID_1141() { OfficeID = Parameter.PracticeID, AvaTypeMatchingID = EnumUtils.GetEnumDescription(AvailabilityType.WebBooking) }, securityTicket).Result; // }, // () => // { // professionsForTenant = cls_Get_Professions_for_TenantID.Invoke(Transaction.Connection.ConnectionString, securityTicket).Result; // } //); appointmnetTypesDB = cls_Get_AllAppointmentTypes_Name_for_TenantID.Invoke(Connection, Transaction, securityTicket).Result; officeNonWorkingTimes = cls_Get_NonWorkingTimesforOfficeID.Invoke(Connection, Transaction, new P_L5TE_GNWTfOID_1506() { OfficeID = Parameter.PracticeID }, securityTicket).Result; officeStandardHours = cls_Get_StandardHours_for_OfficeID.Invoke(Connection, Transaction, new P_L5TE_GSHfOID_1540() { OfficeID = Parameter.PracticeID }, securityTicket).Result; allEmployeesDB = cls_Get_Staff_with_Availability_for_TenantID.Invoke(Connection, Transaction, securityTicket).Result; allStaffExceptions = cls_Get_TimeExceptionsForAllStaff.Invoke(Connection, Transaction, securityTicket).Result; devices = cls_Get_Devices_Availability_for_TenantID.Invoke(Connection, Transaction, securityTicket).Result; hecDoctorsDB = ORM_HEC_Doctor.Query.Search(Connection, Transaction, new ORM_HEC_Doctor.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false }).ToArray(); hecDoctor2ATDB = ORM_HEC_Doctor_AssignableAppointmentType.Query.Search(Connection, Transaction, new ORM_HEC_Doctor_AssignableAppointmentType.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false }).ToArray(); ppsTaskTemplate2Office = ORM_PPS_TSK_Task_Template_OrganizationalUnitAvailability.Query.Search(Connection, Transaction, new ORM_PPS_TSK_Task_Template_OrganizationalUnitAvailability.Query() { Tenant_RefID = securityTicket.TenantID, IsDeleted = false, CMN_STR_Office_RefID = Parameter.PracticeID }).ToArray(); slotsAndCombinationForPractice = cls_Get_BookableSlots_for_PracticeID.Invoke(Connection, Transaction, new P_L5BTS_GBSfPID_1141() { OfficeID = Parameter.PracticeID }, securityTicket).Result; professionsForTenant = cls_Get_Professions_for_TenantID.Invoke(Connection, Transaction, securityTicket).Result; L5TE_GSAfT_1645[] employeesFromPracticeDB = allEmployeesDB.Where(e => e.Offices != null && e.Offices.FirstOrDefault(o => o.OfficeID == Parameter.PracticeID) != null).ToArray(); //prepakuj podatke u zeljeni model var practice = ModelConvertor.ConvertPracticeDBData(Parameter.PracticeID, officeNonWorkingTimes, officeStandardHours, appointmnetTypesDB.Where(w => ppsTaskTemplate2Office.Select(s => s.PPS_TSK_Task_Template_RefID).Contains(w.PPS_TSK_Task_TemplateID)).ToArray()); practice.Staff = ModelConvertor.ConvertStaffDBData(Parameter.PracticeID, employeesFromPracticeDB, hecDoctorsDB, hecDoctor2ATDB, allStaffExceptions, professionsForTenant); practice.Devices = ModelConvertor.ConvertDevice(devices.Where(d => d.CMN_STR_Office_RefID == Parameter.PracticeID).ToArray()); foreach (var appointmentType in practice.AppointmentTypes) { List <Staff> staffForThisAppointmentType = new List <Staff>(practice.Staff.Where(s => s.AvailableAppointmentTypeIds.Contains(appointmentType.ID))); var persistedSlotsForAT = slotsAndCombinationForPractice.Where(w => w.TaskTemplate_RefID == appointmentType.ID).ToArray(); bool needDevices = appointmentType.RequiredDeviceTypes != null && appointmentType.RequiredDeviceTypes.Count > 0; //ucititati sve appointmente tog tipa u praksi var scheduledAppParam = new P_L5A_GAABDfObTfD_1915() { FromDate = DateTime.Now.AddDays(-1), OfficeID = Parameter.PracticeID, TaskTemplateID = appointmentType.ID }; var scheduledAppointmentsDB = cls_Get_AllAppointment_BaseData_for_Office_by_Type_from_Date.Invoke(Connection, Transaction, scheduledAppParam, securityTicket).Result; //ucitane appointmente prebaciti u zeljeni model var scheduledAppointments = ModelConvertor.ConvertAppointments(scheduledAppointmentsDB); var posibleResourceCombinations = new List <ResourceCombination>(); //iskalkulisati sve moguce kombinacije osoblja za zelejni tip appointmenta var staffCombinations = StaffAvailabiltyCalculations.GetFilteredStaffForAppointmentTypeBySkills(staffForThisAppointmentType, appointmentType); var weekFramesPerStaffCombination = new Dictionary <Guid, List <RangeIntersection> >(); foreach (var comb in staffCombinations) { weekFramesPerStaffCombination.Add(comb.ID, StaffAvailabiltyCalculations.CalculateWeekAvailableFramesForStaffCombination(comb.Data, practice.Availabilities)); } //iskalkulisati sve moguce kombinacije osoblja za zelejni tip appointmenta if (needDevices) { var deviceInstanceCombinations = DeviceAvailabilityCalculations.GetFilteredDeviceForAppointmentType(practice.Devices, appointmentType); var weekFramesPerDeviceCombination = new Dictionary <Guid, List <RangeIntersection> >(); foreach (var comb in deviceInstanceCombinations) { var allAbilities = comb.Data.Select(s => s.Availabilities).ToList(); allAbilities.Add(practice.Availabilities); weekFramesPerDeviceCombination.Add(comb.ID, StaffAvailabiltyCalculations.FindAllIntersections(allAbilities)); } foreach (var deviceCombination in weekFramesPerDeviceCombination) { foreach (var staffCombination in weekFramesPerStaffCombination) { var allIntersects = new List <List <RangeIntersection> >(); allIntersects.Add(staffCombination.Value); allIntersects.Add(deviceCombination.Value); var resourceCombinationIntersections = StaffAvailabiltyCalculations.FindAllIntersections(allIntersects); if (resourceCombinationIntersections.Count > 0) { posibleResourceCombinations.Add(new ResourceCombination() { AppointmentTypeID = appointmentType.ID, OfficeID = Parameter.PracticeID, StaffCombination = staffCombinations.Single(s => s.ID == staffCombination.Key), DeviceInstancesCombination = deviceInstanceCombinations.Single(s => s.ID == deviceCombination.Key), TimeIntersections = resourceCombinationIntersections, IsDeviceNeeded = true }); } } } } else { foreach (var staffCombination in weekFramesPerStaffCombination) { posibleResourceCombinations.Add(new ResourceCombination() { AppointmentTypeID = appointmentType.ID, OfficeID = Parameter.PracticeID, StaffCombination = staffCombinations.Single(s => s.ID == staffCombination.Key), TimeIntersections = staffCombination.Value }); } } //pranaci validne slotove od postojecih List <TimeSlot> calculatedSlots = new List <TimeSlot>(); foreach (var combination in posibleResourceCombinations) { //slotovi za narednih 6 meseci u odnosu na nedeljne slotove - izuzeci var combinationSlots = TimeRangeUtils.CalculateTimeFramesFromRanges(combination.TimeIntersections, appointmentType.DurationInSec); var exceptions = new List <ExceptionTime>(practice.Exceptions); exceptions.AddRange(combination.StaffCombination.Data.Select(select => select.Staff).SelectMany(c => c.Exceptions).ToList()); if (combination.IsDeviceNeeded) { exceptions.AddRange(combination.DeviceInstancesCombination.Data.SelectMany(s => s.Exceptions).ToList()); } var makeSlotsForNext3Months = StaffAvailabiltyCalculations.MakeSlotsForPeriod(combinationSlots, exceptions, DateTime.Now, DateTime.Now.AddMonths(3)); var thisCombinationAppointments = scheduledAppointments.Where(w => w.StaffIDs.Intersect(combination.StaffCombination.Data.Select(s => s.Staff.ID)).Any()).ToList(); if (needDevices) { thisCombinationAppointments = thisCombinationAppointments.Where(w => w.DeviceInstanceIDs.Intersect(combination.DeviceInstancesCombination.Data.Select(s => s.ID)).Any()).ToList(); } foreach (var slot in makeSlotsForNext3Months) { if (!TimeRangeUtils.SlotOverlapingWithAppontmentArray(slot, thisCombinationAppointments)) { var slotMatch = calculatedSlots.FirstOrDefault(s => s.PeriodStart == slot.PeriodStart && s.PeriodEnd == slot.PeriodEnd); if (!TimeRangeUtils.SlotOverlapingWithSlotArray(slot, calculatedSlots)) { if (slotMatch == null) { slot.ResourceCombination.Add(combination); calculatedSlots.Add(slot); } else { slotMatch.ResourceCombination.Add(combination); } } else { if (slotMatch != null) { slotMatch.ResourceCombination.Add(combination); } } } } } var updatedSlotIDs = new List <Guid>(); var slotParam = new List <P_L5BTS_CSwRC_1156_Slot>(); foreach (var slot in calculatedSlots) { var persistedSlot = persistedSlotsForAT.FirstOrDefault(f => f.FreeInterval_Start == slot.PeriodStart && f.FreeInterval_End == slot.PeriodEnd); if (persistedSlot != null) // postoji takav slot u bazi { updatedSlotIDs.Add(persistedSlot.PPS_TSK_BOK_BookableTimeSlotID); var keepCombinationsIDs = new List <Guid>(); bool isSlotWebBookable = false; var combinationList = new List <P_L5BTS_CSwRC_1156_Slot_Combination>(); foreach (var slotCombination in slot.ResourceCombination) { bool isCombinaitonWebBookable = true; // da li je vidljiv za web bookovanje foreach (var staff in slotCombination.StaffCombination.Data) { if (isCombinaitonWebBookable) { if (!StaffAvailabiltyCalculations.IsStaffWebBookableInThisTameRange(staff.Staff, slot)) { isCombinaitonWebBookable = false; } } } if (!isSlotWebBookable && isCombinaitonWebBookable) { isSlotWebBookable = true; } // proveri da li vec postoji takva kobinacija u bazi bool thisCombinationMatchedWithSomePersisted = false; foreach (var persistedCombination in persistedSlot.Combinations) { if (CombinationUtils.CompareCombinations(slotCombination, persistedCombination)) { thisCombinationMatchedWithSomePersisted = true; keepCombinationsIDs.Add(persistedCombination.PPS_TSK_BOK_AvailableResourceCombinationID); break; } } if (thisCombinationMatchedWithSomePersisted) // ako postoji preskoci je { if ((persistedSlot.SlotType.GlobalPropertyMatchingID == EnumUtils.GetEnumDescription(AvailabilityType.WebBooking)) != isSlotWebBookable && appointmentType.IsWebBookable) // ako nije isti tip slota { slotParam.Add(new P_L5BTS_CSwRC_1156_Slot() { Combinations = combinationList.ToArray(), End = slot.PeriodEnd, Start = slot.PeriodStart, SlotID = persistedSlot.PPS_TSK_BOK_BookableTimeSlotID, IsWebBookable = isSlotWebBookable && appointmentType.IsWebBookable }); } continue; } var staffList = new List <P_L5BTS_CSwRC_1156_Slot_Combination_Staff>(); var deviceInstanceList = new List <P_L5BTS_CSwRC_1156_Slot_Combination_DeviceInstance>(); foreach (var staff in slotCombination.StaffCombination.Data) { staffList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination_Staff() { CreatedFor_TaskTemplateRequiredStaff_RefID = staff.ID, StaffID = staff.Staff.ID }); //if (isWebBookable) // if (!StaffAvailabiltyCalculations.IsStaffWebBookableInThisTameRange(staff.Staff, slot)) // isWebBookable = false; } if (slotCombination.IsDeviceNeeded) { foreach (var deviceInstance in slotCombination.DeviceInstancesCombination.Data) { deviceInstanceList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination_DeviceInstance() { DeviceInstanceID = deviceInstance.ID }); } } combinationList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination() { DeviceInstance = deviceInstanceList.ToArray(), Staff = staffList.ToArray() }); } if (combinationList.Count > 0 || ((persistedSlot.SlotType.GlobalPropertyMatchingID == EnumUtils.GetEnumDescription(AvailabilityType.WebBooking)) != isSlotWebBookable && appointmentType.IsWebBookable) || keepCombinationsIDs.Count != persistedSlot.Combinations.Count()) { slotParam.Add(new P_L5BTS_CSwRC_1156_Slot() { Combinations = combinationList.ToArray(), End = slot.PeriodEnd, Start = slot.PeriodStart, SlotID = persistedSlot.PPS_TSK_BOK_BookableTimeSlotID, IsWebBookable = isSlotWebBookable && appointmentType.IsWebBookable, CombinationForDelete = new P_L5BTS_CSwRC_1156_Slot_CombinationsForDelete() { CombinationIDs = persistedSlot.Combinations.Select(s => s.PPS_TSK_BOK_AvailableResourceCombinationID).Except(keepCombinationsIDs).ToArray() } }); } } else // slot ne postoji, napravi novi { bool isSlotWebBookable = false; var combinationList = new List <P_L5BTS_CSwRC_1156_Slot_Combination>(); foreach (var slotCombination in slot.ResourceCombination) { bool isCombinaitonWebBookable = true; var staffList = new List <P_L5BTS_CSwRC_1156_Slot_Combination_Staff>(); var deviceInstanceList = new List <P_L5BTS_CSwRC_1156_Slot_Combination_DeviceInstance>(); foreach (var staff in slotCombination.StaffCombination.Data) { staffList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination_Staff() { CreatedFor_TaskTemplateRequiredStaff_RefID = staff.ID, StaffID = staff.Staff.ID }); if (isCombinaitonWebBookable) { if (!StaffAvailabiltyCalculations.IsStaffWebBookableInThisTameRange(staff.Staff, slot)) { isCombinaitonWebBookable = false; } } } if (slotCombination.IsDeviceNeeded) { foreach (var deviceInstance in slotCombination.DeviceInstancesCombination.Data) { deviceInstanceList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination_DeviceInstance() { DeviceInstanceID = deviceInstance.ID }); } } combinationList.Add(new P_L5BTS_CSwRC_1156_Slot_Combination() { DeviceInstance = deviceInstanceList.ToArray(), Staff = staffList.ToArray() }); if (!isSlotWebBookable && isCombinaitonWebBookable) { isSlotWebBookable = true; } } slotParam.Add(new P_L5BTS_CSwRC_1156_Slot() { Combinations = combinationList.ToArray(), End = slot.PeriodEnd, Start = slot.PeriodStart, SlotID = Guid.NewGuid(), IsWebBookable = isSlotWebBookable && appointmentType.IsWebBookable }); } } var createSlotBulkParam = new P_L5BTS_CSwRC_1156() { AppointmentTypeID = appointmentType.ID, OfficeID = Parameter.PracticeID, Slots = slotParam.ToArray() }; var persistedSlotForDeleteIDs = persistedSlotsForAT.Where(s => !updatedSlotIDs.Contains(s.PPS_TSK_BOK_BookableTimeSlotID)).Select(s => s.PPS_TSK_BOK_BookableTimeSlotID).ToArray(); cls_Delete_Slots.Invoke(Connection, Transaction, new P_L5BTS_DS_1510() { SlotIDs = persistedSlotForDeleteIDs }, securityTicket); cls_Create_Slots_with_ResourceCombinations.Invoke(Connection, Transaction, createSlotBulkParam, securityTicket); } return(returnValue); #endregion UserCode }