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:
Algo | Algo | 4,00 | 3,00 | IVA 21% (Bienes) | 12,00 € | 2,00 € | 10,00 € | ||
Tubería 3/4 | Tubería 3/4 | 4,00 | 3,00 | IVA 10% (Bienes) | 12,00 € | 2,00 € | 10,00 € | ||
| ||||||||
After save:
Algo | Algo | 4,00 | 3,00 | IVA 21% (Bienes) | 12,00 € | 2,00 € | 10,00 € | ||
Tubería 3/4 | Tubería 3/4 | 4,00 | 3,00 | IVA 10% (Bienes) | 12,00 € | 2,00 € | 10,00 € | ||
|