Update to latest OCA conventions

Update README
Code cleanup: remove @api.one, better error messages, remove call to MOD_NAME which was not defined any more
Use account.menu_config_multi_currency as parent menu
This commit is contained in:
Alexis de Lattre
2016-12-05 22:08:52 +01:00
parent 39c116a7e9
commit 1017ce3b4c
18 changed files with 267 additions and 237 deletions

View File

@@ -1,10 +1,12 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
====================
Currency Rate Update
====================
Import exchange rates from the Internet.
Download exchange rates automatically from the Internet.
The module is able to use the following sources:
@@ -38,13 +40,11 @@ The module is able to use the following sources:
Configuration
=============
The update can be set under the company form.
You can set for each services which currency you want to update.
The logs of the update are visible under the service note.
You can active or deactivate the update.
The module uses internal ir-cron feature from Odoo, so the job is
launched once the server starts if the 'first execute date' is before
the current day.
To configure the module, go to *Accounting > Configuration > Multi-currencies > Rate Auto-download* and create one or several services to download rates from the Internet.
Then, go to the page *Accounting > Configuration > Settings* and, in the section *Multi Currencies*, make sure that the option *Automatic Currency Rates Download* is enabled.
In developper mode, in the menu *Settings > Technical > Scheduled Actions*, make sure that the action *Currency Rate Update* is active. If you want to run it immediately, use the button *Run Manually*.
Usage
=====
@@ -72,7 +72,6 @@ Roadmap:
* 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
===========
@@ -80,7 +79,6 @@ Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-too
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
@@ -108,13 +106,12 @@ Contributors
* Daniel Dico <ddico@oerp.ca> (BOC)
* Dmytro Katyukha <firemage.dima@gmail.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
:target: https://odoo-community.org
This module is maintained by the OCA.
@@ -122,4 +119,4 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.
To contribute to this module, please visit https://odoo-community.org.

View File

@@ -1,2 +1,4 @@
from . import model
# -*- coding: utf-8 -*-
from . import models
from .services.currency_getter_interface import CurrencyGetterInterface

View File

@@ -13,13 +13,11 @@
"account", # Added to ensure account security groups are present
],
"data": [
"view/service_cron_data.xml",
"view/currency_rate_update.xml",
"view/company_view.xml",
"data/cron.xml",
"views/currency_rate_update.xml",
"views/account_config_settings.xml",
"security/rule.xml",
"security/ir.model.access.csv",
],
"images": [],
"demo": [],
'installable': True
}

View File

@@ -1,2 +0,0 @@
from . import currency_rate_update
from . import company

View File

@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# © 2009-2016 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
class ResCompany(models.Model):
"""override company to add currency update"""
_inherit = "res.company"
@api.multi
def button_refresh_currency(self):
"""Refresh the currencies rates"""
self.ensure_one()
self.services_to_use.refresh_currency()
# Activate the currency update
auto_currency_up = fields.Boolean(
string='Automatic Update',
help="Automatic update of the currencies for this company")
# List of services to fetch rates
services_to_use = fields.One2many(
'currency.rate.update.service',
'company_id',
string='Currency update services')

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import currency_rate_update
from . import company
from . import account_config_settings

View File

@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields
class AccountConfigSettings(models.TransientModel):
_inherit = 'account.config.settings'
auto_currency_up = fields.Boolean(
related='company_id.auto_currency_up')

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# © 2009-2016 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class ResCompany(models.Model):
_inherit = "res.company"
# Activate the currency update
auto_currency_up = fields.Boolean(
string='Automatic Currency Rates Download', default=True,
help="Automatic download of currency rates for this company")

View File

@@ -9,7 +9,9 @@ from datetime import datetime, time
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, _
from odoo import exceptions
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare
from ..services.currency_getter_interface import CurrencyGetterType
@@ -29,17 +31,20 @@ class CurrencyRateUpdateService(models.Model):
_name = "currency.rate.update.service"
_description = "Currency Rate Update"
@api.one
@api.multi
@api.constrains('max_delta_days')
def _check_max_delta_days(self):
if self.max_delta_days < 0:
raise exceptions.Warning(_('Max delta days must be >= 0'))
for srv in self:
if srv.max_delta_days < 0:
raise ValidationError(_(
'Max delta days must be >= 0'))
@api.one
@api.multi
@api.constrains('interval_number')
def _check_interval_number(self):
if self.interval_number < 0:
raise exceptions.Warning(_('Interval number must be >= 0'))
for srv in self:
if srv.interval_number < 0:
raise ValidationError(_('Interval number must be >= 0'))
@api.onchange('interval_number')
def _onchange_interval_number(self):
@@ -74,6 +79,10 @@ class CurrencyRateUpdateService(models.Model):
'service_id',
'currency_id',
string='Currencies available')
# I can't just put readonly=True in the field above because I need
# it as r+w for the on_change to work
currency_list_readonly = fields.Many2many(
related='currency_list', readonly=True)
# List of currency to update
currency_to_update = fields.Many2many('res.currency',
'res_currency_auto_update_rel',
@@ -83,7 +92,7 @@ class CurrencyRateUpdateService(models.Model):
'this service')
# Link with company
company_id = fields.Many2one(
'res.company', 'Company',
'res.company', 'Company', required=True,
default=lambda self: self.env['res.company']._company_default_get(
'currency.rate.update.service'))
# Note fileds that will be used as a logger
@@ -92,7 +101,7 @@ class CurrencyRateUpdateService(models.Model):
string='Max delta days', 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 OpenERP.")
"then the currency rate is not updated in Odoo.")
interval_type = fields.Selection([
('days', 'Day(s)'),
('weeks', 'Week(s)'),
@@ -107,81 +116,87 @@ class CurrencyRateUpdateService(models.Model):
_('You can use a service only one time per '
'company !'))]
@api.one
@api.multi
def refresh_currency(self):
"""Refresh the currencies rates !!for all companies now"""
_logger.info(
'Starting to refresh currencies with service %s (company: %s)',
self.service, self.company_id.name)
rate_obj = self.env['res.currency.rate']
company = self.company_id
# The multi company currency can be set or no so we handle
# The two case
if company.auto_currency_up:
main_currency = self.company_id.currency_id
if not main_currency:
raise exceptions.Warning(_('There is no main '
'currency defined!'))
if main_currency.rate != 1:
raise exceptions.Warning(_('Base currency rate should '
'be 1.00!'))
note = self.note or ''
try:
# We initalize the class that will handle the request
# and return a dict of rate
getter = CurrencyGetterType.get(self.service)
curr_to_fetch = [x.name for x in self.currency_to_update]
res, log_info = getter.get_updated_currency(
curr_to_fetch,
main_currency.name,
self.max_delta_days
)
rate_name = \
fields.Datetime.to_string(datetime.utcnow().replace(
hour=0, minute=0, second=0, microsecond=0))
for curr in self.currency_to_update:
if curr.id == main_currency.id:
continue
do_create = True
for rate in curr.rate_ids:
if rate.name == rate_name:
rate.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(vals)
_logger.info(
'Updated currency %s via service %s',
curr.name, self.service)
for srv in self:
_logger.info(
'Starting to refresh currencies with service %s (company: %s)',
srv.service, srv.company_id.name)
company = srv.company_id
# The multi company currency can be set or no so we handle
# The two case
if company.auto_currency_up:
main_currency = company.currency_id
# No need to test if main_currency exists, because it is a
# required field
if float_compare(
main_currency.rate, 1,
precision_rounding=main_currency.rounding):
raise UserError(_(
"In company '%s', the rate of the main currency (%s) "
"must be 1.00 (current rate: %s).") % (
company.name,
main_currency.name,
main_currency.rate))
note = srv.note or ''
try:
# We initalize the class that will handle the request
# and return a dict of rate
getter = CurrencyGetterType.get(srv.service)
curr_to_fetch = [x.name for x in srv.currency_to_update]
res, log_info = getter.get_updated_currency(
curr_to_fetch,
main_currency.name,
srv.max_delta_days
)
rate_name = \
fields.Datetime.to_string(datetime.utcnow().replace(
hour=0, minute=0, second=0, microsecond=0))
for curr in srv.currency_to_update:
if curr == main_currency:
continue
do_create = True
for rate in curr.rate_ids:
if rate.name == rate_name:
rate.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(vals)
_logger.info(
'Updated currency %s via service %s',
curr.name, srv.service)
# Show the most recent note at the top
msg = '%s \n%s currency updated. %s' % (
log_info or '',
fields.Datetime.to_string(datetime.today()),
note
)
self.write({'note': msg})
except Exception as exc:
error_msg = '\n%s ERROR : %s %s' % (
fields.Datetime.to_string(datetime.today()),
repr(exc),
note
)
_logger.error(repr(exc))
self.write({'note': error_msg})
if self._context.get('cron', False):
midnight = time(0, 0)
next_run = (datetime.combine(
fields.Date.from_string(self.next_run),
midnight) +
_intervalTypes[str(self.interval_type)]
(self.interval_number)).date()
self.next_run = next_run
# Show the most recent note at the top
msg = '%s \n%s currency updated. %s' % (
log_info or '',
fields.Datetime.to_string(datetime.today()),
note
)
srv.write({'note': msg})
except Exception as exc:
error_msg = '\n%s ERROR: %s %s' % (
fields.Datetime.to_string(datetime.today()),
repr(exc),
note
)
_logger.error(repr(exc))
srv.write({'note': error_msg})
if self._context.get('cron'):
midnight = time(0, 0)
next_run = (datetime.combine(
fields.Date.from_string(srv.next_run),
midnight) +
_intervalTypes[str(srv.interval_type)]
(srv.interval_number)).date()
srv.next_run = next_run
return True
@api.multi

View File

@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<odoo noupdate="1">
<record id="currency_rate_update_service_multicompany_rule" model="ir.rule">
<field name="name">Current Rate Update Service multi-company</field>
<field name="model_id" ref="model_currency_rate_update_service"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</data>
</odoo>

View File

@@ -5,8 +5,8 @@
import logging
from datetime import datetime
from odoo import fields
from odoo.exceptions import except_orm
from odoo import fields, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
@@ -143,15 +143,11 @@ class CurrencyGetterInterface(object):
objfile.close()
return rawfile
except ImportError:
raise except_orm(
'Error !',
self.MOD_NAME + 'Unable to import urllib !'
)
raise UserError(
_('Unable to import urllib.'))
except IOError:
raise except_orm(
'Error !',
self.MOD_NAME + 'Web Service does not exist !'
)
raise UserError(
_('Web Service does not exist (%s)!') % url)
def check_rate_date(self, rate_date, max_delta_days):
"""Check date constrains. rate_date must be of datetime type"""
@@ -160,9 +156,9 @@ class CurrencyGetterInterface(object):
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)
'Rate not updated in Odoo.' % (rate_date,
days_delta,
max_delta_days)
)
# We always have a warning when rate_date != today

View File

@@ -6,7 +6,7 @@
from .currency_getter_interface import CurrencyGetterInterface
from datetime import datetime
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from lxml import etree
import logging
_logger = logging.getLogger(__name__)
@@ -49,8 +49,6 @@ class ECBGetter(CurrencyGetterInterface):
# 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)
@@ -61,8 +59,9 @@ class ECBGetter(CurrencyGetterInterface):
}
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)
# Don't use DEFAULT_SERVER_DATE_FORMAT here, because it's
# the format of the XML of ECB, not the format of Odoo server !
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(

View File

@@ -1,22 +0,0 @@
<odoo>
<data>
<record model="ir.ui.view" id="currency_auto_comp">
<field name="name">res.company.form.inherit</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Currency update configuration">
<group>
<field name="auto_currency_up"/>
</group>
<separator string="Currency update services" colspan="4"/>
<field name="services_to_use" colspan="4" nolabel="1"/>
<button name="button_refresh_currency" string="Refresh currencies" type='object' />
</page>
</notebook>
</field>
</record>
</data>
</odoo>

View File

@@ -1,63 +0,0 @@
<?xml version="1.0"?>
<odoo>
<data>
<record model="ir.ui.view" id="currency_rate_update_tree">
<field name="name">Update Rates service</field>
<field name="model">currency.rate.update.service</field>
<field name="arch" type="xml">
<tree string="Currency update services">
<field name="service"/>
<field name="company_id" groups="base.group_multi_company"
invisible="not context.get('currency_rate_update_main_view')"/>
<field name="currency_to_update"/>
<field name="interval_type"/>
<field name="interval_number"/>
<field name="next_run"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="currency_rate_update_form">
<field name="name">Update Rates</field>
<field name="model">currency.rate.update.service</field>
<field name="arch" type="xml">
<form string="Currency update services">
<group name="main">
<group name="left">
<field name="service"/>
<field name="company_id" groups="base.group_multi_company"
invisible="not context.get('currency_rate_update_main_view')"
required="context.get('currency_rate_update_main_view')"/>
<field name="max_delta_days"/>
<button name="refresh_currency" type="object"
string="Update now!"/>
</group>
<group name="right">
<field name="interval_type"/>
<field name="interval_number"/>
<field name="next_run"/>
</group>
</group>
<group string="Currencies to update with this service">
<field name="currency_list" invisible="1"/>
<field name="currency_to_update" nolabel="1" domain="[('id','in', currency_list[0][2])]"/>
</group>
<group string="Logs" name="logs">
<field name="note" nolabel="1"/>
</group>
</form>
</field>
</record>
<record id="currency_rate_update_action" model="ir.actions.act_window">
<field name="name">Currency Rate Update</field>
<field name="res_model">currency.rate.update.service</field>
<field name="view_mode">tree,form</field>
<field name="context">{'currency_rate_update_main_view': True}</field>
</record>
<menuitem id="currency_rate_update_menu" action="currency_rate_update_action"
parent="account.menu_finance_configuration" sequence="21"/>
</data>
</odoo>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_config_settings" model="ir.ui.view">
<field name="name">currency_rate_update.account_config_settings.form</field>
<field name="model">account.config.settings</field>
<field name="inherit_id" ref="account.view_account_config_settings"/>
<field name="arch" type="xml">
<group name="multi_currency" position="after">
<group name="currency_rate_update">
<label for="id" string="Auto-download Rates"/>
<div name="currency_rate_update">
<field name="auto_currency_up" class="oe_inline"/>
<label for="auto_currency_up"/>
</div>
</group>
</group>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="currency_auto_comp">
<field name="name">currency_rate_update.res.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Currency update configuration">
<group>
<field name="auto_currency_up"/>
</group>
<separator string="Currency update services" colspan="4"/>
<field name="services_to_use" colspan="4" nolabel="1"/>
<button name="button_refresh_currency" string="Refresh currencies" type="object" />
</page>
</notebook>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="currency_rate_update_tree">
<field name="name">Update Rates service</field>
<field name="model">currency.rate.update.service</field>
<field name="arch" type="xml">
<tree string="Currency update services">
<field name="service"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="currency_to_update"/>
<field name="interval_type"/>
<field name="interval_number"/>
<field name="next_run"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="currency_rate_update_form">
<field name="name">Update Rates</field>
<field name="model">currency.rate.update.service</field>
<field name="arch" type="xml">
<form string="Currency update services">
<header>
<button name="refresh_currency" type="object"
string="Update now"/>
</header>
<group name="main">
<group name="left">
<field name="service"/>
<field name="currency_list_readonly" widget="many2many_tags"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group name="right">
<field name="interval_type"/>
<field name="interval_number"/>
<field name="next_run"/>
<field name="max_delta_days"/>
</group>
</group>
<group string="Currencies to update with this service" name="currencies">
<!-- I need to have currency_list as r+w for the on_change -->
<field name="currency_list" invisible="1"/>
<field name="currency_to_update" nolabel="1" domain="[('id','in', currency_list[0][2])]"/>
</group>
<group string="Logs" name="logs">
<field name="note" nolabel="1"/>
</group>
</form>
</field>
</record>
<record id="currency_rate_update_action" model="ir.actions.act_window">
<field name="name">Rate Auto-download</field>
<field name="res_model">currency.rate.update.service</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="currency_rate_update_menu" action="currency_rate_update_action"
parent="account.menu_config_multi_currency" sequence="30"/>
</odoo>