2
0

[IMP] account_netting: black, isort

This commit is contained in:
Sergio Teruel 2020-03-19 09:13:15 +01:00 committed by Alexis de Lattre
parent 331ad070d1
commit 3845e23d36
4 changed files with 338 additions and 256 deletions

View File

@ -3,19 +3,14 @@
# 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
{ {
'name': 'Account netting', "name": "Account netting",
'version': '12.0.1.0.0', "version": "12.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, ' "author": "Tecnativa, " "Odoo Community Association (OCA)",
'Odoo Community Association (OCA)', "license": "AGPL-3",
'license': 'AGPL-3', "website": "https://github.com/OCA/account-financial-tools/",
'website': 'https://github.com/OCA/account-financial-tools/', "depends": ["account",],
'depends': [ "data": ["wizards/account_move_make_netting_view.xml",],
'account', "installable": True,
],
'data': [
'wizards/account_move_make_netting_view.xml',
],
'installable': True,
} }

View File

@ -9,209 +9,288 @@ class TestAccountNetting(common.SavepointCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestAccountNetting, cls).setUpClass() super(TestAccountNetting, cls).setUpClass()
cls.partner = cls.env['res.partner'].create({ cls.partner = cls.env["res.partner"].create(
'supplier': True, {"supplier": True, "customer": True, "name": "Supplier/Customer",}
'customer': True, )
'name': "Supplier/Customer", cls.partner1 = cls.env["res.partner"].create(
}) {"supplier": True, "customer": True, "name": "Supplier/Customer 1",}
cls.partner1 = cls.env['res.partner'].create({ )
'supplier': True, res_users_account_manager = cls.env.ref("account.group_account_manager")
'customer': True, partner_manager = cls.env.ref("base.group_partner_manager")
'name': "Supplier/Customer 1", cls.env.user.write(
}) {"groups_id": [(6, 0, [res_users_account_manager.id, partner_manager.id])],}
res_users_account_manager = cls.env.ref( )
'account.group_account_manager')
partner_manager = cls.env.ref('base.group_partner_manager')
cls.env.user.write({
'groups_id': [
(6, 0, [res_users_account_manager.id, partner_manager.id])
],
})
# only adviser can create an account # only adviser can create an account
cls.account_receivable = cls.env['account.account'].create({ cls.account_receivable = cls.env["account.account"].create(
'code': 'cust_acc', {
'name': 'customer account', "code": "cust_acc",
'user_type_id': cls.env.ref( "name": "customer account",
'account.data_account_type_receivable').id, "user_type_id": cls.env.ref("account.data_account_type_receivable").id,
'reconcile': True, "reconcile": True,
}) }
cls.account_payable = cls.env['account.account'].create({ )
'code': 'supp_acc', cls.account_payable = cls.env["account.account"].create(
'name': 'supplier account', {
'user_type_id': cls.env.ref( "code": "supp_acc",
'account.data_account_type_payable').id, "name": "supplier account",
'reconcile': True, "user_type_id": cls.env.ref("account.data_account_type_payable").id,
}) "reconcile": True,
cls.account_revenue = cls.env['account.account'].search([ }
('user_type_id', '=', cls.env.ref( )
'account.data_account_type_revenue').id) cls.account_revenue = cls.env["account.account"].search(
], limit=1) [
cls.account_expense = cls.env['account.account'].search([ (
('user_type_id', '=', cls.env.ref( "user_type_id",
'account.data_account_type_expenses').id) "=",
], limit=1) cls.env.ref("account.data_account_type_revenue").id,
cls.journal = cls.env['account.journal'].create({ )
'name': 'Test sale journal', ],
'type': 'sale', limit=1,
'code': 'TEST', )
}) cls.account_expense = cls.env["account.account"].search(
cls.expenses_journal = cls.env['account.journal'].create({ [
'name': 'Test expense journal', (
'type': 'purchase', "user_type_id",
'code': 'EXP', "=",
}) cls.env.ref("account.data_account_type_expenses").id,
cls.miscellaneous_journal = cls.env['account.journal'].create({ )
'name': 'Miscellaneus journal', ],
'type': 'general', limit=1,
'code': 'OTHER', )
}) cls.journal = cls.env["account.journal"].create(
cls.customer_invoice = cls.env['account.invoice'].create({ {"name": "Test sale journal", "type": "sale", "code": "TEST",}
'journal_id': cls.journal.id, )
'type': 'out_invoice', cls.expenses_journal = cls.env["account.journal"].create(
'partner_id': cls.partner.id, {"name": "Test expense journal", "type": "purchase", "code": "EXP",}
'account_id': cls.account_receivable.id, )
'invoice_line_ids': [(0, 0, { cls.miscellaneous_journal = cls.env["account.journal"].create(
'name': 'Test', {"name": "Miscellaneus journal", "type": "general", "code": "OTHER",}
'price_unit': 100.0, )
'account_id': cls.account_revenue.id, cls.customer_invoice = cls.env["account.invoice"].create(
})], {
}) "journal_id": cls.journal.id,
"type": "out_invoice",
"partner_id": cls.partner.id,
"account_id": cls.account_receivable.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Test",
"price_unit": 100.0,
"account_id": cls.account_revenue.id,
},
)
],
}
)
cls.customer_invoice.action_invoice_open() cls.customer_invoice.action_invoice_open()
customer_move = cls.customer_invoice.move_id customer_move = cls.customer_invoice.move_id
cls.move_line_1 = customer_move.line_ids.filtered( cls.move_line_1 = customer_move.line_ids.filtered(
lambda x: x.account_id == cls.account_receivable) lambda x: x.account_id == cls.account_receivable
cls.supplier_invoice = cls.env['account.invoice'].create({ )
'journal_id': cls.expenses_journal.id, cls.supplier_invoice = cls.env["account.invoice"].create(
'type': 'in_invoice', {
'partner_id': cls.partner.id, "journal_id": cls.expenses_journal.id,
'account_id': cls.account_payable.id, "type": "in_invoice",
'invoice_line_ids': [(0, 0, { "partner_id": cls.partner.id,
'name': 'Test', "account_id": cls.account_payable.id,
'price_unit': 1200.0, "invoice_line_ids": [
'account_id': cls.account_expense.id, (
})], 0,
}) 0,
{
"name": "Test",
"price_unit": 1200.0,
"account_id": cls.account_expense.id,
},
)
],
}
)
cls.supplier_invoice.action_invoice_open() cls.supplier_invoice.action_invoice_open()
supplier_move = cls.supplier_invoice.move_id supplier_move = cls.supplier_invoice.move_id
cls.move_line_2 = supplier_move.line_ids.filtered( cls.move_line_2 = supplier_move.line_ids.filtered(
lambda x: x.account_id == cls.account_payable) lambda x: x.account_id == cls.account_payable
)
cls.move_line_3 = supplier_move.line_ids.filtered( cls.move_line_3 = supplier_move.line_ids.filtered(
lambda x: x.account_id == cls.account_expense) lambda x: x.account_id == cls.account_expense
cls.supplier_invoice = cls.env['account.invoice'].create({ )
'journal_id': cls.expenses_journal.id, cls.supplier_invoice = cls.env["account.invoice"].create(
'type': 'in_invoice', {
'partner_id': cls.partner1.id, "journal_id": cls.expenses_journal.id,
'account_id': cls.account_payable.id, "type": "in_invoice",
'invoice_line_ids': [(0, 0, { "partner_id": cls.partner1.id,
'name': 'Test', "account_id": cls.account_payable.id,
'price_unit': 200.0, "invoice_line_ids": [
'account_id': cls.account_expense.id, (
})], 0,
}) 0,
{
"name": "Test",
"price_unit": 200.0,
"account_id": cls.account_expense.id,
},
)
],
}
)
cls.supplier_invoice.action_invoice_open() cls.supplier_invoice.action_invoice_open()
supplier_move = cls.supplier_invoice.move_id supplier_move = cls.supplier_invoice.move_id
cls.move_line_4 = supplier_move.line_ids.filtered( cls.move_line_4 = supplier_move.line_ids.filtered(
lambda x: x.account_id == cls.account_payable) lambda x: x.account_id == cls.account_payable
cls.supplier_invoice = cls.env['account.invoice'].create({ )
'journal_id': cls.expenses_journal.id, cls.supplier_invoice = cls.env["account.invoice"].create(
'type': 'in_refund', {
'partner_id': cls.partner1.id, "journal_id": cls.expenses_journal.id,
'account_id': cls.account_payable.id, "type": "in_refund",
'invoice_line_ids': [(0, 0, { "partner_id": cls.partner1.id,
'name': 'Test', "account_id": cls.account_payable.id,
'price_unit': 200.0, "invoice_line_ids": [
'account_id': cls.account_expense.id, (
})], 0,
}) 0,
{
"name": "Test",
"price_unit": 200.0,
"account_id": cls.account_expense.id,
},
)
],
}
)
cls.supplier_invoice.action_invoice_open() cls.supplier_invoice.action_invoice_open()
supplier_move = cls.supplier_invoice.move_id supplier_move = cls.supplier_invoice.move_id
cls.move_line_5 = supplier_move.line_ids.filtered( cls.move_line_5 = supplier_move.line_ids.filtered(
lambda x: x.account_id == cls.account_payable) lambda x: x.account_id == cls.account_payable
cls.supplier_invoice = cls.env['account.invoice'].create({ )
'journal_id': cls.expenses_journal.id, cls.supplier_invoice = cls.env["account.invoice"].create(
'type': 'in_refund', {
'partner_id': cls.partner1.id, "journal_id": cls.expenses_journal.id,
'account_id': cls.account_payable.id, "type": "in_refund",
'invoice_line_ids': [(0, 0, { "partner_id": cls.partner1.id,
'name': 'Test', "account_id": cls.account_payable.id,
'price_unit': 200.0, "invoice_line_ids": [
'account_id': cls.account_expense.id, (
})], 0,
}) 0,
{
"name": "Test",
"price_unit": 200.0,
"account_id": cls.account_expense.id,
},
)
],
}
)
cls.supplier_invoice.action_invoice_open() cls.supplier_invoice.action_invoice_open()
supplier_move = cls.supplier_invoice.move_id supplier_move = cls.supplier_invoice.move_id
cls.move_line_6 = supplier_move.line_ids.filtered( cls.move_line_6 = supplier_move.line_ids.filtered(
lambda x: x.account_id == cls.account_payable) lambda x: x.account_id == cls.account_payable
)
def test_compensation(self): def test_compensation(self):
# Test exception line 33 from account_move_make_netting # Test exception line 33 from account_move_make_netting
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(Exception): with self.assertRaises(Exception):
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_1.id])], {
'journal_id': self.miscellaneous_journal.id}) "move_line_ids": [(6, 0, [self.move_line_1.id])],
"journal_id": self.miscellaneous_journal.id,
}
)
# Test exception line 39 from account_move_make_netting # Test exception line 39 from account_move_make_netting
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(Exception): with self.assertRaises(Exception):
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_1.id, {
self.move_line_3.id])], "move_line_ids": [
'journal_id': self.miscellaneous_journal.id}) (6, 0, [self.move_line_1.id, self.move_line_3.id])
],
"journal_id": self.miscellaneous_journal.id,
}
)
# Test exception line 45 from account_move_make_netting # Test exception line 45 from account_move_make_netting
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(Exception): with self.assertRaises(Exception):
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_4.id, {
self.move_line_5.id])], "move_line_ids": [
'journal_id': self.miscellaneous_journal.id}) (6, 0, [self.move_line_4.id, self.move_line_5.id])
],
"journal_id": self.miscellaneous_journal.id,
}
)
# Test exception line 42 from account_move_make_netting # Test exception line 42 from account_move_make_netting
moves = self.env['account.move.line'].browse([self.move_line_4.id, moves = self.env["account.move.line"].browse(
self.move_line_5.id]) [self.move_line_4.id, self.move_line_5.id]
)
moves.reconcile() moves.reconcile()
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(Exception): with self.assertRaises(Exception):
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_4.id, {
self.move_line_5.id])], "move_line_ids": [
'journal_id': self.miscellaneous_journal.id}) (6, 0, [self.move_line_4.id, self.move_line_5.id])
],
"journal_id": self.miscellaneous_journal.id,
}
)
# Test exception line 52 from account_move_make_netting # Test exception line 52 from account_move_make_netting
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(Exception): with self.assertRaises(Exception):
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_1.id, {
self.move_line_6.id])], "move_line_ids": [
'journal_id': self.miscellaneous_journal.id}) (6, 0, [self.move_line_1.id, self.move_line_6.id])
obj = self.env['account.move.make.netting'].with_context( ],
active_ids=[self.move_line_1.id, self.move_line_2.id]) "journal_id": self.miscellaneous_journal.id,
}
)
obj = self.env["account.move.make.netting"].with_context(
active_ids=[self.move_line_1.id, self.move_line_2.id]
)
wizard = obj.create( wizard = obj.create(
{'move_line_ids': [(6, 0, [self.move_line_1.id, {
self.move_line_2.id])], "move_line_ids": [(6, 0, [self.move_line_1.id, self.move_line_2.id])],
'journal_id': self.miscellaneous_journal.id}) "journal_id": self.miscellaneous_journal.id,
}
)
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(
len(move.line_ids), 2, len(move.line_ids), 2, "AR/AP netting move has an incorrect line number"
'AR/AP netting move has an incorrect line number') )
move_line_receivable = move.line_ids.filtered( move_line_receivable = move.line_ids.filtered(
lambda x: x.account_id == self.account_receivable) lambda x: x.account_id == self.account_receivable
)
self.assertEqual( self.assertEqual(
move_line_receivable.credit, 100, move_line_receivable.credit,
'Incorrect credit amount for receivable move line') 100,
"Incorrect credit amount for receivable move line",
)
self.assertTrue( self.assertTrue(
move_line_receivable.reconciled and move_line_receivable.reconciled and move_line_receivable.full_reconcile_id,
move_line_receivable.full_reconcile_id, "Receivable move line should be totally reconciled",
'Receivable move line should be totally reconciled') )
move_line_payable = move.line_ids.filtered( move_line_payable = move.line_ids.filtered(
lambda x: x.account_id == self.account_payable) lambda x: x.account_id == self.account_payable
)
self.assertEqual( self.assertEqual(
move_line_payable.debit, 100, move_line_payable.debit, 100, "Incorrect debit amount for payable move line"
'Incorrect debit amount for payable move line') )
self.assertTrue( self.assertTrue(
move_line_payable.reconciled and not move_line_payable.reconciled and not move_line_payable.full_reconcile_id,
move_line_payable.full_reconcile_id, "Receivable move line should be partially reconciled",
'Receivable move line should be partially reconciled') )

View File

@ -7,83 +7,85 @@ from odoo import _, api, exceptions, fields, models
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"
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')]",
) )
move_line_ids = fields.Many2many( move_line_ids = fields.Many2many(comodel_name="account.move.line",)
comodel_name="account.move.line", balance = fields.Float(readonly=True,)
)
balance = fields.Float(
readonly=True,
)
balance_type = fields.Selection( balance_type = fields.Selection(
selection=[ selection=[("pay", "To pay"), ("receive", "To receive"),], readonly=True,
('pay', 'To pay'),
('receive', 'To receive'),
],
readonly=True,
) )
@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 exceptions.ValidationError(
_("You should compensate at least 2 journal entries.")) _("You should compensate at least 2 journal entries.")
move_lines = self.env['account.move.line'].browse( )
self.env.context['active_ids']) move_lines = self.env["account.move.line"].browse(
if (any(x not in ('payable', 'receivable') for self.env.context["active_ids"]
x in move_lines.mapped('account_id.user_type_id.type'))): )
if any(
x not in ("payable", "receivable")
for x in move_lines.mapped("account_id.user_type_id.type")
):
raise exceptions.ValidationError( raise exceptions.ValidationError(
_("All entries must have a receivable or payable account")) _("All entries must have a receivable or payable account")
if any(move_lines.mapped('reconciled')): )
if any(move_lines.mapped("reconciled")):
raise exceptions.ValidationError(_("All entries mustn't been reconciled"))
if len(move_lines.mapped("account_id")) == 1:
raise exceptions.ValidationError( raise exceptions.ValidationError(
_("All entries mustn't been reconciled")) _(
if len(move_lines.mapped('account_id')) == 1: "The 'Compensate' function is intended to balance "
"operations on different accounts for the same partner.\n"
"In this case all selected entries belong to the same "
"account.\n Please use the 'Reconcile' function."
)
)
if len(move_lines.mapped("partner_id")) != 1:
raise exceptions.ValidationError( raise exceptions.ValidationError(
_("The 'Compensate' function is intended to balance " _(
"operations on different accounts for the same partner.\n" "All entries should have a partner and the partner must "
"In this case all selected entries belong to the same " "be the same for all."
"account.\n Please use the 'Reconcile' function.")) )
if len(move_lines.mapped('partner_id')) != 1: )
raise exceptions.ValidationError(
_("All entries should have a partner and the partner must "
"be the same for all."))
res = super(AccountMoveMakeNetting, self).default_get(fields_list) res = super(AccountMoveMakeNetting, self).default_get(fields_list)
res['move_line_ids'] = [(6, 0, move_lines.ids)] res["move_line_ids"] = [(6, 0, move_lines.ids)]
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'))) - balance = abs(sum(debit_move_lines_debit.mapped("amount_residual"))) - abs(
abs(sum(credit_move_lines_debit.mapped('amount_residual')))) sum(credit_move_lines_debit.mapped("amount_residual"))
res['balance'] = abs(balance) )
res['balance_type'] = 'pay' if balance < 0 else 'receive' res["balance"] = abs(balance)
res["balance_type"] = "pay" if balance < 0 else "receive"
return res return res
def button_compensate(self): def button_compensate(self):
self.ensure_one() self.ensure_one()
# Create account move # Create account move
move = self.env['account.move'].create({ move = self.env["account.move"].create(
'ref': _('AR/AP netting'), {"ref": _("AR/AP netting"), "journal_id": self.journal_id.id,}
'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)],
['account_id', 'amount_residual'], ["account_id", "amount_residual"],
['account_id'], ["account_id"],
) )
debtors = [] debtors = []
creditors = [] creditors = []
total_debtors = 0 total_debtors = 0
total_creditors = 0 total_creditors = 0
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 balance > 0:
debtors.append(group_vals) debtors.append(group_vals)
@ -93,36 +95,37 @@ class AccountMoveMakeNetting(models.TransientModel):
total_creditors += abs(balance) total_creditors += abs(balance)
# Create move lines # Create 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: if account_group["balance"] > available_amount:
amount = available_amount amount = available_amount
else: else:
amount = account_group['balance'] amount = account_group["balance"]
move_line_vals = { move_line_vals = {
field_map[i]: amount, field_map[i]: amount,
'partner_id': self.move_line_ids[0].partner_id.id, "partner_id": self.move_line_ids[0].partner_id.id,
'name': move.ref, "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 available_amount <= 0:
break break
if move_lines: if move_lines:
move.write({'line_ids': move_lines}) move.write({"line_ids": move_lines})
# 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(
lambda x: x.account_id == move_line.account_id) lambda x: x.account_id == move_line.account_id
)
to_reconcile.reconcile() to_reconcile.reconcile()
# Open created move # Open created move
action = self.env.ref('account.action_move_journal_line').read()[0] action = self.env.ref("account.action_move_journal_line").read()[0]
action['view_mode'] = 'form' action["view_mode"] = "form"
del action['views'] del action["views"]
del action['view_id'] del action["view_id"]
action['res_id'] = move.id action["res_id"] = move.id
return action return action

View File

@ -1,33 +1,38 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<act_window
<act_window name="Compensate" name="Compensate"
res_model="account.move.make.netting" res_model="account.move.make.netting"
src_model="account.move.line" src_model="account.move.line"
view_mode="form" view_mode="form"
target="new" target="new"
key2="client_action_multi" key2="client_action_multi"
multi="True" multi="True"
id="act_account_move_make_netting"/> id="act_account_move_make_netting"
/>
<record id="view_account_move_make_netting_form" model="ir.ui.view"> <record id="view_account_move_make_netting_form" model="ir.ui.view">
<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 string="Compensate entries">
<p>This operation will generate account entries that are counterpart of the receivable/payable accounts selected, and reconcile each other, letting this balance in the partner.</p> <p
>This operation will generate account entries that are counterpart of the receivable/payable accounts selected, and reconcile each other, letting this balance in the partner.</p>
<group> <group>
<field name="balance"/> <field name="balance" />
<field name="balance_type"/> <field name="balance_type" />
<field name="journal_id"/> <field name="journal_id" />
</group> </group>
<footer> <footer>
<button name="button_compensate" string="Compensate" type="object" default_focus="1" class="btn-primary"/> <button
name="button_compensate"
string="Compensate"
type="object"
default_focus="1"
class="btn-primary"
/>
<button string="Cancel" class="btn-default" special="cancel" /> <button string="Cancel" class="btn-default" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>