Пример #1
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);
        }
Пример #2
0
        private void GenerarViajesYPlanillas(CalculoDeRecorrido calcRecorrido)
        {
            // Una vez que termino con el cálculo de cada intervalo genero viajes
            // El primer viaje del día es a las 4 AM
            DateTime    inicioProximoViaje = new DateTime(1, 1, 1, 4, 0, 0);
            RecorridoBE recorrido          = calcRecorrido.Recorrido;
            int         descansoChoferes   = int.Parse(ConfigurationManager.AppSettings["descansoChoferes"]);

            foreach (int intervalo in calcRecorrido.FrecuenciaPorIntervalo.Keys)
            {
                while (inicioProximoViaje.Hour - inicioProximoViaje.Hour % 2 == intervalo)
                {
                    ViajeBE viajeIda = new ViajeBE
                    {
                        HoraSalida          = inicioProximoViaje,
                        HoraEstimadaLlegada = inicioProximoViaje.Add(calcRecorrido.DuracionPorIntervalo[intervalo]),
                        EsIda           = true,
                        TerminalOrigen  = recorrido.TerminalInicio,
                        TerminalDestino = recorrido.TerminalFin
                    };

                    // Busco la planilla cuyo último viaje termine en la terminal de salida antes de que
                    // salga este micro (más el descanso de los choferes)
                    PlanillaHorariaBE planillaIda = _planillasGeneradas.Where(p =>
                                                                              p.Recorrido == recorrido &&
                                                                              p.Viajes.Last().TerminalDestino == recorrido.TerminalInicio &&
                                                                              p.Viajes.Last().HoraEstimadaLlegada.AddMinutes(descansoChoferes) < inicioProximoViaje).FirstOrDefault();

                    if (planillaIda == null)
                    {
                        planillaIda = new PlanillaHorariaBE
                        {
                            Fecha     = _fechaAGenerar,
                            Recorrido = recorrido,
                            Viajes    = new List <ViajeBE>()
                        };
                        _planillasGeneradas.Add(planillaIda);
                    }
                    planillaIda.Viajes.Add(viajeIda);

                    // Hago lo mismo con el viaje de vuelta
                    ViajeBE viajeVuelta = new ViajeBE
                    {
                        HoraSalida          = inicioProximoViaje,
                        HoraEstimadaLlegada = inicioProximoViaje.Add(calcRecorrido.DuracionPorIntervalo[intervalo]),
                        EsIda           = false,
                        TerminalOrigen  = recorrido.TerminalFin,
                        TerminalDestino = recorrido.TerminalInicio,
                    };

                    PlanillaHorariaBE planillaVuelta = _planillasGeneradas.Where(p =>
                                                                                 p.Recorrido == recorrido &&
                                                                                 p.Viajes.Last().TerminalDestino == recorrido.TerminalFin &&
                                                                                 p.Viajes.Last().HoraEstimadaLlegada.AddMinutes(descansoChoferes) < inicioProximoViaje).FirstOrDefault();

                    if (planillaVuelta == null)
                    {
                        planillaVuelta = new PlanillaHorariaBE
                        {
                            Fecha     = _fechaAGenerar,
                            Recorrido = recorrido,
                            Viajes    = new List <ViajeBE>()
                        };
                        _planillasGeneradas.Add(planillaVuelta);
                    }
                    planillaVuelta.Viajes.Add(viajeVuelta);

                    inicioProximoViaje = inicioProximoViaje.AddMinutes(calcRecorrido.FrecuenciaPorIntervalo[intervalo]);
                }
            }
        }
Пример #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);
            }
        }