Commit fdde9b45 authored by Jérome Perrin's avatar Jérome Perrin

Make Ingestion/Document scanner more customizable

In "Attach document" action of erp5_ingestion, the default publication section of attach document suggested in the dialog is defined by a type based script.

We could do the same for group, so that we have a script that is easier to customize for specific cases. One use case is for accounting transactions, the group is usually the group of the entity where the document is attached.

Also, we could enable type based script in document scanner dialog, which is very similar to attach document dialog, but it was not using the scripts.

Similarly, we introduce a script to suggest a title in document scanner.

Another difference between "Attach Document" and "Scan Document" is that the later had a "publication state" field, allowing user to choose a state for the created document. We extend this to "Attach Document" as well and introduce another customizable type based method to be able to configure a default value.

See merge request !1359
parents 2bd80a81 3639e25b
Pipeline #13847 failed with stage
if context.AccountingTransaction_isSourceView():
section_list = [
context.getSourceSectionValue(portal_type='Organisation'),
context.getDestinationSectionValue(portal_type='Organisation'),
]
else:
section_list = [
context.getDestinationSectionValue(portal_type='Organisation'),
context.getSourceSectionValue(portal_type='Organisation'),
]
for section in section_list:
if section is not None:
if section.getGroup():
return section.getGroup()
return context.Base_getPreferredAttachedDocumentGroup()
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>AccountingTransaction_getPreferredAttachedDocumentGroup</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -1551,6 +1551,71 @@ class TestDocument(TestDocumentMixin): ...@@ -1551,6 +1551,71 @@ class TestDocument(TestDocumentMixin):
self.tic() self.tic()
self.assertEqual('user supplied title', contributed_document.getTitle()) self.assertEqual('user supplied title', contributed_document.getTitle())
def test_Base_contribute_publication_state(self):
"""Test contributing and choosing the publication state
"""
person = self.portal.person_module.newContent(portal_type='Person')
contributed_document = person.Base_contribute(
publication_state=None,
# we use as_name, to prevent regular expression from detecting a
# reference during ingestion, so that we can upload multiple documents
# in one test.
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'draft')
contributed_document = person.Base_contribute(
publication_state='shared',
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'shared')
contributed_document = person.Base_contribute(
publication_state='released',
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'released')
def test_Base_contribute_publication_state_vs_finishIngestion_script(self):
"""Contribute dialog allow choosing a publication state, but there's
also a "finishIngestion" type based script that can be configured to
force change the state. If user selects a publication_state, the state is
changed before the finishIngestion can operate.
"""
createZODBPythonScript(
self.portal.portal_skins.custom,
'PDF_finishIngestion',
'',
'if context.getValidationState() == "draft":\n'
' context.publish()')
try:
person = self.portal.person_module.newContent(portal_type='Person')
contributed_document = person.Base_contribute(
publication_state='shared',
synchronous_metadata_discovery=True,
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'shared')
contributed_document.setReference(None)
self.tic()
contributed_document = person.Base_contribute(
publication_state='shared',
synchronous_metadata_discovery=False,
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'shared')
contributed_document.setReference(None)
contributed_document = person.Base_contribute(
publication_state=None,
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'published')
finally:
self.portal.portal_skins.custom.manage_delObjects(ids=['PDF_finishIngestion'])
self.commit()
def test_HTML_to_ODT_conversion_keep_enconding(self): def test_HTML_to_ODT_conversion_keep_enconding(self):
"""This test perform an PDF conversion of HTML content """This test perform an PDF conversion of HTML content
then to plain text. then to plain text.
......
# customizable type based script returning a default title to use for
# scanned documents
return ''
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getPreferredScannedDocumentTitle</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -11,13 +11,10 @@ pdf_data_list = context.Base_getTempImageList(active_process, image_list) ...@@ -11,13 +11,10 @@ pdf_data_list = context.Base_getTempImageList(active_process, image_list)
pdf_data = context.ERP5Site_mergePDFList(pdf_data_list=pdf_data_list) pdf_data = context.ERP5Site_mergePDFList(pdf_data_list=pdf_data_list)
file_object = StringIOWithFileName(pdf_data) file_object = StringIOWithFileName(pdf_data)
doc = context.Base_contribute(file=file_object, context.Base_contribute(
file=file_object,
batch_mode=True, batch_mode=True,
redirect_to_document=False, redirect_to_document=False,
follow_up_list=[context.getRelativeUrl(),], follow_up_list=[context.getRelativeUrl(),],
publication_state=publication_state,
**kw) **kw)
if publication_state == "shared":
doc.share()
elif publication_state == "released":
doc.release()
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: context.getProperty(\'group\') or context.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue() is not None and here.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue().getGroup() or \'\'</string> </value> <value> <string>python: context.getTypeBasedMethod(\'getPreferredAttachedDocumentGroup\')()</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>default</string>
<string>title</string> <string>title</string>
</list> </list>
</value> </value>
...@@ -52,6 +53,12 @@ ...@@ -52,6 +53,12 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -75,6 +82,10 @@ ...@@ -75,6 +82,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_category</string> </value> <value> <string>my_dialog_mode_category</string> </value>
...@@ -97,4 +108,17 @@ ...@@ -97,4 +108,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.getTypeBasedMethod(\'getPreferredAttachedDocumentPublicationSection\')()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>default</string>
<string>items</string> <string>items</string>
<string>title</string> <string>title</string>
</list> </list>
...@@ -53,6 +54,12 @@ ...@@ -53,6 +54,12 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -64,7 +71,7 @@ ...@@ -64,7 +71,7 @@
<item> <item>
<key> <string>items</string> </key> <key> <string>items</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
<item> <item>
...@@ -82,6 +89,10 @@ ...@@ -82,6 +89,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_category</string> </value> <value> <string>my_dialog_mode_category</string> </value>
...@@ -111,6 +122,19 @@ ...@@ -111,6 +122,19 @@
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.getTypeBasedMethod(\'getPreferredAttachedDocumentPublicationState\')()</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/> <global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle> </pickle>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
<key> <string>delegated_list</string> </key> <key> <string>delegated_list</string> </key>
<value> <value>
<list> <list>
<string>default</string>
<string>display_width</string> <string>display_width</string>
</list> </list>
</value> </value>
...@@ -52,6 +53,16 @@ ...@@ -52,6 +53,16 @@
<key> <string>tales</string> </key> <key> <string>tales</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>display_width</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>field_id</string> </key> <key> <string>field_id</string> </key>
<value> <string></string> </value> <value> <string></string> </value>
...@@ -71,6 +82,10 @@ ...@@ -71,6 +82,10 @@
<key> <string>values</string> </key> <key> <string>values</string> </key>
<value> <value>
<dictionary> <dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item> <item>
<key> <string>display_width</string> </key> <key> <string>display_width</string> </key>
<value> <int>40</int> </value> <value> <int>40</int> </value>
...@@ -93,4 +108,17 @@ ...@@ -93,4 +108,17 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.getTypeBasedMethod(\'getPreferredScannedDocumentTitle\')()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData> </ZopeData>
...@@ -70,6 +70,12 @@ else: ...@@ -70,6 +70,12 @@ else:
document_kw.update({'file': file}) document_kw.update({'file': file})
document = portal_contributions.newContent(**document_kw) document = portal_contributions.newContent(**document_kw)
if document.getValidationState() == 'draft':
if publication_state == "shared":
document.share()
elif publication_state == "released":
document.release()
is_existing_document_updated = False is_existing_document_updated = False
if synchronous_metadata_discovery: if synchronous_metadata_discovery:
# we need to do all synchronously, in other case portal_contributions will do # we need to do all synchronously, in other case portal_contributions will do
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>file=None, url=None, portal_type=None, classification=None, synchronous_metadata_discovery=None, redirect_to_document=None, attach_document_to_context=False, use_context_for_container=False, redirect_url=None, redirect_to_context=False, cancel_url=None, batch_mode=False, max_repeat=0, editable_mode = 1, follow_up_list=None, user_login=None, group=None, publication_section=None, **kw</string> </value> <value> <string>file=None, url=None, portal_type=None, classification=None, synchronous_metadata_discovery=None, redirect_to_document=None, attach_document_to_context=False, use_context_for_container=False, redirect_url=None, redirect_to_context=False, cancel_url=None, batch_mode=False, max_repeat=0, editable_mode=1, follow_up_list=None, user_login=None, group=None, publication_section=None, publication_state=None,**kw</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
"""
Return the default group relative url to be added in the
document uploaded when attaching document using Base_viewNewFileDialog
"""
portal = context.getPortalObject()
group = context.getProperty('group')
if not group:
user = portal.portal_membership.getAuthenticatedMember().getUserValue()
if user is not None:
group = user.getGroup()
return group
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getPreferredAttachedDocumentGroup</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""Returns the default publication state to change state of the document uploaded
attaching document using Base_viewNewFileDialog
"""
return ''
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getPreferredAttachedDocumentPublicationState</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
<string>your_attach_document_to_context</string> <string>your_attach_document_to_context</string>
<string>your_group</string> <string>your_group</string>
<string>your_publication_section</string> <string>your_publication_section</string>
<string>your_publication_state</string>
</list> </list>
</value> </value>
</item> </item>
......
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: context.getProperty(\'group\') or context.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue() is not None and here.getPortalObject().portal_membership.getAuthenticatedMember().getUserValue().getGroup() or \'\'</string> </value> <value> <string>python: context.getTypeBasedMethod(\'getPreferredAttachedDocumentGroup\')()</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ProxyField" module="Products.ERP5Form.ProxyField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>delegated_list</string> </key>
<value>
<list>
<string>default</string>
<string>items</string>
<string>title</string>
</list>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>your_publication_state</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>field_id</string> </key>
<value> <string>my_dialog_mode_category</string> </value>
</item>
<item>
<key> <string>form_id</string> </key>
<value> <string>Base_viewFieldLibrary</string> </value>
</item>
<item>
<key> <string>items</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>target</string> </key>
<value> <string>Click to edit the target</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Publication State</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: context.getTypeBasedMethod(\'getPreferredAttachedDocumentPublicationState\')()</string> </value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="TALESMethod" module="Products.Formulator.TALESField"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_text</string> </key>
<value> <string>python: [("", ""),] + [(here.Base_translateString(x), y) for x,y in [("Draft", "draft"), ("Shared", "shared"), ("Released", "released"),]]</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment