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
15 import sys, re, datetime as pydt, logging, time
16
17
18
19 import wx
20 import wx.lib.pubsub as wxps
21
22
23
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
37
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
109
110 from Gnumed.wxGladeWidgets import wxgProcedureEAPnl
111
112 -class cProcedureEAPnl(wxgProcedureEAPnl.wxgProcedureEAPnl, gmEditArea.cGenericEditAreaMixin):
113
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
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
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
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
180
192
215
216
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
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
368
380
381
382
387
403
404
405
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
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
523
524
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
569
580
585
586
598
600 print "this was not expected to be used in this edit area"
601
602
603
612
613 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaDlg
614
616 if parent is None:
617 parent = wx.GetApp().GetTopWindow()
618
619
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
627 -def select_encounters(parent=None, patient=None, single_selection=True, encounters=None):
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
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
796
801
802
803
804
805
835
848
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
868 self._TCTRL_name.Enable(False)
869
871 self._TCTRL_l10n_name.SetValue(self.data['l10n_description'])
872 self._TCTRL_name.SetValue(self.data['description'])
873 self._TCTRL_name.Enable(True)
874
875
876
877
878
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
902
903 - def refresh(self, encounter=None, msg=None):
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()
973
974 return True
975
976
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
1018
1028
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
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
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
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
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
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
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
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
1184 return False
1185
1186 elif decision == wx.ID_YES:
1187
1188 existing_epi['episode_open'] = False
1189 existing_epi.save_payload()
1190
1191 elif decision == wx.ID_NO:
1192
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
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
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
1348 - def GetData(self, can_create=False, as_instance=False, is_open=False):
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
1377
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
1407
1408
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
1491
1507
1509 self._refresh_as_new()
1510
1511
1512
1522
1524
1525
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
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
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
1628 - def GetData(self, can_create=False, is_open=False):
1646
1647
1648
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
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
1757
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
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)
1881 self._ChBOX_confidential.SetValue(self.data['is_confidential'])
1882 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death'])
1883
1884
1885
1886
1887
1888 return True
1889
1891 return self._refresh_as_new()
1892
1893
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
1942
1943
1944
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
1985 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1986 return True
1987
1989 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1990 return True
1991
1992
1993
1995
1997
1998 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1999
2000 self.selection_only = False
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
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
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
2054 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow)
2055
2056
2057 self.__pat = gmPerson.gmCurrentPatient()
2058
2059 frame.Show(1)
2060 return 1
2061
2063 """
2064 Close test aplication
2065 """
2066 self.ExitMainLoop ()
2067
2069 app = wx.PyWidgetTester(size = (200, 300))
2070 emr = pat.get_emr()
2071 enc = emr.active_encounter
2072
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
2083
2084 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc)
2085 dlg.ShowModal()
2086
2087
2088
2089
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
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
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
2126 app = wx.PyWidgetTester(size = (200, 300))
2127 edit_procedure(parent=app.frame)
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
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
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159 test_edit_procedure()
2160
2161
2162