diff --git a/fs_attachment/models/ir_attachment.py b/fs_attachment/models/ir_attachment.py index 6bafc7dedb..bf8cdee3ae 100644 --- a/fs_attachment/models/ir_attachment.py +++ b/fs_attachment/models/ir_attachment.py @@ -253,6 +253,18 @@ def _storage(self): storage = super()._storage() return storage + @api.depends("store_fname", "db_datas") + def _compute_raw(self): + """Always expose raw payload as bytes. + + Some callers (e.g. account EDI helpers) slice the value returned by + ``raw`` and crash when it is ``False`` for 0-byte attachments. + """ + res = super()._compute_raw() + false_attachments = self.filtered(lambda att: not att.raw) + false_attachments.raw = b"" + return res + @api.model_create_multi def create(self, vals_list): """ @@ -697,9 +709,10 @@ def _move_attachment_to_store(self): self.ensure_one() _logger.info("inspecting attachment %s (%d)", self.name, self.id) fname = self.store_fname - storage = fname.partition("://")[0] - if self._is_storage_disabled(storage): - fname = False + if fname: + storage = fname.partition("://")[0] + if self._is_storage_disabled(storage): + fname = False if fname: # migrating from filesystem filestore # or from the old 'store_fname' without the bucket name diff --git a/fs_attachment/tests/test_fs_attachment.py b/fs_attachment/tests/test_fs_attachment.py index 22c186ecac..f52c3ec900 100644 --- a/fs_attachment/tests/test_fs_attachment.py +++ b/fs_attachment/tests/test_fs_attachment.py @@ -75,6 +75,12 @@ def test_create_attachment_with_meaningful_name(self): with attachment.open("rb") as f: self.assertEqual(f.read(), new_content) + def test_create_attachment_with_no_payload_has_bytes_raw(self): + attachment = self.ir_attachment_model.create({"name": "empty.txt"}) + + self.assertEqual(attachment.raw, b"") + self.assertEqual(attachment.file_size, 0) + def test_open_attachment_in_db(self): self.env["ir.config_parameter"].sudo().set_param("ir_attachment.location", "db") content = b"This is a test attachment in db"