diff --git a/CHANGES.rst b/CHANGES.rst
index d138c967a..c123386d3 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -13,6 +13,11 @@ Changelog
[chris-adam]
- Considered seal when checking if a signer is defined on a sub/template.
[sgeulette]
+- Updated robotframework tests to include electronic signature (PARAF-166).
+ [chris-adam]
+- Fixed ``ConnectionStateError`` crash when rendering datagrid fields
+ in settings through robotframework tests (DMS-434).
+ [chris-adam]
3.1.5 (2026-06-19)
------------------
diff --git a/imio/dms/mail/browser/settings.py b/imio/dms/mail/browser/settings.py
index 5de790e26..897863d72 100644
--- a/imio/dms/mail/browser/settings.py
+++ b/imio/dms/mail/browser/settings.py
@@ -48,6 +48,7 @@
# from z3c.form.browser.radio import RadioFieldWidget
# from z3c.form.interfaces import WidgetActionExecutionError
from z3c.form.validator import NoInputData
+from ZODB.POSException import ConnectionStateError
from zope import schema
from zope.component import getUtility
from zope.globalrequest import getRequest
@@ -1245,7 +1246,32 @@ class SettingsEditForm(RegistryEditForm):
form.extends(RegistryEditForm)
schema = IImioDmsMailConfig
+ _datagrid_row_schemas = {
+ "mail_types": ITableListSchema,
+ "imail_fields": IIMFieldsSchema,
+ "imail_send_modes": ITableListSchema,
+ "iemail_routing": IRoutingSchema,
+ "iemail_state_set": IStateSetSchema,
+ "omail_types": ITableListSchema,
+ "omail_send_modes": ITableListSchema,
+ "omail_signer_substitutes": ISignerSubstituteSchema,
+ "omail_signer_rules": ISignerRuleSchema,
+ "omail_fields": IOMFieldsSchema,
+ }
+
+ def _heal_datagrid_value_types(self):
+ for name, row_schema in self._datagrid_row_schemas.items():
+ field = self.schema.get(name)
+ if field is None or getattr(field, "value_type", None) is None:
+ continue
+ try:
+ field.value_type.schema
+ except ConnectionStateError:
+ logger.warn("DMS-434: rebuilding stale datagrid value_type for %r", name)
+ field.value_type = DictRow(title=field.title, schema=row_schema, required=False)
+
def update(self):
+ self._heal_datagrid_value_types()
super(SettingsEditForm, self).update()
# !! groups are updated outside and after updateWidgets
# we will display unconfigured fields
diff --git a/imio/dms/mail/tests/robot/doc.robot b/imio/dms/mail/tests/robot/doc.robot
index e4883c580..20bfe845e 100644
--- a/imio/dms/mail/tests/robot/doc.robot
+++ b/imio/dms/mail/tests/robot/doc.robot
@@ -14,6 +14,8 @@ Suite Teardown Close all browsers
#${BROWSER} = GoogleChrome
${SELENIUM_RUN_ON_FAILURE} = Debug
+# Delay (seconds) added after each Selenium action. Override to watch a run, e.g. -v SELENIUM_SPEED:1.0
+${SELENIUM_SPEED} = 0.2
*** Test Cases ***
@@ -194,6 +196,7 @@ CE numerisation
Select from list by value id=form-widgets-original_mail_date-day 6
Select from list by value id=form-widgets-original_mail_date-month 6
Select from list by value id=form-widgets-original_mail_date-year 2012
+ Select checkbox id=form-widgets-send_modes-0
Capture and crop page screenshot doc/utilisation/2-2-1-edition-courrier-fini.png id=content
Click button id=form-buttons-save
Sleep 2
@@ -324,6 +327,7 @@ CS en réponse
Set field value ${UID} recipient_groups ['${DF}'] list
Set field value ${UID} assigned_user agent str
Set field value ${UID} external_reference_no 2017/ESB/00123 str
+ Set field value ${UID} send_modes ['post'] list
Go to ${PLONE_URL}/${im_path}/edit
Click button id=form-buttons-save
Fire transition ${UID} propose_to_n_plus_1
@@ -367,7 +371,7 @@ CS en réponse
Sleep 1
Wait until element is visible css=.DV-pageImage 10
Capture and crop page screenshot doc/utilisation/2-3-1-cs-3-ged-genere.png id=content
- ${note52} Add pointy note css=#fieldset-versions tr.selected td:nth-child(3) Édition externe position=top color=blue
+ ${note52} Add pointy note css=#fieldset-versions tr.selected a.apButtonAction_form_external_edit Édition externe position=top color=blue
Capture and crop page screenshot doc/utilisation/2-3-1-cs-3-ged-edition-externe.png css=#fieldset-versions table ${note52}
Remove element id=${note52}
Delete content /plone/${om_path}/012999900000001
@@ -392,10 +396,10 @@ CS en réponse
Sleep 1
Wait until element is visible css=.DV-pageImage 10
Capture and crop page screenshot doc/utilisation/2-3-1-cs-4-ged-genere-non-pub.png id=content
- ${note55} Add pointy note css=#fieldset-versions tr.selected td:nth-child(6) Publipostage position=top color=blue
+ ${note55} Add pointy note css=#fieldset-versions tr.selected a.apButtonAction_form_mailing Publipostage position=left color=blue
Capture and crop page screenshot doc/utilisation/2-3-1-cs-4-ged-publipostage.png css=#fieldset-versions table ${note55}
Remove element id=${note55}
- Click element css=#fieldset-versions tr.selected td:nth-child(6)
+ Click element css=#fieldset-versions tr.selected a.apButtonAction_form_mailing
Sleep 5
Go to ${PLONE_URL}/${om_path}
Sleep 1
@@ -488,8 +492,11 @@ CS nouveau
Click button id=form-buttons-save
# Set field value ${UID} email_body
Bonjour Monsieur,
Vous trouverez en pièce jointe un document concernant la réfection des trottoirs dans votre rue.
Cordialement
Fred Agent
Administration communale de Belleville
Limite de responsabilité: les informations contenues dans ce courrier électronique (annexes incluses) sont confidentielles et réservées à l'usage exclusif des destinataires repris ci-dessus. Si vous n'êtes pas le destinataire, soyez informé par la présente que vous ne pouvez ni divulguer, ni reproduire, ni faire usage de ces informations pour vous-même ou toute tierce personne. Si vous avez reçu ce courrier électronique par erreur, vous êtes prié d'en avertir immédiatement l'expéditeur et d'effacer le message e-mail de votre ordinateur.
text/html
# Go to ${PLONE_URL}/${om_path}
+ Set Window Size 1300 2200
Wait until element is visible css=#viewlet-below-content-body table.actionspanel-no-style-table 10
Capture and crop page screenshot doc/utilisation/2-3-4-cs-email-visualisation.png css=table.actionspanel-no-style-table id=fieldset-versions id=form-groups-email
+ # Restore window size
+ Set Window Size 1200 1920
# Click element css=input.apButtonAction_sendemail # not working on test env
CS depuis le scanner
@@ -1151,7 +1158,7 @@ Gestion modèles
Wait until element is visible form-widgets-merge_templates 10
Update element style css=#formfield-form-widgets-pod_portal_types display None
${note43} Add pointy note css=#form-widgets-merge_templates tbody tr:first-child td:nth-last-child(2) Ajouter ou supprimer des sous-modèles position=left color=blue
- ${note44} Add pointy note css=#form-widgets-merge_templates-4-widgets-template Choisir le sous-modèle à fusionner position=bottom color=blue
+ ${note44} Add pointy note css=#form-widgets-merge_templates tr.auto-append [id$=-widgets-template] Choisir le sous-modèle à fusionner position=bottom color=blue
Capture and crop page screenshot doc/utilisation/2-10-2-fusion-sous-modeles.png css=#form-widgets-merge_templates id=${note44}
Remove element id=${note43}
Remove element id=${note44}
@@ -1200,16 +1207,14 @@ Configuration
Click element id=fieldsetlegend-outgoingmail
Wait until element is visible id=formfield-form-widgets-outgoingmail_number 10
Capture and crop page screenshot doc/configuration/5-3-config-courrier-cs.png id=content
- # Erreur chargement page, voir https://support.imio.be/browse/DMS-434
- #Go to ${PLONE_URL}/@@imiodmsmail-settings
- #Wait until element is visible id=formfield-form-widgets-mail_types 10
- # TO DO MANUALLY
- #Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-ce.png id=content
- #Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-cs.png id=content
- #Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-contacts.png id=content
- #Go to ${PLONE_URL}/@@contact-plonegroup-settings
- #Wait until element is visible id=pg-orga-link 10
- #Capture and crop page screenshot doc/configuration/5-4-config-services.png id=content
+ Go to ${PLONE_URL}/@@imiodmsmail-settings
+ Wait until element is visible id=formfield-form-widgets-mail_types 10
+ Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-ce.png id=content
+ Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-cs.png id=content
+ Capture and crop page screenshot doc/configuration/5-3-config-courrier-2-contacts.png id=content
+ Go to ${PLONE_URL}/@@contact-plonegroup-settings
+ Wait until element is visible id=pg-orga-link 10
+ Capture and crop page screenshot doc/configuration/5-4-config-services.png id=content
# services
Go to ${PLONE_URL}/contacts/plonegroup-organization
Wait until element is visible css=table.suborganizations-listing 10
@@ -1379,6 +1384,168 @@ Annexes dossiers
Go to ${PLONE_URL}/folders/
Click Element css:.pretty_link_content.state-active
+Signature écrite
+# partie 2.13.1 Mise à la signature manuscrite
+ [TAGS] RUN2131
+ Activate esigning
+ Enable autologin as encodeur
+ Show connected user Jean Encodeur (service encodeur) 2-13-1-user-encodeur.png
+ ${om_path} = Add outgoing mail for signing Décision de voirie à signer manuellement
+ ${UID} = Path to uid /${PLONE_SITE_ID}/${om_path}
+ # Signataires : préremplis par les règles de signature (configuration administrateur) :
+ # Directeur Général (utilisateur "dirg") et Bourgmestre, tous deux SANS approbation et SANS
+ # signature électronique.
+ Wait until element is visible css=#viewlet-below-content-body table.actionspanel-no-style-table 10
+ Wait until element is visible id=form-groups-signing 10
+ ${note1} Add pointy note id=formfield-form-widgets-ISigningBehavior-signers Signataires (sans approbation) position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-1-signataires.png id=form-groups-signing ${note1}
+ Remove element id=${note1}
+ ${note2} Add pointy note id=formfield-form-widgets-ISigningBehavior-esign Signature électronique désactivée position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-1-signature-electronique-off.png id=form-groups-signing ${note2}
+ Remove element id=${note2}
+ # Génération d'un fichier ged depuis un modèle
+ Capture and crop page screenshot doc/utilisation/2-13-1-generation-modele.png css=#parent-fieldname-title span.pretty_link_content
+ ${TPL} = Path to uid /${PLONE_SITE_ID}/templates/om/main
+ Go to ${PLONE_URL}/${om_path}/persistent-document-generation?template_uid=${TPL}&output_format=odt
+ Sleep 2
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 1
+ Wait until element is visible css=.DV-pageImage 10
+ Capture and crop page screenshot doc/utilisation/2-13-1-courrier-genere.png id=content
+ # Mise à la signature manuscrite (état "to_be_signed").
+ # created -> to_be_validated (encodeur) -> to_be_signed (chef)
+ Fire transition ${UID} propose_to_n_plus_1
+ Enable autologin as chef
+ Fire transition ${UID} propose_to_be_signed
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=.DV-pageImage 10
+ Show connected user Michel Chef (responsable de service, n+1) 2-13-1-user-chef.png
+ Capture and crop page screenshot doc/utilisation/2-13-1-a-la-signature.png css=div.viewlet_workflowstate css=table.actionspanel-no-style-table
+ # Scan step not automatable in RF: auto-transition to sent requires physical scan.
+ ${note4} Add pointy note css=div.viewlet_workflowstate Numérisation du document signé (scan papier) puis envoi position=bottom color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-1-etape-numerisation.png css=div.viewlet_workflowstate ${note4}
+ Remove element id=${note4}
+
+Signature électronique
+# partie 2.13.2 Mise à l'approbation et signature électronique
+ [TAGS] RUN2132
+ Activate esigning
+ Enable autologin as encodeur
+ Show connected user Jean Encodeur (service encodeur) 2-13-2-user-encodeur.png
+ ${om_path} = Add outgoing mail for signing Décision de voirie à signer electroniquement
+ ${UID} = Path to uid /${PLONE_SITE_ID}/${om_path}
+ # Édition du panneau de signature. Les signataires (Directeur Général + Bourgmestre) ont été
+ # préremplis par la configuration administrateur (règles de signature).
+ Wait until element is visible css=#viewlet-below-content-body table.actionspanel-no-style-table 10
+ # Clic sur l'icône d'édition présente dans la légende du fieldset "Signature"
+ Wait until element is visible css=#form-groups-signing legend a[href*='/edit#fieldsetlegend-signing'] 10
+ ${note_edit} Add pointy note css=#form-groups-signing legend a[href*='/edit#fieldsetlegend-signing'] Icône d'édition du panneau de signature position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-icone-edition-signature.png id=form-groups-signing ${note_edit}
+ Remove element id=${note_edit}
+ Click element css=#form-groups-signing legend a[href*='/edit#fieldsetlegend-signing']
+ Sleep 0.5
+ Wait until element is visible id=fieldsetlegend-signing 10
+ Click element id=fieldsetlegend-signing
+ Sleep 0.5
+ ${note0} Add pointy note id=formfield-form-widgets-ISigningBehavior-signers Signataires préremplis par la configuration position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-signataires-preremplis.png id=fieldset-signing ${note0}
+ Remove element id=${note0}
+ # Approbation par lui-même pour chaque signataire (on décoche "Aucune approbation", on coche "Lui-même")
+ Unselect checkbox id=form-widgets-ISigningBehavior-signers-0-widgets-approvings-0
+ Select checkbox id=form-widgets-ISigningBehavior-signers-0-widgets-approvings-1
+ Unselect checkbox id=form-widgets-ISigningBehavior-signers-1-widgets-approvings-0
+ Select checkbox id=form-widgets-ISigningBehavior-signers-1-widgets-approvings-1
+ ${note1} Add pointy note id=formfield-form-widgets-ISigningBehavior-signers Approbation activée pour chaque signataire position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-approbation.png id=fieldset-signing ${note1}
+ Remove element id=${note1}
+ Select checkbox id=form-widgets-ISigningBehavior-esign-0
+ ${note2} Add pointy note id=formfield-form-widgets-ISigningBehavior-esign Signature électronique activée position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-signature-electronique-on.png id=fieldset-signing ${note2}
+ Remove element id=${note2}
+ Click button id=form-buttons-save
+ Wait until element is visible css=#viewlet-below-content-body table.actionspanel-no-style-table 10
+ ${TPL} = Path to uid /${PLONE_SITE_ID}/templates/om/main
+ Go to ${PLONE_URL}/${om_path}/persistent-document-generation?template_uid=${TPL}&output_format=odt
+ Sleep 2
+ # Mise à l'approbation : proposition au n+1 (par l'encodeur) puis passage à l'approbation (par le chef, n+1).
+ Fire transition ${UID} propose_to_n_plus_1
+ Enable autologin as chef
+ Fire transition ${UID} propose_to_approve
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=.DV-pageImage 10
+ Show connected user Michel Chef (responsable de service, n+1) 2-13-2-user-chef.png
+ Capture and crop page screenshot doc/utilisation/2-13-2-a-approuver.png css=div.viewlet_workflowstate id=fieldset-versions
+ # Approbation par le premier approbateur (Directeur Général / dirg)
+ Enable autologin as dirg
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=#fieldset-versions td.iconified-approved a.iconified-action.editable 10
+ Show connected user Maxime DG (Directeur Général, 1er approbateur) 2-13-2-user-dirg.png
+ # Mode lecture
+ Wait until element is visible css=.DV-pageImage 10
+ Wait until element is visible id=read_mode_icon 10
+ ${note_rm} Add pointy note id=read_mode_icon Bouton "mode lecture" pour afficher le document en plein écran position=bottom color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-icone-mode-lecture.png id=portal-globalnav ${note_rm}
+ Remove element id=${note_rm}
+ Click element id=read_mode_icon
+ Wait until element is visible css=body.read-mode 10
+ Sleep 1
+ Capture and crop page screenshot doc/utilisation/2-13-2-mode-lecture.png id=content
+ # Sortie du mode lecture
+ Click element id=read_mode_icon
+ Sleep 0.5
+ Delete Cookie dms_document_view
+ Add Cookie dv_zoom_size 500 path=/
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=#fieldset-versions td.iconified-approved a.iconified-action.editable 10
+ ${note3} Add pointy note css=#fieldset-versions td.iconified-approved a.iconified-action.editable Icône d'approbation position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-icone-approbation.png id=fieldset-versions ${note3}
+ Remove element id=${note3}
+ Click element css=#fieldset-versions td.iconified-approved a.iconified-action.editable
+ Sleep 1
+ # Approbation par le second approbateur (Bourgmestre)
+ Enable autologin as bourgmestre
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=#fieldset-versions td.iconified-approved a.iconified-action.editable 10
+ Show connected user Paul BM (Bourgmestre, 2e approbateur) 2-13-2-user-bourgmestre.png
+ Click element css=#fieldset-versions td.iconified-approved a.iconified-action.editable
+ Sleep 1
+ # Une session eSign a été créée à l'état "En création" ; le courrier passe automatiquement à la signature
+ Enable autologin as Manager
+ Set autologin username dirg
+ Go to ${PLONE_URL}/${om_path}
+ Sleep 0.5
+ Wait until element is visible css=span.state-title-draft 10
+ Show connected user Gestionnaire de signatures 2-13-2-user-gestionnaire.png
+ ${note4} Add pointy note css=span.state-title-draft Session eSign en cours de création position=bottom color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-session-en-creation.png id=session-info ${note4}
+ Remove element id=${note4}
+ Wait until page contains element css=#fieldset-versions a.version-link[title*=".pdf"] 10
+ ${note_pdf} Add pointy note css=#fieldset-versions a.version-link[title*=".pdf"] Un document PDF a été généré pour la signature position=top color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-pdf-genere-signature.png id=fieldset-versions ${note_pdf}
+ Remove element id=${note_pdf}
+ # Onglet Paraphéo
+ Wait until element is visible id=portaltab-parapheo 10
+ ${note5} Add pointy note id=portaltab-parapheo Onglet Paraphéo position=bottom color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-onglet-parapheo.png id=portal-globalnav ${note5}
+ Remove element id=${note5}
+ Click element id=portaltab-parapheo
+ Wait until element is visible css=img[onclick*="external-esign-session-create"] 10
+ # Resize the window to show the actions column
+ Set Window Size 2200 1920
+ Sleep 0.5
+ Wait until element is visible css=img[onclick*="external-esign-session-create"] 10
+ ${note6} Add pointy note css=img[onclick*="external-esign-session-create"] Bouton de création de session externe position=left color=blue
+ Capture and crop page screenshot doc/utilisation/2-13-2-creation-session-externe.png id=content ${note6}
+ Sleep 0.5
+ Remove element id=${note6}
+ # Restore window size
+ Set Window Size 1200 1920
+
Debug
[TAGS] DBG
Pass execution Only for debug purpose
@@ -1398,9 +1565,53 @@ Suite Setup
Set Window Size 1200 1920
Set Suite Variable ${CROP_MARGIN} 5
Set Selenium Implicit Wait 2
- Set Selenium Speed 0.2
+ Set Selenium Speed ${SELENIUM_SPEED}
Enable autologin as Manager
Set autologin username dirg
Go to ${PLONE_URL}/robot_init
+ Add Cookie dv_zoom_size 500 path=/
Disable autologin
# Pause
+
+Activate esigning
+ [Documentation] Active la signature/approbation électronique (profil singles).
+ ... N'est appelé que dans les tests 2.13.1 / 2.13.2 : pour tous les autres tests, la
+ ... signature reste désactivée.
+ Enable autologin as Manager
+ Set autologin username dirg
+ Apply profile step imio.dms.mail:singles imiodmsmail-activate-esigning
+ Disable autologin
+
+Show connected user
+ [Documentation] Display a top banner naming the currently connected user (so a video viewer
+ ... always knows who is acting), capture a screenshot, then remove the banner.
+ [Arguments] ${name} ${shot}
+ ${unote} Add main note Connecté en tant que : ${name}
+ Capture and crop page screenshot doc/utilisation/${shot} id=portal-top ${unote}
+ Remove element id=${unote}
+
+Add outgoing mail for signing
+ [Documentation] Create an outgoing mail (as the current user) filling every required field
+ ... (title, recipients, send_modes via UI ; treating_groups and sender).
+ ... Returns the mail relative path.
+ [Arguments] ${title}
+ Go to ${PLONE_URL}/outgoing-mail
+ Wait until element is visible newOMCreation 10
+ Click element newOMCreation
+ Wait until element is visible css=.template-dmsoutgoingmail #formfield-form-widgets-sender 10
+ Sleep 0.5
+ Create content type=person container=/${PLONE_SITE_ID}/contacts firstname=Dale lastname=Cooper zip_code=4000 city=Belleville street=Rue Moyenne number=1991 email=dale.cooper@twinpeaks.com
+ Input text name=form.widgets.IDublinCore.title ${title}
+ Input text name=form.widgets.recipients.widgets.query cooper
+ Wait until element is visible css=.ac_results:not([style*="display: none"]) 10
+ Click element css=.ac_results:not([style*="display: none"]) li
+ Select checkbox id=form-widgets-send_modes-0
+ Click button id=form-buttons-save
+ Wait until element is visible css=#viewlet-below-content-body table.actionspanel-no-style-table 10
+ ${om_path} = Get mail path ptype=dmsoutgoingmail title=${title}
+ ${UID} = Path to uid /${PLONE_SITE_ID}/${om_path}
+ ${TG} = Path to uid /${PLONE_SITE_ID}/contacts/plonegroup-organization/direction-generale/grh
+ Set field value ${UID} treating_groups ${TG} str
+ ${SENDER} = Path to uid /${PLONE_SITE_ID}/contacts/personnel-folder/agent/agent-grh
+ Set field value ${UID} sender ${SENDER} str
+ [Return] ${om_path}