public virtual decimal GetEmployeeHoursFromCalendar(int?employeeID) { decimal hours = 40; var select = new PXSelect <EPEmployee, Where <EPEmployee.bAccountID, Equal <Required <EPEmployee.bAccountID> > > >(graph); EPEmployee employee = select.Select(employeeID); if (employee != null && employee.CalendarID != null) { CSCalendar calendar = PXSelect <CSCalendar, Where <CSCalendar.calendarID, Equal <Required <CSCalendar.calendarID> > > > .Select(graph, employee.CalendarID); if (calendar != null) { hours = 0; hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Monday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Tuesday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Wednesday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Thursday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Friday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Saturday); hours += CalendarHelper.GetHoursWorkedOnDay(calendar, DayOfWeek.Sunday); } } return(hours); }
private static void EnsureUnpaidTimeValid(CSCalendar calendar, DayOfWeek dayOfWeek) { CalendarDayInfo calendarDayInfo = new CalendarDayInfo(calendar, dayOfWeek); if (calendarDayInfo.UnpaidTime == null) { if (calendarDayInfo.WorkDay == true) { SetUnpaidTime(calendar, dayOfWeek, 0); } return; } double maxPossibleBreak = calendarDayInfo.GetMaxPossibleUnpaidBreak(); if (maxPossibleBreak > MinutesInDay) { maxPossibleBreak = MinutesInDay; } if (maxPossibleBreak < 0) { maxPossibleBreak = 0; } if (calendarDayInfo.UnpaidTime < 0 || calendarDayInfo.UnpaidTime > maxPossibleBreak) { SetUnpaidTime(calendar, dayOfWeek, (int)maxPossibleBreak); } }
private static void SetUnpaidTime(CSCalendar calendar, DayOfWeek dayOfWeek, int?unpaidTime) { if (dayOfWeek == DayOfWeek.Sunday) { calendar.SunUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Monday) { calendar.MonUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Tuesday) { calendar.TueUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Wednesday) { calendar.WedUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Thursday) { calendar.ThuUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Friday) { calendar.FriUnpaidTime = unpaidTime; } else if (dayOfWeek == DayOfWeek.Saturday) { calendar.SatUnpaidTime = unpaidTime; } }
} //Unpaid time in minutes public CalendarDayInfo(CSCalendar c, DayOfWeek dayOfWeek) { if (dayOfWeek == DayOfWeek.Sunday) { SetDayInfo(c.SunWorkDay, c.SunStartTime, c.SunEndTime, c.SunGoodsMoves, c.SunUnpaidTime); } else if (dayOfWeek == DayOfWeek.Monday) { SetDayInfo(c.MonWorkDay, c.MonStartTime, c.MonEndTime, c.MonGoodsMoves, c.MonUnpaidTime); } else if (dayOfWeek == DayOfWeek.Tuesday) { SetDayInfo(c.TueWorkDay, c.TueStartTime, c.TueEndTime, c.TueGoodsMoves, c.TueUnpaidTime); } else if (dayOfWeek == DayOfWeek.Wednesday) { SetDayInfo(c.WedWorkDay, c.WedStartTime, c.WedEndTime, c.WedGoodsMoves, c.WedUnpaidTime); } else if (dayOfWeek == DayOfWeek.Thursday) { SetDayInfo(c.ThuWorkDay, c.ThuStartTime, c.ThuEndTime, c.ThuGoodsMoves, c.ThuUnpaidTime); } else if (dayOfWeek == DayOfWeek.Friday) { SetDayInfo(c.FriWorkDay, c.FriStartTime, c.FriEndTime, c.FriGoodsMoves, c.FriUnpaidTime); } else if (dayOfWeek == DayOfWeek.Saturday) { SetDayInfo(c.SatWorkDay, c.SatStartTime, c.SatEndTime, c.SatGoodsMoves, c.SatUnpaidTime); } }
public static bool IsWorkDay(PXGraph graph, string CalendarID, DateTime Date) { PXResult <CSCalendar, CSCalendarExceptions> result = (PXResult <CSCalendar, CSCalendarExceptions>) PXSelectJoin < CSCalendar , LeftJoin <CSCalendarExceptions , On <CSCalendarExceptions.calendarID, Equal <CSCalendar.calendarID>, And <CSCalendarExceptions.date, Equal <Required <CSCalendarExceptions.date> > > > > , Where <CSCalendar.calendarID, Equal <Required <CSCalendar.calendarID> > > > .SelectWindowed(graph, 0, 1, Date, CalendarID); if (result != null) { CSCalendar calendar = result; CSCalendarExceptions exc = result; if (exc.Date != null) { return(exc.WorkDay == true); } else { return(calendar.IsWorkDay(Date)); } } return(true); }
public static void EnsureUnpaidTimeValid(CSCalendar calendar) { if (calendar == null) { return; } EnsureUnpaidTimeValid(calendar, DayOfWeek.Sunday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Monday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Tuesday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Wednesday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Thursday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Friday); EnsureUnpaidTimeValid(calendar, DayOfWeek.Saturday); }
public static void CalculateStartEndTime(PXGraph graph, string calendarID, DateTime date, out DateTime startDate, out DateTime endDate) { CSCalendar calendar = PXSelect <CSCalendar> .Search <CSCalendar.calendarID>(graph, calendarID); if (calendar == null) { throw new InvalidOperationException(Messages.FailedToSelectCalenderId); } CSCalendarExceptions cse = PXSelect <CSCalendarExceptions> . Search <CSCalendarExceptions.calendarID, CSCalendarExceptions.date>(graph, calendarID, date); CalendarHelper helper = new CalendarHelper(calendar, cse, date); helper.CalculateStartEndTime(out startDate, out endDate); }
public static double GetMaxPossibleUnpaidBreak(CSCalendar calendar, DayOfWeek dayOfWeek) { CalendarDayInfo calendarDayInfo = new CalendarDayInfo(calendar, dayOfWeek); return(calendarDayInfo.GetMaxPossibleUnpaidBreak()); }
public static decimal GetHoursWorkedOnDay(CSCalendar calendar, DayOfWeek dayOfWeek) { CalendarDayInfo calendarDayInfo = new CalendarDayInfo(calendar, dayOfWeek); return(calendarDayInfo.GetHoursWorkedOnDay()); }
public virtual TimeWindow GetWorkingTimeWindow(CSCalendar csCalendarRow, DateTime?date) { if (csCalendarRow.MonStartTime == null && csCalendarRow.MonStartTime.HasValue == false) { return(null); } TimeWindow workingTime = new TimeWindow(); workingTime.startTimeSec = 0; workingTime.stopTimeSec = 0; switch (date.Value.DayOfWeek) { case DayOfWeek.Sunday: if (csCalendarRow.SunStartTime != null && csCalendarRow.SunStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.SunStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.SunEndTime != null && csCalendarRow.SunEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.SunEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Monday: if (csCalendarRow.MonStartTime != null && csCalendarRow.MonStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.MonStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.MonEndTime != null && csCalendarRow.MonEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.MonEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Tuesday: if (csCalendarRow.TueStartTime != null && csCalendarRow.TueStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.TueStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.TueEndTime != null && csCalendarRow.TueEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.TueEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Wednesday: if (csCalendarRow.WedStartTime != null && csCalendarRow.WedStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.WedStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.WedEndTime != null && csCalendarRow.WedEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.MonEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Thursday: if (csCalendarRow.ThuStartTime != null && csCalendarRow.ThuStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.ThuStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.ThuEndTime != null && csCalendarRow.ThuEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.ThuEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Friday: if (csCalendarRow.FriStartTime != null && csCalendarRow.FriStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.FriStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.FriEndTime != null && csCalendarRow.FriEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.FriEndTime.Value.TimeOfDay.TotalSeconds; } break; case DayOfWeek.Saturday: if (csCalendarRow.SatStartTime != null && csCalendarRow.SatStartTime.HasValue == true) { workingTime.startTimeSec = (int)csCalendarRow.SatStartTime.Value.TimeOfDay.TotalSeconds; } if (csCalendarRow.SatEndTime != null && csCalendarRow.SatEndTime.HasValue == true) { workingTime.stopTimeSec = (int)csCalendarRow.SatEndTime.Value.TimeOfDay.TotalSeconds; } break; default: break; } return(workingTime.startTimeSec == workingTime.stopTimeSec ? null : workingTime); }
public virtual void OptimizeRoutes(RoutesOptimizationProcess graph, FSAppointmentFilter filter, List <FSAppointmentFSServiceOrder> list, PXResultset <FSAppointmentStaffMember, CSCalendar> staffSelected) { RouteOptimizerClient client = new RouteOptimizerClient(); SingleDayOptimizationInput requestBody = new SingleDayOptimizationInput(); List <FSAppointment> processList = new List <FSAppointment>(); FSSetup fsSetupRow = graph.SetupRecord.Current; requestBody.balanced = true; requestBody.vehicles = new List <Vehicle>(); requestBody.waypoints = new List <Waypoint>(); string address = string.Empty; if (staffSelected != null && staffSelected.Count == 0) { throw new PXException(PXMessages.LocalizeFormatNoPrefix(TX.Error.SELECT_AT_LEAST_ONE_STAFF_MEMBER)); } //Origin end Route location FSAddress fsAddressRow = PXSelectJoin <FSAddress, InnerJoin <FSBranchLocation, On <FSBranchLocation.branchLocationAddressID, Equal <FSAddress.addressID> > >, Where < FSBranchLocation.branchLocationID, Equal <Required <FSBranchLocation.branchLocationID> > > > .Select(graph, list[0].BranchLocationID); address = SharedFunctions.GetAddressForGeolocation(fsAddressRow.PostalCode, fsAddressRow.AddressLine1, fsAddressRow.AddressLine2, fsAddressRow.City, fsAddressRow.State, fsAddressRow.CountryID); GLocation[] results = Geocoder.Geocode(address, fsSetupRow.MapApiKey); if (results.Length == 0) { throw new PXException(PXMessages.LocalizeFormatNoPrefix(TX.Error.MAPS_FAILED_REVERSE_ADRESS, TX.TableName.BRANCH_LOCATION)); } CSCalendar csVendorCalendarRow = PXSelect <CSCalendar, Where <CSCalendar.calendarID, Equal <Required <CSCalendar.calendarID> > > > .Select(graph, fsSetupRow.CalendarID); //Driver Logic foreach (PXResult <FSAppointmentStaffMember, CSCalendar> result in staffSelected) { FSAppointmentStaffMember staffRow = (FSAppointmentStaffMember)result; CSCalendar csCalendarRow = (CSCalendar)result; Vehicle vehicleRow = new Vehicle() { name = staffRow.BAccountID.ToString(), origin = new RouteLocation() { latitude = results[0].LatLng.Latitude, longitude = results[0].LatLng.Longitude }, destination = new RouteLocation() { latitude = results[0].LatLng.Latitude, longitude = results[0].LatLng.Longitude }, tags = new List <string>() { staffRow.BAccountID.ToString() } }; TimeWindow working = graph.GetWorkingTimeWindow(staffRow.EmployeeSDEnabled == true ? csCalendarRow : csVendorCalendarRow, filter.StartDate); Break lunchBreak = graph.GetBreakWindow(fsSetupRow); if (lunchBreak != null) { vehicleRow.breaks = new List <Break>() { lunchBreak }; } if (working != null) { vehicleRow.timeWindow = working; requestBody.vehicles.Add(vehicleRow); } } if (requestBody.vehicles.Count == 0) { for (int i = 0; i < list.Count; i++) { FSAppointment fsAppointmentRow = list[i]; UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE); graph.Appointments.Update(fsAppointmentRow); PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.APPOINTMENT_COULD_NOT_BE_REACH_SERVICED_NO_DRIVER_AVAILABLE)); } if (graph.Appointments.Cache.IsDirty == true) { graph.Appointments.Cache.Persist(PXDBOperation.Update); } return; } //Existing Appointment Logic if (filter.Type == ID.Type_ROOptimization.UNASSIGNED_APP && staffSelected.Count() > 0) { List <object> args = new List <object>(); BqlCommand fsAppointmentList = new Select2 <FSAppointment, InnerJoin <FSServiceOrder, On <FSServiceOrder.sOID, Equal <FSAppointment.sOID> >, InnerJoin <FSAddress, On <FSAddress.addressID, Equal <FSServiceOrder.serviceOrderAddressID> > > > >(); if (filter.BranchID != null) { fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSServiceOrder.branchID, Equal <Required <FSServiceOrder.branchID> > >)); args.Add(filter.BranchID); } if (filter.BranchLocationID != null) { fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSServiceOrder.branchLocationID, Equal <Required <FSServiceOrder.branchLocationID> > >)); args.Add(filter.BranchLocationID); } if (filter.StartDate != null) { fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.scheduledDateTimeBegin, GreaterEqual <Required <FSAppointment.scheduledDateTimeBegin> > >)); args.Add(filter.StartDateWithTime); } if (filter.EndDateWithTime != null) { fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.scheduledDateTimeEnd, LessEqual <Required <FSAppointment.scheduledDateTimeEnd> > >)); args.Add(filter.EndDateWithTime); } if (staffSelected != null && staffSelected.Count() > 0) { fsAppointmentList = fsAppointmentList.WhereAnd(typeof(Where <FSAppointment.primaryDriver, In <Required <FSAppointment.primaryDriver> > >)); int[] staffResult = StaffMemberFilter.Select() .RowCast <FSAppointmentStaffMember>() .Where(_ => _.Selected == true) .Select(_ => _.BAccountID) .Cast <int>() .ToArray(); args.Add(staffResult); } PXView appointmentView = new PXView(graph, true, fsAppointmentList); var fsAppointmentSet = appointmentView.SelectMulti(args.ToArray()); foreach (PXResult <FSAppointment, FSServiceOrder, FSAddress> row in fsAppointmentSet) { FSAppointment fsAppointmentRow = (FSAppointment)row; fsAddressRow = (FSAddress)row; address = SharedFunctions.GetAddressForGeolocation( fsAddressRow.PostalCode, fsAddressRow.AddressLine1, fsAddressRow.AddressLine2, fsAddressRow.City, fsAddressRow.State, fsAddressRow.CountryID); Waypoint wp = GetWaypointFromAppointment(fsSetupRow, fsAppointmentRow, address); if (wp != null) { requestBody.waypoints.Add(wp); processList.Add(fsAppointmentRow); } else { UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.ADDRESS_ERROR); graph.Appointments.Update(fsAppointmentRow); } } } //Appointment Logic for (int i = list.Count - 1; i >= 0; i--) { bool addressError = false; try { address = SharedFunctions.GetAddressForGeolocation( list[i].PostalCode, list[i].AddressLine1, list[i].AddressLine2, list[i].City, list[i].State, list[i].CountryID); Waypoint wp = GetWaypointFromAppointment(fsSetupRow, list[i], address); if (wp != null) { requestBody.waypoints.Add(wp); processList.Add(list[i]); } else { addressError = true; } } catch { addressError = true; } if (addressError == true) { addressError = false; FSAppointment fsAppointmentRow = list[i]; UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.ADDRESS_ERROR); graph.Appointments.Update(fsAppointmentRow); list.RemoveAt(i); PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.MAPS_FAILED_REVERSE_ADRESS, TX.TableName.APPOINTMENT)); } } if (graph.Appointments.Cache.IsDirty == true) { graph.Appointments.Cache.Persist(PXDBOperation.Update); } try { SingleDayOptimizationOutput responseObject = client.getSingleDayOptimization(fsSetupRow.ROWWApiEndPoint, fsSetupRow.ROWWLicensekey, requestBody); AppointmentEntry graphAppointmentEntry = PXGraph.CreateInstance <AppointmentEntry>(); for (int i = 0; i < responseObject.routes.Count; i++) { int assignedstaffID; int.TryParse(responseObject.routes[i].vehicle.name, out assignedstaffID); bool changeFlag = false; for (int j = 1; j < responseObject.routes[i].steps.Count - 1; j++) { RouteOtimizer.RouteStep currentAppointment = responseObject.routes[i].steps[j]; int appointmentID; int.TryParse(currentAppointment.waypoint.name, out appointmentID); FSAppointment fsAppointmentListRow = processList.Find(x => x.AppointmentID == appointmentID); var newBegin = convertSecToTime(currentAppointment.serviceStartTimeSec, fsAppointmentListRow.ScheduledDateTimeBegin); var newEnd = newBegin.AddSeconds(currentAppointment.departureTimeSec - currentAppointment.arrivalTimeSec); UpdateAppointmentHeader(fsAppointmentListRow, ID.Status_ROOptimization.OPTIMIZED, j, null, newBegin, newEnd); if (fsAppointmentListRow.PrimaryDriver != null) { graph.Appointments.Update(fsAppointmentListRow); changeFlag = true; } else { fsAppointmentListRow.PrimaryDriver = assignedstaffID; FSAppointment fsAppointmentRow = graphAppointmentEntry.AppointmentRecords.Current = graphAppointmentEntry.AppointmentRecords.Search <FSAppointment.refNbr>( fsAppointmentListRow.RefNbr, fsAppointmentListRow.SrvOrdType); UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.OPTIMIZED, j, assignedstaffID, newBegin, newEnd); graphAppointmentEntry.AppointmentRecords.Update(fsAppointmentRow); FSAppointmentEmployee fsAppointmentEmployeeRow_New = new FSAppointmentEmployee() { AppointmentID = fsAppointmentRow.AppointmentID, EmployeeID = assignedstaffID }; fsAppointmentEmployeeRow_New = graphAppointmentEntry.AppointmentServiceEmployees.Insert(fsAppointmentEmployeeRow_New); graphAppointmentEntry.Save.Press(); } } if (changeFlag == true) { graph.Appointments.Cache.Persist(PXDBOperation.Update); } } foreach (OutputWaypoint wp in responseObject.unreachableWaypoints.Concat(responseObject.unreachedWaypoints).GroupBy(p => p.name).Select(g => g.First()).ToList()) { int appointmentID; int.TryParse(wp.name, out appointmentID); FSAppointment fsAppointmentRow = list.Find(x => x.AppointmentID == appointmentID); if (fsAppointmentRow != null) { for (int i = 0; i < list.Count; i++) { if (fsAppointmentRow.AppointmentID == list[i].AppointmentID) { UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE); graph.Appointments.Update(fsAppointmentRow); PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(TX.Error.APPOINTMENT_COULD_NOT_BE_REACH_SERVICED)); } } } } graph.Appointments.Cache.Persist(PXDBOperation.Update); } catch (PXException e) { for (int i = 0; i < list.Count; i++) { FSAppointment fsAppointmentRow = list[i]; UpdateAppointmentHeader(fsAppointmentRow, ID.Status_ROOptimization.NOT_ABLE); graph.Appointments.Update(fsAppointmentRow); PXProcessing <FSAppointmentFSServiceOrder> .SetError(i, PXMessages.LocalizeFormatNoPrefix(e.Message)); } graph.Appointments.Cache.Persist(PXDBOperation.Update); } }