Skip to content

Commit

Permalink
[15.0][IMP] Refactor para futura implementación Veri*FACTU.
Browse files Browse the repository at this point in the history
  • Loading branch information
pcastelovigo committed Dec 12, 2024
1 parent 2c79cd3 commit f66dc12
Show file tree
Hide file tree
Showing 46 changed files with 560 additions and 460 deletions.
18 changes: 10 additions & 8 deletions l10n_es_aeat/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import account_fiscal_position
from . import account_journal
from . import account_move
from . import account_tax
from . import res_company
from . import res_partner
from . import res_partner_bank
from . import aeat_certificate
from . import aeat_mixin
from . import aeat_soap
from . import aeat_tax_agency
from . import l10n_es_aeat_export_config
from . import l10n_es_aeat_export_config_line
from . import l10n_es_aeat_map_tax
from . import l10n_es_aeat_map_tax_line
from . import l10n_es_aeat_report
from . import l10n_es_aeat_report_tax_mapping
from . import l10n_es_aeat_tax_line
from . import l10n_es_aeat_export_config
from . import l10n_es_aeat_export_config_line
from . import aeat_certificate
from . import aeat_soap
from . import aeat_tax_agency
from . import res_company
from . import res_partner
from . import res_partner_bank
16 changes: 16 additions & 0 deletions l10n_es_aeat/models/account_fiscal_position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2017 FactorLibre - Ismael Calvo <[email protected]>
# Copyright 2024 Aures TIC - Jose Zambudio <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class AccountFiscalPosition(models.Model):
_inherit = "account.fiscal.position"

aeat_active = fields.Boolean(
string="AEAT Active",
copy=False,
default=True,
help="Enable AEAT communication for this fiscal position?",
)
163 changes: 163 additions & 0 deletions l10n_es_aeat/models/aeat_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Copyright 2021 Tecnativa - João Marques
# Copyright 2022 ForgeFlow - Lois Rilo
# Copyright 2011-2023 Tecnativa - Pedro M. Baeza
# Copyright 2023 Aures Tic - Almudena de la Puente <[email protected]>
# Copyright 2023-2024 Aures Tic - Jose Zambudio <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging

from requests import Session

from odoo import _, api, fields, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)

try:
from zeep import Client
from zeep.plugins import HistoryPlugin
from zeep.transports import Transport
except (ImportError, IOError) as err:
_logger.debug(err)

Check warning on line 21 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L20-L21

Added lines #L20 - L21 were not covered by tests

AEAT_DATE_FORMAT = "%d-%m-%Y"
AEAT_STATES = [
("not_sent", "Not sent"),
("sent", "Sent"),
("sent_w_errors", "Accepted with errors"),
]


def round_by_keys(elem, search_keys, prec=2):
"""This uses ``round`` method directly as if has been tested that Odoo's
``float_round`` still returns incorrect amounts for certain values. Try
3 units x 3,77 €/unit with 10% tax and you will be hit by the error
(on regular x86 architectures)."""
if isinstance(elem, dict):
for key, value in elem.items():
if key in search_keys:
elem[key] = round(elem[key], prec)
else:
round_by_keys(value, search_keys)
elif isinstance(elem, list):
for value in elem:
round_by_keys(value, search_keys)


class AeatMixin(models.AbstractModel):
_name = "aeat.mixin"
_description = "Aeat Mixin"

aeat_state = fields.Selection(
selection=AEAT_STATES,
string="AEAT send state",
default="not_sent",
readonly=True,
copy=False,
help="Indicates the state of this document in relation with the "
"presentation at the AEAT",
)
aeat_send_error = fields.Text(
string="AEAT Send Error",
readonly=True,
copy=False,
)
aeat_send_failed = fields.Boolean(
string="SII send failed",
copy=False,
help="Indicates that the last attempt to communicate this document to "
"the SII has failed. See SII return for details",
)
aeat_header_sent = fields.Text(
string="AEAT last header sent",
copy=False,
readonly=True,
)
aeat_content_sent = fields.Text(
string="AEAT last content sent",
copy=False,
readonly=True,
)

def _get_document_date(self):
raise NotImplementedError()

Check warning on line 83 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L83

Added line #L83 was not covered by tests

def _get_document_serial_number(self):
raise NotImplementedError()

Check warning on line 86 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L86

Added line #L86 was not covered by tests

def _aeat_get_partner(self):
raise NotImplementedError()

Check warning on line 89 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L89

Added line #L89 was not covered by tests

def _get_document_fiscal_date(self):
raise NotImplementedError()

Check warning on line 92 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L92

Added line #L92 was not covered by tests

def _get_document_fiscal_year(self):
return fields.Date.to_date(self._get_document_fiscal_date()).year

Check warning on line 95 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L95

Added line #L95 was not covered by tests

def _change_date_format(self, date):
datetimeobject = fields.Date.to_date(date)
new_date = datetimeobject.strftime(AEAT_DATE_FORMAT)
return new_date

def _get_document_period(self):
return "%02d" % fields.Date.to_date(self._get_document_fiscal_date()).month

Check warning on line 103 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L103

Added line #L103 was not covered by tests

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

Check warning on line 108 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L108

Added line #L108 was not covered by tests

def _get_document_amount_total(self):
raise NotImplementedError()

Check warning on line 111 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L111

Added line #L111 was not covered by tests

def _get_mapping_key(self):
raise NotImplementedError()

Check warning on line 114 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L114

Added line #L114 was not covered by tests

def _get_aeat_invoice_dict(self):
raise NotImplementedError()

Check warning on line 117 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L117

Added line #L117 was not covered by tests

@api.model
def _get_aeat_taxes_map(self, codes, date):
raise NotImplementedError()

Check warning on line 121 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L121

Added line #L121 was not covered by tests

def _get_valid_document_states(self):
raise NotImplementedError()

Check warning on line 124 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L124

Added line #L124 was not covered by tests

def _get_aeat_header(self, tipo_comunicacion=False, cancellation=False):
raise NotImplementedError()

Check warning on line 127 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L127

Added line #L127 was not covered by tests

def _bind_service(self, client, port_name, address=None):
raise NotImplementedError()

Check warning on line 130 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L130

Added line #L130 was not covered by tests

def _connect_params_aeat(self, mapping_key):
raise NotImplementedError()

Check warning on line 133 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L133

Added line #L133 was not covered by tests

def _connect_aeat(self, mapping_key):
self.ensure_one()
public_crt, private_key = self.env["l10n.es.aeat.certificate"].get_certificates(

Check warning on line 137 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L136-L137

Added lines #L136 - L137 were not covered by tests
company=self.company_id
)
params = self._connect_params_aeat(mapping_key)
session = Session()
session.cert = (public_crt, private_key)
transport = Transport(session=session)
history = HistoryPlugin()
client = Client(wsdl=params["wsdl"], transport=transport, plugins=[history])
return self._bind_service(client, params["port_name"], params["address"])

Check warning on line 146 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L140-L146

Added lines #L140 - L146 were not covered by tests

def _get_aeat_country_code(self):
self.ensure_one()
return self._aeat_get_partner()._parse_aeat_vat_info()[0]

def _aeat_check_exceptions(self):
"""Inheritable method for exceptions control when sending AEAT documentss."""
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:
raise UserError(_("The partner has not a VAT configured."))

Check warning on line 159 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L159

Added line #L159 was not covered by tests
if not self.company_id.chart_template_id:
raise UserError(

Check warning on line 161 in l10n_es_aeat/models/aeat_mixin.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/aeat_mixin.py#L161

Added line #L161 was not covered by tests
_("You have to select what account chart template use this" " company.")
)
16 changes: 14 additions & 2 deletions l10n_es_aeat/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Copyright 2019 Tecnativa - Carlos Dauden
# Copyright 2017 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models
Expand All @@ -15,8 +16,8 @@ class ResPartner(models.Model):
aeat_identification_type = fields.Selection(
string="AEAT Identification type",
help=(
"Used to specify an identification type to send to SII. Normally for "
"sending national and export invoices to SII where the customer country "
"Used to specify an identification type to send to AEAT. Normally for "
"sending national and export invoices to AEAT where the customer country "
"is not Spain, it would calculate an identification type of 04 if the VAT "
"field is filled and 06 if it was not. This field is to specify "
"types of 03 through 05, in the event that the customer doesn't identify "
Expand All @@ -35,6 +36,17 @@ class ResPartner(models.Model):
# 02 - NIF - VAT
# 04 - Official document from the original country
# 07 - Not registered on census
aeat_simplified_invoice = fields.Boolean(
string="Simplified invoices in AEAT?",
help="Checking this mark, invoices done to this partner will be "
"sent to AEAT as simplified invoices.",
)
aeat_sending_enabled = fields.Boolean(
compute="_compute_aeat_sending_enabled",
)

def _compute_aeat_sending_enabled(self):
self.aeat_sending_enabled = False

Check warning on line 49 in l10n_es_aeat/models/res_partner.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat/models/res_partner.py#L49

Added line #L49 was not covered by tests

def _map_aeat_country_code(self, country_code, extended=False):
"""Map country codes according the fiscal conditions.
Expand Down
2 changes: 1 addition & 1 deletion l10n_es_aeat/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@
span.pre {
white-space: pre }

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

span.section-subtitle {
Expand Down
7 changes: 7 additions & 0 deletions l10n_es_aeat/views/res_partner_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
</group>
</page>
</notebook>
<xpath expr="//field[@name='vat']" position="after">
<field name="aeat_sending_enabled" invisible="1" />
<field
name="aeat_simplified_invoice"
attrs="{'invisible': [('aeat_sending_enabled', '=', False)]}"
/>
</xpath>
</field>
</record>
</odoo>
16 changes: 8 additions & 8 deletions l10n_es_aeat_sii_match/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def _get_diffs(self, odoo_values, sii_values):
def _get_diffs_values(self, sii_values):
self.ensure_one()
res = []
if self.sii_content_sent:
odoo_values = json.loads(self.sii_content_sent)
if self.aeat_content_sent:
odoo_values = json.loads(self.aeat_content_sent)

Check warning on line 108 in l10n_es_aeat_sii_match/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat_sii_match/models/account_move.py#L108

Added line #L108 was not covered by tests
if self.move_type in ["out_invoice", "out_refund"]:
res += self._get_diffs(
odoo_values["FacturaExpedida"], sii_values["DatosFacturaEmitida"]
Expand Down Expand Up @@ -135,7 +135,7 @@ def _process_invoice_for_contrast_aeat(self):
def contrast_aeat(self):
invoices = self.filtered(
lambda i: (
i.sii_state == "sent"
i.aeat_state == "sent"
and i.state == "posted"
and i.sii_csv
and i.sii_enabled
Expand All @@ -162,7 +162,7 @@ def direct_contrast_aeat(self):
if (
self.sii_csv
and self.sii_enabled
and self.sii_state == "sent"
and self.aeat_state == "sent"
and self.state == "posted"
):
self._contrast_invoice_to_aeat()
Expand Down Expand Up @@ -197,7 +197,7 @@ def _get_contrast_invoice_dict_out(self):
"FechaExpedicionFacturaEmisor": invoice_date,
},
}
if not partner.sii_simplified_invoice:
if not partner.aeat_simplified_invoice:
# Simplified invoices don't have counterpart
inv_dict["Contraparte"] = {"NombreRazon": partner.name[0:120]}
# Uso condicional de IDOtro/NIF
Expand Down Expand Up @@ -231,7 +231,7 @@ def _get_contrast_invoice_dict_in(self):

def _get_contrast_invoice_dict(self):
self.ensure_one()
self._sii_check_exceptions()
self._aeat_check_exceptions()

Check warning on line 234 in l10n_es_aeat_sii_match/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat_sii_match/models/account_move.py#L234

Added line #L234 was not covered by tests
if self.move_type in ["out_invoice", "out_refund"]:
return self._get_contrast_invoice_dict_out()
elif self.move_type in ["in_invoice", "in_refund"]:
Expand All @@ -240,8 +240,8 @@ def _get_contrast_invoice_dict(self):

def _contrast_invoice_to_aeat(self):
for invoice in self.filtered(lambda i: i.state == "posted"):
serv = invoice._connect_sii(invoice.move_type)
header = invoice._get_sii_header(False, True)
serv = invoice._connect_aeat(invoice.move_type)
header = invoice._get_aeat_header(False, True)

Check warning on line 244 in l10n_es_aeat_sii_match/models/account_move.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat_sii_match/models/account_move.py#L243-L244

Added lines #L243 - L244 were not covered by tests
inv_vals = {}
try:
inv_dict = invoice._get_contrast_invoice_dict()
Expand Down
6 changes: 3 additions & 3 deletions l10n_es_aeat_sii_match/models/aeat_sii_match_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,9 @@ def _get_invoices_from_sii(self):
if sii_match_report.invoice_type == "in":
mapping_key = "in_invoice"
serv = (
self.env["account.move"].search([], limit=1)._connect_sii(mapping_key)
self.env["account.move"].search([], limit=1)._connect_aeat(mapping_key)
)
header = sii_match_report._get_sii_header()
header = sii_match_report._get_aeat_header()

Check warning on line 376 in l10n_es_aeat_sii_match/models/aeat_sii_match_report.py

View check run for this annotation

Codecov / codecov/patch

l10n_es_aeat_sii_match/models/aeat_sii_match_report.py#L376

Added line #L376 was not covered by tests
match_vals = {}
summary = {}
try:
Expand Down Expand Up @@ -426,7 +426,7 @@ def _get_invoices_from_sii(self):
new_cr.close()
raise

def _get_sii_header(self):
def _get_aeat_header(self):
"""Builds SII send header
:return Dict with header data depending on cancellation
Expand Down
4 changes: 2 additions & 2 deletions l10n_es_aeat_sii_match/tests/test_l10n_es_aeat_sii_match.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def setUpClass(cls):
def test_invoice_diffs_values(self):
self._activate_certificate()
invoice = self.invoice
invoice.sii_state = "sent"
invoice.sii_csv = invoice._get_sii_invoice_dict()
invoice.aeat_state = "sent"
invoice.sii_csv = invoice._get_aeat_invoice_dict()
res = invoice._get_diffs_values(invoice.sii_csv)
self.assertEqual(res, [])
2 changes: 1 addition & 1 deletion l10n_es_aeat_sii_match/views/account_move_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
('sii_csv', '=', False)]}"
/>
</field>
<field name="sii_state" position="after">
<field name="aeat_state" position="after">
<field name="sii_match_state" />
<field name="sii_contrast_state" />
</field>
Expand Down
Loading

0 comments on commit f66dc12

Please sign in to comment.