fix(auditoria): afluencia (validacion, update sin perder datos ni retroceder etapa, dedup cruzado, notas), alta cliente (registro tras firma, documentos por cliente, aviso de fallos) y reporte de clientes aplanado
This commit is contained in:
@@ -4,7 +4,18 @@ import AltaClientePage from './AltaClientePage'
|
||||
|
||||
// El lienzo de firma necesita canvas 2d (no existe en jsdom); el paso 7 se
|
||||
// prueba solo hasta la orquestación de la página, no el trazo de la firma.
|
||||
vi.mock('../forms/FirmasForm', () => ({ default: () => <div>Paso de firmas</div> }))
|
||||
// Stub del paso de firmas: expone el botón de registro (el registro del alta
|
||||
// ahora se dispara desde este paso, no al salir de Documentos)
|
||||
vi.mock('../forms/FirmasForm', () => ({
|
||||
default: ({ onRegistrar }: { onRegistrar?: () => void }) => (
|
||||
<div>
|
||||
<p>Paso de firmas</p>
|
||||
<button type="button" onClick={onRegistrar}>
|
||||
Registrar alta
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
type FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>
|
||||
|
||||
@@ -136,8 +147,11 @@ describe('AltaClientePage — guardado progresivo (etapa por etapa)', () => {
|
||||
fireEvent.change(await screen.findByLabelText(/^Proyecto/), { target: { value: 'DIAGONAL' } })
|
||||
await avanzar() // Vivienda → Documentos
|
||||
|
||||
// Documentos → Firmas: dispara el submit final del alta
|
||||
// Documentos → Firmas: ya NO registra el alta (se registra tras firmar)
|
||||
await avanzar()
|
||||
expect(llamadasA('/clientes/progreso/prog-1/completar', 'POST')).toHaveLength(0)
|
||||
// El registro se dispara con el botón del paso de firmas
|
||||
fireEvent.click(await screen.findByRole('button', { name: /Registrar alta/ }))
|
||||
await waitFor(() => expect(llamadasA('/clientes/progreso/prog-1/completar', 'POST')).toHaveLength(1))
|
||||
// NO se usó el endpoint legado
|
||||
expect(
|
||||
|
||||
@@ -115,6 +115,12 @@ export default function AltaClientePage() {
|
||||
const [registro, setRegistro] = useState<string>('')
|
||||
const [sinConexion, setSinConexion] = useState(false)
|
||||
const [errorValidacion, setErrorValidacion] = useState<string>('')
|
||||
/** Falta un documento obligatorio (p. ej. INE) al avanzar del paso Documentos */
|
||||
const [errorDocumentos, setErrorDocumentos] = useState('')
|
||||
/** Documentos que no se pudieron subir tras registrar el alta */
|
||||
const [avisoDocumentos, setAvisoDocumentos] = useState('')
|
||||
/** El alta se está registrando en el servidor */
|
||||
const [registrandoAlta, setRegistrandoAlta] = useState(false)
|
||||
|
||||
// ---------- Borradores ----------
|
||||
type Pantalla = 'cargando' | 'entrada' | 'picker' | 'afluencia' | 'wizard'
|
||||
@@ -327,15 +333,26 @@ export default function AltaClientePage() {
|
||||
// responde, el flujo continúa solo local (los PDFs se generan igual). Con
|
||||
// guardado progresivo activo se cierra por el endpoint de progreso.
|
||||
const registrarAlta = async () => {
|
||||
setRegistrandoAlta(true)
|
||||
const res = datos.progresoId
|
||||
? await completarProgreso(datos.progresoId, alta)
|
||||
: await crearAltaCliente(alta)
|
||||
toast.success("Alta de cliente completada")
|
||||
if (res.ok) {
|
||||
await subirDocumentos(res.id, alta)
|
||||
const { fallidos } = await subirDocumentos(res.id, alta)
|
||||
setRegistro(res.id)
|
||||
setSinConexion(false)
|
||||
setErrorValidacion('')
|
||||
// El alta quedó registrada, pero algunos archivos no subieron: se avisa
|
||||
// con el detalle para que el asesor los vuelva a adjuntar.
|
||||
if (fallidos.length > 0) {
|
||||
setAvisoDocumentos(
|
||||
`El alta se registró, pero no se pudieron subir ${fallidos.length} documento(s): ` +
|
||||
`${fallidos.map((f) => f.nombre).join(', ')}. Vuelve a adjuntarlos desde el expediente del cliente.`,
|
||||
)
|
||||
} else {
|
||||
setAvisoDocumentos('')
|
||||
}
|
||||
// El alta ya quedó registrada: el borrador usado ya no hace falta
|
||||
if (borradorId) {
|
||||
eliminarBorrador(borradorId).catch(() => undefined)
|
||||
@@ -350,6 +367,7 @@ export default function AltaClientePage() {
|
||||
setSinConexion(true)
|
||||
setErrorValidacion('')
|
||||
}
|
||||
setRegistrandoAlta(false)
|
||||
}
|
||||
|
||||
// Pantalla de éxito tras registrar el alta (en lugar del redirect automático a Mi día)
|
||||
@@ -559,6 +577,15 @@ export default function AltaClientePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{avisoDocumentos !== '' && (
|
||||
<p
|
||||
role="alert"
|
||||
className="mt-4 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-xs text-amber-800"
|
||||
>
|
||||
{avisoDocumentos}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="mt-6 flex flex-col gap-3 sm:flex-row sm:flex-wrap">
|
||||
<button
|
||||
type="button"
|
||||
@@ -747,6 +774,14 @@ export default function AltaClientePage() {
|
||||
)}
|
||||
{paso === 6 && (
|
||||
<>
|
||||
{errorDocumentos !== '' && (
|
||||
<p
|
||||
role="alert"
|
||||
className="mb-6 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-xs text-amber-700"
|
||||
>
|
||||
{errorDocumentos}
|
||||
</p>
|
||||
)}
|
||||
{cargoDeBorrador && (
|
||||
<p
|
||||
role="note"
|
||||
@@ -767,7 +802,14 @@ export default function AltaClientePage() {
|
||||
}
|
||||
onAnterior={anterior}
|
||||
onSiguiente={() => {
|
||||
void registrarAlta()
|
||||
// La INE es obligatoria en el expediente: se avisa al pasar
|
||||
// de paso (el asesor puede adjuntarla después o por la liga
|
||||
// de firma), y el paso de firmas muestra lo que falte.
|
||||
setErrorDocumentos(
|
||||
alta.documentos.some((d) => d.slot === 'INE')
|
||||
? ''
|
||||
: 'Recuerda adjuntar la INE del cliente: es un documento obligatorio del expediente.',
|
||||
)
|
||||
siguiente()
|
||||
guardarAvance(datos, paso + 1)
|
||||
}}
|
||||
@@ -804,6 +846,8 @@ export default function AltaClientePage() {
|
||||
alta={alta}
|
||||
onCambiarFirma={(f) => actualizar('firma', f)}
|
||||
onAnterior={anterior}
|
||||
onRegistrar={() => void registrarAlta()}
|
||||
registrando={registrandoAlta}
|
||||
/>
|
||||
</TarjetaPaso>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user