- Implemented API for updating company Verifactu profile. - Created entities for company Verifactu profile and defaults. - Developed hooks for querying and updating the company Verifactu profile. - Added UI components for displaying and editing company Verifactu settings. - Introduced validation and error handling for profile updates. - Created utility functions for building form data and handling feedback states. - Added tests for utility functions and error handling.
4.7 KiB
4.7 KiB
Frontend ERP – Settings VeriFactu
Estado
Implementado en V1 como primera pantalla funcional del sistema modular de Settings:
/settings/billing/verifactu
Arquitectura real
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-invoicespublica una única entry de Settings:
{
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:
API
→ DTO common
→ adapter
→ Entity
→ React Query hook
→ controller
→ page controller
→ UI
Archivos clave:
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:
CompanyVerifactuProfileResponseDTOUpdateCompanyVerifactuProfileRequestDTOUpdateCompanyVerifactuProfileRequestSchema
No se usan DTOs snake_case directamente en UI.
Entity frontend
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:
Form ≠ Entity ≠ DTO ≠ Params
El formulario:
- usa
camelCase; - convierte
updatedAtfuera del form; - guarda
verifactuEffectiveAtcomo fecha civilyyyy-MM-dd; - normaliza strings vacíos a
nullen 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
taxRegimeCodeusa el catálogo real existente a través de:
@erp/catalogs/client/tax-regimes
No implementado todavía
operationQualificationCodedefaults.exemptionReasonCodeexemptionReasonCodecomo 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:
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
ErrorAlerty 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
operationQualificationCodeni para motivos de exención; - no se implementa ninguna UI de certificados;
- no se integra con
IssuedInvoiceni con estados operativos AEAT.