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