feat: Implementación de Secciones, Recargos, Porc. Pago Dist. y backend E/S Dist.
Backend API:
- Recargos por Zona (`dist_RecargoZona`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/recargos`.
- Lógica de negocio para vigencias (cierre/reapertura de períodos).
- Auditoría en `dist_RecargoZona_H`.
- Porcentajes de Pago Distribuidores (`dist_PorcPago`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajespago`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcPago_H`.
- Porcentajes/Montos Pago Canillitas (`dist_PorcMonPagoCanilla`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajesmoncanilla`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcMonPagoCanilla_H`.
- Secciones de Publicación (`dist_dtPubliSecciones`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/secciones`.
- Auditoría en `dist_dtPubliSecciones_H`.
- Entradas/Salidas Distribuidores (`dist_EntradasSalidas`):
- Implementado backend (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Lógica para determinar precios/recargos/porcentajes aplicables.
- Cálculo de monto y afectación de saldos de distribuidores en `cue_Saldos`.
- Auditoría en `dist_EntradasSalidas_H`.
- Correcciones de Mapeo Dapper:
- Aplicados alias explícitos en repositorios de RecargoZona, PorcPago, PorcMonCanilla, PubliSeccion,
Canilla, Distribuidor y Precio para asegurar mapeo correcto de IDs y columnas.
Frontend React:
- Recargos por Zona:
- `recargoZonaService.ts`.
- `RecargoZonaFormModal.tsx` para crear/editar períodos de recargos.
- `GestionarRecargosPublicacionPage.tsx` para listar y gestionar recargos por publicación.
- Porcentajes de Pago Distribuidores:
- `porcPagoService.ts`.
- `PorcPagoFormModal.tsx`.
- `GestionarPorcentajesPagoPage.tsx`.
- Porcentajes/Montos Pago Canillitas:
- `porcMonCanillaService.ts`.
- `PorcMonCanillaFormModal.tsx`.
- `GestionarPorcMonCanillaPage.tsx`.
- Secciones de Publicación:
- `publiSeccionService.ts`.
- `PubliSeccionFormModal.tsx`.
- `GestionarSeccionesPublicacionPage.tsx`.
- Navegación:
- Actualizadas rutas y menús para acceder a la gestión de recargos, porcentajes (dist. y canillita) y secciones desde la vista de una publicación.
- Layout:
- Uso consistente de `Box` con Flexbox en lugar de `Grid` en nuevos modales y páginas para evitar errores de tipo.
2025-05-21 14:58:52 -03:00
|
|
|
using GestionIntegral.Api.Data;
|
|
|
|
|
using GestionIntegral.Api.Data.Repositories.Distribucion;
|
2025-06-12 19:36:21 -03:00
|
|
|
using GestionIntegral.Api.Dtos.Auditoria;
|
feat: Implementación de Secciones, Recargos, Porc. Pago Dist. y backend E/S Dist.
Backend API:
- Recargos por Zona (`dist_RecargoZona`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/recargos`.
- Lógica de negocio para vigencias (cierre/reapertura de períodos).
- Auditoría en `dist_RecargoZona_H`.
- Porcentajes de Pago Distribuidores (`dist_PorcPago`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajespago`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcPago_H`.
- Porcentajes/Montos Pago Canillitas (`dist_PorcMonPagoCanilla`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajesmoncanilla`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcMonPagoCanilla_H`.
- Secciones de Publicación (`dist_dtPubliSecciones`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/secciones`.
- Auditoría en `dist_dtPubliSecciones_H`.
- Entradas/Salidas Distribuidores (`dist_EntradasSalidas`):
- Implementado backend (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Lógica para determinar precios/recargos/porcentajes aplicables.
- Cálculo de monto y afectación de saldos de distribuidores en `cue_Saldos`.
- Auditoría en `dist_EntradasSalidas_H`.
- Correcciones de Mapeo Dapper:
- Aplicados alias explícitos en repositorios de RecargoZona, PorcPago, PorcMonCanilla, PubliSeccion,
Canilla, Distribuidor y Precio para asegurar mapeo correcto de IDs y columnas.
Frontend React:
- Recargos por Zona:
- `recargoZonaService.ts`.
- `RecargoZonaFormModal.tsx` para crear/editar períodos de recargos.
- `GestionarRecargosPublicacionPage.tsx` para listar y gestionar recargos por publicación.
- Porcentajes de Pago Distribuidores:
- `porcPagoService.ts`.
- `PorcPagoFormModal.tsx`.
- `GestionarPorcentajesPagoPage.tsx`.
- Porcentajes/Montos Pago Canillitas:
- `porcMonCanillaService.ts`.
- `PorcMonCanillaFormModal.tsx`.
- `GestionarPorcMonCanillaPage.tsx`.
- Secciones de Publicación:
- `publiSeccionService.ts`.
- `PubliSeccionFormModal.tsx`.
- `GestionarSeccionesPublicacionPage.tsx`.
- Navegación:
- Actualizadas rutas y menús para acceder a la gestión de recargos, porcentajes (dist. y canillita) y secciones desde la vista de una publicación.
- Layout:
- Uso consistente de `Box` con Flexbox en lugar de `Grid` en nuevos modales y páginas para evitar errores de tipo.
2025-05-21 14:58:52 -03:00
|
|
|
using GestionIntegral.Api.Dtos.Distribucion;
|
|
|
|
|
using GestionIntegral.Api.Models.Distribucion;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace GestionIntegral.Api.Services.Distribucion
|
|
|
|
|
{
|
|
|
|
|
public class PubliSeccionService : IPubliSeccionService
|
|
|
|
|
{
|
|
|
|
|
private readonly IPubliSeccionRepository _publiSeccionRepository;
|
|
|
|
|
private readonly IPublicacionRepository _publicacionRepository; // Para validar IdPublicacion
|
|
|
|
|
private readonly DbConnectionFactory _connectionFactory;
|
|
|
|
|
private readonly ILogger<PubliSeccionService> _logger;
|
|
|
|
|
|
|
|
|
|
public PubliSeccionService(
|
|
|
|
|
IPubliSeccionRepository publiSeccionRepository,
|
|
|
|
|
IPublicacionRepository publicacionRepository,
|
|
|
|
|
DbConnectionFactory connectionFactory,
|
|
|
|
|
ILogger<PubliSeccionService> logger)
|
|
|
|
|
{
|
|
|
|
|
_publiSeccionRepository = publiSeccionRepository;
|
|
|
|
|
_publicacionRepository = publicacionRepository;
|
|
|
|
|
_connectionFactory = connectionFactory;
|
|
|
|
|
_logger = logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PubliSeccionDto MapToDto(PubliSeccion seccion) => new PubliSeccionDto
|
|
|
|
|
{
|
|
|
|
|
IdSeccion = seccion.IdSeccion,
|
|
|
|
|
IdPublicacion = seccion.IdPublicacion,
|
|
|
|
|
Nombre = seccion.Nombre,
|
|
|
|
|
Estado = seccion.Estado
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public async Task<IEnumerable<PubliSeccionDto>> ObtenerPorPublicacionIdAsync(int idPublicacion, bool? soloActivas = null)
|
|
|
|
|
{
|
|
|
|
|
var secciones = await _publiSeccionRepository.GetByPublicacionIdAsync(idPublicacion, soloActivas);
|
|
|
|
|
return secciones.Select(MapToDto);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<PubliSeccionDto?> ObtenerPorIdAsync(int idSeccion)
|
|
|
|
|
{
|
|
|
|
|
var seccion = await _publiSeccionRepository.GetByIdAsync(idSeccion);
|
|
|
|
|
return seccion == null ? null : MapToDto(seccion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<(PubliSeccionDto? Seccion, string? Error)> CrearAsync(CreatePubliSeccionDto createDto, int idUsuario)
|
|
|
|
|
{
|
|
|
|
|
if (await _publicacionRepository.GetByIdSimpleAsync(createDto.IdPublicacion) == null)
|
|
|
|
|
return (null, "La publicación especificada no existe.");
|
|
|
|
|
if (await _publiSeccionRepository.ExistsByNameInPublicacionAsync(createDto.Nombre, createDto.IdPublicacion))
|
|
|
|
|
return (null, "Ya existe una sección con ese nombre para esta publicación.");
|
|
|
|
|
|
|
|
|
|
var nuevaSeccion = new PubliSeccion
|
|
|
|
|
{
|
|
|
|
|
IdPublicacion = createDto.IdPublicacion,
|
|
|
|
|
Nombre = createDto.Nombre,
|
|
|
|
|
Estado = createDto.Estado
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using var connection = _connectionFactory.CreateConnection();
|
|
|
|
|
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
|
|
|
|
|
using var transaction = connection.BeginTransaction();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var seccionCreada = await _publiSeccionRepository.CreateAsync(nuevaSeccion, idUsuario, transaction);
|
|
|
|
|
if (seccionCreada == null) throw new DataException("Error al crear la sección.");
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
|
|
|
|
_logger.LogInformation("Sección ID {Id} creada por Usuario ID {UserId}.", seccionCreada.IdSeccion, idUsuario);
|
|
|
|
|
return (MapToDto(seccionCreada), null);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
try { transaction.Rollback(); } catch { }
|
|
|
|
|
_logger.LogError(ex, "Error CrearAsync PubliSeccion para Pub ID {IdPub}, Nombre: {Nombre}", createDto.IdPublicacion, createDto.Nombre);
|
|
|
|
|
return (null, $"Error interno: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<(bool Exito, string? Error)> ActualizarAsync(int idSeccion, UpdatePubliSeccionDto updateDto, int idUsuario)
|
|
|
|
|
{
|
|
|
|
|
using var connection = _connectionFactory.CreateConnection();
|
|
|
|
|
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
|
|
|
|
|
using var transaction = connection.BeginTransaction();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var seccionExistente = await _publiSeccionRepository.GetByIdAsync(idSeccion); // Obtener dentro de TX
|
|
|
|
|
if (seccionExistente == null) return (false, "Sección no encontrada.");
|
|
|
|
|
|
|
|
|
|
// Validar unicidad de nombre solo si el nombre ha cambiado
|
|
|
|
|
if (seccionExistente.Nombre != updateDto.Nombre &&
|
|
|
|
|
await _publiSeccionRepository.ExistsByNameInPublicacionAsync(updateDto.Nombre, seccionExistente.IdPublicacion, idSeccion))
|
|
|
|
|
{
|
|
|
|
|
return (false, "Ya existe otra sección con ese nombre para esta publicación.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seccionExistente.Nombre = updateDto.Nombre;
|
|
|
|
|
seccionExistente.Estado = updateDto.Estado;
|
|
|
|
|
|
|
|
|
|
var actualizado = await _publiSeccionRepository.UpdateAsync(seccionExistente, idUsuario, transaction);
|
|
|
|
|
if (!actualizado) throw new DataException("Error al actualizar la sección.");
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
|
|
|
|
_logger.LogInformation("Sección ID {Id} actualizada por Usuario ID {UserId}.", idSeccion, idUsuario);
|
|
|
|
|
return (true, null);
|
|
|
|
|
}
|
|
|
|
|
catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Sección no encontrada."); }
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
try { transaction.Rollback(); } catch { }
|
|
|
|
|
_logger.LogError(ex, "Error ActualizarAsync PubliSeccion ID: {Id}", idSeccion);
|
|
|
|
|
return (false, $"Error interno: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<(bool Exito, string? Error)> EliminarAsync(int idSeccion, int idUsuario)
|
|
|
|
|
{
|
2025-06-12 19:36:21 -03:00
|
|
|
using var connection = _connectionFactory.CreateConnection();
|
feat: Implementación de Secciones, Recargos, Porc. Pago Dist. y backend E/S Dist.
Backend API:
- Recargos por Zona (`dist_RecargoZona`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/recargos`.
- Lógica de negocio para vigencias (cierre/reapertura de períodos).
- Auditoría en `dist_RecargoZona_H`.
- Porcentajes de Pago Distribuidores (`dist_PorcPago`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajespago`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcPago_H`.
- Porcentajes/Montos Pago Canillitas (`dist_PorcMonPagoCanilla`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajesmoncanilla`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcMonPagoCanilla_H`.
- Secciones de Publicación (`dist_dtPubliSecciones`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/secciones`.
- Auditoría en `dist_dtPubliSecciones_H`.
- Entradas/Salidas Distribuidores (`dist_EntradasSalidas`):
- Implementado backend (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Lógica para determinar precios/recargos/porcentajes aplicables.
- Cálculo de monto y afectación de saldos de distribuidores en `cue_Saldos`.
- Auditoría en `dist_EntradasSalidas_H`.
- Correcciones de Mapeo Dapper:
- Aplicados alias explícitos en repositorios de RecargoZona, PorcPago, PorcMonCanilla, PubliSeccion,
Canilla, Distribuidor y Precio para asegurar mapeo correcto de IDs y columnas.
Frontend React:
- Recargos por Zona:
- `recargoZonaService.ts`.
- `RecargoZonaFormModal.tsx` para crear/editar períodos de recargos.
- `GestionarRecargosPublicacionPage.tsx` para listar y gestionar recargos por publicación.
- Porcentajes de Pago Distribuidores:
- `porcPagoService.ts`.
- `PorcPagoFormModal.tsx`.
- `GestionarPorcentajesPagoPage.tsx`.
- Porcentajes/Montos Pago Canillitas:
- `porcMonCanillaService.ts`.
- `PorcMonCanillaFormModal.tsx`.
- `GestionarPorcMonCanillaPage.tsx`.
- Secciones de Publicación:
- `publiSeccionService.ts`.
- `PubliSeccionFormModal.tsx`.
- `GestionarSeccionesPublicacionPage.tsx`.
- Navegación:
- Actualizadas rutas y menús para acceder a la gestión de recargos, porcentajes (dist. y canillita) y secciones desde la vista de una publicación.
- Layout:
- Uso consistente de `Box` con Flexbox en lugar de `Grid` en nuevos modales y páginas para evitar errores de tipo.
2025-05-21 14:58:52 -03:00
|
|
|
if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
|
|
|
|
|
using var transaction = connection.BeginTransaction();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var seccionExistente = await _publiSeccionRepository.GetByIdAsync(idSeccion); // Obtener dentro de TX
|
|
|
|
|
if (seccionExistente == null) return (false, "Sección no encontrada.");
|
|
|
|
|
|
|
|
|
|
if (await _publiSeccionRepository.IsInUseAsync(idSeccion))
|
|
|
|
|
{
|
|
|
|
|
return (false, "No se puede eliminar. La sección está siendo utilizada en registros de tiradas o stock de bobinas.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var eliminado = await _publiSeccionRepository.DeleteAsync(idSeccion, idUsuario, transaction);
|
|
|
|
|
if (!eliminado) throw new DataException("Error al eliminar la sección.");
|
|
|
|
|
|
|
|
|
|
transaction.Commit();
|
|
|
|
|
_logger.LogInformation("Sección ID {Id} eliminada por Usuario ID {UserId}.", idSeccion, idUsuario);
|
|
|
|
|
return (true, null);
|
|
|
|
|
}
|
|
|
|
|
catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Sección no encontrada."); }
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
try { transaction.Rollback(); } catch { }
|
|
|
|
|
_logger.LogError(ex, "Error EliminarAsync PubliSeccion ID: {Id}", idSeccion);
|
|
|
|
|
return (false, $"Error interno: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-06-12 19:36:21 -03:00
|
|
|
|
|
|
|
|
public async Task<IEnumerable<PubliSeccionHistorialDto>> ObtenerHistorialAsync(
|
|
|
|
|
DateTime? fechaDesde, DateTime? fechaHasta,
|
|
|
|
|
int? idUsuarioModifico, string? tipoModificacion,
|
|
|
|
|
int? idSeccionAfectada, int? idPublicacionAfectada)
|
|
|
|
|
{
|
|
|
|
|
var historialData = await _publiSeccionRepository.GetHistorialAsync(fechaDesde, fechaHasta, idUsuarioModifico, tipoModificacion, idSeccionAfectada, idPublicacionAfectada);
|
|
|
|
|
|
|
|
|
|
// Si necesitas NombrePublicacion, harías la llamada a _publicacionRepository aquí.
|
|
|
|
|
return historialData.Select(h => new PubliSeccionHistorialDto
|
|
|
|
|
{
|
|
|
|
|
Id_Seccion = h.Historial.Id_Seccion,
|
|
|
|
|
Id_Publicacion = h.Historial.Id_Publicacion,
|
|
|
|
|
Nombre = h.Historial.Nombre,
|
|
|
|
|
Estado = h.Historial.Estado,
|
|
|
|
|
Id_Usuario = h.Historial.Id_Usuario,
|
|
|
|
|
NombreUsuarioModifico = h.NombreUsuarioModifico,
|
|
|
|
|
FechaMod = h.Historial.FechaMod,
|
|
|
|
|
TipoMod = h.Historial.TipoMod
|
|
|
|
|
}).ToList();
|
|
|
|
|
}
|
feat: Implementación de Secciones, Recargos, Porc. Pago Dist. y backend E/S Dist.
Backend API:
- Recargos por Zona (`dist_RecargoZona`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/recargos`.
- Lógica de negocio para vigencias (cierre/reapertura de períodos).
- Auditoría en `dist_RecargoZona_H`.
- Porcentajes de Pago Distribuidores (`dist_PorcPago`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajespago`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcPago_H`.
- Porcentajes/Montos Pago Canillitas (`dist_PorcMonPagoCanilla`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/porcentajesmoncanilla`.
- Lógica de negocio para vigencias.
- Auditoría en `dist_PorcMonPagoCanilla_H`.
- Secciones de Publicación (`dist_dtPubliSecciones`):
- CRUD completo (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Endpoints anidados bajo `/publicaciones/{idPublicacion}/secciones`.
- Auditoría en `dist_dtPubliSecciones_H`.
- Entradas/Salidas Distribuidores (`dist_EntradasSalidas`):
- Implementado backend (Modelos, DTOs, Repositorio, Servicio, Controlador).
- Lógica para determinar precios/recargos/porcentajes aplicables.
- Cálculo de monto y afectación de saldos de distribuidores en `cue_Saldos`.
- Auditoría en `dist_EntradasSalidas_H`.
- Correcciones de Mapeo Dapper:
- Aplicados alias explícitos en repositorios de RecargoZona, PorcPago, PorcMonCanilla, PubliSeccion,
Canilla, Distribuidor y Precio para asegurar mapeo correcto de IDs y columnas.
Frontend React:
- Recargos por Zona:
- `recargoZonaService.ts`.
- `RecargoZonaFormModal.tsx` para crear/editar períodos de recargos.
- `GestionarRecargosPublicacionPage.tsx` para listar y gestionar recargos por publicación.
- Porcentajes de Pago Distribuidores:
- `porcPagoService.ts`.
- `PorcPagoFormModal.tsx`.
- `GestionarPorcentajesPagoPage.tsx`.
- Porcentajes/Montos Pago Canillitas:
- `porcMonCanillaService.ts`.
- `PorcMonCanillaFormModal.tsx`.
- `GestionarPorcMonCanillaPage.tsx`.
- Secciones de Publicación:
- `publiSeccionService.ts`.
- `PubliSeccionFormModal.tsx`.
- `GestionarSeccionesPublicacionPage.tsx`.
- Navegación:
- Actualizadas rutas y menús para acceder a la gestión de recargos, porcentajes (dist. y canillita) y secciones desde la vista de una publicación.
- Layout:
- Uso consistente de `Box` con Flexbox en lugar de `Grid` en nuevos modales y páginas para evitar errores de tipo.
2025-05-21 14:58:52 -03:00
|
|
|
}
|
|
|
|
|
}
|