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,37 @@ 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 download_template: the POD template object to render
1730+ :param download_url: the URL to encode in the QR/barcode
1731+ :return: PDF bytes, or empty string on failure
1732+ """
1733+ try :
1734+ download_template = api .portal .get ().templates .om .get ("download_barcode" )
1735+ download_url , _short_uid = get_file_download_url (uid , short_uid = get_suid_from_uuid (uid ))
1736+ helper_view = getMultiAdapter (
1737+ (self .context , self .context .REQUEST ),
1738+ name = "document_generation_helper_view" ,
1739+ )
1740+ helper_view .pod_template = download_template .UID ()
1741+ helper_view .output_format = "pdf"
1742+ gen_context = {
1743+ "context" : self .context ,
1744+ "portal" : api .portal .get (),
1745+ "view" : helper_view ,
1746+ "download_barcode" : generate_barcode (download_url ).read (),
1747+ "download_url" : download_url ,
1748+ "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1749+ "render_download_barcode" : True ,
1750+ }
1751+ template_file = NamedBlobFile (download_template .get_file ().data , filename = u"download_template.odt" )
1752+ return convert_odt (template_file , fmt = "pdf" , gen_context = gen_context )
1753+ except Exception as e :
1754+ logger .exception ("Could not render download template to PDF" )
1755+ return ""
1756+
17171757 def _create_pdf_file (self , orig_fobj , nbf , f_title , f_uid , file_index , session_file_uids ):
17181758 """Create a pdf version file.
17191759
@@ -1725,33 +1765,70 @@ def _create_pdf_file(self, orig_fobj, nbf, f_title, f_uid, file_index, session_f
17251765 :param session_file_uids: list to append created pdf file uids
17261766 :return: created pdf file object
17271767 """
1728- new_filename = u "{}.pdf" .format (f_title )
1768+ new_filename = "{}.pdf" .format (f_title )
17291769 if nbf .contentType == "application/pdf" :
17301770 pdf_file = orig_fobj
1771+ new_uid = uuid .uuid4 ().hex
1772+ download_page = self ._render_download_template_to_pdf (new_uid )
1773+ if download_page :
1774+ merged = merge_pdf (nbf .data , download_page )
1775+ file_object = NamedBlobFile (merged , filename = safe_unicode (new_filename ))
1776+ pdf_file = createContentInContainer (
1777+ self .context ,
1778+ orig_fobj .portal_type ,
1779+ title = safe_unicode (new_filename ),
1780+ file = file_object ,
1781+ content_category = orig_fobj .content_category ,
1782+ scan_id = orig_fobj .scan_id ,
1783+ conv_from_uid = f_uid ,
1784+ ** {"_plone.uuid" : new_uid }
1785+ )
1786+ annot = IAnnotations (pdf_file )
1787+ annot ["documentgenerator" ] = {"conv_from_uid" : f_uid }
1788+ pdf_file .to_sign = True
1789+ pdf_file .to_approve = False
1790+ pdf_file .approved = orig_fobj .approved
1791+ update_categorized_elements (
1792+ self .context ,
1793+ pdf_file ,
1794+ get_category_object (self .context , pdf_file .content_category ),
1795+ limited = True ,
1796+ sort = False ,
1797+ logging = True ,
1798+ )
17311799 elif nbf .contentType in get_allowed_omf_content_types (esign = True ):
17321800 gen_context = {}
17331801 new_uid = uuid .uuid4 ().hex
1734- download_url , s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
1802+ download_url , _s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
17351803 orig_template = get_original_template (orig_fobj )
1804+ doc_cb_download_added = False
17361805 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' )
1806+ helper_view = getMultiAdapter (
1807+ (self .context , self .context .REQUEST ), name = "document_generation_helper_view"
1808+ )
17391809 helper_view .pod_template = orig_template .UID ()
17401810 helper_view .output_format = "pdf"
17411811 gen_context = {"context" : self .context , "portal" : api .portal .get (), "view" : helper_view }
17421812 # update_dict_with_validation(gen_context, self._get_context_variables(pod_template),
17431813 # _("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" ]
1814+ merge_templates = [
1815+ dic ["template" ]
1816+ for dic in orig_template .merge_templates
1817+ if dic ["pod_context_name" ] == "doc_cb_download"
1818+ ]
17461819 if merge_templates :
17471820 download_template = uuidToObject (merge_templates [0 ])
17481821 if download_template :
17491822 gen_context ["doc_cb_download" ] = download_template
1823+ doc_cb_download_added = True
17501824 update_dict_with_validation (
17511825 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 },
1826+ {
1827+ "download_barcode" : generate_barcode (download_url ).read (),
1828+ "download_url" : download_url ,
1829+ "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1830+ "render_download_barcode" : True ,
1831+ },
17551832 _dg ("Error when merging 'download_barcode' in generation context" ),
17561833 )
17571834
@@ -1783,14 +1860,21 @@ def _create_pdf_file(self, orig_fobj, nbf, f_title, f_uid, file_index, session_f
17831860 sort = False ,
17841861 logging = True ,
17851862 )
1863+
1864+ # For non-ODT files (e.g. DOC, DOCX), the subtemplate cannot be merged during conversion.
1865+ # Render it to PDF separately and append it to the converted PDF.
1866+ if not doc_cb_download_added :
1867+ download_page = self ._render_download_template_to_pdf (new_uid )
1868+ if download_page :
1869+ merged = merge_pdf (pdf_file .file .data , download_page )
1870+ pdf_file .file = NamedBlobFile (merged , filename = pdf_file .file .filename )
1871+ Converter (pdf_file )() # Refresh pdf preview
17861872 else :
1787- raise NotImplementedError (
1788- "Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType )
1789- )
1873+ raise NotImplementedError ("Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType ))
17901874 pdf_uid = pdf_file .UID ()
17911875 self .pdf_files_uids [file_index ].append (pdf_uid )
17921876 # we rename the pdf filename to include pdf uid. So after the file is later consumed, we can retrieve object
1793- pdf_file .file .filename = u "{}__{}.pdf" .format (f_title , pdf_uid )
1877+ pdf_file .file .filename = "{}__{}.pdf" .format (f_title , pdf_uid )
17941878 session_file_uids .append (pdf_uid )
17951879
17961880 def add_mail_files_to_session (self ):
@@ -1856,21 +1940,28 @@ def add_mail_files_to_session(self):
18561940 signers .append ((signer , email , name , label ))
18571941 watcher_users = api .user .get_users (groupname = "esign_watchers" )
18581942 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 )
1943+ session_id , _session = add_files_to_session (
1944+ signers ,
1945+ session_file_uids ,
1946+ bool (self .context .seal ),
1947+ title = _ ("[ia.docs] Session {sign_id}" ),
1948+ watchers = watcher_emails ,
1949+ )
18621950 self .annot ["session_id" ] = session_id
18631951 session_len = len (session_file_uids )
18641952 if session_len > 1 :
1865- return True , _ ("${count} files added to session number ${session_id}" ,
1866- mapping = {"count" : session_len , "session_id" : session_id })
1953+ return True , _ (
1954+ "${count} files added to session number ${session_id}" ,
1955+ mapping = {"count" : session_len , "session_id" : session_id },
1956+ )
18671957 else :
1868- return True , _ ("${count} file added to session number ${session_id}" ,
1869- mapping = {"count" : session_len , "session_id" : session_id })
1958+ return True , _ (
1959+ "${count} file added to session number ${session_id}" ,
1960+ mapping = {"count" : session_len , "session_id" : session_id },
1961+ )
18701962
18711963
18721964class DmsCategorizedObjectInfoAdapter (CategorizedObjectInfoAdapter ):
1873-
18741965 def get_infos (self , category , limited = False ):
18751966 base_infos = super (DmsCategorizedObjectInfoAdapter , self ).get_infos (category , limited = limited )
18761967 base_infos ["scan_id" ] = getattr (self .obj , "scan_id" , None )
0 commit comments