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,75 @@ 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+
1769+ def update_esign_attributes (pdf_file , orig_fobj ):
1770+ """Set required attributes on a newly created PDF file object."""
1771+ pdf_file .to_sign = True
1772+ pdf_file .to_approve = False
1773+ pdf_file .approved = orig_fobj .approved
1774+ update_categorized_elements (
1775+ self .context ,
1776+ pdf_file ,
1777+ get_category_object (self .context , pdf_file .content_category ),
1778+ limited = True ,
1779+ sort = False ,
1780+ logging = True ,
1781+ )
1782+
1783+ new_filename = "{}.pdf" .format (f_title )
17291784 if nbf .contentType == "application/pdf" :
17301785 pdf_file = orig_fobj
1786+ new_uid = uuid .uuid4 ().hex
1787+ download_page = self ._render_download_template_to_pdf (new_uid )
1788+ if download_page :
1789+ merged = merge_pdf (nbf .data , download_page )
1790+ file_object = NamedBlobFile (merged , filename = safe_unicode (new_filename ))
1791+ pdf_file = createContentInContainer (
1792+ self .context ,
1793+ orig_fobj .portal_type ,
1794+ title = safe_unicode (new_filename ),
1795+ file = file_object ,
1796+ content_category = orig_fobj .content_category ,
1797+ scan_id = orig_fobj .scan_id ,
1798+ conv_from_uid = f_uid ,
1799+ ** {"_plone.uuid" : new_uid }
1800+ )
1801+ annot = IAnnotations (pdf_file )
1802+ annot ["documentgenerator" ] = {"conv_from_uid" : f_uid }
1803+ update_esign_attributes (pdf_file , orig_fobj )
17311804 elif nbf .contentType in get_allowed_omf_content_types (esign = True ):
17321805 gen_context = {}
17331806 new_uid = uuid .uuid4 ().hex
1734- download_url , s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
1807+ download_url , _s_uid = get_file_download_url (new_uid , short_uid = get_suid_from_uuid (new_uid ))
17351808 orig_template = get_original_template (orig_fobj )
1809+ doc_cb_download_added = False
17361810 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' )
1811+ helper_view = getMultiAdapter (
1812+ (self .context , self .context .REQUEST ), name = "document_generation_helper_view"
1813+ )
17391814 helper_view .pod_template = orig_template .UID ()
17401815 helper_view .output_format = "pdf"
17411816 gen_context = {"context" : self .context , "portal" : api .portal .get (), "view" : helper_view }
17421817 # update_dict_with_validation(gen_context, self._get_context_variables(pod_template),
17431818 # _("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" ]
1819+ merge_templates = [
1820+ dic ["template" ]
1821+ for dic in orig_template .merge_templates
1822+ if dic ["pod_context_name" ] == "doc_cb_download"
1823+ ]
17461824 if merge_templates :
17471825 download_template = uuidToObject (merge_templates [0 ])
17481826 if download_template :
17491827 gen_context ["doc_cb_download" ] = download_template
1828+ doc_cb_download_added = True
17501829 update_dict_with_validation (
17511830 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 },
1831+ {
1832+ "download_barcode" : generate_barcode (download_url ).read (),
1833+ "download_url" : download_url ,
1834+ "max_download_date" : get_max_download_date (None , adate = datetime .date .today ()),
1835+ "render_download_barcode" : True ,
1836+ },
17551837 _dg ("Error when merging 'download_barcode' in generation context" ),
17561838 )
17571839
@@ -1772,25 +1854,22 @@ def _create_pdf_file(self, orig_fobj, nbf, f_title, f_uid, file_index, session_f
17721854 gen_context = gen_context ,
17731855 )
17741856 # 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- )
1857+ update_esign_attributes (pdf_file , orig_fobj )
1858+
1859+ # For non-ODT files (e.g. DOC, DOCX), the subtemplate cannot be merged during conversion.
1860+ # Render it to PDF separately and append it to the converted PDF.
1861+ if not doc_cb_download_added :
1862+ download_page = self ._render_download_template_to_pdf (new_uid )
1863+ if download_page :
1864+ merged = merge_pdf (pdf_file .file .data , download_page )
1865+ pdf_file .file = NamedBlobFile (merged , filename = pdf_file .file .filename )
1866+ Converter (pdf_file )() # Refresh pdf preview
17861867 else :
1787- raise NotImplementedError (
1788- "Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType )
1789- )
1868+ raise NotImplementedError ("Cannot convert file of type '{}' to pdf for signing." .format (nbf .contentType ))
17901869 pdf_uid = pdf_file .UID ()
17911870 self .pdf_files_uids [file_index ].append (pdf_uid )
17921871 # 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 )
1872+ pdf_file .file .filename = "{}__{}.pdf" .format (f_title , pdf_uid )
17941873 session_file_uids .append (pdf_uid )
17951874
17961875 def add_mail_files_to_session (self ):
@@ -1856,21 +1935,28 @@ def add_mail_files_to_session(self):
18561935 signers .append ((signer , email , name , label ))
18571936 watcher_users = api .user .get_users (groupname = "esign_watchers" )
18581937 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 )
1938+ session_id , _session = add_files_to_session (
1939+ signers ,
1940+ session_file_uids ,
1941+ bool (self .context .seal ),
1942+ title = _ ("[ia.docs] Session {sign_id}" ),
1943+ watchers = watcher_emails ,
1944+ )
18621945 self .annot ["session_id" ] = session_id
18631946 session_len = len (session_file_uids )
18641947 if session_len > 1 :
1865- return True , _ ("${count} files added to session number ${session_id}" ,
1866- mapping = {"count" : session_len , "session_id" : session_id })
1948+ return True , _ (
1949+ "${count} files added to session number ${session_id}" ,
1950+ mapping = {"count" : session_len , "session_id" : session_id },
1951+ )
18671952 else :
1868- return True , _ ("${count} file added to session number ${session_id}" ,
1869- mapping = {"count" : session_len , "session_id" : session_id })
1953+ return True , _ (
1954+ "${count} file added to session number ${session_id}" ,
1955+ mapping = {"count" : session_len , "session_id" : session_id },
1956+ )
18701957
18711958
18721959class DmsCategorizedObjectInfoAdapter (CategorizedObjectInfoAdapter ):
1873-
18741960 def get_infos (self , category , limited = False ):
18751961 base_infos = super (DmsCategorizedObjectInfoAdapter , self ).get_infos (category , limited = limited )
18761962 base_infos ["scan_id" ] = getattr (self .obj , "scan_id" , None )
0 commit comments