FactuGES_ERP/docs/customer-invoices/settings/frontend-erp-settings-verifactu-design.md

210 lines
4.7 KiB
Markdown
Raw Normal View History

# Frontend ERP – Settings VeriFactu
## Estado
Implementado en V1 como primera pantalla funcional del sistema modular de Settings:
```txt
/settings/billing/verifactu
```
## Arquitectura real
```txt
CustomerInvoicesModuleManifest.settings.entries
│
├── SettingsNavigation
└── buildSettingsRoute(pathPrefix="settings")
│
▼
customer-invoices route: settings/billing/verifactu
│
▼
Page Controller
├── useCompanyVerifactuProfileQuery
└── useCompanyVerifactuProfileController
│
▼
UI sections
├── status
├── configuration
└── defaults
```
## Integración con Settings
- El módulo `customer-invoices` publica una única entry de Settings:
```ts
{
id: "verifactu",
sectionId: "billing",
labelKey: "settings.verifactu.title",
path: "/settings/billing/verifactu",
}
```
- La pantalla se registra como ruta modular del propio módulo con `path: "settings/billing/verifactu"`.
- No se modificó el shell de Settings para esta feature.
## Capa de datos
Estructura implementada:
```txt
API
→ DTO common
→ adapter
→ Entity
→ React Query hook
→ controller
→ page controller
→ UI
```
Archivos clave:
```txt
modules/customer-invoices/src/web/settings/verifactu/shared/
modules/customer-invoices/src/web/settings/verifactu/controllers/
modules/customer-invoices/src/web/settings/verifactu/ui/
```
## DTOs reutilizados
Se reutilizan los DTOs publicados por `@erp/customer-invoices/common`:
- `CompanyVerifactuProfileResponseDTO`
- `UpdateCompanyVerifactuProfileRequestDTO`
- `UpdateCompanyVerifactuProfileRequestSchema`
No se usan DTOs `snake_case` directamente en UI.
## Entity frontend
```ts
interface CompanyVerifactuProfile {
profileStatus:
| "not_configured"
| "exempt"
| "obligated_without_verifactu"
| "obligated_with_verifactu";
configured: boolean;
usesVerifactu: boolean;
exemptionReasonCode: string | null;
exemptionReasonDetail: string | null;
verifactuEffectiveAt: string | null;
autoRenewMode: "disabled" | "enabled" | null;
defaults: {
taxRegimeCode: string | null;
operationQualificationCode: string | null;
exemptionReasonCode: string | null;
};
updatedAt: string | null;
}
```
## Form model
Se mantiene la separación:
```txt
Form ≠ Entity ≠ DTO ≠ Params
```
El formulario:
- usa `camelCase`;
- convierte `updatedAt` fuera del form;
- guarda `verifactuEffectiveAt` como fecha civil `yyyy-MM-dd`;
- normaliza strings vacíos a `null` en el builder de salida.
## Reglas implementadas en frontend
### Estado `not_configured`
- no muestra una opción explícita de radio;
- se usa como estado técnico inicial;
- al guardar se obliga al usuario a elegir un estado configurado real;
- limpia defaults y campos de exención/VeriFactu.
### Estado `exempt`
- muestra solo detalle libre de exención;
- no muestra activación VeriFactu;
- no inventa catálogo de motivos de exención.
### Estado `obligated_without_verifactu`
- limpia `verifactuEffectiveAt`;
- limpia `autoRenewMode`.
### Estado `obligated_with_verifactu`
- muestra `verifactuEffectiveAt`;
- muestra `autoRenewMode`;
- requiere fecha efectiva en Zod.
## Catálogos
### Reutilizado
- `taxRegimeCode` usa el catálogo real existente a través de:
```txt
@erp/catalogs/client/tax-regimes
```
### No implementado todavía
- `operationQualificationCode`
- `defaults.exemptionReasonCode`
- `exemptionReasonCode` como catálogo legal
En V1 no se inventan selects vacíos ni códigos ficticios. Se documenta la limitación en la propia UI.
## UX implementada
La pantalla se resuelve como editor único, no wizard:
```txt
1. Situación
2. Configuración VeriFactu
3. Valores por defecto
4. Footer sticky con guardar/restaurar
```
Se priorizó una primera versión estable y verificable.
## Errores y loading
- Carga inicial con skeleton.
- Error de carga con `PageErrorState`.
- Error de guardado con `ErrorAlert` y toasts.
- Validación de form con foco al primer error.
## Cambio de empresa
No se añadió lógica específica.
La feature depende del comportamiento global ya existente:
- tenant context del ERP;
- reset global de React Query al cambiar de empresa;
- `form.reset(...)` al recibir el nuevo perfil.
## Tests añadidos
- adapter `snake_case -> camelCase`
- builder de `Form -> Update params`
- page error view model
- page feedback state
- manifest/routing básico del módulo
## Limitaciones reales de esta V1
- no hay wizard inicial;
- no hay catálogo backend para `operationQualificationCode` ni para motivos de exención;
- no se implementa ninguna UI de certificados;
- no se integra con `IssuedInvoice` ni con estados operativos AEAT.