From 881df8becc8174dae961160d261e843e43df4dc1 Mon Sep 17 00:00:00 2001 From: Antonio Espinosa Date: Fri, 21 Oct 2016 15:08:38 +0200 Subject: [PATCH] Consider normal and refund operations separately Allow to explore all move lines Spanish translation Bugfixes Show negative lines too Show move type in account.move views Tests include new fields --- account_tax_balance/__openerp__.py | 4 +- account_tax_balance/i18n/es.po | 261 ++++++++++++++++++ account_tax_balance/models/__init__.py | 1 + account_tax_balance/models/account_move.py | 42 +++ account_tax_balance/models/account_tax.py | 128 ++++++++- .../tests/test_account_tax_balance.py | 41 ++- .../views/account_move_view.xml | 40 +++ .../views/account_tax_view.xml | 116 ++++---- .../wizard/open_tax_balances_view.xml | 76 ++--- 9 files changed, 605 insertions(+), 104 deletions(-) create mode 100644 account_tax_balance/i18n/es.po create mode 100644 account_tax_balance/models/account_move.py create mode 100644 account_tax_balance/views/account_move_view.xml diff --git a/account_tax_balance/__openerp__.py b/account_tax_balance/__openerp__.py index c1077042..10e3e685 100644 --- a/account_tax_balance/__openerp__.py +++ b/account_tax_balance/__openerp__.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # © 2016 Lorenzo Battistini - Agile Business Group +# © 2016 Antonio Espinosa # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Tax Balance", @@ -7,7 +8,7 @@ "version": "9.0.1.0.0", "category": "Accounting & Finance", "website": "https://www.agilebg.com/", - "author": "Agile Business Group, Therp BV, " + "author": "Agile Business Group, Therp BV, Tecnativa, " "Odoo Community Association (OCA)", "license": "AGPL-3", "application": False, @@ -18,6 +19,7 @@ ], "data": [ "wizard/open_tax_balances_view.xml", + "views/account_move_view.xml", "views/account_tax_view.xml", ], "images": [ diff --git a/account_tax_balance/i18n/es.po b/account_tax_balance/i18n/es.po new file mode 100644 index 00000000..41cd1957 --- /dev/null +++ b/account_tax_balance/i18n/es.po @@ -0,0 +1,261 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_tax_balance +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-10-21 15:30+0000\n" +"PO-Revision-Date: 2016-10-21 15:30+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +msgid "Account" +msgstr "Cuenta" + +#. module: account_tax_balance +#: model:ir.model,name:account_tax_balance.model_account_move +msgid "Account Entry" +msgstr "Asiento contable" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "Account Tax" +msgstr "Cuenta de impuesto" + +#. module: account_tax_balance +#: selection:wizard.open.tax.balances,target_move:0 +msgid "All Entries" +msgstr "Todos los asientos" + +#. module: account_tax_balance +#: selection:wizard.open.tax.balances,target_move:0 +msgid "All Posted Entries" +msgstr "Todos los asientos asentados" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_balance_regular +msgid "Balance" +msgstr "Cuota" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_balance_refund +msgid "Balance Refund" +msgstr "Cuota devoluciones" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_base_balance_regular +msgid "Base Balance" +msgstr "Base imponible" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_base_balance_refund +msgid "Base Balance Refund" +msgstr "Base devoluciones" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "Base Total" +msgstr "Base total" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.wizard_open_tax_balances +msgid "Cancel" +msgstr "Cancelar" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_company_id +msgid "Company" +msgstr "Compañía" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_create_date +msgid "Created on" +msgstr "Creado en" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_date_range_id +msgid "Date range" +msgstr "Periodo" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_from_date +msgid "From date" +msgstr "Desde" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +msgid "Group By" +msgstr "Agrupar por" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_id +msgid "ID" +msgstr "ID" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances___last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_write_uid +msgid "Last Updated by" +msgstr "Última modificación por" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Liquidity" +msgstr "Liquidez" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_move_move_type +msgid "Move type" +msgstr "Tipo de operación" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.wizard_open_tax_balances +msgid "Open Taxes" +msgstr "Ver impuestos" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Other" +msgstr "Otro" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Payable" +msgstr "A pagar" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Payable refund" +msgstr "Devoluciones a cobrar" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Receivable" +msgstr "A cobrar" + +#. module: account_tax_balance +#: selection:account.move,move_type:0 +msgid "Receivable refund" +msgstr "Devoluciones a pagar" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "Short Name" +msgstr "Nombre corto" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_target_move +msgid "Target Moves" +msgstr "Movimientos destino" + +#. module: account_tax_balance +#: model:ir.model,name:account_tax_balance.model_account_tax +msgid "Tax" +msgstr "Impuesto" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +msgid "Tax Group" +msgstr "Grupo del impuesto" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_search_balance +msgid "Tax Scope" +msgstr "Uso del impuesto" + +#. module: account_tax_balance +#: model:ir.actions.act_window,name:account_tax_balance.action_open_tax_balances +#: model:ir.actions.act_window,name:account_tax_balance.action_tax_balances_tree +#: model:ir.ui.menu,name:account_tax_balance.menu_action_open_tax_balances +#: model:ir.ui.view,arch_db:account_tax_balance.wizard_open_tax_balances +msgid "Taxes Balance" +msgstr "Tabla de impuestos" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_wizard_open_tax_balances_to_date +msgid "To date" +msgstr "Hasta" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "Total" +msgstr "Total" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_balance +msgid "Total Balance" +msgstr "Total cuota" + +#. module: account_tax_balance +#: model:ir.model.fields,field_description:account_tax_balance.field_account_tax_base_balance +msgid "Total Base Balance" +msgstr "Total base imponible" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View base lines" +msgstr "Ver líneas de base imponible" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View base refund lines" +msgstr "Ver líneas de base imponible de devoluciones" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View base regular lines" +msgstr "Ver líneas de base imponible de operaciones corrientes" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View tax lines" +msgstr "Ver líneas de cuota" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View tax refund lines" +msgstr "Ver líneas de cuota de devoluciones" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.view_tax_tree_balance +msgid "View tax regular lines" +msgstr "Ver líneas de cuota de operaciones corrientes" + +#. module: account_tax_balance +#: model:ir.ui.view,arch_db:account_tax_balance.wizard_open_tax_balances +msgid "or" +msgstr "o" + +#. module: account_tax_balance +#: model:ir.model,name:account_tax_balance.model_wizard_open_tax_balances +msgid "wizard.open.tax.balances" +msgstr "wizard.open.tax.balances" diff --git a/account_tax_balance/models/__init__.py b/account_tax_balance/models/__init__.py index 97aedc09..b78e51cd 100644 --- a/account_tax_balance/models/__init__.py +++ b/account_tax_balance/models/__init__.py @@ -2,4 +2,5 @@ # © 2016 Lorenzo Battistini - Agile Business Group # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import account_move from . import account_tax diff --git a/account_tax_balance/models/account_move.py b/account_tax_balance/models/account_move.py new file mode 100644 index 00000000..a7092c95 --- /dev/null +++ b/account_tax_balance/models/account_move.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# © 2016 Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp import models, fields, api + + +class AccountMove(models.Model): + _inherit = 'account.move' + + move_type = fields.Selection( + string="Move type", selection=[ + ('other', 'Other'), + ('liquidity', 'Liquidity'), + ('receivable', 'Receivable'), + ('receivable_refund', 'Receivable refund'), + ('payable', 'Payable'), + ('payable_refund', 'Payable refund'), + ], compute='_compute_move_type', store=True, readonly=True) + + @api.multi + @api.depends('line_ids.account_id.internal_type', 'line_ids.balance') + def _compute_move_type(self): + def _balance_get(line_ids, internal_type): + return sum(line_ids.filtered( + lambda x: x.account_id.internal_type == internal_type).mapped( + 'balance')) + + for move in self: + internal_types = move.line_ids.mapped('account_id.internal_type') + if 'liquidity' in internal_types: + move.move_type = 'liquidity' + elif 'payable' in internal_types: + balance = _balance_get(move.line_ids, 'payable') + move.move_type = ( + 'payable' if balance < 0 else 'payable_refund') + elif 'receivable' in internal_types: + balance = _balance_get(move.line_ids, 'receivable') + move.move_type = ( + 'receivable' if balance > 0 else 'receivable_refund') + else: + move.move_type = 'other' diff --git a/account_tax_balance/models/account_tax.py b/account_tax_balance/models/account_tax.py index 2a0c149e..a6596899 100644 --- a/account_tax_balance/models/account_tax.py +++ b/account_tax_balance/models/account_tax.py @@ -1,16 +1,68 @@ # -*- coding: utf-8 -*- # © 2016 Lorenzo Battistini - Agile Business Group +# © 2016 Antonio Espinosa # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from openerp import models, fields, api +from openerp.tools.safe_eval import safe_eval class AccountTax(models.Model): _inherit = 'account.tax' - balance = fields.Float(string="Balance", compute="_compute_balance") + balance = fields.Float( + string="Total Balance", compute="_compute_balance", + search='_search_balance') base_balance = fields.Float( - string="Base Balance", compute="_compute_balance") + string="Total Base Balance", compute="_compute_balance", + search='_search_base_balance') + balance_regular = fields.Float( + string="Balance", compute="_compute_balance", + search='_search_balance_regular') + base_balance_regular = fields.Float( + string="Base Balance", compute="_compute_balance", + search='_search_base_balance_regular') + balance_refund = fields.Float( + string="Balance Refund", compute="_compute_balance", + search='_search_balance_refund') + base_balance_refund = fields.Float( + string="Base Balance Refund", compute="_compute_balance", + search='_search_base_balance_refund') + + def _search_balance_field(self, field, operator, value): + operators = {'>', '<', '>=', '<=', '!=', '=', '<>'} + fields = { + 'balance', 'base_balance', 'balance_regular', + 'base_balance_regular', 'balance_refund', 'base_balance_refund', + } + domain = [] + if operator in operators and field in fields: + value = float(value) if value else 0 + taxes = self.search([]).filtered( + lambda x: safe_eval( + '%.2f %s %.2f' % (x[field], operator, value))) + domain.append(('id', 'in', taxes.ids)) + return domain + + def _search_balance(self, operator, value): + return self._search_balance_field('balance', operator, value) + + def _search_base_balance(self, operator, value): + return self._search_balance_field('base_balance', operator, value) + + def _search_balance_regular(self, operator, value): + return self._search_balance_field('balance_regular', operator, value) + + def _search_base_balance_regular(self, operator, value): + return self._search_balance_field( + 'base_balance_regular', operator, value) + + def _search_balance_refund(self, operator, value): + return self._search_balance_field('balance_refund', operator, value) + + def _search_base_balance_refund(self, operator, value): + return self._search_balance_field( + 'base_balance_refund', operator, value) def get_context_values(self): context = self.env.context @@ -23,8 +75,24 @@ class AccountTax(models.Model): def _compute_balance(self): for tax in self: - tax.balance = tax.compute_balance(tax_or_base='tax') - tax.base_balance = tax.compute_balance(tax_or_base='base') + tax.balance_regular = tax.compute_balance( + tax_or_base='tax', move_type='regular') + tax.base_balance_regular = tax.compute_balance( + tax_or_base='base', move_type='regular') + tax.balance_refund = tax.compute_balance( + tax_or_base='tax', move_type='refund') + tax.base_balance_refund = tax.compute_balance( + tax_or_base='base', move_type='refund') + tax.balance = tax.balance_regular + tax.balance_refund + tax.base_balance = ( + tax.base_balance_regular + tax.base_balance_refund) + + def get_target_type_list(self, move_type=None): + if move_type == 'refund': + return ['receivable_refund', 'payable_refund'] + elif move_type == 'regular': + return ['receivable', 'payable'] + return [] def get_target_state_list(self, target_move="posted"): if target_move == 'posted': @@ -42,43 +110,53 @@ class AccountTax(models.Model): ('company_id', '=', company_id), ] - def compute_balance(self, tax_or_base='tax'): + def compute_balance(self, tax_or_base='tax', move_type=None): self.ensure_one() - move_lines = self.get_move_lines_domain(tax_or_base=tax_or_base) + move_lines = self.get_move_lines_domain( + tax_or_base=tax_or_base, move_type=move_type) # balance is debit - credit whereas on tax return you want to see what # vat has to be paid so: # VAT on sales (credit) - VAT on purchases (debit). total = -sum([l.balance for l in move_lines]) return total - def get_balance_domain(self, state_list): - return [ + def get_balance_domain(self, state_list, type_list): + domain = [ ('move_id.state', 'in', state_list), ('tax_line_id', '=', self.id), ] + if type_list: + domain.append(('move_id.move_type', 'in', type_list)) + return domain - def get_base_balance_domain(self, state_list): - return [ + def get_base_balance_domain(self, state_list, type_list): + domain = [ ('move_id.state', 'in', state_list), ('tax_ids', 'in', self.id), ] + if type_list: + domain.append(('move_id.move_type', 'in', type_list)) + return domain - def get_move_lines_domain(self, tax_or_base='tax'): + def get_move_lines_domain(self, tax_or_base='tax', move_type=None): move_line_model = self.env['account.move.line'] from_date, to_date, company_id, target_move = self.get_context_values() state_list = self.get_target_state_list(target_move) + type_list = self.get_target_type_list(move_type) domain = self.get_move_line_partial_domain( from_date, to_date, company_id) balance_domain = [] if tax_or_base == 'tax': - balance_domain = self.get_balance_domain(state_list) + balance_domain = self.get_balance_domain(state_list, type_list) elif tax_or_base == 'base': - balance_domain = self.get_base_balance_domain(state_list) + balance_domain = self.get_base_balance_domain( + state_list, type_list) domain.extend(balance_domain) return move_line_model.search(domain) - def get_lines_action(self, tax_or_base='tax'): - move_lines = self.get_move_lines_domain(tax_or_base=tax_or_base) + def get_lines_action(self, tax_or_base='tax', move_type=None): + move_lines = self.get_move_lines_domain( + tax_or_base=tax_or_base, move_type=move_type) move_line_ids = [l.id for l in move_lines] action = self.env.ref('account.action_account_moves_all_tree') vals = action.read()[0] @@ -95,3 +173,23 @@ class AccountTax(models.Model): def view_base_lines(self): self.ensure_one() return self.get_lines_action(tax_or_base='base') + + @api.multi + def view_tax_regular_lines(self): + self.ensure_one() + return self.get_lines_action(tax_or_base='tax', move_type='regular') + + @api.multi + def view_base_regular_lines(self): + self.ensure_one() + return self.get_lines_action(tax_or_base='base', move_type='regular') + + @api.multi + def view_tax_refund_lines(self): + self.ensure_one() + return self.get_lines_action(tax_or_base='tax', move_type='refund') + + @api.multi + def view_base_refund_lines(self): + self.ensure_one() + return self.get_lines_action(tax_or_base='base', move_type='refund') diff --git a/account_tax_balance/tests/test_account_tax_balance.py b/account_tax_balance/tests/test_account_tax_balance.py index 15d0382d..e66eca5c 100644 --- a/account_tax_balance/tests/test_account_tax_balance.py +++ b/account_tax_balance/tests/test_account_tax_balance.py @@ -33,9 +33,9 @@ class TestAccountTaxBalance(TransactionCase): tax_account_id = self.env['account.account'].search( [('name', '=', 'Tax Paid')], limit=1).id tax = self.env['account.tax'].create({ - 'name': 'Tax 10.0', + 'name': 'Tax 10.0%', 'amount': 10.0, - 'amount_type': 'fixed', + 'amount_type': 'percent', 'account_id': tax_account_id, }) invoice_account_id = self.env['account.account'].search( @@ -67,8 +67,12 @@ class TestAccountTaxBalance(TransactionCase): # change the state of invoice to open by clicking Validate button invoice.signal_workflow('invoice_open') - self.assertEquals(tax.base_balance, 100) - self.assertEquals(tax.balance, 10) + self.assertEquals(tax.base_balance, 100.) + self.assertEquals(tax.balance, 10.) + self.assertEquals(tax.base_balance_regular, 100.) + self.assertEquals(tax.balance_regular, 10.) + self.assertEquals(tax.base_balance_refund, 0.) + self.assertEquals(tax.balance_refund, 0.) # testing wizard current_range = self.range.search([ @@ -110,3 +114,32 @@ class TestAccountTaxBalance(TransactionCase): self.assertEqual(state_list, ['posted', 'draft']) state_list = tax.get_target_state_list(target_move='whatever') self.assertEqual(state_list, []) + + refund = self.env['account.invoice'].create({ + 'partner_id': self.env.ref('base.res_partner_2').id, + 'account_id': invoice_account_id, + 'type': 'out_refund', + }) + + self.env['account.invoice.line'].create({ + 'product_id': self.env.ref('product.product_product_2').id, + 'quantity': 1.0, + 'price_unit': 25.0, + 'invoice_id': refund.id, + 'name': 'returned product that cost 25', + 'account_id': invoice_line_account_id, + 'invoice_line_tax_ids': [(6, 0, [tax.id])], + }) + refund._onchange_invoice_line_ids() + refund._convert_to_write(invoice._cache) + self.assertEqual(refund.state, 'draft') + + # change the state of refund to open by clicking Validate button + refund.signal_workflow('invoice_open') + + self.assertEquals(tax.base_balance, 75.) + self.assertEquals(tax.balance, 7.5) + self.assertEquals(tax.base_balance_regular, 100.) + self.assertEquals(tax.balance_regular, 10.) + self.assertEquals(tax.base_balance_refund, -25.) + self.assertEquals(tax.balance_refund, -2.5) diff --git a/account_tax_balance/views/account_move_view.xml b/account_tax_balance/views/account_move_view.xml new file mode 100644 index 00000000..5211c056 --- /dev/null +++ b/account_tax_balance/views/account_move_view.xml @@ -0,0 +1,40 @@ + + + + + + + Add move type column + account.move + + + + + + + + + + Add move type field + account.move + + + + + + + + + + Add move type group by + account.move + + + + + + + + + diff --git a/account_tax_balance/views/account_tax_view.xml b/account_tax_balance/views/account_tax_view.xml index e3f097cf..fa1895c8 100644 --- a/account_tax_balance/views/account_tax_view.xml +++ b/account_tax_balance/views/account_tax_view.xml @@ -1,49 +1,71 @@ - - + + - - account.tax.tree.balance - account.tax - - - - - - - - - - - - - - - account.tax.search.balance - account.tax - - - - - - - - - - - - - - - - - - Taxes Balance - account.tax - form - tree - - - - - + + account.tax.tree.balance + account.tax + + + + + + + +