| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed EMR structure editors
2
3 This module contains widgets to create and edit EMR structural
4 elements (issues, enconters, episodes).
5
6 This is based on initial work and ideas by Syan <kittylitter@swiftdsl.com.au>
7 and Karsten <Karsten.Hilbert@gmx.net>.
8 """
9 #================================================================
10 __version__ = "$Revision: 1.114 $"
11 __author__ = "cfmoro1976@yahoo.es, karsten.hilbert@gmx.net"
12 __license__ = "GPL"
13
14 # stdlib
15 import sys, re, datetime as pydt, logging, time
16
17
18 # 3rd party
19 import wx
20 import wx.lib.pubsub as wxps
21
22
23 # GNUmed
24 if __name__ == '__main__':
25 sys.path.insert(0, '../../')
26 from Gnumed.pycommon import gmI18N, gmMatchProvider, gmDispatcher, gmTools, gmDateTime, gmCfg, gmExceptions
27 from Gnumed.business import gmEMRStructItems, gmPerson, gmSOAPimporter, gmSurgery, gmPersonSearch
28 from Gnumed.wxpython import gmPhraseWheel, gmGuiHelpers, gmListWidgets, gmEditArea, gmPatSearchWidgets
29 from Gnumed.wxGladeWidgets import wxgIssueSelectionDlg, wxgMoveNarrativeDlg
30 from Gnumed.wxGladeWidgets import wxgEncounterTypeEditAreaPnl
31
32
33 _log = logging.getLogger('gm.ui')
34 _log.info(__version__)
35 #================================================================
36 # performed procedure related widgets/functions
37 #----------------------------------------------------------------
39
40 pat = gmPerson.gmCurrentPatient()
41 emr = pat.get_emr()
42
43 if parent is None:
44 parent = wx.GetApp().GetTopWindow()
45 #-----------------------------------------
46 def edit(procedure=None):
47 return edit_procedure(parent = parent, procedure = procedure)
48 #-----------------------------------------
49 def delete(procedure=None):
50 if gmEMRStructItems.delete_performed_procedure(procedure = procedure['pk_procedure']):
51 return True
52
53 gmDispatcher.send (
54 signal = u'statustext',
55 msg = _('Cannot delete performed procedure.'),
56 beep = True
57 )
58 return False
59 #-----------------------------------------
60 def refresh(lctrl):
61 procs = emr.get_performed_procedures()
62
63 items = [
64 [
65 u'%s%s' % (
66 p['clin_when'].strftime('%Y-%m-%d'),
67 gmTools.bool2subst (
68 p['is_ongoing'],
69 _(' (ongoing)'),
70 gmTools.coalesce (
71 initial = p['clin_end'],
72 instead = u'',
73 template_initial = u' - %s',
74 function_initial = ('strftime', u'%Y-%m-%d')
75 )
76 )
77 ),
78 p['clin_where'],
79 p['episode'],
80 p['performed_procedure']
81 ] for p in procs
82 ]
83 lctrl.set_string_items(items = items)
84 lctrl.set_data(data = procs)
85 #-----------------------------------------
86 gmListWidgets.get_choices_from_list (
87 parent = parent,
88 msg = _('\nSelect the procedure you want to edit !\n'),
89 caption = _('Editing performed procedures ...'),
90 columns = [_('When'), _('Where'), _('Episode'), _('Procedure')],
91 single_selection = True,
92 edit_callback = edit,
93 new_callback = edit,
94 delete_callback = delete,
95 refresh_callback = refresh
96 )
97 #----------------------------------------------------------------
99 ea = cProcedureEAPnl(parent = parent, id = -1)
100 ea.data = procedure
101 ea.mode = gmTools.coalesce(procedure, 'new', 'edit')
102 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
103 dlg.SetTitle(gmTools.coalesce(procedure, _('Adding a procedure'), _('Editing a procedure')))
104 if dlg.ShowModal() == wx.ID_OK:
105 dlg.Destroy()
106 return True
107 dlg.Destroy()
108 return False
109 #----------------------------------------------------------------
110 from Gnumed.wxGladeWidgets import wxgProcedureEAPnl
111
113
115 wxgProcedureEAPnl.wxgProcedureEAPnl.__init__(self, *args, **kwargs)
116 gmEditArea.cGenericEditAreaMixin.__init__(self)
117
118 self.mode = 'new'
119 self.data = None
120
121 self.__init_ui()
122 #----------------------------------------------------------------
124 self._PRW_hospital_stay.add_callback_on_lose_focus(callback = self._on_hospital_stay_lost_focus)
125 self._PRW_hospital_stay.set_context(context = 'pat', val = gmPerson.gmCurrentPatient().ID)
126 self._PRW_location.add_callback_on_lose_focus(callback = self._on_location_lost_focus)
127 self._DPRW_date.add_callback_on_lose_focus(callback = self._on_start_lost_focus)
128 self._DPRW_end.add_callback_on_lose_focus(callback = self._on_end_lost_focus)
129
130 # location
131 mp = gmMatchProvider.cMatchProvider_SQL2 (
132 queries = [
133 u"""
134 select distinct on (clin_where) clin_where, clin_where
135 from clin.procedure
136 where clin_where %(fragment_condition)s
137 order by clin_where
138 limit 25
139 """ ]
140 )
141 mp.setThresholds(2, 4, 6)
142 self._PRW_location.matcher = mp
143
144 # procedure
145 mp = gmMatchProvider.cMatchProvider_SQL2 (
146 queries = [
147 u"""
148 select distinct on (narrative) narrative, narrative
149 from clin.procedure
150 where narrative %(fragment_condition)s
151 order by narrative
152 limit 25
153 """ ]
154 )
155 mp.setThresholds(2, 4, 6)
156 self._PRW_procedure.matcher = mp
157 #----------------------------------------------------------------
159 stay = self._PRW_hospital_stay.GetData()
160 if stay is None:
161 self._PRW_hospital_stay.SetText()
162 self._PRW_location.Enable(True)
163 self._PRW_episode.Enable(True)
164 self._LBL_hospital_details.SetLabel(u'')
165 else:
166 self._PRW_location.SetText()
167 self._PRW_location.Enable(False)
168 self._PRW_episode.SetText()
169 self._PRW_episode.Enable(False)
170 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = stay).format())
171 #----------------------------------------------------------------
173 if self._PRW_location.GetValue().strip() == u'':
174 self._PRW_hospital_stay.Enable(True)
175 # self._PRW_episode.Enable(False)
176 else:
177 self._PRW_hospital_stay.SetText()
178 self._PRW_hospital_stay.Enable(False)
179 self._PRW_hospital_stay.display_as_valid(True)
180 # self._PRW_episode.Enable(True)
181 #----------------------------------------------------------------
183 if not self._DPRW_date.is_valid_timestamp():
184 return
185 end = self._DPRW_end.GetData()
186 if end is None:
187 return
188 end = end.get_pydt()
189 start = self._DPRW_date.GetData().get_pydt()
190 if start < end:
191 return
192 self._DPRW_date.display_as_valid(False)
193 #----------------------------------------------------------------
195 end = self._DPRW_end.GetData()
196 if end is None:
197 self._CHBOX_ongoing.Enable(True)
198 self._DPRW_end.display_as_valid(True)
199 else:
200 self._CHBOX_ongoing.Enable(False)
201 end = end.get_pydt()
202 now = gmDateTime.pydt_now_here()
203 if end > now:
204 self._CHBOX_ongoing.SetValue(True)
205 else:
206 self._CHBOX_ongoing.SetValue(False)
207 start = self._DPRW_date.GetData()
208 if start is None:
209 self._DPRW_end.display_as_valid(True)
210 else:
211 start = start.get_pydt()
212 if end > start:
213 self._DPRW_end.display_as_valid(True)
214 else:
215 self._DPRW_end.display_as_valid(False)
216 #----------------------------------------------------------------
217 # generic Edit Area mixin API
218 #----------------------------------------------------------------
220
221 has_errors = False
222
223 if not self._DPRW_date.is_valid_timestamp():
224 self._DPRW_date.display_as_valid(False)
225 has_errors = True
226 else:
227 self._DPRW_date.display_as_valid(True)
228
229 end = self._DPRW_end.GetData()
230 self._DPRW_end.display_as_valid(True)
231 if end is not None:
232 end = end.get_pydt()
233 start = self._DPRW_end.GetData()
234 if start is not None:
235 start = start.get_pydt()
236 if end < start:
237 has_errors = True
238 self._DPRW_end.display_as_valid(False)
239 if self._CHBOX_ongoing.IsChecked():
240 now = gmDateTime.pydt_now_here()
241 if end < now:
242 has_errors = True
243 self._DPRW_end.display_as_valid(False)
244
245 if self._PRW_hospital_stay.GetData() is None:
246 if self._PRW_episode.GetData() is None:
247 self._PRW_episode.display_as_valid(False)
248 has_errors = True
249 else:
250 self._PRW_episode.display_as_valid(True)
251 else:
252 self._PRW_episode.display_as_valid(True)
253
254 if (self._PRW_procedure.GetValue() is None) or (self._PRW_procedure.GetValue().strip() == u''):
255 self._PRW_procedure.display_as_valid(False)
256 has_errors = True
257 else:
258 self._PRW_procedure.display_as_valid(True)
259
260 invalid_location = (
261 (self._PRW_hospital_stay.GetData() is None) and (self._PRW_location.GetValue().strip() == u'')
262 or
263 (self._PRW_hospital_stay.GetData() is not None) and (self._PRW_location.GetValue().strip() != u'')
264 )
265 if invalid_location:
266 self._PRW_hospital_stay.display_as_valid(False)
267 self._PRW_location.display_as_valid(False)
268 has_errors = True
269 else:
270 self._PRW_hospital_stay.display_as_valid(True)
271 self._PRW_location.display_as_valid(True)
272
273 wxps.Publisher().sendMessage (
274 topic = 'statustext',
275 data = {'msg': _('Cannot save procedure.'), 'beep': True}
276 )
277
278 return (has_errors is False)
279 #----------------------------------------------------------------
281
282 pat = gmPerson.gmCurrentPatient()
283 emr = pat.get_emr()
284
285 if self._PRW_hospital_stay.GetData() is None:
286 stay = None
287 epi = self._PRW_episode.GetData()
288 loc = self._PRW_location.GetValue().strip()
289 else:
290 stay = self._PRW_hospital_stay.GetData()
291 epi = gmEMRStructItems.cHospitalStay(aPK_obj = stay)['pk_episode']
292 loc = None
293
294 proc = emr.add_performed_procedure (
295 episode = epi,
296 location = loc,
297 hospital_stay = stay,
298 procedure = self._PRW_procedure.GetValue().strip()
299 )
300
301 proc['clin_when'] = self._DPRW_date.data.get_pydt()
302 if self._DPRW_end.GetData() is None:
303 proc['clin_end'] = None
304 else:
305 proc['clin_end'] = self._DPRW_end.GetData().get_pydt()
306 proc['is_ongoing'] = self._CHBOX_ongoing.IsChecked()
307 proc.save()
308
309 self.data = proc
310
311 return True
312 #----------------------------------------------------------------
314 self.data['clin_when'] = self._DPRW_date.data.get_pydt()
315
316 if self._DPRW_end.GetData() is None:
317 self.data['clin_end'] = None
318 else:
319 self.data['clin_end'] = self._DPRW_end.GetData().get_pydt()
320
321 self.data['is_ongoing'] = self._CHBOX_ongoing.IsChecked()
322
323 if self._PRW_hospital_stay.GetData() is None:
324 self.data['pk_hospital_stay'] = None
325 self.data['clin_where'] = self._PRW_location.GetValue().strip()
326 self.data['pk_episode'] = self._PRW_episode.GetData()
327 else:
328 self.data['pk_hospital_stay'] = self._PRW_hospital_stay.GetData()
329 self.data['clin_where'] = None
330 stay = gmEMRStructItems.cHospitalStay(aPK_obj = self._PRW_hospital_stay.GetData())
331 self.data['pk_episode'] = stay['pk_episode']
332
333 self.data['performed_procedure'] = self._PRW_procedure.GetValue().strip()
334
335 self.data.save()
336 return True
337 #----------------------------------------------------------------
339 self._DPRW_date.SetText()
340 self._DPRW_end.SetText()
341 self._CHBOX_ongoing.SetValue(False)
342 self._CHBOX_ongoing.Enable(True)
343 self._PRW_hospital_stay.SetText()
344 self._PRW_location.SetText()
345 self._PRW_episode.SetText()
346 self._PRW_procedure.SetText()
347
348 self._PRW_procedure.SetFocus()
349 #----------------------------------------------------------------
351 self._DPRW_date.SetData(data = self.data['clin_when'])
352 if self.data['clin_end'] is None:
353 self._DPRW_end.SetText()
354 self._CHBOX_ongoing.Enable(True)
355 self._CHBOX_ongoing.SetValue(self.data['is_ongoing'])
356 else:
357 self._DPRW_end.SetData(data = self.data['clin_end'])
358 self._CHBOX_ongoing.Enable(False)
359 now = gmDateTime.pydt_now_here()
360 if self.data['clin_end'] > now:
361 self._CHBOX_ongoing.SetValue(True)
362 else:
363 self._CHBOX_ongoing.SetValue(False)
364 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode'])
365 self._PRW_procedure.SetText(value = self.data['performed_procedure'], data = self.data['performed_procedure'])
366
367 if self.data['pk_hospital_stay'] is None:
368 self._PRW_hospital_stay.SetText()
369 self._LBL_hospital_details.SetLabel(u'')
370 self._PRW_location.SetText(value = self.data['clin_where'], data = self.data['clin_where'])
371 else:
372 self._PRW_hospital_stay.SetText(value = self.data['clin_where'], data = self.data['pk_hospital_stay'])
373 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = self.data['pk_hospital_stay']).format())
374 self._PRW_location.SetText()
375
376 self._PRW_procedure.SetFocus()
377 #----------------------------------------------------------------
379 self._refresh_as_new()
380 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode'])
381 if self.data['pk_hospital_stay'] is None:
382 self._PRW_hospital_stay.SetText()
383 self._PRW_location.SetText(value = self.data['clin_where'], data = self.data['clin_where'])
384 else:
385 self._PRW_hospital_stay.SetText(value = self.data['clin_where'], data = self.data['pk_hospital_stay'])
386 self._PRW_location.SetText()
387
388 self._PRW_procedure.SetFocus()
389 #----------------------------------------------------------------
390 # event handlers
391 #----------------------------------------------------------------
396 #----------------------------------------------------------------
398 if self._CHBOX_ongoing.IsChecked():
399 end = self._DPRW_end.GetData()
400 if end is None:
401 self._DPRW_end.display_as_valid(True)
402 else:
403 end = end.get_pydt()
404 now = gmDateTime.pydt_now_here()
405 if end > now:
406 self._DPRW_end.display_as_valid(True)
407 else:
408 self._DPRW_end.display_as_valid(False)
409 else:
410 self._DPRW_end.is_valid_timestamp()
411 event.Skip()
412 #================================================================
413 # hospital stay related widgets/functions
414 #----------------------------------------------------------------
416
417 pat = gmPerson.gmCurrentPatient()
418 emr = pat.get_emr()
419
420 if parent is None:
421 parent = wx.GetApp().GetTopWindow()
422 #-----------------------------------------
423 def edit(stay=None):
424 return edit_hospital_stay(parent = parent, hospital_stay = stay)
425 #-----------------------------------------
426 def delete(stay=None):
427 if gmEMRStructItems.delete_hospital_stay(stay = stay['pk_hospital_stay']):
428 return True
429 gmDispatcher.send (
430 signal = u'statustext',
431 msg = _('Cannot delete hospital stay.'),
432 beep = True
433 )
434 return False
435 #-----------------------------------------
436 def refresh(lctrl):
437 stays = emr.get_hospital_stays()
438 items = [
439 [
440 s['admission'].strftime('%Y-%m-%d'),
441 gmTools.coalesce(s['discharge'], u''),
442 s['episode'],
443 gmTools.coalesce(s['hospital'], u'')
444 ] for s in stays
445 ]
446 lctrl.set_string_items(items = items)
447 lctrl.set_data(data = stays)
448 #-----------------------------------------
449 gmListWidgets.get_choices_from_list (
450 parent = parent,
451 msg = _('\nSelect the hospital stay you want to edit !\n'),
452 caption = _('Editing hospital stays ...'),
453 columns = [_('Admission'), _('Discharge'), _('Reason'), _('Hospital')],
454 single_selection = True,
455 edit_callback = edit,
456 new_callback = edit,
457 delete_callback = delete,
458 refresh_callback = refresh
459 )
460
461 #----------------------------------------------------------------
463 ea = cHospitalStayEditAreaPnl(parent = parent, id = -1)
464 ea.data = hospital_stay
465 ea.mode = gmTools.coalesce(hospital_stay, 'new', 'edit')
466 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
467 dlg.SetTitle(gmTools.coalesce(hospital_stay, _('Adding a hospital stay'), _('Editing a hospital stay')))
468 if dlg.ShowModal() == wx.ID_OK:
469 dlg.Destroy()
470 return True
471 dlg.Destroy()
472 return False
473 #----------------------------------------------------------------
475 """Phrasewheel to allow selection of a hospital stay.
476 """
478
479 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs)
480
481 ctxt = {'ctxt_pat': {'where_part': u'pk_patient = %(pat)s and', 'placeholder': u'pat'}}
482
483 mp = gmMatchProvider.cMatchProvider_SQL2 (
484 queries = [
485 u"""
486 select
487 pk_hospital_stay,
488 descr
489 from (
490 select distinct on (pk_hospital_stay)
491 pk_hospital_stay,
492 descr
493 from
494 (select
495 pk_hospital_stay,
496 (
497 to_char(admission, 'YYYY-Mon-DD')
498 || coalesce((' (' || hospital || '):'), ': ')
499 || episode
500 || coalesce((' (' || health_issue || ')'), '')
501 ) as descr
502 from
503 clin.v_pat_hospital_stays
504 where
505 %(ctxt_pat)s
506
507 hospital %(fragment_condition)s
508 or
509 episode %(fragment_condition)s
510 or
511 health_issue %(fragment_condition)s
512 ) as the_stays
513 ) as distinct_stays
514 order by descr
515 limit 25
516 """ ],
517 context = ctxt
518 )
519 mp.setThresholds(3, 4, 6)
520 mp.set_context('pat', gmPerson.gmCurrentPatient().ID)
521
522 self.matcher = mp
523 self.selection_only = True
524 #----------------------------------------------------------------
525 from Gnumed.wxGladeWidgets import wxgHospitalStayEditAreaPnl
526
527 -class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
528
530 wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl.__init__(self, *args, **kwargs)
531 gmEditArea.cGenericEditAreaMixin.__init__(self)
532 #----------------------------------------------------------------
533 # generic Edit Area mixin API
534 #----------------------------------------------------------------
536 if not self._DP_admission.GetValue().IsValid():
537 self._DP_admission.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
538 wxps.Publisher().sendMessage (
539 topic = 'statustext',
540 data = {'msg': _('Missing admission data. Cannot save hospital stay.'), 'beep': True}
541 )
542 return False
543 else:
544 self._DP_admission.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
545
546 if self._DP_discharge.GetValue().IsValid():
547 if not self._DP_discharge.GetValue().IsLaterThan(self._DP_admission.GetValue()):
548 self._DP_discharge.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
549 wxps.Publisher().sendMessage (
550 topic = 'statustext',
551 data = {'msg': _('Discharge date must be empty or later than admission. Cannot save hospital stay.'), 'beep': True}
552 )
553 return False
554
555 if self._PRW_episode.GetValue().strip() == u'':
556 self._PRW_episode.display_as_valid(False)
557 wxps.Publisher().sendMessage (
558 topic = 'statustext',
559 data = {'msg': _('Must select an episode or enter a name for a new one. Cannot save hospital stay.'), 'beep': True}
560 )
561 return False
562
563 return True
564 #----------------------------------------------------------------
566
567 pat = gmPerson.gmCurrentPatient()
568 emr = pat.get_emr()
569 stay = emr.add_hospital_stay(episode = self._PRW_episode.GetData(can_create = True))
570 stay['hospital'] = gmTools.none_if(self._PRW_hospital.GetValue().strip(), u'')
571 stay['admission'] = gmDateTime.wxDate2py_dt(wxDate = self._DP_admission.GetValue())
572 if self._DP_discharge.GetValue().IsValid():
573 stay['discharge'] = gmDateTime.wxDate2py_dt(wxDate = self._DP_discharge.GetValue())
574 stay.save_payload()
575
576 self.data = stay
577 return True
578 #----------------------------------------------------------------
580
581 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
582 self.data['hospital'] = gmTools.none_if(self._PRW_hospital.GetValue().strip(), u'')
583 self.data['admission'] = gmDateTime.wxDate2py_dt(wxDate = self._DP_admission.GetValue())
584 if self._DP_discharge.GetValue().IsValid():
585 self.data['discharge'] = gmDateTime.wxDate2py_dt(wxDate = self._DP_discharge.GetValue())
586 self.data.save_payload()
587
588 return True
589 #----------------------------------------------------------------
591 self._PRW_hospital.SetText(value = u'')
592 self._PRW_episode.SetText(value = u'')
593 self._DP_admission.SetValue(dt = wx.DateTime.UNow())
594 #self._DP_discharge.SetValue(dt = None)
595 #----------------------------------------------------------------
597 if self.data['hospital'] is not None:
598 self._PRW_hospital.SetText(value = self.data['hospital'])
599
600 if self.data['pk_episode'] is not None:
601 self._PRW_episode.SetText(value = self.data['episode'], data = self.data['pk_episode'])
602
603 self._DP_admission.SetValue(gmDateTime.py_dt2wxDate(py_dt = self.data['admission'], wx = wx))
604
605 if self.data['discharge'] is not None:
606 self._DP_discharge.SetValue(gmDateTime.py_dt2wxDate(py_dt = self.data['discharge'], wx = wx))
607 #----------------------------------------------------------------
610 #================================================================
611 # encounter related widgets/functions
612 #----------------------------------------------------------------
614 emr.start_new_encounter()
615 gmDispatcher.send(signal = 'statustext', msg = _('Started a new encounter for the active patient.'), beep = True)
616 time.sleep(0.5)
617 gmGuiHelpers.gm_show_info (
618 _('\nA new encounter was started for the active patient.\n'),
619 _('Start of new encounter')
620 )
621 #----------------------------------------------------------------
622 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaDlg
623
625 if parent is None:
626 parent = wx.GetApp().GetTopWindow()
627
628 # FIXME: use generic dialog 2
629 dlg = cEncounterEditAreaDlg(parent = parent, encounter = encounter)
630 if dlg.ShowModal() == wx.ID_OK:
631 dlg.Destroy()
632 return True
633 dlg.Destroy()
634 return False
635 #----------------------------------------------------------------
637
638 if patient is None:
639 patient = gmPerson.gmCurrentPatient()
640
641 if not patient.connected:
642 gmDispatcher.send(signal = 'statustext', msg = _('Cannot list encounters. No active patient.'))
643 return False
644
645 if parent is None:
646 parent = wx.GetApp().GetTopWindow()
647
648 emr = patient.get_emr()
649
650 #--------------------
651 def refresh(lctrl):
652 if encounters is not None:
653 encs = encounters
654 else:
655 encs = emr.get_encounters()
656
657 items = [
658 [
659 e['started'].strftime('%x %H:%M'),
660 e['last_affirmed'].strftime('%H:%M'),
661 e['l10n_type'],
662 gmTools.coalesce(e['reason_for_encounter'], u''),
663 gmTools.coalesce(e['assessment_of_encounter'], u''),
664 gmTools.bool2subst(e.has_clinical_data(), u'', gmTools.u_checkmark_thin),
665 e['pk_encounter']
666 ] for e in encs
667 ]
668
669 lctrl.set_string_items(items = items)
670 lctrl.set_data(data = encs)
671 #--------------------
672 def edit(enc = None):
673 return edit_encounter(parent = parent, encounter = enc)
674 #--------------------
675 return gmListWidgets.get_choices_from_list (
676 parent = parent,
677 msg = _('\nBelow find the relevant encounters of the patient.\n'),
678 caption = _('Encounters ...'),
679 columns = [_('Started'), _('Ended'), _('Type'), _('Reason for Encounter'), _('Assessment of Encounter'), _('Empty'), '#'],
680 can_return_empty = True,
681 single_selection = single_selection,
682 refresh_callback = refresh,
683 edit_callback = edit
684 )
685 #----------------------------------------------------------------
687 """This is used as the callback when the EMR detects that the
688 patient was here rather recently and wants to ask the
689 provider whether to continue the recent encounter.
690 """
691 if parent is None:
692 parent = wx.GetApp().GetTopWindow()
693
694 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
695 parent = None,
696 id = -1,
697 caption = caption,
698 question = msg,
699 button_defs = [
700 {'label': _('Continue'), 'tooltip': _('Continue the existing recent encounter.'), 'default': False},
701 {'label': _('Start new'), 'tooltip': _('Start a new encounter. The existing one will be closed.'), 'default': True}
702 ],
703 show_checkbox = False
704 )
705
706 result = dlg.ShowModal()
707 dlg.Destroy()
708
709 if result == wx.ID_YES:
710 return True
711
712 return False
713 #----------------------------------------------------------------
715
716 if parent is None:
717 parent = wx.GetApp().GetTopWindow()
718
719 #--------------------
720 def edit(enc_type=None):
721 return edit_encounter_type(parent = parent, encounter_type = enc_type)
722 #--------------------
723 def delete(enc_type=None):
724 if gmEMRStructItems.delete_encounter_type(description = enc_type['description']):
725 return True
726 gmDispatcher.send (
727 signal = u'statustext',
728 msg = _('Cannot delete encounter type [%s]. It is in use.') % enc_type['l10n_description'],
729 beep = True
730 )
731 return False
732 #--------------------
733 def refresh(lctrl):
734 enc_types = gmEMRStructItems.get_encounter_types()
735 lctrl.set_string_items(items = enc_types)
736 #--------------------
737 gmListWidgets.get_choices_from_list (
738 parent = parent,
739 msg = _('\nSelect the encounter type you want to edit !\n'),
740 caption = _('Managing encounter types ...'),
741 columns = [_('Local name'), _('Encounter type')],
742 single_selection = True,
743 edit_callback = edit,
744 new_callback = edit,
745 delete_callback = delete,
746 refresh_callback = refresh
747 )
748 #----------------------------------------------------------------
750 ea = cEncounterTypeEditAreaPnl(parent = parent, id = -1)
751 ea.data = encounter_type
752 ea.mode = gmTools.coalesce(encounter_type, 'new', 'edit')
753 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea)
754 dlg.SetTitle(gmTools.coalesce(encounter_type, _('Adding new encounter type'), _('Editing local encounter type name')))
755 if dlg.ShowModal() == wx.ID_OK:
756 return True
757 return False
758 #----------------------------------------------------------------
760 """Phrasewheel to allow selection of encounter type.
761
762 - user input interpreted as encounter type in English or local language
763 - data returned is pk of corresponding encounter type or None
764 """
766
767 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs)
768
769 mp = gmMatchProvider.cMatchProvider_SQL2 (
770 queries = [
771 u"""
772 select pk, l10n_description from (
773 select distinct on (pk) * from (
774 (select
775 pk,
776 _(description) as l10n_description,
777 1 as rank
778 from
779 clin.encounter_type
780 where
781 _(description) %(fragment_condition)s
782
783 ) union all (
784
785 select
786 pk,
787 _(description) as l10n_description,
788 2 as rank
789 from
790 clin.encounter_type
791 where
792 description %(fragment_condition)s
793 )
794 ) as q_distinct_pk
795 ) as q_ordered order by rank, l10n_description
796 """ ]
797 )
798 mp.setThresholds(2, 4, 6)
799
800 self.matcher = mp
801 self.selection_only = True
802 self.picklist_delay = 50
803 #----------------------------------------------------------------
804 -class cEncounterTypeEditAreaPnl(wxgEncounterTypeEditAreaPnl.wxgEncounterTypeEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
805
807
808 wxgEncounterTypeEditAreaPnl.wxgEncounterTypeEditAreaPnl.__init__(self, *args, **kwargs)
809 gmEditArea.cGenericEditAreaMixin.__init__(self)
810
811 # self.__register_interests()
812 #-------------------------------------------------------
813 # generic edit area API
814 #-------------------------------------------------------
816 if self.mode == 'edit':
817 if self._TCTRL_l10n_name.GetValue().strip() == u'':
818 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = False)
819 return False
820 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True)
821 return True
822
823 no_errors = True
824
825 if self._TCTRL_l10n_name.GetValue().strip() == u'':
826 if self._TCTRL_name.GetValue().strip() == u'':
827 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = False)
828 no_errors = False
829 else:
830 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True)
831 else:
832 self.display_tctrl_as_valid(tctrl = self._TCTRL_l10n_name, valid = True)
833
834 if self._TCTRL_name.GetValue().strip() == u'':
835 if self._TCTRL_l10n_name.GetValue().strip() == u'':
836 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = False)
837 no_errors = False
838 else:
839 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = True)
840 else:
841 self.display_tctrl_as_valid(tctrl = self._TCTRL_name, valid = True)
842
843 return no_errors
844 #-------------------------------------------------------
846 enc_type = gmEMRStructItems.create_encounter_type (
847 description = gmTools.none_if(self._TCTRL_name.GetValue().strip(), u''),
848 l10n_description = gmTools.coalesce (
849 gmTools.none_if(self._TCTRL_l10n_name.GetValue().strip(), u''),
850 self._TCTRL_name.GetValue().strip()
851 )
852 )
853 if enc_type is None:
854 return False
855 self.data = enc_type
856 return True
857 #-------------------------------------------------------
859 enc_type = gmEMRStructItems.update_encounter_type (
860 description = self._TCTRL_name.GetValue().strip(),
861 l10n_description = self._TCTRL_l10n_name.GetValue().strip()
862 )
863 if enc_type is None:
864 return False
865 self.data = enc_type
866 return True
867 #-------------------------------------------------------
869 self._TCTRL_l10n_name.SetValue(u'')
870 self._TCTRL_name.SetValue(u'')
871 self._TCTRL_name.Enable(True)
872 #-------------------------------------------------------
874 self._TCTRL_l10n_name.SetValue(self.data['l10n_description'])
875 self._TCTRL_name.SetValue(self.data['description'])
876 # disallow changing type on all encounters by editing system name
877 self._TCTRL_name.Enable(False)
878 #-------------------------------------------------------
883 #-------------------------------------------------------
884 # internal API
885 #-------------------------------------------------------
886 # def __register_interests(self):
887 # return
888 #----------------------------------------------------------------
889 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaPnl
890
892
894 try:
895 self.__encounter = kwargs['encounter']
896 del kwargs['encounter']
897 except KeyError:
898 self.__encounter = None
899
900 try:
901 msg = kwargs['msg']
902 del kwargs['msg']
903 except KeyError:
904 msg = None
905
906 wxgEncounterEditAreaPnl.wxgEncounterEditAreaPnl.__init__(self, *args, **kwargs)
907
908 self.refresh(msg = msg)
909 #--------------------------------------------------------
910 # external API
911 #--------------------------------------------------------
913
914 if msg is not None:
915 self._LBL_instructions.SetLabel(msg)
916
917 if encounter is not None:
918 self.__encounter = encounter
919
920 if self.__encounter is None:
921 return True
922
923 # getting the patient via the encounter allows us to act
924 # on any encounter regardless of the currently active patient
925 pat = gmPerson.cPatient(aPK_obj = self.__encounter['pk_patient'])
926 self._LBL_patient.SetLabel(pat.get_description_gender())
927
928 self._PRW_encounter_type.SetText(self.__encounter['l10n_type'], data=self.__encounter['pk_type'])
929
930 fts = gmDateTime.cFuzzyTimestamp (
931 timestamp = self.__encounter['started'],
932 accuracy = gmDateTime.acc_minutes
933 )
934 self._PRW_start.SetText(fts.format_accurately(), data=fts)
935
936 fts = gmDateTime.cFuzzyTimestamp (
937 timestamp = self.__encounter['last_affirmed'],
938 accuracy = gmDateTime.acc_minutes
939 )
940 self._PRW_end.SetText(fts.format_accurately(), data=fts)
941
942 self._TCTRL_rfe.SetValue(gmTools.coalesce(self.__encounter['reason_for_encounter'], ''))
943 self._TCTRL_aoe.SetValue(gmTools.coalesce(self.__encounter['assessment_of_encounter'], ''))
944
945 if self.__encounter['last_affirmed'] == self.__encounter['started']:
946 self._PRW_end.SetFocus()
947 else:
948 self._TCTRL_aoe.SetFocus()
949
950 return True
951 #--------------------------------------------------------
953
954 if self._PRW_encounter_type.GetData() is None:
955 self._PRW_encounter_type.SetBackgroundColour('pink')
956 self._PRW_encounter_type.Refresh()
957 self._PRW_encounter_type.SetFocus()
958 return False
959 self._PRW_encounter_type.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
960 self._PRW_encounter_type.Refresh()
961
962 if not self._PRW_start.is_valid_timestamp():
963 self._PRW_start.SetFocus()
964 return False
965
966 if not self._PRW_end.is_valid_timestamp():
967 self._PRW_end.SetFocus()
968 return False
969
970 return True
971 #--------------------------------------------------------
973 if not self.__is_valid_for_save():
974 return False
975
976 self.__encounter['pk_type'] = self._PRW_encounter_type.GetData()
977 self.__encounter['started'] = self._PRW_start.GetData().get_pydt()
978 self.__encounter['last_affirmed'] = self._PRW_end.GetData().get_pydt()
979 self.__encounter['reason_for_encounter'] = gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), u'')
980 self.__encounter['assessment_of_encounter'] = gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), u'')
981 self.__encounter.save_payload() # FIXME: error checking
982
983 return True
984 #----------------------------------------------------------------
985 # FIXME: use generic dialog 2
987
989 encounter = kwargs['encounter']
990 del kwargs['encounter']
991
992 try:
993 button_defs = kwargs['button_defs']
994 del kwargs['button_defs']
995 except KeyError:
996 button_defs = None
997
998 try:
999 msg = kwargs['msg']
1000 del kwargs['msg']
1001 except KeyError:
1002 msg = None
1003
1004 wxgEncounterEditAreaDlg.wxgEncounterEditAreaDlg.__init__(self, *args, **kwargs)
1005 self.SetSize((450, 280))
1006 self.SetMinSize((450, 280))
1007
1008 if button_defs is not None:
1009 self._BTN_save.SetLabel(button_defs[0][0])
1010 self._BTN_save.SetToolTipString(button_defs[0][1])
1011 self._BTN_close.SetLabel(button_defs[1][0])
1012 self._BTN_close.SetToolTipString(button_defs[1][1])
1013 self.Refresh()
1014
1015 self._PNL_edit_area.refresh(encounter = encounter, msg = msg)
1016
1017 self.Fit()
1018 #--------------------------------------------------------
1025 #================================================================
1026 # episode related widgets/functions
1027 #----------------------------------------------------------------
1029 ea = cEpisodeEditAreaPnl(parent = parent, id = -1)
1030 ea.data = episode
1031 ea.mode = gmTools.coalesce(episode, 'new', 'edit')
1032 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
1033 dlg.SetTitle(gmTools.coalesce(episode, _('Adding a new episode'), _('Editing an episode')))
1034 if dlg.ShowModal() == wx.ID_OK:
1035 return True
1036 return False
1037 #----------------------------------------------------------------
1039
1040 created_new_issue = False
1041
1042 try:
1043 issue = gmEMRStructItems.cHealthIssue(name = episode['description'], patient = episode['pk_patient'])
1044 except gmExceptions.NoSuchBusinessObjectError:
1045 issue = None
1046
1047 if issue is None:
1048 issue = emr.add_health_issue(issue_name = episode['description'])
1049 created_new_issue = True
1050 else:
1051 # issue exists already, so ask user
1052 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1053 parent,
1054 -1,
1055 caption = _('Promoting episode to health issue'),
1056 question = _(
1057 'There already is a health issue\n'
1058 '\n'
1059 ' %s\n'
1060 '\n'
1061 'What do you want to do ?'
1062 ) % issue['description'],
1063 button_defs = [
1064 {'label': _('Use existing'), 'tooltip': _('Move episode into existing health issue'), 'default': False},
1065 {'label': _('Create new'), 'tooltip': _('Create a new health issue with another name'), 'default': True}
1066 ]
1067 )
1068 use_existing = dlg.ShowModal()
1069 dlg.Destroy()
1070
1071 if use_existing == wx.ID_CANCEL:
1072 return
1073
1074 # user wants to create new issue with alternate name
1075 if use_existing == wx.ID_NO:
1076 # loop until name modified but non-empty or cancelled
1077 issue_name = episode['description']
1078 while issue_name == episode['description']:
1079 dlg = wx.TextEntryDialog (
1080 parent = parent,
1081 message = _('Enter a short descriptive name for the new health issue:'),
1082 caption = _('Creating a new health issue ...'),
1083 defaultValue = issue_name,
1084 style = wx.OK | wx.CANCEL | wx.CENTRE
1085 )
1086 decision = dlg.ShowModal()
1087 if decision != wx.ID_OK:
1088 dlg.Destroy()
1089 return
1090 issue_name = dlg.GetValue().strip()
1091 dlg.Destroy()
1092 if issue_name == u'':
1093 issue_name = episode['description']
1094
1095 issue = emr.add_health_issue(issue_name = issue_name)
1096 created_new_issue = True
1097
1098 # eventually move the episode to the issue
1099 if not move_episode_to_issue(episode = episode, target_issue = issue, save_to_backend = True):
1100 # user cancelled the move so delete just-created issue
1101 if created_new_issue:
1102 # shouldn't fail as it is completely new
1103 gmEMRStructItems.delete_health_issue(health_issue = issue)
1104 return
1105
1106 return
1107 #----------------------------------------------------------------
1109 """Prepare changing health issue for an episode.
1110
1111 Checks for two-open-episodes conflict. When this
1112 function succeeds, the pk_health_issue has been set
1113 on the episode instance and the episode should - for
1114 all practical purposes - be ready for save_payload().
1115 """
1116 # episode is closed: should always work
1117 if not episode['episode_open']:
1118 episode['pk_health_issue'] = target_issue['pk_health_issue']
1119 if save_to_backend:
1120 episode.save_payload()
1121 return True
1122
1123 # un-associate: should always work, too
1124 if target_issue is None:
1125 episode['pk_health_issue'] = None
1126 if save_to_backend:
1127 episode.save_payload()
1128 return True
1129
1130 # try closing possibly expired episode on target issue if any
1131 db_cfg = gmCfg.cCfgSQL()
1132 epi_ttl = int(db_cfg.get2 (
1133 option = u'episode.ttl',
1134 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1135 bias = 'user',
1136 default = 60 # 2 months
1137 ))
1138 if target_issue.close_expired_episode(ttl=epi_ttl) is True:
1139 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description']))
1140 existing_epi = target_issue.get_open_episode()
1141
1142 # no more open episode on target issue: should work now
1143 if existing_epi is None:
1144 episode['pk_health_issue'] = target_issue['pk_health_issue']
1145 if save_to_backend:
1146 episode.save_payload()
1147 return True
1148
1149 # don't conflict on SELF ;-)
1150 if existing_epi['pk_episode'] == episode['pk_episode']:
1151 episode['pk_health_issue'] = target_issue['pk_health_issue']
1152 if save_to_backend:
1153 episode.save_payload()
1154 return True
1155
1156 # we got two open episodes at once, ask user
1157 move_range = episode.get_access_range()
1158 exist_range = existing_epi.get_access_range()
1159 question = _(
1160 'You want to associate the running episode:\n\n'
1161 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n'
1162 'with the health issue:\n\n'
1163 ' "%(issue_name)s"\n\n'
1164 'There already is another episode running\n'
1165 'for this health issue:\n\n'
1166 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n'
1167 'However, there can only be one running\n'
1168 'episode per health issue.\n\n'
1169 'Which episode do you want to close ?'
1170 ) % {
1171 'new_epi_name': episode['description'],
1172 'new_epi_start': move_range[0].strftime('%m/%y'),
1173 'new_epi_end': move_range[1].strftime('%m/%y'),
1174 'issue_name': target_issue['description'],
1175 'old_epi_name': existing_epi['description'],
1176 'old_epi_start': exist_range[0].strftime('%m/%y'),
1177 'old_epi_end': exist_range[1].strftime('%m/%y')
1178 }
1179 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1180 parent = None,
1181 id = -1,
1182 caption = _('Resolving two-running-episodes conflict'),
1183 question = question,
1184 button_defs = [
1185 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']},
1186 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']}
1187 ]
1188 )
1189 decision = dlg.ShowModal()
1190
1191 if decision == wx.ID_CANCEL:
1192 # button 3: move cancelled by user
1193 return False
1194
1195 elif decision == wx.ID_YES:
1196 # button 1: close old episode
1197 existing_epi['episode_open'] = False
1198 existing_epi.save_payload()
1199
1200 elif decision == wx.ID_NO:
1201 # button 2: close new episode
1202 episode['episode_open'] = False
1203
1204 else:
1205 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision)
1206
1207 episode['pk_health_issue'] = target_issue['pk_health_issue']
1208 if save_to_backend:
1209 episode.save_payload()
1210 return True
1211 #----------------------------------------------------------------
1213
1214 # FIXME: support pre-selection
1215
1217
1218 episodes = kwargs['episodes']
1219 del kwargs['episodes']
1220
1221 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs)
1222
1223 self.SetTitle(_('Select the episodes you are interested in ...'))
1224 self._LCTRL_items.set_columns([_('Episode'), _('Status'), _('Health Issue')])
1225 self._LCTRL_items.set_string_items (
1226 items = [
1227 [ epi['description'],
1228 gmTools.bool2str(epi['episode_open'], _('ongoing'), u''),
1229 gmTools.coalesce(epi['health_issue'], u'')
1230 ]
1231 for epi in episodes ]
1232 )
1233 self._LCTRL_items.set_column_widths()
1234 self._LCTRL_items.set_data(data = episodes)
1235 #----------------------------------------------------------------
1237 """Let user select an episode *description*.
1238
1239 The user can select an episode description from the previously
1240 used descriptions across all episodes across all patients.
1241
1242 Selection is done with a phrasewheel so the user can
1243 type the episode name and matches will be shown. Typing
1244 "*" will show the entire list of episodes.
1245
1246 If the user types a description not existing yet a
1247 new episode description will be returned.
1248 """
1250
1251 mp = gmMatchProvider.cMatchProvider_SQL2 (
1252 queries = [u"""
1253 select distinct on (description) description, description, 1
1254 from clin.episode
1255 where description %(fragment_condition)s
1256 order by description
1257 limit 30"""
1258 ]
1259 )
1260 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1261 self.matcher = mp
1262 #----------------------------------------------------------------
1264 """Let user select an episode.
1265
1266 The user can select an episode from the existing episodes of a
1267 patient. Selection is done with a phrasewheel so the user
1268 can type the episode name and matches will be shown. Typing
1269 "*" will show the entire list of episodes. Closed episodes
1270 will be marked as such. If the user types an episode name not
1271 in the list of existing episodes a new episode can be created
1272 from it if the programmer activated that feature.
1273
1274 If keyword <patient_id> is set to None or left out the control
1275 will listen to patient change signals and therefore act on
1276 gmPerson.gmCurrentPatient() changes.
1277 """
1279
1280 ctxt = {'ctxt_pat': {'where_part': u'and pk_patient = %(pat)s', 'placeholder': u'pat'}}
1281
1282 mp = gmMatchProvider.cMatchProvider_SQL2 (
1283 queries = [
1284 u"""(
1285
1286 select
1287 pk_episode,
1288 coalesce (
1289 description || ' - ' || health_issue,
1290 description
1291 ) as description,
1292 1 as rank
1293 from
1294 clin.v_pat_episodes
1295 where
1296 episode_open is true and
1297 description %(fragment_condition)s
1298 %(ctxt_pat)s
1299
1300 ) union all (
1301
1302 select
1303 pk_episode,
1304 coalesce (
1305 description || _(' (closed)') || ' - ' || health_issue,
1306 description || _(' (closed)')
1307 ) as description,
1308 2 as rank
1309 from
1310 clin.v_pat_episodes
1311 where
1312 description %(fragment_condition)s and
1313 episode_open is false
1314 %(ctxt_pat)s
1315
1316 )
1317 order by rank, description
1318 limit 30"""
1319 ],
1320 context = ctxt
1321 )
1322
1323 try:
1324 kwargs['patient_id']
1325 except KeyError:
1326 kwargs['patient_id'] = None
1327
1328 if kwargs['patient_id'] is None:
1329 self.use_current_patient = True
1330 self.__register_patient_change_signals()
1331 pat = gmPerson.gmCurrentPatient()
1332 if pat.connected:
1333 mp.set_context('pat', pat.ID)
1334 else:
1335 self.use_current_patient = False
1336 self.__patient_id = int(kwargs['patient_id'])
1337 mp.set_context('pat', self.__patient_id)
1338
1339 del kwargs['patient_id']
1340
1341 gmPhraseWheel.cPhraseWheel.__init__ (
1342 self,
1343 *args,
1344 **kwargs
1345 )
1346 self.matcher = mp
1347 #--------------------------------------------------------
1348 # external API
1349 #--------------------------------------------------------
1351 if self.use_current_patient:
1352 return False
1353 self.__patient_id = int(patient_id)
1354 self.set_context('pat', self.__patient_id)
1355 return True
1356 #--------------------------------------------------------
1358 self.__is_open_for_create_data = is_open # used (only) in _create_data()
1359 gmPhraseWheel.cPhraseWheel.GetData(self, can_create = can_create, as_instance = as_instance)
1360 return self.data
1361 #--------------------------------------------------------
1363
1364 epi_name = self.GetValue().strip()
1365 if epi_name == u'':
1366 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create episode without name.'), beep = True)
1367 _log.debug('cannot create episode without name')
1368 return
1369
1370 if self.use_current_patient:
1371 pat = gmPerson.gmCurrentPatient()
1372 else:
1373 pat = gmPerson.cPatient(aPK_obj = self.__patient_id)
1374
1375 emr = pat.get_emr()
1376 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data)
1377 if epi is None:
1378 self.data = None
1379 else:
1380 self.data = epi['pk_episode']
1381 #--------------------------------------------------------
1384 #--------------------------------------------------------
1385 # internal API
1386 #--------------------------------------------------------
1388 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection')
1389 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1390 #--------------------------------------------------------
1393 #--------------------------------------------------------
1395 if self.use_current_patient:
1396 patient = gmPerson.gmCurrentPatient()
1397 self.set_context('pat', patient.ID)
1398 return True
1399 #----------------------------------------------------------------
1400 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl
1401
1402 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
1403
1405
1406 try:
1407 episode = kwargs['episode']
1408 del kwargs['episode']
1409 except KeyError:
1410 episode = None
1411
1412 wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl.__init__(self, *args, **kwargs)
1413 gmEditArea.cGenericEditAreaMixin.__init__(self)
1414
1415 self.data = episode
1416 #----------------------------------------------------------------
1417 # generic Edit Area mixin API
1418 #----------------------------------------------------------------
1420
1421 errors = False
1422
1423 if len(self._PRW_description.GetValue().strip()) == 0:
1424 errors = True
1425 self._PRW_description.display_as_valid(False)
1426 self._PRW_description.SetFocus()
1427 else:
1428 self._PRW_description.display_as_valid(True)
1429 self._PRW_description.Refresh()
1430
1431 return not errors
1432 #----------------------------------------------------------------
1434
1435 pat = gmPerson.gmCurrentPatient()
1436 emr = pat.get_emr()
1437
1438 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip())
1439 epi['summary'] = self._TCTRL_summary.GetValue().strip()
1440 epi['episode_open'] = not self._CHBOX_closed.IsChecked()
1441 epi['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1442
1443 issue_name = self._PRW_issue.GetValue().strip()
1444 if len(issue_name) != 0:
1445 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
1446 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue'])
1447
1448 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False):
1449 gmDispatcher.send (
1450 signal = 'statustext',
1451 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
1452 epi['description'],
1453 issue['description']
1454 )
1455 )
1456 gmEMRStructItems.delete_episode(episode = epi)
1457 return False
1458
1459 epi.save()
1460
1461 self.data = epi
1462 return True
1463 #----------------------------------------------------------------
1465
1466 self.data['description'] = self._PRW_description.GetValue().strip()
1467 self.data['summary'] = self._TCTRL_summary.GetValue().strip()
1468 self.data['episode_open'] = not self._CHBOX_closed.IsChecked()
1469 self.data['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1470
1471 issue_name = self._PRW_issue.GetValue().strip()
1472 if len(issue_name) != 0:
1473 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
1474 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue'])
1475
1476 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False):
1477 gmDispatcher.send (
1478 signal = 'statustext',
1479 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
1480 self.data['description'],
1481 issue['description']
1482 )
1483 )
1484 return False
1485
1486 self.data.save()
1487 return True
1488 #----------------------------------------------------------------
1490 if self.data is None:
1491 ident = gmPerson.gmCurrentPatient()
1492 else:
1493 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
1494 self._TCTRL_patient.SetValue(ident.get_description_gender())
1495 self._PRW_issue.SetText()
1496 self._PRW_description.SetText()
1497 self._TCTRL_summary.SetValue(u'')
1498 self._PRW_classification.SetText()
1499 self._CHBOX_closed.SetValue(False)
1500 #----------------------------------------------------------------
1502 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
1503 self._TCTRL_patient.SetValue(ident.get_description_gender())
1504
1505 if self.data['pk_health_issue'] is not None:
1506 self._PRW_issue.SetText(self.data['health_issue'], data=self.data['pk_health_issue'])
1507
1508 self._PRW_description.SetText(self.data['description'], data=self.data['description'])
1509
1510 self._TCTRL_summary.SetValue(gmTools.coalesce(self.data['summary'], u''))
1511
1512 if self.data['diagnostic_certainty_classification'] is not None:
1513 self._PRW_classification.SetData(data = self.data['diagnostic_certainty_classification'])
1514
1515 self._CHBOX_closed.SetValue(not self.data['episode_open'])
1516 #----------------------------------------------------------------
1519 #================================================================
1520 # health issue related widgets/functions
1521 #----------------------------------------------------------------
1523 ea = cHealthIssueEditAreaPnl(parent = parent, id = -1)
1524 ea.data = issue
1525 ea.mode = gmTools.coalesce(issue, 'new', 'edit')
1526 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (issue is not None))
1527 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue')))
1528 if dlg.ShowModal() == wx.ID_OK:
1529 return True
1530 return False
1531 #----------------------------------------------------------------
1533
1534 # FIXME: support pre-selection
1535
1537
1538 issues = kwargs['issues']
1539 del kwargs['issues']
1540
1541 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs)
1542
1543 self.SetTitle(_('Select the health issues you are interested in ...'))
1544 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u''])
1545
1546 for issue in issues:
1547 if issue['is_confidential']:
1548 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential'))
1549 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED'))
1550 else:
1551 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'')
1552
1553 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description'])
1554 if issue['clinically_relevant']:
1555 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant'))
1556 if issue['is_active']:
1557 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active'))
1558 if issue['is_cause_of_death']:
1559 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal'))
1560
1561 self._LCTRL_items.set_column_widths()
1562 self._LCTRL_items.set_data(data = issues)
1563 #----------------------------------------------------------------
1565 """Let the user select a health issue.
1566
1567 The user can select a health issue from the existing issues
1568 of a patient. Selection is done with a phrasewheel so the user
1569 can type the issue name and matches will be shown. Typing
1570 "*" will show the entire list of issues. Inactive issues
1571 will be marked as such. If the user types an issue name not
1572 in the list of existing issues a new issue can be created
1573 from it if the programmer activated that feature.
1574
1575 If keyword <patient_id> is set to None or left out the control
1576 will listen to patient change signals and therefore act on
1577 gmPerson.gmCurrentPatient() changes.
1578 """
1580
1581 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}}
1582
1583 mp = gmMatchProvider.cMatchProvider_SQL2 (
1584 # FIXME: consider clin.health_issue.clinically_relevant
1585 queries = [u"""
1586 (select pk_health_issue, description, 1
1587 from clin.v_health_issues where
1588 is_active is true and
1589 description %(fragment_condition)s and
1590 %(ctxt_pat)s
1591 order by description)
1592
1593 union
1594
1595 (select pk_health_issue, description || _(' (inactive)'), 2
1596 from clin.v_health_issues where
1597 is_active is false and
1598 description %(fragment_condition)s and
1599 %(ctxt_pat)s
1600 order by description)"""
1601 ],
1602 context = ctxt
1603 )
1604
1605 try: kwargs['patient_id']
1606 except KeyError: kwargs['patient_id'] = None
1607
1608 if kwargs['patient_id'] is None:
1609 self.use_current_patient = True
1610 self.__register_patient_change_signals()
1611 pat = gmPerson.gmCurrentPatient()
1612 if pat.connected:
1613 mp.set_context('pat', pat.ID)
1614 else:
1615 self.use_current_patient = False
1616 self.__patient_id = int(kwargs['patient_id'])
1617 mp.set_context('pat', self.__patient_id)
1618
1619 del kwargs['patient_id']
1620
1621 gmPhraseWheel.cPhraseWheel.__init__ (
1622 self,
1623 *args,
1624 **kwargs
1625 )
1626 self.matcher = mp
1627 #--------------------------------------------------------
1628 # external API
1629 #--------------------------------------------------------
1631 if self.use_current_patient:
1632 return False
1633 self.__patient_id = int(patient_id)
1634 self.set_context('pat', self.__patient_id)
1635 return True
1636 #--------------------------------------------------------
1638 if self.data is None:
1639 if can_create:
1640 issue_name = self.GetValue().strip()
1641
1642 if self.use_current_patient:
1643 pat = gmPerson.gmCurrentPatient()
1644 else:
1645 pat = gmPerson.cPatient(aPK_obj=self.__patient_id)
1646 emr = pat.get_emr()
1647
1648 issue = emr.add_health_issue(issue_name = issue_name)
1649 if issue is None:
1650 self.data = None
1651 else:
1652 self.data = issue['pk_health_issue']
1653
1654 return gmPhraseWheel.cPhraseWheel.GetData(self)
1655 #--------------------------------------------------------
1656 # internal API
1657 #--------------------------------------------------------
1659 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection')
1660 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1661 #--------------------------------------------------------
1664 #--------------------------------------------------------
1666 if self.use_current_patient:
1667 patient = gmPerson.gmCurrentPatient()
1668 self.set_context('pat', patient.ID)
1669 return True
1670 #------------------------------------------------------------
1672
1674 try:
1675 msg = kwargs['message']
1676 except KeyError:
1677 msg = None
1678 del kwargs['message']
1679 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs)
1680 if msg is not None:
1681 self._lbl_message.SetLabel(label=msg)
1682 #--------------------------------------------------------
1693 #------------------------------------------------------------
1694 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl
1695
1696 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
1697 """Panel encapsulating health issue edit area functionality."""
1698
1700
1701 try:
1702 issue = kwargs['issue']
1703 except KeyError:
1704 issue = None
1705
1706 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs)
1707
1708 gmEditArea.cGenericEditAreaMixin.__init__(self)
1709
1710 # FIXME: include more sources: coding systems/other database columns
1711 mp = gmMatchProvider.cMatchProvider_SQL2 (
1712 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"]
1713 )
1714 mp.setThresholds(1, 3, 5)
1715 self._PRW_condition.matcher = mp
1716
1717 mp = gmMatchProvider.cMatchProvider_SQL2 (
1718 queries = [u"""
1719 select distinct on (grouping) grouping, grouping from (
1720
1721 select rank, grouping from ((
1722
1723 select
1724 grouping,
1725 1 as rank
1726 from
1727 clin.health_issue
1728 where
1729 grouping %%(fragment_condition)s
1730 and
1731 (select True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter)
1732
1733 ) union (
1734
1735 select
1736 grouping,
1737 2 as rank
1738 from
1739 clin.health_issue
1740 where
1741 grouping %%(fragment_condition)s
1742
1743 )) as union_result
1744
1745 order by rank
1746
1747 ) as order_result
1748
1749 limit 50""" % gmPerson.gmCurrentPatient().ID
1750 ]
1751 )
1752 mp.setThresholds(1, 3, 5)
1753 self._PRW_grouping.matcher = mp
1754
1755 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted)
1756 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted)
1757
1758 self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted)
1759 self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted)
1760
1761 self._PRW_year_noted.Enable(True)
1762
1763 self.data = issue
1764 #----------------------------------------------------------------
1765 # generic Edit Area mixin API
1766 #----------------------------------------------------------------
1768
1769 if self._PRW_condition.GetValue().strip() == '':
1770 self._PRW_condition.display_as_valid(False)
1771 self._PRW_condition.SetFocus()
1772 return False
1773 self._PRW_condition.display_as_valid(True)
1774 self._PRW_condition.Refresh()
1775
1776 # FIXME: sanity check age/year diagnosed
1777 age_noted = self._PRW_age_noted.GetValue().strip()
1778 if age_noted != '':
1779 if gmDateTime.str2interval(str_interval = age_noted) is None:
1780 self._PRW_age_noted.display_as_valid(False)
1781 self._PRW_age_noted.SetFocus()
1782 return False
1783 self._PRW_age_noted.display_as_valid(True)
1784
1785 return True
1786 #----------------------------------------------------------------
1788 pat = gmPerson.gmCurrentPatient()
1789 emr = pat.get_emr()
1790
1791 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip())
1792
1793 side = u''
1794 if self._ChBOX_left.GetValue():
1795 side += u's'
1796 if self._ChBOX_right.GetValue():
1797 side += u'd'
1798 issue['laterality'] = side
1799
1800 issue['summary'] = self._TCTRL_summary.GetValue().strip()
1801 issue['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1802 issue['grouping'] = self._PRW_grouping.GetValue().strip()
1803 issue['is_active'] = self._ChBOX_active.GetValue()
1804 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue()
1805 issue['is_confidential'] = self._ChBOX_confidential.GetValue()
1806 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue()
1807
1808 age_noted = self._PRW_age_noted.GetData()
1809 if age_noted is not None:
1810 issue['age_noted'] = age_noted
1811
1812 issue.save()
1813
1814 self.data = issue
1815 return True
1816 #----------------------------------------------------------------
1818
1819 self.data['description'] = self._PRW_condition.GetValue().strip()
1820
1821 side = u''
1822 if self._ChBOX_left.GetValue():
1823 side += u's'
1824 if self._ChBOX_right.GetValue():
1825 side += u'd'
1826 self.data['laterality'] = side
1827
1828 self.data['summary'] = self._TCTRL_summary.GetValue().strip()
1829 self.data['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1830 self.data['grouping'] = self._PRW_grouping.GetValue().strip()
1831 self.data['is_active'] = bool(self._ChBOX_active.GetValue())
1832 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue())
1833 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue())
1834 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue())
1835
1836 age_noted = self._PRW_age_noted.GetData()
1837 if age_noted is not None:
1838 self.data['age_noted'] = age_noted
1839
1840 self.data.save()
1841
1842 # FIXME: handle is_operation
1843 return True
1844 #----------------------------------------------------------------
1846 self._PRW_condition.SetText()
1847 self._ChBOX_left.SetValue(0)
1848 self._ChBOX_right.SetValue(0)
1849 self._PRW_classification.SetText()
1850 self._PRW_grouping.SetText()
1851 self._TCTRL_summary.SetValue(u'')
1852 self._PRW_age_noted.SetText()
1853 self._PRW_year_noted.SetText()
1854 self._ChBOX_active.SetValue(0)
1855 self._ChBOX_relevant.SetValue(1)
1856 self._ChBOX_is_operation.SetValue(0)
1857 self._ChBOX_confidential.SetValue(0)
1858 self._ChBOX_caused_death.SetValue(0)
1859
1860 return True
1861 #----------------------------------------------------------------
1863 self._PRW_condition.SetText(self.data['description'])
1864
1865 lat = gmTools.coalesce(self.data['laterality'], '')
1866 if lat.find('s') == -1:
1867 self._ChBOX_left.SetValue(0)
1868 else:
1869 self._ChBOX_left.SetValue(1)
1870 if lat.find('d') == -1:
1871 self._ChBOX_right.SetValue(0)
1872 else:
1873 self._ChBOX_right.SetValue(1)
1874
1875 self._PRW_classification.SetData(data = self.data['diagnostic_certainty_classification'])
1876 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u''))
1877 self._TCTRL_summary.SetValue(gmTools.coalesce(self.data['summary'], u''))
1878
1879 if self.data['age_noted'] is None:
1880 self._PRW_age_noted.SetText()
1881 else:
1882 self._PRW_age_noted.SetText (
1883 value = '%sd' % self.data['age_noted'].days,
1884 data = self.data['age_noted']
1885 )
1886
1887 self._ChBOX_active.SetValue(self.data['is_active'])
1888 self._ChBOX_relevant.SetValue(self.data['clinically_relevant'])
1889 self._ChBOX_is_operation.SetValue(0) # FIXME
1890 self._ChBOX_confidential.SetValue(self.data['is_confidential'])
1891 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death'])
1892
1893 # this dance should assure self._PRW_year_noted gets set -- but it doesn't ...
1894 # self._PRW_age_noted.SetFocus()
1895 # self._PRW_condition.SetFocus()
1896
1897 return True
1898 #----------------------------------------------------------------
1901 #--------------------------------------------------------
1902 # internal helpers
1903 #--------------------------------------------------------
1905
1906 if not self._PRW_age_noted.IsModified():
1907 return True
1908
1909 str_age = self._PRW_age_noted.GetValue().strip()
1910
1911 if str_age == u'':
1912 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1913 return True
1914
1915 age = gmDateTime.str2interval(str_interval = str_age)
1916
1917 if age is None:
1918 gmDispatcher.send(signal='statustext', msg=_('Cannot parse [%s] into valid interval.') % str_age)
1919 self._PRW_age_noted.SetBackgroundColour('pink')
1920 self._PRW_age_noted.Refresh()
1921 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1922 return True
1923
1924 pat = gmPerson.gmCurrentPatient()
1925 if pat['dob'] is not None:
1926 max_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob']
1927
1928 if age >= max_age:
1929 gmDispatcher.send (
1930 signal = 'statustext',
1931 msg = _(
1932 'Health issue cannot have been noted at age %s. Patient is only %s old.'
1933 ) % (age, pat.get_medical_age())
1934 )
1935 self._PRW_age_noted.SetBackgroundColour('pink')
1936 self._PRW_age_noted.Refresh()
1937 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1938 return True
1939
1940 self._PRW_age_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
1941 self._PRW_age_noted.Refresh()
1942 self._PRW_age_noted.SetData(data=age)
1943
1944 if pat['dob'] is not None:
1945 fts = gmDateTime.cFuzzyTimestamp (
1946 timestamp = pat['dob'] + age,
1947 accuracy = gmDateTime.acc_months
1948 )
1949 wx.CallAfter(self._PRW_year_noted.SetText, str(fts), fts)
1950 # if we do this we will *always* navigate there, regardless of TAB vs ALT-TAB
1951 #wx.CallAfter(self._ChBOX_active.SetFocus)
1952 # if we do the following instead it will take us to the save/update button ...
1953 #wx.CallAfter(self.Navigate)
1954
1955 return True
1956 #--------------------------------------------------------
1958
1959 if not self._PRW_year_noted.IsModified():
1960 return True
1961
1962 year_noted = self._PRW_year_noted.GetData()
1963
1964 if year_noted is None:
1965 if self._PRW_year_noted.GetValue().strip() == u'':
1966 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1967 return True
1968 self._PRW_year_noted.SetBackgroundColour('pink')
1969 self._PRW_year_noted.Refresh()
1970 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1971 return True
1972
1973 year_noted = year_noted.get_pydt()
1974
1975 if year_noted >= pydt.datetime.now(tz=year_noted.tzinfo):
1976 gmDispatcher.send(signal='statustext', msg=_('Condition diagnosed in the future.'))
1977 self._PRW_year_noted.SetBackgroundColour('pink')
1978 self._PRW_year_noted.Refresh()
1979 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1980 return True
1981
1982 self._PRW_year_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
1983 self._PRW_year_noted.Refresh()
1984
1985 pat = gmPerson.gmCurrentPatient()
1986 if pat['dob'] is not None:
1987 issue_age = year_noted - pat['dob']
1988 str_age = gmDateTime.format_interval_medically(interval = issue_age)
1989 wx.CallAfter(self._PRW_age_noted.SetText, str_age, issue_age)
1990
1991 return True
1992 #--------------------------------------------------------
1996 #--------------------------------------------------------
2000 #================================================================
2001 # diagnostic certainty related widgets/functions
2002 #----------------------------------------------------------------
2004
2006
2007 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2008
2009 self.selection_only = False # can be NULL, too
2010
2011 mp = gmMatchProvider.cMatchProvider_FixedList (
2012 aSeq = [
2013 {'data': u'A', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1},
2014 {'data': u'B', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1},
2015 {'data': u'C', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1},
2016 {'data': u'D', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1}
2017 ]
2018 )
2019 mp.setThresholds(1, 2, 4)
2020 self.matcher = mp
2021
2022 self.SetToolTipString(_(
2023 "The diagnostic classification or grading of this assessment.\n"
2024 "\n"
2025 "This documents how certain one is about this being a true diagnosis."
2026 ))
2027 #================================================================
2028 # MAIN
2029 #----------------------------------------------------------------
2030 if __name__ == '__main__':
2031
2032 #================================================================
2034 """
2035 Test application for testing EMR struct widgets
2036 """
2037 #--------------------------------------------------------
2039 """
2040 Create test application UI
2041 """
2042 frame = wx.Frame (
2043 None,
2044 -4,
2045 'Testing EMR struct widgets',
2046 size=wx.Size(600, 400),
2047 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
2048 )
2049 filemenu= wx.Menu()
2050 filemenu.AppendSeparator()
2051 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application")
2052
2053 # Creating the menubar.
2054 menuBar = wx.MenuBar()
2055 menuBar.Append(filemenu,"&File")
2056
2057 frame.SetMenuBar(menuBar)
2058
2059 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"),
2060 wx.DefaultPosition, wx.DefaultSize, 0 )
2061
2062 # event handlers
2063 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow)
2064
2065 # patient EMR
2066 self.__pat = gmPerson.gmCurrentPatient()
2067
2068 frame.Show(1)
2069 return 1
2070 #--------------------------------------------------------
2076 #----------------------------------------------------------------
2078 app = wx.PyWidgetTester(size = (200, 300))
2079 emr = pat.get_emr()
2080 enc = emr.active_encounter
2081 #enc = gmEMRStructItems.cEncounter(1)
2082 pnl = cEncounterEditAreaPnl(app.frame, -1, encounter=enc)
2083 app.frame.Show(True)
2084 app.MainLoop()
2085 return
2086 #----------------------------------------------------------------
2088 app = wx.PyWidgetTester(size = (200, 300))
2089 emr = pat.get_emr()
2090 enc = emr.active_encounter
2091 #enc = gmEMRStructItems.cEncounter(1)
2092
2093 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc)
2094 dlg.ShowModal()
2095
2096 # pnl = cEncounterEditAreaDlg(app.frame, -1, encounter=enc)
2097 # app.frame.Show(True)
2098 # app.MainLoop()
2099 #----------------------------------------------------------------
2101 app = wx.PyWidgetTester(size = (200, 300))
2102 emr = pat.get_emr()
2103 epi = emr.get_episodes()[0]
2104 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi)
2105 app.frame.Show(True)
2106 app.MainLoop()
2107 #----------------------------------------------------------------
2109 app = wx.PyWidgetTester(size = (200, 300))
2110 emr = pat.get_emr()
2111 epi = emr.get_episodes()[0]
2112 edit_episode(parent=app.frame, episode=epi)
2113 #----------------------------------------------------------------
2115 app = wx.PyWidgetTester(size = (400, 40))
2116 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2117 app.MainLoop()
2118 #----------------------------------------------------------------
2120 app = wx.PyWidgetTester(size = (400, 40))
2121 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2122 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID)
2123 app.MainLoop()
2124 #----------------------------------------------------------------
2126 app = wx.PyWidgetTester(size = (200, 300))
2127 edit_health_issue(parent=app.frame, issue=None)
2128 #----------------------------------------------------------------
2130 app = wx.PyWidgetTester(size = (200, 300))
2131 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400))
2132 app.MainLoop()
2133 #----------------------------------------------------------------
2137 #================================================================
2138
2139 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2140
2141 gmI18N.activate_locale()
2142 gmI18N.install_domain()
2143 gmDateTime.init()
2144
2145 # obtain patient
2146 pat = gmPersonSearch.ask_for_patient()
2147 if pat is None:
2148 print "No patient. Exiting gracefully..."
2149 sys.exit(0)
2150 gmPatSearchWidgets.set_active_patient(patient=pat)
2151
2152 # try:
2153 # lauch emr dialogs test application
2154 # app = testapp(0)
2155 # app.MainLoop()
2156 # except StandardError:
2157 # _log.exception("unhandled exception caught !")
2158 # but re-raise them
2159 # raise
2160
2161 #test_encounter_edit_area_panel()
2162 #test_encounter_edit_area_dialog()
2163 #test_epsiode_edit_area_pnl()
2164 #test_episode_edit_area_dialog()
2165 #test_health_issue_edit_area_dlg()
2166 #test_episode_selection_prw()
2167 #test_hospital_stay_prw()
2168 test_edit_procedure()
2169
2170 #================================================================
2171
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jan 10 03:56:06 2011 | http://epydoc.sourceforge.net |