Ir al contenido

Liquidaciones

Generada 2026-08-12. Fuente: exploración de código de controlgmg-v2 + observación manual del navegador (QA).

  • Modelo: App\Core\Operations\Operation (app/Core/Operations/Operation.php), tabla operations. Ojo: internamente el dominio se llama “Operations” en todo el código (namespace, controlador, rutas, servicio JS); “Liquidaciones” es solo el nombre visible en UI/menú/módulo. No busques un modelo Settlement/Liquidacion — no existe.
  • Migración base: database/migrations/2018_04_05_210027_create_operations_table.php (columnas originales: user_id, company_id, unit_id, operator_id, checkbook, policy_number, policy_date, amount, settlement, settlement_date, performance, authorized, authorized_by, authorized_on, paid_on). El modelo actual usa muchas más columnas añadidas después vía migraciones incrementales no localizadas por nombre de tabla explícito (team_id, status, expected_payment_date, expected_date_set_by, expected_date_set_on, paid_by, checkbook_id, check_id, bank_account, performance_notes) — usa OperationFactory (database/factories/OperationFactory.php) como referencia rápida de shape en vez de perseguir cada migración.
  • guarded: ['id'] (no fillable explícito). Casts: amount y performance a float. SoftDeletes activo (deleted_at).
  • Team scope: vía App\Scopes\OperationScope (global scope, filtra por operations.team_id = currentTeam()->id), NO por BelongsToTeamTrait/BaseModel. config/modules.php → módulo liquidaciones tiene has_team_scope: true (a diferencia de Remolques, que es false).
  • Estados (status): constantes en el modelo — REC_DATOS (rec-datos), AUTORIZACION (autorizacion), NO_AUTORIZADO (no-autorizado), AUTORIZADO (autorizado), POR_PAGAR (por-pagar), PROCESO_OK (proceso-ok). Es el flujo de aprobación: captura → autorización → autorizado/rechazado → por pagar → pago confirmado.
  • Relaciones clave:
    • unit() → belongsTo(App\Core\Unit::class) (Tractor), withTrashed().
    • operator() → belongsTo(App\Core\Operators\Operator::class), withTrashed().
    • company(), user(), authorizer() (authorized_by), payer() (paid_by), epdsetter() (expected_date_set_by), checkbook_model() (App\Core\LegacyCatalogs\Checkbook), check_model() (App\Core\Catalogs\Check).
    • Archivos adjuntos vía hasMany: lectures() (LectureFiles), policies() (PolicyFiles), settlements() (SettlementFiles — ojo, es el nombre de la relación de ARCHIVOS de liquidación, no el modelo principal), invoices() (InvoiceFiles).
    • file_downloads() → OperationFileDownload (historial de descargas de documentos).
  • Relación Tractor↔Liquidación (la que ves en el módulo Tractores): App\Core\Unit::operations() → hasMany(Operation::class)->withoutGlobalScopes() (app/Core/Unit.php). El reporte de Tractores (resources/js/components/Catalogs/Units/Reports/UnitsReport.vue) ordena/filtra por el alias operations_count (columna “# Liquidaciones”, vía withCount('operations') en Unit::scopeWithOperationAndVoucher()), y también hay un filtro “Sin liquidaciones” (without_operation).
  • Controlador: App\Http\Controllers\OperationController (app/Http/Controllers/OperationController.php, sin subcarpeta Operations/) — no usa Form Requests para todo (p.ej. all() recibe Request plano), sí para store/update/authorize/programPayment/confirmPayment/addComment/destroy/reject (App\Http\Requests\Operations\*).
  • Export: reutiliza App\Core\Export con tipos Export::TYPE_OPERATIONS / TYPE_OPERATIONS_REPORT vía ExportController.

Todas bajo el grupo global (auth:api + password_expired) directamente en routes/web.php (líneas ~38-58) — no vive en un archivo routes/operations/* propio como otros dominios:

Método Ruta Acción
GET /operations listado paginado + stats por estatus
POST /operations crear
POST /operations/update actualizar
DELETE /operations eliminar (soft delete)
PATCH /operations/{id} restaurar
POST /operations/authorize autorizar/rechazar
POST /operations/payment/program programar fecha de pago
POST /operations/payment/confirm confirmar pago
POST /operations/reject rechazar
POST /operations/comments/add comentario
GET /operations/{id}/download-history historial de descargas de archivos
GET /operations/performance/stats, /operations/getChartInfo KPIs de rendimiento
GET /operations/liquidators, /operations/getLiquidatorsOperations, /operations/filterLiqByRole reportes por liquidador (usuario)
GET /operations/excel, POST /operations/exportOpExcel, POST /operations/export exportaciones

No hay middleware permission: a nivel de ruta — la autorización vive en los FormRequests (mismo patrón que Remolques).

  • Ruta raíz /liquidaciones/ → resources/js/components/Operations/Operations.vue (listado principal, sin beforeEnter — el control de vista lo hace el propio componente/menú con can('view-operation')).
  • /liquidaciones/reportes/ → OperationsReports.vue (guard can('view-operations-reports')), con hijos: reportes/tractor → Reports/Units.vue, reportes/operador → Reports/Operators.vue, reportes/liquidaciones → Reports/Operations.vue.
  • /liquidaciones/catalogos/ → OperationsCatalogs.vue (guard can('view-operations-catalogs')), con hijos companias, tractores, etc. bajo Catalogs/.
  • Operations.vue — página de listado: filtros (búsqueda, estatus, rango de fecha con selector de campo operations.created_at/policy_date/settlement_date/paid_on), orden por póliza/operador/tractor/liquidación/captura/pago, botón “Agregar” (can('create-operation')), exportador Excel, toggle papelera (can('delete-operator') — permiso compartido/heredado de Operadores, posible bug de copy-paste a validar).
  • OperationRow.vue — fila de la lista: póliza, monto + chequera, autorizador, usuario que capturó, código de compañía, código de operador, código de tractor (operation.unit.code), barra de progreso de estatus (%), fechas (Liquidación/Captura/Pago), botón de comentarios, historial de descargas (AsyncFileDownloadHistoryDialog, solo si file_downloads_count > 0).
  • OperationForm.vue — formulario expandible inline (alta/edición), aparece al click en “Agregar” o al hacer click en una fila (mismo patrón de expansión que Remolques).
  • Servicio: resources/js/services/operations/operation-service.js — GET /operations (con params), POST /operations (crear, vía Spark.post), POST /operations/update, POST /operations/reject, DELETE /operations, PATCH /operations/{id} (restaurar), POST /operations/payment/confirm, POST /operations/payment/program, POST /operations/authorize, GET /operations/excel (descarga vía DownloadService). Comentarios en servicio aparte: resources/js/services/operations/operation-comment-service.js.
  • Menú lateral: definido en resources/js/components/Nav/menuOptions.js — primer ítem del arreglo menuOptions, name: 'Liquidaciones', module: 'operation', path: '/liquidaciones', canView: 'view-operation', ícono /img/liquidaciones.svg. Submenús: submodules (Liquidaciones), catalogs (Compañías, Tractores), reports (Tractor, Operador, Liquidaciones).

Fuente: config/laratrust_seeder.php (resource operation: c,r,u,d,co,confirm-payment,program-payment,reject,a,v) → generadas en App\Core\Security\PermissionConst:

  • view-operation, create-operation, read-operation, update-operation, delete-operation
  • comment-operation, approve-operation, confirm-payment-operation, program-payment-operation, reject-operation
  • view-operations-reports (gobierna /liquidaciones/reportes/*), view-operations-catalogs (gobierna /liquidaciones/catalogos/*)

Roles relevantes en config/modules.php (módulo liquidaciones): admin, owner, liquidador, jefeLiquidaciones (Jefe de Liquidaciones — flujo de autorización), jefeBancos (autoriza pagos), jefeFinanzas (programa pagos). Los eventos del Message Center (comment, rejected, authorization-request, authorized, not-authorized, payment-programed, payment-confirmed) mapean 1:1 con las transiciones de status del OperationController.

Selectores usados por el tester (riesgo de fragilidad)

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

No hay specs de Playwright para este módulo todavía — a diferencia de Remolques (que sí tiene tests/remolques/expand-trailer-detail.spec.ts), Liquidaciones no ha sido explorado con Playwright/codegen contra QA real. Todo lo que sigue es inferencia de código, no verificación en vivo:

  • No hay data-testid en la app (mismo patrón que el resto de controlgmg-v2, no se modifica el repo para agregarlos).
  • El link “Liquidaciones” del sidebar (menuOptions.js) es el primer ítem, por lo que probablemente SÍ esté visible sin necesidad de scroll (a diferencia de “Remolques”, que queda fuera del viewport) — pero esto debe confirmarse contra QA real, no asumirse.
  • La fila de la lista (OperationRow.vue) no usa una tabla HTML sino divs (info-row/column), igual que Remolques — probablemente aplique una estrategia similar de getByText(policy_number) + heurística de ancestro para ubicar la fila.
  • El formulario de alta/edición (OperationForm.vue) se expande inline igual que en Remolques (mismo patrón el-collapse-transition), pero su estructura interna de campos no ha sido inspeccionada — no asumir que los labels de campo estén asociados correctamente a inputs sin verificar (en Remolques el login ya demostró que getByLabel puede fallar).
  • El filtro “Sin liquidaciones” / “# Liquidaciones” vive en el módulo Tractores (UnitsReport.vue), no en Liquidaciones — si un test necesita verificar la relación Tractor↔Liquidación, navegar a /unidades (o la ruta de Tractores) y no a /liquidaciones.

Antes de escribir cualquier spec para este módulo, correr npm run codegen:gmg contra QA real para verificar selectores, igual que se hizo para Remolques.

  • URL: https://qa.controlgmg.com/liquidaciones — primer ítem del sidebar, título de página “Liquidaciones”.
  • El módulo Tractores muestra una columna “# Liquidaciones” que cuenta liquidaciones por tractor — confirma en vivo la relación Unit::operations() descrita arriba. No se registró en esta pasada el valor exacto de ningún tractor/liquidación de ejemplo; falta una exploración manual más profunda del listado y del formulario de alta/edición para documentar selectores y datos de prueba concretos (pendiente, análogo a lo hecho para Remolques).