## Pendiente
- Definir módulos iniciales

## En progreso
- Ninguna

## Hecho
- Modo demo con reset diario (mayo 2026)
  - Se agregó configuración central en `config/demo.php` controlada por `DEMO_MODE`, `DEMO_RESET_TIME`, `DEMO_DATABASE_NAME_MUST_CONTAIN`, `DEMO_ALLOWED_DATABASES` y `DEMO_DEFAULT_PASSWORD`.
  - Se agregó comando `demo:reset --force` con guards para bloquear ejecución fuera de demo, en producción o contra bases que no parezcan demo.
  - Se agregó `DemoDatabaseSeeder` con desarrollo, configuración financiera, usuarios demo, roles demo, lotes, clientes, ventas, órdenes, pagos y apartado activo.
  - En scheduler, cuando demo está activo se registra reset a las 00:00 y se omiten recargos/apartados diarios si `DEMO_DISABLE_OPERATIONAL_SCHEDULE=true`.
  - Se agregó banda visual global: `Modo demo: los datos se restablecen diariamente.`
  - Pruebas agregadas en `tests/Feature/DemoModeTest.php`.
  - Validación ejecutada:
    - `php -l config/demo.php` (OK)
    - `php -l app/Console/Commands/ResetDemoCommand.php` (OK)
    - `php -l app/Console/Kernel.php` (OK)
    - `php -l database/seeders/DemoDatabaseSeeder.php` (OK)
    - `php -l tests/Feature/DemoModeTest.php` (OK)
    - `./vendor/bin/sail artisan test tests/Feature/DemoModeTest.php` (`4 passed`)
    - `./vendor/bin/sail artisan test tests/Feature/RecargoAutomaticoSchedulerTest.php` (`3 passed`)
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
- Apartados como módulo propio (mayo 2026)
  - Se agregó `GET /apartados` como pantalla principal (`apartados.index`) con alta de apartado, tabs `Activos` y `Vencidos por revisar`.
  - `/apartados/revision` quedó como ruta legacy y redirige a `/apartados?tab=vencidos`.
  - `lote_id` por query string se conserva en `/apartados?lote_id={id}` y solo preselecciona lotes disponibles del desarrollo activo.
  - Menú lateral, Pagos, Caja, Ventas y Mapa de Lotes ahora apuntan al módulo `apartados.index`.
  - Pruebas agregadas/actualizadas en `tests/Feature/ApartadoRevisionPrefillTest.php`.
  - Validación ejecutada:
    - `php -l app/Http/Controllers/ApartadoController.php` (OK)
    - `php -l tests/Feature/ApartadoRevisionPrefillTest.php` (OK)
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
    - `./vendor/bin/sail artisan test tests/Feature/ApartadoRevisionPrefillTest.php` (`6 passed`)
- Ventas: acceso a Apartados desde listado (mayo 2026)
  - Se agregó botón `Apartados` como acción secundaria junto a `Registrar venta` en el encabezado de `Ventas`.
  - Validación ejecutada:
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
- Mapa de lotes: acción Apartar para lotes disponibles (mayo 2026)
  - En el drawer de `Mapa de Lotes`, los lotes `Disponible` ahora muestran `Apartar` junto a `Iniciar venta`.
  - `Apartar` abre `/apartados?lote_id={id}` en una nueva pestaña y preselecciona el lote si sigue disponible en el desarrollo activo.
  - `ApartadoController@index` valida que el `lote_id` pertenezca al desarrollo activo y esté disponible antes de preseleccionarlo.
  - Pruebas agregadas en `tests/Feature/ApartadoRevisionPrefillTest.php`.
  - Validación ejecutada:
    - `php -l app/Http/Controllers/ApartadoController.php` (OK)
    - `php -l tests/Feature/ApartadoRevisionPrefillTest.php` (OK)
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
    - `./vendor/bin/sail artisan test tests/Feature/ApartadoRevisionPrefillTest.php` (`3 passed`)
- Acceso directo a Apartados (mayo 2026)
  - Se agregó `Apartados` como entrada directa en el menú lateral.
  - Se agregó botón `Apartados` en el encabezado de `Pagos`.
  - En Caja (`Registrar pago`) se renombró el botón `Apartados vencidos` a `Apartados`.
  - Plan actualizado en `plans/WIZARD_COBRANZA_APARTADOS_SEPARADOS_PLAN.md`.
  - Validación ejecutada:
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
- Ticket con branding y configuración general (abril 2026)
  - Se agregó configuración global en `/configuracion?tab=general` para nombre de compañía, dirección, teléfono, RFC, email y logo.
  - Se agregó override opcional por desarrollo en `Configuración > Desarrollo > General` con switch para mostrar datos propios del ticket.
  - Los logos se guardan en `storage/app/public/configuracion/logos`; los SVG se sanitizan con el sanitizador existente.
  - `TicketBrandingService` resuelve la prioridad efectiva: override activo, configuración global y fallback a datos del desarrollo.
  - El PDF de ticket ahora muestra logo/datos de compañía, RFC, email, folio, venta, desarrollo, método, concepto, cliente, lote y resumen compacto: saldo contrato, saldo anterior, abono y saldo actual.
  - Plan documentado en `plans/2026-04-28-ticket-branding-configuracion-general.md`.
  - Validación ejecutada:
    - `php -l app/Http/Controllers/ConfiguracionController.php` (OK)
    - `php -l app/Services/TicketBrandingService.php` (OK)
    - `php -l app/Services/PagoTicketService.php` (OK)
    - `php -l app/Models/ConfiguracionGeneral.php` (OK)
    - `php -l app/Models/ConfiguracionTicketDesarrollo.php` (OK)
    - `php -l tests/Feature/ConfiguracionTicketBrandingTest.php` (OK)
    - `php -l database/migrations/2026_04_28_000300_add_rfc_email_to_ticket_configurations.php` (OK)
    - `php artisan test tests/Feature/ConfiguracionTicketBrandingTest.php` (`3 passed`)
    - `php artisan test tests/Feature/CorreccionesConsistenciaTest.php --filter=ticket_balance` (`1 passed`)
    - `php artisan test tests/Feature/ConfiguracionDesarrollosTabTest.php` (`3 passed`)
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
- Configuración: tooltip descriptivo en roles (abril 2026)
  - Se agregó un icono de información junto a cada permiso dentro del modal de roles.
  - Cada tooltip explica qué habilita exactamente el permiso seleccionado.
  - Los permisos sensibles de overrides, descuentos, abonos y apartados tienen copy ampliado con impacto operativo.
  - El cambio reutiliza los tooltips Bootstrap ya inicializados globalmente.
  - Plan documentado en `plans/2026-04-28-tooltip-descripcion-roles.md`.
  - Validación ejecutada:
    - `php artisan view:cache` (OK)
    - `php artisan view:clear` (OK)
    - `php -l app/Http/Controllers/ConfiguracionController.php` (OK)
- Wizard de cobranza: control de fecha de pago por permiso (abril 2026)
  - Se agregó permiso `pagos.cambiar_fecha_pago` para permitir edición de fecha solo a admin/usuarios autorizados.
  - En `pagos/create`, usuarios sin permiso ven fecha de operación/pago fija al día de registro; usuarios autorizados pueden usar fecha anterior con motivo obligatorio.
  - Backend bloquea fechas futuras en operaciones/preview/store y rechaza fechas distintas a hoy sin permiso.
  - Auditoría de pagos wizard registra fecha de pago, fecha de registro y motivo retroactivo cuando aplica.
  - Pruebas agregadas en `PagoWizardFlowTest` para fecha sin permiso, fecha futura, motivo obligatorio y fecha retroactiva autorizada.
  - Validación ejecutada:
    - `php -l app/Actions/Pago/StoreWizardPagoAction.php` (OK)
    - `php -l app/Actions/Pago/PreviewPagoAction.php` (OK)
    - `php -l app/Actions/Pago/BuildPagoCreateViewDataAction.php` (OK)
    - `php -l app/Http/Controllers/PagoController.php` (OK)
    - `php -l resources/views/pagos/create.blade.php` (OK)
    - `php -l tests/Feature/PagoWizardFlowTest.php` (OK)
    - `php artisan test tests/Feature/PagoWizardFlowTest.php` (`16 passed`)
    - `php artisan test` (`128 passed`)
- Wizard de cobranza: montos fijos para tipos cerrados (abril 2026)
  - En paso 4 de `pagos/create`, `Cobro de apartado`, `Pago adelantado mensualidad` y `Liquidación total` muestran solo `Monto a pagar` y bloquean captura manual.
  - `Pago adelantado mensualidad` ahora exige exactamente el monto de la próxima mensualidad futura, sin parcialidad ni excedente.
  - `Liquidación total` ahora exige exactamente el monto requerido cuando hay efectivo a cubrir; sigue respetando saldo a favor/descuento autorizado.
  - Pruebas ajustadas/agregadas en `PagoWizardFlowTest`.
  - Validación ejecutada:
    - `php -l resources/views/pagos/create.blade.php` (OK)
    - `php -l app/Services/CobranzaWizardService.php` (OK)
    - `php -l tests/Feature/PagoWizardFlowTest.php` (OK)
    - `php artisan test` (`123 passed`)
- Wizard de cobranza: copy de monto en resumen rápido (abril 2026)
  - En `pagos/create`, el resumen rápido cambió `Monto capturado` a `Monto` para evitar sugerir que ya fue capturado en el paso de tipo.
  - Para `Liquidación total`, el resumen aclara que el monto incluye saldo programado pendiente.
  - Para `Abono a capital`, el resumen aclara disponibilidad en paso de tipo y, desde captura, que es el monto a aplicar como abono.
  - Validación ejecutada:
    - `php -l resources/views/pagos/create.blade.php` (OK)
- Limpieza de pagos sin wizard (abril 2026)
  - Se eliminó el fallback de `POST /pagos` sin `wizard_mode`; ahora redirige a Caja y no crea pagos.
  - Se retiraron `StorePagoLegacyAction`, `StorePagoCapitalAction`, la ruta `pagos.pagoCapital` y la vista residual `pagos.createPagoCapital`.
  - Se conservan `pagos.newPago` y `pagos.newPagoCapital` únicamente como accesos de prefill hacia el wizard.
  - Se retiró `Orden de Pagos` de la UI financiera por quedar sin efecto operativo.
  - `CobranzaWizardService` reconoce órdenes `Apartado` en la cascada ordinaria y sincroniza el lote al cobrarlas.
  - Plan documentado en `plans/2026-04-28-limpieza-pagos-sin-wizard.md`.
  - Validación ejecutada:
    - `php -l app/Actions/Pago/StorePagoAction.php` (OK)
    - `php -l app/Http/Controllers/PagoController.php` (OK)
    - `php -l app/Services/CobranzaWizardService.php` (OK)
    - `php -l app/Http/Controllers/ConfiguracionController.php` (OK)
    - `php artisan test` (`122 passed`)
- Branding: actualización de isotipo global (abril 2026)
  - Se actualizó el logo central en `resources/views/_partials/macros.blade.php` (sidebar/navbar/login).
  - Se actualizó `public/assets/img/favicon/logo-fracciona.svg` con el nuevo isotipo.
  - Se ajustó tamaño de marca a `25x25` en `resources/assets/css/main.css` y compilado en `public/assets/css/main.css`.
  - Se regeneró favicon fallback (`public/assets/img/favicon/favicon.ico`) y se sincronizó `public/favicon.ico` para evitar icono vacío en la raíz.
- Branding/Tipografia: Times New Roman en nombre y headings (abril 2026)
  - Se reemplazo `Space Grotesk` por `Times New Roman` para `h1..h6` y `.font-display`.
  - Se aplico `Times New Roman` al texto de marca del sidebar (`.app-brand-text.demo.menu-text.fw-bold.ms-2`) con `font-weight: 500 !important`.
  - Se ajusto carga de fuentes globales en `layouts/sections/styles.blade.php` para retirar `Instrument Serif`.
  - Se compilaron assets con `npm run dev` para publicar cambios en `public/assets/css/custom.css` y `mix-manifest`.
- DataTables: localizacion global a espanol (abril 2026)
  - Se centralizo la configuracion de idioma en `resources/js/app.js` para todas las tablas inicializadas globalmente (`#dataTable`).
  - Textos cubiertos: buscador, info de registros, selector de pagina, estado vacio, paginacion y mensajes de carga/proceso.
  - Se compilaron assets con `npm run dev` para publicar el cambio en `public/js/app.js` y `mix-manifest`.
- Dashboard: extracción de estilos inline a CSS de página (abril 2026)
  - Se movió el bloque `<style>` embebido de `resources/views/dashboard/main.blade.php` a `resources/assets/css/pages/dashboard.css`.
  - La vista ahora carga estilos por `@section('page-style')` con `mix('assets/css/pages/dashboard.css')`.
  - Se compiló assets con `npm run dev` para publicar `public/assets/css/pages/dashboard.css` y actualizar `mix-manifest`.
  - Validación ejecutada:
    - `php artisan test tests/Feature/DashboardLayoutTest.php` (`3 passed`)
    - `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`)
- Dashboard: ajuste de KPIs operativos + limpieza de hero (abril 2026)
  - Cards actualizados:
    - `Ingreso mensual` -> `Clientes con retraso`
    - `Cartera vencida` (card superior) -> `Mensualidades vencidas`
  - Se removió el chip de `lotes sin mapeo` en el bloque `Control del desarrollo en tiempo real`.
  - Se eliminó la tarjeta de “Indicadores financieros restringidos” del bloque superior para mantener 4 KPIs operativos consistentes para todos los roles.
  - Validación ejecutada:
    - `php artisan test tests/Feature/DashboardLayoutTest.php` (`3 passed`)
    - `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`)
- Dashboard: corrección de consistencia en bloque de cobranza (abril 2026)
  - La tarjeta interna ya no muestra `Clientes con atraso` en esa sección de lista.
  - Se cambió a `Órdenes en caja rápida` usando el conteo real de renglones visibles (`ordenesEnCajaRapida`) para evitar discrepancia visual con la lista.
  - Se ajustó copy a `Promedio por cliente con atraso` para clarificar base del cálculo.
  - Validación ejecutada:
    - `php artisan test tests/Feature/DashboardLayoutTest.php` (`3 passed`)
    - `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`)
- Dashboard: deduplicación de KPIs + visibilidad por permisos (abril 2026)
  - Se eliminó duplicidad de métricas entre el hero azul y boxes individuales.
  - El hero quedó como resumen operativo no financiero (sin repetir montos de KPIs).
  - KPIs visibles en boxes: `Lotes totales`, `Lotes vendidos`; financieros (`Ingreso mensual`, `Cartera vencida`) solo para roles con acceso.
  - Bloque `Cobranza y vencimientos` ahora es restringido por permisos financieros; para roles sin acceso se muestra mensaje de restricción.
  - En `Ventas recientes`, el monto se oculta para roles sin acceso (`Monto restringido`).
  - Nuevo permiso sembrable: `dashboard.ver_finanzas` (con fallback de acceso por `reportes.ver`).
  - Validación ejecutada:
    - `php artisan test tests/Feature/DashboardLayoutTest.php` (`3 passed`)
    - `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`)
    - `php artisan test --filter=test_dashboard_kpis_use_real_due_from_payment_applications tests/Feature/CorreccionesConsistenciaTest.php` (`1 passed`)
- Simplificación de KPIs en dashboard (abril 2026)
  - La grilla principal se redujo de 8 a 4 tarjetas para bajar ruido visual.
  - KPIs conservados en cards: `Lotes totales`, `Ingreso mensual`, `Cartera vencida`, `Cobranza hoy`.
  - Métricas complementarias permanecen en hero/resumen para contexto sin saturar la pantalla.
  - Validación ejecutada: `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`).
- Rediseño visual del dashboard operativo (abril 2026)
  - Nuevo bloque hero con resumen diario del desarrollo y métricas prioritarias.
  - Reorganización de KPIs en una sola grilla con jerarquía visual y animación ligera de entrada.
  - Rediseño de tarjetas `Distribución de lotes`, `Cobranza y vencimientos` y `Ventas recientes` con estados vacíos más claros.
  - Se conservaron copy y flujos de caja rápida (`Registrar pago` / `Completar pago`) sin cambios de backend.
  - Validación ejecutada: `php artisan test tests/Feature/DashboardQuickPagoTest.php` (`9 passed`).
- Estructura inicial de memoria de proyecto creada
- CRUD base de desarrollos
- CRUD base de lotes
- Nueva Sección de Configuración (sidebar + Roles/Permisos + Desarrollos + Financiero por desarrollo)
  - Migration: configuracion_financiera
  - Model: ConfiguracionFinanciera
  - Seeder: PermissionsSeeder (29 permisos predefinidos)
  - ConfiguracionController: nuevos métodos (desarrolloDetail, updateGeneral, updateFinanciero, roles*, usuarios*)
  - Routes: 9 nuevas rutas bajo middleware role:admin
  - Views: configuracion/index.blade.php rediseñado, configuracion/desarrollo-detail.blade.php creado
- Retiro completo de compatibilidad legacy de planos en runtime/API/UI
  - Eliminado fallback `html_legacy` y render por views `base_view/actions_view`
  - Runtime de mapas ahora depende solo de SVG versionado/publicado
  - Nueva migración para eliminar columnas legacy de `map_templates`
  - Eliminados artefactos legacy (`mapa/partials/template-svg.blade.php`, comando `map-templates:migrate-legacy`)
- Gestión de plantillas de mapa: agregado borrado seguro desde Configuración
  - Nueva ruta `DELETE /configuracion/map-templates/{template}`
  - Botón `Eliminar plantilla` en `configuracion?tab=map-templates`
  - Bloqueo de borrado si plantilla está asignada a desarrollos o tiene lotes mapeados
- Gestión de plantillas de mapa movida al detalle del desarrollo
  - Se eliminó la sección `Plantillas de mapa` del `configuracion/index`
  - El módulo completo (crear/subir/publicar/eliminar) quedó integrado en `configuracion/desarrollos/{id}?tab=general`
- Plantilla de mapa 100% ligada al desarrollo (sin asignación manual)
  - Nueva columna `map_templates.desarrollo_id` (unique) para ownership 1:1
  - Nuevo servicio `MapTemplateOwnershipService` para resolver/autocrear/clonar/sincronizar plantillas por desarrollo
  - Nuevas rutas scope por desarrollo para map-template:
    - `GET /configuracion/desarrollos/{desarrollo}/map-template`
    - `POST /configuracion/desarrollos/{desarrollo}/map-template/versions`
    - `POST /configuracion/desarrollos/{desarrollo}/map-template/versions/{version}/publish`
    - `DELETE /configuracion/desarrollos/{desarrollo}/map-template`
  - Retiradas rutas globales de gestión de plantillas (se mantiene solo `GET .../svg` para stream seguro)
  - `configuracion/desarrollos/{id}?tab=general` ahora muestra únicamente el módulo de upload/publicación del desarrollo actual
  - Eliminado selector “Plantilla asignada” y listado de plantillas de otros desarrollos
  - Nuevo comando `map-templates:backfill-ownership` para clonar plantillas compartidas y reasignar mapeos con reporte JSON
  - Tests feature agregados para visibilidad por desarrollo y autocreación de plantilla en upload
- Estatus de desarrollo convertido a enum controlado (`activo|inactivo`)
  - Nueva migración para normalizar valores existentes y convertir `desarrollos.estatus` a enum en MySQL
  - `DesarrolloController@store/update` ahora valida `estatus` con `in:activo,inactivo`
  - `ConfiguracionController@updateGeneral` ahora valida `estatus` con `in:activo,inactivo`
  - Formularios de desarrollo (crear/editar/configuración) cambiados de input libre a `select`
  - Test feature agregado para validar rechazo de estatus inválido y aceptación de ambos valores válidos
- Upload de plantilla de mapa ahora es solo modo dual
  - Eliminado campo `SVG único (compatibilidad)` en configuración de desarrollo
  - Backend (`MapTemplateController`) ahora requiere siempre `svg_base` + `svg_polygons`
  - Test feature agregado para validar rechazo cuando falta uno de los dos archivos
- Mejora UX en mapeo de lotes (tabla-first + mapa)
  - Se retiró el flujo rígido `manzana/lote/asignar` de la vista de configuración
  - La tabla de estado ahora permite seleccionar lote directo (`Asignar/Reasignar`)
  - Click en nodo del mapa asigna automáticamente al lote seleccionado
  - Se agregó panel de contexto (`Lote seleccionado` / `Nodo seleccionado`)
  - Se agregaron filtros de tabla por manzana, estado y búsqueda por identificador
- Ajustes UX de `mapa-lotes`
  - Click sobre nodos no mapeados ahora se ignora (no abre detalle ni cambia selección)
  - Se alineó el bloque de “Desarrollo activo” al estilo estándar del sistema (cards Bootstrap/Sneat, sin estilo ad-hoc)
- Dashboard enfocado en desarrollo activo (sin “Desarrollos recientes”)
  - Se reemplazó “Desarrollos recientes” por panel operativo de “Cobranza y vencimientos”
  - Nuevos KPIs: lotes vendidos, vendidos del mes, variación mensual de ingresos y cartera vencida
  - Se agregó barra de “Distribución de lotes” por estado operativo (disponible/asignado/apartado/vendido/otros)
- Más datos operativos en dashboard + homogeneidad visual en mapa
  - Dashboard: se agregaron KPIs extra (`Por cobrar`, `Cobranza hoy`, `Ventas del mes`, `Lotes sin mapeo`) y métricas de apoyo (ticket promedio, avance de colocación)
  - Mapa de lotes: `Distribución de estatus` ahora usa el mismo estilo visual de `Distribución de lotes` del dashboard (barra segmentada + leyenda con conteos)
- Ventas/create: alta rápida de cliente ahora selecciona automáticamente el cliente recién creado en `#cliente_id` (Select2) sin recargar la página
  - Ajuste de robustez: selección inmediata del cliente nuevo antes del refresco de lista y sincronización posterior; backend ahora devuelve `cliente_nombre` y errores JSON para flujo AJAX
- Ventas/create: el select de desarrollo ahora abre preseleccionado con el desarrollo activo de la sesión y dispara carga inicial de manzanas
- Ventas/create: bloqueo a desarrollo activo como fuente de verdad
  - UI muestra solo el desarrollo activo (sin opciones de otros desarrollos)
  - Backend fuerza `desarrollo_id` al activo de sesión al guardar venta y valida que el lote pertenezca a ese desarrollo
- Homogeneidad global por desarrollo activo (fuera del selector principal)
  - UI: pagos/reportes/lotes/manzanas/ventas muestran `Desarrollo activo` no editable con estilo unificado
  - Backend: `pagos/reportes/manzanas` ignoran `desarrollo_id` de entrada y usan sesión activa
  - Altas: `lotes/manzanas` fuerzan desarrollo activo en flujo general y conservan excepción `from_configuracion=1`
  - Se agregó test feature `ActiveDesarrolloSourceOfTruthTest` para validar fuente de verdad + excepción de configuración
- Ajuste de copy/UI: se eliminaron mensajes de apoyo tipo “Definido por el selector principal de desarrollo” (y similares) en los bloques de desarrollo activo
- Ventas: nuevos tipos de venta `Apartado` y `Cesion`
  - UI actualizada en `ventas/create` y filtro en `reportes/index`
  - JS de `ventas/create` ajustado: solo `Credito` muestra flujo de amortización; tipos no crédito usan flujo simple
  - Nuevo badge mapping para `Apartado` y `Cesion`
  - Migración agregada para expandir enum `ventas.tipo_venta` en MySQL
  - Test feature agregado `VentaTipoVentaOptionsTest`
- Wizard de Nueva Venta + modalidad de pago (implementación híbrida evolutiva)
  - `ventas/create` rediseñado como asistente de 5 pasos (Lote, Cliente, Tipo, Plan, Resumen) con preselección por `?lote_id=`.
  - Soporte de descuento en operación (`precio_lista`, `descuento_*`, `precio_final`) y payload estructurado (`wizard_payload`).
  - Nuevo flujo de plan de pagos:
    - `Credito`: generación de tabla de amortización desde `POST ventas/tabla-amortizacion` en modo wizard.
    - `Contado/Cesion`: plan dinámico manual por concepto editable.
    - `Donacion`: operación sin plan de pagos.
  - Confirmación de venta:
    - creación de `ordenes_pagos` universales (concepto, monto_programado, orden, metadata),
    - cobro automático de filas con fecha de hoy en `pagos`,
    - ticket por cada pago cobrado hoy.
  - Nuevos servicios: `VentaWizardService`, `VentaPricingService`, `VentaPlanPagosService`, `LoteStatusService`.
  - Catálogos y migraciones:
    - `ventas.tipo_venta` normalizado a `Contado|Credito|Donacion|Cesion` (backfill legacy `Apartado` -> `Contado` + `modalidad_pago=apartado_legacy`),
    - `pagos.tipo_pago` ampliado a conceptos de negocio,
    - `lotes.estatus` migrado a `Disponible|Apartado|Vendido|Cancelado` (backfill legacy).
  - Endpoints auxiliares agregados para wizard:
    - `GET /ventas/wizard/clientes`
    - `GET /ventas/wizard/lotes`
  - Ajustes de homogeneidad de estatus en `dashboard`, `mapa-lotes`, formularios de lotes y badges.
  - Plan de implementación documentado en `plans/VENTAS_WIZARD_MODALIDAD_PAGO_PLAN.md`.
- Estabilización cross-DB del wizard y catálogos (MySQL + SQLite de tests)
  - Migraciones de catálogos (`ventas`, `pagos`, `lotes`) ahora reconstruyen tablas en SQLite para aplicar nuevos enums/checks.
  - `ReporteController` ahora usa agregación mensual portable (`DATE_FORMAT` MySQL / `strftime` SQLite).
  - Pruebas actualizadas a nuevo catálogo de pagos (`Liquidacion` en vez de `Total`).
  - Suite completa verificada en SQLite: `28 passed`.
- Toggle de auto-cobro por desarrollo (`fecha = operación`)
  - Nueva columna `configuracion_financiera.auto_cobro_filas_hoy` (default `true`) y toggle en `Configuración > Desarrollo > Financiero`.
  - `VentaController` ahora resuelve la bandera por desarrollo y aplica regla en `storeWizard` + flujo `legacy/dashboard`.
  - Con toggle OFF:
    - no se crean `pagos` automáticos ni ticket para filas con fecha de operación,
    - se generan solo `ordenes_pagos` pendientes para cobro en caja,
    - `ventas.pago_inicial` queda en `0`.
  - Con toggle ON se mantiene comportamiento actual (auto-cobro + ticket).
  - Test nuevo `VentaAutoCobroToggleTest` (wizard OFF/ON + legacy contado OFF).
  - Suite completa verificada en SQLite: `32 passed`.
- Botón rápido para registrar pago en Dashboard (`Cobranza y vencimientos`)
  - Se agregó acción primaria por renglón de vencimiento:
    - `Registrar pago` para estatus `Pendiente`
    - `Completar pago` para estatus `Parcial`
  - La acción reutiliza `GET pagos/newPago/{ordenPagoId}` (sin rutas nuevas).
  - La caja rápida del dashboard ahora incluye vencidos y próximos (<= 7 días) para evitar “sin botón” cuando hay atraso.
  - `PagoController@nuevoPago` ahora bloquea órdenes `Pagado|Cancelado` con error de sesión controlado (normalizando estatus de forma defensiva).
  - Nuevo flujo operativo en `Pagos`: módulo `Cobro rápido por cliente` (búsqueda por cliente/lote + acción directa a `pagos.newPago` para órdenes `Pendiente|Parcial` del desarrollo activo).
  - Tests feature en `DashboardQuickPagoTest` (dashboard: pendientes/parciales + vencidos, apertura de formulario, rechazo por estatus, 403 por acceso cruzado, y búsqueda de cobro rápido filtrada por desarrollo/estatus).
- Caja unificada de cobro + recargos automáticos por configuración financiera
  - `Pagos/index` retiró el bloque `Cobro rápido por cliente` y dejó `Registrar pago` como acción principal a `pagos.create`.
  - `pagos.create` opera como Caja unificada (búsqueda cliente/lote/venta + selección opcional de orden + captura de pago).
  - Rutas legacy `pagos.newPago` y `pagos.newPagoCapital` se mantienen por compatibilidad redirigiendo con preselección a Caja.
  - `PagoController@store` aplica prioridad de cobro configurada (`orden_pagos`) en mensualidades con recargos vinculados.
  - Configuración financiera extendida con `recargo_automatico`, `recargo_modo`, `recargo_iva`, `recargo_desde` (activación fija fecha actual, sin backfill).
  - Nuevo motor `RecargoAutomaticoService` que genera órdenes `Recargo` automáticas (no pagos) para órdenes `Mensualidad` en `Pendiente|Parcial`, respetando `dias_gracia`, `tipo_interes`, `redondeo`, `recargo_iva`, y `recargo_desde`.
  - Idempotencia técnica en `ordenes_pagos` con campos `es_recargo_automatico`, `orden_pago_origen_id`, `recargo_periodo_clave` + índice único por origen/período.
  - Nuevo comando `pagos:aplicar-recargos` (`--date`, `--desarrollo`, `--dry-run`) y scheduler diario `00:10` en `Kernel`.
  - README actualizado con ejecución de cron (`php artisan schedule:run`).
  - Pruebas nuevas/actualizadas:
    - `DashboardQuickPagoTest`
    - `ConfiguracionRecargosFinancierosTest`
    - `RecargoAutomaticoSchedulerTest`
  - Regresión validada con suite completa: `48 passed`.
- Regla de estatus para apartado sin cobro (lote)
  - Ajuste de negocio: crear orden de `Apartado` sin registrar pago ya no cambia el lote a `Apartado`; permanece `Disponible`.
  - El lote cambia a `Apartado` únicamente cuando existe al menos un `Pago` de tipo `Apartado` en la venta.
  - Se ajustó `LoteStatusService` para distinguir `Apartado` pendiente vs `Apartado` pagado al crear venta.
  - Se agregó sincronización en `PagoController` para actualizar estatus de lote en cobros de apartado.
  - Tests feature nuevos en `ApartadoLoteStatusTest` (sin cobro, cobro manual y auto-cobro).
  - Regresión validada con suite completa: `51 passed`.
- Wizard de cobranza + apartados separados (v1 operativa)
  - `pagos.create` migrado a wizard de 6 pasos (cliente, operación, tipo, monto, preview, confirmación).
  - Endpoints JSON de wizard activos: `pagos.wizard.clientes`, `pagos.wizard.operaciones`, `pagos.preview`.
  - Persistencia de cobranza con trazabilidad: `pago` cabecera + `pago_aplicaciones` por distribución.
  - Rutas legacy `pagos.newPago` y `pagos.newPagoCapital` redirigen con preselección al wizard.
  - Nuevo módulo visual legacy `apartados/revision`: alta de apartado, revisión de vencidos, cancelar y convertir.
  - Ajustes de permisos en `PagoController` para descuento en liquidación y overrides de abono a capital.
  - Plan documentado en `plans/WIZARD_COBRANZA_APARTADOS_SEPARADOS_PLAN.md`.
  - Pruebas nuevas en `PagoWizardFlowTest` + actualización de `DashboardQuickPagoTest`.
  - Regresión completa validada: `55 passed`.
- Wizard de cobranza UX pass (micro-interacciones)
  - Auto-avance: al elegir cliente pasa a paso 2 y si solo existe una operación elegible avanza a paso 3.
  - Botón `Siguiente` con estado de carga y bloqueo temporal durante llamadas async (`loadOperations`, `runPreview`).
  - Paso 4 agrega guía previa de `monto recomendado` y `monto mínimo requerido`.
  - `Cobro de apartado` autocompleta monto pendiente y bloquea edición manual.
  - Se añadió resumen lateral sticky (cliente, operación, tipo y monto) visible en pasos 3-6.
  - Regresión completa validada: `55 passed`.
- Wizard de ventas UX homogéneo con cobranza + guard de diferencia de plan
  - `ventas/create` ajustado a patrón UX de wizard: auto-avance (lote->cliente y cliente->tipo), botón `Siguiente` con estado `Cargando...`, y estado loading en modal de nuevo cliente.
  - Paso de plan de pagos con guía previa (`monto recomendado`, `monto mínimo requerido`, `diferencia actual`) en layout de una sola columna.
  - Regla de negocio en backend: no permite confirmar venta con diferencia de plan salvo override autorizado + motivo.
  - Nuevo permiso de dominio: `ventas.override_plan_diff`.
  - Pruebas nuevas: `VentaWizardPlanDiffOverrideTest` (rechazo sin override, rechazo sin permiso, motivo obligatorio, éxito con override autorizado).
  - Regresión focal validada:
    - `VentaWizardPlanDiffOverrideTest`: `4 passed`
    - `VentaAutoCobroToggleTest|VentaTipoVentaOptionsTest`: `8 passed`
- Wizard de ventas: retiro de `wizard-side-summary`
  - En `ventas/create` se eliminó el panel lateral `wizard-side-summary` por UX (menos ruido visual).
  - El contenido principal del wizard quedó en ancho completo (`col-12`) y se limpiaron referencias JS/CSS asociadas.
  - Validación rápida de sintaxis Blade/JS: `php -l resources/views/ventas/create.blade.php` sin errores.
- Wizard de cobranza: monto recomendado/mínimo unificado con backend + tarjetas de selección
  - Se corrigió desfase entre UI y validación real: `monto_minimo_ordinario` ahora se calcula en backend con la misma cascada (recargos, saldo a favor y parcialidades) y se envía en contexto.
  - Mensaje de rechazo en pago ordinario ahora reporta mínimo total requerido consistente con la cascada.
  - En paso 4 (`pagos/create`) los montos se movieron arriba y se volvieron clickeables:
    - `Monto recomendado`
    - `Monto mínimo requerido`
    - `Otro monto` (captura manual)
  - En `cobro_apartado` se mantiene bloqueo de captura manual y se deshabilita `Otro monto`.
  - Prueba de regresión ejecutada: `PagoWizardFlowTest` (`4 passed`).
- Catálogo de lotes dedicado + importación masiva CSV con template oficial
  - Nuevo módulo: `GET /configuracion/desarrollos/{id}/lotes` para listado/filtrado/edición en contexto de desarrollo.
  - Nuevos endpoints de importación:
    - `GET /configuracion/desarrollos/{id}/lotes/import/template`
    - `POST /configuracion/desarrollos/{id}/lotes/import/preview`
    - `POST /configuracion/desarrollos/{id}/lotes/import/commit`
  - `LoteImportService` centraliza headers/parseo/template (`HEADER_MAP`) para evitar drift.
  - Preview obligatorio con validación de headers y errores por fila.
  - Modo de duplicados por corrida: `cancelar|saltar|actualizar` (actualizar solo si lote existente está `Disponible`).
  - Commit con transacción todo-o-nada y lock defensivo en actualizaciones.
  - Migración nueva de atributos ampliados en `lotes` (superficie/frente/fondo, ubicación interna, precio mínimo, clave catastral, uso de suelo, topografía, servicios y bloqueo de venta).
  - UX: acceso directo al catálogo desde `Configuración > Desarrollo > General` y soporte de edición manual ampliada en `lotes/edit`.
  - Tests nuevos: `LotesImportCsvTest` (`6 passed`).
  - Regresión focal validada:
    - `ActiveDesarrolloSourceOfTruthTest`: `8 passed`
    - `ConfiguracionRecargosFinancierosTest`: `2 passed`
- Configuración > Desarrollo > General: catálogo editable de lotes
  - Se agregó botón `Ver catálogo de lotes` dentro de la card de lotes.
  - El catálogo despliega tabla con lote, manzana, estatus, precio y acción `Editar`.
  - `Editar` abre `lotes.edit` preservando contexto de configuración (`from_configuracion=1`, `redirect_desarrollo_id`).
  - `LoteController@update` ahora respeta ese contexto para regresar al tab `general` del desarrollo tras guardar.
- Configuración > Desarrollo > General: retiro de accesos de alta de lotes/manzanas
  - Se removieron de `General` los controles de `Nuevo lote`, `Nueva manzana` y acceso directo a catálogo de lotes para evitar duplicidad de entradas.
  - Las altas se movieron al módulo `Catálogo de lotes` con botones `Nuevo lote` y `Nueva manzana` en el header.
  - Se añadieron modales de alta en catálogo con contexto de desarrollo (`from_configuracion=1` + `redirect_catalogo_lotes=1`).
  - `LoteController` y `ManzanaController` ahora soportan redirección contextual al catálogo (`configuracion.desarrollo.lotes.catalogo`) al crear/editar desde ese flujo.
  - La edición desde catálogo pasa `redirect_catalogo_lotes=1` y al guardar/cancelar retorna al catálogo.
  - Regresión focal validada: `LotesImportCsvTest` (`6 passed`).
- Ajuste UX inmediato en `General > Lotes` (detalle de desarrollo)
  - Se reemplazó acción `Abrir mapa de lotes` por `Ver catálogo de lotes` para alinear el acceso con el flujo operativo actual.
- Catálogo de lotes: retiro de acción `Nueva manzana`
  - En `configuracion/desarrollos/{id}/lotes` se removió el botón `Nueva manzana` del header.
  - Se eliminó también el modal/JS asociado para evitar acciones ocultas sin entrada visible.
- Catálogo de lotes: acceso rápido a manzanas
  - Se agregó botón `Ver catálogo de manzanas` en el header de `configuracion/desarrollos/{id}/lotes`.
- Catálogo de lotes: modal `Nuevo lote` con atributos ampliados
  - Se añadieron al modal de alta los campos nuevos del lote (dimensiones, ubicación interna, precio mínimo, clave catastral, uso de suelo, topografía, servicios y bloqueo de venta).
  - `LoteController@store` ahora persiste esos campos en creación (aceptando nombres prefijados del modal y fallback a nombres legacy sin prefijo).
  - Validación focal: `ActiveDesarrolloSourceOfTruthTest` (`8 passed`).
- Mapa de lotes: detalle completo al seleccionar lote
  - El panel offcanvas de `mapa-lotes` ahora muestra ficha ampliada del lote (superficie, frente/fondo, etapa/sector, calle/número, precio mínimo, clave catastral, uso de suelo, topografía, servicios, bloqueo y notas).
  - El render JS ahora llena estos campos al seleccionar desde mapa o lista lateral, incluyendo casos `Vendido` con payload tipo `venta` o `lote`.
  - Validación rápida: sintaxis Blade OK + `ActiveDesarrolloSourceOfTruthTest` (`8 passed`).
- Ventas: bypass supervisado para precio bajo mínimo (maker-checker)
  - Se agregó regla base en backend (wizard + legacy): si `precio_final < precio_minimo_autorizado` en `Contado|Credito|Cesion`, la venta se bloquea sin autorización válida.
  - Nuevo endpoint interno: `POST /ventas/autorizar-precio-minimo` con re-login de supervisor (`supervisor_email`, `supervisor_password`, `motivo_autorizacion`).
  - Se emite token efímero (cache) ligado a solicitante + desarrollo + lote + tipo + precio final + motivo; consumo de un solo uso en `POST /ventas` con:
    - `precio_minimo_override_token`
    - `precio_minimo_override_reason`
  - Auditoría obligatoria:
    - `precio-minimo-override-authorized`
    - `precio-minimo-override-applied`
    - payload con solicitante, autorizador, lote, mínimo, final, diferencia y motivo.
  - Wizard `ventas/create` actualizado:
    - alerta visible cuando el precio cae bajo mínimo,
    - modal “Solicitar autorización” (credenciales + motivo),
    - bloqueo de avance en paso 3 sin autorización válida.
  - Permiso nuevo en seeder: `ventas.override_precio_minimo`.
  - Plan agregado: `plans/VENTAS_PRECIO_MINIMO_BYPASS_SUPERVISADO_PLAN.md`.
  - Pruebas nuevas: `VentaPrecioMinimoOverrideTest` (8 escenarios; bloqueo, autorización, token expirado/reutilizado/contexto, legacy, donación excluida).
  - Regresión focal validada:
    - `VentaPrecioMinimoOverrideTest`: `8 passed`
    - `VentaWizardPlanDiffOverrideTest`: `4 passed`
- UX copy en detalle de cliente (`clientes.show`)
  - En la tabla de lotes asignados, la acción que abre `ventas.detallepagos` cambió de `Realizar Pago` a `Ver detalle de venta` para reflejar mejor el destino real de la pantalla.
  - Ajuste visual menor sin cambios de lógica/rutas.
- Naming de detalle de venta (URL + títulos) sin rutas legacy
  - Ruta vigente: `GET /ventas/{venta_id}/detalle` (`ventas.detalle`) como única URL.
  - Se eliminó `GET /ventas/{venta_id}/detallepagos` (sin redirecciones de compatibilidad).
  - Se actualizaron links y redirecciones internas (controllers, vistas, tests) para usar `ventas.detalle`.
  - Título de la vista ajustado a `Ventas - Detalle de venta - Fracciona` y header `Detalle de venta`.
  - Validación focal ejecutada: `21 passed` (`VentaPrecioMinimoOverrideTest`, `VentaWizardPlanDiffOverrideTest`, `VentaAutoCobroToggleTest`, `ApartadoLoteStatusTest`).
- Fix post-rename de vista de detalle
  - Se corrigió error `View [ventas.detalle] not found` renombrando archivo de vista a `resources/views/ventas/detalle.blade.php` para coincidir con `VentaController@detallePagos`.
- Detalle de venta: retiro de botón `Pago a Capital`
  - En `ventas/detalle` se removió la acción superior `Pago a Capital` (flujo crédito), manteniendo solo acciones por orden y controles existentes.
- Retiro de `lotes.show` y enlace `Ver` en cliente
  - En `clientes.show` (tabla de lotes asignados) se eliminó la opción `Ver` de lote.
  - Se retiró la ruta `lotes.show` dejando `Route::resource('lotes')->except(['index','show'])`.
  - Se eliminó `LoteController@show` y la vista `resources/views/lotes/show.blade.php`.
  - En `lotes.index` se eliminó también la acción `Ver` para evitar links rotos.
- Corrección integral P0-P2 de cálculo, consistencia y calidad
  - Se creó `OrdenPagoBalanceService` como fuente única de adeudo/pagado por orden (aplicaciones + legacy directo sin doble conteo).
  - Se unificó el cálculo real de adeudo en dashboard, wizard/caja, recargos automáticos y sincronización de estatus de órdenes.
  - `VentaController@actualizarEstatusVenta` se movió a `VentaStatusService` con regla consistente (`Pagado` solo sin deuda activa `Pendiente|Parcial`).
  - Se eliminó borrado por GET (`/ventas/delete`) y se estandarizó `DELETE /ventas/{venta}` con consumo CSRF en frontend.
  - Conversión de apartado a `saldo_favor` ahora crea movimiento en ledger y corrige orden restante con `saldo_pendiente` real.
  - Se retiró acoplamiento entre controllers (`new PagoController()/VentaController()`), se extrajo lógica a `PagoLegacyService` y tickets a `PagoTicketService`.
  - Se reemplazó `request()->all()` en CRUD críticos (`Cliente`, `Manzana`) por validación explícita + payload validado.
  - Se endureció manejo de errores públicos (sin exponer `getMessage()`), manteniendo detalle técnico en logs.
  - Se normalizó entorno de pruebas a SQLite (`phpunit.xml`) y se ajustaron aserciones cross-DB de fechas.
  - Validación final: suite completa `81 passed`.
- Branding: actualización de logo del sistema
  - Se reemplazó el isotipo global en `resources/views/_partials/macros.blade.php` con el nuevo diseño solicitado.
  - Se ajustó proporción visual del brand en `public/assets/css/main.css` para evitar deformación del nuevo logo (`24x24`).
  - Se agregó favicon SVG de marca (`public/assets/img/favicon/logo-fracciona.svg`) y se enlazó en `commonMaster`.
  - Smoke test ejecutado: `tests/Feature/ExampleTest` (`1 passed`).
- Branding: ajuste final de isotipo (versión fondo negro + bloques blancos)
  - Se dejó el SVG exactamente con la estructura solicitada (`25x25`, círculo naranja y bloques blancos) en `resources/views/_partials/macros.blade.php`.
  - Se sincronizó la misma versión en favicon `public/assets/img/favicon/logo-fracciona.svg`.
  - Se alineó tamaño visual del logo en UI a `25x25` en `public/assets/css/main.css`.
- Branding: logo final aprobado (fondo naranja + 3 bloques grises)
  - Se actualizó el isotipo global en `resources/views/_partials/macros.blade.php` a la versión final compartida por usuario.
  - Se sincronizó favicon en `public/assets/img/favicon/logo-fracciona.svg`.
  - Smoke test ejecutado: `tests/Feature/ExampleTest` (`1 passed`).
- Branding: ajuste inmediato de logo (versión minimal solicitada)
  - Se actualizó isotipo global y favicon a fondo naranja con único bloque blanco en cuadrante inferior derecho.
  - Archivos: `resources/views/_partials/macros.blade.php`, `public/assets/img/favicon/logo-fracciona.svg`.
  - Smoke test ejecutado: `tests/Feature/ExampleTest` (`1 passed`).
- Branding: logo final definitivo (composición solicitada por usuario)
  - Se aplicó SVG literal final en logo global y favicon.
  - Composición: círculo gris (`cx=75, cy=75, r=20`) + tres cuadrantes naranjas (`0,0`, `50,0`, `0,50`).
  - Archivos: `resources/views/_partials/macros.blade.php`, `public/assets/img/favicon/logo-fracciona.svg`.
  - Smoke test ejecutado: `tests/Feature/ExampleTest` (`1 passed`).
- Detalle de venta: recálculo explícito de plan y bloqueo de edición manual por renglón
  - Se agregó acción `Recalcular plan` en `ventas/{id}/detalle` (modal con `monto_financiar`, `interes_anual`, `motivo_recalculo`).
  - Nuevo endpoint backend: `POST ventas/{venta}/recalcular-plan` (`ventas.recalcular_plan`) con:
    - validación de acceso por desarrollo,
    - restricción a `tipo_venta=Credito`,
    - transacción + `FOR UPDATE` de venta y mensualidades pendientes/parciales,
    - recálculo central mediante `PagoLegacyService::refactorizarOrdenesPago`,
    - sincronización de estatus (`VentaStatusService`) y auditoría (`ventas.recalcular-plan`).
  - En tabla de órdenes se removió `Editar` por fila para evitar desajustes por edición aislada de cuotas.
  - `PagoController@updateOrdenPago` ahora bloquea cambios de `cuota_mensual` y devuelve mensaje dirigido a usar `Recalcular plan`.
  - Pruebas agregadas en `CorreccionesConsistenciaTest`:
    - recálculo refluye mensualidades pendientes de forma consistente,
    - edición manual de cuota por orden queda bloqueada.
  - Validación:
    - `tests/Feature/CorreccionesConsistenciaTest.php`: `9 passed`
    - suite completa: `85 passed`.
- Cobranza/ventas: corrección P0 de estatus en edición de pago + lock pesimista en flujo legacy
  - `PagoController@updatePago` ahora recalcula estatus de orden con fuente real (`syncOrderStatusFromPayments`) y dentro de transacción.
  - Se eliminó lógica frágil por resta directa `cuota_mensual - monto_del_pago_editado`.
  - En `PagoController@store` (flujo legacy/manual), se bloquea la orden seleccionada con `FOR UPDATE` antes de validar adeudo y aplicar cobro.
  - En distribución mensualidad+recargos (`applyMensualidadPaymentByConfig`) también se bloquean recargos relacionados (`lockForUpdate`) para serializar cobros simultáneos.
- Ticket de pago: saldo del contrato basado en órdenes de pago
  - `PagoTicketService` ahora calcula `costo_total`, `total_abonado`, `saldo_pendiente` y `saldo_anterior` con balance real de órdenes (`OrdenPagoBalanceService`), no con `monto_total - sum(pagos.monto)`.
  - Para `saldo_anterior`, se usa monto realmente aplicado a órdenes por el pago actual (líneas `pago_aplicaciones`), evitando inflar saldo cuando hay excedente a saldo a favor.
  - Ajuste menor en vista de ticket: fecha usa `fecha_pago` en lugar de `fecha`.
- Pruebas agregadas/actualizadas
  - `CorreccionesConsistenciaTest`:
    - edición de pago mensualidad recalcula estatus correcto por balance real;
    - ticket usa balance por órdenes y no monto bruto del pago.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`7 passed`)
    - `./vendor/bin/sail artisan test` (`83 passed`).
- Recalcular plan (detalle de venta) ajustado a interés + mensualidades pendientes
  - `POST /ventas/{venta}/recalcular-plan` ahora valida y opera solo con `interes_anual`, `mensualidades_pendientes` y `motivo_recalculo` (sin captura de `monto_financiar`).
  - Recálculo con lock transaccional de venta + mensualidades `Pendiente|Parcial`, soporte de aumento/disminución de mensualidades y guardrail por historial de pago en órdenes a cancelar.
  - Bloqueo funcional: si la reducción exige cancelar una orden con historial (`pagos`/`pago_aplicaciones`), se rechaza con mensaje controlado.
  - Se restauró acción `Editar` por renglón en `ventas.detalle`, limitada a `fecha_vencimiento` y `notas` (cuota/interés permanecen bloqueados).
  - `PagoController@updateOrdenPago` mantiene guardrail de negocio para impedir edición de `cuota_mensual`/`interes` fuera de recálculo global.
  - Se creó plan dedicado: `plans/RECALCULO_INTERES_MENSUALIDADES_EDICION_ORDENES_PLAN.md`.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`12 passed`).
- Recalcular plan: base financiera corregida a capital pendiente real
  - En `VentaController@recalcularPlan`, la base ya no usa adeudo total de cuota (capital+interés) para redistribuir.
  - Ahora calcula `capital pendiente operativo` por mensualidad como:
    - `capital_programado` (`pago_a_capital`) menos
    - `capital ya abonado` (monto pagado en la orden descontando interés programado del mes).
  - Efecto: el recálculo se alinea a la regla de negocio “costo del lote menos total abonado a capital”.
  - Prueba nueva: `test_recalcular_plan_uses_pending_capital_instead_of_total_due_with_interest`.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`13 passed`).
- Detalle de venta: base de recálculo visible en modal + guardrail visual
  - `VentaController@detallePagos` ahora expone:
    - `capitalPendienteRecalculo` (misma fuente de verdad que `recalcularPlan`)
    - `sinCapitalPendienteRecalculo` (flag visual para bloqueo en UI).
  - En `ventas.detalle` (modal `Recalcular plan`) se agregó bloque read-only:
    - “Base de recálculo (capital pendiente): $X”
    - leyenda de cálculo automático.
  - Si la base es `<= 0`, se muestra mensaje “Sin capital pendiente para recalcular.” y botón `Recalcular plan` queda deshabilitado.
  - Se mantiene contrato HTTP sin cambios (`interes_anual`, `mensualidades_pendientes`, `motivo_recalculo`).
  - Pruebas nuevas:
    - `test_detalle_modal_shows_recalculo_capital_base_and_no_monto_financiar_input`
    - `test_detalle_modal_disables_recalcular_button_when_capital_base_is_zero`
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`15 passed`).
- Ventas wizard: corrección de validación de “diferencia de plan” para crédito
  - Causa detectada: la validación comparaba `total_programado` vs `precio_final` para todos los tipos; en crédito `total_programado` incluye interés y por diseño puede ser mayor.
  - Regla nueva:
    - `Contado/Cesion`: se mantiene comparación por `total_programado`.
    - `Credito`: la comparación se hace por `capital_programado` vs `precio_final` (no por total con interés).
  - Backend (`VentaController@storeWizard`): nuevo cálculo base `resolvePlanComparableTotalForDiff`.
  - Frontend (`ventas/create`): guía/mensajes y bloqueo en paso 4 ahora usan “capital programado” para crédito.
  - Prueba nueva:
    - `test_wizard_credit_does_not_require_plan_diff_override_when_capital_matches_precio_final`.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/VentaWizardPlanDiffOverrideTest.php` (`5 passed`)
    - `./vendor/bin/sail artisan test --filter='recalcular_plan_uses_pending_capital_instead_of_total_due_with_interest|detalle_modal_shows_recalculo_capital_base_and_no_monto_financiar_input' tests/Feature/CorreccionesConsistenciaTest.php` (`2 passed`).
- Refactoring arquitectónico: Fase 1 (VentaController) + Fase 2 (PagoController) → Actions
  - VentaController: 1,673 → 431 líneas. Lógica de negocio extraída a Actions en `app/Actions/Venta/`:
    - `AutorizarPrecioMinimoAction` — flujo maker-checker de precio mínimo con token efímero Cache::pull
    - `StoreVentaWizardAction` — wizard store con auto-cobro por fila, plan diff, precio mínimo
    - `StoreVentaLegacyAction` — store legacy (Contado/Credito/Apartado/Donacion)
    - `RecalcularPlanAction` — recálculo de plan con lockForUpdate, redistribución y auditoría
  - PagoController: 1,270 → 734 líneas. Lógica extraída a `app/Actions/Pago/`:
    - `StorePagoLegacyAction` — pago legacy con lockForUpdate, distribución mensualidad+recargos, syncVentaFinancing
    - `StoreWizardPagoAction` — pago wizard (cobro apartado + venta) con verificación de permisos públicos
  - Todos los lockForUpdate y DB::transaction críticos se preservaron con exactitud.
  - Permisos (`canApplyDiscountOnLiquidation`, `canForceAbonoCapital`, `canOverrideAbonoPolicy`) expuestos como métodos públicos en StoreWizardPagoAction para uso desde create().
  - `RecalcularPlanAction::resolveCapitalPendientePublic()` agregado para acceso desde detallePagos() del controller.
  - Plan documentado en `plans/REFACTORING_ARQUITECTURA_ACTIONS_QUERIES_PLAN.md`.
  - Regresión validada: suite completa `99 passed`.
- Ventas wizard: tabla de plan con desglose visible de amortización
  - En `ventas/create` la tabla de plan de pagos muestra columnas explícitas `Pago a capital` e `Interés` para desglosar cada mensualidad.
  - El render JS de filas usa `capital`/`interes` cuando existen (tabla de amortización) y mantiene fallback (`monto`/`0`) para conceptos no crédito.
  - Ajuste de prueba en `VentaTipoVentaOptionsTest` para cubrir presencia de ambos encabezados en la vista.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/VentaTipoVentaOptionsTest.php` (`2 passed`)
    - `./vendor/bin/sail artisan test tests/Feature/VentaWizardPlanDiffOverrideTest.php` (`5 passed`).
- Política de cuotas cerradas por desarrollo (amortización de crédito)
  - Se agregaron campos `cuotas_cerradas_*` en `configuracion_financiera` para activar política por desarrollo:
    - `activo`, `unidad`, `modo`, `estrategia_residual`, `permitir_centavos_ultima`.
  - `ConfiguracionController@updateFinanciero` y `ConfiguracionFinanciera` actualizados para validación/persistencia/casts.
  - Tab financiero (`configuracion/desarrollo-detail`) ahora incluye bloque “Cuotas cerradas (crédito)”.
  - `VentaPlanPagosService` quedó como fuente única para desglose de mensualidades con política de redondeo:
    - mensualidades 1..N-1 redondeadas a múltiplo configurado;
    - última cuota absorbe residual (con centavos permitidos en default).
  - Integración de política en:
    - preview `POST /ventas/tabla-amortizacion` (`wizard_mode=1`),
    - alta wizard `POST /ventas`,
    - recálculo `POST /ventas/{venta}/recalcular-plan`,
    - flujo legacy de crédito vía `PagoLegacyService` (sin divergencia de cálculo).
  - UX informativa:
    - leyenda de política activa en `ventas/create`,
    - leyenda en modal de `Recalcular plan` en `ventas/detalle`.
  - Pruebas agregadas/actualizadas:
    - Unit: `VentaPlanPagosServiceTest`.
    - Feature: `ConfiguracionRecargosFinancierosTest`, `VentaTipoVentaOptionsTest`, `CorreccionesConsistenciaTest`.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/CorreccionesConsistenciaTest.php tests/Unit/VentaPlanPagosServiceTest.php tests/Feature/VentaTipoVentaOptionsTest.php tests/Feature/ConfiguracionRecargosFinancierosTest.php` (`24 passed`)
    - `./vendor/bin/sail artisan test tests/Feature/VentaWizardPlanDiffOverrideTest.php tests/Feature/VentaPrecioMinimoOverrideTest.php` (`13 passed`).
- IVA de recargo automático editable por desarrollo
  - Se agregó `recargo_iva_porcentaje` en `configuracion_financiera` (default `16.00`) para eliminar el 16% fijo en recargos automáticos.
  - `ConfiguracionController@updateFinanciero` ahora valida/persiste `recargo_iva_porcentaje` (`0..100`, hasta 2 decimales) y conserva valor previo si no se envía; en alta usa default `16.00`.
  - `RecargoAutomaticoService` dejó de usar constante hardcodeada y ahora calcula IVA con `recargo_iva_porcentaje / 100` cuando `recargo_iva=true`.
  - UI financiera actualizada:
    - copy de switch: `Aplicar IVA en recargo automático` (sin porcentaje fijo),
    - nuevo input `% IVA recargo`,
    - visibilidad/habilitación dinámica del input basada en toggle `recargo_iva`.
  - Pruebas actualizadas:
    - `ConfiguracionRecargosFinancierosTest`: persistencia de porcentaje, preservación de valor cuando no se envía, validación de rango inválido y validación de más de 2 decimales.
    - `RecargoAutomaticoSchedulerTest`: cálculo con porcentaje configurable y caso `recargo_iva=false` sin efecto del porcentaje.
  - Validación ejecutada:
    - `./vendor/bin/sail artisan test tests/Feature/ConfiguracionRecargosFinancierosTest.php tests/Feature/RecargoAutomaticoSchedulerTest.php` (`7 passed`).
- Refactoring arquitectónico completo — Actions, Query Objects, Thin Controllers (Fases 1-5)
  - **Fase 1 — VentaController** (1,673 → 431 líneas):
    - `StoreVentaWizardAction`, `StoreVentaLegacyAction`, `RecalcularPlanAction`, `AutorizarPrecioMinimoAction` creados en `app/Actions/Venta/`.
  - **Fase 2 — PagoController** (1,269 → 734 líneas):
    - `StoreWizardPagoAction`, `StorePagoLegacyAction` creados en `app/Actions/Pago/`.
  - **Fase 3 — Query Objects** en `app/Queries/`:
    - `OrdenesConSaldoQuery` (byVenta, pendingMensualidadesByVenta, pendingByDesarrollo)
    - `VentasConDetalleQuery` (forDesarrollo, forDesarrolloConOrdenes)
    - `PagosIndexQuery` (apply con filtros de tipoPago y fecha)
    - `LotesDisponiblesQuery` (forDesarrollo, withSearch)
  - **Fase 4 — ConfiguracionController / DashboardController**:
    - `ImportLotesAction` en `app/Actions/Configuracion/`
    - `GetDashboardMetricsAction` en `app/Actions/Dashboard/`
    - DashboardController 288 → 116 líneas.
  - **Fase 5 — Deuda técnica en Services**:
    - `ConvertirApartadoAVentaAction` en `app/Actions/Apartado/`; `ApartadoService::convertirAAventa()` es thin wrapper.
    - `RecargoAutomaticoService::apply()` descompuesto en privados: `queryOrdersForDesarrollo`, `calculateRecargoAmount`, `createRecargoOrden` (con `UniqueConstraintViolationException` para concurrencia).
    - `PagoTicketService`: `file_exists/mkdir` reemplazado por `Storage::disk('public')->put()`.
  - Validación: `php artisan test` → **99 tests, 508 assertions pasando** en todas las fases.
- Ajustes de consistencia posteriores a validación del plan de refactor
  - `StoreWizardPagoAction`: checks de permisos endurecidos con patrón defensivo (`admin` || `can(...)` con `try/catch (\Throwable)` + fallback `false`) para tolerar permisos no sembrados y evitar 500 en `pagos.create`.
  - `ConvertirApartadoAVentaAction`: en destino `anticipo/enganche`, la orden inicial marcada como `Pagado` ahora persiste `saldo_pendiente=0` (evita contradicción contable por saldo residual en orden liquidada).
  - `CorreccionesConsistenciaTest`: nuevo caso `test_apartado_conversion_to_anticipo_marks_initial_order_fully_paid` para cubrir regresión del saldo en orden inicial de conversión.
  - Estado del plan `plans/REFACTORING_ARQUITECTURA_ACTIONS_QUERIES_PLAN.md` actualizado a estatus real (fases parciales vs completas).
  - Validación ejecutada:
    - `php artisan test tests/Feature/CorreccionesConsistenciaTest.php tests/Feature/PagoWizardFlowTest.php` (`22 passed`).
- Refactor Fase 2 (PagoController) — extracción de endpoints críticos a Actions
  - Nuevos actions en `app/Actions/Pago/`:
    - `PreviewPagoAction` (lógica de preview apartado/venta + permisos de descuento/abono override).
    - `StorePagoCapitalAction` (flujo `pagoCapital` con `DB::transaction` en action).
    - `UpdatePagoAction` (flujo `updatePago` con lock pesimista + sync de estatus/financiamiento/lote).
  - `PagoController` ahora delega:
    - `preview()` → `PreviewPagoAction`
    - `pagoCapital()` → `StorePagoCapitalAction`
    - `updatePago()` → `UpdatePagoAction`
  - Resultado arquitectónico:
    - `PagoController` sin `DB::transaction()` ni `lockForUpdate()`.
    - LOC de `PagoController`: `698` → `496`.
  - Validación ejecutada:
    - `php artisan test tests/Feature/PagoWizardFlowTest.php tests/Feature/DashboardQuickPagoTest.php tests/Feature/CorreccionesConsistenciaTest.php` (`31 passed`).
- Refactor Fase 2 (PagoController) — adelgazamiento adicional hasta meta LOC
  - Nuevos actions agregados en `app/Actions/Pago/`:
    - `BuildPagoCreateViewDataAction` (prefill + dataset de `pagos.create`)
    - `SearchWizardClientesAction` (búsqueda de clientes para wizard)
    - `BuildWizardOperacionesAction` (operaciones elegibles por cliente/fecha)
    - `UpdateOrdenPagoAction` (actualización de fecha/notas + auditoría)
    - `GetDetallePagoAction`, `GetPagoAction`, `ResolveAbonoTicketPathAction` (lecturas/archivo delegadas)
  - `PagoController` ahora delega `create`, `wizardClientes`, `wizardOperaciones`, `updateOrdenPago`, `getDetallePago`, `getPago`, `verAbonoTicket` a Actions.
  - Resultado arquitectónico:
    - LOC de `PagoController`: `496` → `339` (meta `<350` cumplida).
    - `PagoController` se mantiene sin `DB::transaction()` ni `lockForUpdate()`.
  - Validación ejecutada:
    - `php artisan test tests/Feature/PagoWizardFlowTest.php tests/Feature/DashboardQuickPagoTest.php tests/Feature/CorreccionesConsistenciaTest.php` (`31 passed`).
- Refactor Fase 2 (PagoController) — cierre de acciones clave del plan
  - Nuevos actions agregados:
    - `StorePagoAction` (dispatcher de `POST /pagos` wizard/legacy).
    - `GenerarTicketAction` (wrapper de ticket sobre `PagoTicketService`).
  - `PagoController` ahora delega:
    - `store()` → `StorePagoAction`.
    - `printTicket()` → `GenerarTicketAction`.
  - Resultado arquitectónico final en Fase 2:
    - LOC de `PagoController`: `339` → `316`.
    - sin `DB::transaction()` ni `lockForUpdate()` en controller.
    - criterio de meta `<350` cumplido con margen.
  - Validación ejecutada:
    - `php artisan test tests/Feature/PagoWizardFlowTest.php tests/Feature/DashboardQuickPagoTest.php tests/Feature/CorreccionesConsistenciaTest.php` (`31 passed`).
- Refactor Fase 3 (Query Objects) — adopción en services objetivo
  - Se reemplazaron queries duplicadas de órdenes `Pendiente|Parcial` por `OrdenesConSaldoQuery` en:
    - `PagoLegacyService` (`getDetalleDeuda`, `refactorizarOrdenesPago`)
    - `CobranzaWizardService` (locks de `applyVentaPago`, recalculo de pendientes en `applyAbonoCapital`, obtención de pendientes en `pendingOrdersWithDue`, conteo en `syncVentaStatus`)
    - `RecargoAutomaticoService` (`queryOrdersForDesarrollo`)
  - `OrdenesConSaldoQuery` extendido con firma explícita `byDesarrolloVencidas(int $desarrolloId, string $fecha)`.
  - `GetDashboardMetricsAction` ahora usa `OrdenesConSaldoQuery::byDesarrolloVencidas(...)` en cartera vencida.
  - Validación ejecutada:
    - `php artisan test tests/Feature/RecargoAutomaticoSchedulerTest.php tests/Feature/DashboardQuickPagoTest.php tests/Feature/PagoWizardFlowTest.php tests/Feature/CorreccionesConsistenciaTest.php` (`34 passed`).
    - `php artisan test tests/Feature/DashboardQuickPagoTest.php tests/Feature/CorreccionesConsistenciaTest.php tests/Feature/RecargoAutomaticoSchedulerTest.php` (`30 passed`).
- Refactor Fase 1/Fase 4 — cierre de brechas del plan
  - `VentaController` quedó bajo meta de plan (`365` LOC) con extracción de composición de view-data a `app/Actions/Venta/BuildVentaCreateViewDataAction.php`.
  - `LoteController::store` dejó de contener lógica de construcción masiva; ahora delega a `app/Actions/Lote/CreateMultipleLotesAction.php`.
  - `CreateMultipleLotesAction` centraliza:
    - parsing de `identificador` múltiple (coma),
    - fallback de campos `lote_*` vs keys legacy,
    - validación de manzana por desarrollo,
    - auditoría de creación masiva,
    - retorno explícito de contexto (`from_configuracion`, `redirect_desarrollo_id`, `redirect_catalogo_lotes`) para resolución de redirección en controller.
  - `plans/REFACTORING_ARQUITECTURA_ACTIONS_QUERIES_PLAN.md` actualizado: Fase 1 y Fase 4 marcadas como completadas.
  - Validación ejecutada:
    - `php -l app/Actions/Lote/CreateMultipleLotesAction.php` (OK)
    - `php -l app/Actions/Venta/BuildVentaCreateViewDataAction.php` (OK)
    - `php -l app/Http/Controllers/LoteController.php` (OK)
    - `php -l app/Http/Controllers/VentaController.php` (OK)
    - `php artisan test tests/Feature/ActiveDesarrolloSourceOfTruthTest.php tests/Feature/LotesImportCsvTest.php tests/Feature/VentaTipoVentaOptionsTest.php tests/Feature/VentaWizardPlanDiffOverrideTest.php` (`22 passed`).
- Corrección de métricas en `ventas/create` (monto financiado vs total programado) + persistencia wizard
  - UI paso 4 (`resources/views/ventas/create.blade.php`):
    - tarjeta `Monto financiado` ahora se calcula por capital real (sin interés),
    - excluye `Recargo` y, en la tarjeta de crédito, conceptos de enganche/apartado/anticipo,
    - `Total programado` se mantiene como suma bruta de `monto`.
  - Backend wizard (`app/Actions/Venta/StoreVentaWizardAction.php`):
    - `venta.monto_financiar` dejó de usar suma bruta pendiente,
    - ahora persiste capital pendiente real (sin interés), respetando `auto_cobro_filas_hoy`,
    - excluye `Recargo` y, en `Credito`, también `Enganche/Apartado/Anticipo` para reflejar capital financiado.
  - Cobertura de regresión en `tests/Feature/VentaWizardPlanDiffOverrideTest.php`:
    - nuevo caso crédito + auto-cobro ON,
    - nuevo caso crédito + auto-cobro OFF,
    - nuevo caso con fila `Recargo` que no incrementa `monto_financiar`.
  - Validación ejecutada:
    - `php -l app/Actions/Venta/StoreVentaWizardAction.php` (OK)
    - `php -l resources/views/ventas/create.blade.php` (OK)
    - `php -l tests/Feature/VentaWizardPlanDiffOverrideTest.php` (OK)
    - `php artisan test tests/Feature/VentaWizardPlanDiffOverrideTest.php tests/Feature/VentaAutoCobroToggleTest.php tests/Feature/VentaTipoVentaOptionsTest.php` (`17 passed`)
    - `php artisan test tests/Feature/PagoWizardFlowTest.php tests/Feature/CorreccionesConsistenciaTest.php tests/Feature/DashboardQuickPagoTest.php` (`31 passed`).
- Wizard de cobranza: visibilidad de lote con deuda futura + pago adelantado de mensualidad
  - Backend (`CobranzaWizardService`):
    - separación explícita de `deuda_exigible_hoy` vs `deuda_total_programada`,
    - `buildClienteOperations` ahora incluye ventas con adeudo programado (aunque no haya exigible al corte),
    - nuevos campos de contexto: `total_pendiente_programado`, `total_liquidar_programado`, `proxima_mensualidad_futura_*`, `permite_parcial_mensualidad`,
    - nueva matriz de tipos: `pago_ordinario` (solo exigible), `abono_capital` (sin recargos/vencidos al corte y con capital pendiente), `liquidacion_total` (deuda programada), `pago_adelantado_mensualidad` (próxima mensualidad futura y sin recargos/vencidos al corte),
    - preview/apply para `pago_adelantado_mensualidad` con validaciones de parcialidad y no excedente.
  - UI (`pagos/create`):
    - nuevo tipo de pago `Pago adelantado mensualidad`,
    - copy de vacío en paso 2 orientado a “sin adeudo pendiente”,
    - guía de monto adaptada para adelantado y liquidación programada,
    - contexto de operación muestra próxima mensualidad futura y total programado.
  - Compatibilidad de prefill:
    - `BuildPagoCreateViewDataAction` ya normaliza `pago_adelantado_mensualidad`.
  - Pruebas agregadas en `PagoWizardFlowTest`:
    - operación visible con mensualidades solo futuras,
    - preview adelantado exitoso a próxima mensualidad,
    - rechazo por parcialidad deshabilitada,
    - rechazo por excedente,
    - persistencia/aplicación de pago adelantado en orden futura.
  - Validación ejecutada:
    - `php artisan test tests/Feature/PagoWizardFlowTest.php tests/Feature/DashboardQuickPagoTest.php` (`18 passed`)
    - `php artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`18 passed`).
- Corrección integral de cálculo y consistencia en cobranza/updatePago (abril 2026)
  - `CobranzaWizardService`: liquidación total ahora distribuye por fuente (`saldo_favor`, `descuento`, `pago`) con tope de descuento al adeudo remanente; sin sobreaplicación por orden.
  - `CobranzaWizardService`: abono a capital (`reducir_mensualidad`/`reducir_plazo`) recalcula `monto_programado`, `pago_a_capital`, `interes` y `saldo_pendiente` con política de cuotas cerradas + interés vigente.
  - `PagoController@updatePago` + `UpdatePagoAction`: validación explícita y bloqueo de sobrepago en edición de pagos legacy directos.
  - `PagosIndexQuery`: filtro `mes` corregido para considerar rango mensual con año (evita mezclar años).
  - `RecargoAutomaticoService`: metadata de recargo persiste `base_amount` real (no neto del recargo).
  - Pruebas agregadas/ajustadas:
    - `tests/Feature/PagoWizardFlowTest.php`
    - `tests/Feature/CorreccionesConsistenciaTest.php`
    - `tests/Feature/RecargoAutomaticoSchedulerTest.php`
    - `tests/Feature/PagosIndexFiltersTest.php` (nuevo)
  - Validación ejecutada: `php artisan test` (`114 passed`).
- Consistencia de métodos de pago + conversión de apartado (abril 2026)
  - Se creó `app/Support/MetodoPagoCatalog.php` como fuente única para normalizar (`Efectivo|Transferencia|Deposito|Otro`) y evitar duplicación/hardcode en Actions.
  - Actions migrados a catálogo único:
    - `app/Actions/Pago/StoreWizardPagoAction.php`
    - `app/Actions/Pago/StorePagoLegacyAction.php`
    - `app/Actions/Pago/UpdatePagoAction.php`
    - `app/Actions/Venta/StoreVentaWizardAction.php`
    - `app/Actions/Venta/StoreVentaLegacyAction.php`
  - `StorePagoCapitalAction` ahora normaliza método, valida monto > 0 y fecha obligatoria antes de persistir.
  - `ConvertirApartadoAVentaAction` ya no hardcodea `Efectivo`; toma `metodo_pago` del cobro real de apartado (`ApartadoCobro`) con fallback seguro a `Efectivo` si falta historial legacy.
  - Vistas homologadas al catálogo único de métodos de pago:
    - `resources/views/pagos/create.blade.php`
    - `resources/views/pagos/createPagoCapital.blade.php`
    - `resources/views/pagos/index.blade.php`
    - `resources/views/ventas/detalle.blade.php`
    - `resources/views/ventas/create.blade.php`
  - Pruebas nuevas/actualizadas:
    - `tests/Unit/MetodoPagoCatalogTest.php` (nuevo)
    - `tests/Feature/CorreccionesConsistenciaTest.php` (2 casos nuevos de conversión apartado)
    - `tests/Feature/PagosIndexFiltersTest.php` (nuevo caso para catálogo de métodos)
  - Validación ejecutada: `php artisan test` (`120 passed`).
- Configuración financiera global con override por desarrollo (2026-04-28)
  - Nueva tabla `configuracion_financiera_general` y columna `override_financiero_activo` en `configuracion_financiera`; las filas existentes quedan con override activo.
  - Nuevo `ConfiguracionFinancieraService` para resolver configuración efectiva: override activo por desarrollo, configuración global o defaults operativos.
  - Migradas lecturas críticas a resolver: ventas wizard/legacy, caja/preview, apartados, recálculo, cuotas cerradas, recargos automáticos y view-data.
  - UI:
    - `/configuracion?tab=financiero` permite editar configuración financiera general.
    - `configuracion/desarrollos/{id}?tab=financiero` agrega switch `Usar configuración financiera propia`; apagado hereda global y deshabilita edición.
  - Tests agregados:
    - `tests/Feature/ConfiguracionFinancieraGlobalTest.php`
  - Validación ejecutada:
    - `php -l` en controladores, servicios, actions, modelo y test nuevos/tocados.
    - `php artisan view:cache` y `php artisan view:clear`.
    - `php artisan test tests/Feature/ConfiguracionFinancieraGlobalTest.php` (`4 passed`).
    - `php artisan test tests/Feature/ConfiguracionRecargosFinancierosTest.php tests/Feature/VentaAutoCobroToggleTest.php tests/Feature/PagoWizardFlowTest.php` (`26 passed`).
    - `php artisan test tests/Feature/CorreccionesConsistenciaTest.php` (`24 passed`).
    - `php artisan test tests/Feature/RecargoAutomaticoSchedulerTest.php` (`3 passed`).
