| 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_status.GetValue().strip()
1460 epi['episode_open'] = not self._CHBOX_closed.IsChecked()
1461 epi['diagnostic_certainty_classification'] = self._PRW_certainty.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 epi.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
1482
1483 self.data = epi
1484 return True
1485 #----------------------------------------------------------------
1487
1488 self.data['description'] = self._PRW_description.GetValue().strip()
1489 self.data['summary'] = self._TCTRL_status.GetValue().strip()
1490 self.data['episode_open'] = not self._CHBOX_closed.IsChecked()
1491 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData()
1492
1493 issue_name = self._PRW_issue.GetValue().strip()
1494 if len(issue_name) == 0:
1495 self.data['pk_health_issue'] = None
1496 else:
1497 self.data['pk_health_issue'] = self._PRW_issue.GetData(can_create = True)
1498 issue = gmEMRStructItems.cHealthIssue(aPK_obj = self.data['pk_health_issue'])
1499
1500 if not move_episode_to_issue(episode = self.data, target_issue = issue, save_to_backend = False):
1501 gmDispatcher.send (
1502 signal = 'statustext',
1503 msg = _('Cannot attach episode [%s] to health issue [%s] because it already has a running episode.') % (
1504 self.data['description'],
1505 issue['description']
1506 )
1507 )
1508 return False
1509
1510 self.data.save()
1511 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
1512
1513 return True
1514 #----------------------------------------------------------------
1516 if self.data is None:
1517 ident = gmPerson.gmCurrentPatient()
1518 else:
1519 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
1520 self._TCTRL_patient.SetValue(ident.get_description_gender())
1521 self._PRW_issue.SetText()
1522 self._PRW_description.SetText()
1523 self._TCTRL_status.SetValue(u'')
1524 self._PRW_certainty.SetText()
1525 self._CHBOX_closed.SetValue(False)
1526 self._PRW_codes.SetText()
1527 #----------------------------------------------------------------
1529 ident = gmPerson.cIdentity(aPK_obj = self.data['pk_patient'])
1530 self._TCTRL_patient.SetValue(ident.get_description_gender())
1531
1532 if self.data['pk_health_issue'] is not None:
1533 self._PRW_issue.SetText(self.data['health_issue'], data=self.data['pk_health_issue'])
1534
1535 self._PRW_description.SetText(self.data['description'], data=self.data['description'])
1536
1537 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u''))
1538
1539 if self.data['diagnostic_certainty_classification'] is not None:
1540 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification'])
1541
1542 self._CHBOX_closed.SetValue(not self.data['episode_open'])
1543
1544 codes = self.data.generic_codes
1545 if len(codes) == 0:
1546 self._PRW_codes.SetText()
1547 else:
1548 code_dict = {}
1549 val = u''
1550 for code in codes:
1551 list_label = u'%s (%s - %s %s): %s' % (
1552 code['code'],
1553 code['lang'],
1554 code['name_short'],
1555 code['version'],
1556 code['term']
1557 )
1558 field_label = code['code']
1559 code_dict[field_label] = {'data': code['pk_generic_code'], 'field_label': field_label, 'list_label': list_label}
1560 val += u'%s; ' % field_label
1561 self._PRW_codes.SetText(val.strip(), code_dict)
1562 #----------------------------------------------------------------
1565 #================================================================
1566 # health issue related widgets/functions
1567 #----------------------------------------------------------------
1569 ea = cHealthIssueEditAreaPnl(parent = parent, id = -1)
1570 ea.data = issue
1571 ea.mode = gmTools.coalesce(issue, 'new', 'edit')
1572 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (issue is not None))
1573 dlg.SetTitle(gmTools.coalesce(issue, _('Adding a new health issue'), _('Editing a health issue')))
1574 if dlg.ShowModal() == wx.ID_OK:
1575 return True
1576 return False
1577 #----------------------------------------------------------------
1579
1580 # FIXME: support pre-selection
1581
1583
1584 issues = kwargs['issues']
1585 del kwargs['issues']
1586
1587 gmListWidgets.cGenericListSelectorDlg.__init__(self, *args, **kwargs)
1588
1589 self.SetTitle(_('Select the health issues you are interested in ...'))
1590 self._LCTRL_items.set_columns([u'', _('Health Issue'), u'', u'', u''])
1591
1592 for issue in issues:
1593 if issue['is_confidential']:
1594 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = _('confidential'))
1595 self._LCTRL_items.SetItemTextColour(row_num, col=wx.NamedColour('RED'))
1596 else:
1597 row_num = self._LCTRL_items.InsertStringItem(sys.maxint, label = u'')
1598
1599 self._LCTRL_items.SetStringItem(index = row_num, col = 1, label = issue['description'])
1600 if issue['clinically_relevant']:
1601 self._LCTRL_items.SetStringItem(index = row_num, col = 2, label = _('relevant'))
1602 if issue['is_active']:
1603 self._LCTRL_items.SetStringItem(index = row_num, col = 3, label = _('active'))
1604 if issue['is_cause_of_death']:
1605 self._LCTRL_items.SetStringItem(index = row_num, col = 4, label = _('fatal'))
1606
1607 self._LCTRL_items.set_column_widths()
1608 self._LCTRL_items.set_data(data = issues)
1609 #----------------------------------------------------------------
1611 """Let the user select a health issue.
1612
1613 The user can select a health issue from the existing issues
1614 of a patient. Selection is done with a phrasewheel so the user
1615 can type the issue name and matches will be shown. Typing
1616 "*" will show the entire list of issues. Inactive issues
1617 will be marked as such. If the user types an issue name not
1618 in the list of existing issues a new issue can be created
1619 from it if the programmer activated that feature.
1620
1621 If keyword <patient_id> is set to None or left out the control
1622 will listen to patient change signals and therefore act on
1623 gmPerson.gmCurrentPatient() changes.
1624 """
1626
1627 ctxt = {'ctxt_pat': {'where_part': u'pk_patient=%(pat)s', 'placeholder': u'pat'}}
1628
1629 mp = gmMatchProvider.cMatchProvider_SQL2 (
1630 # FIXME: consider clin.health_issue.clinically_relevant
1631 queries = [u"""
1632 (select pk_health_issue, description, 1
1633 from clin.v_health_issues where
1634 is_active is true and
1635 description %(fragment_condition)s and
1636 %(ctxt_pat)s
1637 order by description)
1638
1639 union
1640
1641 (select pk_health_issue, description || _(' (inactive)'), 2
1642 from clin.v_health_issues where
1643 is_active is false and
1644 description %(fragment_condition)s and
1645 %(ctxt_pat)s
1646 order by description)"""
1647 ],
1648 context = ctxt
1649 )
1650
1651 try: kwargs['patient_id']
1652 except KeyError: kwargs['patient_id'] = None
1653
1654 if kwargs['patient_id'] is None:
1655 self.use_current_patient = True
1656 self.__register_patient_change_signals()
1657 pat = gmPerson.gmCurrentPatient()
1658 if pat.connected:
1659 mp.set_context('pat', pat.ID)
1660 else:
1661 self.use_current_patient = False
1662 self.__patient_id = int(kwargs['patient_id'])
1663 mp.set_context('pat', self.__patient_id)
1664
1665 del kwargs['patient_id']
1666
1667 gmPhraseWheel.cPhraseWheel.__init__ (
1668 self,
1669 *args,
1670 **kwargs
1671 )
1672 self.matcher = mp
1673 #--------------------------------------------------------
1674 # external API
1675 #--------------------------------------------------------
1677 if self.use_current_patient:
1678 return False
1679 self.__patient_id = int(patient_id)
1680 self.set_context('pat', self.__patient_id)
1681 return True
1682 #--------------------------------------------------------
1684 if self.data is None:
1685 if can_create:
1686 issue_name = self.GetValue().strip()
1687
1688 if self.use_current_patient:
1689 pat = gmPerson.gmCurrentPatient()
1690 else:
1691 pat = gmPerson.cPatient(aPK_obj=self.__patient_id)
1692 emr = pat.get_emr()
1693
1694 issue = emr.add_health_issue(issue_name = issue_name)
1695 if issue is None:
1696 self.data = None
1697 else:
1698 self.data = issue['pk_health_issue']
1699
1700 return gmPhraseWheel.cPhraseWheel.GetData(self)
1701 #--------------------------------------------------------
1702 # internal API
1703 #--------------------------------------------------------
1705 gmDispatcher.connect(self._pre_patient_selection, u'pre_patient_selection')
1706 gmDispatcher.connect(self._post_patient_selection, u'post_patient_selection')
1707 #--------------------------------------------------------
1710 #--------------------------------------------------------
1712 if self.use_current_patient:
1713 patient = gmPerson.gmCurrentPatient()
1714 self.set_context('pat', patient.ID)
1715 return True
1716 #------------------------------------------------------------
1718
1720 try:
1721 msg = kwargs['message']
1722 except KeyError:
1723 msg = None
1724 del kwargs['message']
1725 wxgIssueSelectionDlg.wxgIssueSelectionDlg.__init__(self, *args, **kwargs)
1726 if msg is not None:
1727 self._lbl_message.SetLabel(label=msg)
1728 #--------------------------------------------------------
1739 #------------------------------------------------------------
1740 from Gnumed.wxGladeWidgets import wxgHealthIssueEditAreaPnl
1741
1742 -class cHealthIssueEditAreaPnl(gmEditArea.cGenericEditAreaMixin, wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl):
1743 """Panel encapsulating health issue edit area functionality."""
1744
1746
1747 try:
1748 issue = kwargs['issue']
1749 except KeyError:
1750 issue = None
1751
1752 wxgHealthIssueEditAreaPnl.wxgHealthIssueEditAreaPnl.__init__(self, *args, **kwargs)
1753
1754 gmEditArea.cGenericEditAreaMixin.__init__(self)
1755
1756 # FIXME: include more sources: coding systems/other database columns
1757 mp = gmMatchProvider.cMatchProvider_SQL2 (
1758 queries = [u"SELECT DISTINCT ON (description) description, description FROM clin.health_issue WHERE description %(fragment_condition)s LIMIT 50"]
1759 )
1760 mp.setThresholds(1, 3, 5)
1761 self._PRW_condition.matcher = mp
1762
1763 mp = gmMatchProvider.cMatchProvider_SQL2 (
1764 queries = [u"""
1765 select distinct on (grouping) grouping, grouping from (
1766
1767 select rank, grouping from ((
1768
1769 select
1770 grouping,
1771 1 as rank
1772 from
1773 clin.health_issue
1774 where
1775 grouping %%(fragment_condition)s
1776 and
1777 (select True from clin.encounter where fk_patient = %s and pk = clin.health_issue.fk_encounter)
1778
1779 ) union (
1780
1781 select
1782 grouping,
1783 2 as rank
1784 from
1785 clin.health_issue
1786 where
1787 grouping %%(fragment_condition)s
1788
1789 )) as union_result
1790
1791 order by rank
1792
1793 ) as order_result
1794
1795 limit 50""" % gmPerson.gmCurrentPatient().ID
1796 ]
1797 )
1798 mp.setThresholds(1, 3, 5)
1799 self._PRW_grouping.matcher = mp
1800
1801 self._PRW_age_noted.add_callback_on_lose_focus(self._on_leave_age_noted)
1802 self._PRW_year_noted.add_callback_on_lose_focus(self._on_leave_year_noted)
1803
1804 self._PRW_age_noted.add_callback_on_modified(self._on_modified_age_noted)
1805 self._PRW_year_noted.add_callback_on_modified(self._on_modified_year_noted)
1806
1807 self._PRW_year_noted.Enable(True)
1808
1809 self._PRW_codes.add_callback_on_lose_focus(self._on_leave_codes)
1810
1811 self.data = issue
1812 #----------------------------------------------------------------
1813 # generic Edit Area mixin API
1814 #----------------------------------------------------------------
1816
1817 if self._PRW_condition.GetValue().strip() == '':
1818 self._PRW_condition.display_as_valid(False)
1819 self._PRW_condition.SetFocus()
1820 return False
1821 self._PRW_condition.display_as_valid(True)
1822 self._PRW_condition.Refresh()
1823
1824 # FIXME: sanity check age/year diagnosed
1825 age_noted = self._PRW_age_noted.GetValue().strip()
1826 if age_noted != '':
1827 if gmDateTime.str2interval(str_interval = age_noted) is None:
1828 self._PRW_age_noted.display_as_valid(False)
1829 self._PRW_age_noted.SetFocus()
1830 return False
1831 self._PRW_age_noted.display_as_valid(True)
1832
1833 return True
1834 #----------------------------------------------------------------
1836 pat = gmPerson.gmCurrentPatient()
1837 emr = pat.get_emr()
1838
1839 issue = emr.add_health_issue(issue_name = 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 issue['laterality'] = side
1847
1848 issue['summary'] = self._TCTRL_status.GetValue().strip()
1849 issue['diagnostic_certainty_classification'] = self._PRW_certainty.GetData()
1850 issue['grouping'] = self._PRW_grouping.GetValue().strip()
1851 issue['is_active'] = self._ChBOX_active.GetValue()
1852 issue['clinically_relevant'] = self._ChBOX_relevant.GetValue()
1853 issue['is_confidential'] = self._ChBOX_confidential.GetValue()
1854 issue['is_cause_of_death'] = self._ChBOX_caused_death.GetValue()
1855
1856 age_noted = self._PRW_age_noted.GetData()
1857 if age_noted is not None:
1858 issue['age_noted'] = age_noted
1859
1860 issue.save()
1861
1862 issue.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
1863
1864 self.data = issue
1865 return True
1866 #----------------------------------------------------------------
1868
1869 self.data['description'] = self._PRW_condition.GetValue().strip()
1870
1871 side = u''
1872 if self._ChBOX_left.GetValue():
1873 side += u's'
1874 if self._ChBOX_right.GetValue():
1875 side += u'd'
1876 self.data['laterality'] = side
1877
1878 self.data['summary'] = self._TCTRL_status.GetValue().strip()
1879 self.data['diagnostic_certainty_classification'] = self._PRW_certainty.GetData()
1880 self.data['grouping'] = self._PRW_grouping.GetValue().strip()
1881 self.data['is_active'] = bool(self._ChBOX_active.GetValue())
1882 self.data['clinically_relevant'] = bool(self._ChBOX_relevant.GetValue())
1883 self.data['is_confidential'] = bool(self._ChBOX_confidential.GetValue())
1884 self.data['is_cause_of_death'] = bool(self._ChBOX_caused_death.GetValue())
1885
1886 age_noted = self._PRW_age_noted.GetData()
1887 if age_noted is not None:
1888 self.data['age_noted'] = age_noted
1889
1890 self.data.save()
1891 self.data.generic_codes = [ c['data'] for c in self._PRW_codes.GetData() ]
1892
1893 return True
1894 #----------------------------------------------------------------
1896 self._PRW_condition.SetText()
1897 self._ChBOX_left.SetValue(0)
1898 self._ChBOX_right.SetValue(0)
1899 self._PRW_codes.SetText()
1900 self._on_leave_codes()
1901 self._PRW_certainty.SetText()
1902 self._PRW_grouping.SetText()
1903 self._TCTRL_status.SetValue(u'')
1904 self._PRW_age_noted.SetText()
1905 self._PRW_year_noted.SetText()
1906 self._ChBOX_active.SetValue(0)
1907 self._ChBOX_relevant.SetValue(1)
1908 self._ChBOX_confidential.SetValue(0)
1909 self._ChBOX_caused_death.SetValue(0)
1910
1911 return True
1912 #----------------------------------------------------------------
1914 self._PRW_condition.SetText(self.data['description'])
1915
1916 lat = gmTools.coalesce(self.data['laterality'], '')
1917 if lat.find('s') == -1:
1918 self._ChBOX_left.SetValue(0)
1919 else:
1920 self._ChBOX_left.SetValue(1)
1921 if lat.find('d') == -1:
1922 self._ChBOX_right.SetValue(0)
1923 else:
1924 self._ChBOX_right.SetValue(1)
1925
1926 codes = self.data.generic_codes
1927 if len(codes) == 0:
1928 self._PRW_codes.SetText()
1929 else:
1930 code_dict = {}
1931 val = u''
1932 for code in codes:
1933 list_label = u'%s (%s - %s %s): %s' % (
1934 code['code'],
1935 code['lang'],
1936 code['name_short'],
1937 code['version'],
1938 code['term']
1939 )
1940 field_label = code['code']
1941 code_dict[field_label] = {'data': code['pk_generic_code'], 'field_label': field_label, 'list_label': list_label}
1942 val += u'%s; ' % field_label
1943 self._PRW_codes.SetText(val.strip(), code_dict)
1944 self._on_leave_codes()
1945
1946 if self.data['diagnostic_certainty_classification'] is not None:
1947 self._PRW_certainty.SetData(data = self.data['diagnostic_certainty_classification'])
1948 self._PRW_grouping.SetText(gmTools.coalesce(self.data['grouping'], u''))
1949 self._TCTRL_status.SetValue(gmTools.coalesce(self.data['summary'], u''))
1950
1951 if self.data['age_noted'] is None:
1952 self._PRW_age_noted.SetText()
1953 else:
1954 self._PRW_age_noted.SetText (
1955 value = '%sd' % self.data['age_noted'].days,
1956 data = self.data['age_noted']
1957 )
1958
1959 self._ChBOX_active.SetValue(self.data['is_active'])
1960 self._ChBOX_relevant.SetValue(self.data['clinically_relevant'])
1961 self._ChBOX_confidential.SetValue(self.data['is_confidential'])
1962 self._ChBOX_caused_death.SetValue(self.data['is_cause_of_death'])
1963
1964 # this dance should assure self._PRW_year_noted gets set -- but it doesn't ...
1965 # self._PRW_age_noted.SetFocus()
1966 # self._PRW_condition.SetFocus()
1967
1968 return True
1969 #----------------------------------------------------------------
1972 #--------------------------------------------------------
1973 # internal helpers
1974 #--------------------------------------------------------
1976 if not self._PRW_codes.IsModified():
1977 return True
1978
1979 self._TCTRL_code_details.SetValue(u'- ' + u'\n- '.join([ c['list_label'] for c in self._PRW_codes.GetData() ]))
1980 #--------------------------------------------------------
1982
1983 if not self._PRW_age_noted.IsModified():
1984 return True
1985
1986 str_age = self._PRW_age_noted.GetValue().strip()
1987
1988 if str_age == u'':
1989 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1990 return True
1991
1992 age = gmDateTime.str2interval(str_interval = str_age)
1993
1994 if age is None:
1995 gmDispatcher.send(signal='statustext', msg=_('Cannot parse [%s] into valid interval.') % str_age)
1996 self._PRW_age_noted.SetBackgroundColour('pink')
1997 self._PRW_age_noted.Refresh()
1998 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
1999 return True
2000
2001 pat = gmPerson.gmCurrentPatient()
2002 if pat['dob'] is not None:
2003 max_age = pydt.datetime.now(tz=pat['dob'].tzinfo) - pat['dob']
2004
2005 if age >= max_age:
2006 gmDispatcher.send (
2007 signal = 'statustext',
2008 msg = _(
2009 'Health issue cannot have been noted at age %s. Patient is only %s old.'
2010 ) % (age, pat.get_medical_age())
2011 )
2012 self._PRW_age_noted.SetBackgroundColour('pink')
2013 self._PRW_age_noted.Refresh()
2014 wx.CallAfter(self._PRW_year_noted.SetText, u'', None, True)
2015 return True
2016
2017 self._PRW_age_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
2018 self._PRW_age_noted.Refresh()
2019 self._PRW_age_noted.SetData(data=age)
2020
2021 if pat['dob'] is not None:
2022 fts = gmDateTime.cFuzzyTimestamp (
2023 timestamp = pat['dob'] + age,
2024 accuracy = gmDateTime.acc_months
2025 )
2026 wx.CallAfter(self._PRW_year_noted.SetText, str(fts), fts)
2027 # if we do this we will *always* navigate there, regardless of TAB vs ALT-TAB
2028 #wx.CallAfter(self._ChBOX_active.SetFocus)
2029 # if we do the following instead it will take us to the save/update button ...
2030 #wx.CallAfter(self.Navigate)
2031
2032 return True
2033 #--------------------------------------------------------
2035
2036 if not self._PRW_year_noted.IsModified():
2037 return True
2038
2039 year_noted = self._PRW_year_noted.GetData()
2040
2041 if year_noted is None:
2042 if self._PRW_year_noted.GetValue().strip() == u'':
2043 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
2044 return True
2045 self._PRW_year_noted.SetBackgroundColour('pink')
2046 self._PRW_year_noted.Refresh()
2047 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
2048 return True
2049
2050 year_noted = year_noted.get_pydt()
2051
2052 if year_noted >= pydt.datetime.now(tz=year_noted.tzinfo):
2053 gmDispatcher.send(signal='statustext', msg=_('Condition diagnosed in the future.'))
2054 self._PRW_year_noted.SetBackgroundColour('pink')
2055 self._PRW_year_noted.Refresh()
2056 wx.CallAfter(self._PRW_age_noted.SetText, u'', None, True)
2057 return True
2058
2059 self._PRW_year_noted.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
2060 self._PRW_year_noted.Refresh()
2061
2062 pat = gmPerson.gmCurrentPatient()
2063 if pat['dob'] is not None:
2064 issue_age = year_noted - pat['dob']
2065 str_age = gmDateTime.format_interval_medically(interval = issue_age)
2066 wx.CallAfter(self._PRW_age_noted.SetText, str_age, issue_age)
2067
2068 return True
2069 #--------------------------------------------------------
2073 #--------------------------------------------------------
2077 #================================================================
2078 # diagnostic certainty related widgets/functions
2079 #----------------------------------------------------------------
2081
2083
2084 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
2085
2086 self.selection_only = False # can be NULL, too
2087
2088 mp = gmMatchProvider.cMatchProvider_FixedList (
2089 aSeq = [
2090 {'data': u'A', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'A'), 'weight': 1},
2091 {'data': u'B', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'B'), 'weight': 1},
2092 {'data': u'C', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'C'), 'weight': 1},
2093 {'data': u'D', 'label': gmEMRStructItems.diagnostic_certainty_classification2str(u'D'), 'weight': 1}
2094 ]
2095 )
2096 mp.setThresholds(1, 2, 4)
2097 self.matcher = mp
2098
2099 self.SetToolTipString(_(
2100 "The diagnostic classification or grading of this assessment.\n"
2101 "\n"
2102 "This documents how certain one is about this being a true diagnosis."
2103 ))
2104 #================================================================
2105 # MAIN
2106 #----------------------------------------------------------------
2107 if __name__ == '__main__':
2108
2109 #================================================================
2111 """
2112 Test application for testing EMR struct widgets
2113 """
2114 #--------------------------------------------------------
2116 """
2117 Create test application UI
2118 """
2119 frame = wx.Frame (
2120 None,
2121 -4,
2122 'Testing EMR struct widgets',
2123 size=wx.Size(600, 400),
2124 style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
2125 )
2126 filemenu= wx.Menu()
2127 filemenu.AppendSeparator()
2128 filemenu.Append(ID_EXIT,"E&xit"," Terminate test application")
2129
2130 # Creating the menubar.
2131 menuBar = wx.MenuBar()
2132 menuBar.Append(filemenu,"&File")
2133
2134 frame.SetMenuBar(menuBar)
2135
2136 txt = wx.StaticText( frame, -1, _("Select desired test option from the 'File' menu"),
2137 wx.DefaultPosition, wx.DefaultSize, 0 )
2138
2139 # event handlers
2140 wx.EVT_MENU(frame, ID_EXIT, self.OnCloseWindow)
2141
2142 # patient EMR
2143 self.__pat = gmPerson.gmCurrentPatient()
2144
2145 frame.Show(1)
2146 return 1
2147 #--------------------------------------------------------
2153 #----------------------------------------------------------------
2155 app = wx.PyWidgetTester(size = (200, 300))
2156 emr = pat.get_emr()
2157 enc = emr.active_encounter
2158 #enc = gmEMRStructItems.cEncounter(1)
2159 pnl = cEncounterEditAreaPnl(app.frame, -1, encounter=enc)
2160 app.frame.Show(True)
2161 app.MainLoop()
2162 return
2163 #----------------------------------------------------------------
2165 app = wx.PyWidgetTester(size = (200, 300))
2166 emr = pat.get_emr()
2167 enc = emr.active_encounter
2168 #enc = gmEMRStructItems.cEncounter(1)
2169
2170 dlg = cEncounterEditAreaDlg(parent=app.frame, id=-1, size = (400,400), encounter=enc)
2171 dlg.ShowModal()
2172
2173 # pnl = cEncounterEditAreaDlg(app.frame, -1, encounter=enc)
2174 # app.frame.Show(True)
2175 # app.MainLoop()
2176 #----------------------------------------------------------------
2178 app = wx.PyWidgetTester(size = (200, 300))
2179 emr = pat.get_emr()
2180 epi = emr.get_episodes()[0]
2181 pnl = cEpisodeEditAreaPnl(app.frame, -1, episode=epi)
2182 app.frame.Show(True)
2183 app.MainLoop()
2184 #----------------------------------------------------------------
2186 app = wx.PyWidgetTester(size = (200, 300))
2187 emr = pat.get_emr()
2188 epi = emr.get_episodes()[0]
2189 edit_episode(parent=app.frame, episode=epi)
2190 #----------------------------------------------------------------
2192 app = wx.PyWidgetTester(size = (400, 40))
2193 app.SetWidget(cHospitalStayPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2194 app.MainLoop()
2195 #----------------------------------------------------------------
2197 app = wx.PyWidgetTester(size = (400, 40))
2198 app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(180,20), pos=(10,20))
2199 # app.SetWidget(cEpisodeSelectionPhraseWheel, id=-1, size=(350,20), pos=(10,20), patient_id=pat.ID)
2200 app.MainLoop()
2201 #----------------------------------------------------------------
2203 app = wx.PyWidgetTester(size = (200, 300))
2204 edit_health_issue(parent=app.frame, issue=None)
2205 #----------------------------------------------------------------
2207 app = wx.PyWidgetTester(size = (200, 300))
2208 app.SetWidget(cHealthIssueEditAreaPnl, id=-1, size = (400,400))
2209 app.MainLoop()
2210 #----------------------------------------------------------------
2214 #================================================================
2215
2216 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
2217
2218 gmI18N.activate_locale()
2219 gmI18N.install_domain()
2220 gmDateTime.init()
2221
2222 # obtain patient
2223 pat = gmPersonSearch.ask_for_patient()
2224 if pat is None:
2225 print "No patient. Exiting gracefully..."
2226 sys.exit(0)
2227 gmPatSearchWidgets.set_active_patient(patient=pat)
2228
2229 # try:
2230 # lauch emr dialogs test application
2231 # app = testapp(0)
2232 # app.MainLoop()
2233 # except StandardError:
2234 # _log.exception("unhandled exception caught !")
2235 # but re-raise them
2236 # raise
2237
2238 #test_encounter_edit_area_panel()
2239 #test_encounter_edit_area_dialog()
2240 #test_epsiode_edit_area_pnl()
2241 #test_episode_edit_area_dialog()
2242 #test_health_issue_edit_area_dlg()
2243 #test_episode_selection_prw()
2244 #test_hospital_stay_prw()
2245 test_edit_procedure()
2246
2247 #================================================================
2248
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Jun 7 03:58:39 2011 | http://epydoc.sourceforge.net |