Finalización de Reportes y arreglos varios de controles y comportamientos...

This commit is contained in:
2025-06-03 13:45:20 -03:00
parent 99532b03f1
commit 062cc05fd0
67 changed files with 4523 additions and 993 deletions

View File

@@ -1,38 +1,56 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace GestionIntegral.Api.Dtos.Distribucion
{
[CustomValidation(typeof(CreateBulkEntradaSalidaCanillaDto), nameof(ValidateNoDuplicatePublicationsInItems))]
public class CreateBulkEntradaSalidaCanillaDto
{
[Required(ErrorMessage = "El ID del canillita es obligatorio.")]
public int IdCanilla { get; set; }
[Required(ErrorMessage = "La fecha del movimiento es obligatoria.")]
public DateTime Fecha { get; set; } // Fecha común para todos los ítems
public DateTime Fecha { get; set; }
[Required(ErrorMessage = "Debe haber al menos un ítem de movimiento.")]
[MinLength(1, ErrorMessage = "Debe agregar al menos una publicación.")]
// La validación de cada item se hará por los atributos en EntradaSalidaCanillaItemDto
public List<EntradaSalidaCanillaItemDto> Items { get; set; } = new List<EntradaSalidaCanillaItemDto>();
// Validar que no haya publicaciones duplicadas en la lista de items
[CustomValidation(typeof(CreateBulkEntradaSalidaCanillaDto), nameof(ValidateNoDuplicatePublications))]
public string? DuplicateError { get; set; }
public static ValidationResult? ValidateNoDuplicatePublications(CreateBulkEntradaSalidaCanillaDto dto, ValidationContext context)
public static ValidationResult? ValidateNoDuplicatePublicationsInItems(CreateBulkEntradaSalidaCanillaDto instanceToValidate, ValidationContext context)
{
if (dto.Items != null)
if (instanceToValidate == null)
{
var duplicatePublications = dto.Items
.GroupBy(item => item.IdPublicacion)
return new ValidationResult("El objeto principal de la solicitud es nulo.");
}
if (instanceToValidate.Items == null)
{
return ValidationResult.Success; // O error si una lista nula de items es inválida
}
if (instanceToValidate.Items.Any())
{
if (instanceToValidate.Items.Any(item => item == null))
{
return new ValidationResult("La lista de ítems contiene entradas nulas.", new[] { nameof(Items) });
}
var duplicateGroups = instanceToValidate.Items
.Where(item => item.IdPublicacion != 0) // Considerar solo IDs válidos si 0 no lo es
.GroupBy(item => item.IdPublicacion)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList();
if (duplicatePublications.Any())
if (duplicateGroups.Any())
{
return new ValidationResult($"No puede agregar la misma publicación varias veces. Publicaciones duplicadas: {string.Join(", ", duplicatePublications)}");
var duplicatedIds = string.Join(", ", duplicateGroups.Select(g => g.Key));
return new ValidationResult(
$"No puede agregar la misma publicación varias veces. Publicaciones duplicadas IDs: {duplicatedIds}",
new[] { nameof(Items) }
);
}
}
return ValidationResult.Success;

View File

@@ -3,9 +3,11 @@ using System.ComponentModel.DataAnnotations;
namespace GestionIntegral.Api.Dtos.Distribucion
{
[CustomValidation(typeof(EntradaSalidaCanillaItemDto), nameof(ValidateCantidadesItem))] // Aplicar a nivel de clase
public class EntradaSalidaCanillaItemDto
{
[Required(ErrorMessage = "El ID de la publicación es obligatorio.")]
[Range(1, int.MaxValue, ErrorMessage = "El ID de la publicación debe ser válido.")] // Asegurar que no sea 0
public int IdPublicacion { get; set; }
[Required(ErrorMessage = "La cantidad de salida es obligatoria.")]
@@ -17,17 +19,26 @@ namespace GestionIntegral.Api.Dtos.Distribucion
public int CantEntrada { get; set; }
[StringLength(150)]
public string? Observacion { get; set; } // Observación por línea
public string? Observacion { get; set; }
// Validar que CantEntrada no sea mayor que CantSalida
[CustomValidation(typeof(EntradaSalidaCanillaItemDto), nameof(ValidateCantidades))]
public string? CantidadesError { get; set; }
// Ya no necesitamos la propiedad CantidadesError para esta validación
// public string? CantidadesError { get; set; }
public static ValidationResult? ValidateCantidades(EntradaSalidaCanillaItemDto item, ValidationContext context)
public static ValidationResult? ValidateCantidadesItem(EntradaSalidaCanillaItemDto instanceToValidate, ValidationContext context)
{
if (item.CantEntrada > item.CantSalida)
if (instanceToValidate == null)
{
return new ValidationResult("La cantidad de entrada (devolución) no puede ser mayor a la cantidad de salida (retiro) para esta publicación.", new[] { nameof(CantEntrada) });
// Aunque el model binder debería crear la instancia, verificamos
return ValidationResult.Success; // O un error si una instancia nula es inválida por sí misma
}
if (instanceToValidate.CantEntrada > instanceToValidate.CantSalida)
{
// Asociar el error a ambas propiedades podría ser útil en la UI
return new ValidationResult(
"La cantidad de entrada (devolución) no puede ser mayor a la cantidad de salida (retiro).",
new[] { nameof(CantEntrada), nameof(CantSalida) }
);
}
return ValidationResult.Success;
}

View File

@@ -0,0 +1,10 @@
namespace GestionIntegral.Api.Dtos.Distribucion
{
public class PublicacionDiaSemanaDto
{
public int IdPublicacionDia { get; set; } // Útil si se editan individualmente
public int IdPublicacion { get; set; }
public byte DiaSemana { get; set; } // 0 (Domingo) a 6 (Sábado)
public bool Activo { get; set; } = true; // Por defecto activo al crear/mostrar
}
}

View File

@@ -1,25 +1,36 @@
// Similar a E/S Distribuidores, la edición es limitada para no afectar cálculos complejos ya hechos.
// Principalmente para corregir cantidades si aún no está liquidado.
using System.ComponentModel.DataAnnotations;
namespace GestionIntegral.Api.Dtos.Distribucion
{
// Aplicar el CustomValidation a nivel de clase
[CustomValidation(typeof(UpdateEntradaSalidaCanillaDto), nameof(ValidateCantidades))]
public class UpdateEntradaSalidaCanillaDto
{
[Required, Range(0, int.MaxValue)]
public int CantSalida { get; set; }
[Required, Range(0, int.MaxValue)]
public int CantEntrada { get; set; }
[StringLength(150)]
public string? Observacion { get; set; }
[CustomValidation(typeof(UpdateEntradaSalidaCanillaDto), nameof(ValidateCantidades))]
public string? CantidadesError { get; set; } // Dummy para validación
public static ValidationResult? ValidateCantidades(UpdateEntradaSalidaCanillaDto dto, ValidationContext context)
// El método de validación ahora recibe la instancia completa del DTO
public static ValidationResult? ValidateCantidades(UpdateEntradaSalidaCanillaDto instanceToValidate, ValidationContext context)
{
if (dto.CantEntrada > dto.CantSalida)
if (instanceToValidate == null)
{
return new ValidationResult("La cantidad de entrada no puede ser mayor a la de salida.");
// No debería ocurrir si el model binding funcionó, pero es una buena práctica.
return ValidationResult.Success;
}
if (instanceToValidate.CantEntrada > instanceToValidate.CantSalida)
{
// Asociar el error a las propiedades relevantes si es posible y útil
return new ValidationResult(
"La cantidad de entrada no puede ser mayor a la de salida.",
new[] { nameof(CantEntrada), nameof(CantSalida) } // Opcional: nombres de miembros
);
}
return ValidationResult.Success;
}

View File

@@ -0,0 +1,10 @@
// Este DTO se usará para enviar la lista completa de días activos para una publicación.
namespace GestionIntegral.Api.Dtos.Distribucion
{
public class UpdatePublicacionDiasSemanaRequestDto
{
// Lista de los días de la semana (0-6) en los que la publicación estará activa.
// Si un día no está en esta lista, se considerará inactivo o se eliminará la configuración para ese día.
public List<byte> DiasActivos { get; set; } = new List<byte>();
}
}

View File

@@ -0,0 +1,9 @@
public class LiquidacionCanillaDetalleDto
{
public string Publicacion { get; set; } = string.Empty;
public string Canilla { get; set; } = string.Empty; // Para el nombre del canilla en el reporte
public int TotalCantSalida { get; set; }
public int TotalCantEntrada { get; set; }
public decimal TotalRendir { get; set; }
public decimal PrecioEjemplar { get; set; }
}

View File

@@ -0,0 +1,5 @@
public class LiquidacionCanillaGananciaDto
{
public string Publicacion { get; set; } = string.Empty;
public decimal TotalRendir { get; set; } // Asumo que este es el 'monto de comisión'
}