[MIG] account_netting to v16
Add prepare method for the account.move created by the wizard Add multi-company checks Improve error messages Improve usability: use monetary instead of float, display partner Use odoo methods to compare floats Update tests
This commit is contained in:
parent
4643b05b26
commit
936ecfe56c
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
"name": "Account netting",
|
"name": "Account netting",
|
||||||
"version": "15.0.1.0.0",
|
"version": "16.0.1.0.0",
|
||||||
"summary": "Compensate AR/AP accounts from the same partner",
|
"summary": "Compensate AR/AP accounts from the same partner",
|
||||||
"category": "Accounting & Finance",
|
"category": "Accounting & Finance",
|
||||||
"author": "Tecnativa, Odoo Community Association (OCA)",
|
"author": "Tecnativa, Odoo Community Association (OCA)",
|
||||||
|
@ -6,15 +6,16 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
import odoo.tests.common as common
|
import odoo.tests.common as common
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import UserError
|
||||||
from odoo.tests import Form, tagged
|
from odoo.tests import Form, tagged
|
||||||
|
|
||||||
|
|
||||||
@tagged("post_install")
|
@tagged("post_install", "-at_install")
|
||||||
class TestAccountNetting(common.TransactionCase):
|
class TestAccountNetting(common.TransactionCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
super().setUpClass()
|
super().setUpClass()
|
||||||
|
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||||
res_users_account_manager = cls.env.ref("account.group_account_manager")
|
res_users_account_manager = cls.env.ref("account.group_account_manager")
|
||||||
partner_manager = cls.env.ref("base.group_partner_manager")
|
partner_manager = cls.env.ref("base.group_partner_manager")
|
||||||
cls.env.user.write(
|
cls.env.user.write(
|
||||||
@ -23,19 +24,25 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
cls.company = cls.env.ref("base.main_company")
|
cls.company = cls.env.ref("base.main_company")
|
||||||
# only adviser can create an account
|
# only adviser can create an account
|
||||||
cls.aa_model = cls.env["account.account"]
|
cls.aa_model = cls.env["account.account"]
|
||||||
cls.account_receivable = cls._get_account(cls, "receivable")
|
cls.account_receivable = cls._get_account(cls, "asset_receivable")
|
||||||
cls.account_payable = cls._get_account(cls, "payable")
|
cls.account_payable = cls._get_account(cls, "liability_payable")
|
||||||
cls.account_revenue = cls._get_account(cls, "revenue")
|
cls.account_revenue = cls._get_account(cls, "income")
|
||||||
cls.account_expense = cls._get_account(cls, "expenses")
|
cls.account_expense = cls._get_account(cls, "expense")
|
||||||
cls.partner_model = cls.env["res.partner"]
|
cls.partner_model = cls.env["res.partner"]
|
||||||
cls.partner = cls._create_partner(cls, "Supplier/Customer")
|
|
||||||
cls.partner1 = cls._create_partner(cls, "Supplier/Customer 1")
|
cls.partner1 = cls._create_partner(cls, "Supplier/Customer 1")
|
||||||
|
cls.partner2 = cls._create_partner(cls, "Supplier/Customer 2")
|
||||||
cls.miscellaneous_journal = cls.env["account.journal"].search(
|
cls.miscellaneous_journal = cls.env["account.journal"].search(
|
||||||
[("type", "=", "general")], limit=1
|
[("type", "=", "general"), ("company_id", "=", cls.company.id)], limit=1
|
||||||
)
|
)
|
||||||
# We need a product with taxes at 0 so that the amounts are as expected.
|
# We need a product with taxes at 0 so that the amounts are as expected.
|
||||||
cls.account_tax = cls.env["account.tax"].create(
|
cls.account_tax = cls.env["account.tax"].create(
|
||||||
{"name": "0%", "amount_type": "fixed", "type_tax_use": "sale", "amount": 0}
|
{
|
||||||
|
"name": "0%",
|
||||||
|
"amount_type": "fixed",
|
||||||
|
"type_tax_use": "sale",
|
||||||
|
"amount": 0,
|
||||||
|
"company_id": cls.company.id,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
cls.product = cls.env["product.product"].create(
|
cls.product = cls.env["product.product"].create(
|
||||||
{
|
{
|
||||||
@ -44,40 +51,39 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
"taxes_id": [(6, 0, [cls.account_tax.id])],
|
"taxes_id": [(6, 0, [cls.account_tax.id])],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
out_invoice_partner = cls._create_move(cls, "out_invoice", cls.partner, 100)
|
out_invoice_partner1 = cls._create_move(cls, "out_invoice", cls.partner1, 100)
|
||||||
out_invoice_partner.action_post()
|
out_invoice_partner1.action_post()
|
||||||
cls.move_line_1 = out_invoice_partner.line_ids.filtered(
|
cls.move_line_1 = out_invoice_partner1.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_receivable
|
lambda x: x.account_id == cls.account_receivable
|
||||||
)
|
)
|
||||||
in_invoice_partner = cls._create_move(cls, "in_invoice", cls.partner, 1200)
|
in_invoice_partner1 = cls._create_move(cls, "in_invoice", cls.partner1, 1200)
|
||||||
in_invoice_partner.action_post()
|
in_invoice_partner1.action_post()
|
||||||
cls.move_line_2 = in_invoice_partner.line_ids.filtered(
|
cls.move_line_2 = in_invoice_partner1.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_payable
|
lambda x: x.account_id == cls.account_payable
|
||||||
)
|
)
|
||||||
cls.move_line_3 = in_invoice_partner.line_ids.filtered(
|
cls.move_line_3 = in_invoice_partner1.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_expense
|
lambda x: x.account_id == cls.account_expense
|
||||||
)
|
)
|
||||||
in_invoice_partner1 = cls._create_move(cls, "in_invoice", cls.partner1, 200)
|
in_invoice_partner2 = cls._create_move(cls, "in_invoice", cls.partner2, 200)
|
||||||
in_invoice_partner1.action_post()
|
in_invoice_partner2.action_post()
|
||||||
cls.move_line_4 = in_invoice_partner1.line_ids.filtered(
|
cls.move_line_4 = in_invoice_partner2.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_payable
|
lambda x: x.account_id == cls.account_payable
|
||||||
)
|
)
|
||||||
in_refund_partner1 = cls._create_move(cls, "in_refund", cls.partner1, 200)
|
in_refund_partner2 = cls._create_move(cls, "in_refund", cls.partner2, 200)
|
||||||
in_refund_partner1.action_post()
|
in_refund_partner2.action_post()
|
||||||
cls.move_line_5 = in_refund_partner1.line_ids.filtered(
|
cls.move_line_5 = in_refund_partner2.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_payable
|
lambda x: x.account_id == cls.account_payable
|
||||||
)
|
)
|
||||||
in_refund_partner1 = cls._create_move(cls, "in_refund", cls.partner1, 200)
|
in_refund_partner2 = cls._create_move(cls, "in_refund", cls.partner2, 200)
|
||||||
in_refund_partner1.action_post()
|
in_refund_partner2.action_post()
|
||||||
cls.move_line_6 = in_refund_partner1.line_ids.filtered(
|
cls.move_line_6 = in_refund_partner2.line_ids.filtered(
|
||||||
lambda x: x.account_id == cls.account_payable
|
lambda x: x.account_id == cls.account_payable
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_account(self, user_type):
|
def _get_account(self, account_type):
|
||||||
user_type_ref = "account.data_account_type_%s" % user_type
|
|
||||||
return self.aa_model.search(
|
return self.aa_model.search(
|
||||||
[
|
[
|
||||||
("user_type_id", "=", self.env.ref(user_type_ref).id),
|
("account_type", "=", account_type),
|
||||||
("company_id", "=", self.company.id),
|
("company_id", "=", self.company.id),
|
||||||
],
|
],
|
||||||
limit=1,
|
limit=1,
|
||||||
@ -94,7 +100,9 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
|
|
||||||
def _create_move(self, move_type, partner, price):
|
def _create_move(self, move_type, partner, price):
|
||||||
move_form = Form(
|
move_form = Form(
|
||||||
self.env["account.move"].with_context(
|
self.env["account.move"]
|
||||||
|
.with_company(self.company.id)
|
||||||
|
.with_context(
|
||||||
default_move_type=move_type,
|
default_move_type=move_type,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -106,22 +114,22 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
return move_form.save()
|
return move_form.save()
|
||||||
|
|
||||||
def test_compensation(self):
|
def test_compensation(self):
|
||||||
# Test exception line 33 from account_move_make_netting
|
# Test raise if 1 account.move.line selected
|
||||||
obj = self.env["account.move.make.netting"].with_context(
|
obj = self.env["account.move.make.netting"].with_context(
|
||||||
active_ids=[self.move_line_1.id]
|
active_ids=[self.move_line_1.id]
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(UserError):
|
||||||
wizard = obj.create(
|
wizard = obj.create(
|
||||||
{
|
{
|
||||||
"move_line_ids": [(6, 0, [self.move_line_1.id])],
|
"move_line_ids": [(6, 0, [self.move_line_1.id])],
|
||||||
"journal_id": self.miscellaneous_journal.id,
|
"journal_id": self.miscellaneous_journal.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Test exception line 39 from account_move_make_netting
|
# Test raise if not all accounts are payable/receivable
|
||||||
obj = self.env["account.move.make.netting"].with_context(
|
obj = self.env["account.move.make.netting"].with_context(
|
||||||
active_ids=[self.move_line_1.id, self.move_line_3.id]
|
active_ids=[self.move_line_1.id, self.move_line_3.id]
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(UserError):
|
||||||
wizard = obj.create(
|
wizard = obj.create(
|
||||||
{
|
{
|
||||||
"move_line_ids": [
|
"move_line_ids": [
|
||||||
@ -130,11 +138,11 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
"journal_id": self.miscellaneous_journal.id,
|
"journal_id": self.miscellaneous_journal.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Test exception line 45 from account_move_make_netting
|
# Test raise if same account
|
||||||
obj = self.env["account.move.make.netting"].with_context(
|
obj = self.env["account.move.make.netting"].with_context(
|
||||||
active_ids=[self.move_line_4.id, self.move_line_5.id]
|
active_ids=[self.move_line_4.id, self.move_line_5.id]
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(UserError):
|
||||||
wizard = obj.create(
|
wizard = obj.create(
|
||||||
{
|
{
|
||||||
"move_line_ids": [
|
"move_line_ids": [
|
||||||
@ -143,7 +151,7 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
"journal_id": self.miscellaneous_journal.id,
|
"journal_id": self.miscellaneous_journal.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Test exception line 42 from account_move_make_netting
|
# Test raise if reconciled lines
|
||||||
moves = self.env["account.move.line"].browse(
|
moves = self.env["account.move.line"].browse(
|
||||||
[self.move_line_4.id, self.move_line_5.id]
|
[self.move_line_4.id, self.move_line_5.id]
|
||||||
)
|
)
|
||||||
@ -151,7 +159,7 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
obj = self.env["account.move.make.netting"].with_context(
|
obj = self.env["account.move.make.netting"].with_context(
|
||||||
active_ids=[self.move_line_4.id, self.move_line_5.id]
|
active_ids=[self.move_line_4.id, self.move_line_5.id]
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(UserError):
|
||||||
wizard = obj.create(
|
wizard = obj.create(
|
||||||
{
|
{
|
||||||
"move_line_ids": [
|
"move_line_ids": [
|
||||||
@ -160,11 +168,11 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
"journal_id": self.miscellaneous_journal.id,
|
"journal_id": self.miscellaneous_journal.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# Test exception line 52 from account_move_make_netting
|
# Test raise if different partners
|
||||||
obj = self.env["account.move.make.netting"].with_context(
|
obj = self.env["account.move.make.netting"].with_context(
|
||||||
active_ids=[self.move_line_1.id, self.move_line_6.id]
|
active_ids=[self.move_line_1.id, self.move_line_6.id]
|
||||||
)
|
)
|
||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(UserError):
|
||||||
wizard = obj.create(
|
wizard = obj.create(
|
||||||
{
|
{
|
||||||
"move_line_ids": [
|
"move_line_ids": [
|
||||||
@ -182,6 +190,8 @@ class TestAccountNetting(common.TransactionCase):
|
|||||||
"journal_id": self.miscellaneous_journal.id,
|
"journal_id": self.miscellaneous_journal.id,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
self.assertEqual(wizard.partner_id, self.partner1)
|
||||||
|
self.assertEqual(wizard.company_id, self.company)
|
||||||
res = wizard.button_compensate()
|
res = wizard.button_compensate()
|
||||||
move = self.env["account.move"].browse(res["res_id"])
|
move = self.env["account.move"].browse(res["res_id"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -2,20 +2,29 @@
|
|||||||
# Copyright 2017 Tecnativa - Vicent Cubells
|
# Copyright 2017 Tecnativa - Vicent Cubells
|
||||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
|
||||||
from odoo import _, api, exceptions, fields, models
|
from odoo import _, api, fields, models
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
class AccountMoveMakeNetting(models.TransientModel):
|
class AccountMoveMakeNetting(models.TransientModel):
|
||||||
_name = "account.move.make.netting"
|
_name = "account.move.make.netting"
|
||||||
_description = "Wizard to generate account moves for netting"
|
_description = "Wizard to generate account moves for netting"
|
||||||
|
_check_company_auto = True
|
||||||
|
|
||||||
|
company_id = fields.Many2one("res.company", required=True)
|
||||||
journal_id = fields.Many2one(
|
journal_id = fields.Many2one(
|
||||||
comodel_name="account.journal",
|
comodel_name="account.journal",
|
||||||
required=True,
|
required=True,
|
||||||
domain="[('type', '=', 'general')]",
|
domain="[('type', '=', 'general'), ('company_id', '=', company_id)]",
|
||||||
|
check_company=True,
|
||||||
)
|
)
|
||||||
move_line_ids = fields.Many2many(comodel_name="account.move.line")
|
move_line_ids = fields.Many2many(
|
||||||
balance = fields.Float(readonly=True)
|
comodel_name="account.move.line",
|
||||||
|
check_company=True,
|
||||||
|
)
|
||||||
|
partner_id = fields.Many2one("res.partner", readonly=True)
|
||||||
|
company_currency_id = fields.Many2one(related="company_id.currency_id")
|
||||||
|
balance = fields.Monetary(readonly=True, currency_field="company_currency_id")
|
||||||
balance_type = fields.Selection(
|
balance_type = fields.Selection(
|
||||||
selection=[("pay", "To pay"), ("receive", "To receive")],
|
selection=[("pay", "To pay"), ("receive", "To receive")],
|
||||||
readonly=True,
|
readonly=True,
|
||||||
@ -24,54 +33,79 @@ class AccountMoveMakeNetting(models.TransientModel):
|
|||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields_list):
|
def default_get(self, fields_list):
|
||||||
if len(self.env.context.get("active_ids", [])) < 2:
|
if len(self.env.context.get("active_ids", [])) < 2:
|
||||||
raise exceptions.ValidationError(
|
raise UserError(_("You should compensate at least 2 journal items."))
|
||||||
_("You should compensate at least 2 journal entries.")
|
|
||||||
)
|
|
||||||
move_lines = self.env["account.move.line"].browse(
|
move_lines = self.env["account.move.line"].browse(
|
||||||
self.env.context["active_ids"]
|
self.env.context["active_ids"]
|
||||||
)
|
)
|
||||||
if any(
|
partners = self.env["res.partner"]
|
||||||
x not in ("payable", "receivable")
|
for line in move_lines:
|
||||||
for x in move_lines.mapped("account_id.user_type_id.type")
|
if line.parent_state != "posted":
|
||||||
):
|
raise UserError(_("Line '%s' is not posted.") % line.display_name)
|
||||||
raise exceptions.ValidationError(
|
if line.account_id.account_type not in (
|
||||||
_("All entries must have a receivable or payable account")
|
"liability_payable",
|
||||||
)
|
"asset_receivable",
|
||||||
if any(move_lines.mapped("reconciled")):
|
):
|
||||||
raise exceptions.ValidationError(_("All entries mustn't been reconciled"))
|
raise UserError(
|
||||||
if len(move_lines.mapped("account_id")) == 1:
|
_(
|
||||||
raise exceptions.ValidationError(
|
"Line '%(line)s' has account '%(account)s' which is not "
|
||||||
|
"a payable nor a receivable account."
|
||||||
|
)
|
||||||
|
% {
|
||||||
|
"line": line.display_name,
|
||||||
|
"account": line.account_id.display_name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if line.reconciled:
|
||||||
|
raise UserError(
|
||||||
|
_("Line '%s' is already reconciled.") % line.display_name
|
||||||
|
)
|
||||||
|
if not line.partner_id:
|
||||||
|
raise UserError(
|
||||||
|
_("Line '%s' doesn't have a partner.") % line.display_name
|
||||||
|
)
|
||||||
|
partners |= line.partner_id
|
||||||
|
|
||||||
|
if len(move_lines.account_id) == 1:
|
||||||
|
raise UserError(
|
||||||
_(
|
_(
|
||||||
"The 'Compensate' function is intended to balance "
|
"The 'Compensate' function is intended to balance "
|
||||||
"operations on different accounts for the same partner.\n"
|
"operations on different accounts for the same partner. "
|
||||||
"In this case all selected entries belong to the same "
|
"In this case all selected entries belong to the same "
|
||||||
"account.\n Please use the 'Reconcile' function."
|
"account '%s'. Use the 'Reconcile' function instead."
|
||||||
)
|
)
|
||||||
|
% move_lines.account_id.display_name
|
||||||
)
|
)
|
||||||
if len(move_lines.mapped("partner_id")) != 1:
|
if len(partners) != 1:
|
||||||
raise exceptions.ValidationError(
|
raise UserError(
|
||||||
_(
|
_(
|
||||||
"All entries should have a partner and the partner must "
|
"The selected journal items have different partners: %s. "
|
||||||
"be the same for all."
|
"The partner must be the same for all the selected journal items."
|
||||||
)
|
)
|
||||||
|
% ", ".join([p.display_name for p in partners])
|
||||||
)
|
)
|
||||||
res = super().default_get(fields_list)
|
res = super().default_get(fields_list)
|
||||||
res["move_line_ids"] = [(6, 0, move_lines.ids)]
|
company = self.env.company
|
||||||
|
ccur = company.currency_id
|
||||||
debit_move_lines_debit = move_lines.filtered("debit")
|
debit_move_lines_debit = move_lines.filtered("debit")
|
||||||
credit_move_lines_debit = move_lines.filtered("credit")
|
credit_move_lines_debit = move_lines.filtered("credit")
|
||||||
balance = abs(sum(debit_move_lines_debit.mapped("amount_residual"))) - abs(
|
balance = ccur.round(
|
||||||
sum(credit_move_lines_debit.mapped("amount_residual"))
|
abs(sum(debit_move_lines_debit.mapped("amount_residual")))
|
||||||
|
- abs(sum(credit_move_lines_debit.mapped("amount_residual")))
|
||||||
|
)
|
||||||
|
res.update(
|
||||||
|
{
|
||||||
|
"balance": abs(balance),
|
||||||
|
"balance_type": "pay"
|
||||||
|
if ccur.compare_amounts(balance, 0) < 0
|
||||||
|
else "receive",
|
||||||
|
"company_id": company.id,
|
||||||
|
"move_line_ids": move_lines.ids,
|
||||||
|
"partner_id": partners.id,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
res["balance"] = abs(balance)
|
|
||||||
res["balance_type"] = "pay" if balance < 0 else "receive"
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def button_compensate(self):
|
def _prepare_account_move(self):
|
||||||
self.ensure_one()
|
|
||||||
# Create account move
|
|
||||||
move = self.env["account.move"].create(
|
|
||||||
{"ref": _("AR/AP netting"), "journal_id": self.journal_id.id}
|
|
||||||
)
|
|
||||||
# Group amounts by account
|
# Group amounts by account
|
||||||
account_groups = self.move_line_ids.read_group(
|
account_groups = self.move_line_ids.read_group(
|
||||||
[("id", "in", self.move_line_ids.ids)],
|
[("id", "in", self.move_line_ids.ids)],
|
||||||
@ -80,44 +114,50 @@ class AccountMoveMakeNetting(models.TransientModel):
|
|||||||
)
|
)
|
||||||
debtors = []
|
debtors = []
|
||||||
creditors = []
|
creditors = []
|
||||||
total_debtors = 0
|
total_debtors = 0.0
|
||||||
total_creditors = 0
|
total_creditors = 0.0
|
||||||
|
ccur = self.company_id.currency_id
|
||||||
for account_group in account_groups:
|
for account_group in account_groups:
|
||||||
balance = account_group["amount_residual"]
|
balance = account_group["amount_residual"]
|
||||||
group_vals = {
|
group_vals = {
|
||||||
"account_id": account_group["account_id"][0],
|
"account_id": account_group["account_id"][0],
|
||||||
"balance": abs(balance),
|
"balance": abs(balance),
|
||||||
}
|
}
|
||||||
if balance > 0:
|
if ccur.compare_amounts(balance, 0) > 0:
|
||||||
debtors.append(group_vals)
|
debtors.append(group_vals)
|
||||||
total_debtors += balance
|
total_debtors += balance
|
||||||
else:
|
else:
|
||||||
creditors.append(group_vals)
|
creditors.append(group_vals)
|
||||||
total_creditors += abs(balance)
|
total_creditors += abs(balance)
|
||||||
# Create move lines
|
# Compute move lines
|
||||||
netting_amount = min(total_creditors, total_debtors)
|
netting_amount = min(total_creditors, total_debtors)
|
||||||
field_map = {1: "debit", 0: "credit"}
|
field_map = {1: "debit", 0: "credit"}
|
||||||
move_lines = []
|
move_lines = []
|
||||||
for i, group in enumerate([debtors, creditors]):
|
for i, group in enumerate([debtors, creditors]):
|
||||||
available_amount = netting_amount
|
available_amount = netting_amount
|
||||||
for account_group in group:
|
for account_group in group:
|
||||||
if account_group["balance"] > available_amount:
|
|
||||||
amount = available_amount
|
|
||||||
else:
|
|
||||||
amount = account_group["balance"]
|
|
||||||
move_line_vals = {
|
move_line_vals = {
|
||||||
field_map[i]: amount,
|
field_map[i]: min(available_amount, account_group["balance"]),
|
||||||
"partner_id": self.move_line_ids[0].partner_id.id,
|
"partner_id": self.partner_id.id,
|
||||||
"name": move.ref,
|
|
||||||
"account_id": account_group["account_id"],
|
"account_id": account_group["account_id"],
|
||||||
}
|
}
|
||||||
move_lines.append((0, 0, move_line_vals))
|
move_lines.append((0, 0, move_line_vals))
|
||||||
available_amount -= account_group["balance"]
|
available_amount -= account_group["balance"]
|
||||||
if available_amount <= 0:
|
if ccur.compare_amounts(available_amount, 0) <= 0:
|
||||||
break
|
break
|
||||||
if move_lines:
|
vals = {
|
||||||
move.write({"line_ids": move_lines})
|
"ref": _("AR/AP netting"),
|
||||||
move.action_post()
|
"journal_id": self.journal_id.id,
|
||||||
|
"company_id": self.company_id.id,
|
||||||
|
"line_ids": move_lines,
|
||||||
|
}
|
||||||
|
return vals
|
||||||
|
|
||||||
|
def button_compensate(self):
|
||||||
|
self.ensure_one()
|
||||||
|
# Create account move
|
||||||
|
move = self.env["account.move"].create(self._prepare_account_move())
|
||||||
|
move.action_post()
|
||||||
# Make reconciliation
|
# Make reconciliation
|
||||||
for move_line in move.line_ids:
|
for move_line in move.line_ids:
|
||||||
to_reconcile = move_line + self.move_line_ids.filtered(
|
to_reconcile = move_line + self.move_line_ids.filtered(
|
||||||
@ -125,11 +165,15 @@ class AccountMoveMakeNetting(models.TransientModel):
|
|||||||
)
|
)
|
||||||
to_reconcile.reconcile()
|
to_reconcile.reconcile()
|
||||||
# Open created move
|
# Open created move
|
||||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||||
"account.action_move_journal_line"
|
"account.action_move_journal_line"
|
||||||
)
|
)
|
||||||
action["view_mode"] = "form"
|
action.update(
|
||||||
del action["views"]
|
{
|
||||||
del action["view_id"]
|
"view_mode": "form",
|
||||||
action["res_id"] = move.id
|
"views": False,
|
||||||
|
"view_id": False,
|
||||||
|
"res_id": move.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
return action
|
return action
|
||||||
|
@ -13,10 +13,13 @@
|
|||||||
<field name="name">Compensate entries</field>
|
<field name="name">Compensate entries</field>
|
||||||
<field name="model">account.move.make.netting</field>
|
<field name="model">account.move.make.netting</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Compensate entries">
|
<form>
|
||||||
<p
|
<p
|
||||||
>This operation will generate journal entries that are counterpart of the receivable/payable accounts selected, and reconcile each other, letting this balance in the partner.</p>
|
>This operation will generate a journal entry whose lines are counterpart of the receivable/payable accounts selected, and reconcile each other, letting this balance in the partner.</p>
|
||||||
<group>
|
<group>
|
||||||
|
<field name="company_id" invisible="1" />
|
||||||
|
<field name="company_currency_id" invisible="1" />
|
||||||
|
<field name="partner_id" />
|
||||||
<field name="balance" />
|
<field name="balance" />
|
||||||
<field
|
<field
|
||||||
name="balance_type"
|
name="balance_type"
|
||||||
|
1
setup/account_netting/odoo/addons/account_netting
Symbolic link
1
setup/account_netting/odoo/addons/account_netting
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../account_netting
|
6
setup/account_netting/setup.py
Normal file
6
setup/account_netting/setup.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['setuptools-odoo'],
|
||||||
|
odoo_addon=True,
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user