No tenemos un diagrama o documentación de la lógica "exacta", ni tampoco se realiza en ningún SP.
Te puedo copiar el texto de la aplicación de los días de vacación a los períodos, que es lo más exacto que te puedo dar.
/// <summary>
/// Finaliza la entidad
/// </summary>
/// <param name="entity">Entidad a finalizar</param>
/// <remarks>
/// - Crea los registros de detalle de fondo de vacación asociados a los períodos que
/// correspondan, comenzando por el mas antiguo
/// - Actualiza las columnas de días gozados de los períodos a los que se asociaron los
/// dias de vacación
/// </remarks>
/// <returns>Resultado de validacion al actualizar la entidad</returns>
public override ValidationResults FinalizaProcesamientoEntidad(EntityObject entity)
{
var solicitud = (SolicitudVacacion)entity;
solicitud.Estado = EstadoAccion.Autorizado;
solicitud.FechaCambioEstado = DateTime.Now;
var permiteDiasConDecimal = _parametroAplicacionService.GetEsquemaValorParametro<bool>(solicitud.Empleo.Codigo, "Vacacion", NombreParametroVacacionPermiteDiasConDecimales, solicitud.Empleo.Plaza.Compania.Pais.Codigo, null, null, null);
var horasPorDia = _parametroAplicacionService.GetEsquemaValorParametro<int>(solicitud.Empleo.Codigo, "Vacacion", NombreParametroVacacionHorasDia, solicitud.Empleo.Plaza.Compania.Pais.Codigo, null, null, null);
if (horasPorDia <= 0)
{
horasPorDia = 8;
_loggingService.Error(Str.Acciones.SolicitudVacacion.MensajeValorParametroVacacionHorasDiaMenorOIgualQueCero.GetLocalized());
}
var permiteSaldoNegativo = _parametroAplicacionService.GetEsquemaValorParametro<bool>(solicitud.Empleo.Codigo, "Vacacion", NombreParametroVacacionPermiteSaldoNegativo, null, solicitud.Empleo.Plaza.CentroTrabajo.Codigo, null, null);
var diasPorAsignar = solicitud.DiasSolicitados + solicitud.HorasSolicitadas / horasPorDia;
var fechaInicioGoce = solicitud.FechaInicio;
var fondosVacacion = solicitud.Empleo.FondosVacacion;
// variables para controlar que no quede en un loop infinito
var numeroIteraciones = 0;
var maxNumeroIteraciones = 10;
decimal diasPorAsignarIteracionAnterior = diasPorAsignar;
while (diasPorAsignar > 0)
{
// Prevencion de loop infinito
if (diasPorAsignar == diasPorAsignarIteracionAnterior)
numeroIteraciones++;
else
{
numeroIteraciones = 1;
diasPorAsignarIteracionAnterior = diasPorAsignar;
}
// Determina el período inicial donde se procesarán los días
var periodosPorAsignar = fondosVacacion.Where(s => !s.PeriodoCerrado)
.OrderBy(s => s.Orden)
.ThenBy(f => f.FechaInicio)
.Select(f => new { FondoVacacion = f, Saldo = (f.DiasPeriodosAnteriores + f.HorasPeriodoAnterior / (decimal)horasPorDia) + f.Dias - (f.DiasGozados + f.HorasGozadas / (decimal)horasPorDia) })
.ToList();
// Cuando se permiten saldos negativos, si no encontramos periodos con saldo, hay que usar el que tiene saldo cero mas nuevo
var periodoSaldoCeroMasNuevo = periodosPorAsignar.LastOrDefault(x => x.Saldo == 0);
var periodoPorAsignar = periodosPorAsignar.Count(x => x.Saldo != 0) > 0
? periodosPorAsignar.First(x => x.Saldo != 0).FondoVacacion
: permiteSaldoNegativo
? periodoSaldoCeroMasNuevo != null
? periodoSaldoCeroMasNuevo.FondoVacacion
: null
: null;
if (periodoPorAsignar == null)
{
var msg = Str.Acciones.SolicitudVacacion.MensajeNoHayPeriodosParaAsignarDiasGozados.GetLocalized().FormatWith(diasPorAsignar);
throw new InvalidOperationException(msg);
}
decimal diasDescontarDePeriodo;
decimal horasDescontarDePeriodo;
if (diasPorAsignar > periodoPorAsignar.Saldo + periodoPorAsignar.HorasSaldo / horasPorDia && (!permiteSaldoNegativo || periodoPorAsignar != null && periodoPorAsignar.Saldo > 0))
{
if ((periodoPorAsignar.Saldo + periodoPorAsignar.HorasSaldo / horasPorDia) == 0)
{
// Vamos a chequear si hay un problema de datos porque si en este punto el saldo es cero, no podemos procesar la solicitud
throw new AseinfoException("No se puede procesar la solicitud de vacación pues no permite saldo negativo y el período al que se asignarán los datos no tiene saldo. Si ve este mensaje, es muy probable que los datos de los períodos estén incorrectos. Revise en la tabla de fondos de vacación que el saldo coincida con la operación de descontar los días otorgados menos los días gozados (incluyendo horas si ese fuera el caso)");
}
diasDescontarDePeriodo = periodoPorAsignar.Saldo;
horasDescontarDePeriodo = periodoPorAsignar.HorasSaldo;
}
else
{
diasDescontarDePeriodo = permiteDiasConDecimal ? diasPorAsignar : (int)Math.Floor(diasPorAsignar);
horasDescontarDePeriodo = permiteDiasConDecimal ? 0 : (int)Math.Round((diasPorAsignar - diasDescontarDePeriodo) * horasPorDia, 0);
}
if (diasPorAsignar > 0 && diasPorAsignar < 1 && diasDescontarDePeriodo == 0 && horasDescontarDePeriodo == 0)
throw new AseinfoException($"No se puede procesar la solicitud de vacación, porque faltan {diasPorAsignar} dias por procesar y el período al que se le asignarán reporta disponibilidad de cero días y/u horas. Esto puede ser causado porque el parámetro que permite soportar días con decimales NO está activo y los datos en el fondo de vacación o en la solicitud, tienen valores con decimales.");
// Validación para detener un posible loop infinito
if (numeroIteraciones > maxNumeroIteraciones && diasPorAsignar == diasPorAsignarIteracionAnterior)
{
throw new AseinfoException($"No se puede procesar la solicitud de vacación, porque faltan {diasPorAsignar} días por procesar y no se puede aplicar en los períodos disponibles, a pesar que pareciera existir saldo disponible ({periodoPorAsignar.Saldo} días y {periodoPorAsignar.HorasSaldo} horas). Favor revise que los parámetros de digitación de horas, decimales y soporte para saldos negativos, están congruentes con los datos almacenados en los períodos de vacación y en la solicitud que se está procesando.");
}
var fechaFinalGoce = _tiempoService.GetFechaFinalPeriodoGoceVacacion(
solicitud.Empleo,
fechaInicioGoce,
diasDescontarDePeriodo);
var dvaMismaSolicitud = periodoPorAsignar.DiasGozadosVacacion.FirstOrDefault(d => d.Solicitud == solicitud);
if (dvaMismaSolicitud != null)
{
dvaMismaSolicitud.Dias += diasDescontarDePeriodo;
dvaMismaSolicitud.Horas += horasDescontarDePeriodo;
dvaMismaSolicitud.FechaInicial = (new[] { dvaMismaSolicitud.FechaInicial, fechaInicioGoce }).Min();
dvaMismaSolicitud.FechaFin = (new[] { dvaMismaSolicitud.FechaFin, fechaFinalGoce }).Max();
}
else
{
var diaVacacion = new DiaVacacion
{
Dias = diasDescontarDePeriodo,
Horas = horasDescontarDePeriodo,
FechaInicial = fechaInicioGoce,
FechaFin = fechaFinalGoce,
Fondo = periodoPorAsignar,
Solicitud = solicitud,
SePagaron = solicitud.SeranPagadas
};
periodoPorAsignar.DiasGozadosVacacion.Add(diaVacacion);
}
periodoPorAsignar.HorasGozadas += horasDescontarDePeriodo;
if (periodoPorAsignar.HorasGozadas >= horasPorDia)
{
var horasGozadasDias = (int)Math.Floor((periodoPorAsignar.HorasGozadas / horasPorDia));
periodoPorAsignar.DiasGozados += horasGozadasDias;
periodoPorAsignar.HorasGozadas -= horasGozadasDias * horasPorDia;
}
periodoPorAsignar.DiasGozados += diasDescontarDePeriodo;
periodoPorAsignar.Saldo -= diasDescontarDePeriodo;
if (horasDescontarDePeriodo > 0)
{
if (periodoPorAsignar.HorasSaldo < horasDescontarDePeriodo)
{
var horasDescontarDias = (int)Math.Floor(horasDescontarDePeriodo / horasPorDia);
periodoPorAsignar.Saldo -= horasDescontarDias + 1;
periodoPorAsignar.HorasSaldo = horasPorDia - ((horasDescontarDePeriodo - (horasDescontarDias * 8)) - periodoPorAsignar.HorasSaldo);
}
else
{
periodoPorAsignar.HorasSaldo -= horasDescontarDePeriodo;
}
}
diasPorAsignar -= (diasDescontarDePeriodo + (horasDescontarDePeriodo / horasPorDia));
// Asignamos la fecha inicial del siguiente período de goce (si lo hubiere)
fechaInicioGoce = fechaFinalGoce.AddDays(1);
// Se realiza el cierre automatico del período
var saldoPeriodo = (periodoPorAsignar.DiasPeriodosAnteriores + (periodoPorAsignar.HorasPeriodoAnterior / horasPorDia) + periodoPorAsignar.Dias) - (periodoPorAsignar.DiasGozados + (periodoPorAsignar.HorasGozadas / horasPorDia));
if (saldoPeriodo <= 0)
{
if (permiteSaldoNegativo)
{
var ultimoPeriodo = fondosVacacion.OrderByDescending(s => s.Orden).ThenByDescending(s => s.FechaInicio).FirstOrDefault();
if (ultimoPeriodo != null && ultimoPeriodo.Codigo != periodoPorAsignar.Codigo)
{
periodoPorAsignar.PeriodoCerrado = true;
}
}
else
{
periodoPorAsignar.PeriodoCerrado = true;
}
}
}
return ValidationResults;
}
answered
07 Jul '17, 17:48
Fernando Paz ♦♦
17.3k●8●16●35
accept rate:
51%