from odoo import models import mimetypes import base64 import io import zipfile class IrAttachment(models.Model): _inherit = "ir.attachment" def _detect_mimetype(self, datas): # direct copy of the above function try: raw = base64.b64decode(datas) except: return "application/octet-stream" # office zip check if raw.startswith(b"PK"): try: z = zipfile.ZipFile(io.BytesIO(raw)) names = z.namelist() if "ppt/presentation.xml" in names: return "application/vnd.openxmlformats-officedocument.presentationml.presentation" if "word/document.xml" in names: return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" if "xl/workbook.xml" in names: return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" return "application/zip" except: pass if raw.startswith(b"%PDF-"): return "application/pdf" return "application/octet-stream" def _get_extension_from_mimetype(self, mimetype): mapping = { "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx", "application/vnd.openxmlformats-officedocument.presentationml.presentation": ".pptx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ".xlsx", "application/pdf": ".pdf", "application/zip": ".zip", } return mapping.get(mimetype, False) def write(self, vals): res = super().write(vals) # ---------------------------------------------------- # 1) Fix incorrect mimetype (ex: .pptx → zip) # ---------------------------------------------------- if "datas" in vals or "mimetype" in vals: for rec in self: datas = vals.get("datas", rec.datas) mimetype = self._detect_mimetype(datas) # Update mimetype if wrong if mimetype != rec.mimetype: rec.sudo().write({"mimetype": mimetype}) # ---------------------------------------------------- # 2) Fix the filename extension based on correct mimetype # ---------------------------------------------------- # Detect extension from mimetype correct_ext = self._get_extension_from_mimetype(mimetype) or ".bin" filename = rec.name or "" current_ext = "" if "." in filename: current_ext = "." + filename.split(".")[-1].lower() # CASE 1: No filename or no extension if not filename or "." not in filename: new_name = f"{rec.res_field or 'file'}_{rec.id}{correct_ext}" rec.sudo().write({"name": new_name}) # CASE 2: Wrong extension → Replace it elif current_ext != correct_ext: base = filename.rsplit(".", 1)[0] new_name = f"{base}{correct_ext}" rec.sudo().write({"name": new_name}) return res