From 6bd5ed0e84a8a71a01dd40543453c50c15c2dc69 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 1 Sep 2026 13:48:05 +0200 Subject: [PATCH] fix: update API server URL in development environment and enhance issued invoice model search index - Changed VITE_API_SERVER_URL from http://192.168.0.104:3002/api/v1 to http://172.31.142.243:3002/api/v1 in .env.development file. - Added 'invoice_reference' to the FULLTEXT index fields in sequelize-issued-invoice.model.ts for improved search capabilities. - Added a new document detailing the design and information presentation for recurring proformas. --- AGENTS.md | 949 +++++---- apps/web/.env.development | 2 +- ...ada en las pantallas de recurring-proformas.md | 1726 +++++++++++++++++ .../models/sequelize-issued-invoice.model.ts | 2 +- 4 files changed, 2352 insertions(+), 327 deletions(-) create mode 100644 docs/recurring-proformas/DOCUMENTO DE DISEÑO — Información mostrada en las pantallas de recurring-proformas.md diff --git a/AGENTS.md b/AGENTS.md index 0774f7ae..7c77001f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,419 +1,630 @@ -# AGENTS.md +**# AGENTS.md** -## Ámbito +**## Ámbito** -Estas instrucciones se aplican a todo el monorepo, salvo que exista un archivo `AGENTS.md` más específico en un subdirectorio. +Estas instrucciones se aplican a todo el monorepo, salvo que exista un archivo \`AGENTS.md\` más específico en un subdirectorio. -Los archivos `AGENTS.md` descendientes deben añadir o restringir reglas para su ámbito, no duplicar innecesariamente este documento. +Los archivos \`AGENTS.md\` descendientes deben añadir o restringir reglas para su ámbito, no duplicar innecesariamente este documento. -## Objetivo +**## Objetivo** Trabajar sobre el ERP mediante cambios: -- correctos; -- mínimos; -- comprobables; -- coherentes con la arquitectura existente; -- fáciles de entender y mantener por otros desarrolladores. +\- correctos; + +\- mínimos; + +\- comprobables; + +\- coherentes con la arquitectura existente; + +\- fáciles de entender y mantener por otros desarrolladores. Antes de modificar código, revisar las implementaciones y patrones existentes en el área afectada. No introducir patrones nuevos si ya existe una solución equivalente en el proyecto. -## Entorno de ejecución +**## Entorno de ejecución** + +El entorno de desarrollo canónico es WSL2 con Ubuntu 24.04 LTS. El repositorio canónico es: -`/home/rodax/Documentos/uecko-erp` +\`/home/david/dev/uecko-erp\` -Todos los comandos de desarrollo deben ejecutarse en Linux. +Todos los comandos de desarrollo deben ejecutarse dentro de WSL2 usando Linux y \`bash\`. -No ejecutar Node.js, PNPM, Turborepo, TypeScript, Biome ni tests -desde rutas Windows, unidades `Z:` ni rutas UNC. +No ejecutar Node.js, PNPM, Turborepo, TypeScript, Biome, Git ni tests desde Windows, PowerShell, unidades \`Z:\`, rutas UNC o rutas montadas bajo \`/mnt/c\`. + +No usar la antigua máquina Ubuntu remota como entorno de desarrollo salvo que la tarea lo requiera expresamente. + +Codex debe trabajar sobre la distribución WSL \`Ubuntu-24.04\` y abrir el repositorio mediante su ruta Linux real: + +\`/home/david/dev/uecko-erp\` + +No abrir el proyecto para tareas de desarrollo mediante rutas Windows equivalentes como \`\\wsl$\\...\`, \`Z:\` o \`C:\`. Antes de trabajar comprobar: -```bash +\`\`\`bash + pwd + uname -s + +uname -r + +whoami + git rev-parse --show-toplevel -``` + +node --version + +pnpm --version + +\`\`\` + Se espera: -``` +\`\`\`text + +/home/david/dev/uecko-erp + Linux -/home/rodax/Documentos/uecko-erp -``` + -## Stack principal +david -- Node.js >= 22 -- TypeScript -- PNPM -- Turborepo -- ExpressJS -- React -- MariaDB -- Sequelize v6 -- Zod v4 -- Biome +/home/david/dev/uecko-erp -## Principios obligatorios +Node.js 24.x + +pnpm 11.22.0 + +\`\`\` + +Si el entorno no coincide, no continuar con cambios de código hasta identificar la causa. + +Los archivos \`.env\` locales ya configurados no deben mostrarse, copiarse a respuestas ni versionarse. No imprimir secretos, tokens, contraseñas o cadenas de conexión completas. + +La versión de PNPM definida en \`packageManager\` del \`package.json\` raíz es vinculante. No actualizar PNPM ni modificar \`packageManager\` como parte de una tarea no relacionada. + +**## Stack principal** + +\- Node.js 24.x + +\- TypeScript + +\- PNPM + +\- Turborepo + +\- ExpressJS + +\- React + +\- MariaDB + +\- Sequelize v6 + +\- Zod v4 + +\- Biome + +**## Principios obligatorios** Aplicar de forma pragmática: -- SOLID; -- Clean Code; -- DRY; -- KISS; -- YAGNI; -- SSOT; -- Fail Fast; -- programación defensiva; -- inmutabilidad cuando resulte adecuada; -- idempotencia; -- principio de menor privilegio; -- observabilidad en APIs y servicios. +\- SOLID; + +\- Clean Code; + +\- DRY; + +\- KISS; + +\- YAGNI; + +\- SSOT; + +\- Fail Fast; + +\- programación defensiva; + +\- inmutabilidad cuando resulte adecuada; + +\- idempotencia; + +\- principio de menor privilegio; + +\- observabilidad en APIs y servicios. Priorizar siempre: -```text +\`\`\`text + claridad y explicitud -> + +\> + abstracción prematura -``` + +\`\`\` No introducir capas, adaptadores, factories, genéricos, eventos, contenedores DI o abstracciones sin una necesidad real y actual. -## Idioma y convenciones de nombres +**## Idioma y convenciones de nombres** -- Código e identificadores en inglés. -- Comentarios y TSDoc en castellano. -- Ficheros y directorios en `kebab-case`. -- Clases, tipos e interfaces en `PascalCase`. -- Variables, funciones y métodos en `camelCase`. -- Constantes globales en `UPPER_SNAKE_CASE` solo cuando realmente sean constantes globales. -- Mantener la convención de prefijo `I` para interfaces cuando el área existente ya la utilice. +\- Código e identificadores en inglés. -## Comentarios y documentación +\- Comentarios y TSDoc en castellano. + +\- Ficheros y directorios en \`kebab-case\`. + +\- Clases, tipos e interfaces en \`PascalCase\`. + +\- Variables, funciones y métodos en \`camelCase\`. + +\- Constantes globales en \`UPPER\_SNAKE\_CASE\` solo cuando realmente sean constantes globales. + +\- Mantener la convención de prefijo \`I\` para interfaces cuando el área existente ya la utilice. + +**## Comentarios y documentación** + +**### Los comentarios** -### Los comentarios Deben explicar: -- por qué existe una decisión; -- qué riesgo evita; -- qué contrato debe respetarse; -- qué efectos laterales o errores son relevantes. +\- por qué existe una decisión; + +\- qué riesgo evita; + +\- qué contrato debe respetarse; + +\- qué efectos laterales o errores son relevantes. No deben repetir lo que ya expresa el código. Documentar mediante TSDoc las APIs públicas cuando aporten información sobre: -- propósito; -- parámetros; -- valor devuelto; -- errores; -- efectos laterales; -- invariantes o restricciones. +\- propósito; + +\- parámetros; + +\- valor devuelto; + +\- errores; + +\- efectos laterales; + +\- invariantes o restricciones. Después de un refactor, actualizar o eliminar los comentarios que hayan quedado obsoletos. -### La documentación del proyecto +**### La documentación del proyecto** -- debe redactarse en castellano. -- Reside en /docs. -- Utilizar ficheros Markdown -- Los nombres de los ficheros deben estar en castellano. +\- debe redactarse en castellano. + +\- Reside en /docs. + +\- Utilizar ficheros Markdown + +\- Los nombres de los ficheros deben estar en castellano. Reglas de estilo para documentación: -- usar lenguaje claro; -- evitar redacción excesivamente técnica cuando no sea necesaria; -- usar frases directas; -- evitar frases rebuscadas, largas o ambiguas; -- priorizar explicar qué hace el sistema, por qué existe una regla y qué comportamiento debe esperar el usuario o el desarrollador; -- usar términos técnicos cuando sean necesarios para ser precisos, pero explicarlos de forma sencilla; -- no convertir la documentación en una transcripción del código; -- evitar párrafos densos si una explicación breve y directa es suficiente. +\- usar lenguaje claro; -## Disciplina de cambios +\- evitar redacción excesivamente técnica cuando no sea necesaria; -- Realizar cambios incrementales. -- No modificar código no relacionado con la tarea. -- No renombrar, mover o reformatear archivos sin necesidad. -- No introducir dependencias nuevas sin una justificación concreta. -- No copiar código si ya existe una abstracción adecuada y estable. -- No crear una abstracción nueva para eliminar una duplicación pequeña y local. -- Mantener compatibilidad con los contratos existentes salvo que la tarea exija explícitamente romperlos. -- No afirmar que una validación ha pasado si no se ha ejecutado correctamente. -- No ocultar fallos de compilación, lint o tests. -- No añadir supresiones de TypeScript, Biome o ESLint sin justificar el motivo en el código o en la respuesta final. +\- usar frases directas; -## Uso de `Result`, `Maybe` y `Collection` +\- evitar frases rebuscadas, largas o ambiguas; + +\- priorizar explicar qué hace el sistema, por qué existe una regla y qué comportamiento debe esperar el usuario o el desarrollador; + +\- usar términos técnicos cuando sean necesarios para ser precisos, pero explicarlos de forma sencilla; + +\- no convertir la documentación en una transcripción del código; + +\- evitar párrafos densos si una explicación breve y directa es suficiente. + +**## Disciplina de cambios** + +\- Realizar cambios incrementales. + +\- No modificar código no relacionado con la tarea. + +\- No renombrar, mover o reformatear archivos sin necesidad. + +\- No introducir dependencias nuevas sin una justificación concreta. + +\- No copiar código si ya existe una abstracción adecuada y estable. + +\- No crear una abstracción nueva para eliminar una duplicación pequeña y local. + +\- Mantener compatibilidad con los contratos existentes salvo que la tarea exija explícitamente romperlos. + +\- No afirmar que una validación ha pasado si no se ha ejecutado correctamente. + +\- No ocultar fallos de compilación, lint o tests. + +\- No añadir supresiones de TypeScript, Biome o ESLint sin justificar el motivo en el código o en la respuesta final. + +**## Uso de \`Result\`, \`Maybe\` y \`Collection\`** Usar los patrones existentes del proyecto: -- `Result` para operaciones que pueden fallar; -- `Maybe` para ausencia semántica; -- `Collection` para conjuntos de objetos del mismo tipo cuando el dominio requiera comportamiento propio. +\- \`Result\` para operaciones que pueden fallar; -No sustituirlos por excepciones, `null`, arrays o tipos ad hoc si el área existente ya utiliza estos patrones. +\- \`Maybe\` para ausencia semántica; + +\- \`Collection\` para conjuntos de objetos del mismo tipo cuando el dominio requiera comportamiento propio. + +No sustituirlos por excepciones, \`null\`, arrays o tipos ad hoc si el área existente ya utiliza estos patrones. No usar excepciones para flujo de negocio esperado salvo que el diseño actual del módulo lo establezca expresamente. -## Gestión de operaciones asíncronas +**## Gestión de operaciones asíncronas** El proyecto aplica la regla de Biome: -```text -lint/complexity/noVoid -``` +\`\`\`text -Está prohibido usar el operador `void` para descartar el resultado de una promesa. +lint/complexity/noVoid + +\`\`\` + +Está prohibido usar el operador \`void\` para descartar el resultado de una promesa. No generar: -```ts +\`\`\`ts + void handleDuplicate(); + void handleDownload(); + void asyncOperation(); -``` -Toda `Promise` debe gestionarse explícitamente mediante una de estas opciones: +\`\`\` -### Esperar la operación +Toda \`Promise\` debe gestionarse explícitamente mediante una de estas opciones: + +**### Esperar la operación** + +\`\`\`ts -```ts await handleDuplicate(); -``` -Usar esta opción cuando la función actual pueda ser `async` y el flujo deba esperar el resultado. +\`\`\` -### Devolver la promesa +Usar esta opción cuando la función actual pueda ser \`async\` y el flujo deba esperar el resultado. + +**### Devolver la promesa** + +\`\`\`ts -```ts return handleDuplicate(); -``` + +\`\`\` Usar esta opción cuando el llamador deba controlar el ciclo de vida de la operación. -### Gestionar expresamente el error +**### Gestionar expresamente el error** + +\`\`\`ts -```ts handleDuplicate().catch(handleUnexpectedError); -``` + +\`\`\` Usar esta opción solo cuando la operación sea deliberadamente no bloqueante. Reglas adicionales: -- No eliminar `void` dejando una promesa flotante. -- No silenciar errores mediante `.catch(() => undefined)` o equivalentes sin justificación explícita. -- Antes de convertir un callback en `async`, comprobar si su contrato acepta `Promise` o exige `void`. -- Si el contrato exige `void`, encapsular la operación asíncrona y gestionar explícitamente su error. -- No usar `void` como mecanismo para indicar intención. +\- No eliminar \`void\` dejando una promesa flotante. -## TypeScript +\- No silenciar errores mediante \`.catch(() => undefined)\` o equivalentes sin justificación explícita. -### Imports de tipos +\- Antes de convertir un callback en \`async\`, comprobar si su contrato acepta \`Promise\\` o exige \`void\`. -Usar siempre imports de tipos explícitos en la cabecera del fichero mediante `import type`: +\- Si el contrato exige \`void\`, encapsular la operación asíncrona y gestionar explícitamente su error. + +\- No usar \`void\` como mecanismo para indicar intención. + +**## TypeScript** + +**### Imports de tipos** + +Usar siempre imports de tipos explícitos en la cabecera del fichero mediante \`import type\`: + +\`\`\`ts -```ts import type { UniqueID } from "@repo/rdx-ddd"; + import type { Result } from "@repo/rdx-utils"; -``` -No usar referencias de tipo inline mediante `import("...").Tipo`: +\`\`\` + +No usar referencias de tipo inline mediante \`import("...").Tipo\`: + +\`\`\`ts -```ts // Prohibido + companyId: import("@repo/rdx-ddd").UniqueID; -``` + +\`\`\` Aplicar estas reglas: -- Usar `import type { ... } from "..."` para toda dependencia utilizada exclusivamente como tipo. -- Mantener los imports de tipos en la cabecera del fichero, junto con el resto de imports. -- No mezclar imports de tipo y de runtime cuando puedan separarse con claridad. -- No usar `import("...").Tipo` en código fuente ordinario. -- Solo se admite un tipo inline en declaraciones generadas, archivos `.d.ts`, module augmentation o casos excepcionales técnicamente justificados y documentados. -- No introducir imports de runtime para símbolos usados únicamente como tipos. +\- Usar \`import type { ... } from "..."\` para toda dependencia utilizada exclusivamente como tipo. + +\- Mantener los imports de tipos en la cabecera del fichero, junto con el resto de imports. + +\- No mezclar imports de tipo y de runtime cuando puedan separarse con claridad. + +\- No usar \`import("...").Tipo\` en código fuente ordinario. + +\- Solo se admite un tipo inline en declaraciones generadas, archivos \`.d.ts\`, module augmentation o casos excepcionales técnicamente justificados y documentados. + +\- No introducir imports de runtime para símbolos usados únicamente como tipos. Ejemplo correcto: -```ts +\`\`\`ts + import type { UniqueID } from "@repo/rdx-ddd"; + import type { Result } from "@repo/rdx-utils"; export interface IIdentityTenantCompanyFinder { - existsActiveById(params: { - companyId: UniqueID; - transaction?: unknown; - }): Promise>; + +  existsActiveById(params: { + +    companyId: UniqueID; + +    transaction?: unknown; + +  }): Promise\>; + } -``` -- Evitar `any`. Usar `unknown` cuando el tipo todavía no sea conocido. -- No usar type assertions salvo que exista una garantía verificable que el compilador no pueda inferir. -- Evitar `!` salvo que la invariante esté demostrada localmente. -- Preferir tipos semánticos frente a primitivas genéricas. -- Modelar conjuntos cerrados mediante unions o enums existentes. -- Mantener exhaustividad en `switch` cuando el tipo represente un conjunto cerrado. -- No añadir ramas `default` que oculten casos no contemplados cuando pueda usarse comprobación exhaustiva. -- No duplicar tipos derivados de schemas Zod. -- No usar `Partial` si el schema o el tipo de entrada ya representa explícitamente la opcionalidad. -- Mantener inmutabilidad en valores y estructuras cuando no exista necesidad de mutación. +\`\`\` -## Zod y DTOs +\- Evitar \`any\`. Usar \`unknown\` cuando el tipo todavía no sea conocido. + +\- No usar type assertions salvo que exista una garantía verificable que el compilador no pueda inferir. + +\- Evitar \`!\` salvo que la invariante esté demostrada localmente. + +\- Preferir tipos semánticos frente a primitivas genéricas. + +\- Modelar conjuntos cerrados mediante unions o enums existentes. + +\- Mantener exhaustividad en \`switch\` cuando el tipo represente un conjunto cerrado. + +\- No añadir ramas \`default\` que oculten casos no contemplados cuando pueda usarse comprobación exhaustiva. + +\- No duplicar tipos derivados de schemas Zod. + +\- No usar \`Partial\\` si el schema o el tipo de entrada ya representa explícitamente la opcionalidad. + +\- Mantener inmutabilidad en valores y estructuras cuando no exista necesidad de mutación. + +**## Zod y DTOs** Zod es la fuente única de verdad para los contratos HTTP. Reglas: -- Inferir tipos con `z.infer`. -- No duplicar DTOs mediante interfaces manuales equivalentes. -- Cada endpoint debe tener sus DTOs de request y response. -- Reutilizar subschemas solo cuando sean realmente estables y compartidos. -- No mezclar validación de transporte con lógica de negocio. -- Evitar `.default()` y `.transform()` en DTOs de negocio salvo necesidad justificada. -- Diferenciar explícitamente entre campo omitido, `null`, cadena vacía y colección vacía. -- Usar schemas semánticos para UUID, fechas, timestamps, porcentajes, importes y cantidades. -- Los valores decimales exactos no deben viajar como `number`. +\- Inferir tipos con \`z.infer\\`. -## Arquitectura backend +\- No duplicar DTOs mediante interfaces manuales equivalentes. + +\- Cada endpoint debe tener sus DTOs de request y response. + +\- Reutilizar subschemas solo cuando sean realmente estables y compartidos. + +\- No mezclar validación de transporte con lógica de negocio. + +\- Evitar \`.default()\` y \`.transform()\` en DTOs de negocio salvo necesidad justificada. + +\- Diferenciar explícitamente entre campo omitido, \`null\`, cadena vacía y colección vacía. + +\- Usar schemas semánticos para UUID, fechas, timestamps, porcentajes, importes y cantidades. + +\- Los valores decimales exactos no deben viajar como \`number\`. + +**## Arquitectura backend** El backend sigue DDD pragmático, Clean Architecture y arquitectura hexagonal. Separación obligatoria: -```text +\`\`\`text + Domain - no conoce Application ni Infrastructure + +  no conoce Application ni Infrastructure Application - depende de Domain, contratos y Core - no conoce Express, Sequelize ni modelos ORM + +  depende de Domain, contratos y Core + +  no conoce Express, Sequelize ni modelos ORM Infrastructure - depende de Application, Domain y Core -``` + +  depende de Application, Domain y Core + +\`\`\` No se permite: -- `Domain -> Application`; -- `Domain -> Infrastructure`; -- `Application -> Infrastructure`; -- importar infraestructura interna de otro módulo; -- compartir repositorios entre módulos; -- usar Service Locator; -- introducir DI implícita o mágica. +\- \`Domain -> Application\`; -### Flujo de entrada +\- \`Domain -> Infrastructure\`; + +\- \`Application -> Infrastructure\`; + +\- importar infraestructura interna de otro módulo; + +\- compartir repositorios entre módulos; + +\- usar Service Locator; + +\- introducir DI implícita o mágica. + +**### Flujo de entrada** Respetar: -```text +\`\`\`text + RequestDTO - -> RequestMapper - -> Command - -> PropsMapper - -> Aggregate o Entity -``` + +  -> RequestMapper + +  -> Command + +  -> PropsMapper + +  -> Aggregate o Entity + +\`\`\` No mapear directamente: -```text -DTO -> Aggregate -``` +\`\`\`text -### Casos de uso +DTO -> Aggregate + +\`\`\` + +**### Casos de uso** Los casos de uso deben: -- orquestar; -- gestionar transacciones cuando corresponda; -- delegar en servicios de aplicación; -- devolver `Result`; -- construir respuestas mediante builders o mappers de salida. +\- orquestar; + +\- gestionar transacciones cuando corresponda; + +\- delegar en servicios de aplicación; + +\- devolver \`Result\`; + +\- construir respuestas mediante builders o mappers de salida. No deben: -- contener lógica HTTP; -- usar Sequelize directamente; -- construir agregados desde DTOs HTTP; -- asumir responsabilidades propias de repositorios o controllers. +\- contener lógica HTTP; -### Servicios de aplicación +\- usar Sequelize directamente; + +\- construir agregados desde DTOs HTTP; + +\- asumir responsabilidades propias de repositorios o controllers. + +**### Servicios de aplicación** Preferir servicios pequeños y explícitos con una responsabilidad clara. Evitar nombres genéricos como: -- `Manager`; -- `GenericService`; -- `CommandService`; -- `BaseRepository`; -- `Helper` sin semántica concreta. +\- \`Manager\`; -### Repositorios +\- \`GenericService\`; -- Cada repositorio gestiona un agregado o una responsabilidad concreta. -- Sequelize no debe salir de Infrastructure. -- Los repositorios deben usar mappers de persistencia. -- No crear repositorios base genéricos sin una necesidad demostrada. -- Mantener aislamiento por `companyId` y `branchId` cuando corresponda. +\- \`CommandService\`; -### Mappers de persistencia +\- \`BaseRepository\`; + +\- \`Helper\` sin semántica concreta. + +**### Repositorios** + +\- Cada repositorio gestiona un agregado o una responsabilidad concreta. + +\- Sequelize no debe salir de Infrastructure. + +\- Los repositorios deben usar mappers de persistencia. + +\- No crear repositorios base genéricos sin una necesidad demostrada. + +\- Mantener aislamiento por \`companyId\` y \`branchId\` cuando corresponda. + +**### Mappers de persistencia** Usar un mapper bidireccional por agregado: -```ts +\`\`\`ts + toPersistence(); + toDomain(); -``` -Infrastructure debe reconstruir entidades mediante `rehydrate()`. +\`\`\` -### `create()` y `rehydrate()` +Infrastructure debe reconstruir entidades mediante \`rehydrate()\`. + +**### \`create()\` y \`rehydrate()\`** Mantener separadas estas operaciones: -```text +\`\`\`text + create() - creación funcional - valida invariantes - puede fallar - devuelve Result + +  creación funcional + +  valida invariantes + +  puede fallar + +  devuelve Result rehydrate() - reconstrucción desde persistencia - no valida reglas de creación - no genera eventos - no devuelve Result -``` + +  reconstrucción desde persistencia + +  no valida reglas de creación + +  no genera eventos + +  no devuelve Result + +\`\`\` Reglas: -- Infrastructure usa `rehydrate()`. -- Application y Domain usan `create()` para nuevas instancias. -- `update()` no usa `create()` ni `rehydrate()`. -- Los Value Objects no tienen `rehydrate()`; se reconstruyen mediante `create()`. +\- Infrastructure usa \`rehydrate()\`. -### Comunicación entre módulos +\- Application y Domain usan \`create()\` para nuevas instancias. + +\- \`update()\` no usa \`create()\` ni \`rehydrate()\`. + +\- Los Value Objects no tienen \`rehydrate()\`; se reconstruyen mediante \`create()\`. + +**### Comunicación entre módulos** Los módulos solo deben colaborar mediante servicios públicos explícitos. No exponer: -- repositorios; -- modelos Sequelize; -- mappers internos; -- servicios de escritura internos; -- detalles de infraestructura. +\- repositorios; + +\- modelos Sequelize; + +\- mappers internos; + +\- servicios de escritura internos; + +\- detalles de infraestructura. El composition root de cada módulo debe construir sus dependencias explícitamente. -## Snapshots y builders de respuesta +**## Snapshots y builders de respuesta** Los schemas Zod definen el contrato de salida. @@ -421,150 +632,238 @@ Los snapshot builders solo materializan ese contrato. Reglas: -- Tipar el builder con el DTO inferido del schema exacto. -- No crear interfaces `I*Snapshot` que dupliquen un DTO. -- El builder debe ser determinista y no contener lógica de negocio. -- Puede convertir `Maybe` a `null`, Value Objects a primitivas y enums internos a valores de contrato. -- No puede acceder a repositorios ni infraestructura. -- Si cambia el schema, el builder debe fallar en compilación si deja de cumplir el contrato. +\- Tipar el builder con el DTO inferido del schema exacto. -## Frontend +\- No crear interfaces \`I\*Snapshot\` que dupliquen un DTO. -- Mantener React, TanStack Query, TanStack Table, React Hook Form, Zod, shadcn/ui, Tailwind e i18n según los patrones existentes. -- No duplicar estado remoto en estado local sin necesidad. -- Mantener las operaciones de servidor en TanStack Query. -- Centralizar las claves de query siguiendo la convención existente. -- Invalidar o actualizar caché de forma explícita tras mutaciones. -- No introducir efectos para derivar estado que pueda calcularse durante render. -- Evitar componentes monolíticos; extraer responsabilidades cuando exista una frontera clara. -- No extraer componentes triviales que solo oculten JSX sin aportar semántica. -- Mantener accesibilidad, estados disabled, loading, empty y error. -- No eliminar acciones no disponibles si la UX exige mostrarlas deshabilitadas. -- Mantener traducciones en `es` y `en` cuando se añadan textos visibles. -- No insertar textos de interfaz directamente si el área usa i18n. -- Mantener `tabular-nums` en columnas monetarias cuando corresponda. +\- El builder debe ser determinista y no contener lógica de negocio. -## APIs y errores +\- Puede convertir \`Maybe\` a \`null\`, Value Objects a primitivas y enums internos a valores de contrato. -- Usar errores tipados y predecibles. -- No devolver detalles internos, SQL, stack traces o información sensible. -- Mapear errores de dominio y aplicación a errores HTTP en Infrastructure. -- Mantener contratos de error estables. -- Aplicar idempotencia en operaciones que puedan repetirse. -- Validar autorización y aislamiento tenant antes de acceder o modificar datos. -- No confiar en identificadores de compañía enviados por el cliente sin verificar el contexto autenticado. -- Registrar información suficiente para diagnosticar fallos sin exponer datos sensibles. +\- No puede acceder a repositorios ni infraestructura. -## Seguridad +\- Si cambia el schema, el builder debe fallar en compilación si deja de cumplir el contrato. -- Aplicar principio de menor privilegio. -- No introducir secretos, tokens, claves o credenciales en el repositorio. -- No registrar datos sensibles. -- Validar toda entrada externa. -- Usar consultas parametrizadas y APIs seguras de Sequelize. -- Evitar interpolación manual de SQL. -- Revisar autorización además de autenticación. -- Mantener aislamiento multiempresa en todas las consultas y mutaciones. +**## Frontend** -## Base de datos y Sequelize +\- Mantener React, TanStack Query, TanStack Table, React Hook Form, Zod, shadcn/ui, Tailwind e i18n según los patrones existentes. -- Mantener nombres de tablas y columnas coherentes con las convenciones existentes. -- No introducir acceso directo a modelos Sequelize fuera de Infrastructure. -- Ejecutar operaciones agregadas dentro de una transacción cuando deban ser atómicas. -- Diseñar migraciones idempotentes cuando el procedimiento del proyecto lo requiera. -- No eliminar columnas, tablas o datos legacy sin una auditoría previa de referencias. -- No confiar únicamente en restricciones de aplicación cuando una invariante crítica pueda reforzarse en base de datos. -- Evitar `JSON.stringify` para detectar cambios de dominio. -- Comparar Value Objects semánticamente mediante sus primitivas o métodos de igualdad adecuados. +\- No duplicar estado remoto en estado local sin necesidad. -## Comandos y entorno de ejecución +\- Mantener las operaciones de servidor en TanStack Query. -El código se encuentra físicamente en una máquina Ubuntu compartida, aunque pueda aparecer en Windows como unidad `Z:`. +\- Centralizar las claves de query siguiendo la convención existente. -Preferir comandos para Linux ejecutados mediante SSH sobre Ubuntu. +\- Invalidar o actualizar caché de forma explícita tras mutaciones. -No usar rutas Windows como opción principal. +\- No introducir efectos para derivar estado que pueda calcularse durante render. + +\- Evitar componentes monolíticos; extraer responsabilidades cuando exista una frontera clara. + +\- No extraer componentes triviales que solo oculten JSX sin aportar semántica. + +\- Mantener accesibilidad, estados disabled, loading, empty y error. + +\- No eliminar acciones no disponibles si la UX exige mostrarlas deshabilitadas. + +\- Mantener traducciones en \`es\` y \`en\` cuando se añadan textos visibles. + +\- No insertar textos de interfaz directamente si el área usa i18n. + +\- Mantener \`tabular-nums\` en columnas monetarias cuando corresponda. + +**## APIs y errores** + +\- Usar errores tipados y predecibles. + +\- No devolver detalles internos, SQL, stack traces o información sensible. + +\- Mapear errores de dominio y aplicación a errores HTTP en Infrastructure. + +\- Mantener contratos de error estables. + +\- Aplicar idempotencia en operaciones que puedan repetirse. + +\- Validar autorización y aislamiento tenant antes de acceder o modificar datos. + +\- No confiar en identificadores de compañía enviados por el cliente sin verificar el contexto autenticado. + +\- Registrar información suficiente para diagnosticar fallos sin exponer datos sensibles. + +**## Seguridad** + +\- Aplicar principio de menor privilegio. + +\- No introducir secretos, tokens, claves o credenciales en el repositorio. + +\- No registrar datos sensibles. + +\- Validar toda entrada externa. + +\- Usar consultas parametrizadas y APIs seguras de Sequelize. + +\- Evitar interpolación manual de SQL. + +\- Revisar autorización además de autenticación. + +\- Mantener aislamiento multiempresa en todas las consultas y mutaciones. + +**## Base de datos y Sequelize** + +\- Mantener nombres de tablas y columnas coherentes con las convenciones existentes. + +\- No introducir acceso directo a modelos Sequelize fuera de Infrastructure. + +\- Ejecutar operaciones agregadas dentro de una transacción cuando deban ser atómicas. + +\- Diseñar migraciones idempotentes cuando el procedimiento del proyecto lo requiera. + +\- No eliminar columnas, tablas o datos legacy sin una auditoría previa de referencias. + +\- No confiar únicamente en restricciones de aplicación cuando una invariante crítica pueda reforzarse en base de datos. + +\- Evitar \`JSON.stringify\` para detectar cambios de dominio. + +\- Comparar Value Objects semánticamente mediante sus primitivas o métodos de igualdad adecuados. + +**## Comandos y entorno de ejecución** + +El código se encuentra físicamente dentro del filesystem Linux de WSL2, en: + +\`/home/david/dev/uecko-erp\` + +Ejecutar los comandos directamente en la distribución WSL \`Ubuntu-24.04\`. + +No ejecutar los comandos del proyecto mediante SSH contra la antigua máquina Ubuntu, salvo que la tarea lo requiera expresamente. + +No usar como workspace principal rutas Windows, unidades de red, rutas UNC, \`\\wsl$\\...\` ni rutas bajo \`/mnt/c\`. + +Preferir \`bash\` y herramientas Linux disponibles dentro de WSL. + +Antes de una tarea de código, comprobar al menos: + +\`\`\`bash + +pwd + +git status --short + +\`\`\` Ejemplos preferidos: -```bash -pnpm --filter typecheck -pnpm --filter lint -pnpm --filter test -``` +\`\`\`bash + +pnpm --filter \ typecheck + +pnpm --filter \ lint + +pnpm --filter \ test + +\`\`\` Usar comandos acotados al workspace afectado cuando sea suficiente. Usar comandos globales cuando el cambio pueda afectar contratos compartidos o varios workspaces. -## Validación obligatoria +**## Validación obligatoria** Antes de finalizar un cambio, ejecutar las comprobaciones relevantes disponibles para el área modificada: -```bash +\`\`\`bash + pnpm typecheck + pnpm lint + pnpm test -``` + +\`\`\` Cuando corresponda, ejecutar además: -```bash +\`\`\`bash + pnpm check + pnpm build -``` + +\`\`\` Criterios: -- Preferir validación dirigida al paquete o módulo afectado. -- Ejecutar validación global si se modifican paquetes compartidos, contratos o configuración transversal. -- Informar exactamente qué comandos se ejecutaron. -- Informar claramente cualquier validación no ejecutada y su motivo. -- No considerar completada una tarea con errores conocidos de lint, typecheck o tests salvo que el usuario haya limitado expresamente el alcance. +\- Preferir validación dirigida al paquete o módulo afectado. -## Tests +\- Ejecutar validación global si se modifican paquetes compartidos, contratos o configuración transversal. -- Añadir o actualizar tests cuando cambie comportamiento observable. -- No escribir tests que dependan de detalles internos irrelevantes. -- Cubrir casos válidos, inválidos, límites e idempotencia cuando corresponda. -- Mantener tests deterministas. -- No usar esperas arbitrarias. -- No desactivar tests para hacer pasar la suite. +\- Informar exactamente qué comandos se ejecutaron. -## Refactors +\- Informar claramente cualquier validación no ejecutada y su motivo. + +\- No considerar completada una tarea con errores conocidos de lint, typecheck o tests salvo que el usuario haya limitado expresamente el alcance. + +**## Tests** + +\- Añadir o actualizar tests cuando cambie comportamiento observable. + +\- No escribir tests que dependan de detalles internos irrelevantes. + +\- Cubrir casos válidos, inválidos, límites e idempotencia cuando corresponda. + +\- Mantener tests deterministas. + +\- No usar esperas arbitrarias. + +\- No desactivar tests para hacer pasar la suite. + +**## Refactors** Un refactor debe mantener el comportamiento salvo que se indique lo contrario. Antes de eliminar código legacy: -1. buscar referencias en todo el monorepo; -2. clasificar cada referencia como activa, legacy no cableada, migración, documentación o falso positivo; -3. revisar rutas, composition roots, DI, imports, modelos, repositorios, mappers, tests y scripts; -4. eliminar únicamente lo demostrado como no utilizado; -5. ejecutar typecheck, lint y tests relevantes; -6. documentar referencias residuales y motivos. +1\. buscar referencias en todo el monorepo; -## Respuesta final del agente +2\. clasificar cada referencia como activa, legacy no cableada, migración, documentación o falso positivo; + +3\. revisar rutas, composition roots, DI, imports, modelos, repositorios, mappers, tests y scripts; + +4\. eliminar únicamente lo demostrado como no utilizado; + +5\. ejecutar typecheck, lint y tests relevantes; + +6\. documentar referencias residuales y motivos. + +**## Respuesta final del agente** Al terminar una tarea de código, indicar de forma concisa: -- cambios realizados; -- decisiones relevantes; -- archivos principales modificados; -- comandos de validación ejecutados; -- resultado de las validaciones; -- riesgos o pendientes reales. +\- cambios realizados; + +\- decisiones relevantes; + +\- archivos principales modificados; + +\- comandos de validación ejecutados; + +\- resultado de las validaciones; + +\- riesgos o pendientes reales. No afirmar que algo compila, funciona o está probado si no se ha verificado. -## Regla de precedencia +**## Regla de precedencia** En caso de conflicto, aplicar este orden: -1. instrucciones explícitas del usuario para la tarea actual; -2. `AGENTS.md` más cercano al archivo modificado; -3. este `AGENTS.md` raíz; -4. convenciones existentes del código; -5. preferencias generales del agente. +1\. instrucciones explícitas del usuario para la tarea actual; -Si una instrucción contradice la arquitectura o genera un riesgo relevante, señalarlo antes de introducir el cambio. +2\. \`AGENTS.md\` más cercano al archivo modificado; + +3\. este \`AGENTS.md\` raíz; + +4\. convenciones existentes del código; + +5\. preferencias generales del agente. + +Si una instrucción contradice la arquitectura o genera un riesgo relevante, señalarlo antes de introducir el cambio. \ No newline at end of file diff --git a/apps/web/.env.development b/apps/web/.env.development index 956ae5f2..e8b47516 100644 --- a/apps/web/.env.development +++ b/apps/web/.env.development @@ -1 +1 @@ -VITE_API_SERVER_URL=http://192.168.0.104:3002/api/v1 +VITE_API_SERVER_URL=http://172.31.142.243:3002/api/v1 diff --git a/docs/recurring-proformas/DOCUMENTO DE DISEÑO — Información mostrada en las pantallas de recurring-proformas.md b/docs/recurring-proformas/DOCUMENTO DE DISEÑO — Información mostrada en las pantallas de recurring-proformas.md new file mode 100644 index 00000000..f8c0151b --- /dev/null +++ b/docs/recurring-proformas/DOCUMENTO DE DISEÑO — Información mostrada en las pantallas de recurring-proformas.md @@ -0,0 +1,1726 @@ +# DOCUMENTO DE DISEÑO — Información mostrada en las pantallas de `recurring-proformas` + +## 1. Objetivo + +Definir exclusivamente qué información debe presentar el frontend de **Proformas recurrentes** en estas pantallas: + +```text +/recurring-proformas +/recurring-proformas/create +/recurring-proformas/:recurring_proforma_id/update +``` + +Este documento no define: + +- arquitectura frontend; +- controllers; +- hooks; +- DTOs; +- endpoints; +- persistencia; +- scheduler; +- lógica de generación; +- diálogos de acciones; +- implementación de componentes. + +Su objetivo es fijar el **contenido funcional visible** de cada pantalla. + +--- + +# 2. Principios de presentación + +Una `RecurringProforma` debe entenderse visualmente como: + +```text +una plantilla comercial ++ +una programación temporal ++ +un estado de automatización +``` + +No debe presentarse como: + +```text +una Proforma futura +``` + +ni como: + +```text +una factura recurrente +``` + +El nombre visible de la funcionalidad será: + +```text +Proformas recurrentes +``` + +Debe distinguirse claramente entre: + +```text +configuración propia de la recurrencia +``` + +y: + +```text +valores heredados que se resolverán en cada generación +``` + +Especialmente para: + +- forma de pago; +- plazo de pago; +- idioma; +- moneda; +- serie de Proforma; +- serie de factura emitida. + +--- + +# 3. Pantalla de listado + +Ruta: + +```text +/recurring-proformas +``` + +La pantalla debe permitir conocer rápidamente: + +```text +qué recurrencia es +para qué cliente +en qué estado se encuentra +cada cuánto genera +cuándo debe generar de nuevo +si tiene alguna incidencia +cuándo se modificó por última vez +``` + +--- + +## 3.1 Cabecera + +Debe mostrar: + +```text +Proformas recurrentes +``` + +Puede incluir una descripción breve equivalente a: + +```text +Gestiona plantillas que generan Proformas automáticamente según un calendario. +``` + +Debe existir acceso visible a: + +```text +Nueva proforma recurrente +``` + +--- + +# 4. Filtro principal por estado + +Debe existir un filtro segmentado equivalente al utilizado en el listado de Proformas. + +Opciones: + +```text +Todas +Borrador +Activas +Pausadas +Completadas +``` + +No incluir: + +```text +Archivadas +``` + +Las recurrencias archivadas se consultan desde su listado específico. + +--- + +# 5. Búsqueda rápida + +Debe existir búsqueda rápida. + +Debe permitir localizar al menos por: + +```text +Nombre +Descripción interna +``` + +Cuando el backend lo soporte de forma consistente con los demás listados, también debe permitir localizar por: + +```text +Cliente +``` + +--- + +# 6. Filtro de incidencias + +Debe existir un filtro independiente: + +```text +Todas +Con incidencias +Sin incidencias +``` + +Una incidencia no debe mostrarse como un estado alternativo de la recurrencia. + +Ejemplo correcto: + +```text +Estado: Activa +Incidencia: Sí +``` + +No: + +```text +Estado: Incidencia +``` + +--- + +# 7. Información de la tabla + +Columnas principales: + +```text +Nombre +Cliente +Estado +Frecuencia +Próxima generación +Incidencias +Última actualización +Acciones +``` + +--- + +## 7.1 Nombre + +Mostrar: + +```text +RecurringProforma.name +``` + +Es la identificación interna principal de la recurrencia. + +La descripción interna no necesita aparecer como columna independiente. + +Puede mostrarse de forma secundaria junto al nombre si resulta útil y no sobrecarga la tabla. + +--- + +## 7.2 Cliente + +Mostrar el nombre actual del Customer asociado. + +Si se admite un `draft` sin Customer: + +```text +Sin cliente +``` + +Debe quedar visualmente claro que se trata de una configuración todavía incompleta. + +--- + +## 7.3 Estado + +Valores visibles: + +```text +Borrador +Activa +Pausada +Completada +``` + +En el listado de archivadas: + +```text +Archivada +``` + +El estado debe representarse mediante texto, aunque adicionalmente se utilice color o badge. + +--- + +## 7.4 Frecuencia + +Debe expresar el calendario en lenguaje funcional. + +Ejemplos: + +```text +Cada semana +Cada 2 semanas +Cada mes +Cada 3 meses +Cada año +Cada 2 años +``` + +Para recurrencias mensuales puede ser necesario mostrar además la regla: + +```text +Cada mes · mismo día +Cada mes · último día del mes +``` + +No debe obligarse al usuario a interpretar directamente: + +```text +unit = month +interval = 3 +monthlyRule = same_day +``` + +--- + +## 7.5 Próxima generación + +Mostrar: + +```text +nextOccurrenceDate +``` + +formateada según locale. + +Ejemplo: + +```text +15/09/2026 +``` + +Para estados sin próxima generación: + +```text +draft +completed +archived +``` + +mostrar: + +```text +— +``` + +Una recurrencia pausada conserva su `nextOccurrenceDate`, por lo que debe seguir mostrándose. + +Puede acompañarse visualmente del estado pausado, pero no debe ocultarse. + +--- + +## 7.6 Incidencias + +Mostrar si existe alguna occurrence fallida. + +Valores recomendados: + +```text +Sin incidencias +Incidencia +``` + +No mostrar directamente en la tabla: + +```text +lastErrorMessage +``` + +La tabla debe limitarse a señalar que existe una incidencia. + +--- + +## 7.7 Última actualización + +Mostrar: + +```text +updatedAt +``` + +formateado según locale. + +Su objetivo es permitir identificar rápidamente recurrencias modificadas recientemente. + +--- + +# 8. Listado de archivadas + +Ruta: + +```text +/recurring-proformas/archived +``` + +Debe reutilizar la misma estructura de información: + +```text +Nombre +Cliente +Estado +Frecuencia +Próxima generación +Incidencias +Última actualización +Acciones +``` + +Con: + +```text +status = archived +``` + +fijo. + +Para una recurrencia archivada: + +```text +Próxima generación = — +Estado = Archivada +``` + +--- + +# 9. Pantalla de creación + +Ruta: + +```text +/recurring-proformas/create +``` + +La pantalla debe presentar la configuración agrupada en: + +```text +Identificación interna +Cliente +Contenido comercial +Condiciones heredables +Calendario +``` + +La pantalla representa la creación de una plantilla en estado: + +```text +draft +``` + +Por tanto, puede guardarse aunque todavía esté incompleta. + +--- + +# 10. Creación — Identificación interna + +## 10.1 Nombre + +Campo: + +```text +Nombre +``` + +Obligatorio. + +Debe ser claramente identificable como nombre interno de la recurrencia. + +Ejemplos: + +```text +Mantenimiento mensual ACME +Cuota trimestral Cliente Norte +Servicio anual hosting +``` + +No debe sugerirse que este nombre aparecerá en las Proformas generadas. + +--- + +## 10.2 Descripción interna + +Campo: + +```text +Descripción interna +``` + +Opcional. + +Debe incluir ayuda visible indicando: + +```text +Solo para uso interno. No se copiará a las Proformas generadas. +``` + +Esta distinción es importante porque la recurrencia también puede contener una descripción comercial propia de las Proformas que generará. + +--- + +# 11. Creación — Cliente + +Debe existir una sección: + +```text +Cliente +``` + +Debe mostrar el Customer seleccionado. + +Mientras no exista: + +```text +Sin cliente seleccionado +``` + +Debe quedar claro que un draft puede guardarse sin Customer, pero que será necesario antes de activar la recurrencia. + +Cuando haya Customer seleccionado, mostrar como mínimo: + +```text +Nombre +NIF/CIF, si forma parte del selector actual +``` + +y cualquier identificación secundaria ya utilizada de forma consistente por el selector de Customer del ERP. + +--- + +# 12. Creación — Contenido comercial + +Esta sección representa la información que se copiará a cada nueva Proforma. + +Debe mostrar los campos comerciales que finalmente se confirmen tras auditar el modelo real de `Proforma`. + +Conceptualmente incluye: + +```text +Descripción comercial +Notas +Observaciones +Términos +Textos comerciales +Descuento global +Líneas +``` + +Solo deben mostrarse campos que realmente existan en el modelo actual de Proforma. + +No inventar nuevos campos comerciales específicos de `RecurringProforma`. + +--- + +# 13. Creación — Líneas + +Debe existir el editor de líneas de la plantilla. + +Cada línea contiene conceptualmente: + +```text +Descripción +Cantidad +Precio unitario +Descuento +``` + +No mostrar configuración fiscal materializada por línea propia de la recurrencia. + +La recurrencia no almacena: + +```text +impuestos +tax breakdown +totales fiscales +``` + +La fiscalidad se resolverá cuando se genere cada Proforma. + +En `draft` debe permitirse: + +```text +0 líneas +``` + +--- + +# 14. Creación — Condiciones heredables + +Debe existir una sección específica que explique claramente la diferencia entre: + +```text +Heredar +``` + +y: + +```text +Fijar un valor explícito +``` + +Campos: + +```text +Plazo de pago +Forma de pago +Idioma +Moneda +Serie de Proforma +Serie de factura emitida +``` + +--- + +# 15. Representación de campos heredables + +Cada campo debe mostrar dos conceptos: + +```text +valor configurado por el usuario +valor que actualmente se resolvería +``` + +Ejemplo: + +```text +Forma de pago + +Heredar del cliente +Actualmente: Transferencia +``` + +Si existe override: + +```text +Forma de pago + +Transferencia +Valor fijado para esta recurrencia +``` + +No debe mostrarse simplemente: + +```text +Transferencia +``` + +cuando realmente: + +```text +configuredId = null +``` + +porque ocultaría que el valor es dinámico. + +--- + +# 16. Plazo de pago + +Mostrar: + +```text +Heredar +``` + +más las opciones seleccionables existentes. + +Cuando se hereda, mostrar el valor actualmente resuelto. + +Ejemplo: + +```text +Heredar +Actualmente: 30 días +``` + +--- + +# 17. Forma de pago + +Misma semántica: + +```text +Heredar +Actualmente: Transferencia +``` + +o un valor explícito seleccionado. + +--- + +# 18. Idioma + +Debe mostrar: + +```text +Heredar +``` + +o un idioma explícito. + +Cuando se herede: + +```text +Actualmente: Español +``` + +--- + +# 19. Moneda + +Debe mostrar: + +```text +Heredar +``` + +o una moneda explícita. + +Cuando se herede: + +```text +Actualmente: EUR +``` + +--- + +# 20. Serie de Proforma + +Debe permitir distinguir: + +```text +usar resolución/default vigente +``` + +frente a: + +```text +usar esta serie concreta +``` + +Ejemplo: + +```text +Heredar serie predeterminada +Actualmente: PROFORMAS 2026 +``` + +--- + +# 21. Serie de factura emitida + +Debe utilizar la misma representación. + +Debe dejar claro que esta configuración: + +```text +solo se copiará como preferencia a la Proforma generada +``` + +y: + +```text +no provoca la emisión automática de una factura. +``` + +--- + +# 22. Creación — Calendario + +Debe existir una sección: + +```text +Calendario +``` + +Debe mostrar/configurar: + +```text +Fecha de inicio +Frecuencia +Intervalo +Regla mensual, cuando corresponda +Fecha de finalización opcional +``` + +--- + +# 23. Fecha de inicio + +Campo: + +```text +Primera generación +``` + +o: + +```text +Fecha de inicio +``` + +Debe explicarse que representa: + +```text +la primera fecha programada de la recurrencia. +``` + +--- + +# 24. Frecuencia e intervalo + +La UI debe permitir expresar: + +```text +cada N semanas +cada N meses +cada N años +``` + +La información visible debe poder entenderse directamente. + +Ejemplos: + +```text +Cada 2 semanas +Cada mes +Cada 3 meses +Cada año +``` + +--- + +# 25. Regla mensual + +Solo aparece cuando: + +```text +Frecuencia = meses +``` + +Opciones: + +```text +Mismo día del mes +Último día del mes +``` + +La interfaz debe explicar suficientemente la diferencia. + +Para: + +```text +Mismo día del mes +``` + +si el día no existe en un determinado mes se utilizará el último día válido. + +Para: + +```text +Último día del mes +``` + +las siguientes fechas después de la primera utilizarán el último día del mes correspondiente. + +--- + +# 26. Fecha de finalización + +Campo opcional: + +```text +Fecha de finalización +``` + +Debe permitir expresar: + +```text +Sin fecha de finalización +``` + +cuando la recurrencia sea indefinida. + +Debe quedar claro que la fecha: + +```text +limita el calendario +``` + +pero no crea por sí misma una generación adicional. + +--- + +# 27. Preview del calendario + +La pantalla debe mostrar una vista previa de aproximadamente: + +```text +3–5 próximas fechas +``` + +Ejemplo: + +```text +Próximas fechas + +01/09/2026 +01/10/2026 +01/11/2026 +01/12/2026 +``` + +Debe actualizarse según la configuración del calendario. + +Este preview es especialmente importante para: + +```text +día 29 de febrero +día 31 +último día del mes +intervalos superiores a 1 +``` + +--- + +# 28. Información que NO debe mostrarse como configuración en creación + +No deben existir campos editables para: + +```text +Estado +nextOccurrenceDate +Occurrence +Intentos +Último error +Proforma generada +Fecha de generación +Impuestos materializados +Totales derivados +Referencia documental +Fecha de Proforma +Fecha de operación +VeriFactu +``` + +Estos conceptos no forman parte de la configuración inicial editable de una `RecurringProforma`. + +--- + +# 29. Estado del draft en creación + +Debe quedar claro que: + +```text +la plantilla se guardará como Borrador +``` + +y que: + +```text +guardar +``` + +no equivale a: + +```text +activar +``` + +La creación inicial solo requiere: + +```text +Nombre +``` + +El resto puede completarse posteriormente. + +--- + +# 30. Pantalla de edición + +Ruta: + +```text +/recurring-proformas/:recurring_proforma_id/update +``` + +Debe mantener las mismas secciones principales de creación: + +```text +Identificación interna +Cliente +Contenido comercial +Condiciones heredables +Calendario +``` + +y añadir información contextual sobre el estado operativo de la recurrencia. + +--- + +# 31. Edición — Cabecera + +Debe mostrar como mínimo: + +```text +Nombre +Estado +``` + +Estados posibles en una pantalla editable: + +```text +Borrador +Activa +Pausada +``` + +`completed` y `archived` son inmutables, por lo que no deben presentarse como formularios editables. + +--- + +# 32. Edición — Resumen operativo + +Cuando la recurrencia esté: + +```text +active +paused +``` + +debe mostrarse información operativa relevante: + +```text +Estado +Próxima generación +Existencia de incidencias +``` + +Ejemplo: + +```text +Estado +Activa + +Próxima generación +01/10/2026 + +Incidencias +Sin incidencias +``` + +Para `paused`, la próxima fecha debe seguir mostrándose: + +```text +Estado +Pausada + +Próxima generación +01/10/2026 +``` + +porque la pausa no desplaza el calendario. + +--- + +# 33. Edición — Identificación interna + +Mostrar los mismos campos que en creación: + +```text +Nombre +Descripción interna +``` + +Manteniendo la indicación: + +```text +La descripción interna no se copia a las Proformas generadas. +``` + +--- + +# 34. Edición — Cliente + +Mostrar el Customer actualmente configurado. + +Debe quedar claro que un cambio de Customer: + +```text +afectará únicamente a futuras Proformas +``` + +y no modificará las ya generadas. + +En estado: + +```text +active +paused +``` + +no debe presentarse la posibilidad de dejar el Customer vacío como un estado válido. + +--- + +# 35. Edición — Contenido comercial + +Mostrar los mismos campos comerciales configurables que en creación. + +Debe existir una indicación contextual cuando ya haya Proformas generadas: + +```text +Los cambios solo se aplicarán a futuras generaciones. +Las Proformas existentes no se modificarán. +``` + +Este mensaje es especialmente relevante para: + +```text +líneas +descripción comercial +descuentos +condiciones comerciales +Customer +``` + +--- + +# 36. Edición — Líneas + +Mostrar: + +```text +Descripción +Cantidad +Precio unitario +Descuento +``` + +de cada línea. + +Cuando la recurrencia esté activa o pausada, no debe permitir conceptualmente que el estado guardado resultante contenga: + +```text +0 líneas +``` + +aunque esta restricción pertenezca a la validación y no al contenido visual. + +--- + +# 37. Edición — Condiciones heredables + +Mostrar exactamente la misma distinción que en creación: + +```text +valor configurado +vs +valor actualmente resuelto +``` + +Ejemplo: + +```text +Plazo de pago + +Heredar +Actualmente: 30 días +``` + +Debe tener especial importancia en edición porque el valor heredado actualmente resuelto puede haber cambiado desde que se creó la recurrencia. + +--- + +# 38. Cambio dinámico de valores heredados + +Si un valor es heredado y actualmente se resuelve de forma diferente a la que el usuario pudo ver anteriormente, la pantalla debe mostrar únicamente: + +```text +la configuración sigue siendo Heredar ++ +el valor actualmente resuelto +``` + +No debe convertir visual ni funcionalmente ese valor en override. + +Ejemplo: + +```text +Forma de pago +Heredar +Actualmente: Domiciliación bancaria +``` + +aunque anteriormente hubiera sido: + +```text +Transferencia +``` + +--- + +# 39. Override explícito + +Cuando exista override debe mostrarse claramente como valor fijo. + +Ejemplo: + +```text +Forma de pago +Transferencia + +Configurada específicamente para esta recurrencia +``` + +No presentarlo como valor heredado. + +--- + +# 40. Edición — Calendario sin historial + +Mientras no exista ninguna occurrence, deben mostrarse como editables: + +```text +Fecha de inicio +Frecuencia +Intervalo +Regla mensual +Fecha de finalización +``` + +Debe seguir mostrándose el preview de próximas fechas. + +--- + +# 41. Edición — Calendario con historial + +Una vez exista al menos una occurrence, deben seguir mostrándose: + +```text +Fecha de inicio +Frecuencia +Intervalo +Regla mensual +Fecha de finalización +``` + +pero debe quedar visualmente diferenciado que: + +```text +Fecha de inicio +Frecuencia +Intervalo +Regla mensual +``` + +forman parte de un calendario ya iniciado y no pueden modificarse. + +Debe acompañarse de una explicación equivalente a: + +```text +La cadencia no puede modificarse porque la recurrencia ya tiene historial. +Para utilizar otra programación, completa esta recurrencia y crea una nueva mediante duplicación. +``` + +`Fecha de finalización` continúa siendo configurable según las reglas del dominio. + +--- + +# 42. Próximas fechas en edición + +Debe mantenerse el preview del calendario. + +En una recurrencia activa o pausada resulta útil distinguir: + +```text +Próxima generación +``` + +de: + +```text +Siguientes fechas del calendario +``` + +Ejemplo: + +```text +Próxima generación +01/10/2026 + +Siguientes fechas +01/10/2026 +01/11/2026 +01/12/2026 +01/01/2027 +``` + +--- + +# 43. Información sobre incidencias en edición + +Si: + +```text +hasIssue = true +``` + +la pantalla debe mostrar una advertencia visible. + +Debe informar, como mínimo: + +```text +Existe una generación fallida pendiente de resolver. +``` + +La incidencia no debe alterar visualmente el estado principal: + +```text +Activa + Incidencia +``` + +no: + +```text +Estado = Fallida +``` + +Puede mostrarse información funcional derivada de `lastErrorCode`. + +No mostrar indiscriminadamente: + +```text +lastErrorMessage +``` + +como mensaje principal al usuario. + +--- + +# 44. Historial de generaciones dentro de edición + +El diseño general establece un historial de occurrences. + +Si se incluye dentro de la pantalla de edición, debe aparecer separado del formulario principal y como información operativa, no como configuración. + +Columnas: + +```text +Fecha programada +Estado +Proforma +Factura emitida +Intentos +Último intento +Acciones +``` + +Estados visibles: + +```text +Pendiente +Procesando +Fallida +Generada +``` + +--- + +# 45. Fecha programada + +Mostrar: + +```text +Occurrence.scheduledDate +``` + +No confundir con: + +```text +fecha en la que realmente se generó la Proforma +``` + +Especialmente importante en generaciones anticipadas. + +--- + +# 46. Proforma generada + +Para occurrences generadas debe mostrarse la referencia de la Proforma asociada cuando esté disponible. + +Debe permitir identificar claramente: + +```text +qué Proforma produjo esa occurrence. +``` + +Si no existe: + +```text +— +``` + +--- + +# 47. Factura emitida + +Si la Proforma generada fue posteriormente emitida, puede mostrarse la factura resultante como información derivada. + +La recurrencia no almacena directamente: + +```text +issuedInvoiceId +``` + +por lo que esta información debe tratarse visualmente como resultado posterior de la Proforma. + +Si no existe: + +```text +— +``` + +--- + +# 48. Intentos + +Mostrar: + +```text +attemptCount +``` + +Ejemplos: + +```text +1 +2 +3 +``` + +--- + +# 49. Último intento + +Mostrar: + +```text +lastAttemptAt +``` + +según locale. + +Si todavía no existe: + +```text +— +``` + +--- + +# 50. Información de occurrences fallidas + +Cuando una occurrence esté fallida debe mostrar una explicación funcional basada en: + +```text +lastErrorCode +``` + +Ejemplos conceptuales: + +```text +El cliente está inactivo +La forma de pago configurada ya no está disponible +La serie configurada no está disponible +La configuración fiscal actual no permite generar la Proforma +``` + +El detalle técnico: + +```text +lastErrorMessage +``` + +no debe utilizarse como texto principal de interfaz. + +--- + +# 51. Información que debe distinguirse siempre en edición + +La pantalla debe permitir identificar sin ambigüedad cuatro conceptos diferentes: + +```text +1. Configuración interna +2. Configuración comercial de futuras Proformas +3. Calendario +4. Estado de ejecución +``` + +No mezclar visualmente: + +```text +Nombre interno +Descripción interna +``` + +con: + +```text +Descripción comercial +Notas de Proforma +``` + +Tampoco mezclar: + +```text +Próxima generación +``` + +con: + +```text +Fecha de inicio +``` + +--- + +# 52. Información según estado + +## Draft + +Mostrar: + +```text +Estado: Borrador +``` + +Puede presentar información incompleta: + +```text +Sin cliente +Sin líneas +Sin calendario +Sin condiciones comerciales completas +``` + +No debe intentar aparentar que está preparada para ejecutarse. + +--- + +## Active + +Mostrar: + +```text +Estado: Activa +Próxima generación +Incidencias +``` + +Toda la configuración mostrada debe representar un estado actualmente generable, salvo que exista una incidencia provocada posteriormente por cambios externos. + +--- + +## Paused + +Mostrar: + +```text +Estado: Pausada +Próxima generación +Incidencias +``` + +Debe indicarse que: + +```text +la programación permanece intacta durante la pausa. +``` + +--- + +# 53. Información histórica frente a información futura + +En una recurrencia con historial debe quedar clara esta frontera: + +```text +Configuración de la recurrencia +→ afecta futuras occurrences + +Historial +→ refleja executions ya realizadas +``` + +Modificar la primera nunca implica modificar la segunda. + +Mensaje recomendado: + +```text +Los cambios realizados aquí solo afectan a futuras Proformas. +Las Proformas ya generadas conservan sus datos originales. +``` + +--- + +# 54. Resumen de información por pantalla + +## Listado + +Mostrar: + +```text +Nombre +Cliente +Estado +Frecuencia +Próxima generación +Incidencias +Última actualización +``` + +Más: + +```text +búsqueda +filtro de estado +filtro de incidencias +``` + +--- + +## Creación + +Mostrar: + +```text +Identificación interna + Nombre + Descripción interna + +Cliente + +Contenido comercial + Campos comerciales reales de Proforma + Líneas + Descuentos y demás configuración aplicable + +Condiciones heredables + Plazo de pago + Forma de pago + Idioma + Moneda + Serie de Proforma + Serie de factura emitida + +Calendario + Fecha de inicio + Frecuencia + Intervalo + Regla mensual + Fecha de finalización + Preview de próximas fechas +``` + +--- + +## Edición + +Mostrar todo lo anterior más: + +```text +Estado +Próxima generación +Incidencias + +Información de que los cambios afectan solo al futuro + +Bloqueo visual de la cadencia si ya existe historial + +Historial de occurrences, cuando se integre en esta pantalla +``` + +--- + +# 55. Información que no debe duplicarse + +No añadir campos derivados editables como: + +```text +Frecuencia legible +Próxima fecha calculada +hasIssue +Última generación +Número de occurrences +``` + +Estos datos, cuando se muestren, son exclusivamente información calculada/de lectura. + +No deben convertirse en configuración persistida por el usuario. + +--- + +# 56. Criterio final de diseño + +Al abrir cualquiera de estas pantallas el usuario debe poder responder rápidamente: + +## En el listado + +```text +¿Qué recurrencias tengo? +¿Cuáles están activas? +¿Cuándo generan? +¿Cuáles tienen problemas? +``` + +## En creación + +```text +¿Qué Proforma quiero generar repetidamente? +¿Para qué cliente? +¿Qué valores quiero heredar? +¿Cada cuánto debe generarse? +``` + +## En edición + +```text +¿Qué está configurado actualmente? +¿Qué valores son heredados y cuáles están fijados? +¿Cuándo se generará de nuevo? +¿Tiene alguna incidencia? +¿Qué cambios afectarán a futuras Proformas? +¿El calendario todavía puede modificarse? +``` + +La prioridad visual debe ser que estas respuestas sean evidentes sin exponer al usuario conceptos internos de implementación como: + +```text +configured_id +resolved +nextOccurrenceDate +monthlyRule +Occurrence aggregate +``` + +aunque dichos conceptos existan internamente en el sistema. \ No newline at end of file diff --git a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/models/sequelize-issued-invoice.model.ts b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/models/sequelize-issued-invoice.model.ts index f05ea96b..d339368c 100644 --- a/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/models/sequelize-issued-invoice.model.ts +++ b/modules/customer-invoices/src/api/infrastructure/common/persistence/sequelize/models/sequelize-issued-invoice.model.ts @@ -547,7 +547,7 @@ export default (database: Sequelize) => { { name: "idx_qs_issued_invoices", type: "FULLTEXT", - fields: ["invoice_number", "reference", "description"], + fields: ["invoice_number", "invoice_reference", "reference", "description"], }, ], whereMergeStrategy: "and",