Commit Graph

26 Commits

Author SHA1 Message Date
Horux Dev
a24947187a feat(conciliacion): columnas de regimen en tabla Por conciliar segun tab 2026-05-24 19:39:21 +00:00
Horux Dev
f43cb165c6 feat: asignaciones obligaciones/tareas + fixes backend
- Migracion 046: tablas obligacion_asignaciones y tarea_asignaciones
- Servicio y controller de asignaciones (CRUD + listados)
- Fix: enviar correo welcome al invitar usuario nuevo
- Fix: quitar JOIN users de queries tenant (usar Prisma en BD central)
- Fix: req.params.obligacionId correcto en asignaciones controller
- Fix: orden rutas estaticas antes de dinamicas en cartera.routes
- Fix: owner/cfo ven todas las asignaciones en getAsignacionesPorSupervisor
- Fix: validar que entidad pertenezca a cartera padre en subcartera
- Nuevo endpoint GET /carteras/asignaciones/sin-asignar
- Nuevo endpoint GET /tareas/mis-tareas
2026-05-23 23:40:12 +00:00
Horux Dev
a91a2f415d feat(facturacion): cuenta predial para régimen 606 (arrendamiento)
- Frontend: muestra input 'No. Cuenta Predial' en sección 'Datos del Inmueble'
  cuando el régimen del emisor es 606 (Arrendamiento), antes de Conceptos
- Frontend: incluye cuentaPredial en payload; se resetea al cambiar contribuyente
- Backend: pasa property_tax_account a nivel de cada item en Facturapi
  para facturapi.service.ts y contribuyente-facturapi.service.ts
- Build y deploy exitosos
2026-05-22 23:20:36 +00:00
Horux Dev
0c8ae05919 feat(facturacion): precio unitario sin IVA en conceptos
- Cambia label de 'Precio Unitario (IVA incluido)' a 'Precio Unitario (sin IVA)'
- Elimina división interna price/(1+iva) en calcConcepto; ahora price es la base
- Cambia taxIncluded: true → false en payload enviado a backend
- Backend: tax_included default false en facturapi.service.ts y
  contribuyente-facturapi.service.ts
- Build y deploy exitosos
2026-05-22 22:23:38 +00:00
Horux Dev
1bde570035 feat(facturacion): fecha de emisión personalizable para I, E, T
- Frontend: input datetime-local visible solo para tipos I, E, T
  (no P). Default al día actual a las 12:00. Se resetea al cambiar tipo.
- Frontend: validación en handleSubmit: fecha ≤ ahora y ≥ ahora-72h
- Backend controller: validación idéntica antes de consumir timbre
- Backend servicios: pasa campo 'date' al payload de Facturapi
  cuando viene 'fechaEmision' en el body
- Build y deploy exitosos
2026-05-22 20:11:03 +00:00
Horux Dev
5ba31b7291 fix: personalización logo/color por contribuyente en vez de tenant
- Agrega getCustomizationContribuyente, uploadLogoContribuyente,
  updateColorContribuyente en contribuyente-facturapi.service.ts
- Agrega controllers per-contribuyente en facturacion.controller.ts
- Agrega rutas GET/POST/PUT /contribuyentes/:id/facturapi/customization|logo|color
- Modifica CustomizationSection para recibir contribuyenteId, usar endpoints
  per-contribuyente, y corrige useState mal aplicado a useEffect
- Backend y frontend buildeados y deployados
2026-05-22 18:20:09 +00:00
Horux Dev
46846200da feat(sat): factura global + fecha_efectiva, fallback tenant-contribuyente, fix anio_global typo
Factura Global & fecha_efectiva:
- Migracion 045_factura_global.sql: periodicidad, meses_global, año_global, fecha_efectiva
- sat-parser.service.ts: extrae InformacionGlobal del XML
- sat.service.ts: calcFechaEfectiva con soporte bimestral (periodicidad 05)
- metricas-compute, dashboard, impuestos, cfdi, export, conciliacion, alertas:
  reemplaza fecha_emision-1h por COALESCE(fecha_efectiva, fecha_emision-1h)
- Script recalc-metricas.ts para recalculo manual

Fallback datos fiscales tenant → contribuyente:
- contribuyente.service.ts: fetchTenantFiscalData + mergeContribuyenteWithTenant
  rellena regimenFiscal, codigoPostal y domicilio cuando el contribuyente
  tiene el mismo RFC que el tenant y sus campos estan vacios
- contribuyente.controller.ts y contribuyente-config.controller.ts:
  pasan req.user!.tenantId al servicio

Fix critico SAT sync:
- sat.service.ts: anio_global → año_global en INSERT/UPDATE de CFDIs
  (la migracion creo 'año_global' con tilde; el codigo usaba 'anio_global',
   causando fallo en 100% de inserciones de CFDI)
- determineChunkMonths: salta sondeo si existe job previo con requestIds
- MAX_POLL_ATTEMPTS: 45 → 500 (~8h) para syncs iniciales grandes

Docs:
- docs/sessions/2026-05-22-factura-global-contribuyente-fallback.md
2026-05-22 15:52:10 +00:00
Horux Dev
b5e307e142 fix(facturacion): saldo pendiente PPD + seguridad cancelación multi-contribuyente
- Inicializar saldo_pendiente_mxn al emitir facturas I/PPD vía Facturapi
  (antes quedaba NULL y no aparecían en complemento de pago)
- Validar ownership en cancelación: backend rechaza 403 si el caller
  intenta cancelar una factura de otro contribuyente
- Frontend: ocultar botón cancelar si no se es el emisor de la factura
- Frontend: enviar contribuyenteId en la petición de cancelación
2026-05-20 05:18:34 +00:00
Horux Dev
98e982c260 fix(documentos): capturar timeout SAT en consulta CSF manual
El controller ahora devuelve 504 (gateway timeout) con mensaje claro
en vez de 500 genérico cuando el scraper del SAT excede el tiempo.

Anteriormente solo capturaba errores con 'FIEL' en el mensaje;
los timeouts de page.waitForURL se escapaban como 500.
2026-05-19 21:45:20 +00:00
Horux Dev
8f796b2403 fix(api): evitar 500 al crear tenant con email existente + rate-limit trust proxy
- createTenant ahora reusa User si el email ya existe globalmente
  (hace upsert de membership en vez de crear user duplicado)
- Arregla error de express-rate-limit con X-Forwarded-For:
  app.set('trust proxy', 1) para que funcione detrás de Cloudflare
- Tipos de email templates actualizados para tempPassword nullable
2026-05-19 21:42:57 +00:00
Horux Dev
0b704e0e27 feat(admin/usuarios): agregar usuario globalmente desde admin
El admin global ahora puede crear usuarios directamente desde
/admin/usuarios sin depender de que un owner los invite.

Backend:
- Nuevo endpoint POST /usuarios/global (controller + service)
- Valida límite de usuarios del plan del tenant destino
- Si el email ya existe, agrega membership al tenant destino
- Si no existe, crea user con temp password + membership
- Schema Zod: email, nombre, role, tenantId, supervisorUserId?

Frontend:
- Botón 'Agregar Usuario' en /admin/usuarios
- Formulario con: nombre, email, rol, empresa
- Hook useCreateUsuarioGlobal con invalidación de queries
2026-05-17 14:32:45 +00:00
Horux Dev
e8aaf9ff15 fix(clientes): crear tenant como despacho desde admin global
Antes, createTenant() solo seteaba nombre, rfc, plan y databaseName.
Ahora registra tenants completos como despachos:

- dbMode: 'MANAGED'
- verticalProfile: CONTABLE | JURIDICO | ARQUITECTURA
- trialEndsAt: +30 días para plan trial
- codigoPostal: opcional (se llena automáticamente de la CSF al subir FIEL)

Frontend:
- Selector de Tipo de Despacho en /clientes
- C.P. omitido del formulario (viene de CSF -> sincronizarDatosFiscales)
- Tipos Tenant y CreateTenantData actualizados

Backend:
- getAllTenants y getTenantById retornan verticalProfile y codigoPostal

Refs: docs/sessions/2026-05-04-fix-clientes-crea-despacho.md
2026-05-17 06:11:29 +00:00
Horux Dev
44d7c796c9 fix: facturapi onboarding, CSF scraper, SAT sync initial, doc notifications
- Auto-update fiscal data on org creation via updateOrgLegalOnCreate
- Add Carta Manifiesto embedded iframe in CSD config page
- Fix CSF scraper: 60s timeout + manual RFC fallback when SAT doesn't auto-populate
- Fix contribuyenteId propagation in constancia frontend hooks/API
- Fix needsInitialSync to check per-contribuyente, not just per-tenant
- Fix documento notifications for global_admin using viewingTenantId
- Extract CSF manually for Carlos Husberto Torres Romero
- Trigger initial SAT sync for Carlos Husberto Torres Romero
- Update org legal data in Facturapi for Carlos Husberto (tax_system 612 + address)

Files changed:
- apps/api/src/controllers/documentos.controller.ts
- apps/api/src/jobs/sat-sync.job.ts
- apps/api/src/services/constancia.service.ts
- apps/api/src/services/contribuyente-facturapi.service.ts
- apps/api/src/services/sat/sat-csf-login.ts
- apps/web/app/(dashboard)/configuracion/csd/page.tsx
- apps/web/lib/api/constancias.ts
- apps/web/lib/hooks/use-constancias.ts
- docs/sessions/2026-05-17-facturapi-csf-sync-notifications.md
2026-05-17 04:28:32 +00:00
Horux Dev
1c92b8eaf1 fix(sat): muestra extraccion inicial si no hay job initial completado
Problema: el boton 'Sincronizacion inicial (6 años)' desaparecia cuando
existia CUALQUIER job completado (daily, incremental, etc.). Esto era
inconsistente con el cron incremental del backend, que requiere
especificamente un job de tipo 'initial' completado.

Resultado: usuarios que solo habian hecho sync diaria perdian la opcion
de hacer la extraccion inicial completa, y el cron incremental tampoco
corria porque no habia initial.

Fix:
- Backend getSyncStatus: agrega lastCompletedInitialJob (busca solo
  jobs type='initial' status='completed')
- Frontend SyncStatus: muestra el boton de inicial si
  !lastCompletedInitialJob (ignora jobs diarios/incrementales)
- SatSyncStatusResponse: agrega campo lastCompletedInitialJob
2026-05-16 19:16:07 +00:00
Horux Dev
414e862a44 feat(cfdi): backfill codigo_postal_receptor desde xml_original
Script: apps/api/scripts/backfill-cp-receptor.ts
- Escanea 93,617 CFDIs con xml_original y codigo_postal_receptor IS NULL
- Extrae DomicilioFiscalReceptor via parseXml() (misma logica que sync SAT)
- Actualiza 53,858 registros en 6 tenants activos
- 0 fallos de parseo
2026-05-16 14:55:10 +00:00
Horux Dev
bda0a4e212 feat(cfdi): agrega C.P. receptor, regimen receptor, no_identificacion, tipo_relacion y CFDIs relacionados al visualizador
Backend:
- Migracion 044: codigo_postal_receptor VARCHAR(5) + indice
- sat-parser: extrae DomicilioFiscalReceptor
- sat.service: persiste codigo_postal_receptor en INSERT/UPDATE
- cfdi.service: incluye codigo_postal_receptor en CFDI_SELECT
- shared/types: codigoPostalReceptor en interfaz Cfdi

Frontend:
- cfdi-invoice: tarjeta receptor con C.P. y regimen (con descripciones)
- cfdi-invoice: seccion CFDI Relacionado (tipo + UUIDs)
- cfdi-invoice: columna No. Identificacion en tabla de conceptos
- cfdi-viewer-modal: mapea noIdentificacion desde DB y XML
2026-05-16 14:45:00 +00:00
Horux Dev
552a7c7716 feat(cfdi): agrega columna y filtro no_identificacion en tabla Conceptos
- Backend (cfdi.service.ts): getConceptosList ahora soporta filtro noIdentificacion
  via cc.no_identificacion ILIKE

- Frontend API (cfdi.ts): ConceptosFilters incluye noIdentificacion; se envía
  como query param

- Frontend página (cfdi/page.tsx):
  * Nuevo estado noIdentificacion en conceptosFilters
  * Nueva columna 'No. Identificación' en header de tabla con Popover filtro
  * Celda no_identificacion renderizada en cada fila
  * Export a Excel respeta el nuevo filtro
2026-05-15 23:22:38 +00:00
Horux Dev
7b1f60cbf2 feat(reportes): rediseño Estado de Resultados vertical con drill-down, análisis horizontal/vertical y export Excel
- Nuevo endpoint GET /reportes/estado-resultados-detallado con cálculo contable:
  * Ventas, Devoluciones, Ventas netas, Costo de ventas, Utilidad bruta,
    Gastos operativos, Utilidad de la operación
  * Fórmula: subtotal_mxn - descuento_mxn (sin impuestos), nómina usa total_mxn
  * Excluye anticipos (uso_cfdi=P01 o clave_prod_serv=84111506)
  * Filtro por régimen fiscal opcional
  * Año anterior calculado automáticamente

- Nuevo endpoint GET /reportes/estado-resultados/drill-down:
  * Nivel 1: resumen agrupado por RFC
  * Nivel 2: CFDIs individuales filtrados por categoría
  * Categorías: ventas, devoluciones, costo-ventas, gastos-operativos

- Nuevo endpoint GET /reportes/estado-resultados/export:
  * Genera Excel con formato condicional (verde/rojo, negritas)

- Frontend:
  * Tabla vertical con % vertical, año anterior y variación %
  * Filas clickeables para drill-down modal de 2 niveles
  * Top 10 Clientes/Proveedores mantenidos debajo
  * Selector de régimen conectado al reporte

- Fix: NaN en total de drill-down nivel 2 por numeric como string en pg
  * Agregado ::float en queries SQL de CFDIs individuales
2026-05-15 22:53:10 +00:00
Horux Dev
69bf7417a8 feat(invitations): reenviar invitaciones pendientes desde admin
Backend:
- client-invitations.service.ts: funcion resendInvitation() que
  genera nuevo token, actualiza expiresAt y reenvia el email.
- Controller + routes: POST /invitations/client/:id/resend

Frontend:
- API client + hook useResendInvitation con invalidacion de cache.
- Pagina /admin/invitar-cliente: boton 'Reenviar' por cada
  invitacion pendiente en la tabla.

Refs: docs/CAMBIOS-2026-05-09.md
2026-05-13 23:19:07 +00:00
Horux Dev
fbcc788a76 fix(email): color blanco inline en boton de invitacion de cliente 2026-05-11 22:34:59 +00:00
Horux Dev
745bc8385b feat(invitations): flujo de invitacion de clientes por email
Backend:
- Nuevo modelo Prisma ClientInvitation con token unico, expiracion
  y estados (pending/accepted/expired).
- Migracion: 20260511213955_add_client_invitations
- Service client-invitations.service.ts: crear invitacion,
  validar token, registrar desde invitacion (reutiliza logica
  de creacion de tenant + usuario de despacho.service).
- Controller + routes: POST /invitations/client (admin),
  GET /invitations/client/validate/:token (publico),
  POST /invitations/client/register/:token (publico),
  GET /invitations/client (admin).
- Email template client-invitation.ts con link a
  /invitacion/registro/{token}.
- Agregado sendClientInvitation a email.service.

Frontend:
- Pagina /invitacion/registro/[token] para que el invitado
  complete registro (nombre, password, despacho, RFC, perfil).
- Pagina /admin/invitar-cliente para que admin global envie
  invitaciones y vea el historial.
- Hooks useCreateInvitation, useValidateInvitationToken,
  useRegisterFromInvitation, useClientInvitations.
- API client lib/api/client-invitations.ts.

Infra:
- PM2 ecosystem.config.js: usa node --import tsx con
  kill_timeout aumentado a 15s para evitar EADDRINUSE.
- React Query retry=2 con delay exponencial para resiliencia.

Refs: docs/CAMBIOS-2026-05-09.md
2026-05-11 22:03:03 +00:00
Horux Dev
b9bd8cfc1e fix(conciliacion): incluir CFDIs tipo P en filtro de emitidos
La condicion SQL NOT (metodo_pago = 'PPD' AND ...) producia NULL
cuando metodo_pago era NULL (como en complementos de pago tipo P),
lo que excluia silenciosamente todos los tipo P del listado de
emitidos en conciliacion.

Cambiada a: metodo_pago IS NULL OR metodo_pago != 'PPD' OR
regimen_fiscal_emisor IN ('605','616')

Esto mantiene la intencion original (excluir PPD de regimenes
que no son 605/616) sin afectar a tipo P ni otros sin metodo de pago.

Refs: docs/CAMBIOS-2026-05-09.md seccion 8
2026-05-11 17:48:10 +00:00
Horux Dev
6dfcbfc05c fix(conciliacion): complementos de pago usan fecha_pago_p y campos faltantes en visor
- conciliacion.service.ts: filtros y ordenamiento ahora usan
  COALESCE(fecha_pago_p, fecha_emision). Los CFDIs tipo P
  (complementos de pago) aparecen en el periodo del pago real,
  no de la emision del CFDI.

- conciliacion.service.ts: agrega fechaPagoP al SELECT y a la
  interfaz ConciliacionCfdi.

- conciliacion/page.tsx: tablas y export Excel usan
  fechaPagoP || fechaEmision para mostrar la fecha.

- cfdi-invoice.tsx: para tipo P con fechaPagoP, muestra
  'Pago: {fecha}' en el encabezado.

- conciliacion.ts: actualiza interfaz ConciliacionCfdi con
  todos los campos que ya devuelve el backend.

Refs: docs/CAMBIOS-2026-05-09.md secciones 7 y 8
2026-05-11 17:31:35 +00:00
Horux Dev
e21ccd6860 fix(sat,conciliacion): propagar contribuyenteId en sync SAT y campos faltantes en visor de conciliacion
- sat-sync.job.ts: cron diario e incremental ahora iteran contribuyentes
  por tenant y pasan contribuyenteId a startSync(). Evita que CFDIs
  importados del SAT queden con contribuyente_id = NULL.

- sat.service.ts: retryJob() ahora reintenta con job.contribuyenteId.

- conciliacion.service.ts: agrega campos faltantes al SELECT de CFDIs:
  status, formaPago, serie, folio, usoCfdi, subtotal, descuento,
  moneda, tipoCambio, ivaTraslado, ivaRetencion, isrRetencion,
  fechaCertSat. Antes el visor mostraba 'CANCELADO' para todos los
  CFDIs (status era undefined) y faltaban datos de forma de pago,
  impuestos, serie/folio, etc.

Refs: docs/CAMBIOS-2026-05-09.md secciones 6 y 7
2026-05-11 03:58:53 +00:00
Horux Dev
9f11a0ba39 feat: facturación primer pago, fixes SAT/MP, autocompletado RFCs/conceptos
Backend:
- Notificación email al admin cuando llega primer pago aprobado (sin factura auto)
- Endpoints GET /pagos-sin-factura y POST /emitir-factura-pago para admin global
- Fix vinculación org Facturapi Horux 360 (69f23a5a242e0af47a41fa0d)
- Fix webhook MP: validación defensiva de x-signature header
- Fix autocompleto RFCs: eliminado filtro por contribuyenteId
- Fix autocompleto conceptos: eliminado filtro por contribuyenteId
- SAT fixes: anti-bot CSF scraper, request reuse, date range fix, stale job thresholds
- SAT sync request reuse across jobs para evitar agotar cuota diaria
- Typo fix MP_ACCESS_TOKEN en .env
- Trial invitations system backend

Frontend:
- Nueva página /admin/facturas-pendientes con tabla y emisión manual
- Métrica 'Facturas pendientes' en /clientes (clickable)
- Navegación onboarding FIEL/CSD corregida
- Sidebar themes sincronizados
- Fix SAT portal migration scraper (NetIQ)
- Trial invitation acceptance pages
2026-05-09 21:56:42 +00:00
b00b677c54 Initial commit - Horux Despachos NL 2026-05-03 16:47:53 -06:00