1
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
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
273
274
275 -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):
276
277 faulty_args = (
278 (patient is None) and
279 (encounters is None) and
280 (episodes is None) and
281 (issues is None) and
282 (active_encounter is None)
283 )
284 assert not faulty_args, 'one of <patient>, <episodes>, <issues>, <active_encounter> must not be None'
285
286 if (patient is not None) and (active_encounter is not None):
287 if patient != active_encounter['pk_patient']:
288 raise AssertionError('<patient> (%s) and <active_encounter>["pk_patient"] (%s) must match, if both given', patient, active_encounter['pk_patient'])
289
290 if order_by is None:
291 order_by = 'ORDER BY clin_when, pk_episode, scr, modified_when, src_table'
292 else:
293 order_by = 'ORDER BY %s' % order_by
294
295 if (patient is None) and (active_encounter is not None):
296 patient = active_encounter['pk_patient']
297
298 where_parts = []
299 args = {}
300
301 if patient is not None:
302 where_parts.append('c_vej.pk_patient = %(pat)s')
303 args['pat'] = patient
304
305 if soap_cats is not None:
306
307
308 if None in soap_cats:
309 where_parts.append('((c_vej.soap_cat IN %(soap_cat)s) OR (c_vej.soap_cat IS NULL))')
310 soap_cats.remove(None)
311 else:
312 where_parts.append('c_vej.soap_cat IN %(soap_cat)s')
313 args['soap_cat'] = tuple(soap_cats)
314
315 if time_range is not None:
316 where_parts.append("c_vej.clin_when > (now() - '%s days'::interval)" % time_range)
317
318 if encounters is not None:
319 where_parts.append("c_vej.pk_encounter IN %(encs)s")
320 args['encs'] = tuple(encounters)
321
322 if episodes is not None:
323 where_parts.append("c_vej.pk_episode IN %(epis)s")
324 args['epis'] = tuple(episodes)
325
326 if issues is not None:
327 where_parts.append("c_vej.pk_health_issue IN %(issues)s")
328 args['issues'] = tuple(issues)
329
330 cmd_journal = _SQL_get_generic_emr_items
331 if len(where_parts) > 0:
332 cmd_journal += '\nWHERE\n\t'
333 cmd_journal += '\t\tAND\t'.join(where_parts)
334
335 if active_encounter is None:
336 cmd = cmd_journal + '\n' + order_by
337 else:
338 args['pk_enc'] = active_encounter['pk_encounter']
339 args['enc_start'] = active_encounter['started']
340 args['enc_last_affirmed'] = active_encounter['last_affirmed']
341 args['enc_type'] = active_encounter['l10n_type']
342 args['enc_pat'] = active_encounter['pk_patient']
343 cmd = __SQL_union % (
344 cmd_journal,
345 _SQL_get_hints_as_generic_emr_items
346 ) + '\n' + order_by
347
348 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
349 if return_pks:
350 return [ {
351 'src_table': r['src_table'],
352 'src_pk': r['src_pk']
353 } for r in rows ]
354
355 return [ cGenericEMRItem(row = {
356 'data': r,
357 'idx': idx,
358 'pk_obj': {'src_table': r['src_table'], 'src_pk': r['src_pk']}
359 } ) for r in rows ]
360
361
363
364 args = {'pk': pk_XXX}
365 cmd = u"DELETE FROM xxx.xxx WHERE pk = %(pk)s"
366 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
367 return True
368
369
375
376
377
378
379
380 -def edit_xxx(parent=None, xxx=None, single_entry=False, presets=None):
382
385
388
389
390
391
392
393 if __name__ == '__main__':
394
395 if len(sys.argv) < 2:
396 sys.exit()
397
398 if sys.argv[1] != 'test':
399 sys.exit()
400
401
402
403
404
415
416
417
418
419 test_gen_item()
420