feat: incorporar eCMR y mercancias desde 7fbfd30
Traslada los cambios de 7fbfd300b4ea17212c04528145d366a3f00b91e5 conservando la configuracion de entorno de produccion.
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# Consulta y firma eCMR desde la app
|
||||
|
||||
`GET /api/trips/:id/ecmr`
|
||||
|
||||
Enviar `Authorization: Bearer <token de login>` con la sesión de la app.
|
||||
La respuesta contiene únicamente documentos activos con PDF generado de los
|
||||
tramos cuyo DNI coincide con el conductor autenticado.
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"id_documento": 7,
|
||||
"n_proveedor": 2,
|
||||
"numero": "ECMR-123",
|
||||
"version": 1,
|
||||
"estado": "emitido",
|
||||
"fecha_creacion": "2026-09-16 10:00:00",
|
||||
"document_url": "https://<erp>/adm/pages/logic/ecmr/documento.php?t=<token-publico>",
|
||||
"firma_carga_completada": false,
|
||||
"firma_descarga_completada": false,
|
||||
"firma_carga_url": "https://<erp>/adm/pages/logic/ecmr/firmar.php?t=<token-carga>",
|
||||
"firma_descarga_url": "https://<erp>/adm/pages/logic/ecmr/firmar.php?t=<token-descarga>",
|
||||
"firma_expira_en_segundos": 900
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Integración React / React Native
|
||||
|
||||
En el detalle del viaje, consultar esta ruta y mostrar:
|
||||
|
||||
- «Ver eCMR»: abrir `document_url` mediante el visor PDF de la app.
|
||||
- «Firmar carga»: abrir `firma_carga_url` en el navegador seguro o WebView con
|
||||
soporte HTTPS y WebCrypto. Si es `null`, mostrar «Carga firmada».
|
||||
- «Firmar descarga»: abrir `firma_descarga_url` de la misma manera. Si es `null`,
|
||||
mostrar «Descarga firmada».
|
||||
|
||||
Los enlaces son independientes por documento y rol. Después de volver de la
|
||||
pantalla de firma, consultar de nuevo la ruta para refrescar el estado. Los
|
||||
campos `firma_*_completada` son booleanos; no inferir las firmas a partir del
|
||||
estado general del viaje.
|
||||
|
||||
Las URLs de firma duran 15 minutos desde su emisión. Volver a consultar cuando
|
||||
caduquen. Cada consulta crea invitaciones temporales para los roles pendientes:
|
||||
no usar sondeo periódico ni precarga masiva. La respuesta lleva `no-store`.
|
||||
No persistir ni registrar enlaces, y no enviar el Bearer de la app a las URLs
|
||||
PHP. El token del enlace es la credencial temporal, no un parámetro `skip_otp`.
|
||||
|
||||
La pantalla PHP valida el acceso emitido por Node, comprueba que el conductor
|
||||
continúa asignado al tramo y omite el código de seis cifras. El DNI procede de
|
||||
la sesión y no se puede cambiar. Se mantienen nombre, consentimiento y firma
|
||||
criptográfica. Las invitaciones de correo/WhatsApp conservan su OTP.
|
||||
Tras firmar carga desde la app, se consulta la app para acceder a la firma de
|
||||
descarga; no se envía un correo o WhatsApp automático en este canal.
|
||||
|
||||
Si `data` está vacío, mostrar «Este viaje todavía no tiene eCMR disponible».
|
||||
El PDF se entrega como `attachment`; abrirlo en un navegador puede descargarlo.
|
||||
|
||||
Errores: 401 sin sesión/DNI, 404 identificador inválido o viaje inexistente,
|
||||
403 conductor no asignado, 500 error de base de datos/invitaciones. No mostrar
|
||||
los errores como ausencia de documentos. Un enlace PHP caducado o cuyo tramo
|
||||
ya no está asignado devuelve 403 y pide volver a abrirlo desde la app.
|
||||
|
||||
## Requisitos
|
||||
|
||||
- Node y PHP deben usar las mismas tablas `ecmr_documentos`, `ecmr_invitaciones`,
|
||||
`ecmr_firmas` y `c_viajes_proveedor`.
|
||||
- Desplegar también `firma_app.php`, los cambios de `firma_api.php`, `firmar.php`,
|
||||
`common.php` y las traducciones ES/EN del ERP.
|
||||
- `public_url` debe apuntar al ERP actualizado y ser accesible mediante HTTPS.
|
||||
- No requiere nuevas columnas ni migraciones para los enlaces de firma.
|
||||
- No se ha facilitado el código React; queda pendiente conectar sus botones.
|
||||
|
||||
## Validación
|
||||
|
||||
- 40 pruebas Node: consulta eCMR, autorización, enlaces por rol, rollback y
|
||||
regresión de listado, viaje activo y puntos intermedios.
|
||||
- 27 comprobaciones PHP: DNI, caducidad, asignación, OTP y traducciones.
|
||||
- Prueba del JavaScript de firma para sesiones app y enlaces con OTP.
|
||||
- Consultas SQL reales e invitación temporal verificadas en desarrollo mediante
|
||||
una transacción revertida. No se ha firmado ningún documento real.
|
||||
|
||||
## QR del PDF DeCA / eCMR
|
||||
|
||||
`GET /api/trips/:id/ecmr/:documentId/qr`
|
||||
|
||||
Usar el mismo `Authorization: Bearer <token de login>` y el `id_documento`
|
||||
obtenido en la consulta eCMR del viaje. Se especifica el documento porque un
|
||||
viaje puede tener varios tramos y versiones.
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"id_documento": 7,
|
||||
"n_proveedor": 2,
|
||||
"numero": "ECMR-123",
|
||||
"version": 1,
|
||||
"document_url": "https://<erp>/adm/pages/logic/ecmr/documento.php?t=<token-publico>",
|
||||
"qr_data_url": "data:image/png;base64,..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
La imagen PNG es de 320 × 320 píxeles y codifica exactamente `document_url`,
|
||||
la URL del PDF usada por el QR del documento. No codifica un enlace de firma.
|
||||
En React Native puede mostrarse con:
|
||||
|
||||
```jsx
|
||||
<Image source={{ uri: data.qr_data_url }} style={{ width: 240, height: 240 }} />
|
||||
```
|
||||
|
||||
Solo devuelve documentos activos con PDF generado y del tramo asignado al DNI
|
||||
de la sesión. Responde `401` sin sesión/DNI y `404` si los identificadores no son
|
||||
válidos, el documento no existe, pertenece a otro viaje/conductor, está sustituido
|
||||
o no tiene PDF generado. El `404` evita revelar documentos ajenos. Los fallos de
|
||||
BD o generación del QR devuelven `500` con un mensaje genérico.
|
||||
|
||||
La respuesta lleva `Cache-Control: no-store`. Esta consulta no crea invitaciones,
|
||||
no modifica la BD ni envía mensajes; se puede usar para actualizar la imagen sin
|
||||
renovar enlaces de firma. Al sustituirse una versión, volver a consultar los
|
||||
documentos del viaje y utilizar el nuevo identificador. El QR contiene un enlace
|
||||
público al PDF: no registrarlo en logs ni analítica.
|
||||
|
||||
Despliegue: instalar las dependencias del lockfile (`npm ci --omit=dev`) y
|
||||
reiniciar el proceso Node según el procedimiento habitual. Se añade `qrcode`
|
||||
1.5.4. No requiere migraciones de BD ni cambios en PHP.
|
||||
|
||||
Pruebas: `node --test test/trips.ecmr.integration.test.js` cubre autenticación,
|
||||
identificadores, filtrado por tramo/conductor, ausencia de documentos, PNG real,
|
||||
URL codificada, errores de BD/generador y regresión del flujo de firma.
|
||||
Reference in New Issue
Block a user