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_hospital_stay.set_context(context = 'pat', val = gmPerson.gmCurrentPatient().ID)
126 self._PRW_location.add_callback_on_lose_focus(callback = self._on_location_lost_focus)
127 self._DPRW_date.add_callback_on_lose_focus(callback = self._on_start_lost_focus)
128 self._DPRW_end.add_callback_on_lose_focus(callback = self._on_end_lost_focus)
129
130
131 mp = gmMatchProvider.cMatchProvider_SQL2 (
132 queries = [
133 u"""
134 SELECT DISTINCT ON (data) data, location
135 FROM (
136 SELECT
137 clin_where as data,
138 clin_where as location
139 FROM
140 clin.procedure
141 WHERE
142 clin_where %(fragment_condition)s
143
144 UNION ALL
145
146 SELECT
147 narrative as data,
148 narrative as location
149 FROM
150 clin.hospital_stay
151 WHERE
152 narrative %(fragment_condition)s
153 ) as union_result
154 ORDER BY data
155 LIMIT 25"""
156 ]
157 )
158 mp.setThresholds(2, 4, 6)
159 self._PRW_location.matcher = mp
160
161
162 mp = gmMatchProvider.cMatchProvider_SQL2 (
163 queries = [
164 u"""
165 select distinct on (narrative) narrative, narrative
166 from clin.procedure
167 where narrative %(fragment_condition)s
168 order by narrative
169 limit 25
170 """ ]
171 )
172 mp.setThresholds(2, 4, 6)
173 self._PRW_procedure.matcher = mp
174
176 stay = self._PRW_hospital_stay.GetData()
177 if stay is None:
178 self._PRW_hospital_stay.SetText()
179 self._PRW_location.Enable(True)
180 self._PRW_episode.Enable(True)
181 self._LBL_hospital_details.SetLabel(u'')
182 else:
183 self._PRW_location.SetText()
184 self._PRW_location.Enable(False)
185 self._PRW_episode.SetText()
186 self._PRW_episode.Enable(False)
187 self._LBL_hospital_details.SetLabel(gmEMRStructItems.cHospitalStay(aPK_obj = stay).format())
188
190 if self._PRW_location.GetValue().strip() == u'':
191 self._PRW_hospital_stay.Enable(True)
192
193 else:
194 self._PRW_hospital_stay.SetText()
195 self._PRW_hospital_stay.Enable(False)
196 self._PRW_hospital_stay.display_as_valid(True)
197
198
210
233
234
235
237
238 has_errors = False
239
240 if not self._DPRW_date.is_valid_timestamp():
241 self._DPRW_date.display_as_valid(False)
242 has_errors = True
243 else:
244 self._DPRW_date.display_as_valid(True)
245
246 end = self._DPRW_end.GetData()
247 self._DPRW_end.display_as_valid(True)
248 if end is not None:
249 end = end.get_pydt()
250 start = self._DPRW_end.GetData()
251 if start is not None:
252 start = start.get_pydt()
253 if end < start:
254 has_errors = True
255 self._DPRW_end.display_as_valid(False)
256 if self._CHBOX_ongoing.IsChecked():
257 now = gmDateTime.pydt_now_here()
258 if end < now:
259 has_errors = True
260 self._DPRW_end.display_as_valid(False)
261
262 if self._PRW_hospital_stay.GetData() is None:
263 if self._PRW_episode.GetData() is None:
264 self._PRW_episode.display_as_valid(False)
265 has_errors = True
266 else:
267 self._PRW_episode.display_as_valid(True)
268 else:
269 self._PRW_episode.display_as_valid(True)
270
271 if (self._PRW_procedure.GetValue() is None) or (self._PRW_procedure.GetValue().strip() == u''):
272 self._PRW_procedure.display_as_valid(False)
273 has_errors = True
274 else:
275 self._PRW_procedure.display_as_valid(True)
276
277 invalid_location = (
278 (self._PRW_hospital_stay.GetData() is None) and (self._PRW_location.GetValue().strip() == u'')
279 or
280 (self._PRW_hospital_stay.GetData() is not None) and (self._PRW_location.GetValue().strip() != u'')
281 )
282 if invalid_location:
283 self._PRW_hospital_stay.display_as_valid(False)
284 self._PRW_location.display_as_valid(False)
285 has_errors = True
286 else:
287 self._PRW_hospital_stay.display_as_valid(True)
288 self._PRW_location.display_as_valid(True)
289
290 wxps.Publisher().sendMessage (
291 topic = 'statustext',
292 data = {'msg': _('Cannot save procedure.'), 'beep': True}
293 )
294
295 return (has_errors is False)
296
298
299 pat = gmPerson.gmCurrentPatient()
300 emr = pat.get_emr()
301
302 if self._PRW_hospital_stay.GetData() is None:
303 stay = None
304 epi = self._PRW_episode.GetData()
305 loc = self._PRW_location.GetValue().strip()
306 else:
307 stay = self._PRW_hospital_stay.GetData()
308 epi = gmEMRStructItems.cHospitalStay(aPK_obj = stay)['pk_episode']
309 loc = None
310
311 proc = emr.add_performed_procedure (
312 episode = epi,
313 location = loc,
314 hospital_stay = stay,
315 procedure = self._PRW_procedure.GetValue().strip()
316 )
317
318 proc['clin_when'] = self._DPRW_date.data.get_pydt()
319 if self._DPRW_end.GetData() is None:
320 proc['clin_end'] = None
321 else:
322 proc['clin_end'] = self._DPRW_end.GetData().get_pydt()
323 proc['is_ongoing'] = self._CHBOX_ongoing.IsChecked()
324 proc.save()
325
326 self.data = proc
327
328 return True
329
331 self.data['clin_when'] = self._DPRW_date.data.get_pydt()
332
333 if self._DPRW_end.GetData() is None:
334 self.data['clin_end'] = None
335 else:
336 self.data['clin_end'] = self._DPRW_end.GetData().get_pydt()
337
338 self.data['is_ongoing'] = self._CHBOX_ongoing.IsChecked()
339
340 if self._PRW_hospital_stay.GetData() is None:
341 self.data['pk_hospital_stay'] = None
342 self.data['clin_where'] = self._PRW_location.GetValue().strip()
343 self.data['pk_episode'] = self._PRW_episode.GetData()
344 else:
345 self.data['pk_hospital_stay'] = self._PRW_hospital_stay.GetData()
346 self.data['clin_where'] = None
347 stay = gmEMRStructItems.cHospitalStay(aPK_obj = self._PRW_hospital_stay.GetData())
348 self.data['pk_episode'] = stay['pk_episode']
349
350 self.data['performed_procedure'] = self._PRW_procedure.GetValue().strip()
351
352 self.data.save()
353 return True
354
356 self._DPRW_date.SetText()
357 self._DPRW_end.SetText()
358 self._CHBOX_ongoing.SetValue(False)
359 self._CHBOX_ongoing.Enable(True)
360 self._PRW_hospital_stay.SetText()
361 self._PRW_location.SetText()
362 self._PRW_episode.SetText()
363 self._PRW_procedure.SetText()
364
365 self._PRW_procedure.SetFocus()
366
394
406
407
408
413
429
430
431
442
443 def delete(stay=None):
444 if gmEMRStructItems.delete_hospital_stay(stay = stay['pk_hospital_stay']):
445 return True
446 gmDispatcher.send (
447 signal = u'statustext',
448 msg = _('Cannot delete hospital stay.'),
449 beep = True
450 )
451 return False
452
453 def refresh(lctrl):
454 stays = emr.get_hospital_stays()
455 items = [
456 [
457 s['admission'].strftime('%Y-%m-%d'),
458 gmTools.coalesce(s['discharge'], u''),
459 s['episode'],
460 gmTools.coalesce(s['hospital'], u'')
461 ] for s in stays
462 ]
463 lctrl.set_string_items(items = items)
464 lctrl.set_data(data = stays)
465
466 gmListWidgets.get_choices_from_list (
467 parent = parent,
468 msg = _('\nSelect the hospital stay you want to edit !\n'),
469 caption = _('Editing hospital stays ...'),
470 columns = [_('Admission'), _('Discharge'), _('Reason'), _('Hospital')],
471 single_selection = True,
472 edit_callback = edit,
473 new_callback = edit,
474 delete_callback = delete,
475 refresh_callback = refresh
476 )
477
478
490
492 """Phrasewheel to allow selection of a hospital stay.
493 """
495
496 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs)
497
498 ctxt = {'ctxt_pat': {'where_part': u'pk_patient = %(pat)s and', 'placeholder': u'pat'}}
499
500 mp = gmMatchProvider.cMatchProvider_SQL2 (
501 queries = [
502 u"""
503 select
504 pk_hospital_stay,
505 descr
506 from (
507 select distinct on (pk_hospital_stay)
508 pk_hospital_stay,
509 descr
510 from
511 (select
512 pk_hospital_stay,
513 (
514 to_char(admission, 'YYYY-Mon-DD')
515 || coalesce((' (' || hospital || '):'), ': ')
516 || episode
517 || coalesce((' (' || health_issue || ')'), '')
518 ) as descr
519 from
520 clin.v_pat_hospital_stays
521 where
522 %(ctxt_pat)s
523
524 hospital %(fragment_condition)s
525 or
526 episode %(fragment_condition)s
527 or
528 health_issue %(fragment_condition)s
529 ) as the_stays
530 ) as distinct_stays
531 order by descr
532 limit 25
533 """ ],
534 context = ctxt
535 )
536 mp.setThresholds(3, 4, 6)
537 mp.set_context('pat', gmPerson.gmCurrentPatient().ID)
538
539 self.matcher = mp
540 self.selection_only = True
541
542 from Gnumed.wxGladeWidgets import wxgHospitalStayEditAreaPnl
543
544 -class cHospitalStayEditAreaPnl(wxgHospitalStayEditAreaPnl.wxgHospitalStayEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
545
549
550
551
553 if not self._DP_admission.GetValue().IsValid():
554 self._DP_admission.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
555 wxps.Publisher().sendMessage (
556 topic = 'statustext',
557 data = {'msg': _('Missing admission data. Cannot save hospital stay.'), 'beep': True}
558 )
559 return False
560 else:
561 self._DP_admission.SetBackgroundColour(gmPhraseWheel.color_prw_valid)
562
563 if self._DP_discharge.GetValue().IsValid():
564 if not self._DP_discharge.GetValue().IsLaterThan(self._DP_admission.GetValue()):
565 self._DP_discharge.SetBackgroundColour(gmPhraseWheel.color_prw_invalid)
566 wxps.Publisher().sendMessage (
567 topic = 'statustext',
568 data = {'msg': _('Discharge date must be empty or later than admission. Cannot save hospital stay.'), 'beep': True}
569 )
570 return False
571
572 if self._PRW_episode.GetValue().strip() == u'':
573 self._PRW_episode.display_as_valid(False)
574 wxps.Publisher().sendMessage (
575 topic = 'statustext',
576 data = {'msg': _('Must select an episode or enter a name for a new one. Cannot save hospital stay.'), 'beep': True}
577 )
578 return False
579
580 return True
581
595
606
611
612
624
626 print "this was not expected to be used in this edit area"
627
628
629
638
639 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaDlg
640
642 if parent is None:
643 parent = wx.GetApp().GetTopWindow()
644
645
646 dlg = cEncounterEditAreaDlg(parent = parent, encounter = encounter)
647 if dlg.ShowModal() == wx.ID_OK:
648 dlg.Destroy()
649 return True
650 dlg.Destroy()
651 return False
652
653 -def select_encounters(parent=None, patient=None, single_selection=True, encounters=None, ignore_OK_button=False):
654
655 if patient is None:
656 patient = gmPerson.gmCurrentPatient()
657
658 if not patient.connected:
659 gmDispatcher.send(signal = 'statustext', msg = _('Cannot list encounters. No active patient.'))
660 return False
661
662 if parent is None:
663 parent = wx.GetApp().GetTopWindow()
664
665 emr = patient.get_emr()
666
667
668 def refresh(lctrl):
669 if encounters is None:
670 encs = emr.get_encounters()
671 else:
672 encs = encounters
673
674 items = [
675 [
676 e['started'].strftime('%x %H:%M'),
677 e['last_affirmed'].strftime('%H:%M'),
678 e['l10n_type'],
679 gmTools.coalesce(e['reason_for_encounter'], u''),
680 gmTools.coalesce(e['assessment_of_encounter'], u''),
681 gmTools.bool2subst(e.has_clinical_data(), u'', gmTools.u_checkmark_thin),
682 e['pk_encounter']
683 ] for e in encs
684 ]
685
686 lctrl.set_string_items(items = items)
687 lctrl.set_data(data = encs)
688
689 def new():
690 enc = gmEMRStructItems.create_encounter(fk_patient = patient.ID)
691 return edit_encounter(parent = parent, encounter = enc)
692
693 def edit(enc=None):
694 return edit_encounter(parent = parent, encounter = enc)
695
696 return gmListWidgets.get_choices_from_list (
697 parent = parent,
698 msg = _('\nBelow find the relevant encounters of the patient.\n'),
699 caption = _('Encounters ...'),
700 columns = [_('Started'), _('Ended'), _('Type'), _('Reason for Encounter'), _('Assessment of Encounter'), _('Empty'), '#'],
701 can_return_empty = True,
702 single_selection = single_selection,
703 refresh_callback = refresh,
704 edit_callback = edit,
705 new_callback = new,
706 ignore_OK_button = ignore_OK_button
707 )
708
710 """This is used as the callback when the EMR detects that the
711 patient was here rather recently and wants to ask the
712 provider whether to continue the recent encounter.
713 """
714 if parent is None:
715 parent = wx.GetApp().GetTopWindow()
716
717 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
718 parent = None,
719 id = -1,
720 caption = caption,
721 question = msg,
722 button_defs = [
723 {'label': _('Continue'), 'tooltip': _('Continue the existing recent encounter.'), 'default': False},
724 {'label': _('Start new'), 'tooltip': _('Start a new encounter. The existing one will be closed.'), 'default': True}
725 ],
726 show_checkbox = False
727 )
728
729 result = dlg.ShowModal()
730 dlg.Destroy()
731
732 if result == wx.ID_YES:
733 return True
734
735 return False
736
738
739 if parent is None:
740 parent = wx.GetApp().GetTopWindow()
741
742
743 def edit(enc_type=None):
744 return edit_encounter_type(parent = parent, encounter_type = enc_type)
745
746 def delete(enc_type=None):
747 if gmEMRStructItems.delete_encounter_type(description = enc_type['description']):
748 return True
749 gmDispatcher.send (
750 signal = u'statustext',
751 msg = _('Cannot delete encounter type [%s]. It is in use.') % enc_type['l10n_description'],
752 beep = True
753 )
754 return False
755
756 def refresh(lctrl):
757 enc_types = gmEMRStructItems.get_encounter_types()
758 lctrl.set_string_items(items = enc_types)
759
760 gmListWidgets.get_choices_from_list (
761 parent = parent,
762 msg = _('\nSelect the encounter type you want to edit !\n'),
763 caption = _('Managing encounter types ...'),
764 columns = [_('Local name'), _('Encounter type')],
765 single_selection = True,
766 edit_callback = edit,
767 new_callback = edit,
768 delete_callback = delete,
769 refresh_callback = refresh
770 )
771
781
783 """Phrasewheel to allow selection of encounter type.
784
785 - user input interpreted as encounter type in English or local language
786 - data returned is pk of corresponding encounter type or None
787 """
789
790 gmPhraseWheel.cPhraseWheel.__init__ (self, *args, **kwargs)
791
792 mp = gmMatchProvider.cMatchProvider_SQL2 (
793 queries = [
794 u"""
795 select pk, l10n_description from (
796 select distinct on (pk) * from (
797 (select
798 pk,
799 _(description) as l10n_description,
800 1 as rank
801 from
802 clin.encounter_type
803 where
804 _(description) %(fragment_condition)s
805
806 ) union all (
807
808 select
809 pk,
810 _(description) as l10n_description,
811 2 as rank
812 from
813 clin.encounter_type
814 where
815 description %(fragment_condition)s
816 )
817 ) as q_distinct_pk
818 ) as q_ordered order by rank, l10n_description
819 """ ]
820 )
821 mp.setThresholds(2, 4, 6)
822
823 self.matcher = mp
824 self.selection_only = True
825 self.picklist_delay = 50
826
828
833
834
835
836
837
867
880
890
892 self._TCTRL_l10n_name.SetValue(u'')
893 self._TCTRL_name.SetValue(u'')
894 self._TCTRL_name.Enable(True)
895
897 self._TCTRL_l10n_name.SetValue(self.data['l10n_description'])
898 self._TCTRL_name.SetValue(self.data['description'])
899
900 self._TCTRL_name.Enable(False)
901
903 self._TCTRL_l10n_name.SetValue(self.data['l10n_description'])
904 self._TCTRL_name.SetValue(self.data['description'])
905 self._TCTRL_name.Enable(True)
906
907
908
909
910
911
912 from Gnumed.wxGladeWidgets import wxgEncounterEditAreaPnl
913
915
917 try:
918 self.__encounter = kwargs['encounter']
919 del kwargs['encounter']
920 except KeyError:
921 self.__encounter = None
922
923 try:
924 msg = kwargs['msg']
925 del kwargs['msg']
926 except KeyError:
927 msg = None
928
929 wxgEncounterEditAreaPnl.wxgEncounterEditAreaPnl.__init__(self, *args, **kwargs)
930
931 self.refresh(msg = msg)
932
933
934
935 - def refresh(self, encounter=None, msg=None):
974
976
977 if self._PRW_encounter_type.GetData() is None:
978 self._PRW_encounter_type.SetBackgroundColour('pink')
979 self._PRW_encounter_type.Refresh()
980 self._PRW_encounter_type.SetFocus()
981 return False
982 self._PRW_encounter_type.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
983 self._PRW_encounter_type.Refresh()
984
985 if (not self._PRW_start.is_valid_timestamp()) or (self._PRW_start.GetValue().strip() == u''):
986 self._PRW_start.SetFocus()
987 return False
988
989 if (not self._PRW_end.is_valid_timestamp()) or (self._PRW_end.GetValue().strip() == u''):
990 self._PRW_end.SetFocus()
991 return False
992
993 return True
994
996 if not self.__is_valid_for_save():
997 return False
998
999 self.__encounter['pk_type'] = self._PRW_encounter_type.GetData()
1000 self.__encounter['started'] = self._PRW_start.GetData().get_pydt()
1001 self.__encounter['last_affirmed'] = self._PRW_end.GetData().get_pydt()
1002 self.__encounter['reason_for_encounter'] = gmTools.none_if(self._TCTRL_rfe.GetValue().strip(), u'')
1003 self.__encounter['assessment_of_encounter'] = gmTools.none_if(self._TCTRL_aoe.GetValue().strip(), u'')
1004 self.__encounter.save_payload()
1005
1006 return True
1007
1008
1010
1012 encounter = kwargs['encounter']
1013 del kwargs['encounter']
1014
1015 try:
1016 button_defs = kwargs['button_defs']
1017 del kwargs['button_defs']
1018 except KeyError:
1019 button_defs = None
1020
1021 try:
1022 msg = kwargs['msg']
1023 del kwargs['msg']
1024 except KeyError:
1025 msg = None
1026
1027 wxgEncounterEditAreaDlg.wxgEncounterEditAreaDlg.__init__(self, *args, **kwargs)
1028 self.SetSize((450, 280))
1029 self.SetMinSize((450, 280))
1030
1031 if button_defs is not None:
1032 self._BTN_save.SetLabel(button_defs[0][0])
1033 self._BTN_save.SetToolTipString(button_defs[0][1])
1034 self._BTN_close.SetLabel(button_defs[1][0])
1035 self._BTN_close.SetToolTipString(button_defs[1][1])
1036 self.Refresh()
1037
1038 self._PNL_edit_area.refresh(encounter = encounter, msg = msg)
1039
1040 self.Fit()
1041
1048
1049
1050
1060
1130
1132 """Prepare changing health issue for an episode.
1133
1134 Checks for two-open-episodes conflict. When this
1135 function succeeds, the pk_health_issue has been set
1136 on the episode instance and the episode should - for
1137 all practical purposes - be ready for save_payload().
1138 """
1139
1140 if not episode['episode_open']:
1141 episode['pk_health_issue'] = target_issue['pk_health_issue']
1142 if save_to_backend:
1143 episode.save_payload()
1144 return True
1145
1146
1147 if target_issue is None:
1148 episode['pk_health_issue'] = None
1149 if save_to_backend:
1150 episode.save_payload()
1151 return True
1152
1153
1154 db_cfg = gmCfg.cCfgSQL()
1155 epi_ttl = int(db_cfg.get2 (
1156 option = u'episode.ttl',
1157 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1158 bias = 'user',
1159 default = 60
1160 ))
1161 if target_issue.close_expired_episode(ttl=epi_ttl) is True:
1162 gmDispatcher.send(signal='statustext', msg=_('Closed episodes older than %s days on health issue [%s]') % (epi_ttl, target_issue['description']))
1163 existing_epi = target_issue.get_open_episode()
1164
1165
1166 if existing_epi is None:
1167 episode['pk_health_issue'] = target_issue['pk_health_issue']
1168 if save_to_backend:
1169 episode.save_payload()
1170 return True
1171
1172
1173 if existing_epi['pk_episode'] == episode['pk_episode']:
1174 episode['pk_health_issue'] = target_issue['pk_health_issue']
1175 if save_to_backend:
1176 episode.save_payload()
1177 return True
1178
1179
1180 move_range = episode.get_access_range()
1181 exist_range = existing_epi.get_access_range()
1182 question = _(
1183 'You want to associate the running episode:\n\n'
1184 ' "%(new_epi_name)s" (%(new_epi_start)s - %(new_epi_end)s)\n\n'
1185 'with the health issue:\n\n'
1186 ' "%(issue_name)s"\n\n'
1187 'There already is another episode running\n'
1188 'for this health issue:\n\n'
1189 ' "%(old_epi_name)s" (%(old_epi_start)s - %(old_epi_end)s)\n\n'
1190 'However, there can only be one running\n'
1191 'episode per health issue.\n\n'
1192 'Which episode do you want to close ?'
1193 ) % {
1194 'new_epi_name': episode['description'],
1195 'new_epi_start': move_range[0].strftime('%m/%y'),
1196 'new_epi_end': move_range[1].strftime('%m/%y'),
1197 'issue_name': target_issue['description'],
1198 'old_epi_name': existing_epi['description'],
1199 'old_epi_start': exist_range[0].strftime('%m/%y'),
1200 'old_epi_end': exist_range[1].strftime('%m/%y')
1201 }
1202 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1203 parent = None,
1204 id = -1,
1205 caption = _('Resolving two-running-episodes conflict'),
1206 question = question,
1207 button_defs = [
1208 {'label': _('old episode'), 'default': True, 'tooltip': _('close existing episode "%s"') % existing_epi['description']},
1209 {'label': _('new episode'), 'default': False, 'tooltip': _('close moving (new) episode "%s"') % episode['description']}
1210 ]
1211 )
1212 decision = dlg.ShowModal()
1213
1214 if decision == wx.ID_CANCEL:
1215
1216 return False
1217
1218 elif decision == wx.ID_YES:
1219
1220 existing_epi['episode_open'] = False
1221 existing_epi.save_payload()
1222
1223 elif decision == wx.ID_NO:
1224
1225 episode['episode_open'] = False
1226
1227 else:
1228 raise ValueError('invalid result from c3ButtonQuestionDlg: [%s]' % decision)
1229
1230 episode['pk_health_issue'] = target_issue['pk_health_issue']
1231 if save_to_backend:
1232 episode.save_payload()
1233 return True
1234
1258
1260 """Let user select an episode *description*.
1261
1262 The user can select an episode description from the previously
1263 used descriptions across all episodes across all patients.
1264
1265 Selection is done with a phrasewheel so the user can
1266 type the episode name and matches will be shown. Typing
1267 "*" will show the entire list of episodes.
1268
1269 If the user types a description not existing yet a
1270 new episode description will be returned.
1271 """
1273
1274 mp = gmMatchProvider.cMatchProvider_SQL2 (
1275 queries = [u"""
1276 select distinct on (description) description, description, 1
1277 from clin.episode
1278 where description %(fragment_condition)s
1279 order by description
1280 limit 30"""
1281 ]
1282 )
1283 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1284 self.matcher = mp
1285
1287 """Let user select an episode.
1288
1289 The user can select an episode from the existing episodes of a
1290 patient. Selection is done with a phrasewheel so the user
1291 can type the episode name and matches will be shown. Typing
1292 "*" will show the entire list of episodes. Closed episodes
1293 will be marked as such. If the user types an episode name not
1294 in the list of existing episodes a new episode can be created
1295 from it if the programmer activated that feature.
1296
1297 If keyword <patient_id> is set to None or left out the control
1298 will listen to patient change signals and therefore act on
1299 gmPerson.gmCurrentPatient() changes.
1300 """
1302
1303 ctxt = {'ctxt_pat': {'where_part': u'and pk_patient = %(pat)s', 'placeholder': u'pat'}}
1304
1305 mp = gmMatchProvider.cMatchProvider_SQL2 (
1306 queries = [
1307 u"""(
1308
1309 select
1310 pk_episode,
1311 coalesce (
1312 description || ' - ' || health_issue,
1313 description
1314 ) as description,
1315 1 as rank
1316 from
1317 clin.v_pat_episodes
1318 where
1319 episode_open is true and
1320 description %(fragment_condition)s
1321 %(ctxt_pat)s
1322
1323 ) union all (
1324
1325 select
1326 pk_episode,
1327 coalesce (
1328 description || _(' (closed)') || ' - ' || health_issue,
1329 description || _(' (closed)')
1330 ) as description,
1331 2 as rank
1332 from
1333 clin.v_pat_episodes
1334 where
1335 description %(fragment_condition)s and
1336 episode_open is false
1337 %(ctxt_pat)s
1338
1339 )
1340 order by rank, description
1341 limit 30"""
1342 ],
1343 context = ctxt
1344 )
1345
1346 try:
1347 kwargs['patient_id']
1348 except KeyError:
1349 kwargs['patient_id'] = None
1350
1351 if kwargs['patient_id'] is None:
1352 self.use_current_patient = True
1353 self.__register_patient_change_signals()
1354 pat = gmPerson.gmCurrentPatient()
1355 if pat.connected:
1356 mp.set_context('pat', pat.ID)
1357 else:
1358 self.use_current_patient = False
1359 self.__patient_id = int(kwargs['patient_id'])
1360 mp.set_context('pat', self.__patient_id)
1361
1362 del kwargs['patient_id']
1363
1364 gmPhraseWheel.cPhraseWheel.__init__ (
1365 self,
1366 *args,
1367 **kwargs
1368 )
1369 self.matcher = mp
1370
1371
1372
1374 if self.use_current_patient:
1375 return False
1376 self.__patient_id = int(patient_id)
1377 self.set_context('pat', self.__patient_id)
1378 return True
1379
1380 - def GetData(self, can_create=False, as_instance=False, is_open=False):
1384
1386
1387 epi_name = self.GetValue().strip()
1388 if epi_name == u'':
1389 gmDispatcher.send(signal = u'statustext', msg = _('Cannot create episode without name.'), beep = True)
1390 _log.debug('cannot create episode without name')
1391 return
1392
1393 if self.use_current_patient:
1394 pat = gmPerson.gmCurrentPatient()
1395 else:
1396 pat = gmPerson.cPatient(aPK_obj = self.__patient_id)
1397
1398 emr = pat.get_emr()
1399 epi = emr.add_episode(episode_name = epi_name, is_open = self.__is_open_for_create_data)
1400 if epi is None:
1401 self.data = None
1402 else:
1403 self.data = epi['pk_episode']
1404
1407
1408
1409
1413
1416
1418 if self.use_current_patient:
1419 patient = gmPerson.gmCurrentPatient()
1420 self.set_context('pat', patient.ID)
1421 return True
1422
1423 from Gnumed.wxGladeWidgets import wxgEpisodeEditAreaPnl
1424
1425 -class cEpisodeEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgEpisodeEditAreaPnl.wxgEpisodeEditAreaPnl):
1426
1439
1440
1441
1443
1444 errors = False
1445
1446 if len(self._PRW_description.GetValue().strip()) == 0:
1447 errors = True
1448 self._PRW_description.display_as_valid(False)
1449 self._PRW_description.SetFocus()
1450 else:
1451 self._PRW_description.display_as_valid(True)
1452 self._PRW_description.Refresh()
1453
1454 return not errors
1455
1457
1458 pat = gmPerson.gmCurrentPatient()
1459 emr = pat.get_emr()
1460
1461 epi = emr.add_episode(episode_name = self._PRW_description.GetValue().strip())
1462 epi['summary'] = self._TCTRL_summary.GetValue().strip()
1463 epi['episode_open'] = not self._CHBOX_closed.IsChecked()
1464 epi['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1465
1466 issue_name = self._PRW_issue.GetValue().strip()
1467 if len(issue_name) != 0:
1468 epi['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
1469 issue = gmEMRStructItems.cHealthIssue(aPK_obj = epi['pk_health_issue'])
1470
1471 if not move_episode_to_issue(episode = epi, target_issue = issue, save_to_backend = False):
1472 gmDispatcher.send (
1473 signal = 'statustext',
1474 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
1475 epi['description'],
1476 issue['description']
1477 )
1478 )
1479 gmEMRStructItems.delete_episode(episode = epi)
1480 return False
1481
1482 epi.save()
1483
1484 self.data = epi
1485 return True
1486
1488
1489 self.data['description'] = self._PRW_description.GetValue().strip()
1490 self.data['summary'] = self._TCTRL_summary.GetValue().strip()
1491 self.data['episode_open'] = not self._CHBOX_closed.IsChecked()
1492 self.data['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1493
1494 issue_name = self._PRW_issue.GetValue().strip()
1495 if len(issue_name) != 0:
1496 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
1497 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue'])
1498
1499 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False):
1500 gmDispatcher.send (
1501 signal = 'statustext',
1502 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
1503 self.data['description'],
1504 issue['description']
1505 )
1506 )
1507 return False
1508
1509 self.data.save()
1510 return True
1511
1523
1539
1541 self._refresh_as_new()
1542
1543
1544
1554
1556
1557
1558
1560
1561 issues = kwargs['issues']
1562 del kwargs['issues']
1563
1564 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs)
1565
1566 self.SetTitle(_('Select the health issues you are interested in ...'))
1567 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u''])
1568
1569 for issue in issues:
1570 if issue['is_confidential']:
1571 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential'))
1572 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED'))
1573 else:
1574 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'')
1575
1576 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description'])
1577 if issue['clinically_relevant']:
1578 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant'))
1579 if issue['is_active']:
1580 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active'))
1581 if issue['is_cause_of_death']:
1582 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal'))
1583
1584 self._LCTRL_items.set_column_widths()
1585 self._LCTRL_items.set_data(data = issues)
1586
1588 """Let the user select a health issue.
1589
1590 The user can select a health issue from the existing issues
1591 of a patient. Selection is done with a phrasewheel so the user
1592 can type the issue name and matches will be shown. Typing
1593 "*" will show the entire list of issues. Inactive issues
1594 will be marked as such. If the user types an issue name not
1595 in the list of existing issues a new issue can be created
1596 from it if the programmer activated that feature.
1597
1598 If keyword <patient_id> is set to None or left out the control
1599 will listen to patient change signals and therefore act on
1600 gmPerson.gmCurrentPatient() changes.
1601 """
1603
1604 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}}
1605
1606 mp = gmMatchProvider.cMatchProvider_SQL2 (
1607
1608 queries = [u"""
1609 (select pk_health_issue, description, 1
1610 from clin.v_health_issues where
1611 is_active is true and
1612 description %(fragment_condition)s and
1613 %(ctxt_pat)s
1614 order by description)
1615
1616 union
1617
1618 (select pk_health_issue, description || _(' (inactive)'), 2
1619 from clin.v_health_issues where
1620 is_active is false and
1621 description %(fragment_condition)s and
1622 %(ctxt_pat)s
1623 order by description)"""
1624 ],
1625 context = ctxt
1626 )
1627
1628 try: kwargs['patient_id']
1629 except KeyError: kwargs['patient_id'] = None
1630
1631 if kwargs['patient_id'] is None:
1632 self.use_current_patient = True
1633 self.__register_patient_change_signals()
1634 pat = gmPerson.gmCurrentPatient()
1635 if pat.connected:
1636 mp.set_context('pat', pat.ID)
1637 else:
1638 self.use_current_patient = False
1639 self.__patient_id = int(kwargs['patient_id'])
1640 mp.set_context('pat', self.__patient_id)
1641
1642 del kwargs['patient_id']
1643
1644 gmPhraseWheel.cPhraseWheel.__init__ (
1645 self,
1646 *args,
1647 **kwargs
1648 )
1649 self.matcher = mp
1650
1651
1652
1654 if self.use_current_patient:
1655 return False
1656 self.__patient_id = int(patient_id)
1657 self.set_context('pat', self.__patient_id)
1658 return True
1659
1660 - def GetData(self, can_create=False, is_open=False):
1678
1679
1680
1684
1687
1689 if self.use_current_patient:
1690 patient = gmPerson.gmCurrentPatient()
1691 self.set_context('pat', patient.ID)
1692 return True
1693
1695
1697 try:
1698 msg = kwargs['message']
1699 except KeyError:
1700 msg = None
1701 del kwargs['message']
1702 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs)
1703 if msg is not None:
1704 self._lbl_message.SetLabel(label=msg)
1705
1716
1717 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl
1718
1719 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
1720 """Panel encapsulating health issue edit area functionality."""
1721
1723
1724 try:
1725 issue = kwargs['issue']
1726 except KeyError:
1727 issue = None
1728
1729 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs)
1730
1731 gmEditArea.cGenericEditAreaMixin.__init__(self)
1732
1733
1734 mp = gmMatchProvider.cMatchProvider_SQL2 (
1735 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"]
1736 )
1737 mp.setThresholds(1, 3, 5)
1738 self._PRW_condition.matcher = mp
1739
1740 mp = gmMatchProvider.cMatchProvider_SQL2 (
1741 queries = [u"""
1742 select distinct on (grouping) grouping, grouping from (
1743
1744 select rank, grouping from ((
1745
1746 select
1747 grouping,
1748 1 as rank
1749 from
1750 clin.health_issue
1751 where
1752 grouping %%(fragment_condition)s
1753 and
1754 (select True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter)
1755
1756 ) union (
1757
1758 select
1759 grouping,
1760 2 as rank
1761 from
1762 clin.health_issue
1763 where
1764 grouping %%(fragment_condition)s
1765
1766 )) as union_result
1767
1768 order by rank
1769
1770 ) as order_result
1771
1772 limit 50""" % gmPerson.gmCurrentPatient().ID
1773 ]
1774 )
1775 mp.setThresholds(1, 3, 5)
1776 self._PRW_grouping.matcher = mp
1777
1778 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted)
1779 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted)
1780
1781 self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted)
1782 self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted)
1783
1784 self._PRW_year_noted.Enable(True)
1785
1786 self.data = issue
1787
1788
1789
1809
1811 pat = gmPerson.gmCurrentPatient()
1812 emr = pat.get_emr()
1813
1814 issue = emr.add_health_issue(issue_name = self._PRW_condition.GetValue().strip())
1815
1816 side = u''
1817 if self._ChBOX_left.GetValue():
1818 side += u's'
1819 if self._ChBOX_right.GetValue():
1820 side += u'd'
1821 issue['laterality'] = side
1822
1823 issue['summary'] = self._TCTRL_summary.GetValue().strip()
1824 issue['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1825 issue['grouping'] = self._PRW_grouping.GetValue().strip()
1826 issue['is_active'] = self._ChBOX_active.GetValue()
1827 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue()
1828 issue['is_confidential'] = self._ChBOX_confidential.GetValue()
1829 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue()
1830
1831 age_noted = self._PRW_age_noted.GetData()
1832 if age_noted is not None:
1833 issue['age_noted'] = age_noted
1834
1835 issue.save()
1836
1837 self.data = issue
1838 return True
1839
1841
1842 self.data['description'] = self._PRW_condition.GetValue().strip()
1843
1844 side = u''
1845 if self._ChBOX_left.GetValue():
1846 side += u's'
1847 if self._ChBOX_right.GetValue():
1848 side += u'd'
1849 self.data['laterality'] = side
1850
1851 self.data['summary'] = self._TCTRL_summary.GetValue().strip()
1852 self.data['diagnostic_certainty_classification'] = self._PRW_classification.GetData()
1853 self.data['grouping'] = self._PRW_grouping.GetValue().strip()
1854 self.data['is_active'] = bool(self._ChBOX_active.GetValue())
1855 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue())
1856 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue())
1857 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue())
1858
1859 age_noted = self._PRW_age_noted.GetData()
1860 if age_noted is not None:
1861 self.data['age_noted'] = age_noted
1862
1863 self.data.save()
1864
1865
1866 return True
1867
1869 self._PRW_condition.SetText()
1870 self._ChBOX_left.SetValue(0)
1871 self._ChBOX_right.SetValue(0)
1872 self._PRW_classification.SetText()
1873 self._PRW_grouping.SetText()
1874 self._TCTRL_summary.SetValue(u'')
1875 self._PRW_age_noted.SetText()
1876 self._PRW_year_noted.SetText()
1877 self._ChBOX_active.SetValue(0)
1878 self._ChBOX_relevant.SetValue(1)
1879 self._ChBOX_is_operation.SetValue(0)
1880 self._ChBOX_confidential.SetValue(0)
1881 self._ChBOX_caused_death.SetValue(0)
1882
1883 return True
1884
1886 self._PRW_condition.SetText(self.data['description'])
1887
1888 lat = gmTools.coalesce(self.data['laterality'], '')
1889 if lat.find('s') == -1:
1890 self._ChBOX_left.SetValue(0)
1891 else:
1892 self._ChBOX_left.SetValue(1)
1893 if lat.find('d') == -1:
1894 self._ChBOX_right.SetValue(0)
1895 else:
1896 self._ChBOX_right.SetValue(1)
1897
1898 self._PRW_classification.SetData(data = self.data['diagnostic_certainty_classification'])
1899 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u''))
1900 self._TCTRL_summary.SetValue(gmTools.coalesce(self.data['summary'], u''))
1901
1902 if self.data['age_noted'] is None:
1903 self._PRW_age_noted.SetText()
1904 else:
1905 self._PRW_age_noted.SetText (
1906 value = '%sd' % self.data['age_noted'].days,
1907 data = self.data['age_noted']
1908 )
1909
1910 self._ChBOX_active.SetValue(self.data['is_active'])
1911 self._ChBOX_relevant.SetValue(self.data['clinically_relevant'])
1912 self._ChBOX_is_operation.SetValue(0)
1913 self._ChBOX_confidential.SetValue(self.data['is_confidential'])
1914 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death'])
1915
1916
1917
1918
1919
1920 return True
1921
1923 return self._refresh_as_new()
1924
1925
1926
1928
1929 if not self._PRW_age_noted.IsModified():
1930 return True
1931
1932 str_age = self._PRW_age_noted.GetValue().strip()
1933
1934 if str_age == u'':
1935 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1936 return True
1937
1938 age = gmDateTime.str2interval(str_interval = str_age)
1939
1940 if age is None:
1941 gmDispatcher.send(signal='statustext', msg=_('Cannot parse [%s] into valid interval.') % str_age)
1942 self._PRW_age_noted.SetBackgroundColour('pink')
1943 self._PRW_age_noted.Refresh()
1944 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1945 return True
1946
1947 pat = gmPerson.gmCurrentPatient()
1948 if pat['dob'] is not None:
1949 max_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob']
1950
1951 if age >= max_age:
1952 gmDispatcher.send (
1953 signal = 'statustext',
1954 msg = _(
1955 'Health issue cannot have been noted at age %s. Patient is only %s old.'
1956 ) % (age, pat.get_medical_age())
1957 )
1958 self._PRW_age_noted.SetBackgroundColour('pink')
1959 self._PRW_age_noted.Refresh()
1960 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1961 return True
1962
1963 self._PRW_age_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
1964 self._PRW_age_noted.Refresh()
1965 self._PRW_age_noted.SetData(data=age)
1966
1967 if pat['dob'] is not None:
1968 fts = gmDateTime.cFuzzyTimestamp (
1969 timestamp = pat['dob'] + age,
1970 accuracy = gmDateTime.acc_months
1971 )
1972 wx.CallAfter(self._PRW_year_noted.SetText, str(fts), fts)
1973
1974
1975
1976
1977
1978 return True
1979
1981
1982 if not self._PRW_year_noted.IsModified():
1983 return True
1984
1985 year_noted = self._PRW_year_noted.GetData()
1986
1987 if year_noted is None:
1988 if self._PRW_year_noted.GetValue().strip() == u'':
1989 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1990 return True
1991 self._PRW_year_noted.SetBackgroundColour('pink')
1992 self._PRW_year_noted.Refresh()
1993 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
1994 return True
1995
1996 year_noted = year_noted.get_pydt()
1997
1998 if year_noted >= pydt.datetime.now(tz=year_noted.tzinfo):
1999 gmDispatcher.send(signal='statustext', msg=_('Condition diagnosed in the future.'))
2000 self._PRW_year_noted.SetBackgroundColour('pink')
2001 self._PRW_year_noted.Refresh()
2002 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
2003 return True
2004
2005 self._PRW_year_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
2006 self._PRW_year_noted.Refresh()
2007
2008 pat = gmPerson.gmCurrentPatient()
2009 if pat['dob'] is not None:
2010 issue_age = year_noted - pat['dob']
2011 str_age = gmDateTime.format_interval_medically(interval = issue_age)
2012 wx.CallAfter(self._PRW_age_noted.SetText, str_age, issue_age)
2013
2014 return True
2015
2017 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
2018 return True
2019
2021 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
2022 return True
2023
2024
2025
2027
2029
2030 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2031
2032 self.selection_only = False
2033
2034 mp = gmMatchProvider.cMatchProvider_FixedList (
2035 aSeq = [
2036 {'data': u'A', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1},
2037 {'data': u'B', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1},
2038 {'data': u'C', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1},
2039 {'data': u'D', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1}
2040 ]
2041 )
2042 mp.setThresholds(1, 2, 4)
2043 self.matcher = mp
2044
2045 self.SetToolTipString(_(
2046 "The diagnostic classification or grading of this assessment.\n"
2047 "\n"
2048 "This documents how certain one is about this being a true diagnosis."
2049 ))
2050
2051
2052
2053 if __name__ == '__main__':
2054
2055
2057 """
2058 Test application for testing EMR struct widgets
2059 """
2060
2062 """
2063 Create test application UI
2064 """
2065 frame = wx.Frame (
2066 None,
2067 -4,
2068 'Testing EMR struct widgets',
2069 size=wx.Size(600, 400),
2070 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
2071 )
2072 filemenu= wx.Menu()
2073 filemenu.AppendSeparator()
2074 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application")
2075
2076
2077 menuBar = wx.MenuBar()
2078 menuBar.Append(filemenu,"&File")
2079
2080 frame.SetMenuBar(menuBar)
2081
2082 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"),
2083 wx.DefaultPosition, wx.DefaultSize, 0 )
2084
2085
2086 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow)
2087
2088
2089 self.__pat = gmPerson.gmCurrentPatient()
2090
2091 frame.Show(1)
2092 return 1
2093
2095 """
2096 Close test aplication
2097 """
2098 self.ExitMainLoop ()
2099
2101 app = wx.PyWidgetTester(size = (200, 300))
2102 emr = pat.get_emr()
2103 enc = emr.active_encounter
2104
2105 pnl = cEncounterEditAreaPnl(app.frame, -1, encounter=enc)
2106 app.frame.Show(True)
2107 app.MainLoop()
2108 return
2109
2111 app = wx.PyWidgetTester(size = (200, 300))
2112 emr = pat.get_emr()
2113 enc = emr.active_encounter
2114
2115
2116 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc)
2117 dlg.ShowModal()
2118
2119
2120
2121
2122
2124 app = wx.PyWidgetTester(size = (200, 300))
2125 emr = pat.get_emr()
2126 epi = emr.get_episodes()[0]
2127 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi)
2128 app.frame.Show(True)
2129 app.MainLoop()
2130
2136
2138 app = wx.PyWidgetTester(size = (400, 40))
2139 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2140 app.MainLoop()
2141
2143 app = wx.PyWidgetTester(size = (400, 40))
2144 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2145
2146 app.MainLoop()
2147
2149 app = wx.PyWidgetTester(size = (200, 300))
2150 edit_health_issue(parent=app.frame, issue=None)
2151
2153 app = wx.PyWidgetTester(size = (200, 300))
2154 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400))
2155 app.MainLoop()
2156
2158 app = wx.PyWidgetTester(size = (200, 300))
2159 edit_procedure(parent=app.frame)
2160
2161
2162 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2163
2164 gmI18N.activate_locale()
2165 gmI18N.install_domain()
2166 gmDateTime.init()
2167
2168
2169 pat = gmPersonSearch.ask_for_patient()
2170 if pat is None:
2171 print "No patient. Exiting gracefully..."
2172 sys.exit(0)
2173 gmPatSearchWidgets.set_active_patient(patient=pat)
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191 test_edit_procedure()
2192
2193
2194