diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
-index cda29638..ca0193c3 100644
+index cda29638..d8c7282d 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -1694,7 +1694,9 @@ def test_form_multi_page_post_edit(pub):
@@ -26,7 +26,7 @@
editable.status = 'deleted_status_id'
workflow.store()
# go back to st1
-@@ -1710,6 +1712,13 @@ def test_form_multi_page_post_edit(pub):
+@@ -1710,6 +1712,27 @@ def test_form_multi_page_post_edit(pub):
resp = resp.forms[0].submit('submit')
resp = resp.follow()
assert formdef.data_class().get(data_id).status == 'wf-%s' % st1.id # stay on st1
@@ -37,11 +37,34 @@
+ assert logged_error.workflow_id == workflow.id
+ assert logged_error.status_id == st1.id
+ assert logged_error.status_item_id == editable.id
++ assert logged_error.occurences_count == 1
++
++ # do it again: increment logged_error.occurences_count
++ page = login(get_app(pub), username='foo', password='foo').get('/test/%s/' % data_id)
++ resp = page.forms[0].submit('button_editable')
++ resp = resp.follow()
++ resp.forms[0]['f1'] = 'foo3'
++ resp = resp.forms[0].submit('submit')
++ resp = resp.forms[0].submit('submit')
++ resp = resp.follow()
++ assert formdef.data_class().get(data_id).status == 'wf-%s' % st1.id # stay on st1
++ assert LoggedError.count() == 1
++ logged_error = LoggedError.select()[0]
++ assert logged_error.occurences_count == 2
def test_form_count_dispatching(pub):
user = create_user(pub)
+@@ -4359,7 +4382,7 @@ def test_logged_errors(pub):
+ assert LoggedError.count() == 1
+
+ error = LoggedError.get_on_index(
+- '34-12-zerodivisionerror-integer-division-or-modulo-by-zero', 'tech_id')
++ '34-12-None-None-zerodivisionerror-integer-division-or-modulo-by-zero', 'tech_id')
+ assert error.occurences_count == 2
+
+ assert len(LoggedError.get_ids_with_indexed_value('formdef_id', '34')) == 1
diff --git a/wcs/admin/logged_errors.py b/wcs/admin/logged_errors.py
-index c2373925..019f009f 100644
+index c2373925..4ddf1cdb 100644
--- a/wcs/admin/logged_errors.py
+++ b/wcs/admin/logged_errors.py
@@ -56,6 +56,19 @@ class LoggedErrorDirectory(Directory):
@@ -75,8 +98,19 @@
parts = (N_('Exception'), N_('Stack trace (most recent call first)'),
N_('Form'), N_('Cookies'), N_('Environment'))
current_part = None
+@@ -105,10 +122,6 @@ class LoggedErrorDirectory(Directory):
+ r += htmltext('
%s' % _('Acked'))
+ r += htmltext('%s') % _('Delete')
+ r += htmltext('')
+- if get_publisher().logger.error_email:
+- r += htmltext('')
+- r += _('This error has also been sent by email to %s.') % get_publisher().logger.error_email
+- r += htmltext('
')
+ return r.getvalue()
+
+ def ack(self):
diff --git a/wcs/logged_errors.py b/wcs/logged_errors.py
-index 39e568fb..50f932b2 100644
+index 39e568fb..4030d2b6 100644
--- a/wcs/logged_errors.py
+++ b/wcs/logged_errors.py
@@ -31,6 +31,8 @@ class LoggedError(XmlStorableObject):
@@ -88,7 +122,7 @@
traceback = None
occurences_count = 0
first_occurence_timestamp = None
-@@ -41,32 +43,43 @@ class LoggedError(XmlStorableObject):
+@@ -41,32 +43,41 @@ class LoggedError(XmlStorableObject):
XML_NODES = [
('summary', 'str'), ('traceback', 'str'),
('formdata_id', 'str'), ('formdef_id', 'str'), ('workflow_id', 'str'),
@@ -100,7 +134,7 @@
@classmethod
- def record(cls, error_summary, plain_error_msg, publisher):
-+ def record(cls, error_summary, plain_error_msg=None, formdata=None, formdata_id=None,
++ def record(cls, error_summary, plain_error_msg=None, formdata=None,
+ formdef=None, workflow=None, status=None, status_item=None):
error = cls()
error.summary = error_summary
@@ -116,11 +150,9 @@
+ error.formdata_id = str(formdata.id)
+ error.formdef_id = formdata.formdef.id
+ error.workflow_id = formdata.formdef.workflow.id
-+ else:
-+ error.formdata_id = str(formdata_id)
-+ if formdef:
-+ error.formdef_id = formdef.id
-+ error.workflow_id = formdef.workflow.id
++ elif formdef:
++ error.formdef_id = formdef.id
++ error.workflow_id = formdef.workflow.id
+
+ if not error.formdef_id:
# cannot attach error to formdef, don't record in journal, it will
@@ -144,7 +176,7 @@
error.first_occurence_timestamp = datetime.datetime.now()
error.id = '%s-%s' % (
-@@ -80,9 +93,26 @@ class LoggedError(XmlStorableObject):
+@@ -80,9 +91,27 @@ class LoggedError(XmlStorableObject):
error.latest_occurence_timestamp = datetime.datetime.now()
error.store()
@@ -161,7 +193,8 @@
+ # still be sent by email to administrators.
+ return
+ formdef = FormDef.get_by_urlname(formdef_urlname)
-+ cls.record(error_summary, plain_error_msg, formdata_id=formdata_id,
++ formdata = formdef.data_class().get(formdata_id, ignore_errors=True)
++ cls.record(error_summary, plain_error_msg, formdata=formdata,
+ formdef=formdef, workflow=formdef.workflow)
+
@property
@@ -172,7 +205,7 @@
def get_formdef(self):
return FormDef.get(self.formdef_id, ignore_errors=True)
-@@ -91,4 +121,26 @@ class LoggedError(XmlStorableObject):
+@@ -91,4 +120,26 @@ class LoggedError(XmlStorableObject):
return Workflow.get(self.workflow_id, ignore_errors=True)
def get_formdata(self):