Files
ABIANAPP_NODE_PRODUCCION/ECMR_API_APP_GUIDE.md
T
roganet dc545c9d86 feat: incorporar eCMR y mercancias desde 7fbfd30
Traslada los cambios de 7fbfd300b4ea17212c04528145d366a3f00b91e5 conservando la configuracion de entorno de produccion.
2026-09-29 13:32:12 +02:00

5.8 KiB
Raw Blame History

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.

{
  "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.

{
  "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:

<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.