Skip to content

Commit ff1131d

Browse files
committed
[IMP] l10n_it_edi: remove many2one ir.attachment field
This is part of a general change for all the many2one ir.attachment fields to binary in order to avoid security issues as the former would allow access to all ir.attachment records. In l10n_it_edi, we remove the l10n_it_edi_attachment_id and adapt the use of the existing l10n_it_edi_attachment_field, so only this binary field is used. The field l10n_it_edi_attachment_name is added, so it can be used in views. task-4771720 closes odoo#212726 Related: odoo/upgrade#7785 Signed-off-by: John Laterre (jol) <[email protected]>
1 parent ba5896d commit ff1131d

File tree

4 files changed

+51
-48
lines changed

4 files changed

+51
-48
lines changed

addons/l10n_it_edi/models/account_move.py

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Part of Odoo. See LICENSE file for full copyright and licensing details.
22

3-
from base64 import b64encode
3+
from base64 import b64encode, b64decode
44
from collections import defaultdict
55
from datetime import datetime
66
import logging
@@ -82,12 +82,7 @@ class AccountMove(models.Model):
8282
)
8383
l10n_it_edi_transaction = fields.Char(copy=False, string="FatturaPA Transaction")
8484
l10n_it_edi_attachment_file = fields.Binary(copy=False, attachment=True)
85-
l10n_it_edi_attachment_id = fields.Many2one(
86-
comodel_name='ir.attachment',
87-
string="FatturaPA Attachment",
88-
compute=lambda self: self._compute_linked_attachment_id('l10n_it_edi_attachment_id', 'l10n_it_edi_attachment_file'),
89-
depends=['l10n_it_edi_attachment_file'],
90-
)
85+
l10n_it_edi_attachment_name = fields.Char(string="FatturaPA Attachment")
9186
l10n_it_edi_proxy_mode = fields.Selection(related="company_id.l10n_it_edi_proxy_user_id.edi_mode", depends=['company_id'])
9287
l10n_it_edi_button_label = fields.Char(compute="_compute_l10n_it_edi_button_label")
9388
l10n_it_edi_is_self_invoice = fields.Boolean(compute="_compute_l10n_it_edi_is_self_invoice")
@@ -374,9 +369,10 @@ def action_l10n_it_edi_send(self):
374369
}
375370

376371
attachment_vals = self._l10n_it_edi_get_attachment_values(pdf_values=None)
377-
self.env['ir.attachment'].create(attachment_vals)
378-
self.invalidate_recordset(fnames=['l10n_it_edi_attachment_id', 'l10n_it_edi_attachment_file'])
379-
self.message_post(attachment_ids=self.l10n_it_edi_attachment_id.ids)
372+
self.l10n_it_edi_attachment_file = b64encode(attachment_vals['raw'])
373+
self.l10n_it_edi_attachment_name = attachment_vals['name']
374+
self.invalidate_recordset(fnames=['l10n_it_edi_attachment_name', 'l10n_it_edi_attachment_file'])
375+
self.message_post(attachments=[(self.l10n_it_edi_attachment_name, attachment_vals['raw'])])
380376
self._l10n_it_edi_send({self: attachment_vals})
381377
self.is_move_sent = True
382378

@@ -398,18 +394,18 @@ def _get_invoice_legal_documents(self, filetype, allow_fallback=False):
398394
# EXTENDS 'account'
399395
self.ensure_one()
400396
if filetype == 'fatturapa':
401-
if fatturapa_attachment := self.l10n_it_edi_attachment_id:
397+
if fatturapa_attachment := self.l10n_it_edi_attachment_file:
402398
return {
403-
'filename': fatturapa_attachment.name,
399+
'filename': self.l10n_it_edi_attachment_name,
404400
'filetype': 'xml',
405-
'content': fatturapa_attachment.raw,
401+
'content': b64decode(fatturapa_attachment),
406402
}
407403
return super()._get_invoice_legal_documents(filetype, allow_fallback=allow_fallback)
408404

409405
def get_extra_print_items(self):
410406
# EXTENDS 'account' - add possibility to download all FatturaPA XML files
411407
print_items = super().get_extra_print_items()
412-
if self.l10n_it_edi_attachment_id:
408+
if self.filtered('l10n_it_edi_attachment_file'):
413409
print_items.append({
414410
'key': 'download_xml_fatturapa',
415411
'description': _('XML FatturaPA'),
@@ -418,7 +414,7 @@ def get_extra_print_items(self):
418414
return print_items
419415

420416
def action_invoice_download_fatturapa(self):
421-
if invoices_with_fatturapa := self.filtered('l10n_it_edi_attachment_id'):
417+
if invoices_with_fatturapa := self.filtered('l10n_it_edi_attachment_file'):
422418
return {
423419
'type': 'ir.actions.act_url',
424420
'url': f'/account/download_invoice_documents/{",".join(map(str, invoices_with_fatturapa.ids))}/fatturapa',
@@ -1376,16 +1372,11 @@ def _l10n_it_edi_import_invoice(self, invoice, data, is_new):
13761372
})]
13771373

13781374
for element in tree.xpath('.//Allegati'):
1379-
attachment_64 = self.env['ir.attachment'].create({
1380-
'name': get_text(element, './/NomeAttachment'),
1381-
'datas': str.encode(get_text(element, './/Attachment')),
1382-
'type': 'binary',
1383-
'res_model': 'account.move',
1384-
'res_id': self.id,
1385-
})
1375+
self.l10n_it_edi_attachment_name = get_text(element, './/NomeAttachment')
1376+
self.l10n_it_edi_attachment_file = b64decode(get_text(element, './/Attachment'))
13861377
self.sudo().message_post(
13871378
body=(_("Attachment from XML")),
1388-
attachment_ids=[attachment_64.id],
1379+
attachments=[(self.l10n_it_edi_attachment_name, self.l10n_it_edi_attachment_file)],
13891380
)
13901381

13911382
for message in message_to_log:
@@ -1822,7 +1813,7 @@ def _l10n_it_edi_update_send_state(self):
18221813
proxy_user = self.company_id.l10n_it_edi_proxy_user_id
18231814
if proxy_user.edi_mode == 'demo':
18241815
for move in self:
1825-
filename = move.l10n_it_edi_attachment_id and move.l10n_it_edi_attachment_id.name or '???'
1816+
filename = move.l10n_it_edi_attachment_name or '???'
18261817
self._l10n_it_edi_write_send_state(
18271818
transformed_notification={
18281819
'l10n_it_edi_state': 'forwarded',
@@ -1916,8 +1907,8 @@ def _l10n_it_edi_transform_notification(self, parsed_notification):
19161907
filename = parsed_notification.get('filename')
19171908
errors = parsed_notification.get('errors', [])
19181909
date = parsed_notification.get('date', fields.Date.today())
1919-
if not filename and self.l10n_it_edi_attachment_id:
1920-
filename = self.l10n_it_edi_attachment_id.name
1910+
if not filename and self.l10n_it_edi_attachment_name:
1911+
filename = self.l10n_it_edi_attachment_name
19211912
outcome = parsed_notification.get('outcome', False)
19221913
if not outcome:
19231914
new_state = state_map.get(sdi_state, False)

addons/l10n_it_edi/models/account_move_send.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Part of Odoo. See LICENSE file for full copyright and licensing details.
22

33
from odoo import _, api, models
4+
import base64
45

56

67
class AccountMoveSend(models.AbstractModel):
@@ -53,13 +54,17 @@ def _get_alerts(self, moves, moves_data):
5354

5455
def _get_invoice_extra_attachments(self, invoice):
5556
# EXTENDS 'account'
56-
return super()._get_invoice_extra_attachments(invoice) + invoice.l10n_it_edi_attachment_id
57+
return super()._get_invoice_extra_attachments(invoice) + self.env['ir.attachment'].search([
58+
('res_model', '=', 'account.move'),
59+
('res_field', '=', 'l10n_it_edi_attachment_file'),
60+
('res_id', 'in', invoice.ids),
61+
])
5762

5863
def _hook_invoice_document_before_pdf_report_render(self, invoice, invoice_data):
5964
# EXTENDS 'account'
6065
super()._hook_invoice_document_before_pdf_report_render(invoice, invoice_data)
6166
if (
62-
('it_edi_send' in invoice_data['extra_edis'] and not invoice.l10n_it_edi_attachment_id)
67+
('it_edi_send' in invoice_data['extra_edis'] and not invoice.l10n_it_edi_attachment_file)
6368
or (invoice_data['invoice_edi_format'] == 'it_edi_xml' and invoice._l10n_it_edi_ready_for_xml_export())
6469
):
6570
if errors := invoice._l10n_it_edi_export_data_check():
@@ -74,7 +79,7 @@ def _hook_invoice_document_after_pdf_report_render(self, invoice, invoice_data):
7479
if (
7580
invoice_data.get('pdf_attachment_values')
7681
and (
77-
('it_edi_send' in invoice_data['extra_edis'] and not invoice.l10n_it_edi_attachment_id)
82+
('it_edi_send' in invoice_data['extra_edis'] and not invoice.l10n_it_edi_attachment_file)
7883
or (invoice_data['invoice_edi_format'] == 'it_edi_xml' and invoice._l10n_it_edi_ready_for_xml_export())
7984
)
8085
):
@@ -88,8 +93,8 @@ def _call_web_service_after_invoice_pdf_render(self, invoices_data):
8893
moves = self.env['account.move']
8994
for move, move_data in invoices_data.items():
9095
if 'it_edi_send' in move_data['extra_edis']:
91-
if attachment := move.l10n_it_edi_attachment_id:
92-
attachments_vals[move] = {'name': attachment.name, 'raw': attachment.raw}
96+
if attachment := move.l10n_it_edi_attachment_file:
97+
attachments_vals[move] = {'name': move.l10n_it_edi_attachment_name, 'raw': attachment}
9398
moves |= move
9499
elif edi_values := move_data.get('l10n_it_edi_values'):
95100
attachments_vals[move] = edi_values
@@ -100,12 +105,19 @@ def _link_invoice_documents(self, invoices_data):
100105
# EXTENDS 'account'
101106
super()._link_invoice_documents(invoices_data)
102107

103-
attachments_vals = [
104-
invoice_data.get('l10n_it_edi_values')
105-
for invoice_data in invoices_data.values()
106-
if invoice_data.get('l10n_it_edi_values')
107-
]
108-
if attachments_vals:
109-
attachments = self.env['ir.attachment'].sudo().create(attachments_vals)
110-
res_ids = attachments.mapped('res_id')
111-
self.env['account.move'].browse(res_ids).invalidate_recordset(fnames=['l10n_it_edi_attachment_id', 'l10n_it_edi_attachment_file'])
108+
move_ids_to_names = {}
109+
for move, data in invoices_data.items():
110+
if values := data.get('l10n_it_edi_values'):
111+
move.l10n_it_edi_attachment_file = base64.b64encode(values['raw'])
112+
move.l10n_it_edi_attachment_name = values['name']
113+
move.invalidate_recordset(fnames=['l10n_it_edi_attachment_name', 'l10n_it_edi_attachment_file'])
114+
move_ids_to_names[move.id] = values['name']
115+
116+
if move_ids_to_names:
117+
attachments = self.env['ir.attachment'].search([
118+
('res_model', '=', 'account.move'),
119+
('res_field', '=', 'l10n_it_edi_attachment_file'),
120+
('res_id', 'in', list(move_ids_to_names)),
121+
])
122+
for attachment in attachments:
123+
attachment.name = move_ids_to_names.get(attachment.res_id)

addons/l10n_it_edi/tests/test_account_move_send.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def _get_default_extra_edis(self, move):
4646
self.assertEqual((invoice1 + invoice2).mapped('sending_data'), [False, False])
4747
self.assertEqual(1, len(self.get_attachments(invoice1.id)))
4848
self.assertTrue(invoice1.invoice_pdf_report_id)
49-
self.assertFalse(invoice1.l10n_it_edi_attachment_id)
49+
self.assertFalse(invoice1.l10n_it_edi_attachment_file)
5050
self.assertFalse(invoice1.is_being_sent)
5151
self.assertEqual(1, len(self.get_attachments(invoice2.id)))
5252
self.assertTrue(invoice2.invoice_pdf_report_id)
53-
self.assertFalse(invoice2.l10n_it_edi_attachment_id)
53+
self.assertFalse(invoice2.l10n_it_edi_attachment_file)
5454
self.assertFalse(invoice2.is_being_sent)
5555

5656
def test_invoice_multi_with_l10n_it_edi_xml_export(self):
@@ -72,11 +72,11 @@ def _get_default_extra_edis(self, move):
7272
self.assertEqual((invoice1 + invoice2).mapped('sending_data'), [False, False])
7373
self.assertEqual(2, len(self.get_attachments(invoice1.id)))
7474
self.assertTrue(invoice1.invoice_pdf_report_id)
75-
self.assertTrue(invoice1.l10n_it_edi_attachment_id)
75+
self.assertTrue(invoice1.l10n_it_edi_attachment_file)
7676
self.assertFalse(invoice1.is_being_sent)
7777
self.assertEqual(2, len(self.get_attachments(invoice2.id)))
7878
self.assertTrue(invoice2.invoice_pdf_report_id)
79-
self.assertTrue(invoice2.l10n_it_edi_attachment_id)
79+
self.assertTrue(invoice2.l10n_it_edi_attachment_file)
8080
self.assertFalse(invoice2.is_being_sent)
8181

8282
def test_invoice_with_cig_or_cup_or_both(self):

addons/l10n_it_edi/views/l10n_it_view.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
<field name="arch" type="xml">
8484
<field name="status_in_payment" position="before">
8585
<field name="l10n_it_edi_transaction" optional="hide"/>
86-
<field name="l10n_it_edi_attachment_id" optional="hide"/>
86+
<field name="l10n_it_edi_attachment_name" optional="hide"/>
8787
<field name="l10n_it_edi_state" optional="hide"/>
8888
</field>
8989
</field>
@@ -96,7 +96,7 @@
9696
<field name="arch" type="xml">
9797
<xpath expr="//search/field[@name='journal_id']" position="after">
9898
<field name="l10n_it_edi_transaction" groups="base.group_no_one"/>
99-
<field name="l10n_it_edi_attachment_id" groups="base.group_no_one"/>
99+
<field name="l10n_it_edi_attachment_name" groups="base.group_no_one"/>
100100
<field name="l10n_it_edi_state" groups="base.group_no_one"/>
101101
</xpath>
102102
</field>
@@ -118,7 +118,6 @@
118118
</xpath>
119119
<xpath expr="//sheet" position="before">
120120
<field name="l10n_it_edi_is_self_invoice" invisible="1"/>
121-
<field name="l10n_it_edi_attachment_id" invisible="1"/>
122121
<div class="alert alert-warning" role="alert"
123122
invisible="not l10n_it_edi_header
124123
or state == 'draft'
@@ -147,8 +146,9 @@
147146
invisible="move_type not in ('out_invoice', 'out_refund', 'in_invoice', 'in_refund') or country_code != 'IT'">
148147
<group>
149148
<group>
149+
<field name="l10n_it_edi_attachment_name" invisible="1"/>
150150
<field name="l10n_it_edi_transaction" groups="base.group_no_one" readonly="1"/>
151-
<field name="l10n_it_edi_attachment_id" groups="base.group_no_one" readonly="1"/>
151+
<field name="l10n_it_edi_attachment_file" widget="binary" filename="l10n_it_edi_attachment_name" groups="base.group_no_one" readonly="1"/>
152152
<field name="l10n_it_stamp_duty" readonly="state != 'draft'"/>
153153
<field name="l10n_it_ddt_id" readonly="state != 'draft'" invisible="move_type not in ('out_invoice', 'out_refund')"/>
154154
<field name="l10n_it_document_type"

0 commit comments

Comments
 (0)