| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
2 """GNUmed clinical business object in generic form.
3
4 license: GPL v2 or later
5 """
6 #============================================================
7 __author__ = "<karsten.hilbert@gmx.net>"
8
9 import sys
10 import logging
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmBusinessDBObject
16 from Gnumed.pycommon import gmPG2
17 from Gnumed.pycommon import gmTools
18 from Gnumed.pycommon import gmDateTime
19
20 from Gnumed.business import gmSoapDefs
21 from Gnumed.business.gmEMRStructItems import cHealthIssue
22 from Gnumed.business.gmEMRStructItems import cEncounter
23 from Gnumed.business.gmEMRStructItems import cEpisode
24 from Gnumed.business.gmEMRStructItems import cHospitalStay
25 from Gnumed.business.gmEMRStructItems import cPerformedProcedure
26 from Gnumed.business.gmExternalCare import cExternalCareItem
27 from Gnumed.business.gmVaccination import cVaccination
28 from Gnumed.business.gmClinNarrative import cNarrative
29 from Gnumed.business.gmMedication import cSubstanceIntakeEntry
30 from Gnumed.business.gmAllergy import cAllergy
31 from Gnumed.business.gmAllergy import cAllergyState
32 from Gnumed.business.gmFamilyHistory import cFamilyHistory
33 from Gnumed.business.gmAutoHints import cSuppressedHint
34 from Gnumed.business.gmAutoHints import cDynamicHint
35 from Gnumed.business.gmDocuments import cDocument
36 from Gnumed.business.gmProviderInbox import cInboxMessage
37 from Gnumed.business.gmPathLab import cTestResult
38
39 _log = logging.getLogger('gm.emr')
40
41 #============================================================
42 _MAP_generic_emr_item_table2type_str = {
43 'clin.encounter': _('Encounter'),
44 'clin.episode': _('Episode'),
45 'clin.health_issue': _('Health issue'),
46 'clin.external_care': _('External care'),
47 'clin.vaccination': _('Vaccination'),
48 'clin.clin_narrative': _('Progress note'),
49 'clin.test_result': _('Test result'),
50 'clin.substance_intake': _('Substance intake'),
51 'clin.hospital_stay': _('Hospital stay'),
52 'clin.procedure': _('Performed procedure'),
53 'clin.allergy': _('Allergy'),
54 'clin.allergy_state': _('Allergy state'),
55 'clin.family_history': _('Family history'),
56 'blobs.doc_med': _('Document'),
57 'dem.message_inbox': _('Inbox message'),
58 'ref.auto_hint': _('Dynamic hint')
59 }
60
61 _MAP_generic_emr_item_table2class = {
62 'clin.encounter': cEncounter,
63 'clin.episode': cEpisode,
64 'clin.health_issue': cHealthIssue,
65 'clin.external_care': cExternalCareItem,
66 'clin.vaccination': cVaccination,
67 'clin.clin_narrative': cNarrative,
68 'clin.test_result': cTestResult,
69 'clin.substance_intake': cSubstanceIntakeEntry,
70 'clin.hospital_stay': cHospitalStay,
71 'clin.procedure': cPerformedProcedure,
72 'clin.allergy': cAllergy,
73 'clin.allergy_state': cAllergyState,
74 'clin.family_history': cFamilyHistory,
75 'clin.suppressed_hint': cSuppressedHint,
76 'blobs.doc_med': cDocument,
77 'dem.message_inbox': cInboxMessage,
78 'ref.auto_hint': cDynamicHint
79 }
80
81 #============================================================
82 # generic items in clin.v_emr_journal
83 #------------------------------------------------------------
84 _SQL_get_generic_emr_items = """SELECT
85 to_char(c_vej.clin_when, 'YYYY-MM-DD') AS date,
86 c_vej.clin_when,
87 coalesce(c_vej.soap_cat, '') as soap_cat,
88 c_vej.narrative,
89 c_vej.src_table,
90 c_scr.rank AS scr,
91 c_vej.modified_when,
92 to_char(c_vej.modified_when, 'YYYY-MM-DD HH24:MI') AS date_modified,
93 c_vej.modified_by,
94 c_vej.row_version,
95 c_vej.pk_episode,
96 c_vej.pk_encounter,
97 c_vej.soap_cat as real_soap_cat,
98 c_vej.src_pk,
99 c_vej.pk_health_issue,
100 c_vej.health_issue,
101 c_vej.episode,
102 c_vej.issue_active,
103 c_vej.issue_clinically_relevant,
104 c_vej.episode_open,
105 c_vej.encounter_started,
106 c_vej.encounter_last_affirmed,
107 c_vej.encounter_l10n_type,
108 c_vej.pk_patient,
109 -1 AS xmin_dummy
110 FROM
111 clin.v_emr_journal c_vej
112 JOIN clin.soap_cat_ranks c_scr on (c_scr.soap_cat IS NOT DISTINCT FROM c_vej.soap_cat)
113 """
114
115 _SQL_get_hints_as_generic_emr_items = """SELECT
116 to_char(now(), 'YYYY-MM-DD') AS date,
117 now() as clin_when,
118 'u'::text as soap_cat,
119 hints.title || E'\n' || hints.hint
120 as narrative,
121 -- .src_table does not correspond with the
122 -- .src_pk column source because it is generated
123 -- from clin.get_hints_for_patient()
124 'ref.auto_hint'::text as src_table,
125 c_scr.rank AS scr,
126 now() as modified_when,
127 to_char(now(), 'YYYY-MM-DD HH24:MI') AS date_modified,
128 current_user as modified_by,
129 0::integer as row_version,
130 NULL::integer as pk_episode,
131 %(pk_enc)s as pk_encounter,
132 'u'::text as real_soap_cat,
133 hints.pk_auto_hint as src_pk,
134 NULL::integer as pk_health_issue,
135 ''::text as health_issue,
136 ''::text as episode,
137 False as issue_active,
138 False as issue_clinically_relevant,
139 False as episode_open,
140 %(enc_start)s as encounter_started,
141 %(enc_last_affirmed)s as encounter_last_affirmed,
142 %(enc_type)s as encounter_l10n_type,
143 %(enc_pat)s as pk_patient,
144 -1 AS xmin_dummy
145 FROM
146 clin.get_hints_for_patient(%(enc_pat)s) AS hints
147 JOIN clin.soap_cat_ranks c_scr ON (c_scr.soap_cat = 'u')
148 """
149
150 __SQL_union = """(
151 %s
152 ) UNION ALL (
153 %s
154 )"""
155
156 #------------------------------------------------------------
158 """Represents an entry in clin.v_emr_journal."""
159
160 _cmd_fetch_payload = _SQL_get_generic_emr_items + "WHERE src_table = %(src_table)s AND src_pk = %(src_pk)s"
161 _cmds_store_payload = []
162 # [ """
163 # -- typically the underlying table name
164 # UPDATE xxx.xxx SET
165 # -- typically "table_col = %(view_col)s"
166 # xxx = %(xxx)s,
167 # xxx = gm.nullify_empty_string(%(xxx)s)
168 # WHERE
169 # pk = %(pk_XXX)s
170 # AND
171 # xmin = %(xmin_dummy)s
172 # RETURNING
173 # xmin AS xmin_dummy
174 # -- also return columns which are calculated in the view used by
175 # -- the initial SELECT such that they will further on contain their
176 # -- updated value:
177 # --, ...
178 # --, ...
179 # """
180 # ]
181 # view columns that can be updated:
182 _updatable_fields = ['']
183
184 #--------------------------------------------------------
186 lines = self.formatted_header
187 lines.append(gmTools.u_box_horiz_4dashes * 40)
188 lines.extend(self._payload[self._idx['narrative']].strip().split('\n'))
189 lines.append('')
190 lines.append(_(' rev %s (%s) by %s in <%s>') % (
191 self._payload[self._idx['row_version']],
192 self._payload[self._idx['date_modified']],
193 self._payload[self._idx['modified_by']],
194 self._payload[self._idx['src_table']]
195 ))
196 if eol is None:
197 return lines
198 return eol.join(lines)
199
200 #--------------------------------------------------------
202 lines = []
203 lines.append(_('Chart entry (%s): %s [#%s in %s]') % (
204 self.i18n_soap_cat,
205 self.item_type_str,
206 self._payload[self._idx['src_pk']],
207 self._payload[self._idx['src_table']]
208 ))
209 lines.append(_(' Modified: %s by %s (%s rev %s)') % (
210 self._payload[self._idx['date_modified']],
211 self._payload[self._idx['modified_by']],
212 gmTools.u_arrow2right,
213 self._payload[self._idx['row_version']]
214 ))
215 lines.append('')
216 if self._payload[self._idx['health_issue']] is None:
217 issue_info = gmTools.u_diameter
218 else:
219 issue_info = '%s%s' % (
220 self._payload[self._idx['health_issue']],
221 gmTools.bool2subst(self._payload[self._idx['issue_active']], ' (' + _('active') + ')', ' (' + _('inactive') + ')', '')
222 )
223 lines.append(_('Health issue: %s') % issue_info)
224 if self._payload[self._idx['episode']] is None:
225 episode_info = gmTools.u_diameter
226 else:
227 episode_info = '%s%s' % (
228 self._payload[self._idx['episode']],
229 gmTools.bool2subst(self._payload[self._idx['episode_open']], ' (' + _('open') + ')', ' (' + _('closed') + ')', '')
230 )
231 lines.append(_('Episode: %s') % episode_info)
232 if self._payload[self._idx['encounter_started']] is None:
233 enc_info = gmTools.u_diameter
234 else:
235 enc_info = '%s - %s (%s)' % (
236 gmDateTime.pydt_strftime(self._payload[self._idx['encounter_started']], '%Y %b %d %H:%M'),
237 self._payload[self._idx['encounter_last_affirmed']].strftime('%H:%M'),
238 self._payload[self._idx['encounter_l10n_type']]
239 )
240 lines.append(_('Encounter: %s') % enc_info)
241 if eol is None:
242 return lines
243 return eol.join(lines)
244
245 formatted_header = property(format_header)
246
247 #--------------------------------------------------------
249 try:
250 return _MAP_generic_emr_item_table2type_str[self._payload[self._idx['src_table']]]
251 except KeyError:
252 return '[%s:%s]' % (
253 self._payload[self._idx['src_table']],
254 self._payload[self._idx['src_pk']]
255 )
256
257 item_type_str = property(__get_item_type_str)
258
259 #--------------------------------------------------------
262
263 i18n_soap_cat = property(__get_i18n_soap_cat)
264
265 #--------------------------------------------------------
267 item_class = _MAP_generic_emr_item_table2class[self._payload[self._idx['src_table']]]
268 return item_class(aPK_obj = self._payload[self._idx['src_pk']])
269
270 specialized_item = property(__get_specialized_item)
271
272 #------------------------------------------------------------
273 -def get_generic_emr_items(encounters=None, episodes=None, issues=None, patient=None, soap_cats=None, time_range=None, order_by=None, active_encounter=None, return_pks=False):
274
275 faulty_args = (
276 (patient is None) and
277 (encounters is None) and
278 (episodes is None) and
279 (issues is None) and
280 (active_encounter is None)
281 )
282 assert not faulty_args, 'one of <patient>, <episodes>, <issues>, <active_encounter> must not be None'
283
284 if (patient is not None) and (active_encounter is not None):
285 if patient != active_encounter['pk_patient']:
286 raise AssertionError('<patient> (%s) and <active_encounter>["pk_patient"] (%s) must match, if both given', patient, active_encounter['pk_patient'])
287
288 if order_by is None:
289 order_by = 'ORDER BY clin_when, pk_episode, scr, modified_when, src_table'
290 else:
291 order_by = 'ORDER BY %s' % order_by
292
293 if (patient is None) and (active_encounter is not None):
294 patient = active_encounter['pk_patient']
295
296 where_parts = []
297 args = {}
298
299 if patient is not None:
300 where_parts.append('c_vej.pk_patient = %(pat)s')
301 args['pat'] = patient
302
303 if soap_cats is not None:
304 # work around bug in psycopg2 not being able to properly
305 # adapt None to NULL inside tuples
306 if None in soap_cats:
307 where_parts.append('((c_vej.soap_cat IN %(soap_cat)s) OR (c_vej.soap_cat IS NULL))')
308 soap_cats.remove(None)
309 else:
310 where_parts.append('c_vej.soap_cat IN %(soap_cat)s')
311 args['soap_cat'] = tuple(soap_cats)
312
313 if time_range is not None:
314 where_parts.append("c_vej.clin_when > (now() - '%s days'::interval)" % time_range)
315
316 if encounters is not None:
317 where_parts.append("c_vej.pk_encounter IN %(encs)s")
318 args['encs'] = tuple(encounters)
319
320 if episodes is not None:
321 where_parts.append("c_vej.pk_episode IN %(epis)s")
322 args['epis'] = tuple(episodes)
323
324 if issues is not None:
325 where_parts.append("c_vej.pk_health_issue IN %(issues)s")
326 args['issues'] = tuple(issues)
327
328 cmd_journal = _SQL_get_generic_emr_items
329 if len(where_parts) > 0:
330 cmd_journal += '\nWHERE\n\t'
331 cmd_journal += '\t\tAND\t'.join(where_parts)
332
333 if active_encounter is None:
334 cmd = cmd_journal + '\n' + order_by
335 else:
336 args['pk_enc'] = active_encounter['pk_encounter']
337 args['enc_start'] = active_encounter['started']
338 args['enc_last_affirmed'] = active_encounter['last_affirmed']
339 args['enc_type'] = active_encounter['l10n_type']
340 args['enc_pat'] = active_encounter['pk_patient']
341 cmd = __SQL_union % (
342 cmd_journal,
343 _SQL_get_hints_as_generic_emr_items
344 ) + '\n' + order_by
345
346 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
347 if return_pks:
348 return [ {
349 'src_table': r['src_table'],
350 'src_pk': r['src_pk']
351 } for r in rows ]
352
353 return [ cGenericEMRItem(row = {
354 'data': r,
355 'idx': idx,
356 'pk_obj': {'src_table': r['src_table'], 'src_pk': r['src_pk']}
357 } ) for r in rows ]
358
359 #------------------------------------------------------------
361 # forward to specialized item
362 args = {'pk': pk_XXX}
363 cmd = u"DELETE FROM xxx.xxx WHERE pk = %(pk)s"
364 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
365 return True
366
367 #------------------------------------------------------------
369 try:
370 return _MAP_generic_emr_item_table2type_str[table]
371 except KeyError:
372 return _('unmapped entry type from table [%s]') % table
373
374 #------------------------------------------------------------
375 # widget code
376 # remember to add in clinical item generic workflows
377 #------------------------------------------------------------
380 #------------------------------------------------------------
383 #------------------------------------------------------------
386 #------------------------------------------------------------
387
388 #============================================================
389 # main - unit testing
390 #------------------------------------------------------------
391 if __name__ == '__main__':
392
393 if len(sys.argv) < 2:
394 sys.exit()
395
396 if sys.argv[1] != 'test':
397 sys.exit()
398
399 # gmI18N.activate_locale()
400 # gmI18N.install_domain('gnumed')
401
402 #--------------------------------------------------------
413 #print(item.specialized_item)
414 #input('<next>')
415
416 #--------------------------------------------------------
417 test_gen_item()
418
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Feb 29 02:55:27 2020 | http://epydoc.sourceforge.net |