Skip to content

Commit 4609634

Browse files
[IMP] l10n_es*: enable pos orders to be sent to TBAI
An edi document is directly generated from the `pos.order` and is sent to TicketBAI. This avoids creating an invoice for each `pos.order`. Also the commit remove the `sequence.mixin` inheritance on the `l10n_es_edi_tbai.document` model. It was overkill as it was only used for one method call. task-4034665 closes odoo#178613 Related: odoo/upgrade#6453 Signed-off-by: Arnaud Sibille (arsi) <[email protected]>
1 parent e571324 commit 4609634

37 files changed

+641
-184
lines changed

addons/l10n_es/__manifest__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
'views/account_tax_views.xml',
3333
'data/product_data.xml',
3434
'views/report_invoice.xml',
35+
'views/res_config_settings_views.xml',
3536
'data/mod111.xml',
3637
'data/mod115.xml',
3738
'data/mod303.xml',

addons/l10n_es/models/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Part of Odoo. See LICENSE file for full copyright and licensing details.
22
from . import account_move
33
from . import account_tax
4+
from . import res_company
5+
from . import res_config_settings
46
from . import res_partner
57
from . import template_es_assec
68
from . import template_es_common

addons/l10n_es/models/res_company.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from odoo import fields, models
2+
3+
4+
class ResCompany(models.Model):
5+
_inherit = 'res.company'
6+
7+
l10n_es_simplified_invoice_limit = fields.Float(
8+
string="Simplified Invoice limit amount",
9+
help="Over this amount is not legally possible to create a simplified invoice",
10+
default=400,
11+
)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from odoo import fields, models
2+
3+
4+
class ResConfigSettings(models.TransientModel):
5+
_inherit = 'res.config.settings'
6+
7+
l10n_es_simplified_invoice_limit = fields.Float(
8+
related='company_id.l10n_es_simplified_invoice_limit',
9+
readonly=False,
10+
)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo>
3+
<record id="res_config_settings_view_form" model="ir.ui.view">
4+
<field name="name">res.config.settings.view.form</field>
5+
<field name="model">res.config.settings</field>
6+
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
7+
<field name="arch" type="xml">
8+
<xpath expr="//app[@name='account']/block" position="after">
9+
<block title="Spain Localization" name="spain_localization" invisible="1">
10+
<setting string="Simplified Invoice Limit" title="">
11+
<div class="text-muted">
12+
Above this limit the simplified invoice won't be made
13+
</div>
14+
<field name="l10n_es_simplified_invoice_limit"/>
15+
</setting>
16+
</block>
17+
</xpath>
18+
</field>
19+
</record>
20+
</odoo>

addons/l10n_es_edi_sii/views/res_config_settings_views.xml

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,43 @@
33
<record id="res_config_settings_view_form" model="ir.ui.view">
44
<field name="name">res.config.settings.view.form.inherit.l10n.es</field>
55
<field name="model">res.config.settings</field>
6-
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
6+
<field name="inherit_id" ref="l10n_es.res_config_settings_view_form"/>
77
<field name="arch" type="xml">
8-
<xpath expr="//app[@name='account']/block" position="after">
9-
<block title="Spain Localization (SII)" name="spain_localization_sii" invisible="country_code != 'ES'">
10-
<!-- Invisible fields -->
11-
<field name="l10n_es_sii_certificate_ids" invisible="1"/>
12-
<setting string="Registro de Libros connection SII" company_dependent="1">
13-
<div class="content-group">
14-
<div class="mt16">
15-
<label for="l10n_es_sii_tax_agency" class="o_light_label"/>
16-
<field name="l10n_es_sii_tax_agency"/>
17-
<div class="text-muted" invisible="l10n_es_sii_tax_agency">
18-
No tax agency selected: SII not activated.
19-
</div>
20-
<div class="text-muted" invisible="not l10n_es_sii_tax_agency">
21-
Tax agency selected: invoices will be sent by SII.
22-
</div>
23-
<br/>
24-
<div class="o_row">
25-
<label for="l10n_es_sii_test_env" class="o_light_label"/>
26-
<field name="l10n_es_sii_test_env"/>
27-
</div>
28-
<div class="text-muted" invisible="not l10n_es_sii_test_env">
29-
Test mode: EDI data is sent to separate test servers and is not considered official.
30-
</div>
31-
<div class="text-muted" invisible="l10n_es_sii_test_env">
32-
Production mode: EDI data is sent to the official agency servers.
33-
</div>
34-
<br/>
35-
<div>
36-
<button name="%(l10n_es_edi_sii_certificate_action)d" type="action" class="oe_link">Manage certificates (SII)</button>
37-
</div>
8+
<xpath expr="//block[@name='spain_localization']" position="attributes">
9+
<attribute name="invisible">country_code != 'ES'</attribute>
10+
</xpath>
11+
<xpath expr="//block[@name='spain_localization']" position="inside">
12+
<!-- Invisible fields -->
13+
<field name="l10n_es_sii_certificate_ids" invisible="1"/>
14+
<setting string="Registro de Libros connection SII" company_dependent="1">
15+
<div class="content-group">
16+
<div class="mt16">
17+
<label for="l10n_es_sii_tax_agency" class="o_light_label"/>
18+
<field name="l10n_es_sii_tax_agency"/>
19+
<div class="text-muted" invisible="l10n_es_sii_tax_agency">
20+
No tax agency selected: SII not activated.
21+
</div>
22+
<div class="text-muted" invisible="not l10n_es_sii_tax_agency">
23+
Tax agency selected: invoices will be sent by SII.
24+
</div>
25+
<br/>
26+
<div class="o_row">
27+
<label for="l10n_es_sii_test_env" class="o_light_label"/>
28+
<field name="l10n_es_sii_test_env"/>
29+
</div>
30+
<div class="text-muted" invisible="not l10n_es_sii_test_env">
31+
Test mode: EDI data is sent to separate test servers and is not considered official.
32+
</div>
33+
<div class="text-muted" invisible="l10n_es_sii_test_env">
34+
Production mode: EDI data is sent to the official agency servers.
35+
</div>
36+
<br/>
37+
<div>
38+
<button name="%(l10n_es_edi_sii_certificate_action)d" type="action" class="oe_link">Manage certificates (SII)</button>
3839
</div>
3940
</div>
40-
</setting>
41-
</block>
41+
</div>
42+
</setting>
4243
</xpath>
4344
</field>
4445
</record>

addons/l10n_es_edi_tbai/data/template_LROE_bizkaia.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
</FacturaRectificativa>
103103
<FacturasRectificadasSustituidas t-if="credit_note_invoices">
104104
<IDFacturaRectificadaSustituida t-foreach="credit_note_invoices" t-as="credit_note_invoice">
105-
<t t-set="seq_and_num" t-value="credit_note_invoice.l10n_es_tbai_post_document_id._get_l10n_es_tbai_sequence_and_number()"/>
105+
<t t-set="seq_and_num" t-value="credit_note_invoice.l10n_es_tbai_post_document_id._get_tbai_sequence_and_number()"/>
106106
<SerieFactura t-out="seq_and_num[0]"/>
107107
<NumFactura t-out="seq_and_num[1]"/>
108108
<FechaExpedicionFactura t-out="format_date(credit_note_invoice.invoice_date)"/>

addons/l10n_es_edi_tbai/models/account_move.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ def _l10n_es_tbai_get_invoice_values(self, cancel=False):
284284
'taxes': self.invoice_line_ids.tax_ids,
285285
'rate': abs(self.amount_total / self.amount_total_signed) if self.amount_total else 1,
286286
'base_lines': [
287-
line._convert_to_tax_base_line_dict()
287+
line._convert_to_tax_base_line_dict() | {'name': line.name}
288288
for line in self.invoice_line_ids
289289
if line.display_type not in ('line_section', 'line_note') and not line._l10n_es_tbai_is_ignored()
290290
],

addons/l10n_es_edi_tbai/models/l10n_es_edi_tbai_document.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
class L10nEsEdiTbaiDocument(models.Model):
5050
_name = 'l10n_es_edi_tbai.document'
5151
_description = 'TicketBAI Document'
52-
_inherit = 'sequence.mixin'
5352

5453
name = fields.Char(
5554
required=True,
@@ -116,6 +115,9 @@ def _check_can_post(self, values):
116115
return _("Please configure the Tax ID on your company for TicketBAI.")
117116

118117
if values['is_sale'] and not self.is_cancel:
118+
if any(not base_line['taxes'] for base_line in values['base_lines']):
119+
return self.env._("There should be at least one tax set on each line in order to send to TicketBAI.")
120+
119121
# Chain integrity check: chain head must have been REALLY posted
120122
chain_head_doc = self.company_id._get_l10n_es_tbai_last_chained_document()
121123
if chain_head_doc and chain_head_doc != self and chain_head_doc.state != 'accepted':
@@ -436,7 +438,7 @@ def get_base_line_price_total(base_line):
436438
'discount': -sign * (discount / rate),
437439
'unit_price': sign * (base_line['price_unit'] / rate) if base_line['quantity'] > 0 else 0,
438440
'total': sign * (total / rate),
439-
'description': re.sub(r'[^0-9a-zA-Z ]+', '', base_line['product'].display_name or '')[:250]
441+
'description': re.sub(r'[^0-9a-zA-Z ]+', '', base_line['name'] or base_line['product'].display_name or '')[:250]
440442
})
441443

442444
return {'lines': lines}
@@ -740,12 +742,15 @@ def _get_tbai_sequence_and_number(self):
740742
"""Get the TicketBAI sequence a number values for this invoice."""
741743
self.ensure_one()
742744

743-
sequence = self.sequence_prefix.rstrip('/')
745+
matching = list(re.finditer(r'\d+', self.name))[-1]
746+
sequence_prefix = self.name[:matching.start()]
747+
sequence_number = int(matching.group())
744748

745749
# NOTE non-decimal characters should not appear in the number
746-
seq_length = self._get_sequence_format_param(self.name)[1]['seq_length']
747-
number = f"{self.sequence_number:0{seq_length}d}"
750+
seq_length = self.env['sequence.mixin']._get_sequence_format_param(self.name)[1]['seq_length']
751+
number = f"{sequence_number:0{seq_length}d}"
748752

753+
sequence = sequence_prefix.rstrip('/')
749754
sequence = re.sub(r"[^0-9A-Za-z.\_\-\/]+", "", sequence) # remove forbidden characters
750755
sequence = re.sub(r"\s+", " ", sequence) # no more than one consecutive whitespace allowed
751756
# NOTE (optional) not recommended to use chars out of ([0123456789ABCDEFGHJKLMNPQRSTUVXYZ.\_\-\/ ])

addons/l10n_es_edi_tbai/tests/test_edi_tbai_user_errors.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from unittest.mock import patch
22

3+
from odoo import Command
34
from odoo.exceptions import UserError
45
from odoo.tests import tagged
56

@@ -42,6 +43,33 @@ def test_no_company_vat(self):
4243

4344
self.assertEqual(str(e.exception), self.tbai_error_msg + "Please configure the Tax ID on your company for TicketBAI.")
4445

46+
def test_no_tax_on_line(self):
47+
invoice = self.env['account.move'].create({
48+
'move_type': 'out_invoice',
49+
'invoice_date': '2022-01-01',
50+
'partner_id': self.partner_a.id,
51+
'invoice_line_ids': [
52+
Command.create({
53+
'product_id': self.product_a.id,
54+
'price_unit': 1000.0,
55+
'quantity': 1,
56+
'tax_ids': self._get_tax_by_xml_id('s_iva21b').ids,
57+
}),
58+
Command.create({
59+
'product_id': self.product_b.id,
60+
'price_unit': 50.0,
61+
'quantity': 1,
62+
'tax_ids': False,
63+
}),
64+
],
65+
})
66+
invoice.action_post()
67+
68+
with self.assertRaises(UserError) as e:
69+
self._get_invoice_send_wizard(invoice).action_send_and_print()
70+
71+
self.assertEqual(str(e.exception), self.tbai_error_msg + "There should be at least one tax set on each line in order to send to TicketBAI.")
72+
4573
def test_pending_invoice(self):
4674
first_invoice = self._create_posted_invoice()
4775
first_invoice_send_wizard = self._get_invoice_send_wizard(first_invoice)

0 commit comments

Comments
 (0)