[med-svn] [gnumed-client] 03/04: New upstream version 1.6.11+dfsg

Andreas Tille tille at debian.org
Thu Dec 29 07:31:03 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository gnumed-client.

commit 2cbc463bbca8250b41af1fce04e829c9fa98adbe
Author: Andreas Tille <tille at debian.org>
Date:   Thu Dec 29 08:07:39 2016 +0100

    New upstream version 1.6.11+dfsg
---
 client/CHANGELOG                            |  23 +++++
 client/business/gmClinNarrative.py          |  74 +++++++-------
 client/business/gmMedication.py             |  12 +--
 client/doc/schema/gnumed-entire_schema.html |   2 +-
 client/gnumed.py                            |   2 +-
 client/po/de-gnumed.mo                      | Bin 493408 -> 493483 bytes
 client/po/de.po                             |  21 ++--
 client/pycommon/gmNetworkTools.py           |   3 +-
 client/pycommon/gmPG2.py                    | 143 +++++++++++++++++++++-------
 client/wxpython/gmDocumentWidgets.py        |   2 +-
 client/wxpython/gmEMRStructWidgets.py       |   6 ++
 client/wxpython/gmEditArea.py               |   1 +
 client/wxpython/gmGuiMain.py                |   2 +-
 client/wxpython/gmMacro.py                  |   2 +
 client/wxpython/gmPatOverviewWidgets.py     |  40 ++++++--
 client/wxpython/gmSubstanceMgmtWidgets.py   |   2 +-
 external-tools/gm-create_datamatrix         |   1 -
 external-tools/gm-describe_file             |  15 ++-
 18 files changed, 251 insertions(+), 100 deletions(-)

diff --git a/client/CHANGELOG b/client/CHANGELOG
index 83eb9ab..dd89b01 100644
--- a/client/CHANGELOG
+++ b/client/CHANGELOG
@@ -6,6 +6,23 @@
 # rel-1-6-patches
 ------------------------------------------------
 
+	1.6.11
+
+IMPROVED: edit area refresh on first setting data
+IMPROVED: DB link error logging
+IMPROVED: suppressed hints display in patient overview
+IMPROVED: sorting of Hx items in patient overview
+IMPROVED: use of pdfinfo in gm-describe_file
+
+FIX: stall of gm-create_datamatrix in swap storm
+FIX: BMP creation without substance intakes
+FIX: missing quotes in BMP datafile [thanks Moritz]
+FIX: failure to sometimes store progress notes [thanks Marc]
+FIX: exception on double-clicking document tree label node
+FIX: exception on switching to drug database frontend [thanks a sk_SK]
+FIX: exception on saving hospital stay [thanks a sk_SK]
+FIX: exception on checking for upgrade [thanks Philipp]
+
 	1.6.10
 
 FIX: more faults with dynamic hint detection
@@ -1817,6 +1834,12 @@ FIX: missing cast to ::text in dem.date_trunc_utc() calls
 # gnumed_v21
 ------------------------------------------------
 
+	21.11
+
+IMPROVED: backup scripts error checking
+
+FIX: serialization failures due to table mod announcement triggers
+
 	21.10
 
 FIX: clin.get_hints_for_patient()
diff --git a/client/business/gmClinNarrative.py b/client/business/gmClinNarrative.py
index dbd5c78..008afbb 100644
--- a/client/business/gmClinNarrative.py
+++ b/client/business/gmClinNarrative.py
@@ -225,19 +225,46 @@ def create_narrative_item(narrative=None, soap_cat=None, episode_id=None, encoun
 		soap_cat - soap category
 		episode_id - episodes's primary key
 		encounter_id - encounter's primary key
-	"""
-	# any of the args being None (except soap_cat) should fail the SQL code
-
-	# sanity checks:
 
-	# 1) silently do not insert empty narrative
+		any of the args being None (except soap_cat) will fail the SQL code
+	"""
+	# silently do not insert empty narrative
 	narrative = narrative.strip()
 	if narrative == u'':
 		return None
 
-	# 2) also, silently do not insert true duplicates
-	# FIXME: this should check for .provider = current_user but
-	# FIXME: the view has provider mapped to their staff alias
+	args = {'enc': encounter_id, 'epi': episode_id, 'soap': soap_cat, 'narr': narrative}
+
+	# insert new narrative
+	# but, also silently, do not insert true duplicates
+	# this should check for .provider = current_user but
+	# the view has provider mapped to their staff alias
+	cmd = u"""
+		INSERT INTO clin.clin_narrative
+			(fk_encounter, fk_episode, narrative, soap_cat)
+		SELECT
+			%(enc)s, %(epi)s, %(narr)s, %(soap)s
+		WHERE NOT EXISTS (
+			SELECT 1 FROM clin.v_narrative
+			WHERE
+				pk_encounter = %(enc)s
+					AND
+				pk_episode = %(epi)s
+					AND
+				soap_cat = %(soap)s
+					AND
+				narrative = %(narr)s
+		)
+		RETURNING pk"""
+	rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
+	if len(rows) == 1:
+		# re-use same link_obj if given because when called from create_progress_note we won't yet see rows inside a new tx
+		return cNarrative(aPK_obj = rows[0]['pk'], link_obj = link_obj)
+
+	if len(rows) > 1:
+		raise Exception('more than one row returned from single-row INSERT')
+
+	# retrieve existing narrative
 	cmd = u"""
 		SELECT * FROM clin.v_narrative
 		WHERE
@@ -249,41 +276,16 @@ def create_narrative_item(narrative=None, soap_cat=None, episode_id=None, encoun
 				AND
 			narrative = %(narr)s
 	"""
-	args = {
-		'enc': encounter_id,
-		'epi': episode_id,
-		'soap': soap_cat,
-		'narr': narrative
-	}
 	rows, idx = gmPG2.run_ro_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
 	if len(rows) == 1:
-		narrative = cNarrative(row = {'pk_field': 'pk_narrative', 'data': rows[0], 'idx': idx})
-		return narrative
-
-	# insert new narrative
-	queries = [
-		{'cmd': u"""
-			INSERT INTO clin.clin_narrative
-				(fk_encounter, fk_episode, narrative, soap_cat)
-			VALUES
-				(%s, %s, %s, lower(%s))""",
-		 'args': [encounter_id, episode_id, narrative, soap_cat]
-		},
-		{'cmd': u"""
-			SELECT * FROM clin.v_narrative
-			WHERE
-				pk_narrative = currval(pg_get_serial_sequence('clin.clin_narrative', 'pk'))"""
-		}
-	]
-	rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, return_data = True, get_col_idx = True)
+		return cNarrative(row = {'pk_field': 'pk_narrative', 'data': rows[0], 'idx': idx})
 
-	narrative = cNarrative(row = {'pk_field': 'pk_narrative', 'idx': idx, 'data': rows[0]})
-	return narrative
+	raise Exception('retrieving known-to-exist narrative row returned 0 or >1 result: %s' % len(rows))
 
 #------------------------------------------------------------
 def delete_clin_narrative(narrative=None):
 	"""Deletes a clin.clin_narrative row by it's PK."""
-	cmd = u"delete from clin.clin_narrative where pk=%s"
+	cmd = u"DELETE FROM clin.clin_narrative WHERE pk=%s"
 	rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [narrative]}])
 	return True
 
diff --git a/client/business/gmMedication.py b/client/business/gmMedication.py
index 8a9940c..b15a02c 100644
--- a/client/business/gmMedication.py
+++ b/client/business/gmMedication.py
@@ -2984,9 +2984,9 @@ def generate_amts_data_template_definition_file(work_dir=None, strict=True):
  n="$<<range_of::$<praxis::%(praxis)s,%(branch)s::>$,$<current_provider::::>$::30>>$"
 $<praxis_address:: s="%(street)s"::>$
 $<praxis_address:: z="%(postcode)s"::>$
-$<praxis_address:: c="%(urb)s::>$
-$<praxis_comm::workphone// p="%(url)s::20>$
-$<praxis_comm::email// e="%(url)s::80>$
+$<praxis_address:: c="%(urb)s"::>$
+$<praxis_comm::workphone// p="%(url)s"::20>$
+$<praxis_comm::email// e="%(url)s"::80>$
  t="$<today::%Y%m%d::8>$"
 />
 <O ai="s.S.$<amts_total_pages::::1>$ unten"/>
@@ -3018,9 +3018,9 @@ def __generate_enhanced_amts_data_template_definition_file(work_dir=None):
  n="$<praxis::%(praxis)s,%(branch)s::>$,$<current_provider::::>$"
 $<praxis_address:: s="%(street)s %(number)s %(subunit)s"::>$
 $<praxis_address:: z="%(postcode)s"::>$
-$<praxis_address:: c="%(urb)s::>$
-$<praxis_comm::workphone// p="%(url)s::>$
-$<praxis_comm::email// e="%(url)s::>$
+$<praxis_address:: c="%(urb)s"::>$
+$<praxis_comm::workphone// p="%(url)s"::>$
+$<praxis_comm::email// e="%(url)s"::>$
  t="$<today::%Y%m%d::8>$"
 />
 <O ai="Seite 1 unten"/>
diff --git a/client/doc/schema/gnumed-entire_schema.html b/client/doc/schema/gnumed-entire_schema.html
index c6321db..26ae867 100644
--- a/client/doc/schema/gnumed-entire_schema.html
+++ b/client/doc/schema/gnumed-entire_schema.html
@@ -112,7 +112,7 @@
   <body>
 
     <!-- Primary Index -->
-	<p><br><br>Dumped on 2016-11-07</p>
+	<p><br><br>Dumped on 2016-12-19</p>
 <h1><a name="index">Index of database - gnumed_v21</a></h1>
 <ul>
     
diff --git a/client/gnumed.py b/client/gnumed.py
index f721e40..12b57af 100644
--- a/client/gnumed.py
+++ b/client/gnumed.py
@@ -91,7 +91,7 @@ against. Please run GNUmed as a non-root user.
 	sys.exit(1)
 
 #----------------------------------------------------------
-current_client_version = u'1.6.10'
+current_client_version = u'1.6.11'
 current_client_branch = u'1.6'
 
 _log = None
diff --git a/client/po/de-gnumed.mo b/client/po/de-gnumed.mo
index 185fc7f..b74352b 100644
Binary files a/client/po/de-gnumed.mo and b/client/po/de-gnumed.mo differ
diff --git a/client/po/de.po b/client/po/de.po
index 55e0396..55b879e 100644
--- a/client/po/de.po
+++ b/client/po/de.po
@@ -5,8 +5,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: GNUmed\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-09-02 08:48+0200\n"
-"PO-Revision-Date: 2016-08-18 22:42+0200\n"
+"POT-Creation-Date: 2016-12-11 13:20+0100\n"
+"PO-Revision-Date: 2016-12-11 13:22+0100\n"
 "Last-Translator: Karsten Hilbert <Karsten.Hilbert at gmx.net>\n"
 "Language-Team: Deutsch\n"
 "Language: de_DE\n"
@@ -14,7 +14,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: pygettext.py 1.3\n"
-"X-Generator: Poedit 1.8.8\n"
+"X-Generator: Poedit 1.8.11\n"
 
 #, python-format
 msgid "unknown test status [%s]"
@@ -10733,8 +10733,9 @@ msgstr "fällig seit %s: %s"
 msgid "due in %s%s"
 msgstr "fällig in %s%s"
 
-msgid "suppr'd:"
-msgstr "unterdr.:"
+#, python-format
+msgid "suppr'd (%s):"
+msgstr "unterdr (%s):"
 
 msgid "Suppressed hints:\n"
 msgstr "Unterdrückte Hinweise:\n"
@@ -10766,7 +10767,7 @@ msgstr "Derzeit %s-Mal in Warteliste"
 
 #, python-format
 msgid "first (in GMd): %s, %s"
-msgstr "erstmals (in Gmd): %s, %s"
+msgstr "Ersteintrag: %s, %s"
 
 #, python-format
 msgid "last: %s, %s"
@@ -11317,6 +11318,10 @@ msgstr "Texteingabe vom Benutzer abgebrochen."
 msgid "no bill selected"
 msgstr "keine Rechnung gewählt"
 
+#, python-format
+msgid "[%s] bill has no address"
+msgstr "[%s] Rechnung hat keine Adresse"
+
 msgid "attach rejected, already serving a client"
 msgstr "Verbindung abgewiesen, es besteht bereits eine andere"
 
@@ -16653,8 +16658,8 @@ msgstr "Meßergebnisse für den aktiven Patienten verwalten."
 msgid "&Vaccinations"
 msgstr "Impfungen"
 
-msgid "Add (a) vaccination(s) for the current patient."
-msgstr "Impfungen für den aktiven Patienten erfassen."
+msgid "Manage vaccinations for the current patient."
+msgstr "Impfungen für den aktiven Patienten verwalten."
 
 msgid "&Family history (FHx)"
 msgstr "&Familienanamnese"
diff --git a/client/pycommon/gmNetworkTools.py b/client/pycommon/gmNetworkTools.py
index 73a633d..6d36bd2 100644
--- a/client/pycommon/gmNetworkTools.py
+++ b/client/pycommon/gmNetworkTools.py
@@ -202,7 +202,8 @@ def check_for_update(url=None, current_branch=None, current_version=None, consid
 
 	try:
 		remote_file = wget.urlopen(url)
-	except (wget.URLError, ValueError, OSError):
+	except (wget.URLError, ValueError, OSError, IOError):
+		# IOError: socket.error
 		_log.exception("cannot retrieve version file from [%s]", url)
 		return (None, _('Cannot retrieve version information from:\n\n%s') % url)
 
diff --git a/client/pycommon/gmPG2.py b/client/pycommon/gmPG2.py
index acc0d09..38990dc 100644
--- a/client/pycommon/gmPG2.py
+++ b/client/pycommon/gmPG2.py
@@ -1492,6 +1492,59 @@ def sanitize_pg_regex(expression=None, escape_all=False):
 		#']', '\]',			# not needed
 
 #------------------------------------------------------------------------
+def capture_cursor_state(cursor=None):
+	conn = cursor.connection
+
+	tx_status = conn.get_transaction_status()
+	if tx_status in [ psycopg2.extensions.TRANSACTION_STATUS_INERROR, psycopg2.extensions.TRANSACTION_STATUS_UNKNOWN ]:
+		isolation_level = u'tx aborted or unknown, cannot retrieve'
+	else:
+		isolation_level = conn.isolation_level
+
+	txt = u"""Link state:
+Cursor
+  identity: %s; name: %s
+  closed: %s; scrollable: %s; with hold: %s; arraysize: %s; itersize: %s;
+  last rowcount: %s; rownumber: %s; lastrowid (OID): %s;
+  last description: %s
+  statusmessage: %s
+Connection
+  identity: %s; backend pid: %s; protocol version: %s;
+  closed: %s; autocommit: %s; isolation level: %s; encoding: %s; async: %s;
+  TX status: %s; CX status: %s; executing async op: %s;
+Query
+  %s
+""" % (
+		id(cursor),
+		cursor.name,
+		cursor.closed,
+		cursor.scrollable,
+		cursor.withhold,
+		cursor.arraysize,
+		cursor.itersize,
+		cursor.rowcount,
+		cursor.rownumber,
+		cursor.lastrowid,
+		cursor.description,
+		cursor.statusmessage,
+
+		id(conn),
+		conn.get_backend_pid(),
+		conn.protocol_version,
+		conn.closed,
+		conn.autocommit,
+		isolation_level,
+		conn.encoding,
+		conn.async,
+		tx_status,
+		conn.status,
+		conn.isexecuting(),
+
+		cursor.query,
+	)
+	return txt
+
+#------------------------------------------------------------------------
 def run_ro_queries(link_obj=None, queries=None, verbose=False, return_data=True, get_col_idx=False):
 	"""Run read-only queries.
 
@@ -1504,9 +1557,9 @@ def run_ro_queries(link_obj=None, queries=None, verbose=False, return_data=True,
 	"""
 	if isinstance(link_obj, dbapi._psycopg.cursor):
 		curs = link_obj
-		curs_close = __noop
-		tx_rollback = __noop
-		readonly_rollback_just_in_case = __noop
+		curs_close = lambda :1
+		tx_rollback = lambda :1
+		readonly_rollback_just_in_case = lambda :1
 	elif isinstance(link_obj, dbapi._psycopg.connection):
 		curs = link_obj.cursor()
 		curs_close = curs.close
@@ -1517,7 +1570,7 @@ def run_ro_queries(link_obj=None, queries=None, verbose=False, return_data=True,
 			# do not rollback readonly queries on passed-in readwrite
 			# connections just in case because they may have already
 			# seen fully legitimate write action which would get lost
-			readonly_rollback_just_in_case = __noop
+			readonly_rollback_just_in_case = lambda :1
 	elif link_obj is None:
 		conn = get_connection(readonly=True, verbose=verbose)
 		curs = conn.cursor()
@@ -1541,14 +1594,10 @@ def run_ro_queries(link_obj=None, queries=None, verbose=False, return_data=True,
 		try:
 			curs.execute(query['cmd'], args)
 			if verbose:
-				_log.debug('ran query: [%s]', curs.query)
-				if curs.statusmessage != u'':
-					_log.debug('PG status message: %s', curs.statusmessage)
-				_log.debug('cursor description: %s', str(curs.description))
+				_log.debug(capture_cursor_state(curs))
 		except dbapi.Error as pg_exc:
-			_log.error('query failed: [%s]', curs.query)
-			if curs.statusmessage != u'':
-				_log.error('PG status message: %s', curs.statusmessage)
+			_log.error('query failed in RO connection')
+			_log.error(capture_cursor_state(curs))
 			pg_exc = make_pg_exception_fields_unicode(pg_exc)
 			_log.error('PG error code: %s', pg_exc.pgcode)
 			if pg_exc.pgerror is not None:
@@ -1577,9 +1626,8 @@ def run_ro_queries(link_obj=None, queries=None, verbose=False, return_data=True,
 				)
 			raise
 		except:
-			_log.error('query failed: [%s]', curs.query)
-			if curs.statusmessage != u'':
-				_log.error('PG status message: %s', curs.statusmessage)
+			_log.exception('query failed in RO connection')
+			_log.error(capture_cursor_state(curs))
 			try:
 				curs_close()
 			except dbapi.InterfaceError:
@@ -1649,21 +1697,23 @@ def run_rw_queries(link_obj=None, queries=None, end_tx=False, return_data=None,
 			* for <index> see <get_col_idx>
 	"""
 	if isinstance(link_obj, dbapi._psycopg.cursor):
-		conn_close = __noop
-		conn_commit = __noop
-		tx_rollback = __noop
+		conn_close = lambda :1
+		conn_commit = lambda :1
+		tx_rollback = lambda :1
 		curs = link_obj
-		curs_close = __noop
+		curs_close = lambda :1
+		notices_accessor = curs.connection
 	elif isinstance(link_obj, dbapi._psycopg.connection):
-		conn_close = __noop
+		conn_close = lambda :1
 		if end_tx:
 			conn_commit = link_obj.commit
 			tx_rollback = link_obj.rollback
 		else:
-			conn_commit = __noop
-			tx_rollback = __noop
+			conn_commit = lambda :1
+			tx_rollback = lambda :1
 		curs = link_obj.cursor()
 		curs_close = curs.close
+		notices_accessor = link_obj
 	elif link_obj is None:
 		conn = get_connection(readonly=False)
 		conn_close = conn.close
@@ -1671,6 +1721,7 @@ def run_rw_queries(link_obj=None, queries=None, end_tx=False, return_data=None,
 		tx_rollback = conn.rollback
 		curs = conn.cursor()
 		curs_close = curs.close
+		notices_accessor = conn
 	else:
 		raise ValueError('link_obj must be cursor, connection or None but not [%s]' % link_obj)
 
@@ -1684,20 +1735,23 @@ def run_rw_queries(link_obj=None, queries=None, end_tx=False, return_data=None,
 			args = None
 		try:
 			curs.execute(query['cmd'], args)
+			if verbose:
+				_log.debug(capture_cursor_state(curs))
+			for notice in notices_accessor.notices:
+				_log.debug(notice.strip(u'\n').strip(u'\r'))
+			del notices_accessor.notices[:]
+		# DB related exceptions
 		except dbapi.Error as pg_exc:
-			_log.error('RW query failed: [%s]', curs.query)
-			if curs.statusmessage != u'':
-				_log.error('PG status message: %s', curs.statusmessage)
+			_log.error('query failed in RW connection')
+			_log.error(capture_cursor_state(curs))
+			for notice in notices_accessor.notices:
+				_log.error(notice.strip(u'\n').strip(u'\r'))
+			del notices_accessor.notices[:]
 			pg_exc = make_pg_exception_fields_unicode(pg_exc)
 			_log.error(u'PG error code: %s', pg_exc.pgcode)
 			if pg_exc.pgerror is not None:
 				_log.error(u'PG error message: %s', pg_exc.u_pgerror)
-			try:
-				curs_close()
-				tx_rollback()			# just for good measure
-				conn_close()
-			except dbapi.InterfaceError:
-				_log.exception('cannot cleanup')
+			# privilege problem
 			if pg_exc.pgcode == sql_error_codes.INSUFFICIENT_PRIVILEGE:
 				details = u'Query: [%s]' % curs.query.strip().strip(u'\n').strip().strip(u'\n')
 				if curs.statusmessage != u'':
@@ -1709,15 +1763,34 @@ def run_rw_queries(link_obj=None, queries=None, end_tx=False, return_data=None,
 					msg = u'[%s]' % pg_exc.pgcode
 				else:
 					msg = u'[%s]: %s' % (pg_exc.pgcode, pg_exc.u_pgerror)
+				try:
+					curs_close()
+					tx_rollback()			# just for good measure
+					conn_close()
+				except dbapi.InterfaceError:
+					_log.exception('cannot cleanup')
 				raise gmExceptions.AccessDenied (
 					msg,
 					source = u'PostgreSQL',
 					code = pg_exc.pgcode,
 					details = details
 				)
+			# other problem
+			gmLog2.log_stack_trace()
+			try:
+				curs_close()
+				tx_rollback()			# just for good measure
+				conn_close()
+			except dbapi.InterfaceError:
+				_log.exception('cannot cleanup')
 			raise
+		# other exception
 		except:
-			_log.exception('error running RW query')
+			_log.exception('error running query in RW connection')
+			_log.error(capture_cursor_state(curs))
+			for notice in notices_accessor.notices:
+				_log.debug(notice.strip(u'\n').strip(u'\r'))
+			del notices_accessor.notices[:]
 			gmLog2.log_stack_trace()
 			try:
 				curs_close()
@@ -1725,7 +1798,6 @@ def run_rw_queries(link_obj=None, queries=None, end_tx=False, return_data=None,
 				conn_close()
 			except dbapi.InterfaceError:
 				_log.exception('cannot cleanup')
-				raise
 			raise
 
 	data = None
@@ -2776,6 +2848,10 @@ SELECT to_timestamp (foofoo,'YYMMDD.HH24MI') FROM (
 		print get_index_name(indexed_table = 'clin.vaccination', indexed_column = 'fk_episode')
 
 	#--------------------------------------------------------------------
+	def test_faulty_SQL():
+		run_rw_queries(queries = [{'cmd': u'SELEC 1'}])
+
+	#--------------------------------------------------------------------
 	# run tests
 	#test_get_connection()
 	#test_exceptions()
@@ -2799,6 +2875,7 @@ SELECT to_timestamp (foofoo,'YYMMDD.HH24MI') FROM (
 	#test_file2bytea()
 	#test_file2bytea_overlay()
 	#test_file2bytea_copy_from()
-	test_file2bytea_lo()
+	#test_file2bytea_lo()
+	test_faulty_SQL()
 
 # ======================================================================
diff --git a/client/wxpython/gmDocumentWidgets.py b/client/wxpython/gmDocumentWidgets.py
index 21abb62..a2dcd4e 100644
--- a/client/wxpython/gmDocumentWidgets.py
+++ b/client/wxpython/gmDocumentWidgets.py
@@ -2051,7 +2051,7 @@ class cDocTree(wx.TreeCtrl, gmRegetMixin.cRegetOnPaintMixin, treemixin.Expansion
 			return True
 
 		# string nodes are labels such as episodes which may or may not have children
-		if type(node_data) == type('string'):
+		if isinstance(node_data, basestring):
 			self.Toggle(node)
 			return True
 
diff --git a/client/wxpython/gmEMRStructWidgets.py b/client/wxpython/gmEMRStructWidgets.py
index 5dd569a..97ad08e 100644
--- a/client/wxpython/gmEMRStructWidgets.py
+++ b/client/wxpython/gmEMRStructWidgets.py
@@ -710,6 +710,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 	def __init__(self, *args, **kwargs):
 		wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl.__init__(self, *args, **kwargs)
 		gmEditArea.cGenericEditAreaMixin.__init__(self)
+
 	#----------------------------------------------------------------
 	# generic Edit Area mixin API
 	#----------------------------------------------------------------
@@ -749,6 +750,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 						self._PRW_discharge.SetFocus()
 
 		if self._PRW_hospital.GetData() is None:
+			valid = False
 			self._PRW_hospital.display_as_valid(False)
 			self.status_message = _('Must select a hospital. Cannot save hospitalization.')
 			self._PRW_hospital.SetFocus()
@@ -756,6 +758,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 			self._PRW_hospital.display_as_valid(True)
 
 		return (valid is True)
+
 	#----------------------------------------------------------------
 	def _save_as_new(self):
 
@@ -770,6 +773,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 
 		self.data = stay
 		return True
+
 	#----------------------------------------------------------------
 	def _save_as_update(self):
 
@@ -781,6 +785,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 		self.data.save_payload()
 
 		return True
+
 	#----------------------------------------------------------------
 	def _refresh_as_new(self):
 		self._PRW_hospital.SetText(value = u'', data = None)
@@ -789,6 +794,7 @@ class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAre
 		self._PRW_discharge.SetText()
 		self._TCTRL_comment.SetValue(u'')
 		self._PRW_hospital.SetFocus()
+
 	#----------------------------------------------------------------
 	def _refresh_from_existing(self):
 		self._PRW_hospital.SetText(value = u'%s @ %s' % (self.data['ward'], self.data['hospital']), data = self.data['pk_org_unit'])
diff --git a/client/wxpython/gmEditArea.py b/client/wxpython/gmEditArea.py
index bfd84b6..04f9d2b 100644
--- a/client/wxpython/gmEditArea.py
+++ b/client/wxpython/gmEditArea.py
@@ -225,6 +225,7 @@ class cXxxEAPnl(wxgXxxEAPnl.wxgXxxEAPnl, gmEditArea.cGenericEditAreaMixin):
 			return result
 		elif self.__mode == 'edit':
 			result = self._refresh_from_existing()
+			self._valid_for_save()
 			return result
 		elif self.__mode == 'new_from_existing':
 			result = self._refresh_as_new_from_existing()
diff --git a/client/wxpython/gmGuiMain.py b/client/wxpython/gmGuiMain.py
index dab34b4..1cfdec9 100644
--- a/client/wxpython/gmGuiMain.py
+++ b/client/wxpython/gmGuiMain.py
@@ -2561,7 +2561,7 @@ class gmTopLevelFrame(wx.Frame):
 		curr_pat = gmPerson.gmCurrentPatient()
 		if not curr_pat.connected:
 			curr_pat = None
-		gmSubstanceMgmtWidgets.jump_to_drug_database(parent = self, patient = curr_pat)
+		gmSubstanceMgmtWidgets.jump_to_drug_database(patient = curr_pat)
 
 	#----------------------------------------------
 	def __on_kompendium_ch(self, evt):
diff --git a/client/wxpython/gmMacro.py b/client/wxpython/gmMacro.py
index 0009d30..327c5f3 100644
--- a/client/wxpython/gmMacro.py
+++ b/client/wxpython/gmMacro.py
@@ -1801,6 +1801,8 @@ class gmPlaceholderHandler(gmBorg.cBorg):
 		intakes2export = gmMedicationWidgets.manage_substance_intakes(emr = emr)
 		if intakes2export is None:
 			return u''
+		if len(intakes2export) == 0:
+			return u''
 
 		# make them unique:
 		unique_intakes = {}
diff --git a/client/wxpython/gmPatOverviewWidgets.py b/client/wxpython/gmPatOverviewWidgets.py
index bcb81af..78092d0 100644
--- a/client/wxpython/gmPatOverviewWidgets.py
+++ b/client/wxpython/gmPatOverviewWidgets.py
@@ -327,8 +327,8 @@ class cPatientOverviewPnl(wxgPatientOverviewPnl.wxgPatientOverviewPnl, gmRegetMi
 
 		hints = patient.suppressed_hints
 		if len(hints) > 0:
-			list_items.append(_("suppr'd:") + u' ' + u','.join([h['title'][:7] + gmTools.u_ellipsis for h in hints]))
-			list_data.append(_('Suppressed hints:\n') + u'\n'.join([h['title'] for h in hints]))
+			list_items.append((_("suppr'd (%s):") % len(hints)) + u' ' + u','.join([h['title'][:7] + gmTools.u_ellipsis for h in hints]))
+			list_data.append(_('Suppressed hints:\n') + u'\n'.join([u'%s: %s' % (hints.index(h) + 1, h['title']) for h in hints]))
 
 		self._LCTRL_inbox.set_string_items(items = list_items)
 		self._LCTRL_inbox.set_data(data = list_data)
@@ -646,19 +646,41 @@ class cPatientOverviewPnl(wxgPatientOverviewPnl.wxgPatientOverviewPnl, gmRegetMi
 		]
 		for issue in issues:
 			last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
-			if last_encounter is None:
-				last = gmDateTime.pydt_strftime(issue['modified_when'], format = '%Y %b')
-				sort_key = u'%s::%s' % (gmDateTime.pydt_strftime(issue['modified_when'], format = date_format4sorting), issue['pk_health_issue'])
+			linked_encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
+			when_candidates = [issue['modified_when'], linked_encounter['last_affirmed']]
+			if last_encounter is not None:
+				when_candidates.append(last_encounter['last_affirmed'])
+			if (patient['dob'] is not None) and (issue['age_noted'] is not None):
+				when_candidates.append(patient['dob'] + issue['age_noted'])
+			if issue['is_active']:
+				# sort active issues by time of most recent clinical access, which
+				# means the most recent of:
+				# issue.modified_when
+				# last_encounter.last_affirmed
+				# linked_encounter.last_affirmed
+				# dob + age
+				relevant_date = max(when_candidates)
 			else:
-				last = gmDateTime.pydt_strftime(last_encounter['last_affirmed'], format = '%Y %b')
-				sort_key = u'%s::%s' % (gmDateTime.pydt_strftime(last_encounter['last_affirmed'], format = date_format4sorting), issue['pk_health_issue'])
-			sort_key_list.append(sort_key)
+				# sort IN-active issues by best guess of real clinical start
+				# means either:
+				# - dob + age
+				# or the earliest of:
+				# - issue.modified_when
+				# - last_encounter.last_affirmed
+				# - linked_encounter.last_affirmed
+				if (patient['dob'] is not None) and (issue['age_noted'] is not None):
+					relevant_date = patient['dob'] + issue['age_noted']
+				else:
+					relevant_date = min(when_candidates)
+			sort_key = u'%s::%s' % (gmDateTime.pydt_strftime(relevant_date, format = date_format4sorting), issue['pk_health_issue'])
+			relevant_date_str = gmDateTime.pydt_strftime(relevant_date, format = '%Y %b')
 			if issue['age_noted'] is None:
 				encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
 				age = _(u' (entered %s ago)') % gmDateTime.format_interval_medically(now - encounter['started'])
 			else:
 				age = u' (@ %s)' % gmDateTime.format_interval_medically(issue['age_noted'])
-			data[sort_key] = [u'%s %s%s' % (last, issue['description'], age), issue]
+			sort_key_list.append(sort_key)
+			data[sort_key] = [u'%s %s%s' % (relevant_date_str, issue['description'], age), issue]
 		del issues
 
 		stays = emr.get_hospital_stays()
diff --git a/client/wxpython/gmSubstanceMgmtWidgets.py b/client/wxpython/gmSubstanceMgmtWidgets.py
index e17c598..fe09265 100644
--- a/client/wxpython/gmSubstanceMgmtWidgets.py
+++ b/client/wxpython/gmSubstanceMgmtWidgets.py
@@ -115,7 +115,7 @@ def get_drug_database(parent=None, patient=None):
 			return None
 
 	if patient is not None:
-		drug_db.patient = pat
+		drug_db.patient = patient
 
 	return drug_db
 
diff --git a/external-tools/gm-create_datamatrix b/external-tools/gm-create_datamatrix
index 319ad97..cd2aaef 100755
--- a/external-tools/gm-create_datamatrix
+++ b/external-tools/gm-create_datamatrix
@@ -58,7 +58,6 @@ if test "$?" != "0" ; then
 	exit 1
 fi
 
-sync
 mv -vf ${OUTPUT_FILE}.png ${OUTPUT_FILE} &>> ${LOG}
 
 exit 0
diff --git a/external-tools/gm-describe_file b/external-tools/gm-describe_file
index d1abe38..efce52f 100755
--- a/external-tools/gm-describe_file
+++ b/external-tools/gm-describe_file
@@ -28,9 +28,22 @@ fi
 BIN=`which pdfinfo`
 if [ "x${BIN}x" != "xx" ]; then
 	echo "---- pdfinfo ----" > "${DESCRIPTION_FILE}.pdfinfo"
-	pdfinfo -struct -meta -box "${FILE_2_DESCRIBE}" >> "${DESCRIPTION_FILE}.pdfinfo" 2>> "${DESCRIPTION_FILE}.pdfinfo"
+	pdfinfo -box "${FILE_2_DESCRIBE}" >> "${DESCRIPTION_FILE}.pdfinfo" 2>> "${DESCRIPTION_FILE}.pdfinfo"
 	if [ $? -eq 0 ] ; then
 		cat "${DESCRIPTION_FILE}.pdfinfo" >> "${DESCRIPTION_FILE}"
+		rm -f "${DESCRIPTION_FILE}.pdfinfo"
+		echo "" >> "${DESCRIPTION_FILE}"
+	fi
+	pdfinfo -meta "${FILE_2_DESCRIBE}" >> "${DESCRIPTION_FILE}.pdfinfo" 2>> "${DESCRIPTION_FILE}.pdfinfo"
+	if [ $? -eq 0 ] ; then
+		cat "${DESCRIPTION_FILE}.pdfinfo" >> "${DESCRIPTION_FILE}"
+		rm -f "${DESCRIPTION_FILE}.pdfinfo"
+		echo "" >> "${DESCRIPTION_FILE}"
+	fi
+	pdfinfo -struct "${FILE_2_DESCRIBE}" >> "${DESCRIPTION_FILE}.pdfinfo" 2>> "${DESCRIPTION_FILE}.pdfinfo"
+	if [ $? -eq 0 ] ; then
+		cat "${DESCRIPTION_FILE}.pdfinfo" >> "${DESCRIPTION_FILE}"
+		rm -f "${DESCRIPTION_FILE}.pdfinfo"
 		echo "" >> "${DESCRIPTION_FILE}"
 	fi
 	rm -f "${DESCRIPTION_FILE}.pdfinfo"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/gnumed-client.git



More information about the debian-med-commit mailing list