| Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed clinical narrative business object.
2
3 """
4 #============================================================
5 __version__ = "$Revision: 1.45 $"
6 __author__ = "Carlos Moro <cfmoro1976@yahoo.es>, Karsten Hilbert <Karsten.Hilbert@gmx.net>"
7 __license__ = 'GPL (for details see http://gnu.org)'
8
9 import sys, logging
10
11
12 if __name__ == '__main__':
13 sys.path.insert(0, '../../')
14 from Gnumed.pycommon import gmPG2, gmExceptions, gmBusinessDBObject, gmTools
15
16 try:
17 _('dummy-no-need-to-translate-but-make-epydoc-happy')
18 except NameError:
19 _ = lambda x:x
20
21 _log = logging.getLogger('gm.emr')
22 _log.info(__version__)
23
24
25 soap_cat2l10n = {
26 's': _('soap_S').replace(u'soap_', u''),
27 'o': _('soap_O').replace(u'soap_', u''),
28 'a': _('soap_A').replace(u'soap_', u''),
29 'p': _('soap_P').replace(u'soap_', u''),
30 #None: _('soap_ADMIN').replace(u'soap_', u'')
31 None: gmTools.u_ellipsis
32 }
33
34 soap_cat2l10n_str = {
35 's': _('soap_Subjective').replace(u'soap_', u''),
36 'o': _('soap_Objective').replace(u'soap_', u''),
37 'a': _('soap_Assessment').replace(u'soap_', u''),
38 'p': _('soap_Plan').replace(u'soap_', u''),
39 None: _('soap_Administrative').replace(u'soap_', u'')
40 }
41
42 l10n2soap_cat = {
43 _('soap_S').replace(u'soap_', u''): 's',
44 _('soap_O').replace(u'soap_', u''): 'o',
45 _('soap_A').replace(u'soap_', u''): 'a',
46 _('soap_P').replace(u'soap_', u''): 'p',
47 #_('soap_ADMIN').replace(u'soap_', u''): None
48 gmTools.u_ellipsis: None
49 }
50 #============================================================
52 """Represents one real diagnosis.
53 """
54 _cmd_fetch_payload = u"select *, xmin_clin_diag, xmin_clin_narrative from clin.v_pat_diag where pk_diag=%s"
55 _cmds_store_payload = [
56 u"""update clin.clin_diag set
57 laterality=%()s,
58 laterality=%(laterality)s,
59 is_chronic=%(is_chronic)s::boolean,
60 is_active=%(is_active)s::boolean,
61 is_definite=%(is_definite)s::boolean,
62 clinically_relevant=%(clinically_relevant)s::boolean
63 where
64 pk=%(pk_diag)s and
65 xmin=%(xmin_clin_diag)s""",
66 u"""update clin.clin_narrative set
67 narrative=%(diagnosis)s
68 where
69 pk=%(pk_diag)s and
70 xmin=%(xmin_clin_narrative)s""",
71 u"""select xmin_clin_diag, xmin_clin_narrative from clin.v_pat_diag where pk_diag=%s(pk_diag)s"""
72 ]
73
74 _updatable_fields = [
75 'diagnosis',
76 'laterality',
77 'is_chronic',
78 'is_active',
79 'is_definite',
80 'clinically_relevant'
81 ]
82 #--------------------------------------------------------
84 """
85 Retrieves codes linked to this diagnosis
86 """
87 cmd = u"select code, coding_system from clin.v_codes4diag where diagnosis=%s"
88 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self._payload[self._idx['diagnosis']]]}])
89 return rows
90 #--------------------------------------------------------
92 """
93 Associates a code (from coding system) with this diagnosis.
94 """
95 # insert new code
96 cmd = u"select clin.add_coded_phrase (%(diag)s, %(code)s, %(sys)s)"
97 args = {
98 'diag': self._payload[self._idx['diagnosis']],
99 'code': code,
100 'sys': coding_system
101 }
102 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
103 return True
104 #============================================================
106 """Represents one clinical free text entry.
107 """
108 _cmd_fetch_payload = u"select *, xmin_clin_narrative from clin.v_pat_narrative where pk_narrative=%s"
109 _cmds_store_payload = [
110 u"""update clin.clin_narrative set
111 narrative = %(narrative)s,
112 clin_when = %(date)s,
113 soap_cat = lower(%(soap_cat)s),
114 fk_encounter = %(pk_encounter)s
115 where
116 pk=%(pk_narrative)s and
117 xmin=%(xmin_clin_narrative)s""",
118 u"""select xmin_clin_narrative from clin.v_pat_narrative where pk_narrative=%(pk_narrative)s"""
119 ]
120
121 _updatable_fields = [
122 'narrative',
123 'date',
124 'soap_cat',
125 'pk_episode',
126 'pk_encounter'
127 ]
128
129 #xxxxxxxxxxxxxxxx
130 # support row_version in view
131
132 #--------------------------------------------------------
134 """Retrieves codes linked to *this* narrative.
135 """
136 cmd = u"select code, xfk_coding_system from clin.coded_phrase where term=%s"
137 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self._payload[self._idx['narrative']]]}])
138 return rows
139 #--------------------------------------------------------
141 """
142 Associates a code (from coding system) with this narrative.
143 """
144 # insert new code
145 cmd = u"select clin.add_coded_phrase (%(narr)s, %(code)s, %(sys)s)"
146 args = {
147 'narr': self._payload[self._idx['narrative']],
148 'code': code,
149 'sys': coding_system
150 }
151 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
152 return True
153 #--------------------------------------------------------
155
156 if fancy:
157 # FIXME: add revision
158 txt = gmTools.wrap (
159 text = _('%s: %s by %.8s\n%s') % (
160 self._payload[self._idx['date']].strftime('%x %H:%M'),
161 soap_cat2l10n_str[self._payload[self._idx['soap_cat']]],
162 self._payload[self._idx['provider']],
163 self._payload[self._idx['narrative']]
164 ),
165 width = width,
166 initial_indent = u'',
167 subsequent_indent = left_margin + u' '
168 )
169 else:
170 txt = u'%s [%s]: %s (%.8s)' % (
171 self._payload[self._idx['date']].strftime('%x %H:%M'),
172 soap_cat2l10n[self._payload[self._idx['soap_cat']]],
173 self._payload[self._idx['narrative']],
174 self._payload[self._idx['provider']]
175 )
176 if len(txt) > width:
177 txt = txt[:width] + gmTools.u_ellipsis
178
179 return txt
180
181 # lines.append('-- %s ----------' % gmClinNarrative.soap_cat2l10n_str[soap_cat])
182
183 #============================================================
184 # convenience functions
185 #============================================================
187
188 if search_term is None:
189 return []
190
191 if search_term.strip() == u'':
192 return []
193
194 cmd = u'select * from clin.v_narrative4search where narrative ~* %(term)s order by pk_patient limit 1000'
195 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'term': search_term}}], get_col_idx = False)
196
197 return rows
198 #============================================================
200 """Creates a new clinical narrative entry
201
202 narrative - free text clinical narrative
203 soap_cat - soap category
204 episode_id - episodes's primary key
205 encounter_id - encounter's primary key
206 """
207 # any of the args being None (except soap_cat) should fail the SQL code
208
209 # sanity checks:
210
211 # 1) silently do not insert empty narrative
212 narrative = narrative.strip()
213 if narrative == u'':
214 return (True, None)
215
216 # 2) also, silently do not insert true duplicates
217 # FIXME: this should check for .provider = current_user but
218 # FIXME: the view has provider mapped to their staff alias
219 cmd = u"""
220 select *, xmin_clin_narrative from clin.v_pat_narrative where
221 pk_encounter = %(enc)s
222 and pk_episode = %(epi)s
223 and soap_cat = %(soap)s
224 and narrative = %(narr)s
225 """
226 args = {
227 'enc': encounter_id,
228 'epi': episode_id,
229 'soap': soap_cat,
230 'narr': narrative
231 }
232 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
233 if len(rows) == 1:
234 narrative = cNarrative(row = {'pk_field': 'pk_narrative', 'data': rows[0], 'idx': idx})
235 return (True, narrative)
236
237 # insert new narrative
238 queries = [
239 {'cmd': u"insert into clin.clin_narrative (fk_encounter, fk_episode, narrative, soap_cat) values (%s, %s, %s, lower(%s))",
240 'args': [encounter_id, episode_id, narrative, soap_cat]
241 },
242 {'cmd': u"select currval('clin.clin_narrative_pk_seq')"}
243 ]
244 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data=True)
245
246 narrative = cNarrative(aPK_obj = rows[0][0])
247 return (True, narrative)
248 #------------------------------------------------------------
250 """Deletes a clin.clin_narrative row by it's PK."""
251 cmd = u"delete from clin.clin_narrative where pk=%s"
252 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [narrative]}])
253 return True
254 #============================================================
255 # main
256 #------------------------------------------------------------
257 if __name__ == '__main__':
258
259 from Gnumed.pycommon import gmI18N
260 gmI18N.activate_locale()
261 gmI18N.install_domain(domain = 'gnumed')
262
264 print "\nDiagnose test"
265 print "-------------"
266 diagnose = cDiag(aPK_obj=2)
267 fields = diagnose.get_fields()
268 for field in fields:
269 print field, ':', diagnose[field]
270 print "updatable:", diagnose.get_updatable_fields()
271 print "codes:", diagnose.get_codes()
272 #print "adding code..."
273 #diagnose.add_code('Test code', 'Test coding system')
274 #print "codes:", diagnose.get_codes()
275
277 print "\nnarrative test"
278 print "--------------"
279 narrative = cNarrative(aPK_obj=7)
280 fields = narrative.get_fields()
281 for field in fields:
282 print field, ':', narrative[field]
283 print "updatable:", narrative.get_updatable_fields()
284 print "codes:", narrative.get_codes()
285 #print "adding code..."
286 #narrative.add_code('Test code', 'Test coding system')
287 #print "codes:", diagnose.get_codes()
288
289 #print "creating narrative..."
290 #status, new_narrative = create_clin_narrative(narrative = 'Test narrative', soap_cat = 'a', episode_id=1, encounter_id=2)
291 #print new_narrative
292
293 #-----------------------------------------
298 #-----------------------------------------
299
300 #test_search_text_across_emrs()
301 test_diag()
302 test_narrative()
303
304 #============================================================
305 # $Log: gmClinNarrative.py,v $
306 # Revision 1.45 2010/01/31 16:30:20 ncq
307 # - cleanup
308 #
309 # Revision 1.44 2009/12/26 19:05:08 ncq
310 # - improved comment
311 #
312 # Revision 1.43 2009/11/13 20:46:49 ncq
313 # - limit EMR search to 1000 results to remain sane
314 #
315 # Revision 1.42 2009/11/08 20:42:00 ncq
316 # - search across EMRs
317 #
318 # Revision 1.41 2009/06/29 14:50:30 ncq
319 # - use ellipsis for administrational soap rows
320 #
321 # Revision 1.40 2009/05/13 12:17:43 ncq
322 # - enable setting of fk_encounter
323 #
324 # Revision 1.39 2009/04/16 12:46:26 ncq
325 # - episode/encounter patient consistency check now moved to database
326 #
327 # Revision 1.38 2009/01/15 11:31:00 ncq
328 # - cleanup
329 #
330 # Revision 1.37 2008/12/27 15:49:21 ncq
331 # - raise exception on integrity problems in create_narrative
332 #
333 # Revision 1.36 2008/12/18 21:25:56 ncq
334 # - add format() to cClinNarrative
335 #
336 # Revision 1.35 2008/08/15 15:55:14 ncq
337 # - cleanup
338 #
339 # Revision 1.34 2008/05/07 15:15:15 ncq
340 # - use replace() rather than strip() to remove suffixes
341 #
342 # Revision 1.33 2008/04/22 21:11:05 ncq
343 # - define _() for testing
344 #
345 # Revision 1.32 2008/04/11 12:20:16 ncq
346 # - soap_cat2l10n_str
347 #
348 # Revision 1.31 2008/01/30 13:34:49 ncq
349 # - switch to std lib logging
350 #
351 # Revision 1.30 2008/01/22 22:02:29 ncq
352 # - add_coded_term -> add_coded_phrase
353 #
354 # Revision 1.29 2008/01/07 11:40:21 ncq
355 # - fix faulty comparison
356 #
357 # Revision 1.28 2008/01/06 08:08:25 ncq
358 # - check for duplicate narrative before insertion
359 #
360 # Revision 1.27 2007/11/05 12:09:29 ncq
361 # - support admin soap type
362 #
363 # Revision 1.26 2007/09/10 12:31:55 ncq
364 # - improve test suite
365 #
366 # Revision 1.25 2007/09/07 22:36:44 ncq
367 # - soap_cat2l10n and back
368 #
369 # Revision 1.24 2006/11/20 15:55:12 ncq
370 # - gmPG2.run_ro_queries *always* returns (rows, idx) so be aware of that
371 #
372 # Revision 1.23 2006/10/08 15:02:14 ncq
373 # - convert to gmPG2
374 # - convert to cBusinessDBObject
375 #
376 # Revision 1.22 2006/07/19 20:25:00 ncq
377 # - gmPyCompat.py is history
378 #
379 # Revision 1.21 2006/05/06 18:51:55 ncq
380 # - remove comment
381 #
382 # Revision 1.20 2005/11/27 12:44:57 ncq
383 # - clinical tables are in schema "clin" now
384 #
385 # Revision 1.19 2005/10/10 18:27:34 ncq
386 # - v_pat_narrative already HAS .provider
387 #
388 # Revision 1.18 2005/10/08 12:33:09 sjtan
389 # tree can be updated now without refetching entire cache; done by passing emr object to create_xxxx methods and calling emr.update_cache(key,obj);refresh_historical_tree non-destructively checks for changes and removes removed nodes and adds them if cache mismatch.
390 #
391 # Revision 1.17 2005/09/19 16:32:02 ncq
392 # - remove is_rfe/is_aoe/cRFE/cAOE
393 #
394 # Revision 1.16 2005/06/09 21:29:16 ncq
395 # - added missing s in %()s
396 #
397 # Revision 1.15 2005/05/17 08:00:09 ncq
398 # - in create_narrative() ignore empty narrative
399 #
400 # Revision 1.14 2005/04/11 17:53:47 ncq
401 # - id_patient -> pk_patient fix
402 #
403 # Revision 1.13 2005/04/08 13:27:54 ncq
404 # - adapt get_codes()
405 #
406 # Revision 1.12 2005/01/31 09:21:48 ncq
407 # - use commit2()
408 # - add delete_clin_narrative()
409 #
410 # Revision 1.11 2005/01/02 19:55:30 ncq
411 # - don't need _xmins_refetch_col_pos anymore
412 #
413 # Revision 1.10 2004/12/20 16:45:49 ncq
414 # - gmBusinessDBObject now requires refetching of XMIN after save_payload
415 #
416 # Revision 1.9 2004/11/03 22:32:34 ncq
417 # - support _cmds_lock_rows_for_update in business object base class
418 #
419 # Revision 1.8 2004/09/25 13:26:35 ncq
420 # - is_significant -> clinically_relevant
421 #
422 # Revision 1.7 2004/08/11 09:42:50 ncq
423 # - point clin_narrative VO to v_pat_narrative
424 # - robustify by applying lower() to soap_cat on insert/update
425 #
426 # Revision 1.6 2004/07/25 23:23:39 ncq
427 # - Carlos made cAOE.get_diagnosis() return a cDiag instead of a list
428 #
429 # Revision 1.5 2004/07/14 09:10:21 ncq
430 # - Carlos' relentless work brings us get_codes(),
431 # get_possible_codes() and adjustions for the fact
432 # that we can now code any soap row
433 #
434 # Revision 1.4 2004/07/07 15:05:51 ncq
435 # - syntax fixes by Carlos
436 # - get_codes(), get_possible_codes()
437 # - talk to the right views
438 #
439 # Revision 1.3 2004/07/06 00:09:19 ncq
440 # - Carlos added create_clin_narrative(), cDiag, cNarrative, and unit tests - nice work !
441 #
442 # Revision 1.2 2004/07/05 10:24:46 ncq
443 # - use v_pat_rfe/aoe, by Carlos
444 #
445 # Revision 1.1 2004/07/04 13:24:31 ncq
446 # - add cRFE/cAOE
447 # - use in get_rfes(), get_aoes()
448 #
449
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Feb 9 04:01:59 2010 | http://epydoc.sourceforge.net |