BCV Exchange Rate Plugin for iDempiere v10

Descripción

Plugin OSGi que obtiene automáticamente la tasa de cambio oficial del BCV (Banco Central de Venezuela) USD/VES y la registra en la tabla C_Conversion_Rate de iDempiere.

Características

  • Doble fuente de datos: API bcv.today + scraping directo del sitio web del BCV
  • Fallback automático: Si la API no tiene datos recientes, scrapea el sitio del BCV
  • Reintentos automáticos: Hasta 3 intentos con espera de 5 segundos entre ellos
  • Timeout extendido: 30s conexión / 60s lectura para redes lentas
  • Busca hacia atrás cuando el BCV no publica tasa para un día hábil
  • Rellena automáticamente días sin publicación (fines de semana, feriados)
  • Ejecución manual con rango de fechas específico
  • Ejecución automática que detecta días pendientes y los rellena
  • Valida duplicados antes de insertar
  • Modo simulación para pruebas sin guardar
  • Scheduler automático diario

Fuentes de Datos

Flujo de Selección

1. Intentar API bcv.today (búsqueda hacia adelante 1-10 días)
   ↓ (si no encuentra)
2. Scraping directo del sitio web del BCV (hasta 3 reintentos)
   ↓ (si falla)
3. API bcv.today getCurrentRate() (último recurso)

Fuente Principal: API bcv.today

  • Endpoint: https://bcv.today/api/v1/rate.json
  • Endpoint por fecha: https://bcv.today/api/v1/history/YYYY-MM-DD.json
  • Ventaja: Rápida, estructurada
  • Desventaja: Puede tener retraso de actualización

Fuente de Respaldo: Scraping BCV

  • URL: https://www.bcv.org.ve/
  • Método: Extracción directa del HTML con regex
  • Ventaja: Siempre actualizada (datos oficiales)
  • Desventaja: Requiere SSL bypass y parsing de HTML
  • Reintentos: 3 máximo con espera de 5 segundos

Configuración de Red

Timeouts

Operación Valor Descripción
Conexión 30 segundos Tiempo máximo para establecer conexión
Lectura 60 segundos Tiempo máximo para recibir datos
Reintentos 3 Intentos máximos antes de fallar
Entre reintentos 5 segundos Espera entre intentos

SSL Bypass

El sitio web del BCV usa certificados SSL que pueden no estar en el cacerts de Java. El plugin implementa SSL bypass por-conexión (no global) para evitar conflictos con iDempiere.

Comportamiento del Proceso

Ejecución Manual (con parámetros de fecha)

  • Procesa cada día en el rango DateFrom → DateTo
  • Para cada día, busca la última tasa BCV hacia atrás (hasta 10 días)
  • Usa la tasa encontrada pero asigna ValidFrom = fecha solicitada

Ejecución Automática (sin parámetros de fecha)

  1. Obtiene la última tasa BCV publicada (API + scraping)
  2. Compara con la última tasa en BD
  3. Si hay tasa nueva no registrada, procesa desde la última en BD hasta esa fecha
  4. Si ya están todas → "No hay días pendientes"

Lógica de Fallback por Día

Situación Acción
BCV publica tasa para la fecha Usa esa tasa, ValidFrom = fecha solicitada
BCV no publica (feriado, fin de semana) Busca hacia atrás, usa última tasa disponible
No se encuentra tasa en 10 días Registra error

Ejemplo

Fecha solicitada BCV publica Tasa usada ValidFrom
24/06 (miércoles) No 617.6388 (del 23/06) 24/06
25/06 (jueves) Sí (621.5299) 621.5299 25/06
27/06 (sábado) No tasa del 26/06 27/06
28/06 (domingo) No tasa del 26/06 28/06

Archivos del Plugin

com.venezuela.bcvrate/
├ META-INF/
│  └ MANIFEST.MF                    # Manifest OSGi (Bundle-Activator)
├ src/com/venezuela/bcvrate/
│  ├ Activator.java                 # Registra IProcessFactory via BundleContext
│  ├ factory/
│  │  └ BCVProcessFactory.java      # Factory del proceso
│  ├ process/
│  │  └ BCVExchangeRateProcess.java # Lógica principal del proceso
│  └ service/
│     ├ BCVApiService.java          # Cliente HTTP + scraping BCV + reintentos
│     └ BCVRateResponse.java        # Modelo de respuesta
├ dist/
│  └ com.venezuela.bcvrate.jar      # JAR compilado listo para instalar
├ lib/
│  └ org.osgi.framework.jar         # Dependencia OSGi
├ migration/
│  ├ install_v10.sql                # SQL para registrar proceso
│  └ BCV_ExchangeRateProcess_2Pack.xml # 2pack para despliegue
├ .gitignore                        # Archivos ignorados por git
└ build.sh                          # Script de build para Linux

Instalación

Prerrequisitos

  • iDempiere v10 ejecutándose
  • Acceso a consola Felix (http://servidor:8080/system/console)
  • Acceso a la base de datos PostgreSQL
  • Conectividad a internet (bcv.today y bcv.org.ve)

Paso 1: Instalar JAR en Felix

  1. Abrir consola Felix → Bundles
  2. Click Install/Update Bundle
  3. Seleccionar com.venezuela.bcvrate.jar
  4. Seleccionar Start
  5. Verificar estado Active

Importante: Si actualizas el plugin, debes uninstall el bundle anterior primero, luego install el nuevo. Equinox no recarga si la versión es la misma.

Paso 2: Registrar Proceso

Opción A: Ejecutar migration/install_v10.sql en la BD Opción B: Crear manualmente via UI:

  • Proceso: BCV Exchange Rate Update
  • ClassName: com.venezuela.bcvrate.process.BCVExchangeRateProcess
  • AccessLevel: 3 (Client + Organization)
  • Parámetros: Client, Conversion Type, Date From, Date To, Simulation Mode

Opción C: Importar 2pack migration/BCV_ExchangeRateProcess_2Pack.xml

Paso 3: Agregar al Menú

Crear registro en AD_TreeBar o importar 2pack con el menú configurado.

Paso 4: Configurar Scheduler (Agenda)

  1. Ir a Agenda (Process Scheduler)
  2. Crear nuevo registro
  3. Seleccionar proceso: BCV Exchange Rate Update
  4. Frecuencia: 1 dia
  5. Hora: 17:00-18:00 (cuando BCV publica la tasa)
  6. Dejar parámetros de fecha vacíos

Recomendación: Configurar dos ejecuciones (17:00 y 21:00) por si la primera no captura la tasa.

Parámetros del Proceso

Parámetro Tipo Requerido Default Descripción
Grupo Empresarial List @#AD_Client_ID@ Cliente de iDempiere
Tipo de Conversión List BCV Tipo de conversión
Fecha desde Date No (vacío) Fecha inicio (vacío = auto)
Fecha hasta Date No (vacío) Fecha fin (vacío = auto)
Simulación Yes/No No N Ejecutar sin guardar cambios

Datos Clave

Campo Valor Descripción
C_Currency_ID 100 USD (hardcoded)
C_Currency_ID_To (dinámico) Moneda funcional del cliente
AD_Org_ID 0 Todas las organizaciones
MultiplyRate (API/scraping) Tasa USD → VES (4 decimales)
DivideRate 1/MultiplyRate Tasa VES → USD (10 decimales)
ValidFrom (fecha solicitada) Fecha que necesita la empresa
ValidTo (fecha solicitada) Misma que ValidFrom

Solución de Problemas

Error "Failed to create new process instance"

  • Verificar que el bundle está Active en Felix
  • Verificar logs: grep -i bcvrate /opt/idempiere-server/logs/idempiere.log

Error "Cross tenant PO writing"

  • Se resolvió usando set_ValueNoCheck() en vez de setMultiplyRate()
  • El proceso crea el registro con el client ID correcto del contexto

Error "No se pudo obtener la moneda funcional"

  • Verificar que el cliente tiene un esquema contable configurado
  • Verificar que la moneda funcional no sea USD

API bcv.today no responde o tiene retraso

  • Verificar conectividad: curl https://bcv.today/api/v1/rate.json
  • El plugin automáticamente intenta scraping del sitio web del BCV como respaldo

Scraping BCV falla por timeout

  • El plugin reintenta hasta 3 veces con espera de 5 segundos
  • Verificar conectividad: curl https://www.bcv.org.ve/
  • Si hay proxy, configurarlo en el servidor
  • El log muestra "Scraping BCV fallo despues de 3 intentos"

Error SSL en scraping del BCV

  • El plugin incluye SSL bypass para el sitio web del BCV
  • Si persiste, verificar que el bundle tiene la última versión

Tasa con decimales incorrectos

  • Se resolvió usando set_ValueNoCheck() en vez de setters de MConversionRate
  • MultiplyRate: 4 decimales
  • DivideRate: 10 decimales

Scraping captura tasa incorrecta (EUR en vez de USD)

  • El regex busca específicamente después de USD</span> en el HTML
  • Verificar que el HTML del BCV no ha cambiado su estructura

Compilación

En Windows (desarrollo)

# Requiere: JDK 11, JARs de iDempiere v10
$javac = "C:\Program Files\Eclipse Adoptium\jdk-11.0.31.11-hotspot\bin\javac.exe"
$v10Plugins = "path/to/idempiere-v10/plugins"

$sources = Get-ChildItem -Path src -Recurse -Filter "*.java"
$classpath = "$v10Plugins\org.adempiere.base_*.jar;$v10Plugins\json_*.jar;lib\org.osgi.framework.jar"

& $javac -cp $classpath -d dist -source 11 -target 11 @($sources)
& jar cfm dist/com.venezuela.bcvrate.jar META-INF/MANIFEST.MF -C dist .

En Linux (servidor)

chmod +x build.sh
./build.sh

Dependencias

  • org.adempiere.base >= 10.0.0 - Framework iDempiere
  • json >= 20190722.0.0 - Parsing JSON (solo para API bcv.today)
  • org.osgi.framework - Framework OSGi (sistema)

Notas Técnicas

Dual Source: API + Scraping

El plugin implementa dos fuentes de datos para máxima confiabilidad:

  1. API bcv.today: Consulta REST rápida, pero puede tener retraso de actualización
  2. Scraping BCV: Extracción directa del HTML del sitio web oficial

El flujo automático intenta la API primero y fallback al scraping si no hay datos recientes.

Lógica de Reintentos

Cuando el scraping falla (timeout, error de conexión), el plugin reintenta automáticamente:

int maxRetries = 3;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
    // Intentar scraping
    // Si falla, esperar 5 segundos y reintentar
    // Si falla 3 veces, registrar error
}

SSL Bypass para Scraping

El sitio web del BCV usa certificados SSL que pueden no estar en el cacerts de Java. El plugin implementa SSL bypass por-conexión (no global) para evitar conflictos con iDempiere:

TrustManager[] trustAllCerts = new TrustManager[]{...};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier((hostname, session) -> true);

Extracción de Tasa USD del HTML

El regex busca específicamente la tasa del dólar después del elemento USD</span>:

USD</span>.*?strong-tb">\s*([\d.,]+)\s*</strong>

Esto evita capturar otras tasas (EUR, CNY, etc.) que aparecen en la misma página.

Por qué se usa BundleActivator en vez de DS

  • component.xml (Declarative Services) no funcionó en iDempiere v10
  • @Component annotation tampoco funcionó
  • BundleActivator con BundleContext.registerService() es el más confiable
  • Requiere Import-Package: org.osgi.framework en MANIFEST.MF

Por qué se usa regex en vez del JSON library

  • El json_20190722.0.0.jar bundled con iDempiere v10 tiene bugs de precisión
  • getDouble("USD") y get("USD").toString() corrompen decimales
  • Se extrae el valor directamente del string raw con regex: "USD"\s*:\s*([0-9.]+)

Por qué se usa set_ValueNoCheck en vez de setters

  • MConversionRate.setMultiplyRate() modifica el valor internamente
  • MConversionRate.setDivideRate() redondea a 4 decimales
  • set_ValueNoCheck() bypassa la lógica interna y almacena el valor exacto

Cross Tenant

  • MConversionRate.setRate() intenta guardar con AD_Client_ID=0
  • Se crea el registro directamente con MConversionRate y se usa set_ValueNoCheck("AD_Client_ID", ...)

Por qué el JAR debe cambiar de versión

  • Equinox (runtime OSGi) cachea bundles por versión
  • Si la versión no cambia, el bundle anterior permanece activo
  • Siempre incrementar Bundle-Version en MANIFEST.MF al actualizar

Repositorio

El código fuente está disponible en:

Clonar repositorio

git clone https://gitea.inforcloud.net/ezerpa/eru.git

Actualizar código

git pull

Historial de Cambios

v1.0.13 (2026-07-03)

  • Lógica de reintentos: 3 intentos máximo con espera de 5 segundos
  • Timeout incrementado: 30s conexión / 60s lectura
  • Logging detallado de reintentos en servidor

v1.0.12 (2026-07-03)

  • Incremento de timeout HTTP a 30s/60s

v1.0.11 (2026-07-03)

  • Fix regex scraping: captura tasa USD específicamente (no EUR)
  • Regex busca después de USD</span> en el HTML

v1.0.10 (2026-07-03)

  • Logging mejorado en proceso para ver fuente de datos
  • Scraping status visible en output del proceso

v1.0.9 (2026-07-03)

  • SSL bypass por-conexión (no global) para scraping BCV
  • Logging detallado en getLatestRate()

v1.0.8 (2026-07-03)

  • Scraping directo del sitio web del BCV como fuente de respaldo
  • Dual source: API bcv.today + scraping bcv.org.ve
  • Método getRateFromBCVWebsite() con extracción regex del HTML

v1.0.7 (2026-06-23)

  • Lógica automática: detecta días pendientes entre BD y última tasa BCV
  • Ejecución sin parámetros: busca última tasa BCV y rellena huecos

v1.0.6 (2026-06-23)

  • Fix: ejecución automática ahora detecta si hay tasa para hoy
  • Evita procesar si ya existen todas las tasas

v1.0.5 (2026-06-23)

  • Lógica de fallback: busca hacia atrás cuando BCV no publica tasa
  • Rellena días sin publicación con última tasa disponible

v1.0.4 (2026-06-23)

  • getRateForDateWithFallback(): busca hacia atrás hasta 10 días
  • BCVRateResponse: campo requestedDate vs effectiveDate

v1.0.3 (2026-06-23)

  • DivideRate: 10 decimales en vez de 4

v1.0.2 (2026-06-23)

  • Todos los setters usan set_ValueNoCheck() para bypass MConversionRate
  • Log de verificación post-save

v1.0.1 (2026-06-23)

  • Regex para extraer USD directo del string raw (bypass JSON library)

v1.0.0 (2026-06-22)

  • Versión inicial
  • API: bcv.today
  • BundleActivator para registro de IProcessFactory

Licencia

Plugin personalizado para uso interno de Ezerpa.

S
Description
Plugin BCV Exchange Rate para iDempiere v10
Readme 60 KiB
Languages
Java 90.9%
Shell 9.1%