# RF-FIN-002: Monedas y Tipos de Cambio ## Identificacion | Campo | Valor | |-------|-------| | **ID** | RF-FIN-002 | | **Modulo** | MGN-010 Financial | | **Titulo** | Monedas y Tipos de Cambio | | **Prioridad** | P0 - Critica | | **Estado** | Draft | | **Fecha** | 2025-12-05 | --- ## Descripcion El sistema debe soportar operaciones multi-moneda, con gestion de tipos de cambio historicos, conversion automatica, y registro de diferencias cambiarias. --- ## Requisitos Funcionales ### RF-FIN-002.1: Estructura de Moneda ```typescript interface Currency { id: UUID; code: string; // ISO 4217: "MXN", "USD" name: string; // "Peso Mexicano" symbol: string; // "$", "€" decimalPlaces: number; // 2 decimalSeparator: string; // "." thousandSeparator: string; // "," symbolPosition: 'before' | 'after'; isActive: boolean; } // Monedas predefinidas const CURRENCIES = [ { code: 'MXN', name: 'Peso Mexicano', symbol: '$', decimalPlaces: 2 }, { code: 'USD', name: 'Dolar Estadounidense', symbol: 'US$', decimalPlaces: 2 }, { code: 'EUR', name: 'Euro', symbol: '€', decimalPlaces: 2 }, { code: 'COP', name: 'Peso Colombiano', symbol: '$', decimalPlaces: 0 }, // ... ]; ``` ### RF-FIN-002.2: Configuracion de Moneda por Tenant ```typescript interface TenantCurrencyConfig { tenantId: UUID; baseCurrencyId: UUID; // Moneda funcional activeCurrencies: UUID[]; // Monedas habilitadas exchangeRateSource: 'manual' | 'api'; exchangeRateApi?: string; // URL de API autoUpdateRates: boolean; roundingMode: RoundingMode; } enum RoundingMode { HALF_UP = 'half_up', // Redondeo normal HALF_DOWN = 'half_down', FLOOR = 'floor', // Hacia abajo CEILING = 'ceiling' // Hacia arriba } ``` ### RF-FIN-002.3: Tipos de Cambio ```typescript interface ExchangeRate { id: UUID; tenantId: UUID; fromCurrencyId: UUID; toCurrencyId: UUID; rate: Decimal; // 17.50 (1 USD = 17.50 MXN) inverseRate: Decimal; // 0.0571 (1 MXN = 0.0571 USD) effectiveDate: Date; source: string; // "manual", "banxico", "api" createdAt: TIMESTAMPTZ; } // Busqueda de tipo de cambio // Siempre busca el mas reciente <= fecha solicitada function getExchangeRate( fromCurrency: UUID, toCurrency: UUID, date: Date ): ExchangeRate; ``` ### RF-FIN-002.4: Conversion de Moneda ```typescript interface ConversionResult { originalAmount: Decimal; originalCurrency: string; convertedAmount: Decimal; targetCurrency: string; exchangeRate: Decimal; rateDate: Date; rateSource: string; } // Ejemplo POST /api/v1/financial/currencies/convert { "amount": 1000, "fromCurrency": "USD", "toCurrency": "MXN", "date": "2025-12-05" } Response: { "originalAmount": 1000, "originalCurrency": "USD", "convertedAmount": 17500, "targetCurrency": "MXN", "exchangeRate": 17.50, "rateDate": "2025-12-05", "rateSource": "manual" } ``` ### RF-FIN-002.5: Actualizacion Automatica de Tasas Integracion con APIs de tipos de cambio: | Proveedor | Region | Monedas | |-----------|--------|---------| | Banxico | Mexico | MXN | | BCE | Europa | EUR | | Open Exchange | Global | 150+ | | Fixer.io | Global | 170+ | ```typescript interface ExchangeRateJob { tenantId: UUID; schedule: string; // "0 8 * * 1-5" (dias habiles 8am) provider: string; currencies: string[]; lastRunAt?: TIMESTAMPTZ; lastStatus: 'success' | 'failed'; } ``` ### RF-FIN-002.6: Diferencias Cambiarias Al registrar movimientos en moneda extranjera: ```typescript interface ExchangeGainLoss { id: UUID; documentType: string; // "invoice", "payment" documentId: UUID; originalAmount: Decimal; originalCurrency: UUID; originalRate: Decimal; settlementAmount: Decimal; settlementRate: Decimal; gainLoss: Decimal; // Ganancia/perdida cambiaria accountId: UUID; // Cuenta de diferencia cambiaria journalEntryId: UUID; // Asiento generado createdAt: TIMESTAMPTZ; } ``` --- ## Operaciones ### Listar Monedas ```typescript GET /api/v1/financial/currencies Response: { "data": [ { "id": "uuid", "code": "MXN", "name": "Peso Mexicano", "symbol": "$", "isBase": true, "isActive": true }, { "id": "uuid2", "code": "USD", "name": "Dolar Estadounidense", "symbol": "US$", "isBase": false, "currentRate": 17.50 } ] } ``` ### Obtener Historial de Tipos de Cambio ```typescript GET /api/v1/financial/currencies/:code/rates?from=2025-11-01&to=2025-12-05 Response: { "currency": "USD", "baseCurrency": "MXN", "rates": [ { "date": "2025-12-05", "rate": 17.50, "source": "manual" }, { "date": "2025-12-04", "rate": 17.45, "source": "banxico" }, // ... ] } ``` ### Registrar Tipo de Cambio ```typescript POST /api/v1/financial/currencies/:code/rates { "rate": 17.55, "effectiveDate": "2025-12-06" } ``` ### Configurar Actualizacion Automatica ```typescript PUT /api/v1/financial/currencies/auto-update { "enabled": true, "provider": "banxico", "schedule": "0 8 * * 1-5", "currencies": ["USD", "EUR"] } ``` --- ## Reglas de Negocio | ID | Regla | Severidad | |----|-------|-----------| | BR-001 | Moneda base no puede cambiarse si hay movimientos | Error | | BR-002 | Tipo de cambio no puede ser negativo o cero | Error | | BR-003 | No pueden existir dos tasas para la misma fecha | Error | | BR-004 | Diferencias cambiarias se registran automaticamente | Info | | BR-005 | API fallida usa ultima tasa conocida | Warning | --- ## Criterios de Aceptacion - [ ] CRUD de monedas - [ ] Historial de tipos de cambio - [ ] Conversion automatica - [ ] Integracion con APIs externas - [ ] Calculo de diferencias cambiarias - [ ] Soporte para multiples decimales por moneda - [ ] Formato configurable por moneda --- ## Historial | Version | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0 | 2025-12-05 | Requirements-Analyst | Creacion inicial |