diff --git a/l10n_mx_facturae/models/account_invoice.py b/l10n_mx_facturae/models/account_invoice.py index 5c1116c5f8946519897a77ae0f7013d51619c393..17e4cabd5892c2394d5ce62ba9710ddfe8a4b4c2 100644 --- a/l10n_mx_facturae/models/account_invoice.py +++ b/l10n_mx_facturae/models/account_invoice.py @@ -579,9 +579,6 @@ class AccountInvoiceLine(models.Model): """ tax_record = self.env["account.tax"].browse(tax["id"]) tax_group = tax_record.tax_category_id - # IEPS tax only must be included when partner is IEPS subjected - if tax_group.name == "IEPS" and not partner.ieps_subjected: - return # TODO: Delete on version 3.0.0 if "base" not in tax: tax["base"] = currency.cfdi_round(tax["price_unit"] * self.quantity) @@ -597,16 +594,7 @@ class AccountInvoiceLine(models.Model): total_discount *= 1 - self.invoice_id.global_discount / 100 price = float_round(self.price_unit * total_discount, precision) partner = self.invoice_id.partner_id - # Check if IEPS is on taxes, this will be used later to know if need price - # to be recalculated because IEPS must be price included as partner is not - # IEPS subjected and product include IEPS taxes - ieps_group = self.env.ref("l10n_mx.tax_category_ieps") - is_ieps_tax_subjected = any( - tax.tax_category_id == ieps_group for tax in self.invoice_line_tax_id - ) - is_price_included = any( - tax.price_include for tax in self.invoice_line_tax_id - ) + # Compute taxes using original compute_all function from # account.invoice.tax to get same result for CFDI display res = self.invoice_line_tax_id.compute_all( @@ -616,36 +604,19 @@ class AccountInvoiceLine(models.Model): partner=partner, currency=self.invoice_id.currency_id, ) - # pylint: disable=C1801 - if len(res["taxes"]) == 0: + if not len(res["taxes"]): raise ValidationError( _("Product {p} must have at least one tax selected.").format( p=self.product_id.name ) ) - taxes = [] - taxes_list = iter(res["taxes"]) - tax = next(taxes_list) - # Iterate taxes and append to the new tax list as needed - while True: - tax = process_tax(tax) - if tax: - taxes.append(tax) - try: - tax = next(taxes_list) - except StopIteration: - if tax is None: - raise ValidationError( - _( - "Incorrect tax sequence configuration, check " - "this data in Account >> Tax >> Sequence" - ) - ) - break + + is_price_included = any( + tax.price_include for tax in self.invoice_line_tax_id + ) res["price_unit"] = self.price_unit - # Recompute price_unit is needed when any tax is setup to price included or - # when product is IEPS subjected but not partner - if is_price_included or (not partner.ieps_subjected and is_ieps_tax_subjected): + # Recompute price_unit is needed when any tax is setup to price included + if is_price_included: # Send round=False in context to avoid rounding to wrong value when working # with high Product Price precision (6 digits) res["price_unit"] = self.invoice_line_tax_id.with_context( @@ -661,6 +632,25 @@ class AccountInvoiceLine(models.Model): self.env["decimal.precision"].precision_get("Product Price"), ) + taxes = [] + taxes_list = iter(res["taxes"]) + tax = next(taxes_list) + # Iterate taxes and append to the new tax list as needed + while True: + tax = process_tax(tax) + # IEPS tax only must be included when partner is IEPS subjected + if tax["group"] == "IEPS" and not partner.ieps_subjected: + res["price_unit"] = float_round( + res["price_unit"] + (tax["amount"] / self.quantity), + self.env["decimal.precision"].precision_get("Product Price"), + ) + else: + taxes.append(tax) + try: + tax = next(taxes_list) + except StopIteration: + break + res["importe"] = currency.round(res["price_unit"] * self.quantity) res["descuento"] = currency.round(res["importe"] * (1 - total_discount)) # Overrides original taxes with the list computed by us diff --git a/l10n_mx_facturae/tests/features/account_invoice.feature b/l10n_mx_facturae/tests/features/account_invoice.feature index 0f253424731a7b00ab657a2b4123295d2d9c2db1..7dea9a14178d50a03f787a517e61cfb3774cdc02 100644 --- a/l10n_mx_facturae/tests/features/account_invoice.feature +++ b/l10n_mx_facturae/tests/features/account_invoice.feature @@ -31,3 +31,15 @@ CaracterÃstica: Cancelar facturas con CFDIS no timbrados. Cuando se cancele la Factura Entonces la factura cambia a Cancelada Y el CFDI cambia a Cancelado + + +CaracterÃstica: Validación de XML y PDF en el total de factura, importe y precio unitario del producto + Esquema del escenario: + Dado una factura con la siguiente información + El cliente no está sujeto a IEPS + | Concepto | Precio Unitario | Cantidad | Impuesto | + | ProductoA | 308.3554| 5.0 | IEPS 30% | + | | | | IVA 16% | + Cuando: Valido la factura. + Entonces: la factura cambia a Abierta + Y el total de la factura, el importe y precio unitario del producto es correcto en el XML