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