1616from collective .dms .scanbehavior .behaviors .behaviors import IScanFields
1717from collective .documentgenerator import _ as _dg
1818from collective .documentgenerator .utils import convert_and_save_file
19+ from collective .documentgenerator .utils import convert_odt
1920from collective .documentgenerator .utils import get_original_template
2021from collective .documentgenerator .utils import odfsplit
2122from collective .documentgenerator .utils import update_dict_with_validation
23+ from collective .documentviewer .convert import Converter
2224from collective .iconifiedcategory .adapter import CategorizedObjectInfoAdapter
2325from collective .iconifiedcategory .utils import get_category_object
2426from collective .iconifiedcategory .utils import update_categorized_elements
5052from imio .helpers .content import uuidToCatalogBrain
5153from imio .helpers .content import uuidToObject
5254from imio .helpers .emailer import validate_email_address
55+ from imio .helpers .pdf import merge_pdf
5356from imio .helpers .workflow import do_transitions
5457from imio .pm .wsclient .interfaces import ISendableAnnexesToPM
5558from imio .prettylink .adapters import PrettyLinkAdapter
6164from plone .app .contentmenu .menu import FactoriesSubMenuItem as OrigFactoriesSubMenuItem
6265from plone .app .contentmenu .menu import WorkflowMenu as OrigWorkflowMenu
6366from plone .app .contenttypes .indexers import _unicode_save_string_concat
67+ from plone .dexterity .utils import createContentInContainer
6468from plone .indexer import indexer
6569from plone .namedfile .file import NamedBlobFile
6670from plone .registry .interfaces import IRegistry
@@ -1617,8 +1621,11 @@ def approve_file(self, afile, userid, values=None, transition=None, c_a=None):
16171621 message = _ (
16181622 u"The file '${file}' has been approved by ${user}. However, there is/are yet ${nb} files "
16191623 u"to approve on this mail." ,
1620- mapping = {"file" : safe_unicode (afile .Title ()), "user" : safe_unicode (fullname ),
1621- "nb" : len (yet_to_approve )},
1624+ mapping = {
1625+ "file" : safe_unicode (afile .Title ()),
1626+ "user" : safe_unicode (fullname ),
1627+ "nb" : len (yet_to_approve ),
1628+ },
16221629 ),
16231630 request = request ,
16241631 type = "info" ,
@@ -1635,8 +1642,10 @@ def approve_file(self, afile, userid, values=None, transition=None, c_a=None):
16351642 self .context .reindexObjectSecurity () # to update local roles from adapter
16361643 message += u"Next approval number is ${nb}."
16371644 api .portal .show_message (
1638- message = _ (message , mapping = {"file" : safe_unicode (afile .Title ()), "user" : safe_unicode (fullname ),
1639- "nb" : c_a + 1 }),
1645+ message = _ (
1646+ message ,
1647+ mapping = {"file" : safe_unicode (afile .Title ()), "user" : safe_unicode (fullname ), "nb" : c_a + 1 },
1648+ ),
16401649 request = request ,
16411650 type = "info" ,
16421651 )
@@ -1714,6 +1723,36 @@ def unapprove_file(self, afile, signer_userid):
17141723
17151724 self .start_approval_process ()
17161725
1726+ def _render_download_template_to_pdf (self , uid ):
1727+ """Render the download subtemplate (QR code page) to PDF bytes.
1728+
1729+ :param uid: uid of the document to generate the download link for
1730+ :return: PDF bytes, or empty string on failure
1731+ """
1732+ try :
1733+ download_template = api .portal .get ().templates .om .get ("download_barcode" )
1734+ download_url , _short_uid = get_file_download_url (uid , short_uid = get_suid_from_uuid (uid ))
1735+ helper_view = getMultiAdapter (
1736+ (self .context , self .context .REQUEST ),
1737+ name = "document_generation_helper_view" ,
1738+ )
1739+ helper_view .pod_template = download_template .UID ()
1740+ helper_view .output_format = "pdf"
1741+ gen_context = {
1742+ "context" : self .context ,
1743+ "portal" : api .portal .get (),
1744+ "view" : helper_view ,
1745+ "download_barcode" : generate_barcode (download_url ).read (),
1746+ "download_url" : download_url ,
1747+ "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1748+ "render_download_barcode" : True ,
1749+ }
1750+ template_file = NamedBlobFile (download_template .get_file ().data , filename = u"download_template.odt" )
1751+ return convert_odt (template_file , fmt = "pdf" , gen_context = gen_context )
1752+ except Exception :
1753+ logger .exception ("Could not render download template to PDF" )
1754+ return ""
1755+
17171756 def _create_pdf_file (self , orig_fobj , nbf , f_title , f_uid , file_index , session_file_uids ):
17181757 """Create a pdf version file.
17191758
@@ -1725,33 +1764,75 @@ def _create_pdf_file(self, orig_fobj, nbf, f_title, f_uid, file_index, session_f
17251764 :param session_file_uids: list to append created pdf file uids
17261765 :return: created pdf file object
17271766 """
1767+
1768+ def update_esign_attributes (pdf_file , orig_fobj ):
1769+ """Set required attributes on a newly created PDF file object."""
1770+ pdf_file .to_sign = True
1771+ pdf_file .to_approve = False
1772+ pdf_file .approved = orig_fobj .approved
1773+ update_categorized_elements (
1774+ self .context ,
1775+ pdf_file ,
1776+ get_category_object (self .context , pdf_file .content_category ),
1777+ limited = True ,
1778+ sort = False ,
1779+ logging = True ,
1780+ )
1781+
17281782 new_filename = u"{}.pdf" .format (f_title )
17291783 if nbf .contentType == "application/pdf" :
17301784 pdf_file = orig_fobj
1785+ new_uid = uuid .uuid4 ().hex
1786+ download_page = self ._render_download_template_to_pdf (new_uid )
1787+ if download_page :
1788+ merged = merge_pdf (nbf .data , download_page )
1789+ file_object = NamedBlobFile (merged , filename = safe_unicode (new_filename ))
1790+ pdf_file = createContentInContainer (
1791+ self .context ,
1792+ orig_fobj .portal_type ,
1793+ title = safe_unicode (new_filename ),
1794+ file = file_object ,
1795+ content_category = orig_fobj .content_category ,
1796+ scan_id = orig_fobj .scan_id ,
1797+ conv_from_uid = f_uid ,
1798+ ** {"_plone.uuid" : new_uid }
1799+ )
1800+ annot = IAnnotations (pdf_file )
1801+ annot ["documentgenerator" ] = {"conv_from_uid" : f_uid }
1802+ update_esign_attributes (pdf_file , orig_fobj )
17311803 elif nbf .contentType in get_allowed_omf_content_types (esign = True ):
17321804 gen_context = {}
17331805 new_uid = uuid .uuid4 ().hex
1734- download_url , s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
1806+ download_url , _s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
17351807 orig_template = get_original_template (orig_fobj )
1808+ doc_cb_download_added = False
17361809 if orig_template and nbf .contentType == "application/vnd.oasis.opendocument.text" : # own document
1737- helper_view = getMultiAdapter ((self .context , self .context .REQUEST ),
1738- name = 'document_generation_helper_view' )
1810+ helper_view = getMultiAdapter (
1811+ (self .context , self .context .REQUEST ), name = "document_generation_helper_view"
1812+ )
17391813 helper_view .pod_template = orig_template .UID ()
17401814 helper_view .output_format = "pdf"
17411815 gen_context = {"context" : self .context , "portal" : api .portal .get (), "view" : helper_view }
17421816 # update_dict_with_validation(gen_context, self._get_context_variables(pod_template),
17431817 # _("Error when merging context_variables in generation context"))
1744- merge_templates = [dic ["template" ] for dic in orig_template .merge_templates
1745- if dic ["pod_context_name" ] == "doc_cb_download" ]
1818+ merge_templates = [
1819+ dic ["template" ]
1820+ for dic in orig_template .merge_templates
1821+ if dic ["pod_context_name" ] == "doc_cb_download"
1822+ ]
17461823 if merge_templates :
17471824 download_template = uuidToObject (merge_templates [0 ])
17481825 if download_template :
17491826 gen_context ["doc_cb_download" ] = download_template
1827+ doc_cb_download_added = True
17501828 update_dict_with_validation (
17511829 gen_context ,
1752- {"download_barcode" : generate_barcode (download_url ).read (), "download_url" : download_url ,
1753- "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1754- "render_download_barcode" : True },
1830+ {
1831+ "download_barcode" : generate_barcode (download_url ).read (),
1832+ "download_url" : download_url ,
1833+ "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1834+ "render_download_barcode" : True ,
1835+ },
17551836 _dg ("Error when merging 'download_barcode' in generation context" ),
17561837 )
17571838
@@ -1772,21 +1853,18 @@ def _create_pdf_file(self, orig_fobj, nbf, f_title, f_uid, file_index, session_f
17721853 gen_context = gen_context ,
17731854 )
17741855 # we must set attribute after creation
1775- pdf_file .to_sign = True
1776- pdf_file .to_approve = False
1777- pdf_file .approved = orig_fobj .approved
1778- update_categorized_elements (
1779- self .context ,
1780- pdf_file ,
1781- get_category_object (self .context , pdf_file .content_category ),
1782- limited = True ,
1783- sort = False ,
1784- logging = True ,
1785- )
1856+ update_esign_attributes (pdf_file , orig_fobj )
1857+
1858+ # For non-ODT files (e.g. DOC, DOCX), the subtemplate cannot be merged during conversion.
1859+ # Render it to PDF separately and append it to the converted PDF.
1860+ if not doc_cb_download_added :
1861+ download_page = self ._render_download_template_to_pdf (new_uid )
1862+ if download_page :
1863+ merged = merge_pdf (pdf_file .file .data , download_page )
1864+ pdf_file .file = NamedBlobFile (merged , filename = pdf_file .file .filename )
1865+ Converter (pdf_file )() # Refresh pdf preview
17861866 else :
1787- raise NotImplementedError (
1788- "Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType )
1789- )
1867+ raise NotImplementedError ("Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType ))
17901868 pdf_uid = pdf_file .UID ()
17911869 self .pdf_files_uids [file_index ].append (pdf_uid )
17921870 # we rename the pdf filename to include pdf uid. So after the file is later consumed, we can retrieve object
@@ -1856,21 +1934,28 @@ def add_mail_files_to_session(self):
18561934 signers .append ((signer , email , name , label ))
18571935 watcher_users = api .user .get_users (groupname = "esign_watchers" )
18581936 watcher_emails = [user .getProperty ("email" ) for user in watcher_users ]
1859- session_id , session = add_files_to_session (signers , session_file_uids , bool (self .context .seal ),
1860- title = _ ("[ia.docs] Session {sign_id}" ),
1861- watchers = watcher_emails )
1937+ session_id , _session = add_files_to_session (
1938+ signers ,
1939+ session_file_uids ,
1940+ bool (self .context .seal ),
1941+ title = _ ("[ia.docs] Session {sign_id}" ),
1942+ watchers = watcher_emails ,
1943+ )
18621944 self .annot ["session_id" ] = session_id
18631945 session_len = len (session_file_uids )
18641946 if session_len > 1 :
1865- return True , _ ("${count} files added to session number ${session_id}" ,
1866- mapping = {"count" : session_len , "session_id" : session_id })
1947+ return True , _ (
1948+ "${count} files added to session number ${session_id}" ,
1949+ mapping = {"count" : session_len , "session_id" : session_id },
1950+ )
18671951 else :
1868- return True , _ ("${count} file added to session number ${session_id}" ,
1869- mapping = {"count" : session_len , "session_id" : session_id })
1952+ return True , _ (
1953+ "${count} file added to session number ${session_id}" ,
1954+ mapping = {"count" : session_len , "session_id" : session_id },
1955+ )
18701956
18711957
18721958class DmsCategorizedObjectInfoAdapter (CategorizedObjectInfoAdapter ):
1873-
18741959 def get_infos (self , category , limited = False ):
18751960 base_infos = super (DmsCategorizedObjectInfoAdapter , self ).get_infos (category , limited = limited )
18761961 base_infos ["scan_id" ] = getattr (self .obj , "scan_id" , None )
0 commit comments