diff --git a/l10n_br_account/models/account_move.py b/l10n_br_account/models/account_move.py index 89013a3b3dcd..deffa861f917 100644 --- a/l10n_br_account/models/account_move.py +++ b/l10n_br_account/models/account_move.py @@ -301,6 +301,7 @@ def _compute_amount(self): sign = 1 inv_line_ids = move.line_ids.filtered( lambda line: line.display_type == "product" + and (not line.cfop_id or line.cfop_id.finance_move) ) move.amount_untaxed = sum(inv_line_ids.mapped("amount_untaxed")) move.amount_tax = sum(inv_line_ids.mapped("amount_tax")) @@ -322,9 +323,14 @@ def _compute_needed_terms(self): """ Similar to the _compute_needed_terms super method in the account module, but ensure moves are balanced in Brazil when there is a fiscal_operation_id. - WARNING: it seems we might not be able to call the super method here.... """ - for invoice in self: + res = None + invoices_with_fiscal_op = self.filtered(lambda inv: inv.fiscal_operation_id) + invoices_without_fiscal_op = self - invoices_with_fiscal_op + if invoices_without_fiscal_op: + res = super(AccountMove, invoices_without_fiscal_op)._compute_needed_terms() + + for invoice in invoices_with_fiscal_op: is_draft = invoice.id != invoice._origin.id invoice.needed_terms = {} invoice.needed_terms_dirty = True @@ -339,31 +345,16 @@ def _compute_needed_terms(self): pass else: untaxed_amount_currency += line.price_subtotal - for tax_result in (line.compute_all_tax or {}).values(): - tax_amount_currency += -sign * tax_result.get( - "amount_currency", 0.0 - ) + for tax_result in (line.compute_all_tax or {}).values(): + tax_amount_currency += -sign * tax_result.get( + "amount_currency", 0.0 + ) untaxed_amount = untaxed_amount_currency tax_amount = tax_amount_currency else: - tax_amount_currency = invoice.amount_tax * sign - tax_amount = invoice.amount_tax_signed - if invoice.fiscal_operation_id: - if invoice.fiscal_operation_id.deductible_taxes: - amount_currency = ( - invoice.amount_total - + invoice.amount_tax_withholding - ) - else: - amount_currency = ( - invoice.amount_total - invoice.amount_ipi_value - ) * sign - untaxed_amount_currency = amount_currency * sign - untaxed_amount = amount_currency * sign - - else: - untaxed_amount_currency = invoice.amount_untaxed * sign - untaxed_amount = invoice.amount_untaxed_signed + tax_amount_currency = tax_amount = 0.0 + untaxed_amount_currency = invoice.amount_financial_total * sign + untaxed_amount = invoice.amount_financial_total * sign invoice_payment_terms = ( invoice.invoice_payment_term_id._compute_terms( date_ref=invoice.invoice_date @@ -419,6 +410,7 @@ def _compute_needed_terms(self): "balance": invoice.amount_total_signed, "amount_currency": invoice.amount_total_in_currency_signed, } + return res @contextmanager def _sync_dynamic_lines(self, container): diff --git a/l10n_br_account/models/account_move_line.py b/l10n_br_account/models/account_move_line.py index 315b2f21dbf6..ee6186e2c6d5 100644 --- a/l10n_br_account/models/account_move_line.py +++ b/l10n_br_account/models/account_move_line.py @@ -301,6 +301,18 @@ def changed(fname): else: # BRAZIL CASE: if line.cfop_id and not line.cfop_id.finance_move: unsigned_amount_currency = 0 + if not line.move_id.fiscal_operation_id.deductible_taxes: + # Quando não há financeiro associado, mas há impostos e + # nenhum imposto dedutível, é necessário registrar a + # contrapartida dos impostos para manter o balanço contábil + # equilibrado. Na versão 14 do Odoo, essa diferença era + # automaticamente alocada às contas associadas aos termos + # de pagamento. + unsigned_amount_currency = -( + line.amount_tax_included + + line.amount_tax_not_included + - line.amount_tax_withholding + ) else: if line.move_id.fiscal_operation_id.deductible_taxes: unsigned_amount_currency = ( @@ -312,12 +324,10 @@ def changed(fname): ) unsigned_amount_currency = line.currency_id.round( amount_total - - ( - line.amount_tax_included - - line.amount_tax_withholding - ) + - line.amount_tax_included - line.amount_tax_not_included - - line.icms_relief_value + if line.tax_ids + else amount_total ) amount_currency = unsigned_amount_currency * line.move_id.direction_sign if line.amount_currency != amount_currency or line not in before: @@ -394,7 +404,6 @@ def _compute_totals(self): line.price_subtotal = taxes_res["total_excluded"] line.price_total = taxes_res["total_included"] - line._compute_balance() line.price_total += ( line.insurance_value @@ -521,19 +530,33 @@ def _onchange_fiscal_document_line_id(self): # override the default product uom (set by the onchange): self.product_uom_id = self.fiscal_document_line_id.uom_id.id - @api.onchange("fiscal_tax_ids") - def _onchange_fiscal_tax_ids(self): - """Ao alterar o campo fiscal_tax_ids que contém os impostos fiscais, - são atualizados os impostos contábeis relacionados""" - result = super()._onchange_fiscal_tax_ids() + @api.depends("product_id", "product_uom_id", "fiscal_tax_ids") + def _compute_tax_ids(self): + # Adding 'fiscal_tax_ids' as a dependency to ensure that the taxes + # are recalculated when this field changes. + return super()._compute_tax_ids() + + def _get_computed_taxes(self): + """ + Override the native method to load taxes from the fiscal module. + """ + self.ensure_one() + + # If no fiscal operation is defined, fallback to the default implementation. + if not self.fiscal_operation_id: + return super()._get_computed_taxes() - # Atualiza os impostos contábeis relacionados aos impostos fiscais - user_type = "sale" - if self.move_id.move_type in ("in_invoice", "in_refund"): + # Determine the user type based on the document type. + user_type = None + if self.move_id.is_sale_document(include_receipts=True): + user_type = "sale" + elif self.move_id.is_purchase_document(include_receipts=True): user_type = "purchase" - self.tax_ids = self.fiscal_tax_ids.account_taxes( - user_type=user_type, fiscal_operation=self.fiscal_operation_id - ) + # Retrieve taxes based on user type and fiscal operation. + if user_type: + tax_ids = self.fiscal_tax_ids.account_taxes( + user_type=user_type, fiscal_operation=self.fiscal_operation_id + ) - return result + return tax_ids diff --git a/l10n_br_account/tests/test_account_move_lc.py b/l10n_br_account/tests/test_account_move_lc.py index 00c4e1c6ab0c..213b8a1bd90f 100644 --- a/l10n_br_account/tests/test_account_move_lc.py +++ b/l10n_br_account/tests/test_account_move_lc.py @@ -666,8 +666,8 @@ def test_simples_remessa(self): "price_total": 1050.0, "tax_line_id": False, "currency_id": self.company_data["currency"].id, - "amount_currency": 0.0, - "debit": 0.0, + "amount_currency": 206.5, + "debit": 206.5, "credit": 0.0, "date_maturity": False, } @@ -775,6 +775,8 @@ def test_simples_remessa(self): "date_maturity": False, } + # Remessa não gera financeiro, as linhas das condições de pagamento + # devem estar zeradas! term_line_vals_1 = { "name": "", "product_id": False, @@ -789,8 +791,8 @@ def test_simples_remessa(self): "tax_ids": [], "tax_line_id": False, "currency_id": self.company_data["currency"].id, - "amount_currency": 206.5, - "debit": 206.5, + "amount_currency": 0, + "debit": 0, "credit": 0.0, "date_maturity": fields.Date.from_string("2019-01-01"), } @@ -803,9 +805,9 @@ def test_simples_remessa(self): "fiscal_position_id": False, "payment_reference": "", "invoice_payment_term_id": self.pay_terms_a.id, - "amount_untaxed": 1000, - "amount_tax": 50, - "amount_total": 206.5, + "amount_untaxed": 0.0, + "amount_tax": 0.0, + "amount_total": 0.0, } self.assertInvoiceValues( @@ -1271,8 +1273,8 @@ def test_simples_remessa_tax_withholding(self): "price_total": 1050.0, "tax_line_id": False, "currency_id": self.company_data["currency"].id, - "amount_currency": 0.0, - "debit": 0.0, + "amount_currency": 133.5, + "debit": 133.5, "credit": 0.0, "date_maturity": False, } @@ -1390,8 +1392,8 @@ def test_simples_remessa_tax_withholding(self): "tax_ids": [], "tax_line_id": False, "currency_id": self.company_data["currency"].id, - "amount_currency": 133.5, - "debit": 133.5, + "amount_currency": 0.0, + "debit": 0.0, "credit": 0.0, "date_maturity": fields.Date.from_string("2019-01-01"), } @@ -1404,9 +1406,9 @@ def test_simples_remessa_tax_withholding(self): "fiscal_position_id": False, "payment_reference": "", "invoice_payment_term_id": self.pay_terms_a.id, - "amount_untaxed": 1000.0, # FIXME is this correct for a simples remessa?? - "amount_tax": 50.0, - "amount_total": 133.5, + "amount_untaxed": 0.0, + "amount_tax": 0.0, + "amount_total": 0.0, } self.assertInvoiceValues( diff --git a/l10n_br_account/tests/test_invoice_refund.py b/l10n_br_account/tests/test_invoice_refund.py index 896681baf6b1..0e8b69f66c32 100644 --- a/l10n_br_account/tests/test_invoice_refund.py +++ b/l10n_br_account/tests/test_invoice_refund.py @@ -109,18 +109,19 @@ def test_refund(self): with self.assertRaises(UserError): move_reversal.reverse_moves() - invoice["fiscal_operation_id"] = (self.env.ref("l10n_br_fiscal.fo_venda").id,) + invoice.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda") with self.assertRaises(UserError): move_reversal.reverse_moves() - for line_id in invoice.invoice_line_ids: - line_id["fiscal_operation_id"] = ( - self.env.ref("l10n_br_fiscal.fo_venda").id, - ) - line_id["fiscal_operation_line_id"] = self.env.ref( - "l10n_br_fiscal.fo_venda_venda" - ).id + invoice.invoice_line_ids.write( + { + "fiscal_operation_id": self.env.ref("l10n_br_fiscal.fo_venda").id, + "fiscal_operation_line_id": ( + self.env.ref("l10n_br_fiscal.fo_venda_venda").id, + ), + } + ) reversal = move_reversal.reverse_moves() reverse_move = self.env["account.move"].browse(reversal["res_id"]) @@ -137,15 +138,15 @@ def test_refund_force_fiscal_operation(self): reverse_vals = self.reverse_vals invoice = self.invoice - invoice["fiscal_operation_id"] = (self.env.ref("l10n_br_fiscal.fo_venda").id,) - - for line_id in invoice.invoice_line_ids: - line_id["fiscal_operation_id"] = ( - self.env.ref("l10n_br_fiscal.fo_venda").id, - ) - line_id["fiscal_operation_line_id"] = self.env.ref( - "l10n_br_fiscal.fo_venda_venda" - ).id + invoice.fiscal_operation_id = self.env.ref("l10n_br_fiscal.fo_venda") + invoice.invoice_line_ids.write( + { + "fiscal_operation_id": self.env.ref("l10n_br_fiscal.fo_venda").id, + "fiscal_operation_line_id": self.env.ref( + "l10n_br_fiscal.fo_venda_venda" + ).id, + } + ) invoice.action_post() self.assertEqual( diff --git a/l10n_br_fiscal/models/document_line_mixin_methods.py b/l10n_br_fiscal/models/document_line_mixin_methods.py index 704f220ec33f..1c19392f71b9 100644 --- a/l10n_br_fiscal/models/document_line_mixin_methods.py +++ b/l10n_br_fiscal/models/document_line_mixin_methods.py @@ -127,6 +127,8 @@ def _get_view(self, view_id=None, view_type="form", **options): "company_id", "price_unit", "quantity", + "icms_relief_id", + "fiscal_operation_line_id", ) def _compute_fiscal_amounts(self): for record in self: @@ -134,20 +136,20 @@ def _compute_fiscal_amounts(self): # Total value of products or services record.price_gross = round_curr.round(record.price_unit * record.quantity) - - record.amount_untaxed = record.price_gross - record.discount_value - record.amount_fiscal = record.price_gross - record.discount_value - record.amount_tax = record.amount_tax_not_included add_to_amount = sum(record[a] for a in record._add_fields_to_amount()) rm_to_amount = sum(record[r] for r in record._rm_fields_to_amount()) + record.amount_untaxed = ( + record.price_gross + - record.discount_value + + add_to_amount + - rm_to_amount + ) # Valor do documento (NF) - record.amount_total = ( - record.amount_untaxed + record.amount_tax + add_to_amount - rm_to_amount - ) + record.amount_total = record.amount_untaxed + record.amount_tax # Valor Liquido (TOTAL + IMPOSTOS - RETENÇÕES) record.amount_taxed = record.amount_total - record.amount_tax_withholding diff --git a/l10n_br_fiscal/models/tax.py b/l10n_br_fiscal/models/tax.py index 1a583402aa80..773d7d67ef06 100644 --- a/l10n_br_fiscal/models/tax.py +++ b/l10n_br_fiscal/models/tax.py @@ -699,19 +699,15 @@ def compute_taxes(self, **kwargs): except AttributeError: taxes[tax.tax_domain].update(tax._compute_tax(tax, taxes, **kwargs)) - if taxes[tax.tax_domain]["tax_include"]: - result_amounts["amount_included"] += taxes[tax.tax_domain].get( - "tax_value", 0.00 - ) + tax_domain = taxes[tax.tax_domain] + tax_value = tax_domain.get("tax_value", 0.00) + if tax_domain["tax_withholding"]: + result_amounts["amount_withholding"] += tax_value else: - result_amounts["amount_not_included"] += taxes[tax.tax_domain].get( - "tax_value", 0.00 - ) - - if taxes[tax.tax_domain]["tax_withholding"]: - result_amounts["amount_withholding"] += taxes[tax.tax_domain].get( - "tax_value", 0.00 - ) + if tax_domain["tax_include"]: + result_amounts["amount_included"] += tax_value + else: + result_amounts["amount_not_included"] += tax_value # Estimate taxes result_amounts["estimate_tax"] = self._compute_estimate_taxes(**kwargs) diff --git a/l10n_br_purchase/models/purchase_order_line.py b/l10n_br_purchase/models/purchase_order_line.py index 8712d597344d..7a2acbdaf5d7 100644 --- a/l10n_br_purchase/models/purchase_order_line.py +++ b/l10n_br_purchase/models/purchase_order_line.py @@ -104,7 +104,6 @@ def _compute_amount(self): { "price_subtotal": line.amount_untaxed, "price_tax": line.amount_tax, - "price_gross": line.amount_untaxed + line.discount_value, "price_total": line.amount_total, } )