Пример #1
0
        public static void GenerarProximasPlanillas()
        {
            DateTime fechaUltimaPlanilla = PlanillaHoraria.ObtenerUltimaPlanilla();

            if (fechaUltimaPlanilla == default)
            {
                // Si no hay planillas, pongo la fecha de hoy
                fechaUltimaPlanilla = DateTime.Today;
            }

            DateTime proximaFecha = ObtenerProximaFecha(fechaUltimaPlanilla, out bool puedeGenerarse);

            if (puedeGenerarse)
            {
                GeneradorDePlanillas generadorDePlanillas = new GeneradorDePlanillas(proximaFecha);
                generadorDePlanillas.Generar();

                Bitacora.Loguear(string.Format("Se generaron las planillas para el día {0}", proximaFecha));
            }
        }
Пример #2
0
        public void Generar()
        {
            // Busco en el historial de viajes los que correspondan al mismo tipo de día
            TipoDeDia       tipoDeDia        = ObtenerTipoDeDia(_fechaAGenerar);
            List <DateTime> diasDelMismoTipo = ObtenerDiasDelMismoTipo(tipoDeDia);

            // Proceso cada recorrido individualmente
            List <RecorridoBE>        recorridos          = Recorrido.ListarTodos();
            List <CalculoDeRecorrido> calculosDeRecorrido = new List <CalculoDeRecorrido>();

            foreach (RecorridoBE recorrido in recorridos)
            {
                CalculoDeRecorrido calcRecorrido = new CalculoDeRecorrido
                {
                    Recorrido = recorrido
                };
                CalcularIntervalos(calcRecorrido, diasDelMismoTipo);

                GenerarViajesYPlanillas(calcRecorrido);
                calculosDeRecorrido.Add(calcRecorrido);
            }

            bool hayVehiculos = ChequearDisponibilidadDeVehiculos(out int vehiculosFaltantes);
            bool hayChoferes  = ChequearDisponibilidadDeChoferes(out int choferesFaltantes);

            if (!hayVehiculos || !hayChoferes)
            {
                GenerarAlertaDeInsuficiencia(vehiculosFaltantes, choferesFaltantes);
                RecalcularFrecuencias(calculosDeRecorrido);
            }

            AsignarVehiculos();
            DividirEnDosTurnos();
            AsignarChoferes();

            PlanillaHoraria.GuardarMultiples(_planillasGeneradas);
        }
Пример #3
0
        private void CalcularIntervalos(CalculoDeRecorrido calcRecorrido, List <DateTime> dias)
        {
            List <PlanillaHorariaBE> planillas = PlanillaHoraria.ObtenerPlanilas(calcRecorrido.Recorrido, dias);

            calcRecorrido.FrecuenciaPorIntervalo = new Dictionary <int, int>();
            calcRecorrido.DuracionPorIntervalo   = new Dictionary <int, TimeSpan>();

            // Agrupo las planillas por día
            var planillasPorDia = planillas.GroupBy(p => p.Fecha).Select(g => new
            {
                Fecha     = g.Key,
                Planillas = g.ToList()
            }).OrderBy(x => x.Fecha).ToList();

            int diasDeCalculo = planillasPorDia.Count;

            // Un intervalo representa un período de 2 hs. El intervalo 4 es el período de 4 a 6 hs por ej.
            // Empieza en 4 porque el primer viaje del día siempre es a las 4 AM
            for (int intervalo = 4; intervalo <= 22; intervalo += 2)
            {
                decimal  sumaDeIndices         = 0;
                TimeSpan sumaDuracion          = new TimeSpan();
                int      frecuenciaDiaAnterior = -1;
                int      cantidadViajes        = 0;
                for (int dia = 0; dia < diasDeCalculo; dia++)
                {
                    // Viajes de este intervalo de cada planilla
                    List <ViajeBE> viajesDeIntervalo = planillasPorDia[dia].Planillas.SelectMany(p => p.Viajes)
                                                       .Where(v => v.HoraSalida.Hour - v.HoraSalida.Hour % 2 == intervalo).OrderBy(v => v.HoraSalida).ToList();

                    cantidadViajes += viajesDeIntervalo.Count;
                    decimal sumaCompletitud = 0;
                    for (int iViaje = 0; iViaje < viajesDeIntervalo.Count; iViaje++)
                    {
                        ViajeBE viaje = viajesDeIntervalo[iViaje];

                        // Completitud del viaje
                        if (viaje.Completitud == CompletitudViaje.Vacio)
                        {
                            sumaCompletitud += 0.5M;
                        }
                        else if (viaje.Completitud == CompletitudViaje.Moderado || viaje.Completitud == CompletitudViaje.Nulo)
                        {
                            sumaCompletitud += 1;
                        }
                        else if (viaje.Completitud == CompletitudViaje.Lleno)
                        {
                            sumaCompletitud += 1.5M;
                        }

                        // Duración del viaje
                        if (viaje.HoraRealLlegada.HasValue && viaje.HoraRealLlegada.Value < viaje.HoraSalida)
                        {
                            // Este es el caso cuando llega al día siguiente
                            viaje.HoraRealLlegada = viaje.HoraRealLlegada.Value.AddDays(1);
                        }
                        DateTime horaLlegada = viaje.HoraRealLlegada ?? viaje.HoraEstimadaLlegada;
                        sumaDuracion = sumaDuracion.Add(horaLlegada - viaje.HoraSalida);

                        // Frecuencia del día anterior
                        if (dia == 0 && frecuenciaDiaAnterior < 0)
                        {
                            DateTime horaProximoViaje = viajesDeIntervalo.Where(v => v.HoraSalida > viaje.HoraSalida)
                                                        .OrderBy(v => v.HoraSalida).Select(v => v.HoraSalida).FirstOrDefault();
                            if (horaProximoViaje != default)
                            {
                                frecuenciaDiaAnterior = (int)(horaProximoViaje - viaje.HoraSalida).TotalMinutes;
                            }
                            else if (intervalo <= 20)
                            {
                                // No hay proximo viaje en este intervalo, busco en el siguiente
                                horaProximoViaje = planillasPorDia[dia].Planillas.SelectMany(p => p.Viajes)
                                                   .Where(v => v.HoraSalida.Hour - v.HoraSalida.Hour % 2 == (intervalo + 2))
                                                   .OrderBy(v => v.HoraSalida).Select(v => v.HoraSalida).FirstOrDefault();
                                frecuenciaDiaAnterior = (int)(horaProximoViaje - viaje.HoraSalida).TotalMinutes;
                            }
                            else
                            {
                                // No hay siguiente intervalo, tomo la frecuencia respecto al anterior.
                                DateTime horaViajeAnterior = planillasPorDia[dia].Planillas
                                                             .SelectMany(p => p.Viajes)
                                                             .Where(v => v.HoraSalida.Hour - v.HoraSalida.Hour % 2 == (intervalo - 2))
                                                             .OrderBy(v => v.HoraSalida).Select(v => v.HoraSalida).LastOrDefault();
                                frecuenciaDiaAnterior = (int)(viaje.HoraSalida - horaViajeAnterior).TotalMinutes;
                            }
                        }
                    }

                    decimal promedioCompletitudIntervalo = sumaCompletitud / viajesDeIntervalo.Count;
                    decimal indiceDeAjuste = promedioCompletitudIntervalo * (diasDeCalculo - dia) / diasDeCalculo;
                    sumaDeIndices += indiceDeAjuste;
                }

                int      nuevaFrecuencia;
                TimeSpan nuevaDuracion;
                if (diasDeCalculo > 0 && cantidadViajes > 0)
                {
                    decimal divisorDeFrecuencia = sumaDeIndices / diasDeCalculo;
                    nuevaFrecuencia = (int)Math.Round(frecuenciaDiaAnterior / divisorDeFrecuencia);
                    nuevaFrecuencia = Math.Min(nuevaFrecuencia, 60); // No puede haber una frecuencia mayor a 60 minutos
                    nuevaDuracion   = new TimeSpan(sumaDuracion.Ticks / cantidadViajes);
                    // Redondeo al minuto más cercano
                    nuevaDuracion = TimeSpan.FromMinutes(Math.Round(nuevaDuracion.TotalMinutes));
                }
                else
                {
                    // Si no hay datos, tomo la frecuencia y duración por defecto
                    nuevaFrecuencia = int.Parse(ConfigurationManager.AppSettings["frecuenciaDefault"]);
                    nuevaDuracion   = new TimeSpan(0, int.Parse(ConfigurationManager.AppSettings["duracionDefault"]), 0);
                }

                calcRecorrido.FrecuenciaPorIntervalo.Add(intervalo, nuevaFrecuencia);
                calcRecorrido.DuracionPorIntervalo.Add(intervalo, nuevaDuracion);
            }
        }