FACTURA_DIAN.FECHAFACT is DATE type, incompatible with datetime strings.
CAST to TIMESTAMP allows comparison with :fecha_ini/:fecha_fin params.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously used IDRECEPCION to fetch only one reception's services.
Now resolves PREFIJO+NUM_FACTURA from the reception, then fetches all
receptions sharing that factura so the full detallePedido is sent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Joins FACTURA_DIAN to get the actual invoice date. Receptions spread
across multiple days now appear together when their factura was billed
on the selected date. Excludes annulled invoices (ANULADA != 'F').
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of crashing with 500, catches the error and exposes it in
ventas_gen_errors field so it can be diagnosed from the browser.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows IDRECEPCION, PREFIJO, NUM_FACTURA, CODCONTRATO, N_EXAMENES
for all CMXC receptions on a given date.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ventas_raw = filas de Firebird antes de filtrar
ventas_grupos_total = grupos por factura antes del filtro
ventas_filtradas = grupos excluidos con motivo (sin_factura / excluido_ventas)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace dict comprehension with explicit loop so that non-list or empty
grupo values are safely skipped, preventing KeyError: 0 on v[0].
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A single CMXC invoice (e.g. CMXC-307) can have multiple receptions.
Previously each reception was sent as a separate ventas, causing TNS
to accept the first and reject the rest with "ya existe" — leaving
only 1/N of the services registered.
Now agrupar_por_factura groups all receptions sharing the same
NUM_FACTURA into one ventas JSON with all their services in
detallePedido. One factura = one send.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
For terceros, _guardar_envio stores the automation date in the factura
field (not a patient id), so COALESCE(factura, cedula) still collapsed
all terceros into one row. Now GROUP BY uses cedula for tipo=terceros
and factura for transaccion/ventas. Template hides the date in the
factura column for terceros rows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GROUP BY COALESCE(factura, cedula) fixes terceros (factura=NULL)
collapsing into one row — each paciente now gets its own row.
CASE WHEN in estado_final explicitly prioritizes success > warning > error
instead of relying on alphabetical MAX which returned warning over success.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Grouping by cedula caused envíos with null/different cedula to split
into separate groups, making success envíos invisible — factura 4989
showed error persistente despite having a success send.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Groups envios by factura+tipo per day and shows estado_final
(exitoso if any send succeeded, error persistente if all failed).
Supports inline reenvío and JSON detail modal. Added to sidebar
under Historial TNS and as TNS submodule link.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contrato 050 agrupa ~30 laboratorios y clínicas externas (CMXC/LHXC).
Debe enviarse a RDA pero no a Ventas.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _parse_tns_resp retorna 'success'|'warning'|'error' en lugar de bool
- 'ya existe/registrado/autorización' → warning (sin reenvío, no es error real)
- errores reales → error (con reenvío)
- Guarda JSON crudo completo en respuesta_api
- logs.html: badge amarillo para warning, verde para success, rojo para error
- Filtro de historial incluye opción 'warning'
- reenvío en logs.py solo disponible para status='error'
- reenvío en logs.py usa misma lógica _parse_tns_resp y soporta ventas
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bool(400) era True en Python, haciendo que errores de validación de ASP.NET
(status:400, errors:{campo:[msg]}) se guardaran como success. Ahora:
- status bool → ok directamente
- status int → ok si < 400
- errors dict → mensaje legible "campo: mensaje"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TNS requiere ?codigosucursal= en /v2/facturacion/Ventas/Crear igual que en RdaPaciente/Insertar.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- _parse_tns_resp() centraliza parsing: lee status/data.success del body JSON
- "ya esta registrado", "ya existe autorización" → ok=True (no bloquea RDA)
- Aplica en los 4 pasos; terceros_fallidos solo acumula errores reales
- Elimina script tmp buscar_paciente.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Acumula COD_PACIENTE en terceros_fallidos cuando paso1 falla.
En paso2 y paso3, si el paciente está en esa lista se omite el envío
con mensaje claro "Omitido: tercero no creado en TNS".
Evita el error confuso "paciente no existe" en TNS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Agrega columna cedula a tabla envios (migración automática)
- _guardar_envio almacena la cédula en los 4 pasos de automation
- pac_map (COD_PACIENTE→DOCIDENT) para RDA/preserv/ventas
- logs.py busca por cedula LIKE en vez de idrecepcion/contrato
- logs.html etiqueta el input como "Cédula paciente"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- POST /envios/erp/sync-diagnosticos: reads all 12422 diagnosticos from
Firebird, sends to WhatsApp in batches of 500 via ingest_diagnosticos.php
- envios_erp.html: new "Migración CIE-10" card with Migrar button and result
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supports ?q=filter and ?limit=N. Returns total count, column names,
and list of {cod, concepto} rows — used to plan DIAGNOSTICO migration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PRECIO and VALORTOTAL are Decimal from fdb driver; convert via _safe_num()
- HORAINICIORECEPCION is a datetime object; use _fmt_hora_str() for HH:MM:SS
- _parse_hora() now handles datetime objects directly (no str() roundtrip)
- Same fixes applied to pacientes.py exam builder
- sync-now endpoint catches exceptions and returns traceback as JSON
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FECHA_RECEPCION is a TIMESTAMP field, so comparing directly with
CURRENT_DATE (DATE) always returns 0 rows in Firebird. Cast to DATE first.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shows recent recepciones without filters, CURRENT_DATE from Firebird,
and counts with/without NUM_FACTURA filter to diagnose zero-result sync.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- POST /envios/erp/sync-now?ventana_min=N calls sync_recientes with configurable window
- sync_recientes() now returns a result dict (ok, total, created, updated, skipped, errores, detalle)
- ERP tab shows a "Prueba manual" card with ventana selector (2m / 30m / 2h / hoy) and result breakdown
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Hub /envios/tns con 5 sub-tabs (Terceros, Transacción RIPS, Facturas Venta, Prueba RDA, Automatización) via iframe lazy
- Hub /envios/erp con sub-tabs Pacientes y Sync Automático (historial scheduler)
- Modo embed (?embed=1) en base.html para cargar páginas sin sidebar/header dentro de iframes
- Sidebar simplificado: 6 ítems individuales reemplazados por módulos TNS y ERP Lab
- Scheduler y endpoint /pacientes/examenes ahora incluyen médico ordenante (DOCIDMEDICO), empresa/EPS (NIT_EMPRESA) y valor total (VALORTOTAL) desde Firebird
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No enviar facturas cuyo número sea 0 — quedarían como "00000" en TNS.
Filtro aplicado en preview, run y reenviar-venta.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 4 chips toggleables (Terceros/RDA/Pre-servicios/Ventas) que controlan
qué pasos se ejecutan en vista previa y en el envío masivo
- Backend: parámetro `pasos` en run_automation para saltarse pasos no
seleccionados; agrega `idrecepcion`/`codigo` a cada detalle item
- Nuevos endpoints POST /automation/reenviar-tercero, /reenviar-rda y
/reenviar-venta para reenvío individual con SQL BY_ID para cada tipo
- Panel de resultados rediseñado: barra de resumen por paso, sección
de fallos expandida con botón "Reenviar" por item (actualiza row in-
place), sección de exitosos colapsada por defecto
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Los campos excluir/sin_contrato/excluir_ventas solo se aplican en INSERT
(contratos nuevos del seed). En contratos existentes solo se actualizan
los datos descriptivos (nit, tipo_usuario, descripcion) para preservar
la configuracion que el usuario haya definido desde la UI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Automation: agrega Paso 4 (Ventas/Crear) con fetch _SQL_VENTAS,
filtro por excluded_ventas_set, loop de envío y log de actividad
- Automation: _guardar_envio ahora almacena idrecepcion y contrato
para que /ventas reconozca registros enviados por automation
- Contratos: corrige NameError en toggle_excluir (faltaba request: Request)
- Ventas: agrega check if not q en send_one y send para evitar TypeError
- Ventas HTML: agrega columna Contrato en la tabla de facturas
- json_generator: normaliza etnia >2 chars a '99' (ej: 999 → 99)
- json_generator: agrega campo ciudadExp usando el mismo cod_ciudad
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Nueva columna excluir_ventas en tabla contratos (migración automática)
- load_excluded_ventas_set() para filtrar en /ventas
- Toggle independiente en /contratos para RDA y Ventas por separado
- Modal edición con checkbox excluir_ventas
- 040 marcado excluir_rda=1, excluir_ventas=0 en seed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- generar_factura_venta en json_generator.py con mapeo completo del JSON
- Queries default tipo 'ventas' (por fecha y por número) filtradas a contrato 040
- Ruta /ventas con preview, send-one y send masivo
- Template ventas.html con tabla, resumen y modal JSON
- Link en navegación lateral
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
preview_automation usaba _defecto en vez de _default, causando que
profesional y especialidad salieran null en la vista previa del automation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add 'RDA Pre-servicios por fecha' and 'RDA Pre-servicios por número'
default queries joining PRESSERV_DIAN (ID_PS, PS_PREFIJO, PS_NUMERO)
- Refactor _query_rows: only pass params the query actually uses;
prefix filter works for both PREFIJO and PS_PREFIJO columns
- Add _is_preserv(), _agrupar(), _build_rda() helpers that detect
pre-servicio rows and produce correct prefijo/numero overrides
- All 4 send endpoints (preview, send-one, send, send-direct) now
group by ID_PS for pre-servicio queries and pass correct RDA fields
- RCXC prefix still maps to '00' in the RDA codigoPrefijo
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>