From d8c4332c8dc7efa6a4c87aa6cf3336156e595bb1 Mon Sep 17 00:00:00 2001 From: oco-odoo Date: Thu, 15 Jul 2021 20:22:02 +0000 Subject: [PATCH] [IMP] account: allow mixing cash basis and non-cash basis taxes on the same line The tax_exigible field of account.move.line made it impossible to mix 'on_payment' and 'on_invoice' taxes on the same invoice line, as the base line couldn't be be tax exigible and non-tax exigible at the same time. However, this use case is needed by some countries in order to implement withholding taxes. To solve that, we totally remove the tax_exigible field from account.move.line and instead compute it on the fly with a domain (also passed to the query_get for SQL queries). An 'always_tax_exigible' stored computed field is also added on account.move, in order to still allow (like before) putting cash basis taxes on a miscellaneous operation without any payable/receivable line and still see it become exigible without needing any payment. [IMP] account: improve cash basis traceability A smart button is now available on invoices generating cash basis entries, so see them all at once. The move originally creating cash basis entries is also shown as a field on them. Task: 2457374 Part-of: odoo/odoo#74138 --- addons/account/models/account_move.py | 189 +++++++++++++----- .../models/account_move_line_tax_details.py | 8 +- .../models/account_partial_reconcile.py | 49 ++--- .../account/models/account_reconcile_model.py | 1 - addons/account/models/account_tax.py | 21 +- addons/account/tests/common.py | 3 +- .../tests/test_account_move_in_invoice.py | 11 - .../tests/test_account_move_in_refund.py | 11 - .../tests/test_account_move_out_invoice.py | 15 -- .../tests/test_account_move_out_refund.py | 11 - .../tests/test_account_move_reconcile.py | 77 +------ addons/account/views/account_move_views.xml | 13 +- .../account_tax_python/models/account_tax.py | 4 +- 13 files changed, 208 insertions(+), 205 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 81f1efa12a7..94068e26b2f 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -250,10 +250,22 @@ class AccountMove(models.Model): 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.") - tax_cash_basis_move_id = fields.Many2one( + tax_cash_basis_origin_move_id = fields.Many2one( comodel_name='account.move', - string="Origin Tax Cash Basis Entry", + string="Cash Basis Origin", + readonly=1, help="The journal entry from which this tax cash basis journal entry has been created.") + tax_cash_basis_created_move_ids = fields.One2many( + string="Cash Basis Entries", + comodel_name='account.move', + inverse_name='tax_cash_basis_origin_move_id', + help="The cash basis entries created from the taxes on this entry, when reconciling its lines." + ) + always_tax_exigible = fields.Boolean( + compute='_compute_always_tax_exigible', + store=True, + help="Technical field used by cash basis taxes, telling the lines of the move are always exigible. " + "This happens if the move contains no payable or receivable line.") # ==== Auto-post feature fields ==== auto_post = fields.Boolean(string='Post Automatically', default=False, copy=False, @@ -666,6 +678,7 @@ class AccountMove(models.Model): partner=base_line.partner_id, is_refund=is_refund, handle_price_include=handle_price_include, + include_caba_tags=move.always_tax_exigible, ) taxes_map = {} @@ -703,7 +716,6 @@ class AccountMove(models.Model): if not recompute_tax_base_amount: line.tax_tag_ids = compute_all_vals['base_tags'] or [(5, 0, 0)] - tax_exigible = True for tax_vals in compute_all_vals['taxes']: grouping_dict = self._get_tax_grouping_key_from_base_line(line, tax_vals) grouping_key = _serialize_tax_grouping_key(grouping_dict) @@ -711,9 +723,6 @@ class AccountMove(models.Model): tax_repartition_line = self.env['account.tax.repartition.line'].browse(tax_vals['tax_repartition_line_id']) tax = tax_repartition_line.invoice_tax_id or tax_repartition_line.refund_tax_id - if tax.tax_exigibility == 'on_payment': - tax_exigible = False - taxes_map_entry = taxes_map.setdefault(grouping_key, { 'tax_line': None, 'amount': 0.0, @@ -723,8 +732,6 @@ class AccountMove(models.Model): taxes_map_entry['amount'] += tax_vals['amount'] taxes_map_entry['tax_base_amount'] += self._get_base_amount_to_display(tax_vals['base'], tax_repartition_line, tax_vals['group']) taxes_map_entry['grouping_dict'] = grouping_dict - if not recompute_tax_base_amount: - line.tax_exigible = tax_exigible # ==== Process taxes_map ==== for taxes_map_entry in taxes_map.values(): @@ -782,7 +789,6 @@ class AccountMove(models.Model): 'company_currency_id': line.company_currency_id.id, 'tax_base_amount': tax_base_amount, 'exclude_from_invoice_tab': True, - 'tax_exigible': tax.tax_exigibility == 'on_invoice', **taxes_map_entry['grouping_dict'], }) @@ -801,19 +807,6 @@ class AccountMove(models.Model): return -base_amount return base_amount - def update_lines_tax_exigibility(self): - if all(account.user_type_id.type not in {'payable', 'receivable'} for account in self.mapped('line_ids.account_id')): - self.line_ids.write({'tax_exigible': True}) - else: - tax_lines_caba = self.line_ids.filtered(lambda x: x.tax_line_id.tax_exigibility == 'on_payment') - base_lines_caba = self.line_ids.filtered(lambda x: any(tax.tax_exigibility == 'on_payment' - or (tax.amount_type == 'group' - and 'on_payment' in tax.mapped('children_tax_ids.tax_exigibility')) - for tax in x.tax_ids)) - caba_lines = tax_lines_caba + base_lines_caba - caba_lines.write({'tax_exigible': False}) - (self.line_ids - caba_lines).write({'tax_exigible': True}) - def _recompute_cash_rounding_lines(self): ''' Handle the cash rounding feature on invoices. @@ -880,7 +873,6 @@ class AccountMove(models.Model): 'name': _('%s (rounding)', biggest_tax_line.name), 'account_id': biggest_tax_line.account_id.id, 'tax_repartition_line_id': biggest_tax_line.tax_repartition_line_id.id, - 'tax_exigible': biggest_tax_line.tax_exigible, 'exclude_from_invoice_tab': True, }) @@ -1696,6 +1688,16 @@ class AccountMove(models.Model): else: move.tax_lock_date_message = False + @api.depends('line_ids.account_id.internal_type') + def _compute_always_tax_exigible(self): + for record in self: + # We need to check is_invoice as well because always_tax_exigible is used to + # set the tags as well, during the encoding. So, if no receivable/payable + # line has been created yet, the invoice would be detected as always exigible, + # and set the tags on some lines ; which would be wrong. + record.always_tax_exigible = not record.is_invoice(True) \ + and not record._collect_tax_cash_basis_values() + @api.depends('restrict_mode_hash_table', 'state') def _compute_show_reset_to_draft_button(self): for move in self: @@ -2008,11 +2010,7 @@ class AccountMove(models.Model): raise UserError(_('You cannot create a move already in the posted state. Please create a draft move and post it after.')) vals_list = self._move_autocomplete_invoice_lines_create(vals_list) - rslt = super(AccountMove, self).create(vals_list) - for i, vals in enumerate(vals_list): - if 'line_ids' in vals: - rslt[i].update_lines_tax_exigibility() - return rslt + return super(AccountMove, self).create(vals_list) def write(self, vals): for move in self: @@ -2060,10 +2058,8 @@ class AccountMove(models.Model): res |= super(AccountMove, move).write(vals_hashing) # Ensure the move is still well balanced. - if 'line_ids' in vals: - if self._context.get('check_move_validity', True): - self._check_balanced() - self.update_lines_tax_exigibility() + if 'line_ids' in vals and self._context.get('check_move_validity', True): + self._check_balanced() self._synchronize_business_models(set(vals.keys())) @@ -2142,7 +2138,14 @@ class AccountMove(models.Model): - Compute the lines to be processed and the amounts needed to compute a percentage. :return: A dictionary: * move: The current account.move record passed as parameter. - * to_process_lines: An account.move.line recordset being not exigible on the tax report. + * to_process_lines: A tuple (caba_treatment, line) where: + - caba_treatment is either 'tax' or 'base', depending on what should + be considered on the line when generating the caba entry. + For example, a line with tax_ids=caba and tax_line_id=non_caba + will have a 'base' caba treatment, as we only want to treat its base + part in the caba entry (the tax part is already exigible on the invoice) + + - line is an account.move.line record being not exigible on the tax report. * currency: The currency on which the percentage has been computed. * total_balance: sum(payment_term_lines.mapped('balance'). * total_residual: sum(payment_term_lines.mapped('amount_residual'). @@ -2154,7 +2157,7 @@ class AccountMove(models.Model): values = { 'move': self, - 'to_process_lines': self.env['account.move.line'], + 'to_process_lines': [], 'total_balance': 0.0, 'total_residual': 0.0, 'total_amount_currency': 0.0, @@ -2167,17 +2170,20 @@ class AccountMove(models.Model): if line.account_internal_type in ('receivable', 'payable'): sign = 1 if line.balance > 0.0 else -1 - currencies.add(line.currency_id or line.company_currency_id) + currencies.add(line.currency_id) has_term_lines = True values['total_balance'] += sign * line.balance values['total_residual'] += sign * line.amount_residual values['total_amount_currency'] += sign * line.amount_currency values['total_residual_currency'] += sign * line.amount_residual_currency - elif not line.tax_exigible: + elif line.tax_line_id.tax_exigibility == 'on_payment': + values['to_process_lines'].append(('tax', line)) + currencies.add(line.currency_id) - values['to_process_lines'] += line - currencies.add(line.currency_id or line.company_currency_id) + elif 'on_payment' in line.tax_ids.mapped('tax_exigibility'): + values['to_process_lines'].append(('base', line)) + currencies.add(line.currency_id) if not values['to_process_lines'] or not has_term_lines: return None @@ -2189,7 +2195,7 @@ class AccountMove(models.Model): # Don't support the case where there is multiple involved currencies. return None - # Determine is the move is now fully paid. + # Determine whether the move is now fully paid. values['is_fully_paid'] = self.company_id.currency_id.is_zero(values['total_residual']) \ or values['currency'].is_zero(values['total_residual_currency']) @@ -2560,6 +2566,17 @@ class AccountMove(models.Model): 'views': [(False, 'form')], } + def open_created_caba_entries(self): + self.ensure_one() + return { + 'type': 'ir.actions.act_window', + 'name': _("Cash Basis Entries"), + 'res_model': 'account.move', + 'view_mode': 'form', + 'domain': [('id', 'in', self.tax_cash_basis_created_move_ids.ids)], + 'views': [(self.env.ref('account.view_move_tree').id, 'tree'), (False, 'form')], + } + @api.model def message_new(self, msg_dict, custom_values=None): # OVERRIDE @@ -2798,7 +2815,12 @@ class AccountMove(models.Model): for move in self: if move in move.line_ids.mapped('full_reconcile_id.exchange_move_id'): raise UserError(_('You cannot reset to draft an exchange difference journal entry.')) - if move.tax_cash_basis_rec_id: + if move.tax_cash_basis_rec_id or move.tax_cash_basis_origin_move_id: + # If the reconciliation was undone, move.tax_cash_basis_rec_id will be empty; + # but we still don't want to allow setting the caba entry to draft + # (it'll have been reversed automatically, so no manual intervention is required), + # so we also check tax_cash_basis_origin_move_id, which stays unchanged + # (we need both, as tax_cash_basis_origin_move_id did not exist in older versions). raise UserError(_('You cannot reset to draft a tax cash basis journal entry.')) if move.restrict_mode_hash_table and move.state == 'posted' and move.id not in excluded_move_ids: raise UserError(_('You cannot modify a posted entry of this journal because it is in strict mode.')) @@ -3280,10 +3302,6 @@ class AccountMoveLine(models.Model): help='technical field for widget tax-group-custom-field') tax_base_amount = fields.Monetary(string="Base Amount", store=True, readonly=True, currency_field='company_currency_id') - tax_exigible = fields.Boolean(string='Appears in VAT report', default=True, readonly=True, - help="Technical field used to mark a tax line as exigible in the vat report or not (only exigible journal items" - " are displayed). By default all new journal items are directly exigible, but with the feature cash_basis" - " on taxes, some will become exigible only when the payment is recorded.") tax_repartition_line_id = fields.Many2one(comodel_name='account.tax.repartition.line', string="Originator Tax Distribution Line", ondelete='restrict', readonly=True, check_company=True, @@ -3761,6 +3779,40 @@ class AccountMoveLine(models.Model): vals = {'price_unit': 0.0} return vals + @api.model + def _get_tax_exigible_domain(self): + """ Returns a domain to be used to identify the move lines that are allowed + to be taken into account in the tax report. + """ + return [ + # Lines on moves without any payable or receivable line are always exigible + '|', ('move_id.always_tax_exigible', '=', True), + + # Lines with only tags are always exigible + '|', '&', ('tax_line_id', '=', False), ('tax_ids', '=', False), + + # Lines from CABA entries are always exigible + '|', ('move_id.tax_cash_basis_rec_id', '!=', False), + + # Lines from non-CABA taxes are always exigible + '|', ('tax_line_id.tax_exigibility', '!=', 'on_payment'), + ('tax_ids.tax_exigibility', '!=', 'on_payment'), # So: exigible if at least one tax from tax_ids isn't on_payment + ] + + def belongs_to_refund(self): + """ Tells whether or not this move line corresponds to a refund operation. + """ + self.ensure_one() + + if self.tax_repartition_line_id: + return self.tax_repartition_line_id.refund_tax_id + + elif self.move_id.move_type == 'entry': + tax_type = self.tax_ids[0].type_tax_use if self.tax_ids else None + return (tax_type == 'sale' and self.debit) or (tax_type == 'purchase' and self.credit) + + return self.move_id.move_type in ('in_refund', 'out_refund') + # ------------------------------------------------------------------------- # ONCHANGE METHODS # ------------------------------------------------------------------------- @@ -4077,6 +4129,47 @@ class AccountMoveLine(models.Model): "You can just change some non legal fields or you must unreconcile first.\n" "Journal Entry (id): %s (%s)") % (line.move_id.name, line.move_id.id)) + @api.constrains('tax_ids', 'tax_repartition_line_id') + def _check_caba_non_caba_shared_tags(self): + """ When mixing cash basis and non cash basis taxes, it is important + that those taxes don't share tags on the repartition creating + a single account.move.line. + + Shared tags in this context cannot work, as the tags would need to + be present on both the invoice and cash basis move, leading to the same + base amount to be taken into account twice; which is wrong.This is + why we don't support that. A workaround may be provided by the use of + a group of taxes, whose children are type_tax_use=None, and only one + of them uses the common tag. + + Note that taxes of the same exigibility are allowed to share tags. + """ + def get_base_repartition(base_aml, taxes): + if not taxes: + return self.env['account.tax.repartition.line'] + + is_refund = base_aml.belongs_to_refund() + repartition_field = is_refund and 'refund_repartition_line_ids' or 'invoice_repartition_line_ids' + return taxes.mapped(repartition_field) + + for aml in self: + caba_taxes = aml.tax_ids.filtered(lambda x: x.tax_exigibility == 'on_payment') + non_caba_taxes = aml.tax_ids - caba_taxes + + caba_base_tags = get_base_repartition(aml, caba_taxes).filtered(lambda x: x.repartition_type == 'base').tag_ids + non_caba_base_tags = get_base_repartition(aml, non_caba_taxes).filtered(lambda x: x.repartition_type == 'base').tag_ids + + common_tags = caba_base_tags & non_caba_base_tags + + if not common_tags: + # When a tax is affecting another one with different tax exigibility, tags cannot be shared either. + tax_tags = aml.tax_repartition_line_id.tag_ids + comparison_tags = non_caba_base_tags if aml.tax_repartition_line_id.tax_id.tax_exigibility == 'on_payment' else caba_base_tags + common_tags = tax_tags & comparison_tags + + if common_tags: + raise ValidationError(_("Taxes exigible on payment and on invoice cannot be mixed on the same journal item if they share some tag.")) + # ------------------------------------------------------------------------- # LOW-LEVEL METHODS # ------------------------------------------------------------------------- @@ -4647,7 +4740,7 @@ class AccountMoveLine(models.Model): # to compute the residual amount for each of them. # ========================================================================== - for line in move_values['to_process_lines']: + for caba_treatment, line in move_values['to_process_lines']: vals = { 'currency_id': line.currency_id.id, @@ -4658,7 +4751,7 @@ class AccountMoveLine(models.Model): 'credit': line.credit, } - if line.tax_repartition_line_id: + if caba_treatment == 'tax': # Tax line. grouping_key = self.env['account.partial.reconcile']._get_cash_basis_tax_line_grouping_key_from_record(line) if grouping_key in account_vals_to_fix: @@ -4678,7 +4771,7 @@ class AccountMoveLine(models.Model): 'tax_base_amount': line.tax_base_amount, 'tax_repartition_line_id': line.tax_repartition_line_id.id, } - elif line.tax_ids: + elif caba_treatment == 'base': # Base line. account_to_fix = line.company_id.account_cash_basis_base_account_id if not account_to_fix: @@ -4702,7 +4795,7 @@ class AccountMoveLine(models.Model): # in order to retrieve the residual balance of each involved transfer account. # ========================================================================== - cash_basis_moves = self.env['account.move'].search([('tax_cash_basis_move_id', '=', move.id)]) + cash_basis_moves = self.env['account.move'].search([('tax_cash_basis_origin_move_id', '=', move.id)]) for line in cash_basis_moves.line_ids: grouping_key = None if line.tax_repartition_line_id: diff --git a/addons/account/models/account_move_line_tax_details.py b/addons/account/models/account_move_line_tax_details.py index 47c8a0367f8..9a1501f5ceb 100644 --- a/addons/account/models/account_move_line_tax_details.py +++ b/addons/account/models/account_move_line_tax_details.py @@ -387,7 +387,11 @@ class AccountMoveLine(models.Model): comp_curr.decimal_places AS comp_curr_prec, curr.id AS currency_id, curr.decimal_places AS curr_prec, - tax_line.tax_exigible, + ( + tax.tax_exigibility != 'on_payment' + OR tax_move.tax_cash_basis_rec_id IS NOT NULL + OR tax_move.always_tax_exigible + ) AS tax_exigible, base_line.account_id AS base_account_id, sub.base_amount, @@ -423,6 +427,8 @@ class AccountMoveLine(models.Model): FROM base_tax_matching_base_amounts sub JOIN account_move_line tax_line ON tax_line.id = sub.tax_line_id + JOIN account_move tax_move ON + tax_move.id = tax_line.move_id JOIN account_move_line base_line ON base_line.id = sub.base_line_id JOIN account_tax tax ON diff --git a/addons/account/models/account_partial_reconcile.py b/addons/account/models/account_partial_reconcile.py index e32c9727f96..ef1f2d9dec0 100644 --- a/addons/account/models/account_partial_reconcile.py +++ b/addons/account/models/account_partial_reconcile.py @@ -230,6 +230,9 @@ class AccountPartialReconcile(models.Model): account.move.line. ''' account = base_line.company_id.account_cash_basis_base_account_id or base_line.account_id + tax_ids = base_line.tax_ids.filtered(lambda x: x.tax_exigibility == 'on_payment') + is_refund = base_line.belongs_to_refund() + return { 'name': base_line.move_id.name, 'debit': balance if balance > 0.0 else 0.0, @@ -238,9 +241,8 @@ class AccountPartialReconcile(models.Model): 'currency_id': base_line.currency_id.id, 'partner_id': base_line.partner_id.id, 'account_id': account.id, - 'tax_ids': [(6, 0, base_line.tax_ids.ids)], - 'tax_tag_ids': [(6, 0, base_line.tax_tag_ids.ids)], - 'tax_exigible': True, + 'tax_ids': [Command.set(tax_ids.ids)], + 'tax_tag_ids': [Command.set(tax_ids.get_tax_tags(is_refund, 'base').ids)], 'tax_tag_invert': base_line.tax_tag_invert, } @@ -261,7 +263,6 @@ class AccountPartialReconcile(models.Model): 'amount_currency': -cb_base_line_vals['amount_currency'], 'currency_id': cb_base_line_vals['currency_id'], 'partner_id': cb_base_line_vals['partner_id'], - 'tax_exigible': True, } @api.model @@ -274,19 +275,22 @@ class AccountPartialReconcile(models.Model): :return: A python dictionary that could be passed to the create method of account.move.line. ''' + tax_ids = tax_line.tax_ids.filtered(lambda x: x.tax_exigibility == 'on_payment') + base_tags = tax_ids.get_tax_tags(tax_line.tax_repartition_line_id.refund_tax_id, 'base') + all_tags = base_tags + tax_line.tax_repartition_line_id.tag_ids + return { 'name': tax_line.name, 'debit': balance if balance > 0.0 else 0.0, 'credit': -balance if balance < 0.0 else 0.0, 'tax_base_amount': tax_line.tax_base_amount, 'tax_repartition_line_id': tax_line.tax_repartition_line_id.id, - 'tax_ids': [(6, 0, tax_line.tax_ids.ids)], - 'tax_tag_ids': [(6, 0, tax_line.tax_tag_ids.ids)], + 'tax_ids': [Command.set(tax_ids.ids)], + 'tax_tag_ids': [Command.set(all_tags.ids)], 'account_id': tax_line.tax_repartition_line_id.account_id.id or tax_line.account_id.id, 'amount_currency': amount_currency, 'currency_id': tax_line.currency_id.id, 'partner_id': tax_line.partner_id.id, - 'tax_exigible': True, # No need to set tax_tag_invert as on the base line; it will be computed from the repartition line } @@ -308,7 +312,6 @@ class AccountPartialReconcile(models.Model): 'amount_currency': -cb_tax_line_vals['amount_currency'], 'currency_id': cb_tax_line_vals['currency_id'], 'partner_id': cb_tax_line_vals['partner_id'], - 'tax_exigible': True, } @api.model @@ -317,12 +320,13 @@ class AccountPartialReconcile(models.Model): :param base_line_vals: The values to create a new account.move.line record. :return: The grouping key as a tuple. ''' + tax_ids = base_line_vals['tax_ids'][0][2] # Decode [(6, 0, [...])] command + base_taxes = self.env['account.tax'].browse(tax_ids) return ( base_line_vals['currency_id'], base_line_vals['partner_id'], base_line_vals['account_id'], - tuple(base_line_vals['tax_ids'][0][2]), # Decode [(6, 0, [...])] command - tuple(base_line_vals['tax_tag_ids'][0][2]), # Decode [(6, 0, [...])] command + tuple(base_taxes.filtered(lambda x: x.tax_exigibility == 'on_payment').ids), ) @api.model @@ -336,8 +340,7 @@ class AccountPartialReconcile(models.Model): base_line.currency_id.id, base_line.partner_id.id, (account or base_line.account_id).id, - tuple(base_line.tax_ids.ids), - tuple(base_line.tax_tag_ids.ids), + tuple(base_line.tax_ids.filtered(lambda x: x.tax_exigibility == 'on_payment').ids), ) @api.model @@ -346,12 +349,13 @@ class AccountPartialReconcile(models.Model): :param tax_line_vals: The values to create a new account.move.line record. :return: The grouping key as a tuple. ''' + tax_ids = tax_line_vals['tax_ids'][0][2] # Decode [(6, 0, [...])] command + base_taxes = self.env['account.tax'].browse(tax_ids) return ( tax_line_vals['currency_id'], tax_line_vals['partner_id'], tax_line_vals['account_id'], - tuple(tax_line_vals['tax_ids'][0][2]), # Decode [(6, 0, [...])] command - tuple(tax_line_vals['tax_tag_ids'][0][2]), # Decode [(6, 0, [...])] command + tuple(base_taxes.filtered(lambda x: x.tax_exigibility == 'on_payment').ids), tax_line_vals['tax_repartition_line_id'], ) @@ -366,8 +370,7 @@ class AccountPartialReconcile(models.Model): tax_line.currency_id.id, tax_line.partner_id.id, (account or tax_line.account_id).id, - tuple(tax_line.tax_ids.ids), - tuple(tax_line.tax_tag_ids.ids), + tuple(tax_line.tax_ids.filtered(lambda x: x.tax_exigibility == 'on_payment').ids), tax_line.tax_repartition_line_id.id, ) @@ -394,15 +397,15 @@ class AccountPartialReconcile(models.Model): 'journal_id': partial.company_id.tax_cash_basis_journal_id.id, 'line_ids': [], 'tax_cash_basis_rec_id': partial.id, - 'tax_cash_basis_move_id': move.id, - 'fiscal_position_id': move.fiscal_position_id, + 'tax_cash_basis_origin_move_id': move.id, + 'fiscal_position_id': move.fiscal_position_id.id, } # Tracking of lines grouped all together. # Used to reduce the number of generated lines and to avoid rounding issues. partial_lines_to_create = {} - for line in move_values['to_process_lines']: + for caba_treatment, line in move_values['to_process_lines']: # ========================================================================== # Compute the balance of the current line on the cash basis entry. @@ -424,12 +427,12 @@ class AccountPartialReconcile(models.Model): # and well reported in the Tax Report. # ========================================================================== - if line.tax_repartition_line_id: + if caba_treatment == 'tax': # Tax line. cb_line_vals = self._prepare_cash_basis_tax_line_vals(line, balance, amount_currency) grouping_key = self._get_cash_basis_tax_line_grouping_key_from_vals(cb_line_vals) - elif line.tax_ids: + elif caba_treatment == 'base': # Base line. cb_line_vals = self._prepare_cash_basis_base_line_vals(line, balance, amount_currency) @@ -448,7 +451,7 @@ class AccountPartialReconcile(models.Model): 'amount_currency': aggregated_vals['amount_currency'] + cb_line_vals['amount_currency'], }) - if line.tax_repartition_line_id: + if caba_treatment == 'tax': aggregated_vals.update({ 'tax_base_amount': aggregated_vals['tax_base_amount'] + cb_line_vals['tax_base_amount'], }) @@ -457,7 +460,7 @@ class AccountPartialReconcile(models.Model): partial_lines_to_create[grouping_key] = { 'vals': cb_line_vals, } - if line.tax_repartition_line_id: + if caba_treatment == 'tax': partial_lines_to_create[grouping_key].update({ 'tax_line': line, }) diff --git a/addons/account/models/account_reconcile_model.py b/addons/account/models/account_reconcile_model.py index 1d7664d995c..9a2c4014a2d 100644 --- a/addons/account/models/account_reconcile_model.py +++ b/addons/account/models/account_reconcile_model.py @@ -338,7 +338,6 @@ class AccountReconcileModel(models.Model): 'credit': balance < 0 and -balance or 0, 'analytic_account_id': tax.analytic and base_line_dict['analytic_account_id'], 'analytic_tag_ids': tax.analytic and base_line_dict['analytic_tag_ids'], - 'tax_exigible': tax_res['tax_exigibility'], 'tax_repartition_line_id': tax_res['tax_repartition_line_id'], 'tax_ids': [(6, 0, tax_res['tax_ids'])], 'tax_tag_ids': [(6, 0, tax_res['tag_ids'])], diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index be7f55979f0..6c4db2ca3e0 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -359,7 +359,7 @@ class AccountTax(models.Model): rep_lines = self.mapped(is_refund and 'refund_repartition_line_ids' or 'invoice_repartition_line_ids') return rep_lines.filtered(lambda x: x.repartition_type == repartition_type).mapped('tag_ids') - def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None, is_refund=False, handle_price_include=True): + def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None, is_refund=False, handle_price_include=True, include_caba_tags=False): """ Returns all information required to apply taxes (in self + their children in case of a tax group). We consider the sequence of the parent for group of taxes. Eg. considering letters as taxes and alphabetic order as sequence : @@ -569,6 +569,10 @@ class AccountTax(models.Model): subsequent_tags = self.env['account.account.tag'] if tax.include_base_amount: subsequent_taxes = taxes[i+1:].filtered('is_base_affected') + + if not include_caba_tags: + subsequent_taxes = subsequent_taxes.filtered(lambda x: x.tax_exigibility != 'on_payment') + subsequent_tags = subsequent_taxes.get_tax_tags(is_refund, 'base') # Compute the tax line amounts by multiplying each factor with the tax amount. @@ -590,6 +594,11 @@ class AccountTax(models.Model): line_amount += rounding_error nber_rounding_steps -= 1 + if not include_caba_tags and tax.tax_exigibility == 'on_payment': + repartition_line_tags = self.env['account.account.tag'] + else: + repartition_line_tags = repartition_line.tag_ids + taxes_vals.append({ 'id': tax.id, 'name': partner and tax.with_context(lang=partner.lang).name or tax.name, @@ -602,7 +611,7 @@ class AccountTax(models.Model): 'tax_exigibility': tax.tax_exigibility, 'tax_repartition_line_id': repartition_line.id, 'group': groups_map.get(tax), - 'tag_ids': (repartition_line.tag_ids + subsequent_tags).ids, + 'tag_ids': (repartition_line_tags + subsequent_tags).ids, 'tax_ids': subsequent_taxes.ids, }) @@ -618,8 +627,14 @@ class AccountTax(models.Model): total_included += factorized_tax_amount i += 1 + base_taxes_for_tags = taxes + if not include_caba_tags: + base_taxes_for_tags = base_taxes_for_tags.filtered(lambda x: x.tax_exigibility != 'on_payment') + + base_rep_lines = base_taxes_for_tags.mapped(is_refund and 'refund_repartition_line_ids' or 'invoice_repartition_line_ids').filtered(lambda x: x.repartition_type == 'base') + return { - 'base_tags': taxes.mapped(is_refund and 'refund_repartition_line_ids' or 'invoice_repartition_line_ids').filtered(lambda x: x.repartition_type == 'base').mapped('tag_ids').ids, + 'base_tags': base_rep_lines.tag_ids.ids, 'taxes': taxes_vals, 'total_excluded': sign * total_excluded, 'total_included': sign * currency.round(total_included), diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index 9c9e2a599cd..9763b2b9e86 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -391,7 +391,8 @@ class AccountTestInvoicingCommon(TransactionCase): line_form.price_unit = amount if taxes: line_form.tax_ids.clear() - line_form.tax_ids.add(taxes) + for tax in taxes: + line_form.tax_ids.add(tax) rslt = move_form.save() diff --git a/addons/account/tests/test_account_move_in_invoice.py b/addons/account/tests/test_account_move_in_invoice.py index 1308fc6a630..8c596de1ec4 100644 --- a/addons/account/tests/test_account_move_in_invoice.py +++ b/addons/account/tests/test_account_move_in_invoice.py @@ -34,7 +34,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 800.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.product_line_vals_2 = { 'name': cls.product_b.name, @@ -54,7 +53,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 160.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_1 = { 'name': cls.tax_purchase_a.name, @@ -74,7 +72,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 144.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_2 = { 'name': cls.tax_purchase_b.name, @@ -94,7 +91,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 24.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.term_line_vals_1 = { 'name': '', @@ -114,7 +110,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 1128.0, 'date_maturity': fields.Date.from_string('2019-01-01'), - 'tax_exigible': True, } cls.move_vals = { 'partner_id': cls.partner_a.id, @@ -759,7 +754,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'price_subtotal': 800.0, 'price_total': 1176.0, 'tax_ids': (self.tax_purchase_a + self.tax_armageddon).ids, - 'tax_exigible': False, }, self.product_line_vals_2, self.tax_line_vals_1, @@ -782,7 +776,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 64.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_1.name, @@ -802,7 +795,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 96.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_2.name, @@ -822,7 +814,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 96.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { **self.term_line_vals_1, @@ -878,7 +869,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.01, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.product_line_vals_1, @@ -929,7 +919,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 0.04, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, diff --git a/addons/account/tests/test_account_move_in_refund.py b/addons/account/tests/test_account_move_in_refund.py index 6d25d771387..5897c5e32b1 100644 --- a/addons/account/tests/test_account_move_in_refund.py +++ b/addons/account/tests/test_account_move_in_refund.py @@ -33,7 +33,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 800.0, 'date_maturity': False, - 'tax_exigible': True, } cls.product_line_vals_2 = { 'name': cls.product_b.name, @@ -53,7 +52,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 160.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_1 = { 'name': cls.tax_purchase_a.name, @@ -73,7 +71,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 144.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_2 = { 'name': cls.tax_purchase_b.name, @@ -93,7 +90,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 24.0, 'date_maturity': False, - 'tax_exigible': True, } cls.term_line_vals_1 = { 'name': '', @@ -113,7 +109,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 1128.0, 'credit': 0.0, 'date_maturity': fields.Date.from_string('2019-01-01'), - 'tax_exigible': True, } cls.move_vals = { 'partner_id': cls.partner_a.id, @@ -459,7 +454,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'price_subtotal': 800.0, 'price_total': 1176.0, 'tax_ids': (self.tax_purchase_a + self.tax_armageddon).ids, - 'tax_exigible': False, }, self.product_line_vals_2, self.tax_line_vals_1, @@ -482,7 +476,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 96.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_1.name, @@ -502,7 +495,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 64.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_2.name, @@ -522,7 +514,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 96.0, 'date_maturity': False, - 'tax_exigible': False, }, { **self.term_line_vals_1, @@ -578,7 +569,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 0.01, 'date_maturity': False, - 'tax_exigible': True, }, { **self.product_line_vals_1, @@ -629,7 +619,6 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.04, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index 7f88862ae6f..edfef97a210 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -38,7 +38,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 1000.0, 'date_maturity': False, - 'tax_exigible': True, } cls.product_line_vals_2 = { 'name': cls.product_b.name, @@ -58,7 +57,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 200.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_1 = { 'name': cls.tax_sale_a.name, @@ -78,7 +76,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 180.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_2 = { 'name': cls.tax_sale_b.name, @@ -98,7 +95,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 30.0, 'date_maturity': False, - 'tax_exigible': True, } cls.term_line_vals_1 = { 'name': '', @@ -118,7 +114,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 1410.0, 'credit': 0.0, 'date_maturity': fields.Date.from_string('2019-01-01'), - 'tax_exigible': True, } cls.move_vals = { 'partner_id': cls.partner_a.id, @@ -764,7 +759,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'price_subtotal': 1000.0, 'price_total': 1470.0, 'tax_ids': (self.tax_sale_a + self.tax_armageddon).ids, - 'tax_exigible': False, }, self.product_line_vals_2, self.tax_line_vals_1, @@ -787,7 +781,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 120.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_1.name, @@ -807,7 +800,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 80.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_2.name, @@ -827,7 +819,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 120.0, 'date_maturity': False, - 'tax_exigible': False, }, { **self.term_line_vals_1, @@ -1083,7 +1074,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 119.91, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, @@ -1143,7 +1133,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 119.91, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, @@ -1207,7 +1196,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 59.95, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, @@ -1271,7 +1259,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 59.95, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, @@ -1501,7 +1488,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 0.01, 'date_maturity': False, - 'tax_exigible': True, }, { **self.product_line_vals_1, @@ -1552,7 +1538,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'debit': 0.04, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, diff --git a/addons/account/tests/test_account_move_out_refund.py b/addons/account/tests/test_account_move_out_refund.py index 0cdf89298c0..7c9aaa3eba5 100644 --- a/addons/account/tests/test_account_move_out_refund.py +++ b/addons/account/tests/test_account_move_out_refund.py @@ -33,7 +33,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 1000.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.product_line_vals_2 = { 'name': cls.product_b.name, @@ -53,7 +52,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 200.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_1 = { 'name': cls.tax_sale_a.name, @@ -73,7 +71,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 180.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.tax_line_vals_2 = { 'name': cls.tax_sale_b.name, @@ -93,7 +90,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 30.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, } cls.term_line_vals_1 = { 'name': '', @@ -113,7 +109,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 1410.0, 'date_maturity': fields.Date.from_string('2019-01-01'), - 'tax_exigible': True, } cls.move_vals = { 'partner_id': cls.partner_a.id, @@ -459,7 +454,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'price_subtotal': 1000.0, 'price_total': 1470.0, 'tax_ids': (self.tax_sale_a + self.tax_armageddon).ids, - 'tax_exigible': False, }, self.product_line_vals_2, self.tax_line_vals_1, @@ -482,7 +476,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 80.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_1.name, @@ -502,7 +495,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 120.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { 'name': child_tax_2.name, @@ -522,7 +514,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 120.0, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': False, }, { **self.term_line_vals_1, @@ -578,7 +569,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.01, 'credit': 0.0, 'date_maturity': False, - 'tax_exigible': True, }, { **self.product_line_vals_1, @@ -629,7 +619,6 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'debit': 0.0, 'credit': 0.04, 'date_maturity': False, - 'tax_exigible': True, }, { **self.term_line_vals_1, diff --git a/addons/account/tests/test_account_move_reconcile.py b/addons/account/tests/test_account_move_reconcile.py index eaf8abbc767..22d1f103053 100644 --- a/addons/account/tests/test_account_move_reconcile.py +++ b/addons/account/tests/test_account_move_reconcile.py @@ -202,33 +202,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): "Amount currency of %s is incorrect" % account.name, ) - def assertTaxGridAmounts(self, amount_per_tag): - expected_values = {tag.id: (tag, balance) for tag, balance in amount_per_tag} - - if not expected_values: - return - - self.cr.execute(''' - SELECT - rel.account_account_tag_id, - SUM(line.balance) - FROM account_account_tag_account_move_line_rel rel - JOIN account_move_line line ON line.id = rel.account_move_line_id - WHERE line.tax_exigible IS TRUE - AND line.company_id = ANY(%(company_ids)s) - GROUP BY rel.account_account_tag_id - ''', { - 'company_ids': self.env.companies.ids, - }) - - for tag_id, total_balance in self.cr.fetchall(): - tag, expected_balance = expected_values[tag_id] - self.assertEqual( - total_balance, - expected_balance, - "Balance of %s is incorrect" % tag.name, - ) - # ------------------------------------------------------------------------- # Test creation of account.partial.reconcile/account.full.reconcile # during the reconciliation. @@ -1216,7 +1189,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 100.0, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, (self.cash_basis_tax_a_third_amount + self.cash_basis_tax_tiny_amount).ids)], - 'tax_exigible': False, }), # Tax lines @@ -1225,14 +1197,12 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 33.33, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), (0, 0, { 'debit': 0.0, 'credit': 0.01, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable lines @@ -1428,7 +1398,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, taxes.ids)], - 'tax_exigible': False, }), # Tax lines @@ -1439,7 +1408,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), (0, 0, { 'debit': 0.0, @@ -1448,7 +1416,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable lines @@ -1639,7 +1606,7 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): def test_reconcile_cash_basis_exchange_difference_transfer_account_check_entries_1(self): ''' Test the generation of the exchange difference for a tax cash basis journal entry when the transfer - account is not a reconcile one. + account is not reconcilable. ''' currency_id = self.currency_data['currency'].id @@ -1656,7 +1623,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_exigible': False, }), # Tax line @@ -1667,7 +1633,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable lines @@ -1794,7 +1759,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_exigible': False, }), # Tax line @@ -1805,7 +1769,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable lines @@ -1882,7 +1845,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_exigible': False, }), # Tax line @@ -1893,7 +1855,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'currency_id': currency_id, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable lines @@ -1957,7 +1918,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 100.0, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_exigible': False, }), # Tax line @@ -1966,7 +1926,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 33.33, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_exigible': False, }), # Receivable line @@ -2037,8 +1996,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 100.0, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_tag_ids': [(6, 0, self.tax_tags[0].ids)], - 'tax_exigible': False, }), # Tax line @@ -2047,8 +2004,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 33.33, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_tag_ids': [(6, 0, self.tax_tags[1].ids)], - 'tax_exigible': False, }), # Receivable line @@ -2072,8 +2027,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 0.0, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, self.cash_basis_tax_a_third_amount.ids)], - 'tax_tag_ids': [(6, 0, self.tax_tags[2].ids)], - 'tax_exigible': False, }), # Tax line @@ -2081,9 +2034,7 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'debit': 33.33, 'credit': 0.0, 'account_id': self.cash_basis_transfer_account.id, - 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_tag_ids': [(6, 0, self.tax_tags[3].ids)], - 'tax_exigible': False, + 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.refund_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, }), # Receivable line @@ -2104,7 +2055,7 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): self.assertFullReconcile(res['full_reconcile'], receivable_lines) self.assertEqual(len(res.get('tax_cash_basis_moves', [])), 2) - tax_cash_basis_moves = res['tax_cash_basis_moves'].sorted(lambda move: move.tax_cash_basis_move_id.id) + tax_cash_basis_moves = res['tax_cash_basis_moves'].sorted(lambda move: move.tax_cash_basis_origin_move_id.id) # Invoice: cb_lines = tax_cash_basis_moves[0].line_ids.sorted(lambda line: (-abs(line.balance), -line.debit, line.account_id)) @@ -2128,14 +2079,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): {'debit': 0.0, 'credit': 33.33, 'tax_tag_ids': [], 'account_id': self.cash_basis_transfer_account.id}, ]) - self.assertTaxGridAmounts([ - # Tag Balance - (self.tax_tags[0], -100.0), - (self.tax_tags[1], -33.33), - (self.tax_tags[2], 100.0), - (self.tax_tags[3], 33.33), - ]) - def test_reconcile_cash_basis_tax_grid_multi_taxes(self): ''' Test the tax grid when reconciling an invoice with multiple taxes/tax repartition. ''' base_taxes = self.cash_basis_tax_a_third_amount + self.cash_basis_tax_tiny_amount @@ -2152,8 +2095,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 100.0, 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [(6, 0, base_taxes.ids)], - 'tax_tag_ids': [(6, 0, base_tags.ids)], - 'tax_exigible': False, }), # Tax lines @@ -2162,16 +2103,12 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): 'credit': 33.33, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_a_third_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_tag_ids': [(6, 0, self.tax_tags[1].ids)], - 'tax_exigible': False, }), (0, 0, { 'debit': 0.0, 'credit': 0.01, 'account_id': self.cash_basis_transfer_account.id, 'tax_repartition_line_id': self.cash_basis_tax_tiny_amount.invoice_repartition_line_ids.filtered(lambda line: line.repartition_type == 'tax').id, - 'tax_tag_ids': [(6, 0, self.tax_tags[5].ids)], - 'tax_exigible': False, }), # Receivable lines @@ -2214,14 +2151,6 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): {'debit': 0.0, 'credit': 0.01, 'tax_ids': [], 'tax_tag_ids': self.tax_tags[5].ids, 'account_id': self.tax_account_2.id}, ]) - self.assertTaxGridAmounts([ - # Tag Balance - (self.tax_tags[0], -100.0), - (self.tax_tags[1], -33.33), - (self.tax_tags[4], -100.0), - (self.tax_tags[5], -0.01), - ]) - def test_caba_mix_reconciliation(self): """ Test the reconciliation of tax lines (when using a reconcilable tax account) for cases mixing taxes exigible on payment and on invoices. diff --git a/addons/account/views/account_move_views.xml b/addons/account/views/account_move_views.xml index b3296670a76..ae57c003c04 100644 --- a/addons/account/views/account_move_views.xml +++ b/addons/account/views/account_move_views.xml @@ -42,7 +42,6 @@ - @@ -696,6 +695,13 @@ attrs="{'invisible': ['|', '|', ('move_type', '!=', 'entry'), ('id', '=', False), ('has_reconciled_entries', '=', False)]}" string="Reconciled Entries"> + @@ -737,6 +743,7 @@ +
@@ -770,6 +777,7 @@ attrs="{'invisible':[('move_type', 'not in', ('in_invoice', 'in_receipt', 'in_refund'))]}" /> + - @@ -981,7 +988,6 @@ - @@ -1134,7 +1140,6 @@ - diff --git a/addons/account_tax_python/models/account_tax.py b/addons/account_tax_python/models/account_tax.py index 435be47fa9c..83f610879e9 100644 --- a/addons/account_tax_python/models/account_tax.py +++ b/addons/account_tax_python/models/account_tax.py @@ -39,7 +39,7 @@ class AccountTaxPython(models.Model): return localdict['result'] return super(AccountTaxPython, self)._compute_amount(base_amount, price_unit, quantity, product, partner) - def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None, is_refund=False, handle_price_include=True): + def compute_all(self, price_unit, currency=None, quantity=1.0, product=None, partner=None, is_refund=False, handle_price_include=True, include_caba_tags=False): taxes = self.filtered(lambda r: r.amount_type != 'code') company = self.env.company if product and product._name == 'product.template': @@ -50,7 +50,7 @@ class AccountTaxPython(models.Model): safe_eval(tax.python_applicable, localdict, mode="exec", nocopy=True) if localdict.get('result', False): taxes += tax - return super(AccountTaxPython, taxes).compute_all(price_unit, currency, quantity, product, partner, is_refund=is_refund, handle_price_include=handle_price_include) + return super(AccountTaxPython, taxes).compute_all(price_unit, currency, quantity, product, partner, is_refund=is_refund, handle_price_include=handle_price_include, include_caba_tags=include_caba_tags) class AccountTaxTemplatePython(models.Model):