Guía de Migración - Agregar Nueva Moneda

🎯 Objetivo

Esta guía te ayudará a agregar una nueva moneda (ej: EUR, GBP, MXN) al sistema de ThreeTrackr de manera sistemática y sin romper funcionalidad existente.

📋 Checklist de Migración

Fase 1: Backend

  • [ ] Agregar moneda al enum Currency en GraphQL schema
  • [ ] Actualizar tipos generados (apollo build)
  • [ ] Verificar que las queries incluyan el campo currency
  • [ ] Probar creación de órdenes/productos en la nueva moneda

Fase 2: Frontend Core

  • [ ] Actualizar CurrencyDisplay component
  • [ ] Agregar configuración de formateo
  • [ ] Actualizar tasas de cambio
  • [ ] Agregar lógica de conversión
  • [ ] Probar conversiones bidireccionales

Fase 3: Componentes

  • [ ] Verificar que todos los componentes usen CurrencyDisplay
  • [ ] Probar en diferentes contextos (órdenes, productos, billing)
  • [ ] Verificar responsive design
  • [ ] Probar con datos reales

Fase 4: Testing

  • [ ] Tests unitarios para conversiones
  • [ ] Tests de integración
  • [ ] Testing manual en diferentes navegadores
  • [ ] Verificar accesibilidad

🚀 Proceso Paso a Paso

Paso 1: Agregar Moneda al Schema GraphQL

# En el schema de GraphQL (backend)
enum Currency {
USD
COP
EUR # ← Nueva moneda
}

Paso 2: Regenerar Tipos

# Regenerar tipos GraphQL
pnpm --filter=@packages/apollo run build

# Verificar que no hay errores
pnpm check

Paso 3: Actualizar CurrencyDisplay

// packages/ui/src/components/shared/currency.tsx

// 1. Agregar configuración de formateo
const formatConfig = useMemo(() => {
const configs = {
USD: {
locale: "en-US",
currency: "USD",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
COP: {
locale: "es-CO",
currency: "COP",
minimumFractionDigits: 0,
maximumFractionDigits: 0,
},
EUR: { // ← Nueva configuración
locale: "de-DE", // o "es-ES", "fr-FR", etc.
currency: "EUR",
minimumFractionDigits: 2,
maximumFractionDigits: 2,
},
};
return configs[targetCurrency] || configs.USD;
}, [targetCurrency]);

// 2. Actualizar tasas de cambio
const defaultExchangeRates = {
USD_TO_COP: 4200,
COP_TO_USD: 1 / 4200,
USD_TO_EUR: 0.85, // ← Nueva tasa
EUR_TO_USD: 1 / 0.85, // ← Nueva tasa
COP_TO_EUR: 4200 * 0.85, // ← Tasa derivada
EUR_TO_COP: 1 / (4200 * 0.85), // ← Tasa derivada
};

// 3. Actualizar lógica de conversión
const finalValue = useMemo(() => {
if (sourceCurrency === targetCurrency) {
return value;
}
if (exchangeRate) {
return value * exchangeRate;
}

// Conversiones existentes
if (sourceCurrency === "USD" && targetCurrency === "COP") {
return value * defaultExchangeRates.USD_TO_COP;
} else if (sourceCurrency === "COP" && targetCurrency === "USD") {
return value * defaultExchangeRates.COP_TO_USD;
}

// ← Nuevas conversiones para EUR
else if (sourceCurrency === "USD" && targetCurrency === "EUR") {
return value * defaultExchangeRates.USD_TO_EUR;
} else if (sourceCurrency === "EUR" && targetCurrency === "USD") {
return value * defaultExchangeRates.EUR_TO_USD;
} else if (sourceCurrency === "COP" && targetCurrency === "EUR") {
return value * defaultExchangeRates.COP_TO_EUR;
} else if (sourceCurrency === "EUR" && targetCurrency === "COP") {
return value * defaultExchangeRates.EUR_TO_COP;
}

return value;
}, [value, sourceCurrency, targetCurrency, exchangeRate]);

Paso 4: Actualizar Configuración de Proyecto

// En páginas donde se obtiene la moneda del proyecto
const { data: projectData } = await ApolloServerSupabase.query({
query: graphql(/* GraphQL */ `
query GetProjectCurrency {
getProject {
currency # ← Este campo ya debería soportar la nueva moneda
}
}
`),
context: {
headers: {
"x-project-slug": params.projectSlug,
},
},
});

Paso 5: Testing

Test 1: Conversión Básica

// Crear orden en EUR
const order = {
totalPrice: 25.99, // €25.99
currency: "EUR"
};

// Proyecto en USD
<CurrencyDisplay
value={25.99}
sourceCurrency={Currency.Eur}
targetCurrency={Currency.Usd}
/>
// Esperado: $30.58 USD (25.99 * 1/0.85)

Test 2: Sin Conversión

// Orden EUR en proyecto EUR
<CurrencyDisplay
value={25.99}
sourceCurrency={Currency.Eur}
targetCurrency={Currency.Eur}
/>
// Esperado: €25.99 EUR (sin conversión)

Test 3: Planes de Billing

// Plan USD en proyecto EUR
<CurrencyDisplay
value={29.99}
sourceCurrency={Currency.Usd}
targetCurrency={Currency.Eur}
showDecimals={true}
/>
// Esperado: €35.28 EUR

🧪 Script de Testing

#!/bin/bash
# test-currency.sh

echo "🧪 Testing Currency System..."

# Test 1: Build
echo "1. Building Apollo types..."
pnpm --filter=@packages/apollo run build

# Test 2: Lint
echo "2. Running linter..."
pnpm check

# Test 3: Type check
echo "3. Type checking..."
pnpm --filter=app run type-check

echo "✅ All tests passed!"

📊 Matriz de Conversiones

Desde \ Hacia USD COP EUR
USD - ×4,200 ×0.85
COP ÷4,200 - ×0.0002
EUR ÷0.85 ×5,000 -

Nota: Las tasas son ejemplos. Usar tasas reales en producción.

🚨 Problemas Comunes

Problema: "Type 'EUR' is not assignable to type 'Currency'"

Solución Regenerar tipos GraphQL
pnpm --filter=@packages/apollo run build

Problema: Conversiones incorrectas

Solución Verificar tasas de cambio y lógica de conversión
// Debug: Agregar logs temporales
console.log('Conversion:', {
from: sourceCurrency,
to: targetCurrency,
value,
rate: defaultExchangeRates[`${sourceCurrency}_TO_${targetCurrency}`],
result: finalValue
});

Problema: Formateo incorrecto

Solución Verificar configuración de locale
// Verificar que el locale existe
const configs = {
EUR: {
locale: "de-DE", // ← Asegurar que existe
currency: "EUR",
// ...
}
};

Problema: No se muestra la nueva moneda en selects

Solución Actualizar componentes de selección
// En formularios de configuración
const currencyOptions = [
{ value: "USD", label: "USD - US Dollar" },
{ value: "COP", label: "COP - Colombian Peso" },
{ value: "EUR", label: "EUR - Euro" }, // ← Agregar
];

🔄 Rollback Plan

Si algo sale mal:

  1. Revertir cambios en el enum Currency
  2. Regenerar tipos pnpm --filter=@packages/apollo run build
  3. Verificar que todo funciona como antes
  4. Investigar el problema antes de reintentar

📝 Documentación

Después de agregar la nueva moneda:

  1. Actualizar CURRENCY_SYSTEM.md
  2. Actualizar CURRENCY_EXAMPLES.md
  3. Agregar casos de prueba
  4. Actualizar esta guía si es necesario

🎉 Validación Final

  • [ ] ✅ Nueva moneda aparece en selects de configuración
  • [ ] ✅ Conversiones funcionan correctamente (todas las direcciones)
  • [ ] ✅ Formateo es correcto (locale, decimales, símbolo)
  • [ ] ✅ No hay errores de TypeScript
  • [ ] ✅ No hay errores de linting
  • [ ] ✅ Funciona en todos los componentes (órdenes, productos, billing)
  • [ ] ✅ Tests pasan
  • [ ] ✅ Documentación actualizada

Nota Esta guía es un template. Adaptar los valores específicos (tasas de cambio, locales, etc.) según la moneda que se esté agregando.

Última actualización Diciembre 2024