| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed immunisation/vaccination widgets.
2
3 Modelled after Richard Terry's design document.
4
5 copyright: authors
6 """
7 #======================================================================
8 __version__ = "$Revision: 1.36 $"
9 __author__ = "R.Terry, S.J.Tan, K.Hilbert"
10 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
11
12 import sys, time, logging
13
14
15 import wx
16
17
18 if __name__ == '__main__':
19 sys.path.insert(0, '../../')
20 from Gnumed.pycommon import gmDispatcher, gmMatchProvider, gmTools, gmI18N
21 from Gnumed.pycommon import gmCfg, gmDateTime, gmNetworkTools
22 from Gnumed.business import gmPerson
23 from Gnumed.business import gmVaccination
24 from Gnumed.business import gmSurgery
25 from Gnumed.wxpython import gmPhraseWheel, gmTerryGuiParts, gmRegetMixin, gmGuiHelpers
26 from Gnumed.wxpython import gmEditArea
27 from Gnumed.wxpython import gmListWidgets
28
29
30 _log = logging.getLogger('gm.vaccination')
31 _log.info(__version__)
32
33 #======================================================================
34 # vaccination indication related widgets
35 #----------------------------------------------------------------------
37
38 if parent is None:
39 parent = wx.GetApp().GetTopWindow()
40 #------------------------------------------------------------
41 def refresh(lctrl):
42 inds = gmVaccination.get_indications(order_by = 'l10n_description')
43
44 items = [ [
45 i['l10n_description'],
46 gmTools.coalesce (
47 i['atcs_single_indication'],
48 u'',
49 u'%s'
50 ),
51 gmTools.coalesce (
52 i['atcs_combi_indication'],
53 u'',
54 u'%s'
55 ),
56 u'%s' % i['id']
57 ] for i in inds ]
58
59 lctrl.set_string_items(items)
60 lctrl.set_data(inds)
61 #------------------------------------------------------------
62 gmListWidgets.get_choices_from_list (
63 parent = parent,
64 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
65 caption = _('Showing vaccination preventable conditions.'),
66 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
67 single_selection = True,
68 refresh_callback = refresh
69 )
70 #----------------------------------------------------------------------
72
73 if parent is None:
74 parent = wx.GetApp().GetTopWindow()
75
76 if msg is None:
77 msg = _('Pick the relevant indications.')
78
79 if right_column is None:
80 right_columns = ['This vaccine']
81 else:
82 right_columns = [right_column]
83
84 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
85 picker.set_columns(columns = [_('Known indications')], columns_right = right_columns)
86 inds = gmVaccination.get_indications(order_by = 'l10n_description')
87 picker.set_choices (
88 choices = [ i['l10n_description'] for i in inds ],
89 data = inds
90 )
91 picker.set_picks (
92 picks = [ p['l10n_description'] for p in picks ],
93 data = picks
94 )
95 result = picker.ShowModal()
96
97 if result == wx.ID_CANCEL:
98 picker.Destroy()
99 return None
100
101 picks = picker.picks
102 picker.Destroy()
103 return picks
104
105 #======================================================================
106 # vaccines related widgets
107 #----------------------------------------------------------------------
109 ea = cVaccineEAPnl(parent = parent, id = -1)
110 ea.data = vaccine
111 ea.mode = gmTools.coalesce(vaccine, 'new', 'edit')
112 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
113 dlg.SetTitle(gmTools.coalesce(vaccine, _('Adding new vaccine'), _('Editing vaccine')))
114 if dlg.ShowModal() == wx.ID_OK:
115 dlg.Destroy()
116 return True
117 dlg.Destroy()
118 return False
119 #----------------------------------------------------------------------
121
122 if parent is None:
123 parent = wx.GetApp().GetTopWindow()
124 #------------------------------------------------------------
125 def delete(vaccine=None):
126 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
127 if deleted:
128 return True
129
130 gmGuiHelpers.gm_show_info (
131 _(
132 'Cannot delete vaccine\n'
133 '\n'
134 ' %s - %s (#%s)\n'
135 '\n'
136 'It is probably documented in a vaccination.'
137 ) % (
138 vaccine['vaccine'],
139 vaccine['preparation'],
140 vaccine['pk_vaccine']
141 ),
142 _('Deleting vaccine')
143 )
144
145 return False
146 #------------------------------------------------------------
147 def edit(vaccine=None):
148 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
149 #------------------------------------------------------------
150 def refresh(lctrl):
151 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
152
153 items = [ [
154 u'%s' % v['pk_brand'],
155 u'%s%s' % (
156 v['vaccine'],
157 gmTools.bool2subst (
158 v['is_fake_vaccine'],
159 u' (%s)' % _('fake'),
160 u''
161 )
162 ),
163 v['preparation'],
164 #u'%s (%s)' % (v['route_abbreviation'], v['route_description']),
165 #gmTools.bool2subst(v['is_live'], gmTools.u_checkmark_thin, u'', u'?'),
166 gmTools.coalesce(v['atc_code'], u''),
167 u'%s%s' % (
168 gmTools.coalesce(v['min_age'], u'?'),
169 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
170 ),
171 gmTools.coalesce(v['comment'], u'')
172 ] for v in vaccines ]
173 lctrl.set_string_items(items)
174 lctrl.set_data(vaccines)
175 #------------------------------------------------------------
176 gmListWidgets.get_choices_from_list (
177 parent = parent,
178 msg = _('\nThe vaccines currently known to GNUmed.\n'),
179 caption = _('Showing vaccines.'),
180 #columns = [ u'#', _('Brand'), _('Preparation'), _(u'Route'), _('Live'), _('ATC'), _('Age range'), _('Comment') ],
181 columns = [ u'#', _('Brand'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ],
182 single_selection = True,
183 refresh_callback = refresh,
184 edit_callback = edit,
185 new_callback = edit,
186 delete_callback = delete
187 )
188 #----------------------------------------------------------------------
190
192
193 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
194
195 context = {
196 u'ctxt_vaccine': {
197 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
198 u'placeholder': u'pk_vaccine'
199 }
200 }
201
202 query = u"""
203 SELECT data, field_label, list_label FROM (
204
205 SELECT distinct on (field_label)
206 data,
207 field_label,
208 list_label,
209 rank
210 FROM ((
211 -- batch_no by vaccine
212 SELECT
213 batch_no AS data,
214 batch_no AS field_label,
215 batch_no || ' (' || vaccine || ')' AS list_label,
216 1 as rank
217 FROM
218 clin.v_pat_vaccinations
219 WHERE
220 batch_no %(fragment_condition)s
221 %(ctxt_vaccine)s
222 ) UNION ALL (
223 -- batch_no for any vaccine
224 SELECT
225 batch_no AS data,
226 batch_no AS field_label,
227 batch_no || ' (' || vaccine || ')' AS list_label,
228 2 AS rank
229 FROM
230 clin.v_pat_vaccinations
231 WHERE
232 batch_no %(fragment_condition)s
233 )
234
235 ) AS matching_batch_nos
236
237 ) as unique_matches
238
239 ORDER BY rank, list_label
240 LIMIT 25
241 """
242 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
243 mp.setThresholds(1, 2, 3)
244 self.matcher = mp
245
246 self.unset_context(context = u'pk_vaccine')
247 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
248 self.selection_only = False
249 #----------------------------------------------------------------------
251
253
254 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
255
256 # consider ATCs in ref.branded_drug and vacc_indication
257 query = u"""
258 SELECT data, list_label, field_label FROM (
259
260 SELECT DISTINCT ON (data)
261 data,
262 list_label,
263 field_label
264 FROM ((
265 -- fragment -> vaccine
266 SELECT
267 pk_vaccine AS data,
268 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
269 vaccine AS field_label
270 FROM
271 clin.v_vaccines
272 WHERE
273 vaccine %(fragment_condition)s
274
275 ) union all (
276
277 -- fragment -> localized indication -> vaccines
278 SELECT
279 pk_vaccine AS data,
280 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
281 vaccine AS field_label
282 FROM
283 clin.v_indications4vaccine
284 WHERE
285 l10n_indication %(fragment_condition)s
286
287 ) union all (
288
289 -- fragment -> indication -> vaccines
290 SELECT
291 pk_vaccine AS data,
292 vaccine || ' (' || array_to_string(indications, ', ') || ')' AS list_label,
293 vaccine AS field_label
294 FROM
295 clin.v_indications4vaccine
296 WHERE
297 indication %(fragment_condition)s
298 )
299 ) AS distinct_total
300
301 ) AS total
302
303 ORDER by list_label
304 LIMIT 25
305 """
306 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
307 mp.setThresholds(1, 2, 3)
308 self.matcher = mp
309
310 self.selection_only = True
311 #------------------------------------------------------------------
314 #----------------------------------------------------------------------
315 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
316
318
320 try:
321 data = kwargs['vaccine']
322 del kwargs['vaccine']
323 except KeyError:
324 data = None
325
326 wxgVaccineEAPnl.wxgVaccineEAPnl.__init__(self, *args, **kwargs)
327 gmEditArea.cGenericEditAreaMixin.__init__(self)
328
329 self.mode = 'new'
330 self.data = data
331 if data is not None:
332 self.mode = 'edit'
333 #----------------------------------------------------------------
335 self._TCTRL_indications.SetValue(u'')
336 if len(self.__indications) == 0:
337 return
338 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
339 #----------------------------------------------------------------
340 # generic Edit Area mixin API
341 #----------------------------------------------------------------
343
344 has_errors = False
345
346 if self._PRW_brand.GetValue().strip() == u'':
347 has_errors = True
348 self._PRW_brand.display_as_valid(False)
349 else:
350 self._PRW_brand.display_as_valid(True)
351
352 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
353 self._PRW_atc.display_as_valid(True)
354 else:
355 if self._PRW_atc.GetData() is None:
356 self._PRW_atc.display_as_valid(True)
357 else:
358 has_errors = True
359 self._PRW_atc.display_as_valid(False)
360
361 val = self._PRW_age_min.GetValue().strip()
362 if val == u'':
363 self._PRW_age_min.display_as_valid(True)
364 else:
365 if gmDateTime.str2interval(val) is None:
366 has_errors = True
367 self._PRW_age_min.display_as_valid(False)
368 else:
369 self._PRW_age_min.display_as_valid(True)
370
371 val = self._PRW_age_max.GetValue().strip()
372 if val == u'':
373 self._PRW_age_max.display_as_valid(True)
374 else:
375 if gmDateTime.str2interval(val) is None:
376 has_errors = True
377 self._PRW_age_max.display_as_valid(False)
378 else:
379 self._PRW_age_max.display_as_valid(True)
380
381 # are we editing ?
382 ask_user = (self.mode == 'edit')
383 # is this vaccine in use ?
384 ask_user = (ask_user and self.data.is_in_use)
385 # a change ...
386 ask_user = ask_user and (
387 # ... of brand ...
388 (self.data['pk_brand'] != self._PRW_route.GetData())
389 or
390 # ... or indications ?
391 (set(self.data['pk_indications']) != set([ i['id'] for i in self.__indications ]))
392 )
393
394 if ask_user:
395 do_it = gmGuiHelpers.gm_show_question (
396 aTitle = _('Saving vaccine'),
397 aMessage = _(
398 u'This vaccine is already in use:\n'
399 u'\n'
400 u' "%s"\n'
401 u' (%s)\n'
402 u'\n'
403 u'Are you absolutely positively sure that\n'
404 u'you really want to edit this vaccine ?\n'
405 '\n'
406 u'This will change the vaccine name and/or target\n'
407 u'conditions in each patient this vaccine was\n'
408 u'used in to document a vaccination with.\n'
409 ) % (
410 self._PRW_brand.GetValue().strip(),
411 u', '.join(self.data['l10n_indications'])
412 )
413 )
414 if not do_it:
415 has_errors = True
416
417 return (has_errors is False)
418 #----------------------------------------------------------------
420
421 if len(self.__indications) == 0:
422 gmGuiHelpers.gm_show_info (
423 aTitle = _('Saving vaccine'),
424 aMessage = _('You must select at least one indication.')
425 )
426 return False
427
428 # save the data as a new instance
429 data = gmVaccination.create_vaccine (
430 pk_brand = self._PRW_brand.GetData(),
431 brand_name = self._PRW_brand.GetValue(),
432 pk_indications = [ i['id'] for i in self.__indications ]
433 )
434
435 # data['is_live'] = self._CHBOX_live.GetValue()
436 val = self._PRW_age_min.GetValue().strip()
437 if val != u'':
438 data['min_age'] = gmDateTime.str2interval(val)
439 val = self._PRW_age_max.GetValue().strip()
440 if val != u'':
441 data['max_age'] = gmDateTime.str2interval(val)
442 val = self._TCTRL_comment.GetValue().strip()
443 if val != u'':
444 data['comment'] = val
445
446 data.save()
447
448 drug = data.brand
449 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
450 val = self._PRW_atc.GetData()
451 if val is not None:
452 if val != u'J07':
453 drug['atc'] = val.strip()
454 drug.save()
455
456 # must be done very late or else the property access
457 # will refresh the display such that later field
458 # access will return empty values
459 self.data = data
460
461 return True
462 #----------------------------------------------------------------
464
465 if len(self.__indications) == 0:
466 gmGuiHelpers.gm_show_info (
467 aTitle = _('Saving vaccine'),
468 aMessage = _('You must select at least one indication.')
469 )
470 return False
471
472 drug = self.data.brand
473 drug['brand'] = self._PRW_brand.GetValue().strip()
474 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
475 val = self._PRW_atc.GetData()
476 if val is not None:
477 if val != u'J07':
478 drug['atc'] = val.strip()
479 drug.save()
480
481 # the validator already asked for changes so just do it
482 self.data.set_indications(pk_indications = [ i['id'] for i in self.__indications ])
483
484 # self.data['is_live'] = self._CHBOX_live.GetValue()
485 val = self._PRW_age_min.GetValue().strip()
486 if val != u'':
487 self.data['min_age'] = gmDateTime.str2interval(val)
488 if val != u'':
489 self.data['max_age'] = gmDateTime.str2interval(val)
490 val = self._TCTRL_comment.GetValue().strip()
491 if val != u'':
492 self.data['comment'] = val
493
494 self.data.save()
495 return True
496 #----------------------------------------------------------------
498 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True)
499 # self._CHBOX_live.SetValue(True)
500 self._CHBOX_fake.SetValue(False)
501 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True)
502 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
503 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
504 self._TCTRL_comment.SetValue(u'')
505
506 self.__indications = []
507 self.__refresh_indications()
508
509 self._PRW_brand.SetFocus()
510 #----------------------------------------------------------------
512 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
513 # self._CHBOX_live.SetValue(self.data['is_live'])
514 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
515 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
516 if self.data['min_age'] is None:
517 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
518 else:
519 self._PRW_age_min.SetText (
520 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
521 data = self.data['min_age']
522 )
523 if self.data['max_age'] is None:
524 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
525 else:
526 self._PRW_age_max.SetText (
527 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
528 data = self.data['max_age']
529 )
530 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
531
532 self.__indications = self.data.indications
533 self.__refresh_indications()
534
535 self._PRW_brand.SetFocus()
536 #----------------------------------------------------------------
539 #----------------------------------------------------------------
540 #----------------------------------------------------------------
555 #======================================================================
556 # vaccination related widgets
557 #----------------------------------------------------------------------
559 ea = cVaccinationEAPnl(parent = parent, id = -1)
560 ea.data = vaccination
561 ea.mode = gmTools.coalesce(vaccination, 'new', 'edit')
562 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
563 dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccinations'), _('Editing vaccination')))
564 if dlg.ShowModal() == wx.ID_OK:
565 dlg.Destroy()
566 return True
567 dlg.Destroy()
568 if not single_entry:
569 return True
570 return False
571 #----------------------------------------------------------------------
573
574 pat = gmPerson.gmCurrentPatient()
575 emr = pat.get_emr()
576
577 if parent is None:
578 parent = wx.GetApp().GetTopWindow()
579 #------------------------------------------------------------
580 def browse2schedules(vaccination=None):
581 dbcfg = gmCfg.cCfgSQL()
582 url = dbcfg.get2 (
583 option = 'external.urls.vaccination_plans',
584 workplace = gmSurgery.gmCurrentPractice().active_workplace,
585 bias = 'user',
586 default = u'http://www.bundesaerztekammer.de/downloads/STIKOEmpf2011.pdf'
587 )
588
589 gmNetworkTools.open_url_in_browser(url = url)
590 return False
591 #------------------------------------------------------------
592 def edit(vaccination=None):
593 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
594 #------------------------------------------------------------
595 def delete(vaccination=None):
596 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
597 return True
598 #------------------------------------------------------------
599 def refresh(lctrl):
600
601 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
602
603 items = [ [
604 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
605 v['vaccine'],
606 u', '.join(v['l10n_indications']),
607 v['batch_no'],
608 gmTools.coalesce(v['site'], u''),
609 gmTools.coalesce(v['reaction'], u''),
610 gmTools.coalesce(v['comment'], u'')
611 ] for v in vaccs ]
612
613 lctrl.set_string_items(items)
614 lctrl.set_data(vaccs)
615 #------------------------------------------------------------
616 gmListWidgets.get_choices_from_list (
617 parent = parent,
618 msg = _('\nComplete vaccination history for this patient.\n'),
619 caption = _('Showing vaccinations.'),
620 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
621 single_selection = True,
622 refresh_callback = refresh,
623 new_callback = edit,
624 edit_callback = edit,
625 delete_callback = delete,
626 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
627 )
628 #----------------------------------------------------------------------
629 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
630
631 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
632 """
633 - warn on apparent duplicates
634 - ask if "missing" (= previous, non-recorded) vaccinations
635 should be estimated and saved (add note "auto-generated")
636
637 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
638 """
640
641 try:
642 data = kwargs['vaccination']
643 del kwargs['vaccination']
644 except KeyError:
645 data = None
646
647 wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs)
648 gmEditArea.cGenericEditAreaMixin.__init__(self)
649
650 self.mode = 'new'
651 self.data = data
652 if data is not None:
653 self.mode = 'edit'
654
655 self.__init_ui()
656 #----------------------------------------------------------------
658 # adjust phrasewheels etc
659 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
660 self._PRW_provider.selection_only = False
661 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
662 if self.mode == 'edit':
663 self._BTN_select_indications.Disable()
664 #----------------------------------------------------------------
666
667 vaccine = self._PRW_vaccine.GetData(as_instance=True)
668
669 # if we are editing we do not allow using indications rather than a vaccine
670 if self.mode == u'edit':
671 if vaccine is None:
672 self._PRW_batch.unset_context(context = 'pk_vaccine')
673 self.__indications = []
674 else:
675 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
676 self.__indications = vaccine.indications
677 # we are entering a new vaccination
678 else:
679 if vaccine is None:
680 self._PRW_batch.unset_context(context = 'pk_vaccine')
681 self.__indications = []
682 self._BTN_select_indications.Enable()
683 else:
684 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
685 self.__indications = vaccine.indications
686 self._BTN_select_indications.Disable()
687
688 self.__refresh_indications()
689 #----------------------------------------------------------------
691 if self._PRW_reaction.GetValue().strip() == u'':
692 self._BTN_report.Enable(False)
693 else:
694 self._BTN_report.Enable(True)
695 #----------------------------------------------------------------
697 self._TCTRL_indications.SetValue(u'')
698 if len(self.__indications) == 0:
699 return
700 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
701 #----------------------------------------------------------------
702 # generic Edit Area mixin API
703 #----------------------------------------------------------------
705
706 has_errors = False
707
708 if not self._PRW_date_given.is_valid_timestamp(allow_empty = False):
709 has_errors = True
710
711 vaccine = self._PRW_vaccine.GetData(as_instance = True)
712
713 # we are editing, require vaccine rather than indications
714 if self.mode == u'edit':
715 if vaccine is None:
716 has_errors = True
717 self._PRW_vaccine.display_as_valid(False)
718 else:
719 self._PRW_vaccine.display_as_valid(True)
720 # we are creating, allow either vaccine or indications
721 else:
722 if vaccine is None:
723 if len(self.__indications) == 0:
724 self._PRW_vaccine.display_as_valid(False)
725 has_errors = True
726 else:
727 self._PRW_vaccine.display_as_valid(True)
728 else:
729 self._PRW_vaccine.display_as_valid(True)
730
731 if self._PRW_batch.GetValue().strip() == u'':
732 has_errors = True
733 self._PRW_batch.display_as_valid(False)
734 else:
735 self._PRW_batch.display_as_valid(True)
736
737 if self._PRW_episode.GetValue().strip() == u'':
738 self._PRW_episode.SetText(value = _('prevention'))
739
740 return (has_errors is False)
741 #----------------------------------------------------------------
743
744 vaccine = self._PRW_vaccine.GetData()
745 if vaccine is None:
746 data = self.__save_new_from_indications()
747 else:
748 data = self.__save_new_from_vaccine(vaccine = vaccine)
749
750 # must be done very late or else the property access
751 # will refresh the display such that later field
752 # access will return empty values
753 self.data = data
754
755 return True
756 #----------------------------------------------------------------
758
759 if len(self.__indications) == 0:
760 gmGuiHelpers.gm_show_info (
761 aTitle = _('Saving vaccination'),
762 aMessage = _('You must select at least one indication.')
763 )
764 return False
765
766 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ i['description'] for i in self.__indications ])
767
768 if vaccine is None:
769 for ind in self.__indications:
770 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ind['description']])
771 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
772 else:
773 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
774
775 return data
776 #----------------------------------------------------------------
778
779 emr = gmPerson.gmCurrentPatient().get_emr()
780
781 data = emr.add_vaccination (
782 episode = self._PRW_episode.GetData(can_create = True, is_open = False),
783 vaccine = vaccine,
784 batch_no = self._PRW_batch.GetValue().strip()
785 )
786
787 if self._CHBOX_anamnestic.GetValue() is True:
788 data['soap_cat'] = u's'
789 else:
790 data['soap_cat'] = u'p'
791
792 data['date_given'] = self._PRW_date_given.GetData()
793 data['site'] = self._PRW_site.GetValue().strip()
794 data['pk_provider'] = self._PRW_provider.GetData()
795 data['reaction'] = self._PRW_reaction.GetValue().strip()
796 data['comment'] = self._TCTRL_comment.GetValue().strip()
797
798 data.save()
799
800 return data
801 #----------------------------------------------------------------
803
804 if self._CHBOX_anamnestic.GetValue() is True:
805 self.data['soap_cat'] = u's'
806 else:
807 self.data['soap_cat'] = u'p'
808
809 self.data['date_given'] = self._PRW_date_given.GetData()
810 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
811 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
812 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
813 self.data['site'] = self._PRW_site.GetValue().strip()
814 self.data['pk_provider'] = self._PRW_provider.GetData()
815 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
816 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
817
818 self.data.save()
819
820 return True
821 #----------------------------------------------------------------
823 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
824 self._CHBOX_anamnestic.SetValue(False)
825 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
826 self._PRW_batch.unset_context(context = 'pk_vaccine')
827 self._PRW_batch.SetValue(u'')
828 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
829 self._PRW_site.SetValue(u'')
830 self._PRW_provider.SetData(data = None)
831 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
832 self._BTN_report.Enable(False)
833 self._TCTRL_comment.SetValue(u'')
834
835 self.__indications = []
836 self.__refresh_indications()
837 self._BTN_select_indications.Enable()
838
839 self._PRW_date_given.SetFocus()
840 #----------------------------------------------------------------
842 self._PRW_date_given.SetText(data = self.data['date_given'])
843 if self.data['soap_cat'] == u's':
844 self._CHBOX_anamnestic.SetValue(True)
845 else:
846 self._CHBOX_anamnestic.SetValue(False)
847 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
848
849 self._PRW_batch.SetValue(self.data['batch_no'])
850 self._PRW_episode.SetData(data = self.data['pk_episode'])
851 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
852 self._PRW_provider.SetData(self.data['pk_provider'])
853 self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], u''))
854 if self.data['reaction'] is None:
855 self._BTN_report.Enable(False)
856 else:
857 self._BTN_report.Enable(True)
858 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
859
860 self.__indications = self.data.vaccine.indications
861 self.__refresh_indications()
862 self._BTN_select_indications.Disable()
863
864 self._PRW_date_given.SetFocus()
865 #----------------------------------------------------------------
867 self._PRW_date_given.SetText(data = self.data['date_given'])
868 #self._CHBOX_anamnestic.SetValue(False)
869 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
870
871 self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine'])
872 self._PRW_batch.SetValue(u'')
873
874 self._PRW_episode.SetData(data = self.data['pk_episode'])
875 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
876 self._PRW_provider.SetData(self.data['pk_provider'])
877 self._PRW_reaction.SetValue(u'')
878 self._BTN_report.Enable(False)
879 self._TCTRL_comment.SetValue(u'')
880
881 self.__indications = self.data.vaccine.indications
882 self.__refresh_indications()
883 self._BTN_select_indications.Enable()
884
885 self._PRW_date_given.SetFocus()
886 #----------------------------------------------------------------
887 # event handlers
888 #----------------------------------------------------------------
906 #----------------------------------------------------------------
909 # FIXME: could set newly generated vaccine here
910 #----------------------------------------------------------------
925 #======================================================================
926 #======================================================================
928
930 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
931 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
932 self.__pat = gmPerson.gmCurrentPatient()
933 # do this here so "import cImmunisationsPanel from gmVaccWidgets" works
934 self.ID_VaccinatedIndicationsList = wx.NewId()
935 self.ID_VaccinationsPerRegimeList = wx.NewId()
936 self.ID_MissingShots = wx.NewId()
937 self.ID_ActiveSchedules = wx.NewId()
938 self.__do_layout()
939 self.__register_interests()
940 self.__reset_ui_content()
941 #----------------------------------------------------
943 #-----------------------------------------------
944 # top part
945 #-----------------------------------------------
946 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
947 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
948
949 #-----------------------------------------------
950 # middle part
951 #-----------------------------------------------
952 # divider headings below editing area
953 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
954 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
955 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
956 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
957 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
958 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
959 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
960
961 # left list: indications for which vaccinations have been given
962 self.LBOX_vaccinated_indications = wx.ListBox(
963 parent = self,
964 id = self.ID_VaccinatedIndicationsList,
965 choices = [],
966 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
967 )
968 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
969
970 # right list: when an indication has been selected on the left
971 # display the corresponding vaccinations on the right
972 self.LBOX_given_shots = wx.ListBox(
973 parent = self,
974 id = self.ID_VaccinationsPerRegimeList,
975 choices = [],
976 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
977 )
978 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
979
980 self.LBOX_active_schedules = wx.ListBox (
981 parent = self,
982 id = self.ID_ActiveSchedules,
983 choices = [],
984 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
985 )
986 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
987
988 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
989 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
990 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
991 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
992
993 #---------------------------------------------
994 # bottom part
995 #---------------------------------------------
996 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
997 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
998 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
999
1000 self.LBOX_missing_shots = wx.ListBox (
1001 parent = self,
1002 id = self.ID_MissingShots,
1003 choices = [],
1004 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1005 )
1006 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1007
1008 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1009 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1010
1011 # alert caption
1012 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1013
1014 #---------------------------------------------
1015 # add all elements to the main background sizer
1016 #---------------------------------------------
1017 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1018 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1019 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1020 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1021 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1022 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1023 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1024 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1025
1026 self.SetAutoLayout(True)
1027 self.SetSizer(self.mainsizer)
1028 self.mainsizer.Fit(self)
1029 #----------------------------------------------------
1031 # wxPython events
1032 wx.EVT_SIZE(self, self.OnSize)
1033 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1034 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1035 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1036 # wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton)
1037
1038 # client internal signals
1039 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1040 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1041 #----------------------------------------------------
1042 # event handlers
1043 #----------------------------------------------------
1047 #----------------------------------------------------
1049 """Paste previously given shot into edit area.
1050 """
1051 self.editarea.set_data(aVacc=event.GetClientData())
1052 #----------------------------------------------------
1054 self.editarea.set_data(aVacc = event.GetClientData())
1055 #----------------------------------------------------
1057 """Update right hand middle list to show vaccinations given for selected indication."""
1058 ind_list = event.GetEventObject()
1059 selected_item = ind_list.GetSelection()
1060 ind = ind_list.GetClientData(selected_item)
1061 # clear list
1062 self.LBOX_given_shots.Set([])
1063 emr = self.__pat.get_emr()
1064 shots = emr.get_vaccinations(indications = [ind])
1065 # FIXME: use Set() for entire array (but problem with client_data)
1066 for shot in shots:
1067 if shot['is_booster']:
1068 marker = 'B'
1069 else:
1070 marker = '#%s' % shot['seq_no']
1071 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1072 self.LBOX_given_shots.Append(label, shot)
1073 #----------------------------------------------------
1075 # clear edit area
1076 self.editarea.set_data()
1077 # clear lists
1078 self.LBOX_vaccinated_indications.Clear()
1079 self.LBOX_given_shots.Clear()
1080 self.LBOX_active_schedules.Clear()
1081 self.LBOX_missing_shots.Clear()
1082 #----------------------------------------------------
1084 # clear lists
1085 self.LBOX_vaccinated_indications.Clear()
1086 self.LBOX_given_shots.Clear()
1087 self.LBOX_active_schedules.Clear()
1088 self.LBOX_missing_shots.Clear()
1089
1090 emr = self.__pat.get_emr()
1091
1092 t1 = time.time()
1093 # populate vaccinated-indications list
1094 # FIXME: consider adding virtual indication "most recent" to
1095 # FIXME: display most recent of all indications as suggested by Syan
1096 status, indications = emr.get_vaccinated_indications()
1097 # FIXME: would be faster to use Set() but can't
1098 # use Set(labels, client_data), and have to know
1099 # line position in SetClientData :-(
1100 for indication in indications:
1101 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1102 # self.LBOX_vaccinated_indications.Set(lines)
1103 # self.LBOX_vaccinated_indications.SetClientData(data)
1104 print "vaccinated indications took", time.time()-t1, "seconds"
1105
1106 t1 = time.time()
1107 # populate active schedules list
1108 scheds = emr.get_scheduled_vaccination_regimes()
1109 if scheds is None:
1110 label = _('ERROR: cannot retrieve active vaccination schedules')
1111 self.LBOX_active_schedules.Append(label)
1112 elif len(scheds) == 0:
1113 label = _('no active vaccination schedules')
1114 self.LBOX_active_schedules.Append(label)
1115 else:
1116 for sched in scheds:
1117 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1118 self.LBOX_active_schedules.Append(label)
1119 print "active schedules took", time.time()-t1, "seconds"
1120
1121 t1 = time.time()
1122 # populate missing-shots list
1123 missing_shots = emr.get_missing_vaccinations()
1124 print "getting missing shots took", time.time()-t1, "seconds"
1125 if missing_shots is None:
1126 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1127 self.LBOX_missing_shots.Append(label, None)
1128 return True
1129 # due
1130 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1131 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1132 for shot in missing_shots['due']:
1133 if shot['overdue']:
1134 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1135 weeks = days_left / 7
1136 # amount_overdue, seq_no, indication, regime, vacc_comment
1137 label = overdue_template % (
1138 years,
1139 weeks,
1140 shot['seq_no'],
1141 shot['l10n_indication'],
1142 shot['regime'],
1143 shot['vacc_comment']
1144 )
1145 self.LBOX_missing_shots.Append(label, shot)
1146 else:
1147 # time_left, seq_no, regime, latest_due, vacc_comment
1148 label = due_template % (
1149 shot['time_left'].days / 7,
1150 shot['seq_no'],
1151 shot['indication'],
1152 shot['regime'],
1153 shot['latest_due'].strftime('%m/%Y'),
1154 shot['vacc_comment']
1155 )
1156 self.LBOX_missing_shots.Append(label, shot)
1157 # booster
1158 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1159 for shot in missing_shots['boosters']:
1160 # indication, regime, vacc_comment
1161 label = lbl_template % (
1162 shot['l10n_indication'],
1163 shot['regime'],
1164 shot['vacc_comment']
1165 )
1166 self.LBOX_missing_shots.Append(label, shot)
1167 print "displaying missing shots took", time.time()-t1, "seconds"
1168
1169 return True
1170 #----------------------------------------------------
1173 # FIXME:
1174 # if has_focus:
1175 # wxCallAfter(self.__reset_ui_content)
1176 # else:
1177 # return 1
1178 #----------------------------------------------------
1181 # FIXME:
1182 # if has_focus:
1183 # wxCallAfter(self.__reset_ui_content)
1184 # else:
1185 # is_stale == True
1186 # return 1
1187 #======================================================================
1188 # main
1189 #----------------------------------------------------------------------
1190 if __name__ == "__main__":
1191
1192 if len(sys.argv) < 2:
1193 sys.exit()
1194
1195 if sys.argv[1] != u'test':
1196 sys.exit()
1197
1198 app = wx.PyWidgetTester(size = (600, 600))
1199 app.SetWidget(cATCPhraseWheel, -1)
1200 app.MainLoop()
1201 #======================================================================
1202
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 25 03:58:47 2012 | http://epydoc.sourceforge.net |