mirror of
https://github.com/OCA/account-financial-tools.git
synced 2025-02-02 12:47:26 +02:00
221 lines
9.1 KiB
Python
221 lines
9.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# © 2009-2016 Camptocamp
|
|
# © 2010 Akretion
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
|
|
import logging
|
|
|
|
from datetime import datetime, time
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import models, fields, api, _
|
|
from odoo.exceptions import UserError, ValidationError
|
|
from odoo.tools import float_compare
|
|
|
|
|
|
from ..services.currency_getter_interface import CurrencyGetterType
|
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
_intervalTypes = {
|
|
'days': lambda interval: relativedelta(days=interval),
|
|
'weeks': lambda interval: relativedelta(days=7*interval),
|
|
'months': lambda interval: relativedelta(months=interval),
|
|
}
|
|
|
|
|
|
class CurrencyRateUpdateService(models.Model):
|
|
"""Class keep services and currencies that
|
|
have to be updated"""
|
|
_name = "currency.rate.update.service"
|
|
_description = "Currency Rate Update"
|
|
_rec_name = "service"
|
|
|
|
@api.multi
|
|
@api.constrains('max_delta_days')
|
|
def _check_max_delta_days(self):
|
|
for srv in self:
|
|
if srv.max_delta_days < 0:
|
|
raise ValidationError(_(
|
|
'Max delta days must be >= 0'))
|
|
|
|
@api.multi
|
|
@api.constrains('interval_number')
|
|
def _check_interval_number(self):
|
|
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):
|
|
if self.interval_number == 0:
|
|
self.note = '%s Service deactivated. Currencies will no longer ' \
|
|
'be updated. \n%s' % (fields.Datetime.now(),
|
|
self.note and self.note or '')
|
|
|
|
@api.onchange('service')
|
|
def _onchange_service(self):
|
|
currency_list = ''
|
|
res = {'domain': {
|
|
'currency_to_update': "[('id', '=', False)]",
|
|
}}
|
|
if self.service:
|
|
currencies = []
|
|
getter = CurrencyGetterType.get(self.service)
|
|
currency_list = getter.supported_currency_array
|
|
currencies = self.env['res.currency'].search(
|
|
[('name', 'in', currency_list)])
|
|
currency_list = [(6, 0, currencies.ids)]
|
|
res['domain']['currency_to_update'] =\
|
|
"[('id', 'in', %s)]" % currencies.ids
|
|
self.currency_list = currency_list
|
|
return res
|
|
|
|
def _selection_service(self, *a, **k):
|
|
res = [(x.code, x.name) for x in CurrencyGetterType.getters.values()]
|
|
return res
|
|
|
|
# List of webservicies the value sould be a class name
|
|
service = fields.Selection(
|
|
_selection_service,
|
|
string="Webservice to use",
|
|
required=True)
|
|
# List of currencies available on webservice
|
|
currency_list = fields.Many2many('res.currency',
|
|
'res_currency_update_avail_rel',
|
|
'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',
|
|
'service_id',
|
|
'currency_id',
|
|
string='Currencies to update with '
|
|
'this service')
|
|
# Link with company
|
|
company_id = fields.Many2one(
|
|
'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
|
|
note = fields.Text('Update logs')
|
|
max_delta_days = fields.Integer(
|
|
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 Odoo.")
|
|
interval_type = fields.Selection([
|
|
('days', 'Day(s)'),
|
|
('weeks', 'Week(s)'),
|
|
('months', 'Month(s)')],
|
|
string='Currency update frequency',
|
|
default='days')
|
|
interval_number = fields.Integer(string='Frequency', default=1)
|
|
next_run = fields.Date(string='Next run on', default=fields.Date.today())
|
|
|
|
_sql_constraints = [('curr_service_unique',
|
|
'unique (service, company_id)',
|
|
_('You can use a service only one time per '
|
|
'company !'))]
|
|
|
|
@api.multi
|
|
def refresh_currency(self):
|
|
"""Refresh the currencies rates !!for all companies now"""
|
|
rate_obj = self.env['res.currency.rate']
|
|
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
|
|
rates = rate_obj.search([
|
|
('currency_id', '=', curr.id),
|
|
('company_id', '=', company.id),
|
|
('name', '=', rate_name)])
|
|
if not rates:
|
|
vals = {
|
|
'currency_id': curr.id,
|
|
'rate': res[curr.name],
|
|
'name': rate_name,
|
|
'company_id': company.id,
|
|
}
|
|
rate_obj.create(vals)
|
|
_logger.info(
|
|
'Updated currency %s via service %s '
|
|
'in company %s',
|
|
curr.name, srv.service, company.name)
|
|
|
|
# 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
|
|
def run_currency_update(self):
|
|
# Update currency at the given frequence
|
|
services = self.search([('next_run', '=', fields.Date.today())])
|
|
services.with_context(cron=True).refresh_currency()
|
|
|
|
@api.model
|
|
def _run_currency_update(self):
|
|
_logger.info('Starting the currency rate update cron')
|
|
self.run_currency_update()
|
|
_logger.info('End of the currency rate update cron')
|