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