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