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
3 changes: 3 additions & 0 deletions l10n_es_verifactu/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"data/verifactu_map_data.xml",
"data/ir_config_parameter.xml",
"data/ir_cron.xml",
"data/mail_activity_data.xml",
"security/verifactu_security.xml",
"security/ir.model.access.csv",
"views/aeat_tax_agency_view.xml",
"views/account_move_view.xml",
Expand All @@ -36,5 +38,6 @@
"views/verifactu_map_lines_view.xml",
"views/verifactu_registration_keys_view.xml",
"views/report_invoice.xml",
"views/verifactu_send_response_view.xml",
],
}
11 changes: 11 additions & 0 deletions l10n_es_verifactu/data/mail_activity_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="mail_activity_data_exception" model="mail.activity.type">
<field name="name">Exception</field>
<field name="icon">fa-exclamation-triangle</field>
<field name="sequence">5</field>
<field name="summary">Connection error with Verifactu</field>
<field name="res_model">verifactu.send.response</field>
<field name="default_user_id" ref="base.group_system" />
</record>
</odoo>
36 changes: 31 additions & 5 deletions l10n_es_verifactu/models/verifactu_send_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ def _compute_last_error_code(self):

@api.model
def _cron_send_documents_to_verifactu(self):
for company in self.env["res.company"].search([]):
for company in self.env["res.company"].search(
[("verifactu_enabled", "=", True)]
):

# Look for documents where we have to send as an incident
self.env.cr.execute(
Expand Down Expand Up @@ -138,8 +140,8 @@ def _get_verifactu_aeat_header(self):
"NIF": self.company_id.partner_id._parse_aeat_vat_info()[2],
},
}
incicent = self.env.context.get("verifactu_incident", False)
if incicent:
incident = self.env.context.get("verifactu_incident", False)
if incident:
header.update({"RemisionVoluntaria": {"Incidencia": "S"}})
return header

Expand Down Expand Up @@ -192,6 +194,7 @@ def _send_documents_to_verifactu(self):
rec = self[0]
header = rec._get_verifactu_aeat_header()
registro_factura_list = []
create_exception = False
for rec in self:
rec.send_attempt += 1
if rec.move_id:
Expand All @@ -202,18 +205,30 @@ def _send_documents_to_verifactu(self):
res = serv.RegFactuSistemaFacturacion(header, registro_factura_list)
except Exception as e:
res = _("Error when trying to connect to Veri*FACTU: {}").format(e)
create_exception = True
response_name = ""
response = (
self.env["verifactu.send.response"]
.sudo()
.create(
{
"header": json.dumps(header),
"name": response_name,
"invoice_data": json.dumps(registro_factura_list),
"response": res,
"verifactu_csv": "CSV" in res and res["CSV"] or "",
"verifactu_csv": "CSV" in res and res["CSV"] or _("-"),
}
)
)
response.complete_open_activity_on_exception()
if create_exception:
if not response.datetime:
response.datetime = fields.Datetime.now()
response.create_activity_on_exception()
else:
response.complete_open_activity_on_exception()

create_response_activity = False
respuestaLineas = "RespuestaLinea" in res and res["RespuestaLinea"] or []
for linea in respuestaLineas:
invoice_num = linea["IDFactura"]["NumSerieFactura"]
Expand Down Expand Up @@ -260,11 +275,22 @@ def _send_documents_to_verifactu(self):
doc_vals["aeat_send_failed"] = True
doc_vals["verifactu_return"] = linea
send_error = False
if linea["CodigoErrorRegistro"]:
if linea.get("CodigoErrorRegistro"):
send_error = "{} | {}".format(
str(linea["CodigoErrorRegistro"]),
str(linea["DescripcionErrorRegistro"]),
)
doc_vals["aeat_send_error"] = send_error
send_queue.move_id.write(doc_vals)
send_state = VERIFACTU_STATE_MAPPING.get(linea["EstadoRegistro"], "")
if send_state != "correct":
create_response_activity = True
updated_response_name = _("Verifactu sending")
if create_exception:
updated_response_name = _("Connection error with Verifactu")
elif create_response_activity:
updated_response_name = _("Incorrect invoices sent to Verifactu")
response.name = updated_response_name
if create_response_activity:
response.create_send_response_activity()
return True
98 changes: 97 additions & 1 deletion l10n_es_verifactu/models/verifactu_send_response.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,109 @@
# Copyright 2025 ForgeFlow S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
from odoo import _, fields, models


class VerifactuSendResponse(models.Model):
_name = "verifactu.send.response"
_description = "Verifactu Send Response"
_inherit = ["mail.activity.mixin", "mail.thread"]

header = fields.Text()
name = fields.Char()
invoice_data = fields.Text()
response = fields.Text()
verifactu_csv = fields.Text()
datetime = fields.Datetime(readonly=True)
activity_type_id = fields.Many2one(
"mail.activity.type",
string="Activity Type",
compute="_compute_activity_type_id",
store=True,
)

def _compute_activity_type_id(self):
for record in self:
activity = self.env["mail.activity"].search(
[
("res_model", "=", "verifactu.send.response"),
("res_id", "=", record.id),
],
limit=1,
)
record.activity_type_id = activity.activity_type_id if activity else False

def create_activity_on_exception(self):
model_id = self.env["ir.model"]._get_id("verifactu.send.response")
exception_activity_type = self.env.ref(
"l10n_es_verifactu.mail_activity_data_exception"
)
activity_vals = []
responsible_group = self.env.ref(
"l10n_es_verifactu.group_verifactu_responsible"
)
users = responsible_group.users
for record in self:
existing = self.env["mail.activity"].search_count(
[
("activity_type_id", "=", exception_activity_type.id),
("res_model", "=", "verifactu.send.response"),
],
limit=1,
)
if not existing:
user = users[:1] or self.env.user
activity_vals.append(
{
"res_model_id": model_id,
"res_model": "verifactu.send.response",
"res_id": record.id,
"activity_type_id": exception_activity_type.id,
"user_id": user.id,
"summary": _("Check connection error with Verifactu"),
"note": _(
"There has been an error when trying to connect to Verifactu"
),
}
)
if activity_vals:
return self.env["mail.activity"].create(activity_vals)
return False

def create_send_response_activity(self):
activity_type = self.env.ref("mail.mail_activity_data_warning")
model_id = self.env["ir.model"]._get_id("verifactu.send.response")
activity_vals = []
responsible_group = self.env.ref(
"l10n_es_verifactu.group_verifactu_responsible"
)
users = responsible_group.users
for record in self:
user = users[:1] or self.env.user
activity_vals.append(
{
"activity_type_id": activity_type.id,
"user_id": user.id,
"res_id": record.id,
"res_model": "verifactu.send.response",
"res_model_id": model_id,
"summary": _("Check incorrect invoices from Verifactu"),
"note": _("There is an error with one or more invoices"),
}
)
return self.env["mail.activity"].create(activity_vals)

def complete_open_activity_on_exception(self):
exception_activity_type = self.env.ref(
"l10n_es_verifactu.mail_activity_data_exception"
)
for _record in self:
activity = self.env["mail.activity"].search(
[
("activity_type_id", "=", exception_activity_type.id),
("res_model", "=", "verifactu.send.response"),
],
)
for act in activity:
if act.state != "done":
act.action_done()
return True
4 changes: 2 additions & 2 deletions l10n_es_verifactu/models/verifactu_send_response_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class VerifactuSendResponseLine(models.Model):
_description = "Verifactu Send Log"
_order = "id desc"

send_queue_id = fields.Many2one("verifactu.send.queue", required=True)
send_response_id = fields.Many2one("verifactu.send.response", required=True)
send_queue_id = fields.Many2one("verifactu.send.queue")
send_response_id = fields.Many2one("verifactu.send.response")
move_id = fields.Many2one(related="send_queue_id.move_id")
response = fields.Text()
send_state = fields.Selection(
Expand Down
1 change: 1 addition & 0 deletions l10n_es_verifactu/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ access_model_verifactu_send_response_invoice_user,verifactu.send.response invoic
access_model_verifactu_send_response_system,verifactu.send.response system,model_verifactu_send_response,base.group_system,1,1,1,1
access_model_verifactu_send_response_line_invoice_user,verifactu.send.response.line invoice user,model_verifactu_send_response_line,account.group_account_invoice,1,0,0,0
access_model_verifactu_send_response_line_system,verifactu.send.response.line system,model_verifactu_send_response_line,base.group_system,1,1,1,1
access_model_verifactu_send_response_verifactu_responsible,verifactu.send.response verifactu,model_verifactu_send_response,l10n_es_verifactu.group_verifactu_responsible,1,1,0,0
6 changes: 6 additions & 0 deletions l10n_es_verifactu/security/verifactu_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<odoo>
<record id="group_verifactu_responsible" model="res.groups">
<field name="name">Verifactu Responsible</field>
<field name="category_id" ref="base.module_category_accounting" />
</record>
</odoo>
11 changes: 4 additions & 7 deletions l10n_es_verifactu/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@

/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.

See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
Expand Down Expand Up @@ -275,7 +274,7 @@
margin-left: 2em ;
margin-right: 2em }

pre.code .ln { color: gray; } /* line numbers */
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
Expand All @@ -301,7 +300,7 @@
span.pre {
white-space: pre }

span.problematic, pre.problematic {
span.problematic {
color: red }

span.section-subtitle {
Expand Down Expand Up @@ -466,9 +465,7 @@ <h2><a class="toc-backref" href="#toc-entry-7">Contributors</a></h2>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
Expand Down
35 changes: 35 additions & 0 deletions l10n_es_verifactu/tests/json/verifactu_mocked_response_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"CSV": "A-Y23JP3582934",
"DatosPresentacion": {
"NIFPresentador": "G87846952",
"TimestampPresentacion": "2026-01-01T16:54:41+02:00"
},
"Cabecera": {
"ObligadoEmision": {
"NombreRazon": "Spanish test company",
"NIF": "G87846952"
},
"Representante": "",
"RemisionVoluntaria": "",
"RemisionRequerimiento": ""
},
"TiempoEsperaEnvio": "60",
"EstadoEnvio": "Correcto",
"RespuestaLinea": [
{
"IDFactura": {
"IDEmisorFactura": "89890001K",
"NumSerieFactura": "INV/2026/00001",
"FechaExpedicionFactura": "01-01-2026"
},
"Operacion": {
"TipoOperacion": "Alta",
"Subsanacion": "",
"RechazoPrevio": "",
"SinRegistroPrevio": ""
},
"RefExterna": "",
"EstadoRegistro": "AceptadoConErrores"
}
]
}
Loading
Loading