Ir al contenido

Tractores

Generada 2026-08-13. Actualizada 2026-08-13 (misma fecha, sesión posterior) con exploración interactiva completa en vivo (kimi webbridge: filtros, panel de detalle, sub-reportes) — se encontraron 3 bugs reproducibles, ver sección “Bugs / hallazgos encontrados”. Fuente: exploración de código de controlgmg-v2 + observación manual del navegador (QA). Comparar contra remolques.md — Tractores es casi un gemelo estructural de Remolques, pero con una diferencia importante en la llave de identidad usada por el sync AS400 (ver abajo).

  • Modelo: App\Core\Unit (app/Core/Unit.php), tabla units. En UI/negocio se llama “Tractor” (getModelTitleAttribute() devuelve literalmente 'Tractor'; getActionUrlAttribute() apunta a /tractores?unit_id=...).
  • Fillable clave: code, name, fleet_code, fleet_name, user_id, unit_brand_id, unit_model_id, unit_engine_id.
  • Llave de identidad para sync AS400: (units.code, company.code) — ver Unit::createOrFindFromAS400(). No incluye ningún campo tipo “owner”/propietario (a diferencia de Trailer, que usa (company_id, code, trailer_owner_id)).
  • Estado/situación: vive en relación last_movement (App\Core\Unit\UnitLastMovement, hasOne), que a su vez referencia unit_situation_id (FK a UnitSituation) y movement_at. current_situation() es un hasOneThrough sobre UnitLastMovement. hidden (baja AS400, boolean) es distinto de deleted_at (soft delete de Eloquent).
  • Prioridad: columna priority en units (se resetea a null cuando cambia la situación, ver syncLastMovement).
  • Sync status: vía SynchronizableTrait (tabla polimórfica synchronizations), igual patrón que Trailer.
  • Historial de movimientos: App\Core\Unit\UnitMovementHistory (unit_movement_history() hasMany), análogo a TrailerMovementHistory. Cada cambio de situación real crea una fila y cierra (finished_at) la anterior.
  • getModule() devuelve Module::tractor — el módulo de negocio para reglas/eventos se llama “tractor” internamente, aunque el modelo Eloquent es Unit.
  • No comparte el bug GMG-3084. La causa raíz de GMG-3084 en Trailer es que firstOrCreate usa una llave compuesta que incluye trailer_owner_id (propietario), y un cambio de propietario reportado por AS400 hace que Eloquent no encuentre la fila existente y cree una nueva (“duplicidad por cambio de dueño”).
  • En Unit::createOrFindFromAS400(Tractor $tractor) (app/Core/Unit.php:118-134) la búsqueda es:
    self::where('units.code', trim($tranum))
    ->whereJoin('company.code', '=', $tractor->traemp)
    ->withTrashed()
    ->first();
    Es decir, solo (code, company) — no hay una dimensión “propietario” mutable en la llave, porque conceptualmente un tractor (unidad propia de GMG) no cambia de “dueño” como sí lo hace un remolque de terceros. Si se encuentra, se actualiza (updateAs400Unit / syncUnitAndTractor); si no, se crea. No hay patrón firstOrCreate con llave de 3+ columnas.
  • Riesgo residual distinto (no confirmado como bug, solo observación de código): si un tractor cambia de company en AS400 (traemp), la búsqueda por (code, company_nueva) no encontrará la fila existente (que tiene company_vieja) y createFromAS400 creará una fila nueva — un mecanismo de duplicidad potencialmente análogo pero disparado por cambio de empresa, no de propietario. No hay evidencia en el código de que esto ocurra en la práctica (los tractores probablemente no cambian de empresa con frecuencia, al contrario que el propietario de un remolque rentado/subcontratado). Por verificar: no se encontró un ticket equivalente a GMG-3084 para tractores; no se corrió ninguna query de regresión contra la BD.
  • Sync manual: GET /units/sync/{unit} → UnitController@sync (ruta en routes/units/unit.php:9), análogo a GET /units/trailer/sync/{trailer}.
  • Sync masivo: UnitSyncService::sync() (app/AS400/Ein00dat/AS400Sync/Unit/UnitSyncService.php), gateado por isVPNConnected() — igual que Trailer, no disparable de forma realista desde el tester.
  • Conclusión para testing: Tractores usa un patrón de sync estructuralmente más simple/seguro que Remolques (llave de 2 columnas sin dimensión de propietario), por lo que no debería sufrir el mismo tipo de duplicidad que GMG-3084 bajo el mecanismo actual. No se descarta un bug análogo por cambio de compañía, pero no hay evidencia ni reporte que lo confirme — tratar como hipótesis no verificada, no como hallazgo.

Bajo /units (grupo auth:api + password_expired), archivo routes/units/unit.php:

Método Ruta Acción
GET /units, /units/paginated, /units/with-trashed listado
GET /units/sync/{unit} sync manual de un tractor
GET /units/codes catálogo de códigos
PUT /units/executive/{unit} Units\UpdateUnitExecutiveController (usuario ejecutivo)
POST /units/{unit}/comment comentario
GET /units/{unit}/history, /{unit}/download-history, /{unit}/kilometer-history, /{unit}/arquimedes-kilometer-history historiales
PUT /units/{unit}/properties propiedades (marca/modelo/motor)
POST /units/{unit}/restore restaurar soft-delete

Reportes/KPI (routes/units/reports.php, prefijo probable /units/report o similar, controller Units\ReportsController): GET /situations, /situations-units, /situations-chart-info, /situations-histories, /situations-histories-chart-info, /situations-his-units, /situation-totals, POST /situations-his-units-excel.

No se encontró un archivo tractor.php — el hermano directo de trailer.php es unit.php (nombre del modelo, no del dominio de negocio), y el reporte de KPIs vive separado en reports.php (compartido conceptualmente con Situations/SituationHistories, no exclusivo de tractores por nombre de archivo aunque sí por contenido).

  • Ruta /tractores → resources/js/components/Catalogs/Units/Reports/UnitsReport.vue (guard can('view-unit-reports'), definido en resources/js/routes.js). Nótese la carpeta: Catalogs/Units/Reports, no Units/Reports — distinto al patrón Trailer/Reports de Remolques.
  • UnitRow.vue (misma carpeta) — una fila de la lista: código (unit.code), prioridad, vales (unit.vouchers.length), último movimiento, días transcurridos, situación (unit.last_movement.unit_situation.name), sync-status (<sync-model-status>), descarga de historial. Estructura muy similar a TrailerRow.vue.
  • UnitReportDetail.vue + UnitAs400Data.vue (en Catalogs/Units/) + UnitMovementHistory.vue (Catalogs/Units/Reports/) — panel de detalle expandido, análogo a TrailerReportDetail.vue + TrailerAs400Data.vue
    • TrailerMovementHistory.vue.
  • Sub-reportes KPI: Situations/SituationsKpi.vue, SituationHistories/SituationHistoriesKpi.vue (rutas /tractores/reportes/situaciones y /tractores/reportes/historial-situaciones, guard can('view-unit-sub-reports')).
  • Filtros usados en UnitsReport.vue, verificados en vivo en QA 2026-08-13 (navegación real con kimi webbridge, no solo lectura de código):
    • Búsqueda global (Buscar en cualquier campo...).
    • Checkboxes: Sin liquidaciones, Sin vales, Con usuario ejecutivo, Alerta por regla de negocio.
    • Rango de fechas (Fecha inicial - Fecha final).
    • Flota (select, catálogo confirmado: 2 - Autos Utilitarios, 3 - Locales MTY, 4 - NLD-GDL, 6 - NLD-MTY, 7 - NLD-MEX, 8 - Intermodal MEX, 9 - Intermodal GDL).
    • Situaciones (select múltiple, catálogo largo con conteo inline, ej. ACCIDENTADO - 12, CONDUCTOR AUSENTE - 98, BAJA - 41, etc. — decenas de valores).
    • Oficina (select, catálogo confirmado con una métrica numérica junto a cada oficina — 3195 - OFC. MTY, 588 - OFC. MEX, 141 - OFC. NLD, 3188 - OFC. GDL, 13525 - OFC. AGS, 14554 - OFC. SLP; por verificar qué representa el número, probablemente Kms acumulados).
    • Cliente que Paga, Cliente Remitente, Cliente Destinatario (tres selects tipo “Seleccionar”).
    • Prioridad (select) — BUG encontrado, ver sección “Bugs/hallazgos” abajo: nunca muestra opciones.
    • Usuario Ejecutivo (select) — confirmado funcional, catálogo de nombres de usuarios (AGUSTÍN ROBLEDO, Dora Hernandez, Aparicio Gaona, etc.), respaldado por GET /users/by-module/12 y GET /users/assigned-to-units (ambos responden con datos).
    • Botón “borrar” (limpia todos los filtros).
  • Servicio dedicado: no se confirmó el nombre exacto del archivo, pero la app llama GET /units/paginated?page=N&search=&without_voucher=&without_operation=&active=false&with_position=true&with_operations_and_vouchers=true&with_executive_user=false (paginado, 40 registros por página), GET /units/situation (catálogo de situaciones) y GET /modules/tractor/last-sync (barra de sync). No existe ninguna llamada de red para un catálogo de prioridades — confirmado con captura de tráfico completa en carga de página (ver bug).

Panel de detalle expandido (fila) — verificado en vivo 2026-08-13

Sección titulada «Panel de detalle expandido (fila) — verificado en vivo 2026-08-13»

Al hacer click en el chevron de una fila se despliega, en este orden:

  1. Editores inline (no modal): Prioridad (select) y Usuario/Ejecutivo (select), lado a lado, justo debajo del resumen de la fila. Cambian el valor directamente sobre esa unidad sin navegar.
  2. AS-400 (columna izquierda): “Última sincronización” + botón de refresh manual, luego: Posición actual (timestamp + OFC. <código> (Kms: N)), Último movimiento (timestamp), Días transcurridos, Operador (a menudo vacío), Situación, Guía (vacío), Cliente remitente (vacío), Cliente destinatario (vacío), Cliente que paga (vacío), Flota.
  3. Vales (columna derecha): lista de números de vale + fecha (ej. 55913 — agosto 3°, 2026 1:50 PM).
  4. Otros archivos: gestor de documentos por unidad — selector de tipo de documento + botón “Editar” + fecha del archivo actual, y fila final con selector vacío + botón “Subir Archivo”. Catálogo de tipos observado (parcial, hay más scrolleando): Alta control vehicular, avance estetica, Examen prueba de manejo, Factura Cabina, Factura de proveedor, Foto de refacciones, Foto de unidad, Foto engomado emisiones contaminantes, Foto tractor interior cabina, Foto tractor lateral derecho/izquierdo, Foto tractor numero de motor/serie, Foto tractor parte delantera/trasera, Foto Unidad Accidentada, Fotos, Fumigacion, Inspeccion Fisico Mecanica, Orden de compra, PAGO DE SEGURO, Poliza de Seguro, Poliza de Seguro Endoso, Verificacion de Contaminantes, Tarjeta de Circulacion (y al menos uno más truncado como “Requisi…”, por verificar el catálogo completo).
  5. Liquidaciones: lista de números de liquidación + fecha, mismo patrón visual que Vales.
  6. Historial: sección de movimientos — para TRE21 apareció vacía (sin filas), a pesar de que la unidad sí tiene Días transcurridos: 3 y un Último movimiento reciente. Por verificar: si “Historial” aquí es historial de comentarios/observaciones (no de situación — ese ya vive en AS-400) y simplemente no hay ninguno para esta unidad, o si es otro punto de fragilidad.
  • El icono de “burbuja de comentarios” junto al chevron (badge grande, ej. 997 para TRE21, 873 para TRE57, 880 para TRE60) no es clickeable como se esperaba — el link asociado (ícono de mapa contiguo) no abre nada visible al hacer click (intento de navegación externa sin efecto observable, posible popup bloqueado). El número no correlaciona con # Vales/# Liquidaciones de esa fila — por verificar qué mide exactamente (hipótesis: contador de comentarios/eventos automáticos de sync, dado el volumen).

Sub-reportes KPI — verificado en vivo 2026-08-13

Sección titulada «Sub-reportes KPI — verificado en vivo 2026-08-13»
  • Filtros: búsqueda global, Flota, radio Con tractores / Sin tractores / Todos (default Todos).
  • Vista lista (default): tabla Situación | Tractores | [PDF] [Exportador] — una fila por situación con conteo y exportación individual. Valores observados: ACCIDENTADO — 10, AUTOS UTILITARIOS TALLER — 5, BAJA — 0, CARGADO DOMESTICO — 5, CARGADO EXPO PATIO NUEVO LARED — 6, etc. (catálogo largo).
  • Toggle de vista (dos íconos arriba a la derecha de la tabla, img/graph.svg vs vista lista) cambia a gráfica de pastel “Situaciones al momento” — BUG, ver abajo.
  • Filtros: Situaciones, Flota, Tractor (selects), radio Con movimientos / Sin movimientos / Todos (default Con movimientos), rango de fechas de inicio de movimiento, rango de fechas de fin de movimiento.
  • Encabezados de tabla: Situación | Movimientos | Días totales | Días promedio.
  • Totales agregados (Σ movimientos, Σ días totales, Σ días promedio) — BUG, ver abajo.

Bugs / hallazgos encontrados (exploración en vivo 2026-08-13, QA, usuario Benjamin/Oficina Mexico)

Sección titulada «Bugs / hallazgos encontrados (exploración en vivo 2026-08-13, QA, usuario Benjamin/Oficina Mexico)»

Estos tres son reproducibles y estables (confirmados con captura de red y re-verificación, no son parpadeos de carga). Buenos candidatos a spec de regresión de Playwright.

  1. Selector “Prioridad” nunca muestra opciones — ni en el filtro superior ni en el editor inline de fila.

    • Repro: en /tractores, click en el select “Prioridad” (filtro superior) o en el “Prioridad” del panel expandido de cualquier fila (probado con TRE21). El caret gira a estado abierto (clase is-reverse/is-focus de Element UI) pero el panel .el-select-dropdown correspondiente queda sin opciones visibles/renderizadas.
    • Evidencia de causa: captura completa de red (network start + reload de /tractores) no muestra ninguna petición a un catálogo de prioridades (sí hay GET /units/situation, GET /catalogs/geopoint, GET /users/by-module/12, GET /users/assigned-to-units para los otros selects). El frontend nunca pide el catálogo de prioridades.
    • Control: el select “Usuario Ejecutivo” en el mismo filtro sí funciona (muestra nombres reales al abrirlo), así que no es un problema genérico de todos los el-select de la página.
    • Impacto: no se puede filtrar por prioridad ni cambiar la prioridad de un tractor desde la UI, aunque el campo sí se muestra y tiene valor (Prioridad: Normal en todas las filas observadas).
  2. Reporte “Historial Situaciones” — los totales agregados sí calculan pero la tabla de detalle siempre sale vacía.

    • Repro: ir a /tractores/reportes/historial-situaciones, cambiar el radio a Todos (o dejar el default Con movimientos). En ambos casos aparece No hay más elementos bajo los encabezados de tabla (Situación | Movimientos | Días totales | Días promedio).
    • Con Todos seleccionado, los totales sí muestran datos reales: Σ movimientos: 556,890, Σ días totales: 519,368.02, Σ días promedio: 219.4 — prueba de que el backend sí tiene datos para agregar, pero el listado desglosado por situación no se renderiza en ningún filtro probado.
  3. Vista de gráfica “Situaciones al momento” (pie chart) no dibuja datos.

    • Repro: en /tractores/reportes/situaciones, click en el ícono de gráfica (img/graph.svg).
    • Se renderiza un <canvas> de 1618x575 pero visualmente solo aparece un círculo gris sólido, sin colores por segmento, sin leyenda ni etiquetas — pese a que la vista de lista, en la misma página, sí muestra conteos reales por situación (ACCIDENTADO — 10, etc.). Estable tras esperar y re-capturar (no es un parpadeo de carga).

Nota: faltó explorar con un usuario que tenga permisos de escritura reales para confirmar si el bug de Prioridad también ocurre para roles distintos a Benjamin/Oficina Mexico, y faltó probar el flujo de subida de archivo (“Subir Archivo”) de punta a punta (se documentó el catálogo de tipos pero no se subió un archivo real, para no ensuciar el ambiente QA compartido).

Resource unit-reports (constantes en app/Core/Security/PermissionConst.php): view-unit-reports (listado principal /tractores), read-unit-reports, update-executive-user-unit-reports, update-priority-unit-reports. Resource separado unit-sub-reports: view-unit-sub-reports (gobierna los KPIs de situaciones/historial). Por verificar: no se encontró una constante sync-unit-reports explícita (sí existe sync-trailer-reports en Remolques) — puede que el sync de tractor no tenga guard de permiso propio, o que la constante tenga otro nombre no capturado por el grep usado (unit-reports|unit_reports|UNIT_REPORT).

Selectores usados por el tester (riesgo de fragilidad)

Sección titulada «Selectores usados por el tester (riesgo de fragilidad)»

Actualizado 2026-08-13 — ya hay un spec y pasó a la primera: tests/tractores/expand-tractor-detail.spec.ts (pages/tractores/TractorListPage.ts, TractorRowComponent.ts, TractorDetailPanel.ts), copia literal del patrón de Remolques. La hipótesis por analogía se confirmó tal cual, sin ajustes:

  • getByText(code, { exact: true }) (tractor TRE21) + heurística de ancestro con botón para la fila — funcionó igual.
  • Labels y valores del panel de detalle como nodos hermanos (<strong>Label:</strong> + <generic>Valor</generic>) — igual.
  • Navegación directa por URL (page.goto('/tractores')) en vez de clickear el link del sidebar — funcionó, no se probó el click del link así que no se confirmó si también tiene el problema de viewport de Remolques.
  • Solo se verificó el campo “Situación” (PROGRAMADO CON VIAJE para TRE21) — a diferencia de Remolques, la lista de Tractores no muestra Propietario/Ubicación como columnas, así que no se asumió que esos campos existan igual en el panel de detalle de Tractor; falta verificar qué campos SÍ tiene ese panel más allá de Situación.

Datos observados en QA (2026-08-12, columnas/filtros; ampliado 2026-08-13 con navegación real)

Sección titulada «Datos observados en QA (2026-08-12, columnas/filtros; ampliado 2026-08-13 con navegación real)»

URL: https://qa.controlgmg.com/tractores. 287 registros en el listado, 40 por página. Sync: Ok, última sincronización 2026-08-10 13:10:31 (barra muestra 287 / 0 / 0 — total/pendientes/error).

  • Columnas: Tractor (código, ej. TRE21, TRE57), # Liquidaciones, # Vales, Último movimiento, Días transcurridos, Situación (valores vistos: PROGRAMADO CON VIAJE, CONDUCTOR AUSENTE, DISPONIBLE, TALLER MEDIANO PLAZO, SIN CONDUCTOR Y DISPONIBLE, LIBERACIONES INTERMODAL, ACCIDENTADO, PATIERO TALLER REMOLQUES, TALLER CORTO/MEDIANO PLAZO, TALLER ALINEACION BALANCEO, DESENGANCHA CONTENEDOR (FINAL), REVISION GPS, DESCARGANDO IMPORTACION), Prioridad.
  • Filtros: ver lista completa y verificada arriba (sección “Frontend (Vue 2)”).
  • Cada fila: tiene un chevron para expandir el detalle — mismo patrón interactivo que Remolques.

Fixture de prueba fijo: TRE21 (capturado 2026-08-13, QA es ambiente compartido — puede cambiar)

Sección titulada «Fixture de prueba fijo: TRE21 (capturado 2026-08-13, QA es ambiente compartido — puede cambiar)»
  • Prioridad: Normal · # Vales: 11 · Último movimiento: 2026-08-10 13:00:00 · Días transcurridos: 3
  • Situación: PROGRAMADO CON VIAJE · Sincronizado: (2026-08-10 13:10:27) · Badge comentarios: 997
  • AS-400: Posición actual 2026-08-10 01:09 PM, OFC. MTY (Kms: 0), Operador/Guía/Clientes vacíos, Flota: 3 - Locales MTY.
  • Vales (primeros): 55913 (ago 3, 2026 1:50 PM), 421760, 055867, 55867, 421638, 421631…
  • Liquidaciones (primeras): 57265 (ago 4, 2026 6:20 AM), 57173, 57078, 56972, 56603, 56509.
  • Historial (sección “Historial”, movimientos): vacío para esta unidad.
  • Otras filas capturadas de la misma página (para variedad de fixtures): TRE57 (Conductor Ausente, 4 vales, badge 873), TRE60 (Disponible, 13 vales, badge 880), TRE54 (Taller Mediano Plazo, 10 días transcurridos, tiene ícono de alerta adicional en la fila), TRE68 (0 vales, 17 días, Patiero Taller Remolques, alerta), TRE48 (Sin Conductor y Disponible, alerta).