From 04522f01e6fdbf82a657b32b312449fd7d756f79 Mon Sep 17 00:00:00 2001 From: "Nicolas (vin)" Date: Wed, 2 Jun 2021 14:59:27 +0000 Subject: [PATCH] [IMP] account: allows multiple payment acquirers on a journal. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users may want to be able to have transactions coming from multiple payment acquirers to be registered in the same journal. This will allows that. Task id #2414749 closes odoo/odoo#67331 Related: odoo/upgrade#2500 Related: odoo/enterprise#17258 Signed-off-by: William André (wan) --- addons/account/models/account_account.py | 69 ++++- .../account/models/account_bank_statement.py | 5 +- addons/account/models/account_journal.py | 268 ++++++++++++------ addons/account/models/account_payment.py | 70 +++-- .../account/models/account_payment_method.py | 114 +++++++- addons/account/security/ir.model.access.csv | 2 + addons/account/tests/common.py | 12 +- addons/account/tests/test_account_account.py | 4 +- .../tests/test_account_bank_statement.py | 2 +- addons/account/tests/test_account_journal.py | 49 ++++ addons/account/tests/test_account_payment.py | 16 +- .../tests/test_account_payment_register.py | 70 ++--- addons/account/tests/test_reconciliation.py | 18 +- .../test_reconciliation_matching_rules.py | 4 +- .../account/views/account_journal_views.xml | 51 ++-- addons/account/views/account_payment_view.xml | 6 +- .../wizard/account_payment_register.py | 34 +-- .../wizard/account_payment_register_views.xml | 4 +- addons/account_check_printing/__init__.py | 7 +- addons/account_check_printing/__manifest__.py | 1 + .../data/account_check_printing_data.xml | 4 - .../account_check_printing/models/__init__.py | 1 + .../models/account_journal.py | 41 +-- .../models/account_payment.py | 3 +- .../models/account_payment_method.py | 14 + .../tests/test_print_check.py | 7 - .../views/account_journal_views.xml | 5 +- addons/hr_expense/tests/test_expenses.py | 2 +- addons/l10n_in/demo/account_payment_demo.xml | 4 +- addons/payment/__manifest__.py | 1 - addons/payment/data/account_data.xml | 10 - addons/payment/models/__init__.py | 2 +- .../payment/models/account_chart_template.py | 13 - addons/payment/models/account_journal.py | 32 +++ addons/payment/models/account_payment.py | 45 ++- addons/payment/models/payment_acquirer.py | 149 ++-------- addons/payment/models/payment_transaction.py | 3 +- addons/payment/tests/common.py | 17 +- .../payment/views/account_payment_views.xml | 7 +- .../wizards/account_payment_register.py | 52 ++-- .../account_payment_register_views.xml | 5 +- addons/payment_adyen/__init__.py | 1 - addons/payment_adyen/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_adyen/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_adyen/models/payment_acquirer.py | 6 + addons/payment_alipay/__init__.py | 1 - addons/payment_alipay/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_alipay/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_alipay/models/payment_acquirer.py | 6 + addons/payment_authorize/__init__.py | 1 - addons/payment_authorize/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_authorize/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../models/payment_acquirer.py | 6 + addons/payment_buckaroo/__init__.py | 1 - addons/payment_buckaroo/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_buckaroo/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../models/payment_acquirer.py | 6 + addons/payment_odoo/__init__.py | 1 - addons/payment_odoo/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_odoo/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_odoo/models/payment_acquirer.py | 6 + addons/payment_ogone/__init__.py | 1 - addons/payment_ogone/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_ogone/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_ogone/models/payment_acquirer.py | 6 + addons/payment_paypal/__init__.py | 1 - addons/payment_paypal/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_paypal/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_paypal/models/payment_acquirer.py | 6 + addons/payment_payulatam/__init__.py | 1 - addons/payment_payulatam/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_payulatam/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../models/payment_acquirer.py | 6 + addons/payment_payumoney/__init__.py | 1 - addons/payment_payumoney/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_payumoney/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../models/payment_acquirer.py | 6 + addons/payment_sips/__init__.py | 1 - addons/payment_sips/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_sips/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_sips/models/payment_acquirer.py | 6 + addons/payment_stripe/__init__.py | 1 - addons/payment_stripe/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 6 + addons/payment_stripe/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_stripe/models/payment_acquirer.py | 6 + addons/payment_test/__init__.py | 1 - addons/payment_test/__manifest__.py | 1 - .../data/payment_acquirer_data.xml | 7 +- addons/payment_test/models/__init__.py | 1 + .../models/account_payment_method.py | 14 + .../payment_test/models/payment_acquirer.py | 6 + addons/payment_transfer/__init__.py | 1 - addons/payment_transfer/__manifest__.py | 1 - .../models/payment_acquirer.py | 21 -- .../payment_transfer/views/payment_views.xml | 5 + .../security/ir.model.access.csv | 1 + .../tests/test_ui_wslides.py | 5 +- 119 files changed, 1078 insertions(+), 528 deletions(-) create mode 100644 addons/account_check_printing/models/account_payment_method.py delete mode 100644 addons/payment/data/account_data.xml delete mode 100644 addons/payment/models/account_chart_template.py create mode 100644 addons/payment/models/account_journal.py create mode 100644 addons/payment_adyen/models/account_payment_method.py create mode 100644 addons/payment_alipay/models/account_payment_method.py create mode 100644 addons/payment_authorize/models/account_payment_method.py create mode 100644 addons/payment_buckaroo/models/account_payment_method.py create mode 100644 addons/payment_odoo/models/account_payment_method.py create mode 100644 addons/payment_ogone/models/account_payment_method.py create mode 100644 addons/payment_paypal/models/account_payment_method.py create mode 100644 addons/payment_payulatam/models/account_payment_method.py create mode 100644 addons/payment_payumoney/models/account_payment_method.py create mode 100644 addons/payment_sips/models/account_payment_method.py create mode 100644 addons/payment_stripe/models/account_payment_method.py create mode 100644 addons/payment_test/models/account_payment_method.py diff --git a/addons/account/models/account_account.py b/addons/account/models/account_account.py index 3c88a40b811..d6720791080 100644 --- a/addons/account/models/account_account.py +++ b/addons/account/models/account_account.py @@ -131,22 +131,57 @@ class AccountAccount(models.Model): self.env['account.journal'].flush([ 'currency_id', 'default_account_id', - 'payment_debit_account_id', - 'payment_credit_account_id', 'suspense_account_id', ]) + self.env['account.payment.method'].flush(['payment_type']) + self.env['account.payment.method.line'].flush(['payment_method_id', 'payment_account_id']) + self._cr.execute(''' - SELECT account.id, journal.id - FROM account_account account - JOIN res_company company ON company.id = account.company_id - JOIN account_journal journal ON - journal.default_account_id = account.id - WHERE account.id IN %s - AND journal.type IN ('bank', 'cash') - AND journal.currency_id IS NOT NULL + SELECT + account.id, + journal.id + FROM account_journal journal + JOIN res_company company ON company.id = journal.company_id + JOIN account_account account ON account.id = journal.default_account_id + WHERE journal.currency_id IS NOT NULL AND journal.currency_id != company.currency_id AND account.currency_id != journal.currency_id - ''', [tuple(self.ids)]) + AND account.id IN %(accounts)s + + UNION ALL + + SELECT + account.id, + journal.id + FROM account_journal journal + JOIN res_company company ON company.id = journal.company_id + JOIN account_payment_method_line apml ON apml.journal_id = journal.id + JOIN account_payment_method apm on apm.id = apml.payment_method_id + JOIN account_account account ON account.id = COALESCE(apml.payment_account_id, company.account_journal_payment_debit_account_id) + WHERE journal.currency_id IS NOT NULL + AND journal.currency_id != company.currency_id + AND account.currency_id != journal.currency_id + AND apm.payment_type = 'inbound' + AND account.id IN %(accounts)s + + UNION ALL + + SELECT + account.id, + journal.id + FROM account_journal journal + JOIN res_company company ON company.id = journal.company_id + JOIN account_payment_method_line apml ON apml.journal_id = journal.id + JOIN account_payment_method apm on apm.id = apml.payment_method_id + JOIN account_account account ON account.id = COALESCE(apml.payment_account_id, company.account_journal_payment_credit_account_id) + WHERE journal.currency_id IS NOT NULL + AND journal.currency_id != company.currency_id + AND account.currency_id != journal.currency_id + AND apm.payment_type = 'outbound' + AND account.id IN %(accounts)s + ''', { + 'accounts': tuple(self.ids) + }) res = self._cr.fetchone() if res: account = self.env['account.account'].browse(res[0]) @@ -200,14 +235,18 @@ class AccountAccount(models.Model): return self.flush(['reconcile']) + self.env['account.payment.method.line'].flush(['journal_id', 'payment_account_id']) + self._cr.execute(''' SELECT journal.id FROM account_journal journal - WHERE journal.payment_credit_account_id in %(credit_account)s - OR journal.payment_debit_account_id in %(debit_account)s ; + JOIN res_company company on journal.company_id = company.id + LEFT JOIN account_payment_method_line apml ON journal.id = apml.journal_id + WHERE company.account_journal_payment_credit_account_id in %(accounts)s + OR company.account_journal_payment_debit_account_id in %(accounts)s + OR apml.payment_account_id in %(accounts)s ''', { - 'credit_account': tuple(accounts.ids), - 'debit_account': tuple(accounts.ids) + 'accounts': tuple(accounts.ids), }) rows = self._cr.fetchall() diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index ee468b0eb4f..8b9e3c39937 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -1189,10 +1189,7 @@ class AccountBankStatementLine(models.Model): new_lines = self.env['account.move.line'].create(line_vals_list) new_lines = new_lines.with_context(skip_account_move_synchronization=True) for reconciliation_vals, line in zip(reconciliation_overview, new_lines): - if reconciliation_vals.get('payment'): - accounts = (self.journal_id.payment_debit_account_id, self.journal_id.payment_credit_account_id) - counterpart_line = reconciliation_vals['payment'].line_ids.filtered(lambda line: line.account_id in accounts) - elif reconciliation_vals.get('counterpart_line'): + if reconciliation_vals.get('counterpart_line'): counterpart_line = reconciliation_vals['counterpart_line'] else: continue diff --git a/addons/account/models/account_journal.py b/addons/account/models/account_journal.py index e39c0fac2f2..49dc9bffc8f 100644 --- a/addons/account/models/account_journal.py +++ b/addons/account/models/account_journal.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from odoo import api, fields, models, _ +from odoo import api, Command, fields, models, _ from odoo.osv import expression from odoo.exceptions import UserError, ValidationError from odoo.addons.base.models.res_bank import sanitize_account_number @@ -79,26 +79,6 @@ class AccountJournal(models.Model): domain="[('deprecated', '=', False), ('company_id', '=', company_id)," "'|', ('user_type_id', '=', default_account_type), ('user_type_id', 'in', type_control_ids)," "('user_type_id.type', 'not in', ('receivable', 'payable'))]") - payment_debit_account_id = fields.Many2one( - comodel_name='account.account', check_company=True, ondelete='restrict', - compute='_compute_payment_debit_account_id', store=True, readonly=False, - help="Incoming payments entries triggered by invoices/refunds will be posted on the Outstanding Receipts Account " - "and displayed as blue lines in the bank reconciliation widget. During the reconciliation process, concerned " - "transactions will be reconciled with entries on the Outstanding Receipts Account instead of the " - "receivable account.", string='Outstanding Receipts Account', - domain=lambda self: "[('deprecated', '=', False), ('company_id', '=', company_id), \ - ('user_type_id.type', 'not in', ('receivable', 'payable')), \ - '|', ('user_type_id', '=', %s), ('id', '=', default_account_id)]" % self.env.ref('account.data_account_type_current_assets').id) - payment_credit_account_id = fields.Many2one( - comodel_name='account.account', check_company=True, ondelete='restrict', - compute='_compute_payment_credit_account_id', store=True, readonly=False, - help="Outgoing payments entries triggered by bills/credit notes will be posted on the Outstanding Payments Account " - "and displayed as blue lines in the bank reconciliation widget. During the reconciliation process, concerned " - "transactions will be reconciled with entries on the Outstanding Payments Account instead of the " - "payable account.", string='Outstanding Payments Account', - domain=lambda self: "[('deprecated', '=', False), ('company_id', '=', company_id), \ - ('user_type_id.type', 'not in', ('receivable', 'payable')), \ - '|', ('user_type_id', '=', %s), ('id', '=', default_account_id)]" % self.env.ref('account.data_account_type_current_assets').id) suspense_account_id = fields.Many2one( comodel_name='account.account', check_company=True, ondelete='restrict', readonly=False, store=True, compute='_compute_suspense_account_id', @@ -127,42 +107,35 @@ class AccountJournal(models.Model): "e.g: ^(?P.*?)(?P\d{4})(?P\D*?)(?P\d{2})(?P\D+?)(?P\d+)(?P\D*?)$") - inbound_payment_method_ids = fields.Many2many( - comodel_name='account.payment.method', - relation='account_journal_inbound_payment_method_rel', - column1='journal_id', - column2='inbound_payment_method', + inbound_payment_method_line_ids = fields.One2many( + comodel_name='account.payment.method.line', domain=[('payment_type', '=', 'inbound')], + compute='_compute_inbound_payment_method_line_ids', + store=True, + readonly=False, string='Inbound Payment Methods', - compute='_compute_inbound_payment_method_ids', - ondelete="restrict", - store=True, - readonly=False, - help="Manual: Get paid by cash, check or any other method outside of Odoo.\n" - "Electronic: Get paid automatically through a payment acquirer by requesting a transaction" - " on a card saved by the customer when buying or subscribing online (payment token).\n" - "Batch Deposit: Encase several customer checks at once by generating a batch deposit to" - " submit to your bank. When encoding the bank statement in Odoo,you are suggested to" - " reconcile the transaction with the batch deposit. Enable this option from the settings." + inverse_name='journal_id', + copy=False, + check_company=True, + help="Manual :Get paid by any method outside of Odoo." + "Payment Acquirers : Each payment acquirer has its own Payment Method. Request a transaction on/to a card thanks to a payment token saved by the partner when buying or subscribing online." + "Batch Deposit: Collect several customer checks at once generating and submitting a batch deposit to your bank. Module account_batch_payment is necessary." + "SEPA Direct Debit : Get paid in the SEPA zone thanks to a mandate your partner will have granted to you. Module account_sepa is necessary" ) - outbound_payment_method_ids = fields.Many2many( - comodel_name='account.payment.method', - relation='account_journal_outbound_payment_method_rel', - column1='journal_id', - column2='outbound_payment_method', + outbound_payment_method_line_ids = fields.One2many( + comodel_name='account.payment.method.line', domain=[('payment_type', '=', 'outbound')], - string='Outbound Payment Methods', - compute='_compute_outbound_payment_method_ids', - ondelete="restrict", + compute='_compute_outbound_payment_method_line_ids', store=True, readonly=False, - help="Manual:Pay bill by cash or any other method outside of Odoo.\n" - "Check:Pay bill by check and print it from Odoo.\n" - "SEPA Credit Transfer: Pay bill from a SEPA Credit Transfer file you submit to your" - " bank. Enable this option from the settings." + string='Outbound Payment Methods', + inverse_name='journal_id', + copy=False, + check_company=True, + help="Manual : Pay by any method outside of Odoo." + "Check: Pay bills by check and print it from Odoo." + "SEPA Credit Transfer : Pay in the SEPA zone by submitting a SEPA Credit Transfer file to your bank. Module account_sepa is necessary" ) - at_least_one_inbound = fields.Boolean(compute='_methods_compute', store=True) - at_least_one_outbound = fields.Boolean(compute='_methods_compute', store=True) profit_account_id = fields.Many2one( comodel_name='account.account', check_company=True, help="Used to register a profit when the ending balance of a cash register differs from what the system computes", @@ -212,10 +185,87 @@ class AccountJournal(models.Model): check_company=True, readonly=True, copy=False) + available_payment_method_ids = fields.Many2many( + comodel_name='account.payment.method', + compute='_compute_available_payment_method_ids' + ) + + selected_payment_method_codes = fields.Char( + compute='_compute_selected_payment_method_codes', + help='Technical field used to hide or show payment method options if needed.' + ) + _sql_constraints = [ ('code_company_uniq', 'unique (code, company_id)', 'Journal codes must be unique per company.'), ] + @api.depends('outbound_payment_method_line_ids', 'inbound_payment_method_line_ids') + def _compute_available_payment_method_ids(self): + """ + Compute the available payment methods id by respecting the following rules: + Methods of mode 'unique' cannot be used twice on the same company + Methods of mode 'multi' cannot be used twice on the same journal + """ + method_information = self.env['account.payment.method']._get_payment_method_information() + pay_methods = self.env['account.payment.method'].search([('code', 'in', list(method_information.keys()))]) + pay_method_by_code = {x.code + x.payment_type: x for x in pay_methods} + unique_pay_methods = [k for k, v in method_information.items() if v['mode'] == 'unique'] + installed_acquirers = self.env['payment.acquirer'].search([]) + + pay_methods_by_company = {} + pay_methods_by_journal = {} + if unique_pay_methods: + self._cr.execute(''' + SELECT + journal.id, + journal.company_id, + ARRAY_AGG(DISTINCT apm.id) + FROM account_payment_method_line apml + JOIN account_journal journal ON journal.id = apml.journal_id + JOIN account_payment_method apm ON apm.id = apml.payment_method_id + WHERE apm.code IN %s + GROUP BY + journal.id, + journal.company_id + ''', [tuple(unique_pay_methods)]) + for journal_id, company_id, payment_method_ids in self._cr.fetchall(): + pay_methods_by_company[company_id] = set(payment_method_ids) + pay_methods_by_journal[journal_id] = set(payment_method_ids) + + pay_method_ids_commands_x_journal = {j: [Command.clear()] for j in self} + for payment_type in ('inbound', 'outbound'): + for code, vals in method_information.items(): + payment_method = pay_method_by_code.get(code + payment_type) + + if not payment_method: + continue + + # Get the domain of the journals on which the current method is usable. + method_domain = payment_method._get_payment_method_domain() + + for journal in self.filtered_domain(method_domain): + protected_pay_method_ids = pay_methods_by_company.get(journal.company_id._origin.id, set()) \ + - pay_methods_by_journal.get(journal._origin.id, set()) + available_providers = installed_acquirers.filtered( + lambda a: a.company_id == journal.company_id + ).mapped('provider') + + if payment_type == 'inbound': + lines = journal.inbound_payment_method_line_ids + else: + lines = journal.outbound_payment_method_line_ids + + available = payment_method.code in available_providers + already_used = payment_method in lines.payment_method_id + is_protected = payment_method.id in protected_pay_method_ids + if vals['mode'] == 'unique' and (already_used or is_protected or not available): + continue + + pay_method_ids_commands_x_journal[journal].append(Command.link(payment_method.id)) + + for journal, pay_method_ids_commands in pay_method_ids_commands_x_journal.items(): + journal.available_payment_method_ids = pay_method_ids_commands + @api.depends('type') def _compute_default_account_type(self): default_account_id_types = { @@ -232,20 +282,38 @@ class AccountJournal(models.Model): journal.default_account_type = False @api.depends('type') - def _compute_outbound_payment_method_ids(self): + def _compute_inbound_payment_method_line_ids(self): for journal in self: + pay_method_line_ids_commands = [Command.clear()] if journal.type in ('bank', 'cash'): - journal.outbound_payment_method_ids = self._default_outbound_payment_methods() - else: - journal.outbound_payment_method_ids = False + default_methods = journal._default_inbound_payment_methods() + pay_method_line_ids_commands += [Command.create({ + 'name': pay_method.name, + 'payment_method_id': pay_method.id, + }) for pay_method in default_methods] + journal.inbound_payment_method_line_ids = pay_method_line_ids_commands @api.depends('type') - def _compute_inbound_payment_method_ids(self): + def _compute_outbound_payment_method_line_ids(self): for journal in self: + pay_method_line_ids_commands = [Command.clear()] if journal.type in ('bank', 'cash'): - journal.inbound_payment_method_ids = self._default_inbound_payment_methods() - else: - journal.inbound_payment_method_ids = False + default_methods = journal._default_outbound_payment_methods() + pay_method_line_ids_commands += [Command.create({ + 'name': pay_method.name, + 'payment_method_id': pay_method.id, + }) for pay_method in default_methods] + journal.outbound_payment_method_line_ids = pay_method_line_ids_commands + + @api.depends('outbound_payment_method_line_ids', 'inbound_payment_method_line_ids') + def _compute_selected_payment_method_codes(self): + """ + Set the selected payment method as a list of comma separated codes like: ,manual,check_printing,... + These will be then used to display or not payment method specific fields in the view. + """ + for journal in self: + codes = [line.code for line in journal.inbound_payment_method_line_ids + journal.outbound_payment_method_line_ids] + journal.selected_payment_method_codes = ',' + ','.join(codes) + ',' @api.depends('company_id', 'type') def _compute_suspense_account_id(self): @@ -259,30 +327,6 @@ class AccountJournal(models.Model): else: journal.suspense_account_id = False - @api.depends('company_id', 'type') - def _compute_payment_debit_account_id(self): - for journal in self: - if journal.type not in ('bank', 'cash'): - journal.payment_debit_account_id = False - elif journal.payment_debit_account_id: - journal.payment_debit_account_id = journal.payment_debit_account_id - elif journal.company_id.account_journal_payment_debit_account_id: - journal.payment_debit_account_id = journal.company_id.account_journal_payment_debit_account_id - else: - journal.payment_debit_account_id = False - - @api.depends('company_id', 'type') - def _compute_payment_credit_account_id(self): - for journal in self: - if journal.type not in ('bank', 'cash'): - journal.payment_credit_account_id = False - elif journal.payment_credit_account_id: - journal.payment_credit_account_id = journal.payment_credit_account_id - elif journal.company_id.account_journal_payment_credit_account_id: - journal.payment_credit_account_id = journal.company_id.account_journal_payment_credit_account_id - else: - journal.payment_credit_account_id = False - def _compute_alias_domain(self): alias_domain = self._default_alias_domain() for record in self: @@ -351,6 +395,38 @@ class AccountJournal(models.Model): if journal.type in ('sale', 'purchase') and journal.default_account_id.user_type_id.type in ('receivable', 'payable'): raise ValidationError(_("The type of the journal's default credit/debit account shouldn't be 'receivable' or 'payable'.")) + @api.constrains('inbound_payment_method_line_ids', 'outbound_payment_method_line_ids') + def _check_payment_method_line_ids_multiplicity(self): + """ + Check and ensure that the payment method lines multiplicity is respected. + """ + method_info = self.env['account.payment.method']._get_payment_method_information() + unique_codes = tuple(code for code, info in method_info.items() if info.get('mode') == 'unique') + + self.flush(['inbound_payment_method_line_ids', 'outbound_payment_method_line_ids', 'company_id']) + self.env['account.payment.method.line'].flush(['payment_method_id', 'journal_id']) + self.env['account.payment.method'].flush(['code']) + + if unique_codes: + self._cr.execute(''' + SELECT apm.id + FROM account_payment_method apm + JOIN account_payment_method_line apml on apm.id = apml.payment_method_id + JOIN account_journal journal on journal.id = apml.journal_id + JOIN res_company company on journal.company_id = company.id + WHERE apm.code in %s + GROUP BY + company.id, + apm.id + HAVING array_length(array_agg(journal.id), 1) > 1; + ''', [unique_codes]) + + method_ids = [res[0] for res in self._cr.fetchall()] + if method_ids: + methods = self.env['account.payment.method'].browse(method_ids) + raise ValidationError(_("Some payment methods supposed to be unique already exists somewhere else.\n" + "(%s)", ', '.join([method.display_name for method in methods]))) + @api.onchange('type') def _onchange_type(self): self.refund_sequence = self.type in ('sale', 'purchase') @@ -600,12 +676,6 @@ class AccountJournal(models.Model): domain = [connector, ('code', operator, name), ('name', operator, name)] return self._search(expression.AND([domain, args]), limit=limit, access_rights_uid=name_get_uid) - @api.depends('inbound_payment_method_ids', 'outbound_payment_method_ids') - def _methods_compute(self): - for journal in self: - journal.at_least_one_inbound = bool(len(journal.inbound_payment_method_ids)) - journal.at_least_one_outbound = bool(len(journal.outbound_payment_method_ids)) - def action_configure_bank_journal(self): """ This function is called by the "configure" button of bank journals, visible on dashboard if no bank statement source has been defined yet @@ -721,6 +791,26 @@ class AccountJournal(models.Model): nb_lines, balance, amount_currency = self._cr.fetchone() return amount_currency if journal_currency else balance, nb_lines + def _get_journal_inbound_outstanding_payment_accounts(self): + """ + :return: A recordset with all the account.account used by this journal for inbound transactions. + """ + self.ensure_one() + account_ids = set() + for line in self.inbound_payment_method_line_ids: + account_ids.add(line.payment_account_id.id or self.company_id.account_journal_payment_debit_account_id.id) + return self.env['account.account'].browse(account_ids) + + def _get_journal_outbound_outstanding_payment_accounts(self): + """ + :return: A recordset with all the account.account used by this journal for outbound transactions. + """ + self.ensure_one() + account_ids = set() + for line in self.outbound_payment_method_line_ids: + account_ids.add(line.payment_account_id.id or self.company_id.account_journal_payment_credit_account_id.id) + return self.env['account.account'].browse(account_ids) + def _get_journal_outstanding_payments_account_balance(self, domain=None, date=None): ''' Get the outstanding payments balance of the current journal by filtering the journal items using the journal's accounts. @@ -733,7 +823,7 @@ class AccountJournal(models.Model): self.env['account.move.line'].check_access_rights('read') conversion_date = date or fields.Date.context_today(self) - accounts = self.payment_debit_account_id + self.payment_credit_account_id + accounts = self._get_journal_inbound_outstanding_payment_accounts().union(self._get_journal_outbound_outstanding_payment_accounts()) if not accounts: return 0.0, 0 diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index 6ef2998e6bb..dc2407f6b73 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -52,11 +52,12 @@ class AccountPayment(models.Model): readonly=False, store=True, compute='_compute_payment_method_id', domain="[('id', 'in', available_payment_method_ids)]", - help="Manual: Get paid by cash, check or any other method outside of Odoo.\n"\ - "Electronic: Get paid automatically through a payment acquirer by requesting a transaction on a card saved by the customer when buying or subscribing online (payment token).\n"\ - "Check: Pay bill by check and print it from Odoo.\n"\ - "Batch Deposit: Encase several customer checks at once by generating a batch deposit to submit to your bank. When encoding the bank statement in Odoo, you are suggested to reconcile the transaction with the batch deposit.To enable batch deposit, module account_batch_payment must be installed.\n"\ - "SEPA Credit Transfer: Pay bill from a SEPA Credit Transfer file you submit to your bank. To enable sepa credit transfer, module account_sepa must be installed ") + help="Manual : Pay or Get paid by any method outside of Odoo." + "Payment Acquirers : Each payment acquirer has its own Payment Method. Request a transaction on/to a card thanks to a payment token saved by the partner when buying or subscribing online." + "Check: Pay bills by check and print it from Odoo." + "Batch Deposit: Collect several customer checks at once generating and submitting a batch deposit to your bank. Module account_batch_payment is necessary." + "SEPA Credit Transfer : Pay in the SEPA zone by submitting a SEPA Credit Transfer file to your bank. Module account_sepa is necessary" + "SEPA Direct Debit : Get paid in the SEPA zone thanks to a mandate your partner will have granted to you. Module account_sepa is necessary") available_payment_method_ids = fields.Many2many('account.payment.method', compute='_compute_payment_method_fields') hide_payment_method = fields.Boolean( @@ -85,6 +86,12 @@ class AccountPayment(models.Model): compute='_compute_partner_id', domain="['|', ('parent_id','=', False), ('is_company','=', True)]", check_company=True) + outstanding_account_id = fields.Many2one( + comodel_name='account.account', + string="Outstanding Account", + store=True, + compute='_compute_outstanding_account_id', + check_company=True) destination_account_id = fields.Many2one( comodel_name='account.account', string='Destination Account', @@ -162,11 +169,20 @@ class AccountPayment(models.Model): counterpart_lines = self.env['account.move.line'] writeoff_lines = self.env['account.move.line'] + if self.payment_type == 'inbound': + payment_method_account_ids = self.journal_id.inbound_payment_method_line_ids + else: + payment_method_account_ids = self.journal_id.outbound_payment_method_line_ids + + payment_method_account_id = payment_method_account_ids\ + .filtered(lambda line: line.code == self.payment_method_id.code).payment_account_id + for line in self.move_id.line_ids: if line.account_id in ( self.journal_id.default_account_id, - self.journal_id.payment_debit_account_id, - self.journal_id.payment_credit_account_id, + payment_method_account_id, + self.journal_id.company_id.account_journal_payment_debit_account_id, + self.journal_id.company_id.account_journal_payment_credit_account_id, ): liquidity_lines += line elif line.account_id.internal_type in ('receivable', 'payable') or line.partner_id == line.company_id.partner_id: @@ -187,10 +203,10 @@ class AccountPayment(models.Model): self.ensure_one() write_off_line_vals = write_off_line_vals or {} - if not self.journal_id.payment_debit_account_id or not self.journal_id.payment_credit_account_id: + if not self.outstanding_account_id: raise UserError(_( - "You can't create a new payment without an outstanding payments/receipts account set on the %s journal.", - self.journal_id.display_name)) + "You can't create a new payment without an outstanding payments/receipts account set either on the company or the %s payment method in the %s journal.", + self.payment_method_id.name, self.journal_id.display_name)) # Compute amounts. write_off_amount_currency = write_off_line_vals.get('amount', 0.0) @@ -256,7 +272,7 @@ class AccountPayment(models.Model): 'debit': liquidity_balance if liquidity_balance > 0.0 else 0.0, 'credit': -liquidity_balance if liquidity_balance < 0.0 else 0.0, 'partner_id': self.partner_id.id, - 'account_id': self.journal_id.payment_credit_account_id.id if liquidity_balance < 0.0 else self.journal_id.payment_debit_account_id.id, + 'account_id': self.outstanding_account_id.id, }, # Receivable / Payable. { @@ -371,9 +387,9 @@ class AccountPayment(models.Model): ''' for pay in self: if pay.payment_type == 'inbound': - available_payment_methods = pay.journal_id.inbound_payment_method_ids + available_payment_methods = pay.journal_id.inbound_payment_method_line_ids.mapped('payment_method_id') else: - available_payment_methods = pay.journal_id.outbound_payment_method_ids + available_payment_methods = pay.journal_id.outbound_payment_method_line_ids.mapped('payment_method_id') # Select the first available one by default. if pay.payment_method_id in available_payment_methods: @@ -384,14 +400,14 @@ class AccountPayment(models.Model): pay.payment_method_id = False @api.depends('payment_type', - 'journal_id.inbound_payment_method_ids', - 'journal_id.outbound_payment_method_ids') + 'journal_id.inbound_payment_method_line_ids', + 'journal_id.outbound_payment_method_line_ids') def _compute_payment_method_fields(self): for pay in self: if pay.payment_type == 'inbound': - pay.available_payment_method_ids = pay.journal_id.inbound_payment_method_ids + pay.available_payment_method_ids = pay.journal_id.inbound_payment_method_line_ids.mapped('payment_method_id') else: - pay.available_payment_method_ids = pay.journal_id.outbound_payment_method_ids + pay.available_payment_method_ids = pay.journal_id.outbound_payment_method_line_ids.mapped('payment_method_id') to_exclude = self._get_payment_method_codes_to_exclude() if to_exclude: pay.available_payment_method_ids = pay.available_payment_method_ids.filtered(lambda x: x.code not in to_exclude) @@ -417,6 +433,24 @@ class AccountPayment(models.Model): else: pay.partner_id = pay.partner_id + @api.depends('journal_id', 'payment_type') + def _compute_outstanding_account_id(self): + for pay in self: + if pay.payment_type == 'inbound': + payment_method_account_id = pay.journal_id.inbound_payment_method_line_ids\ + .filtered(lambda line: line.code == pay.payment_method_id.code).payment_account_id + + pay.outstanding_account_id = (payment_method_account_id + or pay.journal_id.company_id.account_journal_payment_debit_account_id) + elif pay.payment_type == 'outbound': + payment_method_account_id = pay.journal_id.outbound_payment_method_line_ids\ + .filtered(lambda line: line.code == pay.payment_method_id.code).payment_account_id + + pay.outstanding_account_id = (payment_method_account_id + or pay.journal_id.company_id.account_journal_payment_credit_account_id) + else: + pay.outstanding_account_id = False + @api.depends('journal_id', 'partner_id', 'partner_type', 'is_internal_transfer') def _compute_destination_account_id(self): self.destination_account_id = False @@ -542,7 +576,7 @@ class AccountPayment(models.Model): part.debit_move_id = counterpart_line.id OR part.credit_move_id = counterpart_line.id - WHERE (account.id = journal.payment_debit_account_id OR account.id = journal.payment_credit_account_id) + WHERE account.id = payment.outstanding_account_id AND payment.id IN %(payment_ids)s AND line.id != counterpart_line.id AND counterpart_line.statement_id IS NOT NULL diff --git a/addons/account/models/account_payment_method.py b/addons/account/models/account_payment_method.py index 24de32ae15e..dde58dddcec 100644 --- a/addons/account/models/account_payment_method.py +++ b/addons/account/models/account_payment_method.py @@ -1,14 +1,120 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import models, fields +from odoo import api, fields, models +from odoo.osv import expression class AccountPaymentMethod(models.Model): _name = "account.payment.method" _description = "Payment Methods" - _order = 'sequence' name = fields.Char(required=True, translate=True) code = fields.Char(required=True) # For internal identification - payment_type = fields.Selection([('inbound', 'Inbound'), ('outbound', 'Outbound')], required=True) - sequence = fields.Integer(help='Used to order Methods in the form view', default=10) + 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) + limit = None if information.get('mode') == 'multi' else 1 + + method_domain = method._get_payment_method_domain() + + journals = self.env['account.journal'].search(method_domain, limit=limit) + + 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 + + def _get_payment_method_domain(self): + """ + :return: The domain specyfying which journal can accomodate this payment method. + """ + self.ensure_one() + information = self._get_payment_method_information().get(self.code) + + unique = information.get('mode') == 'unique' + currency_id = information.get('currency_id') + country_id = information.get('country_id') + default_domain = [('type', 'in', ('bank', 'cash'))] + domains = [information.get('domain', default_domain)] + + if currency_id: + domains += [expression.OR([ + [('currency_id', '=', False), ('company_id.currency_id', '=', currency_id)], + [('currency_id', '=', currency_id)]], + )] + + if country_id: + domains += [[('company_id.account_fiscal_country_id', '=', country_id)]] + + if unique: + company_ids = self.env['payment.acquirer'].search([('provider', '=', self.code)]).mapped('company_id') + if company_ids: + domains += [[('company_id', 'in', company_ids.ids)]] + + 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" + + # == 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)]" % self.env.ref('account.data_account_type_current_assets').id + ) + journal_id = fields.Many2one(comodel_name='account.journal', required=True, 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: + method.name = method.payment_method_id.name diff --git a/addons/account/security/ir.model.access.csv b/addons/account/security/ir.model.access.csv index b6a47288b84..ea258a28b53 100644 --- a/addons/account/security/ir.model.access.csv +++ b/addons/account/security/ir.model.access.csv @@ -120,6 +120,8 @@ access_account_payment_term_partner_manager,account.payment.term partner manager access_account_payment_term_manager,account.payment.term,model_account_payment_term,account.group_account_manager,1,1,1,1 access_account_payment_term_line_partner_manager,account.payment.term.line partner manager,model_account_payment_term_line,base.group_user,1,0,0,0 access_account_payment_term_line_manager,account.payment.term.line,model_account_payment_term_line,account.group_account_manager,1,1,1,1 +access_account_payment_method_line_readonly,account.payment.method.line,model_account_payment_method_line,base.group_user,1,0,0,0 +access_account_payment_method_line,account.payment.method.line,model_account_payment_method_line,account.group_account_invoice,1,1,1,1 access_account_payment_method_readonly,account.payment.method,model_account_payment_method,base.group_user,1,0,0,0 access_account_payment_method,account.payment.method,model_account_payment_method,account.group_account_invoice,1,1,1,1 access_account_payment_readonly,account.payment,model_account_payment,account.group_account_readonly,1,0,0,0 diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index 8de0b74ab9d..6cbecc6ddcf 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -170,6 +170,12 @@ class AccountTestInvoicingCommon(TransactionCase): 'rounding_method': 'DOWN', }) + # ==== Payment methods ==== + bank_journal = cls.company_data['default_journal_bank'] + + cls.inbound_payment_method = bank_journal.inbound_payment_method_line_ids[0].payment_method_id + cls.outbound_payment_method = bank_journal.outbound_payment_method_line_ids[0].payment_method_id + @classmethod def setup_company_data(cls, company_name, chart_template=None, **kwargs): ''' Create a new company having the name passed as parameter. @@ -541,12 +547,6 @@ class TestAccountReconciliationCommon(AccountTestInvoicingCommon): cls.diff_income_account = cls.company.income_currency_exchange_account_id cls.diff_expense_account = cls.company.expense_currency_exchange_account_id - cls.inbound_payment_method = cls.env['account.payment.method'].create({ - 'name': 'inbound', - 'code': 'IN', - 'payment_type': 'inbound', - }) - cls.expense_account = cls.company_data['default_account_expense'] # cash basis intermediary account cls.tax_waiting_account = cls.env['account.account'].create({ diff --git a/addons/account/tests/test_account_account.py b/addons/account/tests/test_account_account.py index cded3517c55..277d98ef3b8 100644 --- a/addons/account/tests/test_account_account.py +++ b/addons/account/tests/test_account_account.py @@ -132,6 +132,6 @@ class TestAccountAccount(AccountTestInvoicingCommon): is configured with this account as the payment credit or debit account. Since such an account should be reconcilable by nature, a ValidationError is raised.''' with self.assertRaises(ValidationError), self.cr.savepoint(): - self.company_data['default_journal_bank'].payment_debit_account_id.reconcile = False + self.company_data['default_journal_bank'].company_id.account_journal_payment_debit_account_id.reconcile = False with self.assertRaises(ValidationError), self.cr.savepoint(): - self.company_data['default_journal_bank'].payment_credit_account_id.reconcile = False + self.company_data['default_journal_bank'].company_id.account_journal_payment_credit_account_id.reconcile = False diff --git a/addons/account/tests/test_account_bank_statement.py b/addons/account/tests/test_account_bank_statement.py index 8c0cdb9992b..547851003e1 100644 --- a/addons/account/tests/test_account_bank_statement.py +++ b/addons/account/tests/test_account_bank_statement.py @@ -1146,7 +1146,7 @@ class TestAccountBankStatementLine(TestAccountBankStatementCommon): receivable_acc_1 = self.company_data['default_account_receivable'] receivable_acc_2 = self.copy_account(self.company_data['default_account_receivable']) - payment_account = self.bank_journal_1.payment_debit_account_id + payment_account = self.bank_journal_1.company_id.account_journal_payment_debit_account_id random_acc_1 = self.company_data['default_account_revenue'] random_acc_2 = self.copy_account(self.company_data['default_account_revenue']) test_move = self.env['account.move'].create({ diff --git a/addons/account/tests/test_account_journal.py b/addons/account/tests/test_account_journal.py index b8644db037d..2d3b06e172a 100644 --- a/addons/account/tests/test_account_journal.py +++ b/addons/account/tests/test_account_journal.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +from unittest.mock import patch + from odoo.addons.account.tests.common import AccountTestInvoicingCommon +from odoo.addons.account.models.account_payment_method import AccountPaymentMethod from odoo.tests import tagged from odoo.exceptions import UserError, ValidationError @@ -82,3 +85,49 @@ class TestAccountJournal(AccountTestInvoicingCommon): # Assigning both should be allowed self.company_data['default_journal_misc'].account_control_ids = \ self.company_data['default_account_revenue'] + self.company_data['default_account_expense'] + + def test_account_journal_add_new_payment_method_unique(self): + """ + Test the automatic creation of payment method lines with the mode set to unique + """ + Method_get_payment_method_information = AccountPaymentMethod._get_payment_method_information + + def _get_payment_method_information(self): + res = Method_get_payment_method_information(self) + res['unique'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res + + with patch.object(AccountPaymentMethod, '_get_payment_method_information', _get_payment_method_information): + self.env['account.payment.method'].create({ + 'name': 'Unique method', + 'code': 'unique', + 'payment_type': 'inbound' + }) + + journals = self.env['account.journal'].search([('inbound_payment_method_line_ids.code', '=', 'unique')]) + + # Only one of the bank journals has been set + self.assertEqual(len(journals), 1) + + def test_account_journal_add_new_payment_method_multi(self): + """ + Test the automatic creation of payment method lines with the mode set to multi + """ + Method_get_payment_method_information = AccountPaymentMethod._get_payment_method_information + + def _get_payment_method_information(self): + res = Method_get_payment_method_information(self) + res['multi'] = {'mode': 'multi', 'domain': [('type', '=', 'bank')]} + return res + + with patch.object(AccountPaymentMethod, '_get_payment_method_information', _get_payment_method_information): + self.env['account.payment.method'].create({ + 'name': 'Multi method', + 'code': 'multi', + 'payment_type': 'inbound' + }) + + journals = self.env['account.journal'].search([('inbound_payment_method_line_ids.code', '=', 'multi')]) + + # The two bank journals have been set + self.assertEqual(len(journals), 2) diff --git a/addons/account/tests/test_account_payment.py b/addons/account/tests/test_account_payment.py index 5ef482db4a4..648c00a78e3 100644 --- a/addons/account/tests/test_account_payment.py +++ b/addons/account/tests/test_account_payment.py @@ -11,8 +11,10 @@ class TestAccountPayment(AccountTestInvoicingCommon): def setUpClass(cls, chart_template_ref=None): super().setUpClass(chart_template_ref=chart_template_ref) - cls.payment_debit_account_id = cls.copy_account(cls.company_data['default_journal_bank'].payment_debit_account_id) - cls.payment_credit_account_id = cls.copy_account(cls.company_data['default_journal_bank'].payment_credit_account_id) + company_id = cls.company_data['default_journal_bank'].company_id + + cls.payment_debit_account_id = cls.copy_account(company_id.account_journal_payment_debit_account_id) + cls.payment_credit_account_id = cls.copy_account(company_id.account_journal_payment_credit_account_id) cls.partner_bank_account = cls.env['res.partner.bank'].create({ 'acc_number': 'BE32707171912447', @@ -20,11 +22,9 @@ class TestAccountPayment(AccountTestInvoicingCommon): 'acc_type': 'bank', }) - cls.company_data['default_journal_bank'].write({ - 'payment_debit_account_id': cls.payment_debit_account_id.id, - 'payment_credit_account_id': cls.payment_credit_account_id.id, - 'inbound_payment_method_ids': [(6, 0, cls.env.ref('account.account_payment_method_manual_in').ids)], - 'outbound_payment_method_ids': [(6, 0, cls.env.ref('account.account_payment_method_manual_out').ids)], + company_id.write({ + 'account_journal_payment_debit_account_id': cls.payment_debit_account_id.id, + 'account_journal_payment_credit_account_id': cls.payment_credit_account_id.id }) cls.partner_a.write({ @@ -640,7 +640,7 @@ class TestAccountPayment(AccountTestInvoicingCommon): 'credit': 50.0, 'amount_currency': -50.0, 'currency_id': self.company_data['currency'].id, - 'account_id': self.company_data['default_journal_cash'].payment_credit_account_id.id, + 'account_id': self.company_data['default_journal_cash'].company_id.account_journal_payment_credit_account_id.id, } expected_counterpart_line = { 'debit': 50.0, diff --git a/addons/account/tests/test_account_payment_register.py b/addons/account/tests/test_account_payment_register.py index 1515ca4822c..2a78ae90737 100644 --- a/addons/account/tests/test_account_payment_register.py +++ b/addons/account/tests/test_account_payment_register.py @@ -18,36 +18,8 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'currency_subunit_label': "Broken Umbrella", }, rate2017=0.01) - cls.payment_debit_account_id = cls.company_data['default_journal_bank'].payment_debit_account_id.copy() - cls.payment_credit_account_id = cls.company_data['default_journal_bank'].payment_credit_account_id.copy() - - cls.custom_payment_method_in = cls.env['account.payment.method'].create({ - 'name': 'custom_payment_method_in', - 'code': 'CUSTOMIN', - 'payment_type': 'inbound', - }) - cls.manual_payment_method_in = cls.env.ref('account.account_payment_method_manual_in') - - cls.custom_payment_method_out = cls.env['account.payment.method'].create({ - 'name': 'custom_payment_method_out', - 'code': 'CUSTOMOUT', - 'payment_type': 'outbound', - }) - cls.manual_payment_method_out = cls.env.ref('account.account_payment_method_manual_out') - - cls.company_data['default_journal_bank'].write({ - 'payment_debit_account_id': cls.payment_debit_account_id.id, - 'payment_credit_account_id': cls.payment_credit_account_id.id, - 'inbound_payment_method_ids': [(6, 0, ( - cls.manual_payment_method_in.id, - cls.custom_payment_method_in.id, - ))], - 'outbound_payment_method_ids': [(6, 0, ( - cls.env.ref('account.account_payment_method_manual_out').id, - cls.custom_payment_method_out.id, - cls.manual_payment_method_out.id, - ))], - }) + cls.payment_debit_account_id = cls.company_data['default_journal_bank'].company_id.account_journal_payment_debit_account_id.copy() + cls.payment_credit_account_id = cls.company_data['default_journal_bank'].company_id.account_journal_payment_credit_account_id.copy() # Customer invoices sharing the same batch. cls.out_invoice_1 = cls.env['account.move'].create({ @@ -115,12 +87,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'group_payment': True, 'payment_difference_handling': 'open', 'currency_id': self.currency_data['currency'].id, - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'INV/2017/01/0001 INV/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Receivable line: @@ -149,12 +121,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'group_payment': True, 'payment_difference_handling': 'open', 'currency_id': self.currency_data['currency'].id, - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'INV/2017/01/0001 INV/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Receivable line: @@ -184,12 +156,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'payment_difference_handling': 'reconcile', 'writeoff_account_id': self.company_data['default_account_revenue'].id, 'writeoff_label': 'writeoff', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'INV/2017/01/0001 INV/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Receivable line: @@ -227,12 +199,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'payment_difference_handling': 'reconcile', 'writeoff_account_id': self.company_data['default_account_revenue'].id, 'writeoff_label': 'writeoff', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'INV/2017/01/0001 INV/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Receivable line: @@ -270,12 +242,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'payment_difference_handling': 'reconcile', 'writeoff_account_id': self.company_data['default_account_revenue'].id, 'writeoff_label': 'writeoff', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'BILL/2017/01/0001 BILL/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Writeoff line: @@ -313,12 +285,12 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): 'payment_difference_handling': 'reconcile', 'writeoff_account_id': self.company_data['default_account_revenue'].id, 'writeoff_label': 'writeoff', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, })._create_payments() self.assertRecordValues(payments, [{ 'ref': 'BILL/2017/01/0001 BILL/2017/01/0002', - 'payment_method_id': self.custom_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }]) self.assertRecordValues(payments.line_ids.sorted('balance'), [ # Liquidity line: @@ -357,11 +329,11 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): self.assertRecordValues(payments, [ { 'ref': 'INV/2017/01/0001', - 'payment_method_id': self.manual_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }, { 'ref': 'INV/2017/01/0002', - 'payment_method_id': self.manual_payment_method_in.id, + 'payment_method_id': self.inbound_payment_method.id, }, ]) self.assertRecordValues(payments[0].line_ids.sorted('balance') + payments[1].line_ids.sorted('balance'), [ @@ -413,11 +385,11 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): self.assertRecordValues(payments, [ { 'ref': 'BILL/2017/01/0001 BILL/2017/01/0002', - 'payment_method_id': self.manual_payment_method_out.id, + 'payment_method_id': self.outbound_payment_method.id, }, { 'ref': 'BILL/2017/01/0003', - 'payment_method_id': self.manual_payment_method_out.id, + 'payment_method_id': self.outbound_payment_method.id, }, ]) self.assertRecordValues(payments[0].line_ids.sorted('balance') + payments[1].line_ids.sorted('balance'), [ @@ -469,15 +441,15 @@ class TestAccountPaymentRegister(AccountTestInvoicingCommon): self.assertRecordValues(payments, [ { 'ref': 'BILL/2017/01/0001', - 'payment_method_id': self.manual_payment_method_out.id, + 'payment_method_id': self.outbound_payment_method.id, }, { 'ref': 'BILL/2017/01/0002', - 'payment_method_id': self.manual_payment_method_out.id, + 'payment_method_id': self.outbound_payment_method.id, }, { 'ref': 'BILL/2017/01/0003', - 'payment_method_id': self.manual_payment_method_out.id, + 'payment_method_id': self.outbound_payment_method.id, }, ]) self.assertRecordValues(payments[0].line_ids.sorted('balance') + payments[1].line_ids.sorted('balance') + payments[2].line_ids.sorted('balance'), [ diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index 98559eab908..73b7576db84 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -271,7 +271,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): 'company_id': self.company.id, 'date': time.strftime('%Y') + '-' + '07' + '-01', 'partner_id': self.partner_agrolait_id, - 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, + 'payment_method_id': self.inbound_payment_method.id, 'partner_type': 'supplier'}) # One that will complete the payment of a, the rest goes to b @@ -282,7 +282,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): 'company_id': self.company.id, 'date': time.strftime('%Y') + '-' + '08' + '-01', 'partner_id': self.partner_agrolait_id, - 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, + 'payment_method_id': self.outbound_payment_method.id, 'partner_type': 'supplier'}) # The last one will complete the payment of b @@ -293,7 +293,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): 'company_id': self.company.id, 'date': time.strftime('%Y') + '-' + '09' + '-01', 'partner_id': self.partner_agrolait_id, - 'payment_method_id': self.env.ref('account.account_payment_method_manual_out').id, + 'payment_method_id': self.outbound_payment_method.id, 'partner_type': 'supplier'}) payment_a.action_post() @@ -339,7 +339,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): inv2 = self.create_invoice(invoice_amount=20, currency_id=self.currency_usd_id) payment = self.env['account.payment'].create({ 'payment_type': 'inbound', - 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id, + 'payment_method_id': self.inbound_payment_method.id, 'partner_type': 'customer', 'partner_id': self.partner_agrolait_id, 'amount': 100, @@ -389,7 +389,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): inv = self.create_invoice(invoice_amount=111, currency_id=self.currency_usd_id) payment = self.env['account.payment'].create({ 'payment_type': 'inbound', - 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id, + 'payment_method_id': self.inbound_payment_method.id, 'partner_type': 'customer', 'partner_id': self.partner_agrolait_id, 'amount': 111, @@ -426,7 +426,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): self.assertEqual(len(payment.line_ids), 2) - bank_line = payment.line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.payment_debit_account_id.id) + bank_line = payment.line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.company_id.account_journal_payment_debit_account_id.id) customer_line = payment.line_ids - bank_line self.assertEqual(len(bank_line), 1) @@ -443,7 +443,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): self.assertEqual(len(reversed_move.line_ids), 2) # Testing the reconciliation matching between the move lines and their reversed counterparts - reversed_bank_line = reversed_move.line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.payment_debit_account_id.id) + reversed_bank_line = reversed_move.line_ids.filtered(lambda l: l.account_id.id == self.bank_journal_usd.company_id.account_journal_payment_debit_account_id.id) reversed_customer_line = reversed_move.line_ids - reversed_bank_line self.assertEqual(len(reversed_bank_line), 1) @@ -495,7 +495,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): inv = self.create_invoice(invoice_amount=111, currency_id=self.currency_usd_id) payment = self.env['account.payment'].create({ 'payment_type': 'inbound', - 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id, + 'payment_method_id': self.inbound_payment_method.id, 'partner_type': 'customer', 'partner_id': self.partner_agrolait_id, 'amount': 111, @@ -617,7 +617,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): payment = self.env['account.payment'].create({ 'date': time.strftime('%Y') + '-07-15', 'payment_type': 'inbound', - 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id, + 'payment_method_id': self.inbound_payment_method.id, 'partner_type': 'customer', 'partner_id': self.partner_agrolait_id, 'amount': 25, diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index 4db5fb20537..bb73a5d42e6 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -597,7 +597,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): 'debit': 10, }), (0, 0, { - 'account_id': self.bank_journal.payment_credit_account_id.id, + 'account_id': self.bank_journal.company_id.account_journal_payment_credit_account_id.id, 'partner_id': partner.id, 'name': 'I\'m gonna cut you into little pieces', 'credit': 10, @@ -605,7 +605,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): ], }) - payment_bnk_line = move.line_ids.filtered(lambda l: l.account_id == self.bank_journal.payment_credit_account_id) + payment_bnk_line = move.line_ids.filtered(lambda l: l.account_id == self.bank_journal.company_id.account_journal_payment_credit_account_id) move.action_post() move_reversed = move._reverse_moves() diff --git a/addons/account/views/account_journal_views.xml b/addons/account/views/account_journal_views.xml index 93d8c4b2740..3c3db5991ca 100644 --- a/addons/account/views/account_journal_views.xml +++ b/addons/account/views/account_journal_views.xml @@ -15,8 +15,6 @@ - - @@ -89,23 +87,42 @@ - - - - + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + - diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml index 7c279060746..2f2078fe55a 100644 --- a/addons/account/views/account_payment_view.xml +++ b/addons/account/views/account_payment_view.xml @@ -165,7 +165,7 @@ @@ -237,7 +237,7 @@ - - - Checks check_printing outbound - 20 - - - Print Checks diff --git a/addons/account_check_printing/models/__init__.py b/addons/account_check_printing/models/__init__.py index 7341412a7f7..1248c083071 100644 --- a/addons/account_check_printing/models/__init__.py +++ b/addons/account_check_printing/models/__init__.py @@ -4,6 +4,7 @@ from . import account_journal from . import account_move from . import account_payment +from . import account_payment_method from . import res_company from . import res_config_settings from . import res_partner diff --git a/addons/account_check_printing/models/account_journal.py b/addons/account_check_printing/models/account_journal.py index 004293a1fb3..43b864f905a 100644 --- a/addons/account_check_printing/models/account_journal.py +++ b/addons/account_check_printing/models/account_journal.py @@ -5,9 +5,16 @@ import re from odoo import models, fields, api, _ from odoo.exceptions import ValidationError + class AccountJournal(models.Model): _inherit = "account.journal" + def _default_outbound_payment_methods(self): + res = super()._default_outbound_payment_methods() + if self.type == 'bank': + res |= self.env.ref('account_check_printing.account_payment_method_check') + return res + check_manual_sequencing = fields.Boolean( string='Manual Numbering', default=False, @@ -26,10 +33,6 @@ class AccountJournal(models.Model): inverse='_inverse_check_next_number', help="Sequence number of the next printed check.", ) - check_printing_payment_method_selected = fields.Boolean( - compute='_compute_check_printing_payment_method_selected', - help="Technical feature used to know whether check printing was enabled as payment method.", - ) @api.depends('check_manual_sequencing') def _compute_check_next_number(self): @@ -54,22 +57,6 @@ class AccountJournal(models.Model): journal.check_sequence_id.sudo().number_next_actual = int(journal.check_next_number) journal.check_sequence_id.sudo().padding = len(journal.check_next_number) - @api.depends('type') - def _compute_outbound_payment_method_ids(self): - super()._compute_outbound_payment_method_ids() - for journal in self: - if journal.type == 'cash': - check_method = self.env.ref('account_check_printing.account_payment_method_check') - journal.outbound_payment_method_ids -= check_method - - @api.depends('outbound_payment_method_ids') - def _compute_check_printing_payment_method_selected(self): - for journal in self: - journal.check_printing_payment_method_selected = any( - pm.code == 'check_printing' - for pm in journal.outbound_payment_method_ids - ) - @api.model def create(self, vals): rec = super(AccountJournal, self).create(vals) @@ -94,20 +81,6 @@ class AccountJournal(models.Model): 'company_id': journal.company_id.id, }) - def _default_outbound_payment_methods(self): - methods = super(AccountJournal, self)._default_outbound_payment_methods() - return methods + self.env.ref('account_check_printing.account_payment_method_check') - - @api.model - def _enable_check_printing_on_bank_journals(self): - """ Enables check printing payment method and add a check sequence on bank journals. - Called upon module installation via data file. - """ - check_method = self.env.ref('account_check_printing.account_payment_method_check') - for bank_journal in self.search([('type', '=', 'bank')]): - bank_journal._create_check_sequence() - bank_journal.outbound_payment_method_ids += check_method - def get_journal_dashboard_datas(self): domain_checks_to_print = [ ('journal_id', '=', self.id), diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py index 42894ea1a6b..f349be9c621 100644 --- a/addons/account_check_printing/models/account_payment.py +++ b/addons/account_check_printing/models/account_payment.py @@ -93,7 +93,8 @@ class AccountPayment(models.Model): super()._compute_payment_method_id() for record in self: preferred = record.partner_id.with_company(record.company_id).property_payment_method_id - if record.payment_type == 'outbound' and preferred in record.journal_id.outbound_payment_method_ids: + if (record.payment_type == 'outbound' + and preferred in record.journal_id.outbound_payment_method_line_ids.mapped('payment_method_id')): record.payment_method_id = preferred def action_post(self): diff --git a/addons/account_check_printing/models/account_payment_method.py b/addons/account_check_printing/models/account_payment_method.py new file mode 100644 index 00000000000..cb959dce010 --- /dev/null +++ b/addons/account_check_printing/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['check_printing'] = {'mode': 'multi', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/account_check_printing/tests/test_print_check.py b/addons/account_check_printing/tests/test_print_check.py index 59a2299c8ec..7386756a007 100644 --- a/addons/account_check_printing/tests/test_print_check.py +++ b/addons/account_check_printing/tests/test_print_check.py @@ -15,13 +15,6 @@ class TestPrintCheck(AccountTestInvoicingCommon): cls.payment_method_check = cls.env.ref("account_check_printing.account_payment_method_check") - cls.company_data['default_journal_bank'].write({ - 'outbound_payment_method_ids': [(6, 0, ( - cls.env.ref('account.account_payment_method_manual_out').id, - cls.payment_method_check.id, - ))], - }) - def test_in_invoice_check_manual_sequencing(self): ''' Test the check generation for vendor bills. ''' nb_invoices_to_test = INV_LINES_PER_STUB + 1 diff --git a/addons/account_check_printing/views/account_journal_views.xml b/addons/account_check_printing/views/account_journal_views.xml index db8961ffa18..2c89c35e33c 100644 --- a/addons/account_check_printing/views/account_journal_views.xml +++ b/addons/account_check_printing/views/account_journal_views.xml @@ -26,10 +26,9 @@ account.journal - + - + attrs="{'invisible': ['|', '!', ('selected_payment_method_codes', 'ilike', ',check_printing,'), ('type', '!=', 'bank')]}"> diff --git a/addons/hr_expense/tests/test_expenses.py b/addons/hr_expense/tests/test_expenses.py index 7c97e68df4c..8fdbe74986c 100644 --- a/addons/hr_expense/tests/test_expenses.py +++ b/addons/hr_expense/tests/test_expenses.py @@ -16,7 +16,7 @@ class TestExpenses(TestExpenseCommon): payment_register = self.env['account.payment.register'].with_context(**ctx).create({ 'amount': amount, 'journal_id': self.company_data['default_journal_bank'].id, - 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id, + 'payment_method_id': self.inbound_payment_method.id, }) return payment_register._create_payments() diff --git a/addons/l10n_in/demo/account_payment_demo.xml b/addons/l10n_in/demo/account_payment_demo.xml index 54bfc1f7bd1..91493034c30 100644 --- a/addons/l10n_in/demo/account_payment_demo.xml +++ b/addons/l10n_in/demo/account_payment_demo.xml @@ -14,10 +14,10 @@ + ('company_id', '=', ref('l10n_in.demo_company_in'))], limit=1).inbound_payment_method_line_ids[0].id"/> - \ No newline at end of file + diff --git a/addons/payment/__manifest__.py b/addons/payment/__manifest__.py index 207d6ff3971..e60f0d0e7aa 100644 --- a/addons/payment/__manifest__.py +++ b/addons/payment/__manifest__.py @@ -8,7 +8,6 @@ 'description': """Payment Acquirer Base Module""", 'depends': ['account'], 'data': [ - 'data/account_data.xml', 'data/payment_icon_data.xml', 'data/payment_acquirer_data.xml', 'data/payment_cron.xml', diff --git a/addons/payment/data/account_data.xml b/addons/payment/data/account_data.xml deleted file mode 100644 index bb9fb181a21..00000000000 --- a/addons/payment/data/account_data.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Electronic - electronic - inbound - - - diff --git a/addons/payment/models/__init__.py b/addons/payment/models/__init__.py index e60a9738041..495a668f3e9 100644 --- a/addons/payment/models/__init__.py +++ b/addons/payment/models/__init__.py @@ -1,6 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import account_chart_template from . import account_payment from . import account_move from . import ir_http @@ -11,3 +10,4 @@ from . import payment_token from . import payment_transaction from . import res_company from . import res_partner +from . import account_journal diff --git a/addons/payment/models/account_chart_template.py b/addons/payment/models/account_chart_template.py deleted file mode 100644 index 3f07138f1b6..00000000000 --- a/addons/payment/models/account_chart_template.py +++ /dev/null @@ -1,13 +0,0 @@ -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import models - - -class AccountChartTemplate(models.Model): - _inherit = 'account.chart.template' - - def _create_bank_journals(self, company, acc_template_ref): - res = super()._create_bank_journals(company, acc_template_ref) - - # Try to generate the missing journals - return res + self.env['payment.acquirer']._create_missing_journals(company=company) diff --git a/addons/payment/models/account_journal.py b/addons/payment/models/account_journal.py new file mode 100644 index 00000000000..8621eed8591 --- /dev/null +++ b/addons/payment/models/account_journal.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, models +from odoo.exceptions import UserError + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + @api.constrains('inbound_payment_method_line_ids') + def _check_inbound_payment_method_line_ids(self): + """ + Check and ensure that the user do not remove a apml that is linked to an acquirer in the test or enabled state. + """ + self.env['account.payment.method'].flush(['code', 'payment_type']) + self.env['account.payment.method.line'].flush(['payment_method_id']) + self.env['payment.acquirer'].flush(['provider', 'state']) + + self._cr.execute(''' + SELECT acquirer.id + FROM payment_acquirer acquirer + JOIN account_payment_method apm ON apm.code = acquirer.provider + LEFT JOIN account_payment_method_line apml ON apm.id = apml.payment_method_id + WHERE acquirer.state IN ('enabled', 'test') AND apm.payment_type = 'inbound' + AND apml.id IS NULL + ''') + ids = [r[0] for r in self._cr.fetchall()] + acquirers = self.env['payment.acquirer'].browse(ids) + if acquirers: + raise UserError(_("You can't delete a payment method that is linked to an acquirer in the enabled or test state.\n" + "Linked acquirer(s): %s", ', '.join(a.display_name for a in acquirers))) diff --git a/addons/payment/models/account_payment.py b/addons/payment/models/account_payment.py index ada0fefe827..13e6f2c8a82 100644 --- a/addons/payment/models/account_payment.py +++ b/addons/payment/models/account_payment.py @@ -1,35 +1,58 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import _, api, fields, models +from odoo import _, api, Command, fields, models from odoo.exceptions import ValidationError class AccountPayment(models.Model): _inherit = 'account.payment' + # == Business fields == payment_transaction_id = fields.Many2one( string="Payment Transaction", comodel_name='payment.transaction', readonly=True) payment_token_id = fields.Many2one( string="Saved Payment Token", comodel_name='payment.token', domain="""[ - (payment_method_code == 'electronic', '=', 1), - ('company_id', '=', company_id), - ('acquirer_id.capture_manually', '=', False), - ('acquirer_id.journal_id', '=', journal_id), - ('partner_id', 'in', related_partner_ids), + ('id', 'in', suitable_payment_token_ids), ]""", help="Note that only tokens from acquirers allowing to capture the amount are available.") - related_partner_ids = fields.Many2many( - comodel_name='res.partner', compute='_compute_related_partners') - @api.depends('partner_id.commercial_partner_id.child_ids') - def _compute_related_partners(self): + # == Display purpose fields == + suitable_payment_token_ids = fields.Many2many( + comodel_name='payment.token', + compute='_compute_suitable_payment_token_ids' + ) + use_electronic_payment_method = fields.Boolean( + compute='_compute_use_electronic_payment_method', + help='Technical field used to hide or show the payment_token_id if needed.' + ) + + @api.depends('payment_method_id') + def _compute_suitable_payment_token_ids(self): for payment in self: - payment.related_partner_ids = ( + related_partner_ids = ( payment.partner_id | payment.partner_id.commercial_partner_id | payment.partner_id.commercial_partner_id.child_ids )._origin + if payment.use_electronic_payment_method: + payment.suitable_payment_token_ids = self.env['payment.token'].search([ + ('company_id', '=', payment.company_id.id), + ('acquirer_id.capture_manually', '=', False), + ('partner_id', 'in', related_partner_ids.ids), + ]).filtered(lambda t: t.acquirer_id.journal_id == payment.journal_id.id) + else: + payment.suitable_payment_token_ids = [Command.clear()] + + @api.depends('payment_method_id') + def _compute_use_electronic_payment_method(self): + for payment in self: + # Get a list of all electronic payment method codes. + # These codes are comprised of 'electronic' and the providers of each payment acquirer. + codes = [key for key in dict(self.env['payment.acquirer']._fields['provider']._description_selection(self.env))] + codes.append('electronic') + payment.use_electronic_payment_method = payment.payment_method_code in codes + @api.onchange('partner_id', 'payment_method_id', 'journal_id') def _onchange_set_payment_token_id(self): if not (self.payment_method_code == 'electronic' and self.partner_id and self.journal_id): diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index 3bf26313be1..aace35c59bb 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -1,7 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import logging -import psycopg2 from odoo import _, api, fields, models, SUPERUSER_ID from odoo.exceptions import ValidationError @@ -10,12 +9,6 @@ from odoo.osv import expression _logger = logging.getLogger(__name__) -def create_missing_journals(cr, registry): - """ Post-init hook responsible for the creation of a journal for all acquirers missing one. """ - env = api.Environment(cr, SUPERUSER_ID, {}) - env['payment.acquirer']._create_missing_journals() - - class PaymentAcquirer(models.Model): _name = 'payment.acquirer' _description = 'Payment Acquirer' @@ -66,9 +59,9 @@ class PaymentAcquirer(models.Model): "If none is set, it is available for all countries.") journal_id = fields.Many2one( string="Payment Journal", comodel_name='account.journal', - copy=False, + compute='_compute_journal_id', inverse='_inverse_journal_id', help="The journal in which the successful transactions are posted", - domain="[('type', 'in', ['bank', 'cash']), ('company_id', '=', company_id)]") + domain="[('type', '=', 'bank'), ('company_id', '=', company_id)]") # Fees fields fees_active = fields.Boolean(string="Add Extra Fees") @@ -171,30 +164,33 @@ class PaymentAcquirer(models.Model): 'show_cancel_msg': True, }) - #=== ONCHANGE METHODS ===# - - @api.onchange('state') - def _onchange_state(self): - """ Only enable dashboard display for journals of enabled acquirers. - - :return: None - """ + def _compute_journal_id(self): for acquirer in self: - acquirer.journal_id.show_on_dashboard = acquirer.state == 'enabled' + payment_method = self.env['account.payment.method.line'].search([ + ('journal_id.company_id', '=', acquirer.company_id.id), + ('code', '=', acquirer.provider) + ], limit=1) + if payment_method: + acquirer.journal_id = payment_method.journal_id + else: + acquirer.journal_id = False - @api.onchange('allow_tokenization') - def _onchange_allow_tokenization(self): - """ Add (remove) the electronic payment method for acquirers (not) allowing tokenization. - - :return: None - """ - electronic = self.env.ref('payment.account_payment_method_electronic_in') + def _inverse_journal_id(self): for acquirer in self: - if acquirer.allow_tokenization: - if electronic not in acquirer.journal_id.inbound_payment_method_ids: - acquirer.journal_id.inbound_payment_method_ids = [(4, electronic.id)] - elif electronic in acquirer.journal_id.inbound_payment_method_ids: - acquirer.journal_id.inbound_payment_method_ids = [(3, electronic.id)] + payment_method = self.env['account.payment.method.line'].search([ + ('journal_id.company_id', '=', acquirer.company_id.id), + ('code', '=', acquirer.provider) + ], limit=1) + if acquirer.journal_id: + if not payment_method: + self.env['account.payment.method.line'].create({ + 'payment_method_id': self._get_default_payment_method(), + 'journal_id': self.journal_id.id, + }) + else: + payment_method.journal_id = acquirer.journal_id + elif payment_method: + payment_method.unlink() #=== CONSTRAINT METHODS ===# @@ -250,95 +246,6 @@ class PaymentAcquirer(models.Model): _("The following fields must be filled: %s", ", ".join(field_names)) ) - @api.model - def _create_missing_journals(self, company=None): - """ Create a journal for installed acquirers missing one. - - Each acquirer must have its own journal. It can't however be created along the - `payment.acquirer` record because there is no guarantee that the chart template is already - installed. - - :param recordset company: The company for which the journals are created, as a `res.company` - recordset - :return: The created journals - :rtype: recordset of `account.journal` - """ - # Search for installed acquirer modules having no journal for the current company - company = company or self.env.company - acquirers = self.env['payment.acquirer'].search([ - ('journal_id', '=', False), - ('company_id', '=', company.id), - ('module_state', 'in', ('to install', 'installed')), - ]) - - # Create or find the missing journals. - # This is done in this order and not the other way around because the most common cause for - # a missing journal is the first install of an acquirer's module. The other (less common) - # cause is a re-install. In this last case, the creation will fail because of a unique - # constraint violation, we catch the error, and fallback on searching the previous journal. - Journal = journals = self.env['account.journal'] - for acquirer in acquirers.filtered('company_id.chart_template_id'): - try: - with self.env.cr.savepoint(): - journal = Journal.create(acquirer._get_journal_create_values()) - except psycopg2.IntegrityError as error: # Journal already exists - if error.pgcode == psycopg2.errorcodes.UNIQUE_VIOLATION: - journal = Journal.search(acquirer._get_journal_search_domain(), limit=1) - else: - raise error - acquirer.journal_id = journal - journals += journal - return journals - - def _get_journal_create_values(self): - """ Return a dict of values to create the acquirer's journal. - - Note: self.ensure_one() - - :return: The dict of create values for `account.journal` - :rtype: dict - """ - self.ensure_one() - - account_vals = self.company_id.chart_template_id. \ - _prepare_transfer_account_for_direct_creation(self.name, self.company_id) - account = self.env['account.account'].create(account_vals) - inbound_payment_method_ids = [] - if self.allow_tokenization: - inbound_payment_method_ids.append( - (4, self.env.ref('payment.account_payment_method_electronic_in').id) - ) - return { - 'name': self.name, - 'code': self.name.upper(), - 'sequence': 999, - 'type': 'bank', - 'company_id': self.company_id.id, - 'default_account_id': account.id, - # Show the journal on dashboard if the acquirer is published on the website. - 'show_on_dashboard': self.state == 'enabled', - # Don't show payment methods in the backend - 'inbound_payment_method_ids': inbound_payment_method_ids, - 'outbound_payment_method_ids': [], - } - - def _get_journal_search_domain(self): - """ Return a domain for searching a journal corresponding to the acquirer. - - Note: self.ensure_one() - - :return: The search domain - :rtype: list - """ - self.ensure_one() - - code_cutoff = self.env['account.journal']._fields['code'].size - return [ - ('name', '=', self.name), - ('code', '=', self.name.upper()[:code_cutoff]), - ('company_id', '=', self.company_id.id), - ] - #=== ACTION METHODS ===# def button_immediate_install(self): @@ -481,3 +388,7 @@ class PaymentAcquirer(models.Model): """ self.ensure_one() return self.journal_id.currency_id or self.company_id.currency_id + + def _get_default_payment_method(self): + self.ensure_one() + return self.env.ref('account.account_payment_method_manual_in').id diff --git a/addons/payment/models/payment_transaction.py b/addons/payment/models/payment_transaction.py index 733d308440c..4ba95589546 100644 --- a/addons/payment/models/payment_transaction.py +++ b/addons/payment/models/payment_transaction.py @@ -819,6 +819,7 @@ class PaymentTransaction(models.Model): """ self.ensure_one() + payment_method = self.env['account.payment.method'].search([('code', '=', self.acquirer_id.provider)], limit=1) payment_values = { 'amount': self.amount, 'payment_type': 'inbound' if self.amount > 0 else 'outbound', @@ -827,7 +828,7 @@ class PaymentTransaction(models.Model): 'partner_type': 'customer', 'journal_id': self.acquirer_id.journal_id.id, 'company_id': self.acquirer_id.company_id.id, - 'payment_method_id': self.env.ref('payment.account_payment_method_electronic_in').id, + 'payment_method_id': payment_method.id, 'payment_token_id': self.token_id.id, 'payment_transaction_id': self.id, 'ref': self.reference, diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py index 89428d7934a..a33745b7b10 100644 --- a/addons/payment/tests/common.py +++ b/addons/payment/tests/common.py @@ -1,7 +1,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import logging - +from unittest.mock import patch +from odoo.addons.account.models.account_payment_method import AccountPaymentMethod from odoo.fields import Command from odoo.addons.payment.tests.utils import PaymentTestUtils @@ -15,6 +16,13 @@ class PaymentCommon(PaymentTestUtils): def setUpClass(cls, chart_template_ref=None): super().setUpClass(chart_template_ref=chart_template_ref) + Method_get_payment_method_information = AccountPaymentMethod._get_payment_method_information + + def _get_payment_method_information(self): + res = Method_get_payment_method_information(self) + res['none'] = {'mode': 'multi', 'domain': [('type', '=', 'bank')]} + return res + cls.currency_euro = cls._prepare_currency('EUR') cls.currency_usd = cls._prepare_currency('USD') @@ -68,6 +76,13 @@ class PaymentCommon(PaymentTestUtils): 'type': 'qweb', 'arch': arch, }) + + with patch.object(AccountPaymentMethod, '_get_payment_method_information', _get_payment_method_information): + cls.env['account.payment.method'].create({ + 'name': 'Dummy method', + 'code': 'none', + 'payment_type': 'inbound' + }) cls.dummy_acquirer = cls.env['payment.acquirer'].create({ 'name': "Dummy Acquirer", 'provider': 'none', diff --git a/addons/payment/views/account_payment_views.xml b/addons/payment/views/account_payment_views.xml index a484b69799d..d287acb9c5a 100644 --- a/addons/payment/views/account_payment_views.xml +++ b/addons/payment/views/account_payment_views.xml @@ -7,13 +7,14 @@ - + - + + + attrs="{'invisible': [('use_electronic_payment_method', '!=', True)], 'readonly': [('state', '!=', 'draft')]}"/> diff --git a/addons/payment/wizards/account_payment_register.py b/addons/payment/wizards/account_payment_register.py index e826b37219d..34938123ef2 100644 --- a/addons/payment/wizards/account_payment_register.py +++ b/addons/payment/wizards/account_payment_register.py @@ -1,4 +1,4 @@ -from odoo import models, fields, api, _ +from odoo import api, Command, fields, models class AccountPaymentRegister(models.TransientModel): @@ -11,19 +11,20 @@ class AccountPaymentRegister(models.TransientModel): store=True, readonly=False, compute='_compute_payment_token_id', domain='''[ - (payment_method_code == 'electronic', '=', 1), - ('company_id', '=', company_id), - ('acquirer_id.capture_manually', '=', False), - ('acquirer_id.journal_id', '=', journal_id), - ('partner_id', 'in', suitable_payment_token_partner_ids), + ('id', 'in', suitable_payment_token_ids), ]''', help="Note that tokens from acquirers set to only authorize transactions (instead of capturing the amount) are " "not available.") # == Display purpose fields == - suitable_payment_token_partner_ids = fields.Many2many( - comodel_name='res.partner', - compute='_compute_suitable_payment_token_partner_ids') + suitable_payment_token_ids = fields.Many2many( + comodel_name='payment.token', + compute='_compute_suitable_payment_token_ids' + ) + use_electronic_payment_method = fields.Boolean( + compute='_compute_use_electronic_payment_method', + help='Technical field used to hide or show the payment_token_id if needed.' + ) payment_method_code = fields.Char( related='payment_method_id.code') @@ -31,17 +32,32 @@ class AccountPaymentRegister(models.TransientModel): # COMPUTE METHODS # ------------------------------------------------------------------------- - @api.depends('can_edit_wizard') - def _compute_suitable_payment_token_partner_ids(self): + @api.depends('payment_method_id') + def _compute_suitable_payment_token_ids(self): for wizard in self: - if wizard.can_edit_wizard: - lines = wizard._get_batches()[0]['lines'] - partners = lines.partner_id - commercial_partners = partners.commercial_partner_id - children_partners = commercial_partners.child_ids - wizard.suitable_payment_token_partner_ids = (partners + commercial_partners + children_partners)._origin + if wizard.can_edit_wizard and wizard.use_electronic_payment_method: + related_partner_ids = ( + wizard.partner_id + | wizard.partner_id.commercial_partner_id + | wizard.partner_id.commercial_partner_id.child_ids + )._origin + + wizard.suitable_payment_token_ids = self.env['payment.token'].search([ + ('company_id', '=', wizard.company_id.id), + ('acquirer_id.capture_manually', '=', False), + ('partner_id', 'in', related_partner_ids.ids), + ]).filtered(lambda t: t.acquirer_id.journal_id == wizard.journal_id.id) else: - wizard.suitable_payment_token_partner_ids = False + wizard.suitable_payment_token_ids = [Command.clear()] + + @api.depends('payment_method_id') + def _compute_use_electronic_payment_method(self): + for wizard in self: + # Get a list of all electronic payment method codes. + # These codes are comprised of 'electronic' and the providers of each payment acquirer. + codes = [key for key in dict(self.env['payment.acquirer']._fields['provider']._description_selection(self.env))] + codes.append('electronic') + wizard.use_electronic_payment_method = wizard.payment_method_code in codes @api.onchange('can_edit_wizard', 'payment_method_id', 'journal_id') def _compute_payment_token_id(self): diff --git a/addons/payment/wizards/account_payment_register_views.xml b/addons/payment/wizards/account_payment_register_views.xml index a1db97cc74c..ad8278bd6ff 100644 --- a/addons/payment/wizards/account_payment_register_views.xml +++ b/addons/payment/wizards/account_payment_register_views.xml @@ -8,10 +8,11 @@ - + + + attrs="{'invisible': ['|', ('use_electronic_payment_method', '!=', True), '|', ('can_edit_wizard', '=', False), '&', ('can_group_payments', '=', True), ('group_payment', '=', False)]}"/> diff --git a/addons/payment_adyen/__init__.py b/addons/payment_adyen/__init__.py index aed6fceb8ec..7627ceef542 100644 --- a/addons/payment_adyen/__init__.py +++ b/addons/payment_adyen/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_adyen/__manifest__.py b/addons/payment_adyen/__manifest__.py index acca464c070..9184104c227 100644 --- a/addons/payment_adyen/__manifest__.py +++ b/addons/payment_adyen/__manifest__.py @@ -14,7 +14,6 @@ 'data/payment_acquirer_data.xml', # Depends on views/payment_adyen_templates.xml ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', 'assets': { 'web.assets_frontend': [ diff --git a/addons/payment_adyen/data/payment_acquirer_data.xml b/addons/payment_adyen/data/payment_acquirer_data.xml index 4c2fccf496e..e6c95454230 100644 --- a/addons/payment_adyen/data/payment_acquirer_data.xml +++ b/addons/payment_adyen/data/payment_acquirer_data.xml @@ -10,4 +10,10 @@ True + + Adyen + adyen + inbound + + diff --git a/addons/payment_adyen/models/__init__.py b/addons/payment_adyen/models/__init__.py index 22eb69117db..2303108a7c9 100644 --- a/addons/payment_adyen/models/__init__.py +++ b/addons/payment_adyen/models/__init__.py @@ -1,5 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_token from . import payment_transaction diff --git a/addons/payment_adyen/models/account_payment_method.py b/addons/payment_adyen/models/account_payment_method.py new file mode 100644 index 00000000000..e5344413810 --- /dev/null +++ b/addons/payment_adyen/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['adyen'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_adyen/models/payment_acquirer.py b/addons/payment_adyen/models/payment_acquirer.py index 7f91ea992f8..5c259aaba19 100644 --- a/addons/payment_adyen/models/payment_acquirer.py +++ b/addons/payment_adyen/models/payment_acquirer.py @@ -117,3 +117,9 @@ class PaymentAcquirer(models.Model): :rtype: str """ return f'ODOO_PARTNER_{partner_id}' + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'adyen': + return super()._get_default_payment_method() + return self.env.ref('payment_adyen.payment_method_adyen').id diff --git a/addons/payment_alipay/__init__.py b/addons/payment_alipay/__init__.py index eddb86ff1c1..4bc8ac694f5 100644 --- a/addons/payment_alipay/__init__.py +++ b/addons/payment_alipay/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_alipay/__manifest__.py b/addons/payment_alipay/__manifest__.py index 442c2a152d0..b7cbde5289d 100644 --- a/addons/payment_alipay/__manifest__.py +++ b/addons/payment_alipay/__manifest__.py @@ -14,6 +14,5 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_alipay/data/payment_acquirer_data.xml b/addons/payment_alipay/data/payment_acquirer_data.xml index a8d9a1f578c..d25bc887e16 100644 --- a/addons/payment_alipay/data/payment_acquirer_data.xml +++ b/addons/payment_alipay/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + Alipay + alipay + inbound + + diff --git a/addons/payment_alipay/models/__init__.py b/addons/payment_alipay/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_alipay/models/__init__.py +++ b/addons/payment_alipay/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_alipay/models/account_payment_method.py b/addons/payment_alipay/models/account_payment_method.py new file mode 100644 index 00000000000..ca552ea1014 --- /dev/null +++ b/addons/payment_alipay/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['alipay'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_alipay/models/payment_acquirer.py b/addons/payment_alipay/models/payment_acquirer.py index 291eab157f9..38551ee40a0 100644 --- a/addons/payment_alipay/models/payment_acquirer.py +++ b/addons/payment_alipay/models/payment_acquirer.py @@ -58,3 +58,9 @@ class PaymentAcquirer(models.Model): return 'https://mapi.alipay.com/gateway.do' else: # test environment return 'https://openapi.alipaydev.com/gateway.do' + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'alipay': + return super()._get_default_payment_method() + return self.env.ref('payment_alipay.payment_method_alipay').id diff --git a/addons/payment_authorize/__init__.py b/addons/payment_authorize/__init__.py index d338ed54df9..22957034603 100644 --- a/addons/payment_authorize/__init__.py +++ b/addons/payment_authorize/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_authorize/__manifest__.py b/addons/payment_authorize/__manifest__.py index c1215dbbbae..16957c61488 100644 --- a/addons/payment_authorize/__manifest__.py +++ b/addons/payment_authorize/__manifest__.py @@ -14,7 +14,6 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', 'assets': { 'web.assets_frontend': [ diff --git a/addons/payment_authorize/data/payment_acquirer_data.xml b/addons/payment_authorize/data/payment_acquirer_data.xml index bb66a4704fb..222bdb45f85 100644 --- a/addons/payment_authorize/data/payment_acquirer_data.xml +++ b/addons/payment_authorize/data/payment_acquirer_data.xml @@ -10,4 +10,10 @@ True + + Authorize.Net + authorize + inbound + + diff --git a/addons/payment_authorize/models/__init__.py b/addons/payment_authorize/models/__init__.py index 22eb69117db..2303108a7c9 100644 --- a/addons/payment_authorize/models/__init__.py +++ b/addons/payment_authorize/models/__init__.py @@ -1,5 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_token from . import payment_transaction diff --git a/addons/payment_authorize/models/account_payment_method.py b/addons/payment_authorize/models/account_payment_method.py new file mode 100644 index 00000000000..bf78f232f43 --- /dev/null +++ b/addons/payment_authorize/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['authorize'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_authorize/models/payment_acquirer.py b/addons/payment_authorize/models/payment_acquirer.py index fb8ced9f8bc..7b1b2825193 100644 --- a/addons/payment_authorize/models/payment_acquirer.py +++ b/addons/payment_authorize/models/payment_acquirer.py @@ -92,3 +92,9 @@ class PaymentAcquirer(models.Model): return res return self.authorize_currency_id + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'authorize': + return super()._get_default_payment_method() + return self.env.ref('payment_authorize.payment_method_authorize').id diff --git a/addons/payment_buckaroo/__init__.py b/addons/payment_buckaroo/__init__.py index 43c88da84e3..5b385b2d908 100644 --- a/addons/payment_buckaroo/__init__.py +++ b/addons/payment_buckaroo/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_buckaroo/__manifest__.py b/addons/payment_buckaroo/__manifest__.py index 1be68e8b107..586b331040c 100644 --- a/addons/payment_buckaroo/__manifest__.py +++ b/addons/payment_buckaroo/__manifest__.py @@ -14,6 +14,5 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_buckaroo/data/payment_acquirer_data.xml b/addons/payment_buckaroo/data/payment_acquirer_data.xml index 09c7ce95945..e25e09cec15 100644 --- a/addons/payment_buckaroo/data/payment_acquirer_data.xml +++ b/addons/payment_buckaroo/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + Buckaroo + buckaroo + inbound + + diff --git a/addons/payment_buckaroo/models/__init__.py b/addons/payment_buckaroo/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_buckaroo/models/__init__.py +++ b/addons/payment_buckaroo/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_buckaroo/models/account_payment_method.py b/addons/payment_buckaroo/models/account_payment_method.py new file mode 100644 index 00000000000..68b5d007c78 --- /dev/null +++ b/addons/payment_buckaroo/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['buckaroo'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_buckaroo/models/payment_acquirer.py b/addons/payment_buckaroo/models/payment_acquirer.py index 5b298e8401e..9be343b1b74 100644 --- a/addons/payment_buckaroo/models/payment_acquirer.py +++ b/addons/payment_buckaroo/models/payment_acquirer.py @@ -63,3 +63,9 @@ class PaymentAcquirer(models.Model): sign_string += self.buckaroo_secret_key # Calculate the SHA-1 hash over the signing string return sha1(sign_string.encode('utf-8')).hexdigest() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'buckaroo': + return super()._get_default_payment_method() + return self.env.ref('payment_buckaroo.payment_method_buckaroo').id diff --git a/addons/payment_odoo/__init__.py b/addons/payment_odoo/__init__.py index 9fe1f558a00..816928efc22 100644 --- a/addons/payment_odoo/__init__.py +++ b/addons/payment_odoo/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_odoo/__manifest__.py b/addons/payment_odoo/__manifest__.py index 07de8fad857..b2a87fd5cc1 100644 --- a/addons/payment_odoo/__manifest__.py +++ b/addons/payment_odoo/__manifest__.py @@ -15,6 +15,5 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_odoo/data/payment_acquirer_data.xml b/addons/payment_odoo/data/payment_acquirer_data.xml index ac585037e32..f2bf5b2ccd0 100644 --- a/addons/payment_odoo/data/payment_acquirer_data.xml +++ b/addons/payment_odoo/data/payment_acquirer_data.xml @@ -10,4 +10,10 @@ True + + Odoo + odoo + inbound + + diff --git a/addons/payment_odoo/models/__init__.py b/addons/payment_odoo/models/__init__.py index ba88253ca9c..447999fe187 100644 --- a/addons/payment_odoo/models/__init__.py +++ b/addons/payment_odoo/models/__init__.py @@ -3,6 +3,7 @@ from . import account_move from . import adyen_account from . import adyen_transaction +from . import account_payment_method from . import payment_acquirer from . import payment_token from . import payment_transaction diff --git a/addons/payment_odoo/models/account_payment_method.py b/addons/payment_odoo/models/account_payment_method.py new file mode 100644 index 00000000000..586d4da6ca3 --- /dev/null +++ b/addons/payment_odoo/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['odoo'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_odoo/models/payment_acquirer.py b/addons/payment_odoo/models/payment_acquirer.py index f0ef0ee8dff..2403906b6e7 100644 --- a/addons/payment_odoo/models/payment_acquirer.py +++ b/addons/payment_odoo/models/payment_acquirer.py @@ -32,3 +32,9 @@ class PaymentAcquirer(models.Model): :rtype: str """ return f'{self.odoo_adyen_account_id.adyen_uuid}_{partner_id}' + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'odoo': + return super()._get_default_payment_method() + return self.env.ref('payment_odoo.payment_method_odoo').id diff --git a/addons/payment_ogone/__init__.py b/addons/payment_ogone/__init__.py index a852ddecf9d..186e6a3ded9 100644 --- a/addons/payment_ogone/__init__.py +++ b/addons/payment_ogone/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_ogone/__manifest__.py b/addons/payment_ogone/__manifest__.py index 0959dc5e627..9e253e2ff04 100644 --- a/addons/payment_ogone/__manifest__.py +++ b/addons/payment_ogone/__manifest__.py @@ -14,6 +14,5 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_ogone/data/payment_acquirer_data.xml b/addons/payment_ogone/data/payment_acquirer_data.xml index bb02c17fd80..4d3cf79f467 100644 --- a/addons/payment_ogone/data/payment_acquirer_data.xml +++ b/addons/payment_ogone/data/payment_acquirer_data.xml @@ -9,5 +9,11 @@ True True + + + Ogone + ogone + inbound + diff --git a/addons/payment_ogone/models/__init__.py b/addons/payment_ogone/models/__init__.py index 22eb69117db..2303108a7c9 100644 --- a/addons/payment_ogone/models/__init__.py +++ b/addons/payment_ogone/models/__init__.py @@ -1,5 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_token from . import payment_transaction diff --git a/addons/payment_ogone/models/account_payment_method.py b/addons/payment_ogone/models/account_payment_method.py new file mode 100644 index 00000000000..2dcb8174c66 --- /dev/null +++ b/addons/payment_ogone/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['ogone'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_ogone/models/payment_acquirer.py b/addons/payment_ogone/models/payment_acquirer.py index f3fdaec9c6e..0e18bd6d7ec 100644 --- a/addons/payment_ogone/models/payment_acquirer.py +++ b/addons/payment_ogone/models/payment_acquirer.py @@ -120,3 +120,9 @@ class PaymentAcquirer(models.Model): _logger.exception("invalid API request at %s with data %s", url, payload) raise ValidationError("Ogone: " + _("The communication with the API failed.")) return response.content + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'ogone': + return super()._get_default_payment_method() + return self.env.ref('payment_ogone.payment_method_ogone').id diff --git a/addons/payment_paypal/__init__.py b/addons/payment_paypal/__init__.py index 27fdcd688d3..bb623f55af5 100644 --- a/addons/payment_paypal/__init__.py +++ b/addons/payment_paypal/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_paypal/__manifest__.py b/addons/payment_paypal/__manifest__.py index 0935c755827..de2e0e3e0c3 100644 --- a/addons/payment_paypal/__manifest__.py +++ b/addons/payment_paypal/__manifest__.py @@ -15,6 +15,5 @@ 'data/payment_paypal_email_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_paypal/data/payment_acquirer_data.xml b/addons/payment_paypal/data/payment_acquirer_data.xml index f68b7eb2b4c..f3ed608369f 100644 --- a/addons/payment_paypal/data/payment_acquirer_data.xml +++ b/addons/payment_paypal/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + Paypal + paypal + inbound + + diff --git a/addons/payment_paypal/models/__init__.py b/addons/payment_paypal/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_paypal/models/__init__.py +++ b/addons/payment_paypal/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_paypal/models/account_payment_method.py b/addons/payment_paypal/models/account_payment_method.py new file mode 100644 index 00000000000..14df1f23d1e --- /dev/null +++ b/addons/payment_paypal/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['paypal'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_paypal/models/payment_acquirer.py b/addons/payment_paypal/models/payment_acquirer.py index 648b4a0e093..0d8813b934f 100644 --- a/addons/payment_paypal/models/payment_acquirer.py +++ b/addons/payment_paypal/models/payment_acquirer.py @@ -65,3 +65,9 @@ class PaymentAcquirer(models.Model): 'author_id': self.create_uid.partner_id.id, } self.env['mail.mail'].sudo().create(mail_values).send() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'paypal': + return super()._get_default_payment_method() + return self.env.ref('payment_paypal.payment_method_paypal').id diff --git a/addons/payment_payulatam/__init__.py b/addons/payment_payulatam/__init__.py index c56ff5159ac..0408be81401 100644 --- a/addons/payment_payulatam/__init__.py +++ b/addons/payment_payulatam/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_payulatam/__manifest__.py b/addons/payment_payulatam/__manifest__.py index 5c04525a204..7993e48ca92 100644 --- a/addons/payment_payulatam/__manifest__.py +++ b/addons/payment_payulatam/__manifest__.py @@ -14,6 +14,5 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_payulatam/data/payment_acquirer_data.xml b/addons/payment_payulatam/data/payment_acquirer_data.xml index 892bd5a2f0e..5d6d5283ba8 100644 --- a/addons/payment_payulatam/data/payment_acquirer_data.xml +++ b/addons/payment_payulatam/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + payulatam + payulatam + inbound + + diff --git a/addons/payment_payulatam/models/__init__.py b/addons/payment_payulatam/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_payulatam/models/__init__.py +++ b/addons/payment_payulatam/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_payulatam/models/account_payment_method.py b/addons/payment_payulatam/models/account_payment_method.py new file mode 100644 index 00000000000..18139d1f690 --- /dev/null +++ b/addons/payment_payulatam/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['payulatam'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_payulatam/models/payment_acquirer.py b/addons/payment_payulatam/models/payment_acquirer.py index 6010c8b9be7..d3833e3dede 100644 --- a/addons/payment_payulatam/models/payment_acquirer.py +++ b/addons/payment_payulatam/models/payment_acquirer.py @@ -68,3 +68,9 @@ class PaymentAcquirer(models.Model): values['currency'], ]) return md5(data_string.encode('utf-8')).hexdigest() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'payulatam': + return super()._get_default_payment_method() + return self.env.ref('payment_payulatam.payment_method_payulatam').id diff --git a/addons/payment_payumoney/__init__.py b/addons/payment_payumoney/__init__.py index 472a51c2c4c..6765de37d7e 100644 --- a/addons/payment_payumoney/__init__.py +++ b/addons/payment_payumoney/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_payumoney/__manifest__.py b/addons/payment_payumoney/__manifest__.py index e0d4826eea2..5adcbd5bd6b 100644 --- a/addons/payment_payumoney/__manifest__.py +++ b/addons/payment_payumoney/__manifest__.py @@ -18,6 +18,5 @@ PayUmoney payment gateway supports only INR currency. 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_payumoney/data/payment_acquirer_data.xml b/addons/payment_payumoney/data/payment_acquirer_data.xml index 3e204767c4d..faaf9d2b73b 100644 --- a/addons/payment_payumoney/data/payment_acquirer_data.xml +++ b/addons/payment_payumoney/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + PayUmoney + payumoney + inbound + + diff --git a/addons/payment_payumoney/models/__init__.py b/addons/payment_payumoney/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_payumoney/models/__init__.py +++ b/addons/payment_payumoney/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_payumoney/models/account_payment_method.py b/addons/payment_payumoney/models/account_payment_method.py new file mode 100644 index 00000000000..f440153ef1d --- /dev/null +++ b/addons/payment_payumoney/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['payumoney'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_payumoney/models/payment_acquirer.py b/addons/payment_payumoney/models/payment_acquirer.py index 282b45f052b..73b4337f65a 100644 --- a/addons/payment_payumoney/models/payment_acquirer.py +++ b/addons/payment_payumoney/models/payment_acquirer.py @@ -49,3 +49,9 @@ class PaymentAcquirer(models.Model): keys = 'key|txnid|amount|productinfo|firstname|email|udf1|udf2|udf3|udf4|udf5||||||salt' sign = '|'.join(f'{sign_values.get(k) or ""}' for k in keys.split('|')) return hashlib.sha512(sign.encode('utf-8')).hexdigest() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'payumoney': + return super()._get_default_payment_method() + return self.env.ref('payment_payumoney.payment_method_payumoney').id diff --git a/addons/payment_sips/__init__.py b/addons/payment_sips/__init__.py index ba88cb2944c..a4666ef725d 100644 --- a/addons/payment_sips/__init__.py +++ b/addons/payment_sips/__init__.py @@ -4,7 +4,6 @@ from . import models from . import controllers from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_sips/__manifest__.py b/addons/payment_sips/__manifest__.py index c6628c76a1a..7907dddd4e6 100644 --- a/addons/payment_sips/__manifest__.py +++ b/addons/payment_sips/__manifest__.py @@ -19,6 +19,5 @@ not guaranteed.""", 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_sips/data/payment_acquirer_data.xml b/addons/payment_sips/data/payment_acquirer_data.xml index 043cbece8a3..95c766fd3ef 100644 --- a/addons/payment_sips/data/payment_acquirer_data.xml +++ b/addons/payment_sips/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ False + + Sips + sips + inbound + + diff --git a/addons/payment_sips/models/__init__.py b/addons/payment_sips/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_sips/models/__init__.py +++ b/addons/payment_sips/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_sips/models/account_payment_method.py b/addons/payment_sips/models/account_payment_method.py new file mode 100644 index 00000000000..ad8f59d4141 --- /dev/null +++ b/addons/payment_sips/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['sips'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_sips/models/payment_acquirer.py b/addons/payment_sips/models/payment_acquirer.py index b96a2c17446..8e43ebf89bf 100644 --- a/addons/payment_sips/models/payment_acquirer.py +++ b/addons/payment_sips/models/payment_acquirer.py @@ -54,3 +54,9 @@ class PaymentAcquirer(models.Model): key = self.sips_secret shasign = sha256((data + key).encode('utf-8')) return shasign.hexdigest() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'sips': + return super()._get_default_payment_method() + return self.env.ref('payment_sips.payment_method_sips').id diff --git a/addons/payment_stripe/__init__.py b/addons/payment_stripe/__init__.py index f11a519ce7b..72c8c7887ad 100644 --- a/addons/payment_stripe/__init__.py +++ b/addons/payment_stripe/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_stripe/__manifest__.py b/addons/payment_stripe/__manifest__.py index 24d9ef4d1c6..355682b909f 100644 --- a/addons/payment_stripe/__manifest__.py +++ b/addons/payment_stripe/__manifest__.py @@ -14,7 +14,6 @@ 'data/payment_acquirer_data.xml', ], 'application': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', 'assets': { 'web.assets_frontend': [ diff --git a/addons/payment_stripe/data/payment_acquirer_data.xml b/addons/payment_stripe/data/payment_acquirer_data.xml index 30396ead025..7e76bdcc091 100644 --- a/addons/payment_stripe/data/payment_acquirer_data.xml +++ b/addons/payment_stripe/data/payment_acquirer_data.xml @@ -9,4 +9,10 @@ True + + Stripe + stripe + inbound + + diff --git a/addons/payment_stripe/models/__init__.py b/addons/payment_stripe/models/__init__.py index 22eb69117db..2303108a7c9 100644 --- a/addons/payment_stripe/models/__init__.py +++ b/addons/payment_stripe/models/__init__.py @@ -1,5 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_token from . import payment_transaction diff --git a/addons/payment_stripe/models/account_payment_method.py b/addons/payment_stripe/models/account_payment_method.py new file mode 100644 index 00000000000..9f74eb9979e --- /dev/null +++ b/addons/payment_stripe/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['stripe'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_stripe/models/payment_acquirer.py b/addons/payment_stripe/models/payment_acquirer.py index a35fdcdd463..85fa1d5f103 100644 --- a/addons/payment_stripe/models/payment_acquirer.py +++ b/addons/payment_stripe/models/payment_acquirer.py @@ -84,3 +84,9 @@ class PaymentAcquirer(models.Model): _logger.exception("unable to reach endpoint at %s", url) raise ValidationError("Stripe: " + _("Could not establish the connection to the API.")) return response.json() + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'stripe': + return super()._get_default_payment_method() + return self.env.ref('payment_stripe.payment_method_stripe').id diff --git a/addons/payment_test/__init__.py b/addons/payment_test/__init__.py index 3237f394099..261dde99df2 100644 --- a/addons/payment_test/__init__.py +++ b/addons/payment_test/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_test/__manifest__.py b/addons/payment_test/__manifest__.py index 356c5e48b7b..205f1952ddb 100644 --- a/addons/payment_test/__manifest__.py +++ b/addons/payment_test/__manifest__.py @@ -13,7 +13,6 @@ It should never be used in production environment. Make sure to disable it befor 'views/payment_test_templates.xml', 'data/payment_acquirer_data.xml', ], - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', 'assets': { 'web.assets_frontend': [ diff --git a/addons/payment_test/data/payment_acquirer_data.xml b/addons/payment_test/data/payment_acquirer_data.xml index a4c9ffed3e5..3aee823aee6 100644 --- a/addons/payment_test/data/payment_acquirer_data.xml +++ b/addons/payment_test/data/payment_acquirer_data.xml @@ -8,7 +8,12 @@ False True True - test + + + + Test + test + inbound diff --git a/addons/payment_test/models/__init__.py b/addons/payment_test/models/__init__.py index 8e04237423a..28c8703fcc1 100644 --- a/addons/payment_test/models/__init__.py +++ b/addons/payment_test/models/__init__.py @@ -1,4 +1,5 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import account_payment_method from . import payment_acquirer from . import payment_transaction diff --git a/addons/payment_test/models/account_payment_method.py b/addons/payment_test/models/account_payment_method.py new file mode 100644 index 00000000000..016c2c08f12 --- /dev/null +++ b/addons/payment_test/models/account_payment_method.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class AccountPaymentMethod(models.Model): + _inherit = 'account.payment.method' + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res['test'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]} + return res diff --git a/addons/payment_test/models/payment_acquirer.py b/addons/payment_test/models/payment_acquirer.py index d2130487e48..41367eb5445 100644 --- a/addons/payment_test/models/payment_acquirer.py +++ b/addons/payment_test/models/payment_acquirer.py @@ -22,3 +22,9 @@ class PaymentAcquirer(models.Model): def _check_acquirer_state(self): if self.filtered(lambda a: a.provider == 'test' and a.state not in ('test', 'disabled')): raise UserError(_("Test acquirers should never be enabled.")) + + def _get_default_payment_method(self): + self.ensure_one() + if self.provider != 'test': + return super()._get_default_payment_method() + return self.env.ref('payment_test.payment_method_test').id diff --git a/addons/payment_transfer/__init__.py b/addons/payment_transfer/__init__.py index 401b3fe0d4e..ae8fd5b6faa 100644 --- a/addons/payment_transfer/__init__.py +++ b/addons/payment_transfer/__init__.py @@ -4,7 +4,6 @@ from . import controllers from . import models from odoo.addons.payment import reset_payment_acquirer -from odoo.addons.payment.models.payment_acquirer import create_missing_journals # post-init hook def uninstall_hook(cr, registry): diff --git a/addons/payment_transfer/__manifest__.py b/addons/payment_transfer/__manifest__.py index d5a52cb7686..9dcb894cfc1 100644 --- a/addons/payment_transfer/__manifest__.py +++ b/addons/payment_transfer/__manifest__.py @@ -13,6 +13,5 @@ 'data/payment_acquirer_data.xml', ], 'auto_install': True, - 'post_init_hook': 'create_missing_journals', 'uninstall_hook': 'uninstall_hook', } diff --git a/addons/payment_transfer/models/payment_acquirer.py b/addons/payment_transfer/models/payment_acquirer.py index 1d7d51f4b16..5704b2d08b5 100644 --- a/addons/payment_transfer/models/payment_acquirer.py +++ b/addons/payment_transfer/models/payment_acquirer.py @@ -27,27 +27,6 @@ class PaymentAcquirer(models.Model): 'show_cancel_msg': False, }) - @api.model - def _create_missing_journals(self, company=None): - """ Override of payment to assign the default Bank journal instead or Electronic. """ - # Search for transfer acquirers having no journal - company = company or self.env.company - transfer_acquirers = self.env['payment.acquirer'].search([ - ('provider', '=', 'transfer'), - ('journal_id', '=', False), - ('company_id', '=', company.id) - ]) - - if transfer_acquirers: - # Pick the Bank journal - bank_journal = self.env['account.journal'].search( - [('type', '=', 'bank'), ('company_id', '=', company.id)], limit=1 - ) - if bank_journal: - transfer_acquirers.write({'journal_id': bank_journal.id}) - - return super()._create_missing_journals(company=company) - @api.model_create_multi def create(self, values_list): """ Make sure to have a pending_msg set. """ diff --git a/addons/payment_transfer/views/payment_views.xml b/addons/payment_transfer/views/payment_views.xml index 7667e8670d7..a336f276e16 100644 --- a/addons/payment_transfer/views/payment_views.xml +++ b/addons/payment_transfer/views/payment_views.xml @@ -9,6 +9,11 @@ + + + {'invisible': [('provider', '=', 'transfer')]} + + diff --git a/addons/point_of_sale/security/ir.model.access.csv b/addons/point_of_sale/security/ir.model.access.csv index 608ab415a30..fce7173b119 100644 --- a/addons/point_of_sale/security/ir.model.access.csv +++ b/addons/point_of_sale/security/ir.model.access.csv @@ -9,6 +9,7 @@ access_stock_move_pos_user,stock.move pos_user,stock.model_stock_move,group_pos_ access_report_pos_order,report.pos.order,model_report_pos_order,group_pos_user,1,1,1,1 access_account_journal_pos_user,account.journal pos_user,account.model_account_journal,group_pos_user,1,0,0,0 access_account_payment_method_pos_user,account.payment.method pos_user,account.model_account_payment_method,group_pos_manager,1,0,0,0 +access_account_payment_method_line_pos_user,account.payment.method.line pos_user,account.model_account_payment_method_line,group_pos_manager,1,0,0,0 access_account_bank_statement,account.bank.statement,account.model_account_bank_statement,group_pos_user,1,1,1,0 access_account_bank_statement_manager,account.bank.statement manager,account.model_account_bank_statement,group_pos_manager,1,1,1,1 access_account_bank_statement_line,account.bank.statement.line,account.model_account_bank_statement_line,group_pos_user,1,1,1,0 diff --git a/addons/test_website_slides_full/tests/test_ui_wslides.py b/addons/test_website_slides_full/tests/test_ui_wslides.py index 9956f7e59c6..3943cd6daa1 100644 --- a/addons/test_website_slides_full/tests/test_ui_wslides.py +++ b/addons/test_website_slides_full/tests/test_ui_wslides.py @@ -26,7 +26,10 @@ class TestUi(TestUICommon): # Specify Accounting Data cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'}) - self.env['payment.acquirer'].search([('journal_id', '=', False)]).journal_id = cash_journal + self.env['payment.acquirer'].search([('provider', '=', 'test')]).write({ + 'journal_id': cash_journal.id, + 'state': 'test' + }) a_recv = self.env['account.account'].create({ 'code': 'X1012', 'name': 'Debtors - (test)',