mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Create module account_payment_mode_default_account
This commit is contained in:
2
account_payment_mode_default_account/__init__.py
Normal file
2
account_payment_mode_default_account/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import models
|
||||
from .hooks import post_init_hook, uninstall_hook
|
||||
20
account_payment_mode_default_account/__manifest__.py
Normal file
20
account_payment_mode_default_account/__manifest__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
{
|
||||
"name": "Account Payment Mode Default Account",
|
||||
"summary": "Set Receivable or Payable account according to payment mode",
|
||||
"version": "14.0.1.0.0",
|
||||
"development_status": "Alpha",
|
||||
"category": "Accounting/Accounting",
|
||||
"website": "https://github.com/OCA/bank-payment",
|
||||
"author": "Camptocamp, Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"depends": [
|
||||
"account_payment_partner",
|
||||
],
|
||||
"data": [
|
||||
"views/account_payment_mode.xml",
|
||||
],
|
||||
"post_init_hook": "post_init_hook",
|
||||
"uninstall_hook": "uninstall_hook",
|
||||
}
|
||||
39
account_payment_mode_default_account/hooks.py
Normal file
39
account_payment_mode_default_account/hooks.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import SUPERUSER_ID, api
|
||||
|
||||
|
||||
def post_init_hook(cr, registry):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
fields_mapping = [
|
||||
("property_account_receivable_id", "property_stored_account_receivable_id"),
|
||||
("property_account_payable_id", "property_stored_account_payable_id"),
|
||||
]
|
||||
for orig_fname, new_fname in fields_mapping:
|
||||
orig_model_field = env["ir.model.fields"]._get("res.partner", orig_fname)
|
||||
new_model_field = env["ir.model.fields"]._get("res.partner", new_fname)
|
||||
sql = """
|
||||
UPDATE ir_property
|
||||
SET name = %s,
|
||||
fields_id = %s
|
||||
WHERE fields_id = %s;
|
||||
"""
|
||||
cr.execute(sql, (new_fname, new_model_field.id, orig_model_field.id))
|
||||
|
||||
|
||||
def uninstall_hook(cr, registry):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
fields_mapping = [
|
||||
("property_account_receivable_id", "property_stored_account_receivable_id"),
|
||||
("property_account_payable_id", "property_stored_account_payable_id"),
|
||||
]
|
||||
for orig_fname, new_fname in fields_mapping:
|
||||
orig_model_field = env["ir.model.fields"]._get("res.partner", orig_fname)
|
||||
new_model_field = env["ir.model.fields"]._get("res.partner", new_fname)
|
||||
sql = """
|
||||
UPDATE ir_property
|
||||
SET name = %s,
|
||||
fields_id = %s
|
||||
WHERE fields_id = %s;
|
||||
"""
|
||||
cr.execute(sql, (orig_fname, orig_model_field.id, new_model_field.id))
|
||||
4
account_payment_mode_default_account/models/__init__.py
Normal file
4
account_payment_mode_default_account/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from . import account_move
|
||||
from . import account_payment_mode
|
||||
from . import chart_template
|
||||
from . import res_partner
|
||||
38
account_payment_mode_default_account/models/account_move.py
Normal file
38
account_payment_mode_default_account/models/account_move.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
|
||||
_inherit = "account.move"
|
||||
|
||||
def _recompute_payment_terms_lines(self):
|
||||
if self.payment_mode_id:
|
||||
return super(
|
||||
AccountMove,
|
||||
self.with_context(
|
||||
_partner_property_account_payment_mode=self.payment_mode_id.id
|
||||
),
|
||||
)._recompute_payment_terms_lines()
|
||||
else:
|
||||
return super()._recompute_payment_terms_lines()
|
||||
|
||||
def _get_payment_term_lines(self):
|
||||
self.ensure_one()
|
||||
return self.line_ids.filtered(
|
||||
lambda line: line.account_id.user_type_id.type in ("receivable", "payable")
|
||||
)
|
||||
|
||||
@api.onchange("payment_mode_id")
|
||||
def _onchange_payment_mode_id(self):
|
||||
if self.payment_mode_id and self.partner_id:
|
||||
payment_term_lines = self._get_payment_term_lines()
|
||||
partner = self.partner_id.with_context(
|
||||
_partner_property_account_payment_mode=self.payment_mode_id.id
|
||||
)
|
||||
# Retrieve account from partner.
|
||||
if self.is_sale_document(include_receipts=True):
|
||||
payment_term_lines.account_id = partner.property_account_receivable_id
|
||||
else:
|
||||
payment_term_lines.account_id = partner.property_account_payable_id
|
||||
@@ -0,0 +1,19 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountPaymentMode(models.Model):
|
||||
|
||||
_inherit = "account.payment.mode"
|
||||
|
||||
default_receivable_account_id = fields.Many2one(
|
||||
"account.account",
|
||||
domain="[('deprecated', '=', False),('company_id', '=', company_id),('user_type_id.type', '=', 'receivable')]", # noqa
|
||||
help="This account will be used instead of the default one as the receivable account on invoices using this payment mode", # noqa
|
||||
)
|
||||
default_payable_account_id = fields.Many2one(
|
||||
"account.account",
|
||||
domain="[('deprecated', '=', False), ('company_id', '=', company_id),('user_type_id.type', '=', 'payable')]", # noqa
|
||||
help="This account will be used instead of the default one as the payable account on invoices using this payment mode", # noqa
|
||||
)
|
||||
@@ -0,0 +1,31 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class AccountChartTemplate(models.Model):
|
||||
_inherit = "account.chart.template"
|
||||
|
||||
def generate_properties(self, acc_template_ref, company):
|
||||
super().generate_properties(acc_template_ref, company)
|
||||
# Make sure a property with stored in its name is created as default for the company
|
||||
# so that _get_multi would fetch it if the partner does not have a property itself
|
||||
PropertyObj = self.env["ir.property"]
|
||||
todo_list = [
|
||||
(
|
||||
"property_account_receivable_id",
|
||||
"property_stored_account_receivable_id",
|
||||
"res.partner",
|
||||
),
|
||||
(
|
||||
"property_account_payable_id",
|
||||
"property_stored_account_payable_id",
|
||||
"res.partner",
|
||||
),
|
||||
]
|
||||
for chart_field, partner_field, model in todo_list:
|
||||
account = self[chart_field]
|
||||
value = acc_template_ref[account.id] if account else False
|
||||
if value:
|
||||
PropertyObj._set_default(partner_field, model, value, company=company)
|
||||
76
account_payment_mode_default_account/models/res_partner.py
Normal file
76
account_payment_mode_default_account/models/res_partner.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
|
||||
_inherit = "res.partner"
|
||||
|
||||
property_account_receivable_id = fields.Many2one(
|
||||
company_dependent=False,
|
||||
compute="_compute_property_account_receivable_id",
|
||||
inverse="_inverse_property_account_receivable_id",
|
||||
)
|
||||
|
||||
property_stored_account_receivable_id = fields.Many2one(
|
||||
"account.account",
|
||||
company_dependent=True,
|
||||
string="Account Receivable",
|
||||
domain="[('internal_type', '=', 'receivable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]", # noqa
|
||||
)
|
||||
|
||||
property_account_payable_id = fields.Many2one(
|
||||
company_dependent=False,
|
||||
compute="_compute_property_account_payable_id",
|
||||
inverse="_inverse_property_account_payable_id",
|
||||
)
|
||||
|
||||
property_stored_account_payable_id = fields.Many2one(
|
||||
"account.account",
|
||||
company_dependent=True,
|
||||
string="Account payable",
|
||||
domain="[('internal_type', '=', 'payable'), ('deprecated', '=', False), ('company_id', '=', current_company_id)]", # noqa
|
||||
)
|
||||
|
||||
@api.depends("property_stored_account_receivable_id")
|
||||
@api.depends_context("_partner_property_account_payment_mode")
|
||||
def _compute_property_account_receivable_id(self):
|
||||
payment_mode_id = self.env.context.get("_partner_property_account_payment_mode")
|
||||
if payment_mode_id:
|
||||
payment_mode = self.env["account.payment.mode"].browse(payment_mode_id)
|
||||
rec_account = payment_mode.default_receivable_account_id
|
||||
if rec_account:
|
||||
self.update({"property_account_receivable_id": rec_account})
|
||||
return
|
||||
for partner in self:
|
||||
partner.property_account_receivable_id = (
|
||||
partner.property_stored_account_receivable_id
|
||||
)
|
||||
|
||||
def _inverse_property_account_receivable_id(self):
|
||||
for partner in self:
|
||||
partner.property_stored_account_receivable_id = (
|
||||
partner.property_account_receivable_id
|
||||
)
|
||||
|
||||
@api.depends("property_stored_account_payable_id")
|
||||
@api.depends_context("_partner_property_account_payment_mode")
|
||||
def _compute_property_account_payable_id(self):
|
||||
payment_mode_id = self.env.context.get("_partner_property_account_payment_mode")
|
||||
if payment_mode_id:
|
||||
payment_mode = self.env["account.payment.mode"].browse(payment_mode_id)
|
||||
rec_account = payment_mode.default_payable_account_id
|
||||
if rec_account:
|
||||
self.update({"property_account_payable_id": rec_account})
|
||||
return
|
||||
for partner in self:
|
||||
partner.property_account_payable_id = (
|
||||
partner.property_stored_account_payable_id
|
||||
)
|
||||
|
||||
def _inverse_property_account_payable_id(self):
|
||||
for partner in self:
|
||||
partner.property_stored_account_payable_id = (
|
||||
partner.property_account_payable_id
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
* Akim Juillerat <akim.juillerat@camptocamp.com>
|
||||
@@ -0,0 +1,3 @@
|
||||
This module allows to define default receivable and payable accounts
|
||||
on payment mode to override the account selected on the customer
|
||||
when computing payment terms lines on invoices.
|
||||
1
account_payment_mode_default_account/tests/__init__.py
Normal file
1
account_payment_mode_default_account/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_account_payment_mode_default_account
|
||||
@@ -0,0 +1,148 @@
|
||||
# Copyright 2022 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo.tests import Form, SavepointCase
|
||||
|
||||
|
||||
class TestAccountPaymentModeDefaultAccount(SavepointCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
chart_template = cls.env.company.chart_template_id
|
||||
chart_template.try_loading(company=cls.env.company)
|
||||
receivable_code = chart_template["property_account_receivable_id"].code
|
||||
cls.receivable_account = cls.env["account.account"].search(
|
||||
[
|
||||
("company_id", "=", cls.env.company.id),
|
||||
("user_type_id.type", "=", "receivable"),
|
||||
("code", "=like", receivable_code + "%"),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
cls.payable_account = cls.env["account.account"].search(
|
||||
[
|
||||
("company_id", "=", cls.env.company.id),
|
||||
("user_type_id.type", "=", "payable"),
|
||||
],
|
||||
limit=1,
|
||||
)
|
||||
cls.receivable_account2 = cls.receivable_account.copy(
|
||||
{"code": cls.receivable_account.code + "2"}
|
||||
)
|
||||
cls.payable_account2 = cls.payable_account.copy(
|
||||
{"code": cls.payable_account.code + "2"}
|
||||
)
|
||||
cls.partner_1 = cls.env.ref("base.res_partner_1")
|
||||
|
||||
cls.payment_mode = cls.env.ref("account_payment_mode.payment_mode_inbound_dd1")
|
||||
cls.payment_mode.write(
|
||||
{
|
||||
"default_receivable_account_id": cls.receivable_account2.id,
|
||||
"default_payable_account_id": cls.payable_account2.id,
|
||||
}
|
||||
)
|
||||
cls.payment_mode_without_default = cls.env.ref(
|
||||
"account_payment_mode.payment_mode_inbound_ct1"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _create_invoice(cls, move_type="out_invoice", payment_mode=None):
|
||||
move_form = Form(
|
||||
cls.env["account.move"].with_context(default_move_type=move_type)
|
||||
)
|
||||
move_form.partner_id = cls.partner_1
|
||||
if payment_mode is not None:
|
||||
move_form.payment_mode_id = payment_mode
|
||||
with move_form.invoice_line_ids.new() as line_form:
|
||||
line_form.name = "test"
|
||||
line_form.quantity = 1.0
|
||||
line_form.price_unit = 100
|
||||
invoice = move_form.save()
|
||||
return invoice
|
||||
|
||||
def test_create_customer_invoice_payment_mode_default(self):
|
||||
invoice = self._create_invoice(payment_mode=self.payment_mode)
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account2)
|
||||
|
||||
def test_create_supplier_invoice_payment_mode_default(self):
|
||||
invoice = self._create_invoice(
|
||||
move_type="in_invoice", payment_mode=self.payment_mode
|
||||
)
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account2)
|
||||
|
||||
def test_change_customer_invoice_payment_mode_default(self):
|
||||
invoice = self._create_invoice()
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account)
|
||||
with Form(invoice) as move_form:
|
||||
move_form.payment_mode_id = self.payment_mode
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account2)
|
||||
|
||||
def test_change_supplier_invoice_payment_mode_default(self):
|
||||
invoice = self._create_invoice(move_type="in_invoice")
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account)
|
||||
with Form(invoice) as move_form:
|
||||
move_form.payment_mode_id = self.payment_mode
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account2)
|
||||
|
||||
def test_create_customer_invoice_payment_mode_without_default(self):
|
||||
invoice = self._create_invoice(payment_mode=self.payment_mode_without_default)
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account)
|
||||
|
||||
def test_create_supplier_invoice_payment_mode_without_default(self):
|
||||
invoice = self._create_invoice(
|
||||
move_type="in_invoice", payment_mode=self.payment_mode_without_default
|
||||
)
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account)
|
||||
|
||||
def test_change_customer_invoice_payment_mode_without_default(self):
|
||||
invoice = self._create_invoice()
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account)
|
||||
with Form(invoice) as move_form:
|
||||
move_form.payment_mode_id = self.payment_mode_without_default
|
||||
self.assertEqual(payment_term_line.account_id, self.receivable_account)
|
||||
|
||||
def test_change_supplier_invoice_payment_mode_without_default(self):
|
||||
invoice = self._create_invoice(move_type="in_invoice")
|
||||
payment_term_line = invoice._get_payment_term_lines()
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account)
|
||||
with Form(invoice) as move_form:
|
||||
move_form.payment_mode_id = self.payment_mode_without_default
|
||||
self.assertEqual(payment_term_line.account_id, self.payable_account)
|
||||
|
||||
def test_partner_compute_inverse(self):
|
||||
self.assertEqual(
|
||||
self.partner_1.property_account_receivable_id, self.receivable_account
|
||||
)
|
||||
self.assertEqual(
|
||||
self.partner_1.property_account_payable_id, self.payable_account
|
||||
)
|
||||
self.assertEqual(
|
||||
self.partner_1.with_context(
|
||||
_partner_property_account_payment_mode=self.payment_mode.id
|
||||
).property_account_receivable_id,
|
||||
self.receivable_account2,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.partner_1.with_context(
|
||||
_partner_property_account_payment_mode=self.payment_mode.id
|
||||
).property_account_payable_id,
|
||||
self.payable_account2,
|
||||
)
|
||||
self.partner_1.write(
|
||||
{
|
||||
"property_account_receivable_id": self.receivable_account2.id,
|
||||
"property_account_payable_id": self.payable_account2.id,
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
self.partner_1.property_account_receivable_id, self.receivable_account2
|
||||
)
|
||||
self.assertEqual(
|
||||
self.partner_1.property_account_payable_id, self.payable_account2
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="account_payment_mode_form" model="ir.ui.view">
|
||||
<field name="name">account.payment.mode.form.inherit</field>
|
||||
<field name="model">account.payment.mode</field>
|
||||
<field name="inherit_id" ref="account_payment_mode.account_payment_mode_form" />
|
||||
<field name="arch" type="xml">
|
||||
<group name="note" position="before">
|
||||
<group name="account_defaults" string="Default accounts">
|
||||
<field name="default_receivable_account_id" />
|
||||
<field name="default_payable_account_id" />
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
../../../../account_payment_mode_default_account
|
||||
6
setup/account_payment_mode_default_account/setup.py
Normal file
6
setup/account_payment_mode_default_account/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user