144 lines
7.2 KiB
Python
144 lines
7.2 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||
|
|
||
|
from odoo import api, models, _
|
||
|
from odoo.exceptions import UserError
|
||
|
from odoo.tools import float_is_zero
|
||
|
|
||
|
|
||
|
class AccountPartialReconcileCashBasis(models.Model):
|
||
|
_inherit = 'account.partial.reconcile'
|
||
|
|
||
|
def _get_tax_cash_basis_base_account(self, line, tax):
|
||
|
''' Get the account of lines that will contain the base amount of taxes.
|
||
|
|
||
|
:param line: An account.move.line record
|
||
|
:param tax: An account.tax record
|
||
|
:return: An account record
|
||
|
'''
|
||
|
return line.account_id
|
||
|
|
||
|
def _get_tax_cash_basis_lines(self, value_before_reconciliation):
|
||
|
# Search in account_move if we have any taxes account move lines
|
||
|
tax_group = {}
|
||
|
total_by_cash_basis_account = {}
|
||
|
line_to_create = []
|
||
|
move_date = self.debit_move_id.date
|
||
|
for move in (self.debit_move_id.move_id, self.credit_move_id.move_id):
|
||
|
if move_date < move.date:
|
||
|
move_date = move.date
|
||
|
for line in move.line_ids:
|
||
|
#TOCHECK: normal and cash basis taxes shoudn't be mixed together (on the same invoice line for example) as it will
|
||
|
#create reporting issues. Not sure of the behavior to implement in that case, though.
|
||
|
# amount to write is the current cash_basis amount minus the one before the reconciliation
|
||
|
currency_id = line.currency_id or line.company_id.currency_id
|
||
|
matched_percentage = value_before_reconciliation[move.id]
|
||
|
amount = currency_id.round((line.credit_cash_basis - line.debit_cash_basis) - (line.credit - line.debit) * matched_percentage)
|
||
|
if not float_is_zero(amount, precision_rounding=currency_id.rounding) and not line.tax_exigible:
|
||
|
if line.tax_line_id and line.tax_line_id.use_cash_basis:
|
||
|
# 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 and tax
|
||
|
acc = line.tax_line_id.cash_basis_account.id
|
||
|
if not acc:
|
||
|
raise UserError(_('Please configure a Tax Received Account for tax %s') % line.tax_line_id.name)
|
||
|
key = (acc, line.tax_line_id.id)
|
||
|
if key in total_by_cash_basis_account:
|
||
|
total_by_cash_basis_account[key] += amount
|
||
|
else:
|
||
|
total_by_cash_basis_account[key] = amount
|
||
|
if any([tax.use_cash_basis for tax in line.tax_ids]):
|
||
|
for tax in line.tax_ids:
|
||
|
account_id = self._get_tax_cash_basis_base_account(line, tax)
|
||
|
line_to_create.append((0, 0, {
|
||
|
'name': '/',
|
||
|
'debit': currency_id.round(line.debit_cash_basis - line.debit * matched_percentage),
|
||
|
'credit': currency_id.round(line.credit_cash_basis - line.credit * matched_percentage),
|
||
|
'account_id': account_id.id,
|
||
|
'tax_ids': [(6, 0, [tax.id])],
|
||
|
'tax_exigible': True,
|
||
|
}))
|
||
|
line_to_create.append((0, 0, {
|
||
|
'name': '/',
|
||
|
'credit': currency_id.round(line.debit_cash_basis - line.debit * matched_percentage),
|
||
|
'debit': currency_id.round(line.credit_cash_basis - line.credit * matched_percentage),
|
||
|
'account_id': account_id.id,
|
||
|
'tax_exigible': True,
|
||
|
}))
|
||
|
|
||
|
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,
|
||
|
'tax_exigible': True,
|
||
|
}))
|
||
|
|
||
|
# Create counterpart vals
|
||
|
for key, v in total_by_cash_basis_account.items():
|
||
|
k, tax_id = key
|
||
|
# Only entries with cash flow must be created
|
||
|
if not self.company_id.currency_id.is_zero(v):
|
||
|
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,
|
||
|
'tax_line_id': tax_id,
|
||
|
'tax_exigible': True,
|
||
|
}))
|
||
|
return line_to_create, move_date
|
||
|
|
||
|
def create_tax_cash_basis_entry(self, value_before_reconciliation):
|
||
|
line_to_create, move_date = self._get_tax_cash_basis_lines(value_before_reconciliation)
|
||
|
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_vals = {
|
||
|
'journal_id': self.company_id.tax_cash_basis_journal_id.id,
|
||
|
'line_ids': line_to_create,
|
||
|
'tax_cash_basis_rec_id': self.id
|
||
|
}
|
||
|
# The move date should be the maximum date between payment and invoice (in case
|
||
|
# of payment in advance). However, we should make sure the move date is not
|
||
|
# recorded after the period lock date as the tax statement for this period is
|
||
|
# probably already sent to the estate.
|
||
|
if move_date > self.company_id.period_lock_date:
|
||
|
move_vals['date'] = move_date
|
||
|
move = self.env['account.move'].create(move_vals)
|
||
|
# 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()
|