Modulo
$
src/utils/currencyUtils.js
Utilidades centralizadas para manejo de monedas CRC/USD en facturacion y proveedores

Funciones compartidas entre facturas de venta (Invoice) y compras (Bill) para evitar duplicacion de logica de moneda. Maneja deteccion, diferenciacion de entidades, tipo de cambio y formateo.

const CurrencyUtils = require('../utils/currencyUtils');

// Detectar moneda de una factura
const config = CurrencyUtils.determinarConfiguracionMoneda(factura);
// { moneda: 'USD', exchangeRate: 520, simbolo: '$', ... }
API Reference
determinarConfiguracionMoneda(facturaData, clienteProveedorData?)
Detecta la moneda de una factura analizando campos moneda, currency y el nombre del cliente/proveedor.
facturaData Object — Datos de la factura
clienteProveedorData Object? — Datos del cliente o proveedor (opcional)
→ { moneda, requiereConfiguracion, exchangeRate, simbolo, nombre }
buscarEntidadPorMoneda(entidades, nombre, configMoneda, normalizarFn)
Busca cliente o proveedor considerando el sufijo de moneda. Primero busca con sufijo exacto, luego variaciones.
entidades Array — Lista de clientes/proveedores QB
nombre string — Nombre a buscar
configMoneda Object — Config de determinarConfiguracionMoneda
normalizarFn Function — Funcion para normalizar nombres
→ Object | null (entidad encontrada o null)
crearNombreConMoneda(nombre, configMoneda, normalizarFn)
Crea el DisplayName con sufijo de moneda. Normaliza el nombre y agrega CRC o USD (max 41 chars).
nombre string — Nombre base
configMoneda Object — Config de moneda
→ string (ej: "EMPRESA ABC USD")
agregarConfiguracionMoneda(estructura, configMoneda)
Agrega CurrencyRef y ExchangeRate a una estructura QB (Bill o Invoice). Solo modifica si la moneda es USD.
estructura Object — Bill o Invoice data
configMoneda Object — Config de moneda
→ void (muta el objeto directamente)
formatearMonto(monto, configMoneda)
Formatea un monto con el simbolo de moneda apropiado.
monto number — Monto a formatear
configMoneda Object — Config de moneda
→ string (ej: "$1500.00" o "₡1500.00")
Logica de deteccion

Criterios para USD

CriterioCampo evaluadoEjemplo
Campo moneda explicitomoneda o currency"moneda": "USD"
Nombre de entidadnombre, cliente, proveedor"proveedor": "ATM USD"
Tipo de cambio presentetipo_cambio o exchange_rate"tipo_cambio": 520
Default CRC: Si ningun criterio USD se cumple, la moneda es CRC (colon costarricense). Es la moneda base del sistema y no requiere tipo de cambio.

Tipo de cambio

MonedaExchange RateFuente
CRC1Moneda base, siempre 1
USDtipo_cambio de facturaCampo tipo_cambio o exchange_rate
USD (fallback)500Si no se especifica en la factura
ExchangeRate siempre number: QuickBooks rechaza ExchangeRate como string. CurrencyUtils garantiza que siempre sea tipo number.
Uso en scripts

Facturas de compra (Bills)

const CurrencyUtils = require('../../src/utils/currencyUtils');

async convertirABill(facturaCompra) {
  // 1. Determinar moneda
  const configMoneda = CurrencyUtils.determinarConfiguracionMoneda(facturaCompra);

  // 2. Buscar proveedor con sufijo de moneda
  const proveedor = CurrencyUtils.buscarEntidadPorMoneda(
    proveedores, facturaCompra.nombre, configMoneda, this.normalizar
  );

  // 3. Crear estructura Bill
  const billData = {
    VendorRef: { value: proveedor.Id },
    DocNumber: facturaCompra.numero,
    TxnDate: facturaCompra.fecha,
    Line: [/* ... */]
  };

  // 4. Agregar CurrencyRef + ExchangeRate si USD
  CurrencyUtils.agregarConfiguracionMoneda(billData, configMoneda);

  return billData;
}

Facturas de venta (Invoices)

const CurrencyUtils = require('../../src/utils/currencyUtils');

async procesarFactura(factura) {
  const configMoneda = CurrencyUtils.determinarConfiguracionMoneda(factura);

  // Buscar cliente con diferenciacion por moneda
  const cliente = CurrencyUtils.buscarEntidadPorMoneda(
    clientes, factura.cliente, configMoneda, this.normalizar
  );

  // Si no existe, crear con nombre + sufijo
  if (!cliente) {
    const displayName = CurrencyUtils.crearNombreConMoneda(
      factura.cliente, configMoneda, this.normalizar
    );
    // crear cliente con displayName...
  }
}
Configuracion de monedas
MonedaSimboloNombreRequiere config
CRCCosta Rican ColonNo
USD$United States DollarSi (ExchangeRate)

Agregar nuevas monedas

// Para soportar una nueva moneda, actualizar:

// 1. getMonedasSoportadas() - Agregar moneda
{ codigo: 'EUR', simbolo: '€', nombre: 'Euro' }

// 2. determinarConfiguracionMoneda() - Logica de deteccion
if (monedaStr.includes('EUR')) return configEUR;

// 3. buscarEntidadPorMoneda() - Sufijos de busqueda
// 4. crearNombreConMoneda() - Sufijo en DisplayName
Troubleshooting
ProblemaCausaSolucion
Configuracion de moneda invalidaexchangeRate es 0, null o stringVerificar campo tipo_cambio en datos de factura
Entidades duplicadasFuncion normalizarFn inconsistenteAsegurar que la normalizacion sea igual en busqueda y creacion
Tipo de cambio incorrectoFalta campo en API externaVerificar tipo_cambio o exchange_rate en respuesta
Moneda no detectada como USDCampo no reconocidoAgregar campo a criterios de deteccion en determinarConfiguracionMoneda
DisplayName excede 41 charsNombre original muy largocrearNombreConMoneda trunca automaticamente
# Verificar monedas configuradas en QB
node scripts/utilities/check-quickbooks-currencies.js

# Debug detallado de deteccion de moneda
node scripts/utilities/debug-currency.js