Skip to Content
Menú
This question has been flagged
2 Respostes
1705 Vistes

Hi.

Odoo 15

I have a piece of code that I want to use to calculate taxes based on a value called x_liquido_mes. This value is obtained by subtracting another manually entered value, x_anterior, from x_actual (which is the value of price_unit multiplied by quantity).

The tax_totals_json values are correct, and the appropriate values appear in the invoice, but as soon as I save, the tax values change. The rest remains correct.

What should I modify to ensure the correct results display when I save?

Code:


from odoo import api, models, fields
from odoo.tools import formatLang
import logging
import json

_logger = logging.getLogger(__name__)


class AccountMove(models.Model):
    _inherit = "account.move"

    obra_id = fields.Many2one("tabla.esal.obras", string="Obra", store=True)
    pedido_id = fields.Many2one("tabla.esal.pedidos", string="Pedido", store=True)
    total_liquido_mes = fields.Monetary(
        string="Total Líquido Mes", compute="_compute_amount", store=True
    )

    # Campo para seleccionar la cuenta de la empresa para recibir pagos
    partner_bank_id = fields.Many2one(
        "res.partner.bank",
        string="Cuenta Bancaria para Pago",
        domain="[('partner_id', '=', company_partner_id)]",  # Ajuste en el dominio
        help="Seleccione la cuenta bancaria de la empresa donde desea recibir el pago.",
    )
    company_partner_id = fields.Many2one(
        "res.partner",
        related="company_id.partner_id",
        store=True,
        readonly=True,
        string="Partner de la Empresa",
    )

    # Función para que cuando se selecciona una nueva obra, el campo pedido se vacíe
    @api.onchange("obra_id")
    def _onchange_obra_id(self):
        self.pedido_id = False

    @api.model
    def create(self, vals):
        if vals.get("invoice_origin") and vals.get("move_type"):
            move_type = vals.get("move_type")
            if move_type in ["in_invoice", "in_refund"]:  # Facturas de proveedores
                purchase_order = self.env["purchase.order"].search(
                    [("name", "=", vals.get("invoice_origin"))], limit=1
                )
                if purchase_order:
                    vals["obra_id"] = purchase_order.purchase_obras_id.id
                    vals["pedido_id"] = purchase_order.purchase_pedidos_id.id

            elif move_type in ["out_invoice", "out_refund"]:  # Facturas de clientes
                sale_order = self.env["sale.order"].search(
                    [("name", "=", vals.get("invoice_origin"))], limit=1
                )
                if sale_order:
                    vals["obra_id"] = sale_order.sale_obras_id.id
                    vals["pedido_id"] = sale_order.sale_pedidos_id.id

        return super(AccountMove, self).create(vals)

    @api.depends("line_ids.x_liquido_mes", "line_ids.tax_ids")
    def _compute_amount(self):
        for move in self:
            # Sumar x_liquido_mes filtrando las líneas que no son de impuestos ni excluidas de la pestaña de factura
            amount_untaxed = sum(
                line.x_liquido_mes
                for line in move.line_ids
                if not line.tax_line_id and not line.exclude_from_invoice_tab
            )

            # Calcular el total de impuestos sobre x_liquido_mes filtrado
            amount_tax = 0.0
            for line in move.line_ids:
                if not line.tax_line_id and not line.exclude_from_invoice_tab:
                    # Usar x_liquido_mes para calcular impuestos en lugar de price_subtotal
                    taxes = line.tax_ids.compute_all(
                        line.x_liquido_mes,  # Base imponible personalizada (x_liquido_mes)
                        currency=move.currency_id,
                        quantity=1.0,  # El valor total ya está en x_liquido_mes
                        product=line.product_id,
                        partner=move.partner_id,
                    )
                    # Sumar los impuestos calculados
                    amount_tax += taxes["total_included"] - taxes["total_excluded"]

            # Calcular el total con impuestos
            amount_total = amount_untaxed + amount_tax

            # Actualizar los campos de la factura
            move.update(
                {
                    "amount_untaxed": amount_untaxed,
                    "amount_untaxed_signed": amount_untaxed,
                    "amount_tax": amount_tax,
                    "amount_tax_signed": amount_tax,
                    "amount_total": amount_total,  # Total con impuestos,
                    "amount_total_signed": amount_total,  # Total con impuestos
                }
            )

            if move.tax_totals_json:
                tax_totals = json.loads(move.tax_totals_json)

                # Verificar si existe 'groups_by_subtotal' y 'Base imponible' en el JSON
                if (
                    "groups_by_subtotal" not in tax_totals
                    or "Base imponible" not in tax_totals["groups_by_subtotal"]
                ):
                    _logger.warning(
                        "No se encontró 'groups_by_subtotal' o 'Base imponible' en tax_totals_json"
                    )
                    tax_totals["groups_by_subtotal"] = {
                        "Base imponible": []
                    }  # Inicializar si no existe

                # Inicializar un diccionario para acumular los datos por grupo de impuestos
                tax_groups_data = {}

                # Iterar sobre las líneas de la factura para calcular los impuestos basados en 'x_liquido_mes'
                for line in move.line_ids:
                    if not line.exclude_from_invoice_tab and line.x_liquido_mes:
                        # Forzar el uso de x_liquido_mes como base imponible en lugar de price_subtotal
                        base_imponible = line.x_liquido_mes

                        # Calcular manualmente los impuestos basados en x_liquido_mes
                        for tax in line.tax_ids:
                            tax_amount = tax.amount / 100.0 * base_imponible
                            tax_group_id = tax.tax_group_id.id
                            tax_group_name = tax.tax_group_id.name

                            # Si el grupo no está en el diccionario, lo añadimos
                            if tax_group_id not in tax_groups_data:
                                tax_groups_data[tax_group_id] = {
                                    "tax_group_name": tax_group_name,
                                    "tax_group_amount": 0.0,  # Para acumular los impuestos calculados sobre 'x_liquido_mes'
                                    "tax_group_base_amount": 0.0,  # Para acumular 'x_liquido_mes' como base imponible
                                }

                            # Sumar el monto del impuesto calculado sobre 'x_liquido_mes'
                            tax_groups_data[tax_group_id][
                                "tax_group_amount"
                            ] += tax_amount
                            tax_groups_data[tax_group_id][
                                "tax_group_base_amount"
                            ] += base_imponible

                            _logger.info(
                                f"Calculado manualmente: Grupo: {tax_group_name}, Base: {base_imponible}, Impuesto: {tax_amount}"
                            )

                # Iterar sobre los grupos en el JSON y sobrescribir con los valores calculados
                for group in tax_totals["groups_by_subtotal"]["Base imponible"]:
                    group_key = group.get("tax_group_id")

                    if group_key in tax_groups_data:
                        tax_data = tax_groups_data[group_key]
                        group["tax_group_amount"] = tax_data[
                            "tax_group_amount"
                        ]  # Sobrescribir con el nuevo cálculo
                        group["tax_group_base_amount"] = tax_data[
                            "tax_group_base_amount"
                        ]  # Sobrescribir con la nueva base

                        # Formatear los valores usando 'formatLang'
                        group["formatted_tax_group_amount"] = formatLang(
                            self.env,
                            group["tax_group_amount"],
                            currency_obj=move.currency_id,
                        )
                        group["formatted_tax_group_base_amount"] = formatLang(
                            self.env,
                            group["tax_group_base_amount"],
                            currency_obj=move.currency_id,
                        )

                # Guardar los cambios nuevamente en el campo 'tax_totals_json'
                move.tax_totals_json = json.dumps(tax_totals)
                _logger.info(
                    f"Tax Totals JSON modificado manualmente: {move.tax_totals_json}"
                )


This is the tax_totals_json:


{
  "amount_total": 23.1,
  "amount_untaxed": 20,
  "formatted_amount_total": "23,10 €",
  "formatted_amount_untaxed": "20,00 €",
  "groups_by_subtotal": {
    "Base imponible": [
      {
        "tax_group_name": "IVA 21%",
        "tax_group_amount": 2.1,
        "tax_group_base_amount": 10,
        "formatted_tax_group_amount": "2,10 €",
        "formatted_tax_group_base_amount": "10,00 €",
        "tax_group_id": 21,
        "group_key": "Base imponible-21"
      },
      {
        "tax_group_name": "IVA 10%",
        "tax_group_amount": 1,
        "tax_group_base_amount": 10,
        "formatted_tax_group_amount": "1,00 €",
        "formatted_tax_group_base_amount": "10,00 €",
        "tax_group_id": 14,
        "group_key": "Base imponible-14"
      }
    ]
  },
  "subtotals": [
    {
      "name": "Base imponible",
      "amount": 20,
      "formatted_amount": "20,00 €"
    }
  ],
  "allow_tax_edition": false
}



from odoo import models, fields, api


class AccountMoveLine(models.Model):
    _inherit = "account.move.line"

    x_anterior = fields.Monetary(string="Anterior", store=True)
    x_liquido_mes = fields.Monetary(
        string="Líquido Mes", compute="_compute_liquido_mes", store=True
    )

    @api.depends("quantity", "price_unit", "x_anterior")
    def _compute_liquido_mes(self):
        for line in self:
            line.x_liquido_mes = (line.quantity * line.price_unit) - line.x_anterior



Before save:

AlgoAlgo4,003,00IVA 21% (Bienes)12,00 €2,00 €10,00 €
Tubería 3/4Tubería 3/44,003,00IVA 10% (Bienes)12,00 €2,00 €10,00 €





Tax base:20,00 €
IVA 21%2,10 €
IVA 10%1,00 €
Total23,10 €




After save:


AlgoAlgo4,003,00IVA 21% (Bienes)12,00 €2,00 €10,00 €
Tubería 3/4Tubería 3/44,003,00IVA 10% (Bienes)12,00 €2,00 €10,00 €


Tax base:
20,00 €
IVA 21%2,52 €
IVA 10%1,20 €
Total23,10 €








Avatar
Descartar
Autor Best Answer

I need to know how to do the following in Odoo 15.

I have a model that inherits from account.move.line.

The model has two new fields: x_actual and x_anterior. x_anterior is directly entered in the invoice. I have another field that attempts to overwrite price_subtotal.


from odoo import models, fields, api class AccountMoveLine(models.Model): _inherit = 'account.move.line' x_actual = fields.Monetary(string="Actual", compute='_compute_x_actual', store=True) x_anterior = fields.Monetary(string="Previous", store=True) price_subtotal = fields.Monetary(string="Net Amount", compute='_compute_price_subtotal', store=True) @api.depends('quantity', 'price_unit', 'x_anterior') def _compute_x_actual(self): for line in self: line.x_actual = line.quantity * line.price_unit @api.depends('x_actual', 'price_unit', 'x_anterior') def _compute_price_subtotal(self): for line in self: line.price_subtotal = (line.quantity * line.price_unit) - line.x_anterior

When I run it, I get this:

data:
price_unit 3,00€,
quantity: 4,
x_actual: 12,00€,
x_anterior: 2,00€,




Taxable Base (Base imponible): 12

VAT 21% (Iva 21%): 2.52

Total: 14.52

I would like the summary to show the calculated value of price_subtotal (10) as the taxable base, the correct tax values (2.10), a correct sum (12.10), and the correct application in other places where the tax calculation would apply.

I've been at this for a while and haven’t found the right solution. When I modified tax_totals_json correctly, I only see it correctly before saving. When I save, it doesn’t save the data I need correctly and behaves as if nothing was subtracted from price_subtotal.

Avatar
Descartar
Best Answer

I am not entirely sure what you are trying to say here. 

It seems that one or more of your dependencies are forcing the values to be recalculated, even when the function already run before, and it's using the wrong base value. 

You must be sure that your computed functions are only launched when needed, and that previous calculations do not affect the end result, or there is not another function overriding your own.

Calling the same function several times, should not affect its result when the data is the same.

If you are not sure what is happening, I suggest that you either put some prints inside of those functions and  try to understand why or when they are being called,

 or...

launch your code in debug mode, with stops in your tax calculation, and look up your field values in the debug window. 

Avatar
Descartar