Files
odoo_source/addons/account/models/account_payment_method.py
T
Nicolas (vin) 66e0e4086b [FIX] account_*: payment method journal filter
Fix two issues linked to payment methods and their journal link.

SEPA Credit Transfer was marked as only available on EUR journals, but
from what we have been told, and we have seen, it should also be made
available for other currencies (CHF/SEK).
So we are changing the rule used to determine if SEPA Credit Transfer
is available on a journal to allow to use it on journals using CHF or
SEK as a currency.

There is another issue, where the filtering is done differently at the
journal creation and when the user add the payment method manually in
the lists.
The filter rules were not respected at the journal creation, which
would lead to incorrect default inbound and outbound payment method list.
For example, a new journal would have the company currency (let's say,
USD) but still have SEPA Credit Transfer (EUR,CHF,SEK) added on it by
default while it should not be available there.

opw-2777522

X-original-commit: 0ad8faf3bfc7b28e5668c3445fcc06c24ad98354
[FIX] account_*: payment method journal filter

Fix two issues linked to payment methods and their journal link.

SEPA Credit Transfer was marked as only available on EUR journals, but
from what we have been told, and we have seen, it should also be made
available for other currencies (CHF/SEK).
So we are changing the rule used to determine if SEPA Credit Transfer
is available on a journal to allow to use it on journals using CHF or
SEK as a currency.

There is another issue, where the filtering is done differently at the
journal creation and when the user add the payment method manually in
the lists.
The filter rules were not respected at the journal creation, which
would lead to incorrect default inbound and outbound payment method list.
For example, a new journal would have the company currency (let's say,
USD) but still have SEPA Credit Transfer (EUR,CHF,SEK) added on it by
default while it should not be available there.

opw-2777522

closes odoo/odoo#88677

X-original-commit: e2cd91ad8339f73b2547bc839e675443528f3adf
Related: odoo/enterprise#26172
Signed-off-by: Florian Gilbert <flg@odoo.com>
2022-04-14 15:11:27 +02:00

177 lines
7.2 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.osv import expression
from odoo.exceptions import UserError
class AccountPaymentMethod(models.Model):
_name = "account.payment.method"
_description = "Payment Methods"
name = fields.Char(required=True, translate=True)
code = fields.Char(required=True) # For internal identification
payment_type = fields.Selection(selection=[('inbound', 'Inbound'), ('outbound', 'Outbound')], required=True)
_sql_constraints = [
('name_code_unique', 'unique (code, payment_type)', 'The combination code/payment type already exists!'),
]
@api.model_create_multi
def create(self, vals_list):
payment_methods = super().create(vals_list)
methods_info = self._get_payment_method_information()
for method in payment_methods:
information = methods_info.get(method.code)
if information.get('mode') == 'multi':
method_domain = method._get_payment_method_domain(method.code)
journals = self.env['account.journal'].search(method_domain)
self.env['account.payment.method.line'].create([{
'name': method.name,
'payment_method_id': method.id,
'journal_id': journal.id
} for journal in journals])
return payment_methods
@api.model
def _get_payment_method_domain(self, code):
"""
:return: The domain specyfying which journal can accomodate this payment method.
"""
if not code:
return []
information = self._get_payment_method_information().get(code)
currency_ids = information.get('currency_ids')
country_id = information.get('country_id')
default_domain = [('type', 'in', ('bank', 'cash'))]
domains = [information.get('domain', default_domain)]
if currency_ids:
domains += [expression.OR([
[('currency_id', '=', False), ('company_id.currency_id', 'in', currency_ids)],
[('currency_id', 'in', currency_ids)]],
)]
if country_id:
domains += [[('company_id.account_fiscal_country_id', '=', country_id)]]
return expression.AND(domains)
@api.model
def _get_payment_method_information(self):
"""
Contains details about how to initialize a payment method with the code x.
The contained info are:
mode: Either unique if we only want one of them at a single time (payment acquirers for example)
or multi if we want the method on each journal fitting the domain.
domain: The domain defining the eligible journals.
currency_id: The id of the currency necessary on the journal (or company) for it to be eligible.
country_id: The id of the country needed on the company for it to be eligible.
hidden: If set to true, the method will not be automatically added to the journal,
and will not be selectable by the user.
"""
return {
'manual': {'mode': 'multi', 'domain': [('type', 'in', ('bank', 'cash'))]},
}
class AccountPaymentMethodLine(models.Model):
_name = "account.payment.method.line"
_description = "Payment Methods"
_order = 'sequence, id'
# == Business fields ==
name = fields.Char(compute='_compute_name', readonly=False, store=True)
sequence = fields.Integer(default=10)
payment_method_id = fields.Many2one(
string='Payment Method',
comodel_name='account.payment.method',
domain="[('payment_type', '=?', payment_type), ('id', 'in', available_payment_method_ids)]",
required=True
)
payment_account_id = fields.Many2one(
comodel_name='account.account',
check_company=True,
copy=False,
ondelete='restrict',
domain=lambda self: "[('deprecated', '=', False), "
"('company_id', '=', company_id), "
"('user_type_id.type', 'not in', ('receivable', 'payable')), "
"'|', ('user_type_id', '=', %s), ('id', '=', parent.default_account_id)]"
% self.env.ref('account.data_account_type_current_assets').id
)
journal_id = fields.Many2one(comodel_name='account.journal', ondelete="cascade")
# == Display purpose fields ==
code = fields.Char(related='payment_method_id.code')
payment_type = fields.Selection(related='payment_method_id.payment_type')
company_id = fields.Many2one(related='journal_id.company_id')
available_payment_method_ids = fields.Many2many(related='journal_id.available_payment_method_ids')
@api.depends('payment_method_id.name')
def _compute_name(self):
for method in self:
if not method.name:
method.name = method.payment_method_id.name
@api.constrains('name')
def _ensure_unique_name_for_journal(self):
self.flush(['name'])
self._cr.execute('''
SELECT apml.name, apm.payment_type
FROM account_payment_method_line apml
JOIN account_payment_method apm ON apml.payment_method_id = apm.id
WHERE apml.journal_id IS NOT NULL
GROUP BY apml.name, journal_id, apm.payment_type
HAVING count(apml.id) > 1
''')
res = self._cr.fetchall()
if res:
(name, payment_type) = res[0]
raise UserError(_("You can't have two payment method lines of the same payment type (%s) "
"and with the same name (%s) on a single journal.", payment_type, name))
def unlink(self):
"""
Payment method lines which are used in a payment should not be deleted from the database,
only the link betweend them and the journals must be broken.
"""
unused_payment_method_lines = self
for line in self:
payment_count = self.env['account.payment'].search_count([('payment_method_line_id', '=', line.id)])
if payment_count > 0:
unused_payment_method_lines -= line
(self - unused_payment_method_lines).write({'journal_id': False})
return super(AccountPaymentMethodLine, unused_payment_method_lines).unlink()
@api.model
def _auto_toggle_account_to_reconcile(self, account_id):
""" Automatically toggle the account to reconcile if allowed.
:param account_id: The id of an account.account.
"""
account = self.env['account.account'].browse(account_id)
if not account.reconcile and account.internal_type != 'liquidity' and account.internal_group != 'off_balance':
account.reconcile = True
@api.model_create_multi
def create(self, vals_list):
# OVERRIDE
for vals in vals_list:
if vals.get('payment_account_id'):
self._auto_toggle_account_to_reconcile(vals['payment_account_id'])
return super().create(vals_list)
def write(self, vals):
# OVERRIDE
if vals.get('payment_account_id'):
self._auto_toggle_account_to_reconcile(vals['payment_account_id'])
return super().write(vals)