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)
- Obtiene la última tasa BCV publicada (API + scraping)
- Compara con la última tasa en BD
- Si hay tasa nueva no registrada, procesa desde la última en BD hasta esa fecha
- 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
- Abrir consola Felix → Bundles
- Click Install/Update Bundle
- Seleccionar
com.venezuela.bcvrate.jar - Seleccionar Start
- 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)
- Ir a Agenda (Process Scheduler)
- Crear nuevo registro
- Seleccionar proceso: BCV Exchange Rate Update
- Frecuencia: 1 dia
- Hora: 17:00-18:00 (cuando BCV publica la tasa)
- 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 | Sí | @#AD_Client_ID@ | Cliente de iDempiere |
| Tipo de Conversión | List | Sí | 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 desetMultiplyRate() - 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:
- API bcv.today: Consulta REST rápida, pero puede tener retraso de actualización
- 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@Componentannotation tampoco funcionóBundleActivatorconBundleContext.registerService()es el más confiable- Requiere
Import-Package: org.osgi.frameworken MANIFEST.MF
Por qué se usa regex en vez del JSON library
- El
json_20190722.0.0.jarbundled con iDempiere v10 tiene bugs de precisión getDouble("USD")yget("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 internamenteMConversionRate.setDivideRate()redondea a 4 decimalesset_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
MConversionRatey se usaset_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-Versionen MANIFEST.MF al actualizar
Repositorio
El código fuente está disponible en:
- Gitea: https://gitea.inforcloud.net/ezerpa/eru
- Branch principal: master
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.