Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions l10n_es_aeat/models/aeat_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,16 @@ def _change_date_format(self, date):
def _get_document_period(self):
return "%02d" % fields.Date.to_date(self._get_document_fiscal_date()).month

# TODO: Remove in 20.0 migration and use _is_aeat_unidentified_document
def _is_aeat_simplified_invoice(self):
"""Inheritable method to allow control when an
invoice are simplified or normal"""
return self._aeat_get_partner().aeat_simplified_invoice

def _is_aeat_unidentified_document(self):
"""Inheritable method to allow control when an document is identified"""
return self._is_aeat_simplified_invoice()

def _get_document_amount_total(self):
raise NotImplementedError()

Expand Down Expand Up @@ -154,8 +159,8 @@ def _aeat_check_exceptions(self):
self.ensure_one()
partner = self._aeat_get_partner()
country_code = self._get_aeat_country_code()
is_simplified_invoice = self._is_aeat_simplified_invoice()
if country_code == "ES" and not partner.vat and not is_simplified_invoice:
is_unidentified_document = self._is_aeat_unidentified_document()
if country_code == "ES" and not partner.vat and not is_unidentified_document:
raise UserError(_("The partner has not a VAT configured."))
if not self.company_id.chart_template:
raise UserError(
Expand Down
74 changes: 32 additions & 42 deletions l10n_es_aeat_sii_invoice_summary/models/account_move.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# © 2017 FactorLibre - Hugo Santos <hugo.santos@factorlibre.com>
# © 2018 FactorLibre - Victor Rodrigo <victor.rodrigo@factorlibre.com>
# © 2022 ProcessControl - David Ramia <david.ramia@processcontrol.es>
# Copyright 2026 Tecnativa - Carlos Dauden
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import _, exceptions, fields, models
from odoo import _, fields, models


class AccountMove(models.Model):
Expand All @@ -12,51 +13,40 @@ class AccountMove(models.Model):
sii_invoice_summary_start = fields.Char("SII Invoice Summary: First Invoice")
sii_invoice_summary_end = fields.Char("SII Invoice Summary: Last Invoice")

def _is_aeat_summary_invoice(self):
if (
self.is_invoice_summary
and self.is_sale_document()
and self.sii_invoice_summary_start != self.sii_invoice_summary_end
):
return True
return False

def _is_aeat_unidentified_document(self):
# En el SII, una factura resumen (F4) debe considerarse, a efectos de estructura
# y validaciones, equivalente a una factura simplificada (F2), compartiendo
# todas sus restricciones y campos obligatorios, con la única diferencia de
# requerir la clave TipoFactura = F4 y el campo adicional
# NumSerieFacturaEmisorResumenFin
return self.is_invoice_summary or super()._is_aeat_unidentified_document()

def _get_sii_invoice_type(self):
invoice_type = super()._get_sii_invoice_type()
if self._is_aeat_summary_invoice() and invoice_type == "F2":
invoice_type = "F4"
return invoice_type

def _get_aeat_invoice_dict_out(self, cancel=False):
inv_dict = super()._get_aeat_invoice_dict_out(cancel=cancel)
if self.is_invoice_summary and self.is_sale_document():
tipo_factura = "F4"
if self.sii_invoice_summary_start:
if self.sii_invoice_summary_start == self.sii_invoice_summary_end:
tipo_factura = "F2" if self.move_type == "out_invoice" else "R5"
else:
inv_dict["IDFactura"][
"NumSerieFacturaEmisor"
] = self.sii_invoice_summary_start
inv_dict["IDFactura"][
"NumSerieFacturaEmisorResumenFin"
] = self.sii_invoice_summary_end
if "FacturaExpedida" in inv_dict:
if "TipoFactura" in inv_dict["FacturaExpedida"]:
inv_dict["FacturaExpedida"]["TipoFactura"] = tipo_factura
if "Contraparte" in inv_dict["FacturaExpedida"]:
del inv_dict["FacturaExpedida"]["Contraparte"]
if (
"TipoRectificativa" in inv_dict["FacturaExpedida"]
and tipo_factura == "F4"
):
del inv_dict["FacturaExpedida"]["TipoRectificativa"]

if inv_dict.get("FacturaExpedida", {}).get("TipoFactura", "") == "F4":
inv_dict["IDFactura"][
"NumSerieFacturaEmisor"
] = self.sii_invoice_summary_start
inv_dict["IDFactura"][
"NumSerieFacturaEmisorResumenFin"
] = self.sii_invoice_summary_end
return inv_dict

def _aeat_check_exceptions(self):
Comment thread
pedrobaeza marked this conversation as resolved.
"""Inheritable method for exceptions control when sending SII invoices."""
res = False
try:
res = super()._aeat_check_exceptions()
except exceptions.UserError as e:
if (
e.args[0] == _("The partner has not a VAT configured.")
and self.is_invoice_summary
):
pass
else:
raise

if self.is_invoice_summary and self.is_purchase_document():
raise exceptions.UserError(_("You can't make a supplier summary invoice."))
return res

def write(self, vals):
"""Cannot let change sii_invoice_summary fields
values in a SII registered supplier invoice"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
"IDEmisorFactura": {
"NIF": "U2687761C"
},
"NumSerieFacturaEmisor": "1",
"FechaExpedicionFacturaEmisor": "01-01-2020",
"NumSerieFacturaEmisorResumenFin": "10"
"NumSerieFacturaEmisor": "TEST001",
"FechaExpedicionFacturaEmisor": "01-01-2020"
},
"PeriodoLiquidacion": {
"Ejercicio": 2020,
"Periodo": "01"
},
"FacturaExpedida": {
"TipoFactura": "F4",
"TipoFactura": "R5",
"ClaveRegimenEspecialOTrascendencia": "01",
"DescripcionOperacion": "/",
"TipoDesglose": {
Expand All @@ -36,6 +35,7 @@
}
}
},
"TipoRectificativa": "I",
"ImporteTotal": -300.0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
"IDEmisorFactura": {
"NIF": "U2687761C"
},
"NumSerieFacturaEmisor": "1",
"FechaExpedicionFacturaEmisor": "01-01-2020",
"NumSerieFacturaEmisorResumenFin": "10"
"NumSerieFacturaEmisor": "TEST001",
"FechaExpedicionFacturaEmisor": "01-01-2020"
},
"PeriodoLiquidacion": {
"Ejercicio": 2020,
"Periodo": "01"
},
"FacturaExpedida": {
"TipoFactura": "F4",
"TipoFactura": "R5",
"ClaveRegimenEspecialOTrascendencia": "01",
"DescripcionOperacion": "/",
"TipoDesglose": {
Expand Down Expand Up @@ -51,6 +50,7 @@
}
}
},
"TipoRectificativa": "I",
"ImporteTotal": -462.0
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
"IDEmisorFactura": {
"NIF": "U2687761C"
},
"NumSerieFacturaEmisor": "1",
"FechaExpedicionFacturaEmisor": "01-01-2020",
"NumSerieFacturaEmisorResumenFin": "10"
"NumSerieFacturaEmisor": "TEST001",
"FechaExpedicionFacturaEmisor": "01-01-2020"
},
"PeriodoLiquidacion": {
"Ejercicio": 2020,
"Periodo": "01"
},
"FacturaExpedida": {
"TipoFactura": "F4",
"TipoFactura": "R5",
"ClaveRegimenEspecialOTrascendencia": "01",
"DescripcionOperacion": "/",
"TipoDesglose": {
Expand All @@ -36,6 +35,7 @@
}
}
},
"TipoRectificativa": "I",
"ImporteTotal": -300.0
}
}
6 changes: 3 additions & 3 deletions l10n_es_aeat_sii_oca/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,13 +430,13 @@ def _get_sii_invoice_type(self):
if self.move_type in ["in_invoice", "in_refund"]:
invoice_type = "R4" if self.move_type == "in_refund" else "F1"
elif self.move_type in ["out_invoice", "out_refund"]:
is_simplified = self._is_aeat_simplified_invoice()
invoice_type = "F2" if is_simplified else "F1"
is_unidentified_document = self._is_aeat_unidentified_document()
invoice_type = "F2" if is_unidentified_document else "F1"
if self.move_type == "out_refund":
if self.sii_refund_specific_invoice_type:
invoice_type = self.sii_refund_specific_invoice_type
else:
invoice_type = "R5" if is_simplified else "R1"
invoice_type = "R5" if is_unidentified_document else "R1"
return invoice_type

def _get_aeat_invoice_dict_out(self, cancel=False):
Expand Down
14 changes: 4 additions & 10 deletions l10n_es_aeat_sii_oca/models/sii_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,27 +347,21 @@ def _get_sii_gen_type(self):
res = 1
return res

def _is_aeat_simplified_invoice(self):
"""Inheritable method to allow control when an
invoice are simplified or normal"""
partner = self._aeat_get_partner()
return partner.aeat_simplified_invoice

def _aeat_check_exceptions(self):
"""Inheritable method for exceptions control when sending SII invoices."""
res = super()._aeat_check_exceptions()
if self.company_id.sii_enabled:
gen_type = self._get_sii_gen_type()
partner = self._aeat_get_partner()
country_code = self._get_aeat_country_code()
is_simplified_invoice = self._is_aeat_simplified_invoice()
is_unidentified_document = self._is_aeat_unidentified_document()
if (
(gen_type != 3 or country_code == "ES")
and not partner.vat
and not (
partner.aeat_identification_type and partner.aeat_identification
)
and not is_simplified_invoice
and not is_unidentified_document
):
raise UserError(_("The partner has not a VAT configured."))
if not self.sii_enabled:
Expand Down Expand Up @@ -697,7 +691,7 @@ def _get_aeat_invoice_dict_out(self, cancel=False):
company = self.company_id
fiscal_year = self._get_document_fiscal_year()
period = self._get_document_period()
is_simplified_invoice = self._is_aeat_simplified_invoice()
is_unidentified_document = self._is_aeat_unidentified_document()
serial_number = self._get_document_serial_number()
inv_dict = {
"IDFactura": {
Expand Down Expand Up @@ -726,7 +720,7 @@ def _get_aeat_invoice_dict_out(self, cancel=False):
if self.sii_macrodata:
inv_dict["FacturaExpedida"].update(Macrodato="S")
exp_dict = inv_dict["FacturaExpedida"]
if not is_simplified_invoice:
if not is_unidentified_document:
# Simplified invoices don't have counterpart
exp_dict["Contraparte"] = {
"NombreRazon": partner.name[0:120],
Expand Down
5 changes: 5 additions & 0 deletions l10n_es_aeat_sii_oca/tests/test_l10n_es_aeat_sii.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,11 @@ def test_is_aeat_simplified_invoice(self):
self.partner.aeat_simplified_invoice = True
self.assertTrue(self.invoice._is_aeat_simplified_invoice())

def test_is_aeat_unidentified_document(self):
self.assertFalse(self.invoice._is_aeat_unidentified_document())
self.partner.aeat_simplified_invoice = True
self.assertTrue(self.invoice._is_aeat_unidentified_document())

def test_aeat_check_exceptions_case_supplier_simplified(self):
self.partner.aeat_simplified_invoice = True
invoice = self.env["account.move"].create(
Expand Down
3 changes: 3 additions & 0 deletions l10n_es_pos_sii/models/pos_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ def _aeat_get_partner(self):
def _is_aeat_simplified_invoice(self):
return True

def _is_aeat_unidentified_document(self):
return True

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aquí hay que seguir teniendo en cuenta los límites de las simplificadas (<400 €).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eso queda fuera del ámbito de este PR.

Pregunta a quien hiciese al PR que añadió "el código original" y a quien aprobase y fusionase esos cambios:

Image


def _get_mapping_key(self):
return "out_invoice"

Expand Down
4 changes: 4 additions & 0 deletions l10n_es_pos_sii/tests/test_l10n_es_pos_sii.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,7 @@ def test_07_export_for_ui_session_is_closed(self):
),
"The session is closed",
)

def test_08_is_aeat_unidentified_document(self):
for order in self.session.order_ids:
self.assertTrue(order._is_aeat_unidentified_document())
2 changes: 1 addition & 1 deletion l10n_es_verifactu_oca/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def _compute_verifactu_registration_key(self):
def _get_verifactu_document_type(self):
invoice_type = ""
if self.move_type in ["out_invoice", "out_refund"]:
is_simplified = self._is_aeat_simplified_invoice()
is_simplified = self._is_aeat_unidentified_document()
invoice_type = "F2" if is_simplified else "F1"
if self.move_type == "out_refund":
if self.verifactu_refund_specific_type:
Expand Down