# Auditoria vigente del plan SmartPlus

> **Corte canónico posterior al despliegue — 2026-10-21.** Este bloque prevalece
> sobre cualquier sección histórica posterior que describa el estado anterior.
> Producción SmartPlus está en el release `134cde35`; el symlink activo
> `/var/www/html/smart` apunta a `/var/www/html/smart-release-134cde35`.
> Se aplicaron las migraciones tenant para `website_id=5` después de crear el
> respaldo identificado `20261021T004926Z-134cde35...`. FCM está instalado en el
> almacenamiento privado compartido, montado en FPM/worker/scheduler. El
> preflight pasó con disco al 88%, sin OOM reciente ni webpack activo. El APK
> release usa el proyecto Firebase de producción y fue instalado en el equipo
> físico `373ead9f`.

Estado real: el código, las migraciones de `smart_demo`, el deploy y los
healthchecks están aplicados. No se debe declarar terminado el plan completo
hasta ejecutar un pedido de prueba controlado de punta a punta: crear → asignar
→ notificar con APK cerrada/bloqueada → aceptar → ruta/GPS → entrega → cobro →
validación de Caja. También falta la evidencia runtime de apagar
`water_distributor`, configurar una campaña/presentaciones reales y probar el
ciclo físico de bidones. Las secciones con “pendiente” anteriores son
históricas si contradicen este corte.

Fecha de corte: 2026-10-20
Proyecto: SmartPlus / Eleden
Regla de activacion: reparto, bidones, seguimiento movil, puntos y configuracion especifica de presentaciones solo estan disponibles si el tenant tiene activo water_distributor.

## Objetivo consolidado

Implementar un flujo auditable para vender agua con presentaciones y reglas de puntos independientes, preparar y entregar pedidos desde el APK del repartidor, registrar cobros y evidencias para Caja, controlar bidones individuales y cerrar automaticamente la ruta, sin duplicar pedidos, cobros, puntos, movimientos, notificaciones ni ubicaciones.

Con el giro inactivo, el menu y configuracion no aparecen, el login y la API del APK responden 403, no se crean nuevos datos exclusivos de reparto y la APK detiene el rastreo y descarta la cola de ubicaciones. Los datos historicos se conservan.

## Estados

- Completado y probado: codigo, prueba automatizada y evidencia runtime suficiente.
- Implementado, prueba incompleta: existe codigo/prueba parcial, pero falta integracion, dispositivo o datos reales.
- Pendiente: falta codigo, migracion, decision comercial o evidencia.
- Fuera del codigo: requiere inventario, conciliacion, credenciales, dispositivo o decision comercial.

## Comparacion punto a punto

| Punto | Estado vigente | Evidencia actual | Falta para cerrarlo |
|---|---|---|---|
| Inventario de duplicados y saldos negativos | Fuera del codigo | El plan identifica duplicados de agua y saldos negativos | Conciliar existencias, documentos y clientes; no borrar historicos |
| Producto maestro y presentaciones | Implementado, prueba incompleta | item_unit_types, PresentationPriceResolver, reglas y PHPUnit | Crear dos presentaciones reales y validar POS |
| Listas de precio por canal/sucursal | Implementado, prueba incompleta | item_unit_type_price_rules, resolver y pruebas | Validar datos controlados y pantalla |
| Puntos por presentacion | Completado localmente | PresentationPointIntegrationServiceTest, reglas por item_unit_type_id y gate | Prueba comercial demo |
| Canje separado de acumulacion | Completado localmente | ItemUnitTypePointRuleTest, integracion y validaciones | Confirmar politica final |
| Campana de 11 puntos | Implementado, prueba incompleta | LoyaltyCampaign, ledger, redencion, reversa e idempotencia | Definir recompensa, vigencia y consumo exacto |
| Ledger, saldo y reversa | Completado localmente | PointLedgerServiceTest: bloqueo e idempotencia | Concurrencia en MariaDB |
| Snapshot historico | Completado localmente | snapshots y DeliveryOrderResourceSnapshotTest | Validar venta historica real |
| Detalle de pedido en APK | Completado por contrato | DeliveryOrderResource y presentation_contract_test.dart | Flujo web autenticado hasta APK |
| Adicional/sustitucion/faltante/devolucion | Implementado, prueba incompleta | lineas de ajuste y DeliveryAdjustmentApprovalServiceTest | Dos dispositivos, offline y aprobacion de Caja |
| Cobro efectivo | Implementado, prueba incompleta | liquidacion, monto, vuelto, offline e idempotencia | Flujo repartidor -> Caja |
| Yape/Plin con evidencia | Implementado, prueba incompleta | referencia/foto obligatorias y endpoints | Carga, visualizacion, rechazo y reintento |
| Un cobro por pedido | Completado por servicio | bloqueo e idempotencia | E2E doble clic/timeout/dos dispositivos |
| Estados y cambio de repartidor | Completado localmente | bloqueo fuera de pending y pruebas de asignacion | E2E estados terminales |
| Bidones por tipo/estado/condicion/QR | Implementado, prueba incompleta | catalogo, QR, estados y ContainerMovementServiceTest | Migracion y recorrido fisico |
| Saldo de bidones por cliente | Implementado, prueba incompleta | balances, movimientos y depositos | Conciliar saldos existentes |
| Carga y liquidacion de ruta | Implementado, prueba incompleta | RouteContainerSettlementServiceTest | E2E lleno, vacio, prestamo, venta, dano y faltante |
| Aceptar primer pedido activa ruta | Completado backend | DeliveryController::accept, auto-finisher y sin inicio manual | APK con pedido nuevo en demo |
| Cierre automatico | Completado por servicio | auto-finisher serializado | Ruta real con varios pedidos |
| GPS durante ruta | Implementado, prueba incompleta | foreground Android, cola offline y consulta de estado | Pantalla bloqueada, red intermitente y cierre |
| FCM/outbox/reintentos | Implementado, prueba incompleta | outbox, intentos y pruebas del servicio | Credencial FCM, APK cerrada/bloqueada y segundo dispositivo |
| Ubicacion para Caja | Implementado, prueba incompleta | API delivery/routes/active y recurso | Validar UI durante ruta |
| Entrega transaccional central | Implementado, prueba incompleta | DeliveryCompletionService agrupa lineas, ajustes y bidones | E2E completo; pago sigue etapa de Caja |
| Restriccion del repartidor | Completado localmente | DeliveryDriverWebRestrictionTest, API y middleware | Verificacion visual del menu |
| Gate water_distributor | Completado localmente | guard en API, web, servicios, jobs, puntos y bidones; pruebas negativas | Evidencia runtime activo/inactivo |
| Login RUC/tenant/sucursal | Implementado, prueba incompleta | DeliveryTenantController resuelve RUC y valida sucursal | Validar tenant real sin cambio de empresa |
| Direcciones multiples/coordenadas | Implementado, prueba incompleta | person_addresses, seleccion y pertenencia | Dos direcciones reales y persistencia |
| Migraciones y reversa | Completado en SQLite | TenantMigrationChainTest y reversibles | Staging controlado con backup |
| Despliegue seguro | Completado operacionalmente | flock, preflight, no-build, backup, healthchecks y rollback | Mantener prueba Linux periodica |

## Auditoría de gates por endpoint

La ruta API `api/delivery/*` usa `DeliveryController::ensureDriver()` antes de
ejecutar cada operación del repartidor. Ese método exige simultáneamente el
giro `water_distributor` activo, sesión autenticada y `delivery_driver=true`.

| Grupo | Operaciones protegidas |
|---|---|
| Pedidos | listar, aceptar, estados, entregar y sustituciones |
| Ruta/GPS | ruta actual, ubicación individual y lotes de ubicaciones |
| Cobros | registrar pago, depósitos, liquidación de efectivo y revisión |
| Bidones | opciones, búsqueda QR, asociación, carga y liquidación |
| Dispositivo | registrar/revocar FCM y registrar apertura de notificación |
| Backoffice web | middleware adicional bloquea el acceso del repartidor |

Los servicios internos también vuelven a validar el giro antes de crear
movimientos, cobrar, cerrar rutas, enviar notificaciones o procesar puntos.
Esto evita que una llamada interna omita el gate del controlador.

## Verificación SSH de solo lectura del servidor

Se verificó `root@5.161.118.178` sin ejecutar cambios:

- release activo: `/var/www/html/smart-release-91bd0e8c`;
- marcador servido: `91bd0e8c03b4dd3fb3fde8d13550ac686f238690`;
- `vendor/autoload.php` y `public/js/app.js`: presentes;
- `mariadb_smartplus`, `redis_smartplus`, `fpm_smartplus`, `worker_smartplus`,
  `scheduling_smartplus` y `nginx_smartplus`: saludables;
- `tenancy:migrate --pretend --website_id=5` mostró que aún se debe crear
  `order_note_items.item_unit_type_id`;
- `.env` referencia
  `/var/www/html/storage/app/private/firebase-service-account-production.json`,
  pero el archivo no existe;
- disco raíz: 93 %, por encima del umbral seguro de deploy.

No se ejecutó migración, backup, recreación de contenedores ni deploy. El
preflight debe continuar bloqueando hasta liberar espacio y preparar la
credencial FCM fuera del repositorio.

## Evidencia histórica de cortes anteriores

Los datos de esta sección se conservan como trazabilidad y no sustituyen el
corte vigente documentado más abajo. Las cifras y el estado runtime actual se
deben tomar de la sección `Matriz consolidada vigente por requisito`.

- PHP: php artisan test --no-coverage — 101 pruebas aprobadas, incluida la validación de actualización parcial de reglas de puntos.
- Flutter: flutter analyze — sin incidencias.
- Flutter: flutter test --no-pub — 18 pruebas aprobadas, incluidas las pruebas de normalización HTTPS.
- Playwright demo: 3 pruebas aprobadas: login, proteccion POS y sanitizacion autenticada.
- APK: ADB 373ead9f, paquete instalado, actividad presente y dispositivo desbloqueado. Tras aplicar la migración faltante, el APK release corregido inició sesión mediante RUC → credenciales y cargó dos pedidos con sus detalles.
- Bloqueador demo corregido: el tenant `smart_demo` no tenía la tabla `delivery_order_item_lines`; se respaldó y se aplicó únicamente la migración `2026_10_19_000010_tenant_create_delivery_order_item_lines.php` para `website_id=5`. El APK volvió a cargar el detalle sin el error SQL.
- APK corregido: el resolver normaliza URLs remotas `http` a `https`; el release compiló y se instaló reemplazando la versión anterior.
- Demo: release 91bd0e8c03b4dd3fb3fde8d13550ac686f238690; seis contenedores SmartPlus saludables y /login HTTP 200.
- Demo: se ejecutó únicamente la migración indicada para `smart_demo`, después del respaldo identificado.
- Demo: existe `FCM_SERVICE_ACCOUNT_FILE` en el `.env` del host, pero el archivo referido no está presente ni en el host ni en FPM; FCM con APK cerrada no se puede declarar operativo hasta instalar la credencial fuera del repositorio.

## Reglas funcionales obligatorias

### Ruta y GPS

1. Vendedor crea el pedido.
2. Vendedor/administrador asigna repartidor.
3. Outbox crea la notificacion.
4. Repartidor acepta el primer pedido.
5. Backend activa la ruta y cambia pedidos a en_route.
6. APK inicia foreground y envia ubicaciones con UUID.
7. Repartidor confirma entrega, no entrega, reprogramacion, cancelacion o rechazo; no hay iniciar/finalizar manual.
8. Backend cierra cuando todos los pedidos son terminales y los cobros aplicables estan validados o marcados como no cobrados.
9. APK detiene GPS al recibir el cierre.

### Pagos

El repartidor declara metodo y evidencia; Caja valida o rechaza. No genera comprobantes ni accede a POS, caja, clientes completos o informacion administrativa. Un reintento nunca crea un segundo cobro.

### Bidones

La entrega registra, cuando corresponda, llenos entregados, vacios recibidos, prestados, vendidos, danados o perdidos. Los movimientos son inmutables, identifican pedido/ruta/usuario/evento y no permiten saldos negativos.

### Puntos y presentaciones

Producto maestro, presentacion, precio y regla son entidades distintas. Una presentacion puede acumular, otra no, y solo una regla vigente permite canje. El snapshot conserva precio y puntos. El canje de 11 puntos no se infiere del precio ni se aplica a todas las presentaciones.

## Trabajo que falta antes de declarar el plan terminado

1. Crear dos presentaciones y una campana de 11 puntos en tenant no productivo.
2. Ejecutar web -> asignacion -> FCM -> APK -> aceptacion -> ruta -> entrega -> cobro -> Caja.
3. Repetir con APK cerrada, pantalla bloqueada, sin red y dos dispositivos.
4. Validar GPS, ultima ubicacion y cierre automatico con varios pedidos.
5. Probar Yape con foto, referencia, rechazo y reintento sin duplicar.
6. Probar bidones con QR: lleno, vacio, prestamo, venta, dano y faltante.
7. Ejecutar migraciones en staging controlado, comprobar rollback y respaldar antes de demo/produccion.
8. Probar negativamente water_distributor en UI, API, APK, jobs, GPS, pagos, puntos y bidones.
9. Configurar FCM en servidor antes de exigir notificaciones con APK cerrada.
10. Conciliar catalogo, existencias, clientes y documentos antes de consolidar duplicados.

## Criterio de cierre

Cada punto solo se marca terminado cuando tiene codigo, migracion compatible, prueba automatizada, permiso por giro y evidencia runtime del escenario descrito.

Resultado actual: base funcional implementada y probada localmente; integracion demo/dispositivo y decisiones comerciales aun pendientes.

## Corte de validacion adicional: Playwright + APK fisico

- Playwright en `https://demo.sistemax.net.pe/pos`: el listado autenticado de pedidos cargo correctamente; el endpoint de pedidos respondio HTTP 200 y no genero errores de consola.
- APK fisico `373ead9f`: inicio sesion por RUC y credenciales, cargo pedidos asignados y mostro producto, cantidad, precio, total, direccion y contacto.
- APK fisico `373ead9f`: abrir el detalle y usar retroceso regreso a `Mis pedidos` sin cerrar la aplicacion.
- APK fisico `373ead9f`: `Ruta de reparto` muestra `Ruta detenida` y explica que la ruta se inicia automaticamente al aceptar el primer pedido; no se requiere un boton manual de iniciar ruta.
- En este corte los pedidos visibles ya estaban en estado `Aceptado`, por lo que no se repitio asignacion -> notificacion -> aceptacion con un pedido nuevo. FCM con la APK cerrada sigue sin poder declararse operativo porque falta la cuenta de servicio configurada en el servidor.

## Correcciones de la auditoria continua

- Las actualizaciones parciales de reglas de puntos conservan tambien el estado persistido `active`; una regla inactiva ya no se trata erroneamente como activa.
- La APK elimina la cola offline de reparto cuando el servidor confirma que `water_distributor` esta desactivado; tambien detiene el rastreo y vacia los pedidos visibles.
- PHP: 105 pruebas aprobadas. Flutter: 17 pruebas aprobadas y `flutter analyze` sin incidencias.

## Matriz consolidada vigente por requisito

| Requisito del plan | Estado actual | Evidencia | Falta para cerrarlo |
|---|---|---|---|
| Producto maestro y presentaciones | Implementado local | migraciones, resolver, snapshots y pruebas PHP | dos presentaciones reales en demo |
| Listas de precios por canal/sucursal | Implementado local | resolver y pruebas de precedencia | validación visual y comercial en demo |
| Puntos por presentación | Implementado local | ledger, reglas, canje, reversa e idempotencia | configurar campaña real de 11 puntos |
| Canje de 11 puntos | Implementado local | campaña/recompensa validada por presentación | definir recompensa comercial y probar POS |
| Ajustes, adicionales, faltantes y devoluciones | Implementado local | líneas de entrega, aprobación e idempotencia | E2E con vendedor, repartidor y Caja |
| Efectivo, Yape, Plin y no cobrado | Implementado local | validaciones, evidencia e idempotencia | flujo real repartidor → Caja |
| No duplicar cobros | Implementado local | bloqueo transaccional y claves idempotentes | doble dispositivo y doble clic en demo |
| Estados y bloqueo de reasignación | Implementado local | transición y prueba de asignación concurrente | repetir con pedido nuevo |
| Panel web de reparto | Corregido local | se agregó filtro `Aceptados` | regenerar assets y validar en demo |
| Detalle del pedido en APK | Verificado en dispositivo | producto, cantidad, precio, total, dirección y contacto | actualizar pedido nuevo |
| Inicio automático de ruta | Implementado local / parcial runtime | código y pantalla APK sin botón manual | aceptar un pedido nuevo en dispositivo |
| GPS y cierre automático | Implementado local | servicio nativo, cola offline y auto-finisher | pantalla bloqueada, sin red y varios pedidos |
| Notificación FCM | Implementado con outbox / no operativo externo | pruebas de reintento e idempotencia | instalar cuenta de servicio en servidor |
| Ubicación visible para Caja | Implementado local | API de última ubicación y ruta | verificar pantalla web durante ruta activa |
| Bidones, QR y saldos | Implementado local | catálogo, movimientos, depósitos y liquidación | prueba física con QR y estados reales |
| Restricciones del repartidor | Implementado local | middleware, API y pruebas de permisos | comprobación visual final en demo |
| Activación por `water_distributor` | Implementado y probado local | gates en API, servicios, POS, puntos y bidones | prueba runtime con giro inactivo |
| Login RUC/tenant/sucursal | Implementado local / parcial runtime | endpoint de resolución y login APK | repetir con segundo tenant/sucursal |
| Migraciones reversibles | Implementado local | cadena tenant y pruebas de reversa | aplicar en demo con backup |
| Deploy seguro | Implementado en script | lock, preflight, no-build, healthchecks y rollback | ejecutar solo después de revisar servidor |

### Corrección de compatibilidad de esquema

`OrderNoteController` ahora conserva el flujo legacy cuando el tenant todavía
no tiene `order_note_items.item_unit_type_id` y no se seleccionó una
presentación. Si llega una presentación real sin la migración, responde 503
explicando que el esquema no está habilitado; ya no expone un error SQL 500.
Esto no activa las funciones de presentaciones: esas siguen protegidas por la
existencia de sus tablas y por el giro `water_distributor`.

## Flujo integral ejecutado en demo: resultado del corte

- Se intentó crear un pedido nuevo desde el POS con producto, cantidad, cliente,
  dirección guardada, teléfono, referencia y coordenadas. El endpoint respondió
  HTTP 200, pero el cuerpo informó `SQLSTATE[42S22]`: falta la columna
  `item_unit_type_id` en `order_note_items`. El pedido no se creó; por tanto,
  no se continuó artificialmente con asignación o cobro.
- El error corresponde a una migración tenant pendiente en `smart_demo`, no a
  FCM ni al APK. La migración existente es
  `2026_10_19_000013_tenant_add_item_unit_type_id_to_order_note_items.php`.
  Debe aplicarse con respaldo antes de repetir el flujo.
- Se verificaron los filtros del panel. `accepted` tenía pedidos reales, pero
  no existía una pestaña visible para consultarlos. Se agregó `Aceptados` al
  componente del panel; la reasignación continúa bloqueada cuando el pedido ya
  no está `pending`.
- El APK físico continúa mostrando pedidos asignados con producto, cantidad,
  precio, total, dirección y contacto. La navegación de detalle y retroceso
  pasó la prueba. La aceptación nueva, la ruta automática, el GPS y el cobro
  no se declaran E2E completos hasta corregir la migración y contar con FCM
  operativo en el servidor.

## Verificacion externa adicional 2026-10-20

- El host remoto conserva `/var/www/html/smart` apuntando al release
  `91bd0e8c03b4dd3fb3fde8d13550ac686f238690`, que coincide con el commit local
  actual.
- FPM y Nginx montan `/var/www/html/smart`; no se detecto un montaje directo a
  `smart-release-*` en esos contenedores. El Compose local queda protegido para
  mantener el mismo contrato en worker y scheduler.
- `mariadb_smartplus`, `redis_smartplus`, `fpm_smartplus`, `worker_smartplus`,
  `scheduling_smartplus` y `nginx_smartplus` estan saludables.
- El disco remoto sigue al 93 %, por encima del umbral del deploy, y el archivo
  configurado en `FCM_SERVICE_ACCOUNT_FILE` continua ausente. No se ejecuto
  deploy, migracion ni limpieza.

## Corte canónico posterior verificado — 2026-10-21

El bloque anterior es histórico. El estado actual verificado es: producción
sirve `134cde35` mediante `/var/www/html/smart`, FCM está montado desde
almacenamiento privado, las migraciones tenant de `website_id=5` fueron
aplicadas con backup previo y el disco está al 88%. El APK release fue
instalado en `373ead9f`. La implementación queda abierta únicamente por el
E2E controlado POS → APK bloqueada → GPS → entrega → cobro → Caja, la prueba
runtime del giro desactivado y la operación real de presentaciones/campaña y
bidones físicos.
