diff --git a/currency_rate_update/services/__init__.py b/currency_rate_update/services/__init__.py
new file mode 100644
index 000000000..5c70dd472
--- /dev/null
+++ b/currency_rate_update/services/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
diff --git a/currency_rate_update/services/currency_getter.py b/currency_rate_update/services/currency_getter.py
new file mode 100644
index 000000000..bc5cf5a51
--- /dev/null
+++ b/currency_rate_update/services/currency_getter.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from update_service_ECB import ECB_getter
+from update_service_YAHOO import YAHOO_getter
+
+from update_service_CA_BOC import CA_BOC_getter
+from update_service_CH_ADMIN import CH_ADMIN_getter
+from update_service_MX_BdM import MX_BdM_getter
+from update_service_PL_NBP import PL_NBP_getter
+from update_service_RO_BNR import RO_BNR_getter
+
+class AbstractClassError(Exception):
+ def __str__(self):
+ return 'Abstract Class'
+
+ def __repr__(self):
+ return 'Abstract Class'
+
+
+class AbstractMethodError(Exception):
+ def __str__(self):
+ return 'Abstract Method'
+
+ def __repr__(self):
+ return 'Abstract Method'
+
+
+class UnknowClassError(Exception):
+ def __str__(self):
+ return 'Unknown Class'
+
+ def __repr__(self):
+ return 'Unknown Class'
+
+
+class UnsuportedCurrencyError(Exception):
+ def __init__(self, value):
+ self.curr = value
+
+ def __str__(self):
+ return 'Unsupported currency %s' % self.curr
+
+ def __repr__(self):
+ return 'Unsupported currency %s' % self.curr
+
+
+class Currency_getter_factory():
+ """Factory pattern class that will return
+ a currency getter class base on the name passed
+ to the register method
+
+ """
+ def register(self, class_name):
+ allowed = [
+ 'CH_ADMIN_getter',
+ 'PL_NBP_getter',
+ 'ECB_getter',
+ 'GOOGLE_getter',
+ 'YAHOO_getter',
+ 'MX_BdM_getter',
+ 'CA_BOC_getter',
+ 'RO_BNR_getter',
+ ]
+ if class_name in allowed:
+ class_def = eval(class_name)
+ return class_def()
+ else:
+ raise UnknowClassError
diff --git a/currency_rate_update/services/currency_getter_interface.py b/currency_rate_update/services/currency_getter_interface.py
new file mode 100644
index 000000000..712507d09
--- /dev/null
+++ b/currency_rate_update/services/currency_getter_interface.py
@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+import logging
+
+from datetime import datetime
+from openerp import fields
+from openerp.exceptions import except_orm
+
+_logger = logging.getLogger(__name__)
+
+class AbstractClassError(Exception):
+ def __str__(self):
+ return 'Abstract Class'
+
+ def __repr__(self):
+ return 'Abstract Class'
+
+
+class AbstractMethodError(Exception):
+ def __str__(self):
+ return 'Abstract Method'
+
+ def __repr__(self):
+ return 'Abstract Method'
+
+
+class UnknowClassError(Exception):
+ def __str__(self):
+ return 'Unknown Class'
+
+ def __repr__(self):
+ return 'Unknown Class'
+
+
+class UnsuportedCurrencyError(Exception):
+ def __init__(self, value):
+ self.curr = value
+
+ def __str__(self):
+ return 'Unsupported currency %s' % self.curr
+
+ def __repr__(self):
+ return 'Unsupported currency %s' % self.curr
+
+class Currency_getter_interface(object):
+ "Abstract class of currency getter"
+
+ log_info = " "
+
+ supported_currency_array = [
+ 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
+ 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL',
+ 'BSD', 'BTN', 'BWP', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY',
+ 'COP', 'CRC', 'CUP', 'CVE', 'CYP', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD',
+ 'EEK', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP',
+ 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG',
+ 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD',
+ 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD',
+ 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'LYD', 'MAD',
+ 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MTL', 'MUR', 'MVR',
+ 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD',
+ 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON',
+ 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP',
+ 'SLL', 'SOS', 'SPL', 'SRD', 'STD', 'SVC', 'SYP', 'SZL', 'THB', 'TJS',
+ 'TMM', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX',
+ 'USD', 'UYU', 'UZS', 'VEB', 'VEF', 'VND', 'VUV', 'WST', 'XAF', 'XAG',
+ 'XAU', 'XCD', 'XDR', 'XOF', 'XPD', 'XPF', 'XPT', 'YER', 'ZAR', 'ZMK',
+ 'ZWD'
+ ]
+
+ # Updated currency this arry will contain the final result
+ updated_currency = {}
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """Interface method that will retrieve the currency
+ This function has to be reinplemented in child
+ """
+ raise AbstractMethodError
+
+ def validate_cur(self, currency):
+ """Validate if the currency to update is supported"""
+ if currency not in self.supported_currency_array:
+ raise UnsuportedCurrencyError(currency)
+
+ def get_url(self, url):
+ """Return a string of a get url query"""
+ try:
+ import urllib
+ objfile = urllib.urlopen(url)
+ rawfile = objfile.read()
+ objfile.close()
+ return rawfile
+ except ImportError:
+ raise except_orm(
+ 'Error !',
+ self.MOD_NAME + 'Unable to import urllib !'
+ )
+ except IOError:
+ raise except_orm(
+ 'Error !',
+ self.MOD_NAME + 'Web Service does not exist !'
+ )
+
+ def check_rate_date(self, rate_date, max_delta_days):
+ """Check date constrains. rate_date must be of datetime type"""
+ days_delta = (datetime.today() - rate_date).days
+ if days_delta > max_delta_days:
+ raise Exception(
+ 'The rate timestamp %s is %d days away from today, '
+ 'which is over the limit (%d days). '
+ 'Rate not updated in OpenERP.' % (rate_date,
+ days_delta,
+ max_delta_days)
+ )
+
+ # We always have a warning when rate_date != today
+ if rate_date.date() != datetime.today().date():
+ rate_date_str = fields.Date.to_string(rate_date)
+ msg = "The rate timestamp %s is not today's date %s" % (
+ rate_date_str, fields.Date.today())
+ self.log_info = ("\n WARNING : %s") % msg
+ _logger.warning(msg)
diff --git a/currency_rate_update/services/currency_rate_update.py b/currency_rate_update/services/currency_rate_update.py
deleted file mode 100644
index 91419dfdc..000000000
--- a/currency_rate_update/services/currency_rate_update.py
+++ /dev/null
@@ -1,799 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright (c) 2009 Camptocamp SA
-# @source JBA and AWST inpiration
-# @contributor Grzegorz Grzelak (grzegorz.grzelak@birdglobe.com),
-# Joel Grand-Guillaume
-# Copyright (c) 2010 Alexis de Lattre (alexis@via.ecp.fr)
-# - ported XML-based webservices (Admin.ch, ECB, PL NBP) to new XML lib
-# - rates given by ECB webservice is now correct even when main_cur <> EUR
-# - rates given by PL_NBP webs. is now correct even when main_cur <> PLN
-# - if company_currency <> CHF, you can now update CHF via Admin.ch
-# (same for EUR with ECB webservice and PLN with NBP webservice)
-# For more details, see Launchpad bug #645263
-# - mecanism to check if rates given by the webservice are "fresh"
-# enough to be written in OpenERP
-# ('max_delta_days' parameter for each currency update service)
-# Ported to OpenERP 7.0 by Lorenzo Battistini
-#
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-# TODO "nice to have" : restrain the list of currencies that can be added for
-# a webservice to the list of currencies supported by the Webservice
-# TODO : implement max_delta_days for Yahoo webservice
-
-import logging
-import time
-from datetime import datetime, timedelta
-from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
-from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
-from openerp.osv import fields, osv, orm
-from openerp.tools.translate import _
-
-_logger = logging.getLogger(__name__)
-
-
-class Currency_rate_update_service(osv.Model):
- """Class that tells for wich services wich currencies have to be updated
-
- """
- _name = "currency.rate.update.service"
- _description = "Currency Rate Update"
- _columns = {
- # List of webservicies the value sould be a class name
- 'service': fields.selection(
- [
- ('Admin_ch_getter', 'Admin.ch'),
- ('ECB_getter', 'European Central Bank'),
- ('Yahoo_getter', 'Yahoo Finance '),
- # Added for polish rates
- ('PL_NBP_getter', 'Narodowy Bank Polski'),
- # Added for mexican rates
- ('Banxico_getter', 'Banco de México'),
- # Bank of Canada is using RSS-CB
- # http://www.cbwiki.net/wiki/index.php/Specification_1.1
- # This RSS format is used by other national banks
- # (Thailand, Malaysia, Mexico...)
- ('CA_BOC_getter', 'Bank of Canada - noon rates'),
- ],
- "Webservice to use",
- required=True
- ),
- # List of currency to update
- 'currency_to_update': fields.many2many(
- 'res.currency',
- 'res_curreny_auto_udate_rel',
- 'service_id',
- 'currency_id',
- 'currency to update with this service',
- ),
- # Back ref
- 'company_id': fields.many2one(
- 'res.company',
- 'linked company',
- ),
- # Note fileds that will be used as a logger
- 'note': fields.text('update notice'),
- 'max_delta_days': fields.integer(
- 'Max delta days',
- required=True,
- help="If the time delta between the "
- "rate date given by the webservice and "
- "the current date exeeds this value, "
- "then the currency rate is not updated in OpenERP."
- ),
- }
- _defaults = {'max_delta_days': lambda *a: 4}
- _sql_constraints = [
- (
- 'curr_service_unique',
- 'unique (service, company_id)',
- _('You can use a service one time per company !')
- )
- ]
-
- def _check_max_delta_days(self, cr, uid, ids):
- for company in self.read(cr, uid, ids, ['max_delta_days']):
- if company['max_delta_days'] >= 0:
- continue
- else:
- return False
- return True
-
- _constraints = [
- (_check_max_delta_days,
- "'Max delta days' must be >= 0",
- ['max_delta_days']),
- ]
-
-
-class Currency_rate_update(osv.Model):
- """Class that handle an ir cron call who will
- update currencies based on a web url"""
- _name = "currency.rate.update"
- _description = "Currency Rate Update"
- # Dict that represent a cron object
- nextcall_time = datetime.today() + timedelta(days=1)
- nextcall = nextcall_time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
- cron = {
- 'active': False,
- 'priority': 1,
- 'interval_number': 1,
- 'interval_type': 'weeks',
- 'nextcall': nextcall,
- 'numbercall': -1,
- 'doall': True,
- 'model': 'currency.rate.update',
- 'function': 'run_currency_update',
- 'args': '()',
- }
-
- LOG_NAME = 'cron-rates'
- MOD_NAME = 'currency_rate_update: '
-
- def get_cron_id(self, cr, uid, context):
- """Returns the updater cron's id.
- Create one if the cron does not exists
- """
-
- cron_id = 0
- cron_obj = self.pool.get('ir.cron')
- try:
- # Finds the cron that send messages
- cron_id = cron_obj.search(
- cr,
- uid,
- [
- ('function', 'ilike', self.cron['function']),
- ('model', 'ilike', self.cron['model'])
- ],
- context={
- 'active_test': False
- }
- )
- cron_id = int(cron_id[0])
- except Exception:
- _logger.info('warning cron not found one will be created')
- # Ignore if the cron is missing cause we are
- # going to create it in db
- pass
- if not cron_id:
- self.cron['name'] = _('Currency Rate Update')
- cron_id = cron_obj.create(cr, uid, self.cron, context)
- return cron_id
-
- def save_cron(self, cr, uid, datas, context=None):
- """save the cron config data should be a dict"""
- cron_id = self.get_cron_id(cr, uid, context)
- return self.pool.get('ir.cron').write(cr, uid, [cron_id], datas)
-
- def run_currency_update(self, cr, uid):
- "update currency at the given frequence"
- factory = Currency_getter_factory()
- curr_obj = self.pool.get('res.currency')
- rate_obj = self.pool.get('res.currency.rate')
- companies = self.pool.get('res.company').search(cr, uid, [])
- for comp in self.pool.get('res.company').browse(cr, uid, companies):
- # The multi company currency can beset or no so we handle
- # The two case
- if not comp.auto_currency_up:
- continue
- # We fetch the main currency looking for currency with base = true.
- # The main rate should be set at 1.00
- main_curr_ids = curr_obj.search(
- cr, uid,
- [('base', '=', True), ('company_id', '=', comp.id)]
- )
- if not main_curr_ids:
- # If we can not find a base currency for this company
- # we look for one with no company set
- main_curr_ids = curr_obj.search(
- cr, uid,
- [('base', '=', True), ('company_id', '=', False)]
- )
- if main_curr_ids:
- main_curr_rec = curr_obj.browse(cr, uid, main_curr_ids[0])
- else:
- raise orm.except_orm(
- _('Error!'),
- ('There is no base currency set!')
- )
- if main_curr_rec.rate != 1:
- raise orm.except_orm(
- _('Error!'),
- ('Base currency rate should be 1.00!')
- )
- main_curr = main_curr_rec.name
- for service in comp.services_to_use:
- note = service.note or ''
- try:
- # We initalize the class that will handle the request
- # and return a dict of rate
- getter = factory.register(service.service)
- curr_to_fetch = map(lambda x: x.name,
- service.currency_to_update)
- res, log_info = getter.get_updated_currency(
- curr_to_fetch,
- main_curr,
- service.max_delta_days
- )
- rate_name = time.strftime(DEFAULT_SERVER_DATE_FORMAT)
- for curr in service.currency_to_update:
- if curr.name == main_curr:
- continue
- do_create = True
- for rate in curr.rate_ids:
- if rate.name == rate_name:
- rate.write({'rate': res[curr.name]})
- do_create = False
- break
- if do_create:
- vals = {
- 'currency_id': curr.id,
- 'rate': res[curr.name],
- 'name': rate_name
- }
- rate_obj.create(
- cr,
- uid,
- vals,
- )
-
- # Show the most recent note at the top
- msg = "%s \n%s currency updated. %s" % (
- log_info or '',
- datetime.today().strftime(
- DEFAULT_SERVER_DATETIME_FORMAT
- ),
- note
- )
- service.write({'note': msg})
- except Exception as exc:
- error_msg = "\n%s ERROR : %s %s" % (
- datetime.today().strftime(
- DEFAULT_SERVER_DATETIME_FORMAT
- ),
- repr(exc),
- note
- )
- _logger.info(repr(exc))
- service.write({'note': error_msg})
-
-
-class AbstractClassError(Exception):
- def __str__(self):
- return 'Abstract Class'
-
- def __repr__(self):
- return 'Abstract Class'
-
-
-class AbstractMethodError(Exception):
- def __str__(self):
- return 'Abstract Method'
-
- def __repr__(self):
- return 'Abstract Method'
-
-
-class UnknowClassError(Exception):
- def __str__(self):
- return 'Unknown Class'
-
- def __repr__(self):
- return 'Unknown Class'
-
-
-class UnsuportedCurrencyError(Exception):
- def __init__(self, value):
- self.curr = value
-
- def __str__(self):
- return 'Unsupported currency %s' % self.curr
-
- def __repr__(self):
- return 'Unsupported currency %s' % self.curr
-
-
-class Currency_getter_factory():
- """Factory pattern class that will return
- a currency getter class base on the name passed
- to the register method
-
- """
- def register(self, class_name):
- allowed = [
- 'Admin_ch_getter',
- 'PL_NBP_getter',
- 'ECB_getter',
- 'NYFB_getter',
- 'Google_getter',
- 'Yahoo_getter',
- 'Banxico_getter',
- 'CA_BOC_getter',
- ]
- if class_name in allowed:
- class_def = eval(class_name)
- return class_def()
- else:
- raise UnknowClassError
-
-
-class Curreny_getter_interface(object):
- "Abstract class of currency getter"
-
- log_info = " "
-
- supported_currency_array = [
- 'AED', 'AFN', 'ALL', 'AMD', 'ANG', 'AOA', 'ARS', 'AUD', 'AWG', 'AZN',
- 'BAM', 'BBD', 'BDT', 'BGN', 'BHD', 'BIF', 'BMD', 'BND', 'BOB', 'BRL',
- 'BSD', 'BTN', 'BWP', 'BYR', 'BZD', 'CAD', 'CDF', 'CHF', 'CLP', 'CNY',
- 'COP', 'CRC', 'CUP', 'CVE', 'CYP', 'CZK', 'DJF', 'DKK', 'DOP', 'DZD',
- 'EEK', 'EGP', 'ERN', 'ETB', 'EUR', 'FJD', 'FKP', 'GBP', 'GEL', 'GGP',
- 'GHS', 'GIP', 'GMD', 'GNF', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG',
- 'HUF', 'IDR', 'ILS', 'IMP', 'INR', 'IQD', 'IRR', 'ISK', 'JEP', 'JMD',
- 'JOD', 'JPY', 'KES', 'KGS', 'KHR', 'KMF', 'KPW', 'KRW', 'KWD', 'KYD',
- 'KZT', 'LAK', 'LBP', 'LKR', 'LRD', 'LSL', 'LTL', 'LVL', 'LYD', 'MAD',
- 'MDL', 'MGA', 'MKD', 'MMK', 'MNT', 'MOP', 'MRO', 'MTL', 'MUR', 'MVR',
- 'MWK', 'MXN', 'MYR', 'MZN', 'NAD', 'NGN', 'NIO', 'NOK', 'NPR', 'NZD',
- 'OMR', 'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG', 'QAR', 'RON',
- 'RSD', 'RUB', 'RWF', 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP',
- 'SLL', 'SOS', 'SPL', 'SRD', 'STD', 'SVC', 'SYP', 'SZL', 'THB', 'TJS',
- 'TMM', 'TND', 'TOP', 'TRY', 'TTD', 'TVD', 'TWD', 'TZS', 'UAH', 'UGX',
- 'USD', 'UYU', 'UZS', 'VEB', 'VEF', 'VND', 'VUV', 'WST', 'XAF', 'XAG',
- 'XAU', 'XCD', 'XDR', 'XOF', 'XPD', 'XPF', 'XPT', 'YER', 'ZAR', 'ZMK',
- 'ZWD'
- ]
-
- # Updated currency this arry will contain the final result
- updated_currency = {}
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """Interface method that will retrieve the currency
- This function has to be reinplemented in child
- """
- raise AbstractMethodError
-
- def validate_cur(self, currency):
- """Validate if the currency to update is supported"""
- if currency not in self.supported_currency_array:
- raise UnsuportedCurrencyError(currency)
-
- def get_url(self, url):
- """Return a string of a get url query"""
- try:
- import urllib
- objfile = urllib.urlopen(url)
- rawfile = objfile.read()
- objfile.close()
- return rawfile
- except ImportError:
- raise osv.except_osv(
- 'Error !',
- self.MOD_NAME + 'Unable to import urllib !'
- )
- except IOError:
- raise osv.except_osv(
- 'Error !',
- self.MOD_NAME + 'Web Service does not exist !'
- )
-
- def check_rate_date(self, rate_date, max_delta_days):
- """Check date constrains. rate_date must be of datetime type"""
- days_delta = (datetime.today() - rate_date).days
- if days_delta > max_delta_days:
- raise Exception(
- 'The rate timestamp (%s) is %d days away from today, '
- 'which is over the limit (%d days). '
- 'Rate not updated in OpenERP.' % (rate_date,
- days_delta,
- max_delta_days)
- )
-
- # We always have a warning when rate_date != today
- rate_date_str = datetime.strftime(rate_date,
- DEFAULT_SERVER_DATE_FORMAT)
- if rate_date.date() != datetime.today().date():
- msg = "The rate timestamp (%s) is not today's date"
- self.log_info = ("WARNING : %s %s") % (msg, rate_date_str)
- _logger.warning(msg, rate_date_str)
-
-
-# Yahoo #######################################################################
-class Yahoo_getter(Curreny_getter_interface):
- """Implementation of Currency_getter_factory interface
- for Yahoo finance service
- """
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """implementation of abstract method of curreny_getter_interface"""
- self.validate_cur(main_currency)
- url = ('http://download.finance.yahoo.com/d/'
- 'quotes.txt?s="%s"=X&f=sl1c1abg')
- if main_currency in currency_array:
- currency_array.remove(main_currency)
- for curr in currency_array:
- self.validate_cur(curr)
- res = self.get_url(url % (main_currency + curr))
- val = res.split(',')[1]
- if val:
- self.updated_currency[curr] = val
- else:
- raise Exception('Could not update the %s' % (curr))
-
- return self.updated_currency, self.log_info
-
-
-# Admin CH ####################################################################
-class Admin_ch_getter(Curreny_getter_interface):
- """Implementation of Currency_getter_factory interface
- for Admin.ch service
-
- """
-
- def rate_retrieve(self, dom, ns, curr):
- """Parse a dom node to retrieve currencies data"""
- res = {}
- xpath_rate_currency = ("/def:wechselkurse/def:devise[@code='%s']/"
- "def:kurs/text()") % (curr.lower())
- xpath_rate_ref = ("/def:wechselkurse/def:devise[@code='%s']/"
- "def:waehrung/text()") % (curr.lower())
- res['rate_currency'] = float(
- dom.xpath(xpath_rate_currency, namespaces=ns)[0]
- )
- res['rate_ref'] = float(
- (dom.xpath(xpath_rate_ref, namespaces=ns)[0]).split(' ')[0]
- )
- return res
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """Implementation of abstract method of Curreny_getter_interface"""
- url = ('http://www.afd.admin.ch/publicdb/newdb/'
- 'mwst_kurse/wechselkurse.php')
- # We do not want to update the main currency
- if main_currency in currency_array:
- currency_array.remove(main_currency)
- # Move to new XML lib cf Launchpad bug #645263
- from lxml import etree
- _logger.debug("Admin.ch currency rate service : connecting...")
- rawfile = self.get_url(url)
- dom = etree.fromstring(rawfile)
- _logger.debug("Admin.ch sent a valid XML file")
- adminch_ns = {
- 'def': 'http://www.afd.admin.ch/publicdb/newdb/mwst_kurse'
- }
- rate_date = dom.xpath(
- '/def:wechselkurse/def:datum/text()',
- namespaces=adminch_ns
- )
- rate_date = rate_date[0]
- rate_date_datetime = datetime.strptime(rate_date,
- DEFAULT_SERVER_DATE_FORMAT)
- self.check_rate_date(rate_date_datetime, max_delta_days)
- # we dynamically update supported currencies
- self.supported_currency_array = dom.xpath(
- "/def:wechselkurse/def:devise/@code",
- namespaces=adminch_ns
- )
- self.supported_currency_array = [x.upper() for x
- in self.supported_currency_array]
- self.supported_currency_array.append('CHF')
-
- _logger.debug(
- "Supported currencies = " + str(self.supported_currency_array)
- )
- self.validate_cur(main_currency)
- if main_currency != 'CHF':
- main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency)
- # 1 MAIN_CURRENCY = main_rate CHF
- rate_curr = main_curr_data['rate_currency']
- rate_ref = main_curr_data['rate_ref']
- main_rate = rate_curr / rate_ref
- for curr in currency_array:
- self.validate_cur(curr)
- if curr == 'CHF':
- rate = main_rate
- else:
- curr_data = self.rate_retrieve(dom, adminch_ns, curr)
- # 1 MAIN_CURRENCY = rate CURR
- if main_currency == 'CHF':
- rate = curr_data['rate_ref'] / curr_data['rate_currency']
- else:
- rate = (main_rate * curr_data['rate_ref'] /
- curr_data['rate_currency'])
- self.updated_currency[curr] = rate
- _logger.debug(
- "Rate retrieved : 1 %s = %s %s" % (main_currency, rate, curr)
- )
- return self.updated_currency, self.log_info
-
-
-# ECB getter #################################################################
-class ECB_getter(Curreny_getter_interface):
- """Implementation of Currency_getter_factory interface
- for ECB service
- """
-
- def rate_retrieve(self, dom, ns, curr):
- """Parse a dom node to retrieve-
- currencies data
-
- """
- res = {}
- xpath_curr_rate = ("/gesmes:Envelope/def:Cube/def:Cube/"
- "def:Cube[@currency='%s']/@rate") % (curr.upper())
- res['rate_currency'] = float(
- dom.xpath(xpath_curr_rate, namespaces=ns)[0]
- )
- return res
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """implementation of abstract method of Curreny_getter_interface"""
- url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'
- # Important : as explained on the ECB web site, the currencies are
- # at the beginning of the afternoon ; so, until 3 p.m. Paris time
- # the currency rates are the ones of trading day N-1
- # http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html
-
- # We do not want to update the main currency
- if main_currency in currency_array:
- currency_array.remove(main_currency)
- # Move to new XML lib cf Launchpad bug #645263
- from lxml import etree
- _logger.debug("ECB currency rate service : connecting...")
- rawfile = self.get_url(url)
- dom = etree.fromstring(rawfile)
- _logger.debug("ECB sent a valid XML file")
- ecb_ns = {
- 'gesmes': 'http://www.gesmes.org/xml/2002-08-01',
- 'def': 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref'
- }
- rate_date = dom.xpath('/gesmes:Envelope/def:Cube/def:Cube/@time',
- namespaces=ecb_ns)[0]
- rate_date_datetime = datetime.strptime(rate_date,
- DEFAULT_SERVER_DATE_FORMAT)
- self.check_rate_date(rate_date_datetime, max_delta_days)
- # We dynamically update supported currencies
- self.supported_currency_array = dom.xpath(
- "/gesmes:Envelope/def:Cube/def:Cube/def:Cube/@currency",
- namespaces=ecb_ns
- )
- self.supported_currency_array.append('EUR')
- _logger.debug("Supported currencies = %s " %
- self.supported_currency_array)
- self.validate_cur(main_currency)
- if main_currency != 'EUR':
- main_curr_data = self.rate_retrieve(dom, ecb_ns, main_currency)
- for curr in currency_array:
- self.validate_cur(curr)
- if curr == 'EUR':
- rate = 1 / main_curr_data['rate_currency']
- else:
- curr_data = self.rate_retrieve(dom, ecb_ns, curr)
- if main_currency == 'EUR':
- rate = curr_data['rate_currency']
- else:
- rate = (curr_data['rate_currency'] /
- main_curr_data['rate_currency'])
- self.updated_currency[curr] = rate
- _logger.debug(
- "Rate retrieved : 1 %s = %s %s" % (main_currency, rate, curr)
- )
- return self.updated_currency, self.log_info
-
-
-# PL NBP ######################################################################
-class PL_NBP_getter(Curreny_getter_interface):
- """Implementation of Currency_getter_factory interface
- for PL NBP service
-
- """
-
- def rate_retrieve(self, dom, ns, curr):
- """ Parse a dom node to retrieve
- currencies data"""
- res = {}
- xpath_rate_currency = ("/tabela_kursow/pozycja[kod_waluty='%s']/"
- "kurs_sredni/text()") % (curr.upper())
- xpath_rate_ref = ("/tabela_kursow/pozycja[kod_waluty='%s']/"
- "przelicznik/text()") % (curr.upper())
- res['rate_currency'] = float(
- dom.xpath(xpath_rate_currency, namespaces=ns)[0].replace(',', '.')
- )
- res['rate_ref'] = float(dom.xpath(xpath_rate_ref, namespaces=ns)[0])
- return res
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """implementation of abstract method of Curreny_getter_interface"""
- # LastA.xml is always the most recent one
- url = 'http://www.nbp.pl/kursy/xml/LastA.xml'
- # We do not want to update the main currency
- if main_currency in currency_array:
- currency_array.remove(main_currency)
- # Move to new XML lib cf Launchpad bug #645263
- from lxml import etree
- _logger.debug("NBP.pl currency rate service : connecting...")
- rawfile = self.get_url(url)
- dom = etree.fromstring(rawfile)
- ns = {} # Cool, there are no namespaces !
- _logger.debug("NBP.pl sent a valid XML file")
- rate_date = dom.xpath('/tabela_kursow/data_publikacji/text()',
- namespaces=ns)[0]
- rate_date_datetime = datetime.strptime(rate_date,
- DEFAULT_SERVER_DATE_FORMAT)
- self.check_rate_date(rate_date_datetime, max_delta_days)
- # We dynamically update supported currencies
- self.supported_currency_array = dom.xpath(
- '/tabela_kursow/pozycja/kod_waluty/text()',
- namespaces=ns
- )
- self.supported_currency_array.append('PLN')
- _logger.debug("Supported currencies = %s" %
- self.supported_currency_array)
- self.validate_cur(main_currency)
- if main_currency != 'PLN':
- main_curr_data = self.rate_retrieve(dom, ns, main_currency)
- # 1 MAIN_CURRENCY = main_rate PLN
- main_rate = (main_curr_data['rate_currency'] /
- main_curr_data['rate_ref'])
- for curr in currency_array:
- self.validate_cur(curr)
- if curr == 'PLN':
- rate = main_rate
- else:
- curr_data = self.rate_retrieve(dom, ns, curr)
- # 1 MAIN_CURRENCY = rate CURR
- if main_currency == 'PLN':
- rate = curr_data['rate_ref'] / curr_data['rate_currency']
- else:
- rate = (main_rate * curr_data['rate_ref'] /
- curr_data['rate_currency'])
- self.updated_currency[curr] = rate
- _logger.debug("Rate retrieved : %s = %s %s" %
- (main_currency, rate, curr))
- return self.updated_currency, self.log_info
-
-
-# Banco de México #############################################################
-class Banxico_getter(Curreny_getter_interface):
- """Implementation of Currency_getter_factory interface
- for Banco de México service
-
- """
-
- def rate_retrieve(self):
- """ Get currency exchange from Banxico.xml and proccess it
- TODO: Get correct data from xml instead of process string
- """
- url = ('http://www.banxico.org.mx/rsscb/rss?'
- 'BMXC_canal=pagos&BMXC_idioma=es')
-
- from xml.dom.minidom import parse
- from StringIO import StringIO
-
- logger = logging.getLogger(__name__)
- logger.debug("Banxico currency rate service : connecting...")
- rawfile = self.get_url(url)
-
- dom = parse(StringIO(rawfile))
- logger.debug("Banxico sent a valid XML file")
-
- value = dom.getElementsByTagName('cb:value')[0]
- rate = value.firstChild.nodeValue
-
- return float(rate)
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days=1):
- """implementation of abstract method of Curreny_getter_interface"""
- logger = logging.getLogger(__name__)
- # we do not want to update the main currency
- if main_currency in currency_array:
- currency_array.remove(main_currency)
-
- # Suported currencies
- suported = ['MXN', 'USD']
- for curr in currency_array:
- if curr in suported:
- # Get currency data
- main_rate = self.rate_retrieve()
- if main_currency == 'MXN':
- rate = 1 / main_rate
- else:
- rate = main_rate
- else:
- # No other currency supported
- continue
-
- self.updated_currency[curr] = rate
- logger.debug("Rate retrieved : %s = %s %s" %
- (main_currency, rate, curr))
-
-
-# CA BOC ##### Bank of Canada #############################################
-class CA_BOC_getter(Curreny_getter_interface):
- """Implementation of Curreny_getter_factory interface
- for Bank of Canada RSS service
-
- """
-
- def get_updated_currency(self, currency_array, main_currency,
- max_delta_days):
- """implementation of abstract method of Curreny_getter_interface"""
-
- # as of Jan 2014 BOC is publishing noon rates for about 60 currencies
- url = ('http://www.bankofcanada.ca/stats/assets/'
- 'rates_rss/noon/en_%s.xml')
- # closing rates are available as well (please note there are only 12
- # currencies reported):
- # http://www.bankofcanada.ca/stats/assets/rates_rss/closing/en_%s.xml
-
- # We do not want to update the main currency
- if main_currency in currency_array:
- currency_array.remove(main_currency)
-
- import feedparser
- import pytz
- from dateutil import parser
-
- for curr in currency_array:
-
- _logger.debug("BOC currency rate service : connecting...")
- dom = feedparser.parse(url % curr)
-
- self.validate_cur(curr)
-
- # check if BOC service is running
- if dom.bozo and dom.status != 404:
- _logger.error("Bank of Canada - service is down - try again\
- later...")
-
- # check if BOC sent a valid response for this currency
- if dom.status != 200:
- _logger.error("Exchange data for %s is not reported by Bank\
- of Canada." % curr)
- raise osv.except_osv('Error !', 'Exchange data for %s is not\
- reported by Bank of Canada.' % str(curr))
-
- _logger.debug("BOC sent a valid RSS file for: " + curr)
-
- # check for valid exchange data
- if (dom.entries[0].cb_basecurrency == main_currency) and \
- (dom.entries[0].cb_targetcurrency == curr):
- rate = dom.entries[0].cb_exchangerate.split('\n', 1)[0]
- rate_date_datetime = parser.parse(dom.entries[0].updated)\
- .astimezone(pytz.utc).replace(tzinfo=None)
- self.check_rate_date(rate_date_datetime, max_delta_days)
- self.updated_currency[curr] = rate
- _logger.debug("BOC Rate retrieved : %s = %s %s" %
- (main_currency, rate, curr))
- else:
- _logger.error(
- "Exchange data format error for Bank of Canada -"
- "%s. Please check provider data format "
- "and/or source code." % curr)
- raise osv.except_osv('Error !',
- 'Exchange data format error for\
- Bank of Canada - %s !' % str(curr))
-
- return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_CA_BOC.py b/currency_rate_update/services/update_service_CA_BOC.py
new file mode 100644
index 000000000..d0e18399a
--- /dev/null
+++ b/currency_rate_update/services/update_service_CA_BOC.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from Bank of Canada
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from currency_getter_interface import Currency_getter_interface
+
+from openerp import _
+from openerp.exceptions import except_orm
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class CA_BOC_getter(Currency_getter_interface):
+ """Implementation of Curreny_getter_factory interface
+ for Bank of Canada RSS service
+
+ """
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """implementation of abstract method of Curreny_getter_interface"""
+
+ # as of Jan 2014 BOC is publishing noon rates for about 60 currencies
+ url = ('http://www.bankofcanada.ca/stats/assets/'
+ 'rates_rss/noon/en_%s.xml')
+ # closing rates are available as well (please note there are only 12
+ # currencies reported):
+ # http://www.bankofcanada.ca/stats/assets/rates_rss/closing/en_%s.xml
+
+ # We do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+
+ import feedparser
+ import pytz
+ from dateutil import parser
+
+ for curr in currency_array:
+
+ _logger.debug("BOC currency rate service : connecting...")
+ dom = feedparser.parse(url % curr)
+
+ self.validate_cur(curr)
+
+ # check if BOC service is running
+ if dom.bozo and dom.status != 404:
+ _logger.error("Bank of Canada - service is down - try again\
+ later...")
+
+ # check if BOC sent a valid response for this currency
+ if dom.status != 200:
+ _logger.error("Exchange data for %s is not reported by Bank\
+ of Canada." % curr)
+ raise except_orm(_('Error !'), _('Exchange data for %s is not\
+ reported by Bank of Canada.' % str(curr)))
+
+ _logger.debug("BOC sent a valid RSS file for: " + curr)
+
+ # check for valid exchange data
+ if (dom.entries[0].cb_basecurrency == main_currency) and \
+ (dom.entries[0].cb_targetcurrency == curr):
+ rate = dom.entries[0].cb_exchangerate.split('\n', 1)[0]
+ rate_date_datetime = parser.parse(dom.entries[0].updated)\
+ .astimezone(pytz.utc).replace(tzinfo=None)
+ self.check_rate_date(rate_date_datetime, max_delta_days)
+ self.updated_currency[curr] = rate
+ _logger.debug("BOC Rate retrieved : %s = %s %s" %
+ (main_currency, rate, curr))
+ else:
+ _logger.error(
+ "Exchange data format error for Bank of Canada -"
+ "%s. Please check provider data format "
+ "and/or source code." % curr)
+ raise except_orm(_('Error !'),
+ _('Exchange data format error for\
+ Bank of Canada - %s !' % str(curr)))
+
+ return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_CH_ADMIN.py b/currency_rate_update/services/update_service_CH_ADMIN.py
new file mode 100644
index 000000000..110ad5c5a
--- /dev/null
+++ b/currency_rate_update/services/update_service_CH_ADMIN.py
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from Swiss Federal Authorities
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from currency_getter_interface import Currency_getter_interface
+
+import logging
+_logger = logging.getLogger(__name__)
+
+from datetime import datetime
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+
+
+class CH_ADMIN_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface
+ for Admin.ch service
+
+ """
+
+ def rate_retrieve(self, dom, ns, curr):
+ """Parse a dom node to retrieve currencies data"""
+ res = {}
+ xpath_rate_currency = ("/def:wechselkurse/def:devise[@code='%s']/"
+ "def:kurs/text()") % (curr.lower())
+ xpath_rate_ref = ("/def:wechselkurse/def:devise[@code='%s']/"
+ "def:waehrung/text()") % (curr.lower())
+ res['rate_currency'] = float(
+ dom.xpath(xpath_rate_currency, namespaces=ns)[0]
+ )
+ res['rate_ref'] = float(
+ (dom.xpath(xpath_rate_ref, namespaces=ns)[0]).split(' ')[0]
+ )
+ return res
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """Implementation of abstract method of Curreny_getter_interface"""
+ url = ('http://www.afd.admin.ch/publicdb/newdb/'
+ 'mwst_kurse/wechselkurse.php')
+ # We do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+ # Move to new XML lib cf Launchpad bug #645263
+ from lxml import etree
+ _logger.debug("Admin.ch currency rate service : connecting...")
+ rawfile = self.get_url(url)
+ dom = etree.fromstring(rawfile)
+ _logger.debug("Admin.ch sent a valid XML file")
+ adminch_ns = {
+ 'def': 'http://www.afd.admin.ch/publicdb/newdb/mwst_kurse'
+ }
+ rate_date = dom.xpath(
+ '/def:wechselkurse/def:datum/text()',
+ namespaces=adminch_ns
+ )
+ rate_date = rate_date[0]
+ rate_date_datetime = datetime.strptime(rate_date,
+ DEFAULT_SERVER_DATE_FORMAT)
+ self.check_rate_date(rate_date_datetime, max_delta_days)
+ # we dynamically update supported currencies
+ self.supported_currency_array = dom.xpath(
+ "/def:wechselkurse/def:devise/@code",
+ namespaces=adminch_ns
+ )
+ self.supported_currency_array = [x.upper() for x
+ in self.supported_currency_array]
+ self.supported_currency_array.append('CHF')
+
+ _logger.debug(
+ "Supported currencies = " + str(self.supported_currency_array)
+ )
+ self.validate_cur(main_currency)
+ if main_currency != 'CHF':
+ main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency)
+ # 1 MAIN_CURRENCY = main_rate CHF
+ rate_curr = main_curr_data['rate_currency']
+ rate_ref = main_curr_data['rate_ref']
+ main_rate = rate_curr / rate_ref
+ for curr in currency_array:
+ self.validate_cur(curr)
+ if curr == 'CHF':
+ rate = main_rate
+ else:
+ curr_data = self.rate_retrieve(dom, adminch_ns, curr)
+ # 1 MAIN_CURRENCY = rate CURR
+ if main_currency == 'CHF':
+ rate = curr_data['rate_ref'] / curr_data['rate_currency']
+ else:
+ rate = (main_rate * curr_data['rate_ref'] /
+ curr_data['rate_currency'])
+ self.updated_currency[curr] = rate
+ _logger.debug(
+ "Rate retrieved : 1 %s = %s %s" % (main_currency, rate, curr)
+ )
+ return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_ECB.py b/currency_rate_update/services/update_service_ECB.py
new file mode 100644
index 000000000..ceddce108
--- /dev/null
+++ b/currency_rate_update/services/update_service_ECB.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from European Central Bank
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from currency_getter_interface import Currency_getter_interface
+
+from datetime import datetime
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class ECB_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface
+ for ECB service
+ """
+
+ def rate_retrieve(self, dom, ns, curr):
+ """Parse a dom node to retrieve-
+ currencies data
+
+ """
+ res = {}
+ xpath_curr_rate = ("/gesmes:Envelope/def:Cube/def:Cube/"
+ "def:Cube[@currency='%s']/@rate") % (curr.upper())
+ res['rate_currency'] = float(
+ dom.xpath(xpath_curr_rate, namespaces=ns)[0]
+ )
+ return res
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """implementation of abstract method of Curreny_getter_interface"""
+ url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'
+ # Important : as explained on the ECB web site, the currencies are
+ # at the beginning of the afternoon ; so, until 3 p.m. Paris time
+ # the currency rates are the ones of trading day N-1
+ # http://www.ecb.europa.eu/stats/exchange/eurofxref/html/index.en.html
+
+ # We do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+ # Move to new XML lib cf Launchpad bug #645263
+ from lxml import etree
+ _logger.debug("ECB currency rate service : connecting...")
+ rawfile = self.get_url(url)
+ dom = etree.fromstring(rawfile)
+ _logger.debug("ECB sent a valid XML file")
+ ecb_ns = {
+ 'gesmes': 'http://www.gesmes.org/xml/2002-08-01',
+ 'def': 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref'
+ }
+ rate_date = dom.xpath('/gesmes:Envelope/def:Cube/def:Cube/@time',
+ namespaces=ecb_ns)[0]
+ rate_date_datetime = datetime.strptime(rate_date,
+ DEFAULT_SERVER_DATE_FORMAT)
+ self.check_rate_date(rate_date_datetime, max_delta_days)
+ # We dynamically update supported currencies
+ self.supported_currency_array = dom.xpath(
+ "/gesmes:Envelope/def:Cube/def:Cube/def:Cube/@currency",
+ namespaces=ecb_ns
+ )
+ self.supported_currency_array.append('EUR')
+ _logger.debug("Supported currencies = %s " %
+ self.supported_currency_array)
+ self.validate_cur(main_currency)
+ if main_currency != 'EUR':
+ main_curr_data = self.rate_retrieve(dom, ecb_ns, main_currency)
+ for curr in currency_array:
+ self.validate_cur(curr)
+ if curr == 'EUR':
+ rate = 1 / main_curr_data['rate_currency']
+ else:
+ curr_data = self.rate_retrieve(dom, ecb_ns, curr)
+ if main_currency == 'EUR':
+ rate = curr_data['rate_currency']
+ else:
+ rate = (curr_data['rate_currency'] /
+ main_curr_data['rate_currency'])
+ self.updated_currency[curr] = rate
+ _logger.debug(
+ "Rate retrieved : 1 %s = %s %s" % (main_currency, rate, curr)
+ )
+ return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_MX_BdM.py b/currency_rate_update/services/update_service_MX_BdM.py
new file mode 100644
index 000000000..8e3680a18
--- /dev/null
+++ b/currency_rate_update/services/update_service_MX_BdM.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from Banco de México
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from currency_getter_interface import Currency_getter_interface
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class MX_BdM_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface
+ for Banco de México service
+
+ """
+
+ def rate_retrieve(self):
+ """ Get currency exchange from Banxico.xml and proccess it
+ TODO: Get correct data from xml instead of process string
+ """
+ url = ('http://www.banxico.org.mx/rsscb/rss?'
+ 'BMXC_canal=pagos&BMXC_idioma=es')
+
+ from xml.dom.minidom import parse
+ from StringIO import StringIO
+
+ logger = logging.getLogger(__name__)
+ logger.debug("Banxico currency rate service : connecting...")
+ rawfile = self.get_url(url)
+
+ dom = parse(StringIO(rawfile))
+ logger.debug("Banxico sent a valid XML file")
+
+ value = dom.getElementsByTagName('cb:value')[0]
+ rate = value.firstChild.nodeValue
+
+ return float(rate)
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days=1):
+ """implementation of abstract method of Curreny_getter_interface"""
+ logger = logging.getLogger(__name__)
+ # we do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+
+ # Suported currencies
+ suported = ['MXN', 'USD']
+ for curr in currency_array:
+ if curr in suported:
+ # Get currency data
+ main_rate = self.rate_retrieve()
+ if main_currency == 'MXN':
+ rate = 1 / main_rate
+ else:
+ rate = main_rate
+ else:
+ # No other currency supported
+ continue
+
+ self.updated_currency[curr] = rate
+ logger.debug("Rate retrieved : %s = %s %s" %
+ (main_currency, rate, curr))
diff --git a/currency_rate_update/services/update_service_PL_NBP.py b/currency_rate_update/services/update_service_PL_NBP.py
new file mode 100644
index 000000000..0f57cc265
--- /dev/null
+++ b/currency_rate_update/services/update_service_PL_NBP.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from National Bank of Poland
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from currency_getter_interface import Currency_getter_interface
+
+from datetime import datetime
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class PL_NBP_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface
+ for PL NBP service
+
+ """
+
+ def rate_retrieve(self, dom, ns, curr):
+ """ Parse a dom node to retrieve
+ currencies data"""
+ res = {}
+ xpath_rate_currency = ("/tabela_kursow/pozycja[kod_waluty='%s']/"
+ "kurs_sredni/text()") % (curr.upper())
+ xpath_rate_ref = ("/tabela_kursow/pozycja[kod_waluty='%s']/"
+ "przelicznik/text()") % (curr.upper())
+ res['rate_currency'] = float(
+ dom.xpath(xpath_rate_currency, namespaces=ns)[0].replace(',', '.')
+ )
+ res['rate_ref'] = float(dom.xpath(xpath_rate_ref, namespaces=ns)[0])
+ return res
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """implementation of abstract method of Curreny_getter_interface"""
+ # LastA.xml is always the most recent one
+ url = 'http://www.nbp.pl/kursy/xml/LastA.xml'
+ # We do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+ # Move to new XML lib cf Launchpad bug #645263
+ from lxml import etree
+ _logger.debug("NBP.pl currency rate service : connecting...")
+ rawfile = self.get_url(url)
+ dom = etree.fromstring(rawfile)
+ ns = {} # Cool, there are no namespaces !
+ _logger.debug("NBP.pl sent a valid XML file")
+ rate_date = dom.xpath('/tabela_kursow/data_publikacji/text()',
+ namespaces=ns)[0]
+ rate_date_datetime = datetime.strptime(rate_date,
+ DEFAULT_SERVER_DATE_FORMAT)
+ self.check_rate_date(rate_date_datetime, max_delta_days)
+ # We dynamically update supported currencies
+ self.supported_currency_array = dom.xpath(
+ '/tabela_kursow/pozycja/kod_waluty/text()',
+ namespaces=ns
+ )
+ self.supported_currency_array.append('PLN')
+ _logger.debug("Supported currencies = %s" %
+ self.supported_currency_array)
+ self.validate_cur(main_currency)
+ if main_currency != 'PLN':
+ main_curr_data = self.rate_retrieve(dom, ns, main_currency)
+ # 1 MAIN_CURRENCY = main_rate PLN
+ main_rate = (main_curr_data['rate_currency'] /
+ main_curr_data['rate_ref'])
+ for curr in currency_array:
+ self.validate_cur(curr)
+ if curr == 'PLN':
+ rate = main_rate
+ else:
+ curr_data = self.rate_retrieve(dom, ns, curr)
+ # 1 MAIN_CURRENCY = rate CURR
+ if main_currency == 'PLN':
+ rate = curr_data['rate_ref'] / curr_data['rate_currency']
+ else:
+ rate = (main_rate * curr_data['rate_ref'] /
+ curr_data['rate_currency'])
+ self.updated_currency[curr] = rate
+ _logger.debug("Rate retrieved : %s = %s %s" %
+ (main_currency, rate, curr))
+ return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_RO_BNR.py b/currency_rate_update/services/update_service_RO_BNR.py
new file mode 100644
index 000000000..468a8f563
--- /dev/null
+++ b/currency_rate_update/services/update_service_RO_BNR.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from National Bank of Romania
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from currency_getter_interface import Currency_getter_interface
+
+from datetime import datetime, timedelta
+
+import logging
+_logger = logging.getLogger(__name__)
+
+
+class RO_BNR_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface for BNR service"""
+
+ def rate_retrieve(self, dom, ns, curr):
+ """ Parse a dom node to retrieve-
+ currencies data"""
+ res = {}
+ xpath_rate_currency = "/def:DataSet/def:Body/def:Cube/def:Rate" + \
+ "[@currency='%s']/text()" % (curr.upper())
+ xpath_rate_ref = "/def:DataSet/def:Body/def:Cube/def:Rate" + \
+ "[@currency='%s']/@multiplier" % (curr.upper())
+ res['rate_currency'] = float(dom.xpath(xpath_rate_currency,
+ namespaces=ns)[0])
+ try:
+ res['rate_ref'] = float(dom.xpath(xpath_rate_ref,
+ namespaces=ns)[0])
+ except:
+ res['rate_ref'] = 1
+ return res
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """implementation of abstract method of Curreny_getter_interface"""
+ url = 'http://www.bnr.ro/nbrfxrates.xml'
+ # we do not want to update the main currency
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+ # Move to new XML lib cf Launchpad bug #645263
+ from lxml import etree
+ _logger.debug("BNR currency rate service : connecting...")
+ rawfile = self.get_url(url)
+ dom = etree.fromstring(rawfile)
+ adminch_ns = {'def': 'http://www.bnr.ro/xsd'}
+ rate_date = dom.xpath('/def:DataSet/def:Body/def:Cube/@date',
+ namespaces=adminch_ns)[0]
+ rate_date_datetime = datetime.strptime(rate_date,
+ '%Y-%m-%d') + \
+ timedelta(days=1)
+ self.check_rate_date(rate_date_datetime, max_delta_days)
+ # we dynamically update supported currencies
+ self.supported_currency_array = dom.xpath("/def:DataSet/def:Body/" + \
+ "def:Cube/def:Rate/@currency",
+ namespaces=adminch_ns)
+ self.supported_currency_array = [x.upper() for x in \
+ self.supported_currency_array]
+ self.supported_currency_array.append('RON')
+
+ self.validate_cur(main_currency)
+ if main_currency != 'RON':
+ main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency)
+ # 1 MAIN_CURRENCY = main_rate RON
+ main_rate = main_curr_data['rate_currency'] / \
+ main_curr_data['rate_ref']
+ for curr in currency_array:
+ self.validate_cur(curr)
+ if curr == 'RON':
+ rate = main_rate
+ else:
+ curr_data = self.rate_retrieve(dom, adminch_ns, curr)
+ # 1 MAIN_CURRENCY = rate CURR
+ if main_currency == 'RON':
+ rate = curr_data['rate_ref'] / curr_data['rate_currency']
+ else:
+ rate = main_rate * curr_data['rate_ref'] / \
+ curr_data['rate_currency']
+ self.updated_currency[curr] = rate
+ _logger.debug("BNR Rate retrieved : 1 " + main_currency +
+ ' = ' + str(rate) + ' ' + curr)
+ return self.updated_currency, self.log_info
diff --git a/currency_rate_update/services/update_service_YAHOO.py b/currency_rate_update/services/update_service_YAHOO.py
new file mode 100644
index 000000000..7ed18a954
--- /dev/null
+++ b/currency_rate_update/services/update_service_YAHOO.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# Copyright (c) 2009 CamptoCamp. All rights reserved.
+# @author Nicolas Bessi
+#
+# Abstract class to fetch rates from Yahoo Financial
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+
+from currency_getter_interface import Currency_getter_interface
+
+
+class YAHOO_getter(Currency_getter_interface):
+ """Implementation of Currency_getter_factory interface
+ for Yahoo finance service
+ """
+
+ def get_updated_currency(self, currency_array, main_currency,
+ max_delta_days):
+ """implementation of abstract method of curreny_getter_interface"""
+ self.validate_cur(main_currency)
+ url = ('http://download.finance.yahoo.com/d/'
+ 'quotes.txt?s="%s"=X&f=sl1c1abg')
+ if main_currency in currency_array:
+ currency_array.remove(main_currency)
+ for curr in currency_array:
+ self.validate_cur(curr)
+ res = self.get_url(url % (main_currency + curr))
+ val = res.split(',')[1]
+ if val:
+ self.updated_currency[curr] = val
+ else:
+ raise Exception('Could not update the %s' % (curr))
+
+ return self.updated_currency, self.log_info