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
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
305
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
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
373
374
375
376
377
378 -def edit_xxx(parent=None, xxx=None, single_entry=False, presets=None):
380
383
386
387
388
389
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
400
401
402
413
414
415
416
417 test_gen_item()
418