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
+
+
+
+
+
+
+
+
+
+
+
+