Fix PEP8 of module currency_rate_update in order to be able to activate flake8 testing on travis.

No refactoring has been done despite the current need
This commit is contained in:
Nicolas Bessi
2014-07-04 17:14:22 +02:00
parent 9c8d433b7d
commit 71dbec7e8c
3 changed files with 420 additions and 361 deletions

View File

@@ -22,11 +22,11 @@
#
##############################################################################
{
"name" : "Currency Rate Update",
"version" : "0.7",
"author" : "Camptocamp",
"website" : "http://camptocamp.com",
"category" : "Financial Management/Configuration",
"name": "Currency Rate Update",
"version": "0.7",
"author": "Camptocamp",
"website": "http://camptocamp.com",
"category": "Financial Management/Configuration",
"description": """Import exchange rates from the Internet.
The module is able to use 4 different sources:
@@ -48,7 +48,7 @@ The module is able to use 4 different sources:
You should check when rates should apply to bookkeeping. If next day you should
change the update hour in schedule settings because in OpenERP they apply from
date of update (date - no hours).
5. Banxico for USD & MXN (created by Agustín Cruz)
Updated daily
@@ -64,7 +64,7 @@ The module uses internal ir_cron feature from OpenERP, so the job is launched on
the server starts if the 'first execute date' is before the current day.
The module supports multi-company currency in two ways:
* the currencies are shared, you can set currency update only on one
* the currencies are shared, you can set currency update only on one
company
* the currency are separated, you can set currency on every company
separately
@@ -76,16 +76,16 @@ found in database.
Thanks to main contributors: Grzegorz Grzelak, Alexis de Lattre
""",
"depends" : [
"depends": [
"base",
"account", #Added to ensure account security groups are present
],
"data" : [
"account", # Added to ensure account security groups are present
],
"data": [
"currency_rate_update.xml",
"company_view.xml",
"security/security.xml",
],
"demo" : [],
],
"demo": [],
"active": False,
'installable': True
}

View File

@@ -18,17 +18,21 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import netsvc
from openerp.osv import fields, orm
class res_company(orm.Model):
"""override company to add currency update"""
def _multi_curr_enable(self, cr, uid, ids, field_name, arg, context={}):
"check if multi company currency is enabled"
result = {}
if self.pool.get('ir.model.fields').search(cr, uid, [('name', '=', 'company_id'), ('model', '=', 'res.currency')])==[]:
fields = self.pool.get('ir.model.fields').search(
cr, uid,
[('name', '=', 'company_id'),
('model', '=', 'res.currency')]
)
if not fields:
enable = 0
else:
enable = 1
@@ -36,18 +40,15 @@ class res_company(orm.Model):
result[id] = enable
return result
def button_refresh_currency(self, cr, uid, ids, context=None):
"""Refrech the currency !!for all the company
now"""
"""Refrech the currency for all the company now"""
currency_updater_obj = self.pool.get('currency.rate.update')
try:
currency_updater_obj.run_currency_update(cr, uid)
except Exception, e:
except Exception:
return False
return True
def on_change_auto_currency_up(self, cr, uid, id, value):
"""handle the activation of the currecny update on compagnies.
There are two ways of implementing multi_company currency,
@@ -56,102 +57,100 @@ class res_company(orm.Model):
auto update on one company, this will avoid to have unusefull cron
object running.
If yours currency are not share you will be able to activate the
auto update on each separated company"""
auto update on each separated company
if len(id) :
"""
if len(id):
id = id[0]
else :
else:
return {}
enable = self.browse(cr, uid, id).multi_company_currency_enable
compagnies = self.search(cr, uid, [])
compagnies = self.search(cr, uid, [])
activate_cron = 'f'
if not value :
if not value:
# this statement is here beacaus we do no want to save in case of error
self.write(cr, uid, id,{'auto_currency_up':value})
for comp in compagnies :
self.write(cr, uid, id, {'auto_currency_up': value})
for comp in compagnies:
if self.browse(cr, uid, comp).auto_currency_up:
activate_cron = 't'
break
self.pool.get('currency.rate.update').save_cron(
cr,
uid,
{'active':activate_cron}
)
cr,
uid,
{'active': activate_cron}
)
return {}
else :
for comp in compagnies :
else:
for comp in compagnies:
if comp != id and not enable:
if self.browse(cr, uid, comp).multi_company_currency_enable:
#we ensure taht we did not have write a true value
self.write(cr, uid, id,{'auto_currency_up':False})
self.write(cr, uid, id, {'auto_currency_up': False})
return {
'value':{
'auto_currency_up':False
},
'value': {'auto_currency_up': False},
'warning':{
'title':"Warning",
'message': 'Yon can not activate auto currency '+\
'update on more thant one company with this '+
'multi company configuration'
}
}
self.write(cr, uid, id,{'auto_currency_up':value})
for comp in compagnies :
'warning': {
'title': "Warning",
'message': 'You can not activate auto currency '
'update on more thant one company with this '
'multi company configuration'
}
}
self.write(cr, uid, id, {'auto_currency_up': value})
for comp in compagnies:
if self.browse(cr, uid, comp).auto_currency_up:
activate_cron = 't'
self.pool.get('currency.rate.update').save_cron(
cr,
uid,
{'active':activate_cron}
)
cr,
uid,
{'active': activate_cron}
)
break
return {}
def on_change_intervall(self, cr, uid, id, interval) :
###Function that will update the cron
###freqeuence
def on_change_intervall(self, cr, uid, id, interval):
# Function that will update the cron freqeuence
self.pool.get('currency.rate.update').save_cron(
cr,
uid,
{'interval_type':interval}
)
compagnies = self.search(cr, uid, [])
for comp in compagnies :
self.write(cr, uid, comp,{'interval_type':interval})
cr,
uid,
{'interval_type': interval}
)
compagnies = self.search(cr, uid, [])
for comp in compagnies:
self.write(cr, uid, comp, {'interval_type': interval})
return {}
_inherit = "res.company"
_columns = {
### activate the currency update
'auto_currency_up': fields.boolean('Automatical update of the currency this company'),
'services_to_use' : fields.one2many(
'currency.rate.update.service',
'company_id',
'Currency update services'
),
###predifine cron frequence
# Activate the currency update
'auto_currency_up': fields.boolean(
'Automatical update of the currency this company'
),
'services_to_use': fields.one2many(
'currency.rate.update.service',
'company_id',
'Currency update services'
),
# Predifine cron frequence
'interval_type': fields.selection(
[
('days','Day(s)'),
('weeks', 'Week(s)'),
('months', 'Month(s)')
],
'Currency update frequence',
help="""changing this value will
also affect other compagnies"""
),
###function field that allows to know the
###mutli company currency implementation
'multi_company_currency_enable' : fields.function(
_multi_curr_enable,
method=True,
type='boolean',
string="Multi company currency",
help='if this case is not check you can'+\
' not set currency is active on two company'
),
[
('days', 'Day(s)'),
('weeks', 'Week(s)'),
('months', 'Month(s)')
],
'Currency update frequence',
help="Changing this value will "
"also affect other compagnies"
),
# Function field that allows to know the
# mutli company currency implementation
'multi_company_currency_enable': fields.function(
_multi_curr_enable,
method=True,
type='boolean',
string="Multi company currency",
help="If this case is not check you can"
" not set currency is active on two company"
),
}

View File

@@ -2,7 +2,6 @@
##############################################################################
#
# Copyright (c) 2009 Camptocamp SA
# @author Nicolas Bessi
# @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)
@@ -31,68 +30,75 @@
#
##############################################################################
# TODO "nice to have" : restain the list of currencies that can be added for
# 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
from openerp.osv import fields, osv, orm
import logging
import time
from datetime import datetime, timedelta
import logging
from openerp.osv import fields, osv, orm
from openerp.tools.translate import _
_logger = logging.getLogger(__name__)
class Currency_rate_update_service(osv.Model):
"""Class thats tell for wich services wich currencies
have to be updated"""
"""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'),
#('NYFB_getter','Federal Reserve Bank of NY'),
#('Google_getter','Google Finance'),
('Yahoo_getter','Yahoo Finance '),
('PL_NBP_getter','Narodowy Bank Polski'), # Added for polish rates
('Banxico_getter', 'Banco de México'), # Added for mexican rates
# 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'), # Added for canadian 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,
# List of webservicies the value sould be a class name
'service': fields.selection(
[
('Admin_ch_getter', 'Admin.ch'),
('ECB_getter', 'European Central Bank'),
#('NYFB_getter','Federal Reserve Bank of NY'),
#('Google_getter','Google Finance'),
('Yahoo_getter', 'Yahoo Finance '),
('PL_NBP_getter', 'Narodowy Bank Polski'), # Added for polish rates
('Banxico_getter', 'Banco de México'), # Added for mexican rates
# 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'), # Added for canadian 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 !')
)
]
(
'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']):
@@ -103,7 +109,9 @@ class Currency_rate_update_service(osv.Model):
return True
_constraints = [
(_check_max_delta_days, "'Max delta days' must be >= 0", ['max_delta_days']),
(_check_max_delta_days,
"'Max delta days' must be >= 0",
['max_delta_days']),
]
@@ -112,58 +120,59 @@ class Currency_rate_update(osv.Model):
update currencies based on a web url"""
_name = "currency.rate.update"
_description = "Currency Rate Update"
##dict that represent a cron object
# Dict that represent a cron object
cron = {
'active' : False,
'priority' : 1,
'interval_number' : 1,
'interval_type' : 'weeks',
'nextcall' : time.strftime("%Y-%m-%d %H:%M:%S", (datetime.today() + timedelta(days=1)).timetuple() ), #tomorrow same time
'numbercall' : -1,
'doall' : True,
'model' : 'currency.rate.update',
'function' : 'run_currency_update',
'args' : '()',
'active': False,
'priority': 1,
'interval_number': 1,
'interval_type': 'weeks',
'nextcall': time.strftime("%Y-%m-%d %H:%M:%S",
datetime.today() + timedelta(days=1)).timetuple(),
'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):
"""return the updater cron's id. Create one if the cron does not exists """
"""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:
#find the cron that send messages
#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
}
)
cr,
uid,
[
('function', 'ilike', self.cron['function']),
('model', 'ilike', self.cron['model'])
],
context={
'active_test': False
}
)
cron_id = int(cron_id[0])
except Exception,e :
except Exception:
_logger.info('warning cron not found one will be created')
pass # ignore if the cron is missing cause we are going to create it in db
pass # Ignore if the cron is missing cause we are going to create it in db
#the cron does not exists
if not cron_id :
#translate
#The cron does not exists
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={}):
"""save the cron config data should be a dict"""
#modify the cron
cron_id = self.get_cron_id(cr, uid, context)
result = self.pool.get('ir.cron').write(cr, uid, [cron_id], datas)
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"
@@ -172,123 +181,145 @@ class Currency_rate_update(osv.Model):
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 :
#The multi company currency can beset or no so we handle
#The two case
if not comp.auto_currency_up:
continue
#we initialise the multi compnay search filter or not serach filter
search_filter = []
if comp.multi_company_currency_enable :
search_filter = [('company_id','=',comp.id)]
#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)])
#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 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!'))
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!'))
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 :
print "comp.services_to_use =", comp.services_to_use
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
try:
#We initalize the class that will handle the request
#and return a dict of rate
getter = factory.register(service.service)
print "getter =", getter
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)
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('%Y-%m-%d')
for curr in service.currency_to_update :
if curr.name == main_curr :
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]})
for rate in curr.rate_ids:
if rate.name == rate_name:
rate.write({'rate': res[curr.name]})
do_create = False
break
if do_create :
if do_create:
vals = {
'currency_id': curr.id,
'rate':res[curr.name],
'name': rate_name
}
'currency_id': curr.id,
'rate': res[curr.name],
'name': rate_name
}
rate_obj.create(
cr,
uid,
vals,
)
cr,
uid,
vals,
)
# show the most recent note at the top
note = "\n%s currency updated. "\
%(datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'))\
+ note
note = (log_info or '') + note
service.write({'note':note})
except Exception, e:
error_msg = "\n%s ERROR : %s"\
%(datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'), str(e))\
+ note
_logger.info(str(e))
service.write({'note':error_msg})
# Show the most recent note at the top
msg = "%s \n%s currency updated. %s" % \
(log_info or '',
datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'),
note)
service.write({'note': msg})
except Exception as exc:
error_msg = "\n%s ERROR : %s %s" %\
(datetime.strftime(datetime.today(), '%Y-%m-%d %H:%M:%S'),
repr(exc),
note)
_logger.info(repr(exc))
service.write({'note': error_msg})
### Error Definition as specified in python 2.6 PEP
class AbstractClassError(Exception):
def __str__(self):
return 'Abstract Class'
def __repr__(self):
return 'Abstract Class'
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 '+self.curr
def __repr__(self):
return 'Unsupported currency '+self.curr
self.curr = value
def __str__(self):
return 'Unsupported currency %s' % self.curr
def __repr__(self):
return 'Unsupported currency %s' % self.curr
### end of error definition
class Currency_getter_factory():
"""Factory pattern class that will return
a currency getter class base on the name passed
to the register method"""
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',
]
'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 :
else:
raise UnknowClassError
class Curreny_getter_interface(object) :
class Curreny_getter_interface(object):
"Abstract class of currency getter"
#remove in order to have a dryer code
@@ -297,47 +328,49 @@ class Curreny_getter_interface(object) :
log_info = " "
supported_currency_array = \
['AFN', 'ALL', 'DZD', 'USD', 'USD', 'USD', 'EUR', 'AOA', 'XCD', 'XCD', 'ARS',
'AMD', 'AWG', 'AUD', 'EUR', 'AZN', 'EUR', 'BSD', 'BHD', 'EUR', 'BDT', 'BBD',
'XCD', 'BYR', 'EUR', 'BZD', 'XOF', 'BMD', 'BTN', 'INR', 'BOB', 'ANG', 'BAM',
'BWP', 'NOK', 'BRL', 'GBP', 'USD', 'USD', 'BND', 'BGN', 'XOF', 'MMK', 'BIF',
'XOF', 'USD', 'KHR', 'XAF', 'CAD', 'EUR', 'CVE', 'KYD', 'XAF', 'XAF', 'CLP',
'CNY', 'AUD', 'AUD', 'COP', 'XAF', 'KMF', 'XPF', 'XAF', 'CDF', 'NZD', 'CRC',
'HRK', 'CUP', 'ANG', 'EUR', 'CYP', 'CZK', 'DKK', 'DJF', 'XCD', 'DOP', 'EUR',
'XCD', 'IDR', 'USD', 'EGP', 'EUR', 'SVC', 'USD', 'GBP', 'XAF', 'ETB', 'ERN',
'EEK', 'ETB', 'EUR', 'FKP', 'DKK', 'FJD', 'EUR', 'EUR', 'EUR', 'XPF', 'XPF',
'EUR', 'XPF', 'XAF', 'GMD', 'GEL', 'EUR', 'GHS', 'GIP', 'XAU', 'GBP', 'EUR',
'DKK', 'XCD', 'XCD', 'EUR', 'USD', 'GTQ', 'GGP', 'GNF', 'XOF', 'GYD', 'HTG',
'USD', 'AUD', 'BAM', 'EUR', 'EUR', 'HNL', 'HKD', 'HUF', 'ISK', 'INR', 'IDR',
'XDR', 'IRR', 'IQD', 'EUR', 'IMP', 'ILS', 'EUR', 'JMD', 'NOK', 'JPY', 'JEP',
'JOD', 'KZT', 'AUD', 'KES', 'AUD', 'KPW', 'KRW', 'KWD', 'KGS', 'LAK', 'LVL',
'LBP', 'LSL', 'ZAR', 'LRD', 'LYD', 'CHF', 'LTL', 'EUR', 'MOP', 'MKD', 'MGA',
'EUR', 'MWK', 'MYR', 'MVR', 'XOF', 'EUR', 'MTL', 'FKP', 'USD', 'USD', 'EUR',
'MRO', 'MUR', 'EUR', 'AUD', 'MXN', 'USD', 'USD', 'EUR', 'MDL', 'EUR', 'MNT',
'EUR', 'XCD', 'MAD', 'MZN', 'MMK', 'NAD', 'ZAR', 'AUD', 'NPR', 'ANG', 'EUR',
'XCD', 'XPF', 'NZD', 'NIO', 'XOF', 'NGN', 'NZD', 'AUD', 'USD', 'NOK', 'OMR',
'PKR', 'USD', 'XPD', 'PAB', 'USD', 'PGK', 'PYG', 'PEN', 'PHP', 'NZD', 'XPT',
'PLN', 'EUR', 'STD', 'USD', 'QAR', 'EUR', 'RON', 'RUB', 'RWF', 'STD', 'ANG',
'MAD', 'XCD', 'SHP', 'XCD', 'XCD', 'EUR', 'XCD', 'EUR', 'USD', 'WST', 'EUR',
'SAR', 'SPL', 'XOF', 'RSD', 'SCR', 'SLL', 'XAG', 'SGD', 'ANG', 'ANG', 'EUR',
'EUR', 'SBD', 'SOS', 'ZAR', 'GBP', 'GBP', 'EUR', 'XDR', 'LKR', 'SDG', 'SRD',
'NOK', 'SZL', 'SEK', 'CHF', 'SYP', 'TWD', 'RUB', 'TJS', 'TZS', 'THB', 'IDR',
'TTD', 'XOF', 'NZD', 'TOP', 'TTD', 'TND', 'TRY', 'TMM', 'USD', 'TVD', 'UGX',
'UAH', 'AED', 'GBP', 'USD', 'USD', 'UYU', 'USD', 'UZS', 'VUV', 'EUR', 'VEB',
'VEF', 'VND', 'USD', 'USD', 'USD', 'XPF', 'MAD', 'YER', 'ZMK', 'ZWD']
supported_currency_array = [
'AFN', 'ALL', 'DZD', 'USD', 'USD', 'USD', 'EUR', 'AOA', 'XCD', 'XCD', 'ARS',
'AMD', 'AWG', 'AUD', 'EUR', 'AZN', 'EUR', 'BSD', 'BHD', 'EUR', 'BDT', 'BBD',
'XCD', 'BYR', 'EUR', 'BZD', 'XOF', 'BMD', 'BTN', 'INR', 'BOB', 'ANG', 'BAM',
'BWP', 'NOK', 'BRL', 'GBP', 'USD', 'USD', 'BND', 'BGN', 'XOF', 'MMK', 'BIF',
'XOF', 'USD', 'KHR', 'XAF', 'CAD', 'EUR', 'CVE', 'KYD', 'XAF', 'XAF', 'CLP',
'CNY', 'AUD', 'AUD', 'COP', 'XAF', 'KMF', 'XPF', 'XAF', 'CDF', 'NZD', 'CRC',
'HRK', 'CUP', 'ANG', 'EUR', 'CYP', 'CZK', 'DKK', 'DJF', 'XCD', 'DOP', 'EUR',
'XCD', 'IDR', 'USD', 'EGP', 'EUR', 'SVC', 'USD', 'GBP', 'XAF', 'ETB', 'ERN',
'EEK', 'ETB', 'EUR', 'FKP', 'DKK', 'FJD', 'EUR', 'EUR', 'EUR', 'XPF', 'XPF',
'EUR', 'XPF', 'XAF', 'GMD', 'GEL', 'EUR', 'GHS', 'GIP', 'XAU', 'GBP', 'EUR',
'DKK', 'XCD', 'XCD', 'EUR', 'USD', 'GTQ', 'GGP', 'GNF', 'XOF', 'GYD', 'HTG',
'USD', 'AUD', 'BAM', 'EUR', 'EUR', 'HNL', 'HKD', 'HUF', 'ISK', 'INR', 'IDR',
'XDR', 'IRR', 'IQD', 'EUR', 'IMP', 'ILS', 'EUR', 'JMD', 'NOK', 'JPY', 'JEP',
'JOD', 'KZT', 'AUD', 'KES', 'AUD', 'KPW', 'KRW', 'KWD', 'KGS', 'LAK', 'LVL',
'LBP', 'LSL', 'ZAR', 'LRD', 'LYD', 'CHF', 'LTL', 'EUR', 'MOP', 'MKD', 'MGA',
'EUR', 'MWK', 'MYR', 'MVR', 'XOF', 'EUR', 'MTL', 'FKP', 'USD', 'USD', 'EUR',
'MRO', 'MUR', 'EUR', 'AUD', 'MXN', 'USD', 'USD', 'EUR', 'MDL', 'EUR', 'MNT',
'EUR', 'XCD', 'MAD', 'MZN', 'MMK', 'NAD', 'ZAR', 'AUD', 'NPR', 'ANG', 'EUR',
'XCD', 'XPF', 'NZD', 'NIO', 'XOF', 'NGN', 'NZD', 'AUD', 'USD', 'NOK', 'OMR',
'PKR', 'USD', 'XPD', 'PAB', 'USD', 'PGK', 'PYG', 'PEN', 'PHP', 'NZD', 'XPT',
'PLN', 'EUR', 'STD', 'USD', 'QAR', 'EUR', 'RON', 'RUB', 'RWF', 'STD', 'ANG',
'MAD', 'XCD', 'SHP', 'XCD', 'XCD', 'EUR', 'XCD', 'EUR', 'USD', 'WST', 'EUR',
'SAR', 'SPL', 'XOF', 'RSD', 'SCR', 'SLL', 'XAG', 'SGD', 'ANG', 'ANG', 'EUR',
'EUR', 'SBD', 'SOS', 'ZAR', 'GBP', 'GBP', 'EUR', 'XDR', 'LKR', 'SDG', 'SRD',
'NOK', 'SZL', 'SEK', 'CHF', 'SYP', 'TWD', 'RUB', 'TJS', 'TZS', 'THB', 'IDR',
'TTD', 'XOF', 'NZD', 'TOP', 'TTD', 'TND', 'TRY', 'TMM', 'USD', 'TVD', 'UGX',
'UAH', 'AED', 'GBP', 'USD', 'USD', 'UYU', 'USD', 'UZS', 'VUV', 'EUR', 'VEB',
'VEF', 'VND', 'USD', 'USD', 'USD', 'XPF', 'MAD', 'YER', 'ZMK', 'ZWD'
]
##updated currency this arry will contain the final result
#Updated currency this arry will contain the final result
updated_currency = {}
def get_updated_currency(self, currency_array, main_currency, max_delta_days) :
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"""
This function has to be reinplemented in child
"""
raise AbstractMethodError
def validate_cur(self, currency) :
def validate_cur(self, currency):
"""Validate if the currency to update is supported"""
if currency not in self.supported_currency_array :
if currency not in self.supported_currency_array:
raise UnsuportedCurrencyError(currency)
def get_url(self, url):
@@ -349,65 +382,83 @@ class Curreny_getter_interface(object) :
objfile.close()
return rawfile
except ImportError:
raise osv.except_osv('Error !', self.MOD_NAME+'Unable to import urllib !')
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 !')
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. WARN : rate_date must be of datetime type"""
"""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
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, '%Y-%m-%d')
if rate_date_str != datetime.strftime(datetime.today(), '%Y-%m-%d'):
self.log_info = "WARNING : the rate timestamp (%s) is not today's date" % rate_date_str
_logger.warning("the rate timestamp (%s) is not today's date", rate_date_str)
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) :
#Yahoo ########################################################################
class Yahoo_getter(Curreny_getter_interface):
"""Implementation of Currency_getter_factory interface
for Yahoo finance service"""
for Yahoo finance service
"""
def get_updated_currency(self, currency_array, main_currency, max_delta_days):
"""implementation of abstract method of Curreny_getter_interface"""
"""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 :
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 :
for curr in currency_array:
self.validate_cur(curr)
res = self.get_url(url%(main_currency+curr))
res = self.get_url(url % (main_currency + curr))
val = res.split(',')[1]
if val :
if val:
self.updated_currency[curr] = val
else :
raise Exception('Could not update the %s'%(curr))
else:
raise Exception('Could not update the %s' % (curr))
return self.updated_currency, self.log_info # empty string added by polish changes
##Admin CH ############################################################################
class Admin_ch_getter(Curreny_getter_interface) :
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"""
for Admin.ch service
def rate_retrieve(self, dom, ns, curr) :
""" Parse a dom node to retrieve-
currencies data"""
"""
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())
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 :
"""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
#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)
@@ -428,60 +479,70 @@ class Admin_ch_getter(Curreny_getter_interface) :
main_curr_data = self.rate_retrieve(dom, adminch_ns, main_currency)
# 1 MAIN_CURRENCY = main_rate CHF
main_rate = main_curr_data['rate_currency'] / main_curr_data['rate_ref']
for curr in currency_array :
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' :
if main_currency == 'CHF':
rate = curr_data['rate_ref'] / curr_data['rate_currency']
else :
else:
rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency']
self.updated_currency[curr] = rate
_logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr)
_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) :
## ECB getter #################################################################
class ECB_getter(Curreny_getter_interface):
"""Implementation of Currency_getter_factory interface
for ECB service"""
for ECB service
"""
def rate_retrieve(self, dom, ns, curr) :
""" Parse a dom node to retrieve-
currencies data"""
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())
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'
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
# see 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 :
#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
#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]
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, '%Y-%m-%d')
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 = dom.xpath("/gesmes:Envelope/def:Cube/def:Cube/def:Cube/@currency",
namespaces=ecb_ns)
self.supported_currency_array.append('EUR')
_logger.debug("Supported currencies = " + str(self.supported_currency_array))
_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)
@@ -496,56 +557,53 @@ class ECB_getter(Curreny_getter_interface) :
else:
rate = curr_data['rate_currency'] / main_curr_data['rate_currency']
self.updated_currency[curr] = rate
_logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr)
_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) : # class added according to polish needs = based on class Admin_ch_getter
"""Implementation of Currency_getter_factory interface
for PL NBP service"""
def rate_retrieve(self, dom, ns, curr) :
#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(',','.'))
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"""
url='http://www.nbp.pl/kursy/xml/LastA.xml' # LastA.xml is always the most recent one
url = 'http://www.nbp.pl/kursy/xml/LastA.xml' # LastA.xml is always the most recent one
#we do not want to update the main currency
if main_currency in currency_array :
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) # If rawfile is not XML, it crashes here
ns = {} # Cool, there are no namespaces !
dom = etree.fromstring(rawfile)
ns = {} # Cool, there are no namespaces !
_logger.debug("NBP.pl sent a valid XML file")
#node = xpath.Evaluate("/tabela_kursow", dom) # BEGIN Polish - rates table name
#if isinstance(node, list) :
# node = node[0]
#self.log_info = node.getElementsByTagName('numer_tabeli')[0].childNodes[0].data
#self.log_info = self.log_info + " " + node.getElementsByTagName('data_publikacji')[0].childNodes[0].data # END Polish - rates table name
rate_date = dom.xpath('/tabela_kursow/data_publikacji/text()', namespaces=ns)[0]
rate_date_datetime = datetime.strptime(rate_date, '%Y-%m-%d')
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 = " + str(self.supported_currency_array))
_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 :
for curr in currency_array:
self.validate_cur(curr)
if curr == 'PLN':
rate = main_rate
@@ -557,14 +615,16 @@ class PL_NBP_getter(Curreny_getter_interface) : # class added according to pol
else:
rate = main_rate * curr_data['rate_ref'] / curr_data['rate_currency']
self.updated_currency[curr] = rate
_logger.debug("Rate retrieved : 1 " + main_currency + ' = ' + str(rate) + ' ' + curr)
_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) : # class added for Mexico rates
##Banco de México #############################################################
class Banxico_getter(Curreny_getter_interface):
"""Implementation of Currency_getter_factory interface
for Banco de México service"""
for Banco de México service
"""
def rate_retrieve(self):
""" Get currency exchange from Banxico.xml and proccess it
@@ -587,17 +647,16 @@ class Banxico_getter(Curreny_getter_interface) : # class added for Mexico rates
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 :
if main_currency in currency_array:
currency_array.remove(main_currency)
# Suported currencies
suported = ['MXN', 'USD']
for curr in currency_array :
for curr in currency_array:
if curr in suported:
# Get currency data
main_rate = self.rate_retrieve()
@@ -606,17 +665,19 @@ class Banxico_getter(Curreny_getter_interface) : # class added for Mexico rates
else:
rate = main_rate
else:
""" No other currency supported
"""
# No other currency supported
continue
self.updated_currency[curr] = rate
logger.debug("Rate retrieved : " + main_currency + ' = ' + str(rate) + ' ' + curr)
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"""
##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"""
@@ -643,7 +704,7 @@ class CA_BOC_getter(Curreny_getter_interface) :
self.validate_cur(curr)
# check if BOC service is running
if dom.bozo and dom.status <> 404:
if dom.bozo and dom.status != 404:
_logger.error("Bank of Canada - service is down - try again\
later...")
@@ -664,8 +725,7 @@ class CA_BOC_getter(Curreny_getter_interface) :
.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 : 1 " + main_currency +
' = ' + str(rate) + ' ' + curr)
_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)