diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index cefd92e0f6a..399626da736 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -55,7 +55,7 @@ class AccountMove(models.Model): for partial_line in (line.matched_debit_ids + line.matched_credit_ids): total_reconciled += partial_line.amount if total_amount == 0.0: - move.matched_percentage = 100.0 + move.matched_percentage = 1.0 else: move.matched_percentage = total_reconciled / total_amount diff --git a/addons/account/models/res_config.py b/addons/account/models/res_config.py index d8e763ce0ff..de6c105d9b0 100644 --- a/addons/account/models/res_config.py +++ b/addons/account/models/res_config.py @@ -84,6 +84,8 @@ class AccountConfigSettings(models.TransientModel): 'Once the master budgets and the budgets are defined, ' 'the project managers can set the planned amount on each analytic account.\n' '-This installs the module account_budget.') + module_account_tax_cash_basis = fields.Boolean(string="Allow Tax Cash Basis", + help='Generate tax cash basis entrie when reconciliating entries') group_proforma_invoices = fields.Boolean(string='Allow pro-forma invoices', implied_group='account.group_proforma_invoices', help="Allows you to put invoices in pro-forma state.") diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 739d99df3bc..d516a07a99b 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -925,50 +925,6 @@ -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -981,7 +937,7 @@ - + diff --git a/addons/account/views/res_config_view.xml b/addons/account/views/res_config_view.xml index 3e98cba0dc6..918ca8eac63 100644 --- a/addons/account/views/res_config_view.xml +++ b/addons/account/views/res_config_view.xml @@ -131,6 +131,10 @@ diff --git a/addons/account_tax_cash_basis/__init__.py b/addons/account_tax_cash_basis/__init__.py new file mode 100644 index 00000000000..e6b78dead08 --- /dev/null +++ b/addons/account_tax_cash_basis/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import tax_cash_basis diff --git a/addons/account_tax_cash_basis/__openerp__.py b/addons/account_tax_cash_basis/__openerp__.py new file mode 100644 index 00000000000..9120d25a544 --- /dev/null +++ b/addons/account_tax_cash_basis/__openerp__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name' : 'Account Tax Cash Basis', + 'version' : '1.1', + 'author' : 'OpenERP SA', + 'summary': 'Allow to have cash basis on tax', + 'sequence': 4, + 'description': """ + Add an option on tax to allow them to be cash based, meaning that during reconciliation, if there is a tax with + cash basis involved, a new journal entry will be create containing those taxes value. + """, + 'category' : 'Accounting & Finance', + 'website': 'https://www.odoo.com/page/accounting', + 'depends' : ['account'], + 'data': [ + 'views/tax_cash_basis_view.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/addons/account_tax_cash_basis/tax_cash_basis.py b/addons/account_tax_cash_basis/tax_cash_basis.py new file mode 100644 index 00000000000..8f45ab3e3a9 --- /dev/null +++ b/addons/account_tax_cash_basis/tax_cash_basis.py @@ -0,0 +1,115 @@ +# -*- coding: utf-8 -*- + +from openerp import models, fields, api, _ +from openerp.exceptions import UserError + +class AccountTaxCashBasis(models.Model): + _inherit = 'account.tax' + + use_cash_basis = fields.Boolean('Use Cash Basis', help='Select this if the tax should use cash basis, which will \ + create an entry for this tax on a given account during reconciliation') + cash_basis_account = fields.Many2one('account.account', string='Tax Received Account', domain=[('deprecated', '=', False)], help='Account use when \ + creating entry for tax cash basis') + + +class AccountMoveCashBasis(models.Model): + _inherit = 'account.move' + + tax_cash_basis_rec_id = fields.Many2one('account.partial.reconcile', string='Tax Cash Basis Entry of', help="Technical field used to keep track of the tax cash basis reconciliation. This is needed when cancelling the source: it will post the inverse journal entry to cancel that part too.") + + +class AccountConfigSettings(models.TransientModel): + _inherit = 'account.config.settings' + + tax_cash_basis_journal_id = fields.Many2one('account.journal', + related='company_id.tax_cash_basis_journal_id', + string="Tax Cash Basis Journal",) + + +class ResCompany(models.Model): + _inherit = 'res.company' + + tax_cash_basis_journal_id = fields.Many2one('account.journal', string="Tax Cash Basis Journal") + + +class AccountPartialReconcileCashBasis(models.Model): + _inherit = 'account.partial.reconcile' + + def create_tax_cash_basis_entry(self, value_before_reconciliation): + #Search in account_move if we have any taxes account move lines + tax_group = {} + total_by_cash_basis_account = {} + for move in (self.debit_move_id.move_id, self.credit_move_id.move_id): + for line in move.line_ids: + if line.tax_line_id and line.tax_line_id.use_cash_basis: + #amount to write is the current cash_basis amount minus the one before the reconciliation + matched_percentage = value_before_reconciliation[move.id] + amount = (line.credit_cash_basis - line.debit_cash_basis) - (line.credit - line.debit) * matched_percentage + #group by line account + acc = line.account_id.id + if tax_group.get(acc, False): + tax_group[acc] += amount + else: + tax_group[acc] = amount + #Group by cash basis account + acc = line.tax_line_id.cash_basis_account.id + if total_by_cash_basis_account.get(acc, False): + total_by_cash_basis_account[acc] += amount + else: + total_by_cash_basis_account[acc] = amount + line_to_create = [] + for k,v in tax_group.items(): + line_to_create.append((0, 0, { + 'name': '/', + 'debit': v if v > 0 else 0.0, + 'credit': abs(v) if v < 0 else 0.0, + 'account_id': k, + })) + + #Create counterpart vals + for k,v in total_by_cash_basis_account.items(): + line_to_create.append((0, 0, { + 'name': '/', + 'debit': abs(v) if v < 0 else 0.0, + 'credit': v if v > 0 else 0.0, + 'account_id': k, + })) + + #Create move + if len(line_to_create) > 0: + #Check if company_journal for cash basis is set if not, raise exception + if not self.company_id.tax_cash_basis_journal_id: + raise UserError(_('There is no tax cash basis journal defined ' \ + 'for this company: "%s" \nConfigure it in Accounting/Configuration/Settings') % \ + (self.company_id.name)) + move = self.env['account.move'].create({ + 'journal_id': self.company_id.tax_cash_basis_journal_id.id, + 'line_ids': line_to_create, + 'tax_cash_basis_rec_id': self.id}) + #post move + move.post() + + @api.model + def create(self, vals): + aml = [] + if vals.get('debit_move_id', False): + aml.append(vals['debit_move_id']) + if vals.get('credit_move_id', False): + aml.append(vals['credit_move_id']) + #Get value of matched percentage from both move before reconciliating + lines = self.env['account.move.line'].browse(aml) + value_before_reconciliation = {} + for line in lines: + if not value_before_reconciliation.get(line.move_id.id, False): + value_before_reconciliation[line.move_id.id] = line.move_id.matched_percentage + #Reconcile + res = super(AccountPartialReconcileCashBasis, self).create(vals) + #eventually create a tax cash basis entry + res.create_tax_cash_basis_entry(value_before_reconciliation) + return res + + @api.multi + def unlink(self): + move = self.env['account.move'].search([('tax_cash_basis_rec_id', 'in', self._ids)]) + move.reverse_moves() + super(AccountPartialReconcileCashBasis, self).unlink() diff --git a/addons/account_tax_cash_basis/views/tax_cash_basis_view.xml b/addons/account_tax_cash_basis/views/tax_cash_basis_view.xml new file mode 100644 index 00000000000..4c1d06d1aa2 --- /dev/null +++ b/addons/account_tax_cash_basis/views/tax_cash_basis_view.xml @@ -0,0 +1,32 @@ + + + + + + tax.form.cash.basis.inherit + account.tax + + + + + + + + + + + view.account.config.cash.basis.form.inherit + + account.config.settings + + +
+
+
+
+
+ +
+