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