123 lines
4.8 KiB
Python
123 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
# Part of the Fusion Plating product family.
|
|
|
|
import logging
|
|
|
|
from odoo import api, models
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
# Map of quality-module res_model -> bridge tag XML id.
|
|
# Kept module-level so both create() and write() can consult it cheaply.
|
|
_QUALITY_MODELS_TO_TAG = {
|
|
'fusion.plating.ncr': 'fusion_plating_bridge_documents.documents_tag_ncr',
|
|
'fusion.plating.capa': 'fusion_plating_bridge_documents.documents_tag_capa',
|
|
'fusion.plating.fair': 'fusion_plating_bridge_documents.documents_tag_fair',
|
|
'fusion.plating.doc.control': 'fusion_plating_bridge_documents.documents_tag_doc_control',
|
|
}
|
|
|
|
_FOLDER_XMLID = 'fusion_plating_bridge_documents.documents_folder_plating_quality'
|
|
|
|
|
|
class IrAttachment(models.Model):
|
|
"""Bridge ir.attachment with Odoo EE `documents.document`.
|
|
|
|
Whenever an attachment is created on one of the Fusion Plating QMS
|
|
record types (NCR, CAPA, FAIR, Doc Control) we silently mirror it as
|
|
a `documents.document` record inside the "Plating — Quality"
|
|
workspace, tagged with the corresponding record type. The original
|
|
`ir.attachment` record is untouched and continues to live on the
|
|
quality record as before — the bridge is purely additive.
|
|
|
|
Design notes
|
|
------------
|
|
* We resolve the folder and tag XML ids via ``env.ref`` with
|
|
``raise_if_not_found=False`` so that a partial install, a missing
|
|
demo record, or a future schema change can never break attachment
|
|
creation on a quality record — the worst case is that the
|
|
`documents.document` mirror record isn't created and a line goes
|
|
to the log.
|
|
* The write is wrapped in a broad try/except for the same reason:
|
|
user-facing attachment creation must never be blocked by a bridge
|
|
failure.
|
|
* We use ``sudo()`` on the `documents.document` create because the
|
|
user uploading the attachment may not have write access to the
|
|
Documents app — the bridge is a system-level convenience.
|
|
"""
|
|
_inherit = 'ir.attachment'
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
attachments = super().create(vals_list)
|
|
try:
|
|
self._fusion_plating_bridge_promote_to_documents(attachments)
|
|
except Exception: # pragma: no cover - defensive only
|
|
_logger.exception(
|
|
"Fusion Plating Documents bridge: failed to promote attachments %s",
|
|
attachments.ids,
|
|
)
|
|
return attachments
|
|
|
|
def _fusion_plating_bridge_promote_to_documents(self, attachments):
|
|
"""Create `documents.document` mirror records for quality attachments.
|
|
|
|
Silently skips if:
|
|
- the documents module isn't in the registry (defensive, the
|
|
manifest already depends on it but this module may be tested
|
|
on CE)
|
|
- the target folder hasn't been created yet
|
|
- the attachment is not attached to a quality record
|
|
"""
|
|
if 'documents.document' not in self.env:
|
|
return
|
|
|
|
folder = self.env.ref(_FOLDER_XMLID, raise_if_not_found=False)
|
|
if not folder:
|
|
_logger.warning(
|
|
"Fusion Plating Documents bridge: target folder %s not found",
|
|
_FOLDER_XMLID,
|
|
)
|
|
return
|
|
|
|
Document = self.env['documents.document'].sudo()
|
|
|
|
# Cache tag lookups across the batch so we don't hit env.ref per attachment.
|
|
tag_cache = {}
|
|
|
|
for att in attachments:
|
|
if att.res_model not in _QUALITY_MODELS_TO_TAG:
|
|
continue
|
|
# Skip attachments linked to a specific field (e.g. image_1920) —
|
|
# those are UI artefacts, not user-uploaded docs.
|
|
if att.res_field:
|
|
continue
|
|
# Skip records that have no concrete res_id (drafts being built).
|
|
if not att.res_id:
|
|
continue
|
|
|
|
tag_xmlid = _QUALITY_MODELS_TO_TAG[att.res_model]
|
|
if tag_xmlid not in tag_cache:
|
|
tag = self.env.ref(tag_xmlid, raise_if_not_found=False)
|
|
tag_cache[tag_xmlid] = tag.id if tag else False
|
|
tag_id = tag_cache[tag_xmlid]
|
|
|
|
doc_vals = {
|
|
'attachment_id': att.id,
|
|
'folder_id': folder.id,
|
|
'name': att.name or 'Untitled',
|
|
}
|
|
if tag_id:
|
|
doc_vals['tag_ids'] = [(4, tag_id)]
|
|
|
|
try:
|
|
Document.create(doc_vals)
|
|
except Exception: # pragma: no cover - defensive only
|
|
_logger.exception(
|
|
"Fusion Plating Documents bridge: could not create "
|
|
"documents.document for attachment id=%s (res_model=%s, res_id=%s)",
|
|
att.id, att.res_model, att.res_id,
|
|
)
|