# 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.