# RF-CATALOG-001: Gestion de Contactos ## Identificacion | Campo | Valor | |-------|-------| | **ID** | RF-CATALOG-001 | | **Modulo** | MGN-005 Catalogs | | **Titulo** | Gestion de Contactos | | **Prioridad** | Alta | | **Estado** | Draft | | **Fecha** | 2025-12-05 | --- ## Descripcion El sistema debe permitir gestionar contactos (empresas, personas, direcciones) que representan clientes, proveedores, empleados y otros terceros relacionados con el tenant. **Referencia Odoo:** `res.partner` (odoo/addons/base/models/res_partner.py) --- ## Requisitos Funcionales ### RF-CATALOG-001.1: Tipos de Contacto El sistema debe soportar tres tipos de contacto: | Tipo | Descripcion | Puede tener hijos | |------|-------------|-------------------| | `company` | Empresa/Organizacion | Si | | `individual` | Persona fisica independiente | No | | `contact` | Contacto de una empresa (empleado) | No | **Reglas:** - Un contacto tipo `contact` DEBE tener `parent_id` (empresa padre) - Un contacto tipo `company` puede tener contactos hijos - Un contacto tipo `individual` NO puede tener hijos ### RF-CATALOG-001.2: Roles de Contacto Un contacto puede tener uno o mas roles: ```typescript enum ContactRole { CUSTOMER = 'customer', // Puede comprar VENDOR = 'vendor', // Puede vender EMPLOYEE = 'employee', // Empleado interno OTHER = 'other' // Otro tipo } ``` **Reglas:** - Un contacto puede ser cliente Y proveedor simultaneamente - El rol `employee` permite vincular con tabla `users` - Los roles determinan visibilidad en diferentes modulos ### RF-CATALOG-001.3: Datos de Identificacion Campos obligatorios y opcionales de identificacion: | Campo | Obligatorio | Descripcion | |-------|-------------|-------------| | name | Si | Nombre completo | | display_name | Auto | Computed: incluye parent name | | ref | No | Codigo interno del tenant | | vat | Condicional | RFC/NIT/RUT (obligatorio si es facturador) | | company_registry | No | Registro mercantil | **Validaciones:** - VAT debe validarse segun formato del pais - REF debe ser unico dentro del tenant ### RF-CATALOG-001.4: Datos de Contacto | Campo | Tipo | Validacion | |-------|------|------------| | email | string | Formato email valido | | phone | string | Formato segun pais | | mobile | string | Formato segun pais | | website | string | URL valida | ### RF-CATALOG-001.5: Direcciones El sistema debe soportar direccion estructurada: | Campo | Tipo | Descripcion | |-------|------|-------------| | street | string | Calle principal | | street2 | string | Linea adicional | | city | string | Ciudad | | zip | string | Codigo postal | | state_id | FK | Estado/Provincia (global) | | country_id | FK | Pais (global) | **Referencia:** El formato de direccion varia por pais (ver `res.country.address_format`) ### RF-CATALOG-001.6: Contactos Hijos Para empresas, se pueden agregar contactos relacionados: ```typescript interface ContactChild { parent_id: UUID; // Empresa padre contact_type: 'contact'; // Siempre 'contact' function: string; // Cargo/Puesto name: string; // Nombre del contacto email: string; // Email directo phone: string; // Telefono directo } ``` **Reglas:** - Un contacto hijo hereda direccion del padre si no tiene propia - Al eliminar empresa, contactos hijos se eliminan en cascada ### RF-CATALOG-001.7: Vinculacion con Usuarios Un contacto puede vincularse con un usuario del sistema: ```typescript interface ContactUserLink { contact_id: UUID; user_id: UUID; // FK a core_users.users } ``` **Reglas:** - Un usuario puede tener UN contacto asociado - Un contacto puede tener UN usuario asociado - Esta relacion se usa para empleados que son usuarios **Diferencia con Odoo:** En Odoo, `res.users` hereda de `res.partner` mediante `_inherits`. Nosotros usamos FK explicita para mayor claridad. ### RF-CATALOG-001.8: Campos Comerciales Para clientes/proveedores: | Campo | Tipo | Descripcion | |-------|------|-------------| | currency_id | FK | Moneda preferida | | payment_term_days | int | Dias de credito | | credit_limit | decimal | Limite de credito | | bank_accounts | JSONB | Cuentas bancarias | ### RF-CATALOG-001.9: Tags/Categorias Los contactos pueden tener multiples tags: ```sql -- Tabla de tags core_catalogs.contact_tags ( id, tenant_id, name, color, parent_id ) -- Relacion M:N core_catalogs.contact_tag_rel ( contact_id, tag_id ) ``` --- ## Operaciones CRUD ### Crear Contacto ```typescript POST /api/v1/contacts { "name": "Empresa Demo S.A.", "contactType": "company", "roles": ["customer", "vendor"], "vat": "RFC123456789", "email": "contacto@demo.com", "phone": "+52 55 1234 5678", "address": { "street": "Av. Principal 123", "city": "Ciudad de Mexico", "stateId": "uuid-estado", "countryId": "uuid-mexico", "zip": "06600" }, "tags": ["uuid-tag-1", "uuid-tag-2"] } ``` ### Listar Contactos ```typescript GET /api/v1/contacts?role=customer&type=company&search=demo&page=1&limit=20 Response: { "data": [...], "meta": { "total": 100, "page": 1, "limit": 20 } } ``` ### Busqueda Rapida ```typescript GET /api/v1/contacts/search?q=demo&limit=10 // Busca en: name, email, vat, ref, phone ``` ### Obtener Contacto con Hijos ```typescript GET /api/v1/contacts/:id?include=children,tags Response: { "id": "uuid", "name": "Empresa Demo", "children": [...], "tags": [...] } ``` --- ## Reglas de Negocio | ID | Regla | Severidad | |----|-------|-----------| | BR-001 | VAT unico por tenant (si existe) | Error | | BR-002 | REF unico por tenant (si existe) | Error | | BR-003 | Email formato valido | Error | | BR-004 | Contact type 'contact' requiere parent_id | Error | | BR-005 | No eliminar contacto con transacciones | Warning | | BR-006 | credit_limit >= 0 | Error | --- ## Casos de Prueba | ID | Escenario | Resultado Esperado | |----|-----------|-------------------| | TC-001 | Crear empresa con datos completos | Contacto creado exitosamente | | TC-002 | Crear contacto tipo 'contact' sin parent | Error: parent_id requerido | | TC-003 | Crear contacto con VAT duplicado | Error: VAT ya existe | | TC-004 | Buscar por nombre parcial | Lista filtrada correctamente | | TC-005 | Agregar contacto hijo a empresa | Relacion creada | | TC-006 | Eliminar empresa con hijos | Cascada aplicada | | TC-007 | Vincular contacto con usuario | Relacion 1:1 creada | --- ## Criterios de Aceptacion - [ ] CRUD completo de contactos - [ ] Soporte para 3 tipos de contacto - [ ] Relacion padre-hijo funcional - [ ] Tags/categorias asignables - [ ] Busqueda en menos de 100ms - [ ] Validacion de VAT por pais - [ ] Exportacion a CSV --- ## Notas Tecnicas ### Indice Recomendado ```sql -- Busqueda rapida CREATE INDEX idx_contacts_search ON contacts USING gin(to_tsvector('spanish', name || ' ' || COALESCE(email, '') || ' ' || COALESCE(vat, ''))); -- Filtro por tipo y rol CREATE INDEX idx_contacts_type_roles ON contacts(contact_type, roles) WHERE deleted_at IS NULL; ``` ### Computed Fields ```sql -- display_name computed CASE WHEN parent_id IS NOT NULL THEN (SELECT name FROM contacts WHERE id = parent_id) || ', ' || name ELSE name END AS display_name ``` --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | System | Creacion inicial |