diff --git a/currency_rate_update/README.rst b/currency_rate_update/README.rst index 5e6972ed0..51dda11f9 100644 --- a/currency_rate_update/README.rst +++ b/currency_rate_update/README.rst @@ -37,6 +37,9 @@ The module is able to use the following sources: 7. National Bank of Romania (Banca Nationala a Romaniei) +8. Joint Stock Commercial Bank for Foreign Trade of Vietnam - Vietcombank + + Configuration ============= @@ -69,8 +72,7 @@ To fix: Roadmap: * Google Finance. -* Updated daily from Citibank N.A., source in EUR. Information may be delayed. - This is parsed from an HTML page, so it may be broken at anytime. +* Updated daily from Citibank N.A., source in EUR. Information may be delayed. This is parsed from an HTML page, so it may be broken at anytime. Bug Tracker =========== @@ -105,6 +107,7 @@ Contributors * Assem Bayahi * Daniel Dico (BOC) * Dmytro Katyukha +* Lam Thai Binh (VCB) Maintainer ---------- diff --git a/currency_rate_update/models/currency_rate_update.py b/currency_rate_update/models/currency_rate_update.py index 0a825fd39..d50533e3a 100644 --- a/currency_rate_update/models/currency_rate_update.py +++ b/currency_rate_update/models/currency_rate_update.py @@ -106,7 +106,7 @@ class CurrencyRateUpdateService(models.Model): # Note fileds that will be used as a logger note = fields.Text('Update logs') max_delta_days = fields.Integer( - string='Max delta days', default=4, required=True, + default=4, required=True, help="If the time delta between the rate date given by the " "webservice and the current date exceeds this value, " "then the currency rate is not updated in Odoo.") diff --git a/currency_rate_update/services/__init__.py b/currency_rate_update/services/__init__.py index e08882d2e..1afccd016 100644 --- a/currency_rate_update/services/__init__.py +++ b/currency_rate_update/services/__init__.py @@ -6,3 +6,4 @@ from . import update_service_YAHOO from . import update_service_PL_NBP from . import update_service_MX_BdM from . import update_service_RO_BNR +from . import update_service_VN_VCB diff --git a/currency_rate_update/services/update_service_CA_BOC.py b/currency_rate_update/services/update_service_CA_BOC.py index 853adfeab..c3a4dea1b 100644 --- a/currency_rate_update/services/update_service_CA_BOC.py +++ b/currency_rate_update/services/update_service_CA_BOC.py @@ -12,7 +12,7 @@ import logging _logger = logging.getLogger(__name__) -class CA_BOCGetter(CurrencyGetterInterface): +class CaBocGetter(CurrencyGetterInterface): """Implementation of Curreny_getter_factory interface for Bank of Canada RSS service diff --git a/currency_rate_update/services/update_service_CH_ADMIN.py b/currency_rate_update/services/update_service_CH_ADMIN.py index 93e329db8..42ce8c88c 100644 --- a/currency_rate_update/services/update_service_CH_ADMIN.py +++ b/currency_rate_update/services/update_service_CH_ADMIN.py @@ -10,7 +10,7 @@ from odoo.tools import DEFAULT_SERVER_DATE_FORMAT _logger = logging.getLogger(__name__) -class CH_ADMINGetter(CurrencyGetterInterface): +class ChAdminGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for Admin.ch service. """ diff --git a/currency_rate_update/services/update_service_ECB.py b/currency_rate_update/services/update_service_ECB.py index 73ea0689d..04b4e920a 100644 --- a/currency_rate_update/services/update_service_ECB.py +++ b/currency_rate_update/services/update_service_ECB.py @@ -12,7 +12,7 @@ import logging _logger = logging.getLogger(__name__) -class ECBGetter(CurrencyGetterInterface): +class EcbGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for ECB service """ diff --git a/currency_rate_update/services/update_service_MX_BdM.py b/currency_rate_update/services/update_service_MX_BdM.py index 4d0bc30f0..591c50ce3 100644 --- a/currency_rate_update/services/update_service_MX_BdM.py +++ b/currency_rate_update/services/update_service_MX_BdM.py @@ -9,7 +9,7 @@ import logging _logger = logging.getLogger(__name__) -class MX_BdMGetter(CurrencyGetterInterface): +class MxBdmGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for Banco de México service diff --git a/currency_rate_update/services/update_service_PL_NBP.py b/currency_rate_update/services/update_service_PL_NBP.py index aabf15609..5f02715ce 100644 --- a/currency_rate_update/services/update_service_PL_NBP.py +++ b/currency_rate_update/services/update_service_PL_NBP.py @@ -12,7 +12,7 @@ import logging _logger = logging.getLogger(__name__) -class PL_NBPGetter(CurrencyGetterInterface): +class PlNbpGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for PL NBP service diff --git a/currency_rate_update/services/update_service_RO_BNR.py b/currency_rate_update/services/update_service_RO_BNR.py index 650bcb85f..4484dc5c7 100644 --- a/currency_rate_update/services/update_service_RO_BNR.py +++ b/currency_rate_update/services/update_service_RO_BNR.py @@ -11,7 +11,7 @@ import logging _logger = logging.getLogger(__name__) -class RO_BNRGetter(CurrencyGetterInterface): +class RoBnrGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for BNR service""" code = 'RO_BNR' diff --git a/currency_rate_update/services/update_service_VN_VCB.py b/currency_rate_update/services/update_service_VN_VCB.py new file mode 100644 index 000000000..dc8679280 --- /dev/null +++ b/currency_rate_update/services/update_service_VN_VCB.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# © 2017 Binh Lam +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from datetime import datetime +import logging + +from lxml import etree + +from .currency_getter_interface import CurrencyGetterInterface + +_logger = logging.getLogger(__name__) + + +class VnVcbGetter(CurrencyGetterInterface): + """Implementation of Currency_getter_factory interface for VCB service.""" + + code = 'VN_VCB' + name = 'Joint Stock Commercial Bank for Foreign ' \ + 'Trade of Vietnam - Vietcombank' + supported_currency_array = [ + "AUD", "CAD", "CHF", "DKK", "EUR", "GBP", "HKD", "INR", "JPY", "KRW", + "KWD", "MYR", "NOK", "RUB", "SAR", "SEK", "SGD", "THB", "USD", "VND"] + + def rate_retrieve(self, dom, ns, curr): + """Parse a dom node to retrieve-currencies data.""" + res = {} + xpath_curr_rate = ("/ExrateList/Exrate[@CurrencyCode='%s']/@Transfer" + % 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.vietcombank.com.vn/ExchangeRates/ExrateXML.aspx' + # we do not want to update the main currency + if main_currency in currency_array: + currency_array.remove(main_currency) + _logger.debug("VCB currency rate service : connecting...") + + rawfile = self.get_url(url) + dom = etree.fromstring(rawfile) + vcb_ns = {} # there are no namespace ! + _logger.debug("VCB sent a valid XML file") + rate_date = dom.xpath('/ExrateList/DateTime/text()', + namespaces=vcb_ns)[0] + # Don't use DEFAULT_SERVER_DATE_FORMAT here, because it's + # the format of the XML of VCB, not the format of Odoo server ! + rate_date_datetime = datetime.strptime( + str(rate_date), '%m/%d/%Y %I:%M:%S %p') + + self.check_rate_date(rate_date_datetime, max_delta_days) + # We dynamically update supported currencies + self.supported_currency_array = dom.xpath( + "/ExrateList/Exrate/@CurrencyCode", + namespaces=vcb_ns) + + self.supported_currency_array.append('VND') + _logger.debug("Supported currencies = %s " % + self.supported_currency_array) + + self.validate_cur(main_currency) + if main_currency != 'VND': + main_curr_data = self.rate_retrieve(dom, vcb_ns, main_currency) + + for curr in currency_array: + self.validate_cur(curr) + if curr == 'VND': + rate = main_curr_data['rate_currency'] + else: + curr_data = self.rate_retrieve(dom, vcb_ns, curr) + if main_currency == 'VND': + rate = 1 / curr_data['rate_currency'] + else: + rate = ( + main_curr_data['rate_currency'] / + 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_YAHOO.py b/currency_rate_update/services/update_service_YAHOO.py index 1ecde3ebe..5c0520a0b 100644 --- a/currency_rate_update/services/update_service_YAHOO.py +++ b/currency_rate_update/services/update_service_YAHOO.py @@ -5,7 +5,7 @@ from .currency_getter_interface import CurrencyGetterInterface -class YAHOOGetter(CurrencyGetterInterface): +class YahooGetter(CurrencyGetterInterface): """Implementation of Currency_getter_factory interface for Yahoo finance service """ diff --git a/currency_rate_update/tests/__init__.py b/currency_rate_update/tests/__init__.py new file mode 100644 index 000000000..433c9d382 --- /dev/null +++ b/currency_rate_update/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Author: Lam Thai Binh +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_currency_rate_update diff --git a/currency_rate_update/tests/test_currency_rate_update.py b/currency_rate_update/tests/test_currency_rate_update.py new file mode 100644 index 000000000..6b351edf9 --- /dev/null +++ b/currency_rate_update/tests/test_currency_rate_update.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +# Author: Lam Thai Binh +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import datetime +import logging + +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestCurrencyRateUpdate(TransactionCase): + + def setUp(self): + super(TestCurrencyRateUpdate, self).setUp() + self.env.user.company_id.auto_currency_up = True + self.env.user.company_id.currency_id = self.env.ref('base.EUR') + self.service_env = self.env['currency.rate.update.service'] + self.rate_env = self.env['res.currency.rate'] + + def _test_cron_by_service(self, service_code, currency_xml_ids): + """Test the ir.cron with any service for some currencies + """ + currency_ids = [ + self.env.ref(currency_xml_id).id + for currency_xml_id in currency_xml_ids] + + service_x = self.service_env.create({ + 'service': service_code, + 'currency_to_update': [(6, 0, currency_ids)] + }) + + rate_name = \ + fields.Datetime.to_string(datetime.datetime.utcnow().replace( + hour=0, minute=0, second=0, microsecond=0)) + for currency_id in currency_ids: + rates = self.rate_env.search([ + ('currency_id', '=', currency_id), + ('company_id', '=', self.env.user.company_id.id), + ('name', '=', rate_name)]) + rates.unlink() + self.service_env._run_currency_update() + logging.info("Service note: %s", service_x.note) + self.assertFalse('ERROR' in service_x.note) + + # FIXME: except_orm(u'Error !', u'Exchange data for USD is not reported + # by Bank of Canada.') + # def test_cron_CA_BOC(self): + # """Test the ir.cron with Bank of Canada service for USD + # """ + # self._test_cron_by_service('CA_BOC', ['base.USD']) + + def test_cron_CH_ADMIN(self): + """Test the ir.cron with Admin.ch service for USD + """ + self._test_cron_by_service('CH_ADMIN', ['base.USD']) + + def test_cron_ECB(self): + """Test the ir.cron with European Central Bank service for USD + """ + self._test_cron_by_service('ECB', ['base.USD']) + + def test_cron_MX_BdM(self): + """Test the ir.cron with Bank of Mexico service for USD + """ + self._test_cron_by_service('MX_BdM', ['base.USD']) + + def test_cron_PL_NBP(self): + """Test the ir.cron with National Bank of Poland service for USD + """ + self._test_cron_by_service('PL_NBP', ['base.USD']) + + def test_cron_RO_BNR(self): + """Test the ir.cron with National Bank of Romania service for USD + """ + self._test_cron_by_service('RO_BNR', ['base.USD']) + + def test_cron_VN_VCB(self): + """Test the ir.cron with Vietcombank service for USD + """ + self._test_cron_by_service('VN_VCB', ['base.USD'])