Skip to content

fix(analytics): parsear las fechas de la API en vez de usar new Date()#5

Open
Asermar wants to merge 1 commit into
FacturaScripts:mainfrom
Asermar:fix/fs-date-parsing
Open

fix(analytics): parsear las fechas de la API en vez de usar new Date()#5
Asermar wants to merge 1 commit into
FacturaScripts:mainfrom
Asermar:fix/fs-date-parsing

Conversation

@Asermar

@Asermar Asermar commented Jul 25, 2026

Copy link
Copy Markdown

Problema

Los KPI de analytics descartan o descolocan la mayoría de los registros al filtrar o agrupar por fecha, sin dar ningún error.

Causa

La API de FacturaScripts devuelve las fechas con el estilo de FS (por defecto d-m-Y): "04-01-2023", "01-09-2025 10:48:33". Pero los KPI las pasan por new Date(), que interpreta esa cadena como MM-DD-YYYY:

new Date("04-01-2023")  // -> 1 de ABRIL de 2023   (mes y día intercambiados)
new Date("19-08-2025")  // -> Invalid Date         (no existe el mes 19)

Con día ≤ 12 el registro se contabiliza en el mes equivocado; con día > 12 la comparación es siempre falsa y el registro desaparece del cálculo. Es decir, 19 de cada 31 días se caen de cualquier KPI filtrado por fecha y el resto se cuenta mal.

Afecta a aging de cobros, DSO, clientes perdidos, lifetime value, comparativa de periodos y funnel.

Hay un segundo caso de la misma familia en get_clientes_lifetime_value: la primera/última compra se calculaban comparando las fechas como cadenas d-m-Y, lo que ordena por día (31-01-2023 salía posterior a 01-02-2023).

Solución

Nuevo utils/fsDate.ts con parseFsDate(), que entiende d-m-Y, d/m/Y (el estilo de fecha es configurable en FS) e ISO, con hora opcional, y valida que la fecha exista (31-02 ya no desborda a marzo).

Devuelve Date a propósito, para poder sustituir a new Date() en el sitio de llamada sin reestructurar la lógica. Con entradas no interpretables devuelve Invalid Date, igual que antes, así que no cambia el comportamiento para valores basura.

Alcance

38 llamadas sustituidas en modules/analytics/index.ts y kpis-extended.ts: solo las que parsean valores de la API o entradas del usuario. Se dejan intactas las que construyen la fecha actual (new Date()) o clonan un Date existente, que son correctas.

Verificación

Se añade npm test con el runner integrado de Node, sin dependencias nuevas. 11 tests sobre el parseo, que es donde el fallo pasaba desapercibido: el formato de la API, días > 12, el separador de barra, ISO, fechas inexistentes y la ordenación cronológica.

Nota: si se fusiona también #PR-de-rango, ambos añaden la misma línea "test" a package.json; el conflicto es de una línea.

La API de FacturaScripts devuelve las fechas con el estilo de FS (por defecto
`d-m-Y`: "04-01-2023", "01-09-2025 10:48:33"), pero los KPI las pasaban por
`new Date()`, que interpreta esa cadena como MM-DD-YYYY. Consecuencia, siempre
en silencio:

  - día <= 12: se intercambian mes y día, y el registro cuenta en el mes equivocado
      new Date('04-01-2023')  ->  1 de ABRIL de 2023
  - día > 12:  Invalid Date, y el registro DESAPARECE del cálculo
      new Date('19-08-2025')  ->  Invalid Date

Es decir, 19 de cada 31 días se caían de cualquier KPI filtrado o agrupado por
fecha, y el resto se contabilizaba en el mes que no era. Afecta a aging de cobros,
DSO, clientes perdidos, lifetime value, comparativa de periodos y funnel.

Añade `utils/fsDate.ts` con `parseFsDate()`, que entiende `d-m-Y`, `d/m/Y` (el
estilo de fecha es configurable) e ISO, con hora opcional, y valida que la fecha
exista (`31-02` ya no desborda a marzo). Devuelve `Date` para poder sustituir a
`new Date()` en el sitio de llamada sin reestructurar nada.

Se sustituyen las 38 llamadas que parsean valores de la API o entradas del usuario;
se dejan intactas las que construyen la fecha actual o clonan un Date.

Corrige además el cálculo de primera/última compra en get_clientes_lifetime_value,
que comparaba las fechas como CADENAS `d-m-Y` y por tanto ordenaba por día
(31-01-2023 salía posterior a 01-02-2023).

Incluye tests con el runner de Node (`npm test`), sin dependencias nuevas.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant