123 lines
5.0 KiB
Python
123 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import base64
|
|
import io
|
|
import logging
|
|
from collections import defaultdict
|
|
|
|
from odoo import models, api, fields
|
|
from odoo.tools.pdf import OdooPdfFileReader, OdooPdfFileWriter
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class IrAttachment(models.Model):
|
|
_inherit = 'ir.attachment'
|
|
|
|
document_ids = fields.One2many('documents.document', 'attachment_id', export_string_translation=False)
|
|
|
|
def get_documents_operation_add_destination(self):
|
|
self.ensure_one()
|
|
return {'destination': 'MY', 'display_name': self.env._('My Drive')}
|
|
|
|
@api.model
|
|
def _pdf_split(self, new_files=None, open_files=None):
|
|
"""Creates and returns new pdf attachments based on existing data.
|
|
|
|
:param new_files: the array that represents the new pdf
|
|
structure::
|
|
|
|
[{
|
|
'name': 'New File Name',
|
|
'new_pages': [{
|
|
'old_file_index': 7,
|
|
'old_page_number': 5,
|
|
}],
|
|
}]
|
|
:param open_files: array of open file objects.
|
|
:returns: the new PDF attachments
|
|
"""
|
|
vals_list = []
|
|
pdf_from_files = [OdooPdfFileReader(open_file, strict=False) for open_file in open_files]
|
|
|
|
for new_file in new_files:
|
|
output = OdooPdfFileWriter()
|
|
used_pages_by_pdf = defaultdict(set)
|
|
for page in new_file['new_pages']:
|
|
file_index = int(page['old_file_index'])
|
|
page_index = page['old_page_number'] - 1
|
|
input_pdf = pdf_from_files[file_index]
|
|
output.addPage(input_pdf.getPage(page_index))
|
|
used_pages_by_pdf[file_index].add(page_index)
|
|
if len(used_pages_by_pdf[file_index]) != input_pdf.getNumPages():
|
|
continue
|
|
try:
|
|
for fname, fcontent in input_pdf.getAttachments():
|
|
output.addAttachment(name=fname, data=fcontent)
|
|
except Exception: # noqa: BLE001
|
|
_logger.warning(
|
|
'Impossible to add (all) attachments from pdf at index %i',
|
|
file_index, exc_info=True,
|
|
)
|
|
with io.BytesIO() as stream:
|
|
output.write(stream)
|
|
vals_list.append({
|
|
'name': new_file['name'] + ".pdf",
|
|
'datas': base64.b64encode(stream.getvalue()),
|
|
})
|
|
return self.create(vals_list)
|
|
|
|
def _create_document(self, vals):
|
|
"""
|
|
Implemented by bridge modules that create new documents if attachments are linked to
|
|
their business models.
|
|
|
|
:param vals: the create/write dictionary of ir attachment
|
|
:return: True if new documents are created
|
|
"""
|
|
# Special case for documents
|
|
if vals.get('res_model') == 'documents.document' and vals.get('res_id'):
|
|
document = self.env['documents.document'].search_fetch(
|
|
[('id', '=', vals['res_id'])], [])
|
|
if document and not document.attachment_id and document.type == 'binary':
|
|
document.attachment_id = self[0].id
|
|
return False
|
|
|
|
# Generic case for all other models
|
|
res_model = vals.get('res_model')
|
|
res_id = vals.get('res_id')
|
|
model = self.env.get(res_model)
|
|
if model is not None and res_id and issubclass(self.pool[res_model], self.pool['documents.mixin']):
|
|
vals_list = [
|
|
model.browse(res_id)._get_document_vals(attachment)
|
|
for attachment in self
|
|
if not attachment.res_field and model.browse(res_id)._check_create_documents()
|
|
]
|
|
vals_list = [vals for vals in vals_list if vals] # Remove empty values
|
|
self.env['documents.document'].create(vals_list)
|
|
return True
|
|
return False
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
attachments = super().create(vals_list)
|
|
for attachment, vals in zip(attachments, vals_list):
|
|
# the context can indicate that this new attachment is created from documents, and therefore
|
|
# doesn't need a new document to contain it.
|
|
if not self.env.context.get('no_document') and not attachment.res_field:
|
|
attachment.sudo()._create_document(dict(vals, res_model=attachment.res_model, res_id=attachment.res_id))
|
|
return attachments
|
|
|
|
def write(self, vals):
|
|
old_values = {
|
|
att.id: (att.res_model, att.res_id)
|
|
for att in self
|
|
} if 'res_model' in vals or 'res_id' in vals else {}
|
|
res = super().write(vals)
|
|
for attachment in self:
|
|
if (
|
|
old_values and old_values.get(attachment.id) != (attachment.res_model, attachment.res_id)
|
|
and not self.env.context.get('no_document') and not attachment.res_field
|
|
):
|
|
attachment.sudo()._create_document(dict(res_model=attachment.res_model, res_id=attachment.res_id))
|
|
return res
|