Merge pull request #504 from binhlam/add_VCB_service

Add service update VCB exchange rates
This commit is contained in:
Stefan Rijnhart (Opener)
2017-11-23 12:09:38 +01:00
committed by GitHub
13 changed files with 188 additions and 10 deletions

View File

@@ -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 <ddico@oerp.ca> (BOC)
* Dmytro Katyukha <firemage.dima@gmail.com>
* Lam Thai Binh <binh.lt@komit-consulting.com> (VCB)
Maintainer
----------

View File

@@ -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.")

View File

@@ -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

View File

@@ -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

View File

@@ -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.
"""

View File

@@ -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
"""

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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
"""

View File

@@ -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

View File

@@ -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'])