# RF-CATALOG-002: Paises y Estados (Catalogo Global) ## Identificacion | Campo | Valor | |-------|-------| | **ID** | RF-CATALOG-002 | | **Modulo** | MGN-005 Catalogs | | **Titulo** | Paises y Estados (Catalogo Global) | | **Prioridad** | Alta | | **Estado** | Draft | | **Fecha** | 2025-12-05 | --- ## Descripcion El sistema debe proporcionar un catalogo global de paises y sus subdivisiones (estados, provincias, departamentos) basado en estandares ISO. Este catalogo es compartido por todos los tenants y NO tiene `tenant_id`. **Referencia Odoo:** - `res.country` (odoo/addons/base/models/res_country.py) - `res.country.state` (mismo archivo) - `res.country.group` (agrupaciones regionales) --- ## Requisitos Funcionales ### RF-CATALOG-002.1: Catalogo de Paises El sistema debe incluir todos los paises segun ISO 3166-1: | Campo | Tipo | Descripcion | Ejemplo | |-------|------|-------------|---------| | id | UUID | Identificador unico | auto | | name | string | Nombre del pais (traducible) | "Mexico" | | code | char(2) | Codigo ISO 3166-1 alpha-2 | "MX" | | code3 | char(3) | Codigo ISO 3166-1 alpha-3 | "MEX" | | numeric_code | int | Codigo ISO 3166-1 numerico | 484 | | phone_code | int | Codigo telefonico internacional | 52 | | currency_id | FK | Moneda oficial | UUID-MXN | | flag_url | string | URL a imagen de bandera | computed | | is_active | boolean | Disponible para seleccion | true | **Datos:** - 249 paises segun ISO 3166-1 - Precargados en migracion inicial ### RF-CATALOG-002.2: Formato de Direccion por Pais Cada pais define su formato de direccion: ``` address_format: "%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s" ``` | Campo | Tipo | Descripcion | |-------|------|-------------| | address_format | text | Template de direccion | | name_position | enum | before/after address | | state_required | boolean | Estado obligatorio | | zip_required | boolean | CP obligatorio | | vat_label | string | Etiqueta para VAT (RFC, NIT, RUT) | **Ejemplos de formato:** ``` Mexico: "%(street)s\n%(street2)s\n%(zip)s %(city)s, %(state_code)s\n%(country_name)s" USA: "%(street)s\n%(street2)s\n%(city)s, %(state_code)s %(zip)s\n%(country_name)s" Spain: "%(street)s\n%(street2)s\n%(zip)s %(city)s (%(state_name)s)\n%(country_name)s" ``` ### RF-CATALOG-002.3: Estados/Provincias Subdivisiones de paises segun ISO 3166-2: | Campo | Tipo | Descripcion | Ejemplo | |-------|------|-------------|---------| | id | UUID | Identificador unico | auto | | country_id | FK | Pais padre | UUID-MX | | name | string | Nombre del estado | "Jalisco" | | code | string | Codigo ISO 3166-2 | "MX-JAL" | | is_active | boolean | Disponible para seleccion | true | **Datos:** - ~4,000 subdivisiones globales - Precargados para paises principales (MX, US, ES, CO, AR, etc.) ### RF-CATALOG-002.4: Grupos de Paises Agrupaciones regionales para configuraciones: | Campo | Tipo | Descripcion | |-------|------|-------------| | id | UUID | Identificador unico | | name | string | Nombre del grupo | | country_ids | M:N | Paises incluidos | **Grupos predefinidos:** - EU (Union Europea) - LATAM (Latinoamerica) - NAFTA (Norteamerica) - MERCOSUR - CARICOM --- ## Operaciones (Solo Lectura para Tenants) ### Listar Paises ```typescript GET /api/v1/catalogs/countries?active=true&search=mex Response: { "data": [ { "id": "uuid", "name": "Mexico", "code": "MX", "phoneCode": 52, "flagUrl": "/flags/mx.png", "currencyId": "uuid-mxn" } ] } ``` ### Obtener Estados de un Pais ```typescript GET /api/v1/catalogs/countries/:code/states Response: { "data": [ { "id": "uuid", "name": "Aguascalientes", "code": "MX-AGU" }, { "id": "uuid", "name": "Jalisco", "code": "MX-JAL" }, ... ] } ``` ### Busqueda de Paises ```typescript GET /api/v1/catalogs/countries/search?q=me // Busca en: name, code, code3 Response: [ { "id": "uuid", "name": "Mexico", "code": "MX" }, { "id": "uuid", "name": "Montenegro", "code": "ME" } ] ``` --- ## Restricciones ### Catalogo Global - Solo Lectura | Operacion | Permitido | Rol Requerido | |-----------|-----------|---------------| | Leer | Si | Cualquier usuario autenticado | | Crear | No | - (Solo migracion) | | Actualizar | No | - (Solo platform_admin) | | Eliminar | No | - (Solo platform_admin) | **Justificacion:** Los datos de paises son estandares internacionales que no deben ser modificados por tenants individuales. ### Sin RLS Las tablas de paises y estados NO tienen `tenant_id` ni RLS: ```sql -- No tiene tenant_id CREATE TABLE core_catalogs.countries ( id UUID PRIMARY KEY, name VARCHAR(100) NOT NULL, code CHAR(2) NOT NULL UNIQUE, ... ); -- Sin RLS -- ALTER TABLE ... ENABLE ROW LEVEL SECURITY; (NO APLICAR) ``` --- ## Seed de Datos ### Fuentes de Datos | Datos | Fuente | Cantidad | |-------|--------|----------| | Paises | ISO 3166-1 | 249 | | Estados MX | INEGI | 32 | | Estados US | USPS | 50 + DC + territories | | Estados ES | INE | 52 provincias | | Otros | ISO 3166-2 | Variable | ### Script de Carga ```sql -- Paises principales (ejemplo) INSERT INTO core_catalogs.countries (name, code, code3, numeric_code, phone_code, vat_label) VALUES ('Mexico', 'MX', 'MEX', 484, 52, 'RFC'), ('United States', 'US', 'USA', 840, 1, 'Tax ID'), ('Spain', 'ES', 'ESP', 724, 34, 'NIF'), ('Colombia', 'CO', 'COL', 170, 57, 'NIT'), ('Argentina', 'AR', 'ARG', 32, 54, 'CUIT'); -- Estados Mexico (ejemplo) INSERT INTO core_catalogs.states (country_id, name, code) VALUES ((SELECT id FROM countries WHERE code = 'MX'), 'Aguascalientes', 'MX-AGU'), ((SELECT id FROM countries WHERE code = 'MX'), 'Baja California', 'MX-BCN'), ... ``` --- ## Casos de Prueba | ID | Escenario | Resultado Esperado | |----|-----------|-------------------| | TC-001 | Listar paises activos | 200+ paises | | TC-002 | Obtener estados de Mexico | 32 estados | | TC-003 | Buscar por codigo "MX" | Mexico encontrado | | TC-004 | Buscar por nombre parcial | Resultados filtrados | | TC-005 | Intentar crear pais (tenant) | 403 Forbidden | | TC-006 | Pais inactivo no aparece en lista | Excluido | --- ## Criterios de Aceptacion - [ ] 249 paises cargados segun ISO 3166-1 - [ ] Estados cargados para paises principales - [ ] Busqueda por nombre y codigo - [ ] Formato de direccion por pais - [ ] Solo lectura para tenants - [ ] Banderas disponibles --- ## Notas Tecnicas ### Indices ```sql -- Busqueda rapida CREATE INDEX idx_countries_code ON core_catalogs.countries(code); CREATE INDEX idx_countries_name ON core_catalogs.countries(name); CREATE INDEX idx_states_country ON core_catalogs.states(country_id); CREATE INDEX idx_states_code ON core_catalogs.states(code); ``` ### Cache Los catalogos globales deben cachearse agresivamente: - TTL: 24 horas - Invalidacion: Manual por platform_admin --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | System | Creacion inicial |