From eb0b664349072c06b3f873be3e6d6ad8b06a985a Mon Sep 17 00:00:00 2001 From: "Nasreddin (bon)" Date: Tue, 24 Nov 2020 12:52:43 +0000 Subject: [PATCH] [FIX] account: Negative fixed taxes on 100% discount Issue - Install 'Accounting' module - Create a new 'Tax' X with a fixed price (e.g.: O.O57 $) - Create a new 'Customer Invoice' - Add a product P and set unit price to 0 $ - Set tax X to product P Total tax amount : - 0.06 $ . Solution The sign must be forced to a negative sign in case the balance is on credit to avoid negatif taxes amount. enterprise PR : https://github.com/odoo/enterprise/pull/15035 opw-2378978 closes odoo/odoo#62758 X-original-commit: 684855529e8aaafa0cb90f958d19c563d6e2a897 Related: odoo/enterprise#15105 Signed-off-by: Laurent Smet Signed-off-by: bon-odoo --- addons/account/models/account_move.py | 18 +++++++++++++++--- addons/account/models/account_tax.py | 5 ++++- .../models/account_edi_format.py | 2 +- .../models/account_move_line.py | 6 +++--- .../purchase_stock/models/account_invoice.py | 2 +- 5 files changed, 24 insertions(+), 9 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 4eb1043af8a..8be4259d358 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -529,6 +529,17 @@ class AccountMove(models.Model): 'tax_tag_ids': [(6, 0, tax_vals['tag_ids'])], } + def _get_tax_force_sign(self): + """ The sign must be forced to a negative sign in case the balance is on credit + to avoid negatif taxes amount. + Example - Customer Invoice : + Fixed Tax | unit price | discount | amount_tax | amount_total | + ------------------------------------------------------------------------- + 0.67 | 115 | 100% | - 0.67 | 0 + -------------------------------------------------------------------------""" + self.ensure_one() + return -1 if self.move_type in ('out_invoice', 'in_refund', 'out_receipt') else 1 + def _recompute_tax_lines(self, recompute_tax_base_amount=False): ''' Compute the dynamic tax lines of the journal entry. @@ -570,7 +581,7 @@ class AccountMove(models.Model): is_refund = (tax_type == 'sale' and base_line.debit) or (tax_type == 'purchase' and base_line.credit) price_unit_wo_discount = base_line.balance - balance_taxes_res = base_line.tax_ids._origin.compute_all( + balance_taxes_res = base_line.tax_ids._origin.with_context(force_sign=move._get_tax_force_sign()).compute_all( price_unit_wo_discount, currency=base_line.currency_id, quantity=quantity, @@ -3213,7 +3224,8 @@ class AccountMoveLine(models.Model): # Compute 'price_total'. if taxes: - taxes_res = taxes._origin.compute_all(line_discount_price_unit, + force_sign = -1 if move_type in ('out_invoice', 'in_refund', 'out_receipt') else 1 + taxes_res = taxes._origin.with_context(force_sign=force_sign).compute_all(line_discount_price_unit, quantity=quantity, currency=currency, product=product, partner=partner, is_refund=move_type in ('out_refund', 'in_refund')) res['price_subtotal'] = taxes_res['total_excluded'] res['price_total'] = taxes_res['total_included'] @@ -3325,7 +3337,7 @@ class AccountMoveLine(models.Model): # 220 | 10% incl, 5% | | 200 | 230 # 20 | | 10% incl | 20 | 20 # 10 | | 5% | 10 | 10 - taxes_res = taxes._origin.compute_all(amount_currency, currency=currency, handle_price_include=False) + taxes_res = taxes._origin.with_context(force_sign=self.move_id._get_tax_force_sign()).compute_all(amount_currency, currency=currency, handle_price_include=False) for tax_res in taxes_res['taxes']: tax = self.env['account.tax'].browse(tax_res['id']) if tax.price_include: diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index 72908349b9e..759928f083f 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -439,9 +439,12 @@ class AccountTax(models.Model): # For the computation of move lines, we could have a negative base value. # In this case, compute all with positive values and negate them at the end. sign = 1 + if currency.is_zero(base): + sign = self._context.get('force_sign', 1) + elif base < 0: + sign = -1 if base < 0: base = -base - sign = -1 # Store the totals to reach when using price_include taxes (only the last price included in row) total_included_checkpoints = {} diff --git a/addons/account_edi_facturx/models/account_edi_format.py b/addons/account_edi_facturx/models/account_edi_format.py index 7da91c9db6f..59e14cc6c31 100644 --- a/addons/account_edi_facturx/models/account_edi_format.py +++ b/addons/account_edi_facturx/models/account_edi_format.py @@ -68,7 +68,7 @@ class AccountEdiFormat(models.Model): # Invoice lines. for i, line in enumerate(invoice.invoice_line_ids.filtered(lambda l: not l.display_type)): price_unit_with_discount = line.price_unit * (1 - (line.discount / 100.0)) - taxes_res = line.tax_ids.compute_all( + taxes_res = line.tax_ids.with_context(force_sign=line.move_id._get_tax_force_sign()).compute_all( price_unit_with_discount, currency=line.currency_id, quantity=line.quantity, diff --git a/addons/l10n_latam_invoice_document/models/account_move_line.py b/addons/l10n_latam_invoice_document/models/account_move_line.py index a0dbeb75179..7ec91811a80 100644 --- a/addons/l10n_latam_invoice_document/models/account_move_line.py +++ b/addons/l10n_latam_invoice_document/models/account_move_line.py @@ -30,7 +30,7 @@ class AccountMoveLine(models.Model): invoice.l10n_latam_document_type_id and invoice.l10n_latam_document_type_id._filter_taxes_included( line.tax_ids) if not included_taxes: - price_unit = line.tax_ids.with_context(round=False).compute_all( + price_unit = line.tax_ids.with_context(round=False, force_sign=invoice._get_tax_force_sign()).compute_all( line.price_unit, invoice.currency_id, 1.0, line.product_id, invoice.partner_id) l10n_latam_price_unit = price_unit['total_excluded'] l10n_latam_price_subtotal = line.price_subtotal @@ -38,11 +38,11 @@ class AccountMoveLine(models.Model): l10n_latam_price_net = l10n_latam_price_unit * (1 - (line.discount or 0.0) / 100.0) else: not_included_taxes = line.tax_ids - included_taxes - l10n_latam_price_unit = included_taxes.compute_all( + l10n_latam_price_unit = included_taxes.with_context(force_sign=invoice._get_tax_force_sign()).compute_all( line.price_unit, invoice.currency_id, 1.0, line.product_id, invoice.partner_id)['total_included'] l10n_latam_price_net = l10n_latam_price_unit * (1 - (line.discount or 0.0) / 100.0) price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) - l10n_latam_price_subtotal = included_taxes.compute_all( + l10n_latam_price_subtotal = included_taxes.with_context(force_sign=invoice._get_tax_force_sign()).compute_all( price, invoice.currency_id, line.quantity, line.product_id, invoice.partner_id)['total_included'] diff --git a/addons/purchase_stock/models/account_invoice.py b/addons/purchase_stock/models/account_invoice.py index 6731c3c05b0..e2454486a18 100644 --- a/addons/purchase_stock/models/account_invoice.py +++ b/addons/purchase_stock/models/account_invoice.py @@ -123,7 +123,7 @@ class AccountMove(models.Model): # Since compute_all still rounds the total, we use an ugly workaround: # multiply then divide the price unit. price_unit *= line.quantity - price_unit = line.tax_ids.with_context(round=False).compute_all( + price_unit = line.tax_ids.with_context(round=False, force_sign=move._get_tax_force_sign()).compute_all( price_unit, currency=move.currency_id, quantity=1.0, is_refund=move.move_type == 'in_refund')['total_excluded'] price_unit /= line.quantity