Fix: Fechas de Estado Bobinas
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 14m8s
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 14m8s
- Las fechas de estado de las bobinas no pueden ser anterior a la fecha de remito (ingreso).
This commit is contained in:
@@ -199,13 +199,21 @@ namespace GestionIntegral.Api.Services.Impresion
|
|||||||
using var transaction = connection.BeginTransaction();
|
using var transaction = connection.BeginTransaction();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var bobina = await _stockBobinaRepository.GetByIdAsync(idBobina); // Obtener dentro de la transacción
|
var bobina = await _stockBobinaRepository.GetByIdAsync(idBobina);
|
||||||
if (bobina == null)
|
if (bobina == null)
|
||||||
{
|
{
|
||||||
try { transaction.Rollback(); } catch { }
|
try { transaction.Rollback(); } catch { }
|
||||||
return (false, "Bobina no encontrada.");
|
return (false, "Bobina no encontrada.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comparamos solo las fechas (sin hora) para evitar problemas de precisión.
|
||||||
|
if (cambiarEstadoDto.FechaCambioEstado.Date < bobina.FechaRemito.Date)
|
||||||
|
{
|
||||||
|
try { transaction.Rollback(); } catch { }
|
||||||
|
return (false, $"Error de integridad: La fecha del nuevo estado ({cambiarEstadoDto.FechaCambioEstado:dd/MM/yyyy}) " +
|
||||||
|
$"no puede ser anterior a la fecha de ingreso por remito ({bobina.FechaRemito:dd/MM/yyyy}).");
|
||||||
|
}
|
||||||
|
|
||||||
var nuevoEstado = await _estadoBobinaRepository.GetByIdAsync(cambiarEstadoDto.NuevoEstadoId);
|
var nuevoEstado = await _estadoBobinaRepository.GetByIdAsync(cambiarEstadoDto.NuevoEstadoId);
|
||||||
if (nuevoEstado == null)
|
if (nuevoEstado == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import type { StockBobinaDto } from '../../../models/dtos/Impresion/StockBobinaDto';
|
import type { StockBobinaDto } from '../../../models/dtos/Impresion/StockBobinaDto';
|
||||||
import type { CambiarEstadoBobinaDto } from '../../../models/dtos/Impresion/CambiarEstadoBobinaDto';
|
import type { CambiarEstadoBobinaDto } from '../../../models/dtos/Impresion/CambiarEstadoBobinaDto';
|
||||||
import type { EstadoBobinaDto } from '../../../models/dtos/Impresion/EstadoBobinaDto';
|
import type { EstadoBobinaDto } from '../../../models/dtos/Impresion/EstadoBobinaDto';
|
||||||
// --- CAMBIO: Importar PublicacionDropdownDto ---
|
|
||||||
import type { PublicacionDropdownDto } from '../../../models/dtos/Distribucion/PublicacionDropdownDto';
|
import type { PublicacionDropdownDto } from '../../../models/dtos/Distribucion/PublicacionDropdownDto';
|
||||||
import type { PubliSeccionDto } from '../../../models/dtos/Distribucion/PubliSeccionDto';
|
import type { PubliSeccionDto } from '../../../models/dtos/Distribucion/PubliSeccionDto';
|
||||||
import estadoBobinaService from '../../../services/Impresion/estadoBobinaService';
|
import estadoBobinaService from '../../../services/Impresion/estadoBobinaService';
|
||||||
@@ -56,7 +55,6 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
const [fechaCambioEstado, setFechaCambioEstado] = useState('');
|
const [fechaCambioEstado, setFechaCambioEstado] = useState('');
|
||||||
|
|
||||||
const [estadosDisponibles, setEstadosDisponibles] = useState<EstadoBobinaDto[]>([]);
|
const [estadosDisponibles, setEstadosDisponibles] = useState<EstadoBobinaDto[]>([]);
|
||||||
// --- CAMBIO: Usar PublicacionDropdownDto para el estado ---
|
|
||||||
const [publicacionesDisponibles, setPublicacionesDisponibles] = useState<PublicacionDropdownDto[]>([]);
|
const [publicacionesDisponibles, setPublicacionesDisponibles] = useState<PublicacionDropdownDto[]>([]);
|
||||||
const [seccionesDisponibles, setSeccionesDisponibles] = useState<PubliSeccionDto[]>([]);
|
const [seccionesDisponibles, setSeccionesDisponibles] = useState<PubliSeccionDto[]>([]);
|
||||||
|
|
||||||
@@ -77,7 +75,6 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
} else if (bobinaActual.idEstadoBobina === ID_ESTADO_EN_USO) {
|
} else if (bobinaActual.idEstadoBobina === ID_ESTADO_EN_USO) {
|
||||||
estadosFiltrados = todosLosEstados.filter(e => e.idEstadoBobina === ID_ESTADO_DANADA);
|
estadosFiltrados = todosLosEstados.filter(e => e.idEstadoBobina === ID_ESTADO_DANADA);
|
||||||
} else if (bobinaActual.idEstadoBobina === ID_ESTADO_DISPONIBLE) {
|
} else if (bobinaActual.idEstadoBobina === ID_ESTADO_DISPONIBLE) {
|
||||||
// --- CAMBIO: Usar ID_ESTADO_EN_USO ---
|
|
||||||
estadosFiltrados = todosLosEstados.filter(
|
estadosFiltrados = todosLosEstados.filter(
|
||||||
e => e.idEstadoBobina === ID_ESTADO_EN_USO || e.idEstadoBobina === ID_ESTADO_DANADA
|
e => e.idEstadoBobina === ID_ESTADO_EN_USO || e.idEstadoBobina === ID_ESTADO_DANADA
|
||||||
);
|
);
|
||||||
@@ -90,7 +87,6 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
const sePuedePonerEnUso = estadosFiltrados.some(e => e.idEstadoBobina === ID_ESTADO_EN_USO);
|
const sePuedePonerEnUso = estadosFiltrados.some(e => e.idEstadoBobina === ID_ESTADO_EN_USO);
|
||||||
|
|
||||||
if (sePuedePonerEnUso) {
|
if (sePuedePonerEnUso) {
|
||||||
// --- CAMBIO: La data es PublicacionDropdownDto[] ---
|
|
||||||
const publicacionesData: PublicacionDropdownDto[] = await publicacionService.getPublicacionesForDropdown(true);
|
const publicacionesData: PublicacionDropdownDto[] = await publicacionService.getPublicacionesForDropdown(true);
|
||||||
setPublicacionesDisponibles(publicacionesData);
|
setPublicacionesDisponibles(publicacionesData);
|
||||||
} else {
|
} else {
|
||||||
@@ -101,7 +97,7 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error al cargar datos para dropdowns (Cambio Estado Bobina)", error);
|
console.error("Error al cargar datos para dropdowns (Cambio Estado Bobina)", error);
|
||||||
setLocalErrors(prev => ({...prev, dropdowns: 'Error al cargar datos necesarios.'}));
|
setLocalErrors(prev => ({ ...prev, dropdowns: 'Error al cargar datos necesarios.' }));
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingDropdowns(false);
|
setLoadingDropdowns(false);
|
||||||
}
|
}
|
||||||
@@ -140,7 +136,7 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
setSeccionesDisponibles(data);
|
setSeccionesDisponibles(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error al cargar secciones:", error);
|
console.error("Error al cargar secciones:", error);
|
||||||
setLocalErrors(prev => ({ ...prev, secciones: 'Error al cargar secciones.'}));
|
setLocalErrors(prev => ({ ...prev, secciones: 'Error al cargar secciones.' }));
|
||||||
setSeccionesDisponibles([]);
|
setSeccionesDisponibles([]);
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingDropdowns(false);
|
setLoadingDropdowns(false);
|
||||||
@@ -170,8 +166,16 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
const validate = (): boolean => {
|
const validate = (): boolean => {
|
||||||
const errors: { [key: string]: string | null } = {};
|
const errors: { [key: string]: string | null } = {};
|
||||||
if (!nuevoEstadoId) errors.nuevoEstadoId = 'Seleccione un nuevo estado.';
|
if (!nuevoEstadoId) errors.nuevoEstadoId = 'Seleccione un nuevo estado.';
|
||||||
if (!fechaCambioEstado.trim()) errors.fechaCambioEstado = 'La fecha es obligatoria.';
|
if (!fechaCambioEstado.trim()) {
|
||||||
else if (!/^\d{4}-\d{2}-\d{2}$/.test(fechaCambioEstado)) errors.fechaCambioEstado = 'Formato de fecha inválido.';
|
errors.fechaCambioEstado = 'La fecha es obligatoria.';
|
||||||
|
} else if (!/^\d{4}-\d{2}-\d{2}$/.test(fechaCambioEstado)) {
|
||||||
|
errors.fechaCambioEstado = 'Formato de fecha inválido.';
|
||||||
|
} else if (bobinaActual) {
|
||||||
|
const fechaRemitoSimple = bobinaActual.fechaRemito.split('T')[0];
|
||||||
|
if (fechaCambioEstado < fechaRemitoSimple) {
|
||||||
|
errors.fechaCambioEstado = `La fecha no puede ser anterior al ingreso (${fechaRemitoSimple}).`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Number(nuevoEstadoId) === ID_ESTADO_EN_USO) {
|
if (Number(nuevoEstadoId) === ID_ESTADO_EN_USO) {
|
||||||
if (!idPublicacion) errors.idPublicacion = 'Seleccione una publicación.';
|
if (!idPublicacion) errors.idPublicacion = 'Seleccione una publicación.';
|
||||||
@@ -251,7 +255,7 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
<FormControl fullWidth margin="dense" error={!!localErrors.idPublicacion} required>
|
<FormControl fullWidth margin="dense" error={!!localErrors.idPublicacion} required>
|
||||||
<InputLabel id="publicacion-estado-select-label">Publicación</InputLabel>
|
<InputLabel id="publicacion-estado-select-label">Publicación</InputLabel>
|
||||||
<Select labelId="publicacion-estado-select-label" label="Publicación" value={idPublicacion}
|
<Select labelId="publicacion-estado-select-label" label="Publicación" value={idPublicacion}
|
||||||
onChange={(e) => {setIdPublicacion(e.target.value as number); handleInputChange('idPublicacion');}}
|
onChange={(e) => { setIdPublicacion(e.target.value as number); handleInputChange('idPublicacion'); }}
|
||||||
disabled={loading || loadingDropdowns || publicacionesDisponibles.length === 0}
|
disabled={loading || loadingDropdowns || publicacionesDisponibles.length === 0}
|
||||||
>
|
>
|
||||||
<MenuItem value="" disabled><em>Seleccione publicación</em></MenuItem>
|
<MenuItem value="" disabled><em>Seleccione publicación</em></MenuItem>
|
||||||
@@ -262,22 +266,33 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
<FormControl fullWidth margin="dense" error={!!localErrors.idSeccion} required>
|
<FormControl fullWidth margin="dense" error={!!localErrors.idSeccion} required>
|
||||||
<InputLabel id="seccion-estado-select-label">Sección</InputLabel>
|
<InputLabel id="seccion-estado-select-label">Sección</InputLabel>
|
||||||
<Select labelId="seccion-estado-select-label" label="Sección" value={idSeccion}
|
<Select labelId="seccion-estado-select-label" label="Sección" value={idSeccion}
|
||||||
onChange={(e) => {setIdSeccion(e.target.value as number); handleInputChange('idSeccion');}}
|
onChange={(e) => { setIdSeccion(e.target.value as number); handleInputChange('idSeccion'); }}
|
||||||
disabled={loading || loadingDropdowns || !idPublicacion || seccionesDisponibles.length === 0}
|
disabled={loading || loadingDropdowns || !idPublicacion || seccionesDisponibles.length === 0}
|
||||||
>
|
>
|
||||||
<MenuItem value="" disabled><em>{idPublicacion ? (seccionesDisponibles.length > 0 ? 'Seleccione sección' : 'No hay secciones para esta pub.') : 'Seleccione publicación primero'}</em></MenuItem>
|
<MenuItem value="" disabled><em>{idPublicacion ? (seccionesDisponibles.length > 0 ? 'Seleccione sección' : 'No hay secciones para esta pub.') : 'Seleccione publicación primero'}</em></MenuItem>
|
||||||
{seccionesDisponibles.map((s) => (<MenuItem key={s.idSeccion} value={s.idSeccion}>{s.nombre}</MenuItem>))}
|
{seccionesDisponibles.map((s) => (<MenuItem key={s.idSeccion} value={s.idSeccion}>{s.nombre}</MenuItem>))}
|
||||||
</Select>
|
</Select>
|
||||||
{localErrors.idSeccion && <Typography color="error" variant="caption">{localErrors.idSeccion}</Typography>}
|
{localErrors.idSeccion && <Typography color="error" variant="caption">{localErrors.idSeccion}</Typography>}
|
||||||
{localErrors.secciones && <Alert severity="warning" sx={{mt:0.5}}>{localErrors.secciones}</Alert>}
|
{localErrors.secciones && <Alert severity="warning" sx={{ mt: 0.5 }}>{localErrors.secciones}</Alert>}
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TextField label="Fecha Cambio de Estado" type="date" value={fechaCambioEstado} required
|
<TextField
|
||||||
onChange={(e) => {setFechaCambioEstado(e.target.value); handleInputChange('fechaCambioEstado');}}
|
label="Fecha Cambio de Estado"
|
||||||
margin="dense" fullWidth error={!!localErrors.fechaCambioEstado} helperText={localErrors.fechaCambioEstado || ''}
|
type="date"
|
||||||
disabled={loading} InputLabelProps={{ shrink: true }}
|
value={fechaCambioEstado}
|
||||||
|
required
|
||||||
|
onChange={(e) => { setFechaCambioEstado(e.target.value); handleInputChange('fechaCambioEstado'); }}
|
||||||
|
margin="dense"
|
||||||
|
fullWidth
|
||||||
|
error={!!localErrors.fechaCambioEstado}
|
||||||
|
helperText={localErrors.fechaCambioEstado || ''}
|
||||||
|
disabled={loading}
|
||||||
|
InputLabelProps={{ shrink: true }}
|
||||||
|
inputProps={{
|
||||||
|
min: bobinaActual?.fechaRemito.split('T')[0]
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<TextField label="Observaciones (Opcional)" value={obs}
|
<TextField label="Observaciones (Opcional)" value={obs}
|
||||||
onChange={(e) => setObs(e.target.value)}
|
onChange={(e) => setObs(e.target.value)}
|
||||||
@@ -291,7 +306,7 @@ const StockBobinaCambioEstadoModal: React.FC<StockBobinaCambioEstadoModalProps>
|
|||||||
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
|
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'flex-end', gap: 1 }}>
|
||||||
<Button onClick={onClose} color="secondary" disabled={loading}>Cancelar</Button>
|
<Button onClick={onClose} color="secondary" disabled={loading}>Cancelar</Button>
|
||||||
<Button type="submit" variant="contained"
|
<Button type="submit" variant="contained"
|
||||||
disabled={loading || loadingDropdowns || (estadosDisponibles.length === 0 && bobinaActual.idEstadoBobina === ID_ESTADO_EN_USO) }>
|
disabled={loading || loadingDropdowns || (estadosDisponibles.length === 0 && bobinaActual.idEstadoBobina === ID_ESTADO_EN_USO)}>
|
||||||
{loading ? <CircularProgress size={24} /> : 'Guardar Cambio de Estado'}
|
{loading ? <CircularProgress size={24} /> : 'Guardar Cambio de Estado'}
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
Reference in New Issue
Block a user