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 (details at http://www.gnu.org)"
11
12 import sys, time, logging, webbrowser
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
22 from Gnumed.business import gmPerson, gmVaccination, gmSurgery
23 from Gnumed.wxpython import gmPhraseWheel, gmTerryGuiParts, gmRegetMixin, gmGuiHelpers
24 from Gnumed.wxpython import gmEditArea, gmListWidgets
25
26
27 _log = logging.getLogger('gm.vaccination')
28 _log.info(__version__)
29
30
31
32
34
35 if parent is None:
36 parent = wx.GetApp().GetTopWindow()
37
38 def refresh(lctrl):
39 inds = gmVaccination.get_indications(order_by = 'description')
40
41 items = [ [
42 i['description'],
43 gmTools.coalesce (
44 i['atcs_single_indication'],
45 u'',
46 u'%s'
47 ),
48 gmTools.coalesce (
49 i['atcs_combi_indication'],
50 u'',
51 u'%s'
52 ),
53 u'%s' % i['id']
54 ] for i in inds ]
55
56 lctrl.set_string_items(items)
57 lctrl.set_data(inds)
58
59 gmListWidgets.get_choices_from_list (
60 parent = parent,
61 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
62 caption = _('Showing vaccination preventable conditions.'),
63 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
64 single_selection = True,
65 refresh_callback = refresh
66 )
67
68 from Gnumed.wxGladeWidgets import wxgVaccinationIndicationsPnl
69
71
73
74 wxgVaccinationIndicationsPnl.wxgVaccinationIndicationsPnl.__init__(self, *args, **kwargs)
75
76 self.__indication2field = {
77 u'coxiella burnetii (Q fever)': self._CHBOX_coxq,
78 u'salmonella typhi (typhoid)': self._CHBOX_typhoid,
79 u'varicella (chickenpox, shingles)': self._CHBOX_varicella,
80 u'influenza (seasonal)': self._CHBOX_influenza,
81 u'bacillus anthracis (Anthrax)': self._CHBOX_anthrax,
82 u'human papillomavirus': self._CHBOX_hpv,
83 u'rotavirus': self._CHBOX_rota,
84 u'tuberculosis': self._CHBOX_tuberculosis,
85 u'variola virus (smallpox)': self._CHBOX_smallpox,
86 u'influenza (H1N1)': self._CHBOX_h1n1,
87 u'cholera': self._CHBOX_cholera,
88 u'diphtheria': self._CHBOX_diphtheria,
89 u'haemophilus influenzae b': self._CHBOX_hib,
90 u'hepatitis A': self._CHBOX_hepA,
91 u'hepatitis B': self._CHBOX_hepB,
92 u'japanese B encephalitis': self._CHBOX_japanese,
93 u'measles': self._CHBOX_measles,
94 u'meningococcus A': self._CHBOX_menA,
95 u'meningococcus C': self._CHBOX_menC,
96 u'meningococcus W': self._CHBOX_menW,
97 u'meningococcus Y': self._CHBOX_menY,
98 u'mumps': self._CHBOX_mumps,
99 u'pertussis': self._CHBOX_pertussis,
100 u'pneumococcus': self._CHBOX_pneumococcus,
101 u'poliomyelitis': self._CHBOX_polio,
102 u'rabies': self._CHBOX_rabies,
103 u'rubella': self._CHBOX_rubella,
104 u'tetanus': self._CHBOX_tetanus,
105 u'tick-borne meningoencephalitis': self._CHBOX_fsme,
106 u'yellow fever': self._CHBOX_yellow_fever,
107 u'yersinia pestis': self._CHBOX_yersinia_pestis
108 }
109
111 for field in self.__dict__.keys():
112 if field.startswith('_CHBOX_'):
113 self.__dict__[field].Enable()
114 self.Enable()
115
117 for field in self.__dict__.keys():
118 if field.startswith('_CHBOX_'):
119 self.__dict__[field].Disable()
120 self.Disable()
121
123 for field in self.__dict__.keys():
124 if field.startswith('_CHBOX_'):
125 self.__dict__[field].SetValue(False)
126
127 - def select(self, indications=None):
128 for indication in indications:
129 self.__indication2field[indication].SetValue(True)
130
132 indications = []
133 for indication in self.__indication2field.keys():
134 if self.__indication2field[indication].IsChecked():
135 indications.append(indication)
136 return indications
137
138 selected_indications = property(_get_selected_indications, lambda x:x)
139
141 for indication in self.__indication2field.keys():
142 if self.__indication2field[indication].IsChecked():
143 return True
144 return False
145
146 has_selection = property(_get_has_selection, lambda x:x)
147
148
149
150
151 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
162
164
165 if parent is None:
166 parent = wx.GetApp().GetTopWindow()
167
168 def delete(vaccine=None):
169 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
170 if deleted:
171 return True
172
173 gmGuiHelpers.gm_show_info (
174 _(
175 'Cannot delete vaccine\n'
176 '\n'
177 ' %s - %s (#%s)\n'
178 '\n'
179 'It is probably documented in a vaccination.'
180 ) % (
181 vaccine['vaccine'],
182 vaccine['preparation'],
183 vaccine['pk_vaccine']
184 ),
185 _('Deleting vaccine')
186 )
187
188 return False
189
190 def edit(vaccine=None):
191 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
192
193 def refresh(lctrl):
194 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
195
196 items = [ [
197 u'%s' % v['pk_brand'],
198 u'%s%s' % (
199 v['vaccine'],
200 gmTools.bool2subst (
201 v['is_fake_vaccine'],
202 u' (%s)' % _('fake'),
203 u''
204 )
205 ),
206 v['preparation'],
207 u'%s (%s)' % (v['route_abbreviation'], v['route_description']),
208 gmTools.bool2subst(v['is_live'], gmTools.u_checkmark_thin, u''),
209 gmTools.coalesce(v['atc_code'], u''),
210 u'%s%s' % (
211 gmTools.coalesce(v['min_age'], u'?'),
212 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
213 ),
214 gmTools.coalesce(v['comment'], u'')
215 ] for v in vaccines ]
216 lctrl.set_string_items(items)
217 lctrl.set_data(vaccines)
218
219 gmListWidgets.get_choices_from_list (
220 parent = parent,
221 msg = _('\nThe vaccines currently known to GNUmed.\n'),
222 caption = _('Showing vaccines.'),
223 columns = [ u'#', _('Brand'), _('Preparation'), _(u'Route'), _('Live'), _('ATC'), _('Age range'), _('Comment') ],
224 single_selection = True,
225 refresh_callback = refresh,
226 edit_callback = edit,
227 new_callback = edit,
228 delete_callback = delete
229 )
230
232
234
235 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
236
237 context = {
238 u'ctxt_vaccine': {
239 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
240 u'placeholder': u'pk_vaccine'
241 }
242 }
243
244 query = u"""
245 SELECT code, batch_no FROM (
246
247 SELECT distinct on (batch_no) code, batch_no, rank FROM (
248
249 (
250 -- batch_no by vaccine
251 SELECT
252 batch_no AS code,
253 batch_no,
254 1 AS rank
255 FROM
256 clin.v_pat_vaccinations
257 WHERE
258 batch_no %(fragment_condition)s
259 %(ctxt_vaccine)s
260 ) UNION ALL (
261 -- batch_no for any vaccine
262 SELECT
263 batch_no AS code,
264 batch_no,
265 2 AS rank
266 FROM
267 clin.v_pat_vaccinations
268 WHERE
269 batch_no %(fragment_condition)s
270 )
271
272 ) AS matching_batch_nos
273
274 ) as unique_matches
275
276 ORDER BY rank, batch_no
277 LIMIT 25
278 """
279 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
280 mp.setThresholds(1, 2, 3)
281 self.matcher = mp
282
283 self.unset_context(context = u'pk_vaccine')
284 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
285 self.selection_only = False
286
288
290
291 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
292
293
294 query = u"""
295 SELECT pk_vaccine, description FROM (
296
297 SELECT DISTINCT ON (pk_vaccine) pk_vaccine, description FROM (
298
299 (
300 -- fragment -> vaccine
301 SELECT
302 pk_vaccine,
303 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')'
304 AS description
305 FROM
306 clin.v_vaccines
307 WHERE
308 vaccine %(fragment_condition)s
309
310 ) union all (
311
312 -- fragment -> localized indication -> vaccines
313 SELECT
314 pk_vaccine,
315 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')'
316 AS description
317 FROM
318 clin.v_indications4vaccine
319 WHERE
320 l10n_indication %(fragment_condition)s
321
322 ) union all (
323
324 -- fragment -> indication -> vaccines
325 SELECT
326 pk_vaccine,
327 vaccine || ' (' || array_to_string(indications, ', ') || ')'
328 AS description
329 FROM
330 clin.v_indications4vaccine
331 WHERE
332 indication %(fragment_condition)s
333 )
334 ) AS distinct_total
335
336 ) AS total
337
338 ORDER by description
339 LIMIT 25
340 """
341 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
342 mp.setThresholds(1, 2, 3)
343 self.matcher = mp
344
345 self.selection_only = True
346
349
350 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
351
352 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
353
371
373
374
375 query = u"""
376 SELECT DISTINCT ON (abbreviation)
377 id,
378 abbreviation || ' (' || _(description) || ')'
379 FROM
380 clin.vacc_route
381 WHERE
382 abbreviation %(fragment_condition)s
383 OR
384 description %(fragment_condition)s
385 ORDER BY
386 abbreviation
387 """
388 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
389 mp.setThresholds(1, 2, 3)
390 self._PRW_route.matcher = mp
391 self._PRW_route.selection_only = True
392
393
394
395
396 self.Layout()
397 self.Fit()
398
399
400
402
403 has_errors = False
404
405 if self._PRW_brand.GetValue().strip() == u'':
406 has_errors = True
407 self._PRW_brand.display_as_valid(False)
408 else:
409 self._PRW_brand.display_as_valid(True)
410
411 if self._PRW_route.GetData() is None:
412 has_errors = True
413 self._PRW_route.display_as_valid(False)
414 else:
415 self._PRW_route.display_as_valid(True)
416
417 if not self._PNL_indications.has_selection:
418 has_errors = True
419
420 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
421 self._PRW_atc.display_as_valid(True)
422 else:
423 if self._PRW_atc.GetData() is None:
424 self._PRW_atc.display_as_valid(True)
425 else:
426 has_errors = True
427 self._PRW_atc.display_as_valid(False)
428
429 val = self._PRW_age_min.GetValue().strip()
430 if val == u'':
431 self._PRW_age_min.display_as_valid(True)
432 else:
433 if gmDateTime.str2interval(val) is None:
434 has_errors = True
435 self._PRW_age_min.display_as_valid(False)
436 else:
437 self._PRW_age_min.display_as_valid(True)
438
439 val = self._PRW_age_max.GetValue().strip()
440 if val == u'':
441 self._PRW_age_max.display_as_valid(True)
442 else:
443 if gmDateTime.str2interval(val) is None:
444 has_errors = True
445 self._PRW_age_max.display_as_valid(False)
446 else:
447 self._PRW_age_max.display_as_valid(True)
448
449
450 ask_user = (self.mode == 'edit')
451
452 ask_user = (ask_user and self.data.is_in_use)
453
454 ask_user = ask_user and (
455
456 (self.data['pk_brand'] != self._PRW_route.GetData())
457 or
458
459 (self.data['indications'] != self._PNL_indications.selected_indications)
460 )
461
462 if ask_user:
463 do_it = gmGuiHelpers.gm_show_question (
464 aTitle = _('Saving vaccine'),
465 aMessage = _(
466 u'This vaccine is already in use:\n'
467 u'\n'
468 u' "%s"\n'
469 u' (%s)\n'
470 u'\n'
471 u'Are you absolutely positively sure that\n'
472 u'you really want to edit this vaccine ?\n'
473 '\n'
474 u'This will change the vaccine name and/or target\n'
475 u'conditions in each patient this vaccine was\n'
476 u'used in to document a vaccination with.\n'
477 ) % (
478 self._PRW_brand.GetValue().strip(),
479 u', '.join(self.data['l10n_indications'])
480 )
481 )
482 if not do_it:
483 has_errors = True
484
485 return (has_errors is False)
486
523
551
564
566 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
567 self._PRW_route.SetText(value = self.data['route_description'], data = self.data['pk_route'])
568 self._CHBOX_live.SetValue(self.data['is_live'])
569 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
570 self._PNL_indications.select(self.data['indications'])
571 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
572 if self.data['min_age'] is None:
573 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
574 else:
575 self._PRW_age_min.SetText (
576 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
577 data = self.data['min_age']
578 )
579 if self.data['max_age'] is None:
580 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
581 else:
582 self._PRW_age_max.SetText (
583 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
584 data = self.data['max_age']
585 )
586 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
587
588 self._PRW_brand.SetFocus()
589
591 self._refresh_as_new()
592
593
594
606
608
609 pat = gmPerson.gmCurrentPatient()
610 emr = pat.get_emr()
611
612 if parent is None:
613 parent = wx.GetApp().GetTopWindow()
614
615 def browse2schedules(vaccination=None):
616 dbcfg = gmCfg.cCfgSQL()
617 url = dbcfg.get2 (
618 option = 'external.urls.vaccination_plans',
619 workplace = gmSurgery.gmCurrentPractice().active_workplace,
620 bias = 'user',
621 default = u'http://www.bundesaerztekammer.de/downloads/ImpfempfehlungenRKI2009.pdf'
622 )
623
624 webbrowser.open (
625 url = url,
626 new = False,
627 autoraise = True
628 )
629 return False
630
631 def edit(vaccination=None):
632 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = True)
633
634 def delete(vaccination=None):
635 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
636 return True
637
638 def refresh(lctrl):
639
640 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
641
642 items = [ [
643 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
644 v['vaccine'],
645 u', '.join(v['l10n_indications']),
646 v['batch_no'],
647 gmTools.coalesce(v['site'], u''),
648 gmTools.coalesce(v['reaction'], u''),
649 gmTools.coalesce(v['comment'], u'')
650 ] for v in vaccs ]
651
652 lctrl.set_string_items(items)
653 lctrl.set_data(vaccs)
654
655 gmListWidgets.get_choices_from_list (
656 parent = parent,
657 msg = _('\nComplete vaccination history for this patient.\n'),
658 caption = _('Showing vaccinations.'),
659 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
660 single_selection = True,
661 refresh_callback = refresh,
662 new_callback = edit,
663 edit_callback = edit,
664 delete_callback = delete,
665 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
666 )
667
668 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
669
670 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
671 """
672 - warn on apparent duplicates
673 - ask if "missing" (= previous, non-recorded) vaccinations
674 should be estimated and saved (add note "auto-generated")
675
676 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
677 """
695
702
704
705 vaccine = self._PRW_vaccine.GetData(as_instance=True)
706
707
708 if self.mode == u'edit':
709 self._PNL_indications.clear_all()
710 if vaccine is None:
711 self._PRW_batch.unset_context(context = 'pk_vaccine')
712 else:
713 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
714 self._PNL_indications.select(indications = vaccine['indications'])
715 self._PNL_indications.disable_all()
716
717
718 else:
719 if vaccine is None:
720 self._PRW_batch.unset_context(context = 'pk_vaccine')
721 self._PNL_indications.enable_all()
722 else:
723 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
724 self._PNL_indications.clear_all()
725 self._PNL_indications.select(indications = vaccine['indications'])
726 self._PNL_indications.disable_all()
727
729 if self._PRW_reaction.GetValue().strip() == u'':
730 self._BTN_report.Enable(False)
731 else:
732 self._BTN_report.Enable(True)
733
734
735
737
738 has_errors = False
739
740 if not self._DP_date_given.is_valid_timestamp(allow_none = False):
741 has_errors = True
742
743 vaccine = self._PRW_vaccine.GetData(as_instance = True)
744
745
746 if self.mode == u'edit':
747 if vaccine is None:
748 has_errors = True
749 self._PRW_vaccine.display_as_valid(False)
750 else:
751 self._PRW_vaccine.display_as_valid(True)
752 self._PNL_indications.clear_all()
753 self._PNL_indications.select(indications = vaccine['indications'])
754 self._PNL_indications.disable_all()
755
756 else:
757 if vaccine is None:
758 if self._PNL_indications.has_selection:
759 self._PRW_vaccine.display_as_valid(True)
760 else:
761 has_errors = True
762 self._PRW_vaccine.display_as_valid(False)
763 else:
764 self._PRW_vaccine.display_as_valid(True)
765
766 if self._PRW_batch.GetValue().strip() == u'':
767 has_errors = True
768 self._PRW_batch.display_as_valid(False)
769 else:
770 self._PRW_batch.display_as_valid(True)
771
772 if self._PRW_episode.GetValue().strip() == u'':
773 self._PRW_episode.SetText(value = _('prevention'))
774
775 return (has_errors is False)
776
778
779 vaccine = self._PRW_vaccine.GetData()
780 if vaccine is None:
781 data = self.__save_new_from_indications()
782 else:
783 data = self.__save_new_from_vaccine(vaccine = vaccine)
784
785
786
787
788 self.data = data
789
790 return True
791
805
830
832
833 if self._CHBOX_anamnestic.GetValue() is True:
834 self.data['soap_cat'] = u's'
835 else:
836 self.data['soap_cat'] = u'p'
837
838 self.data['date_given'] = self._DP_date_given.get_pydt()
839 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
840 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
841 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
842 self.data['site'] = self._PRW_site.GetValue().strip()
843 self.data['pk_provider'] = self._PRW_provider.GetData()
844 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
845 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
846
847 self.data.save()
848
849 return True
850
868
893
914
915
916
938
941
942
943
945
947 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
948 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
949 self.__pat = gmPerson.gmCurrentPatient()
950
951 self.ID_VaccinatedIndicationsList = wx.NewId()
952 self.ID_VaccinationsPerRegimeList = wx.NewId()
953 self.ID_MissingShots = wx.NewId()
954 self.ID_ActiveSchedules = wx.NewId()
955 self.__do_layout()
956 self.__register_interests()
957 self.__reset_ui_content()
958
960
961
962
963 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
964 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
965
966
967
968
969
970 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
971 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
972 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
973 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
974 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
975 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
976 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
977
978
979 self.LBOX_vaccinated_indications = wx.ListBox(
980 parent = self,
981 id = self.ID_VaccinatedIndicationsList,
982 choices = [],
983 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
984 )
985 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
986
987
988
989 self.LBOX_given_shots = wx.ListBox(
990 parent = self,
991 id = self.ID_VaccinationsPerRegimeList,
992 choices = [],
993 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
994 )
995 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
996
997 self.LBOX_active_schedules = wx.ListBox (
998 parent = self,
999 id = self.ID_ActiveSchedules,
1000 choices = [],
1001 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1002 )
1003 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1004
1005 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1006 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1007 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1008 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1009
1010
1011
1012
1013 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1014 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1015 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1016
1017 self.LBOX_missing_shots = wx.ListBox (
1018 parent = self,
1019 id = self.ID_MissingShots,
1020 choices = [],
1021 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1022 )
1023 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1024
1025 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1026 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1027
1028
1029 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1030
1031
1032
1033
1034 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1035 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1036 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1037 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1038 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1039 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1040 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1041 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1042
1043 self.SetAutoLayout(True)
1044 self.SetSizer(self.mainsizer)
1045 self.mainsizer.Fit(self)
1046
1048
1049 wx.EVT_SIZE(self, self.OnSize)
1050 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1051 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1052 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1053
1054
1055
1056 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1057 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1058
1059
1060
1062 w, h = event.GetSize()
1063 self.mainsizer.SetDimension (0, 0, w, h)
1064
1066 """Paste previously given shot into edit area.
1067 """
1068 self.editarea.set_data(aVacc=event.GetClientData())
1069
1071 self.editarea.set_data(aVacc = event.GetClientData())
1072
1074 """Update right hand middle list to show vaccinations given for selected indication."""
1075 ind_list = event.GetEventObject()
1076 selected_item = ind_list.GetSelection()
1077 ind = ind_list.GetClientData(selected_item)
1078
1079 self.LBOX_given_shots.Set([])
1080 emr = self.__pat.get_emr()
1081 shots = emr.get_vaccinations(indications = [ind])
1082
1083 for shot in shots:
1084 if shot['is_booster']:
1085 marker = 'B'
1086 else:
1087 marker = '#%s' % shot['seq_no']
1088 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1089 self.LBOX_given_shots.Append(label, shot)
1090
1092
1093 self.editarea.set_data()
1094
1095 self.LBOX_vaccinated_indications.Clear()
1096 self.LBOX_given_shots.Clear()
1097 self.LBOX_active_schedules.Clear()
1098 self.LBOX_missing_shots.Clear()
1099
1101
1102 self.LBOX_vaccinated_indications.Clear()
1103 self.LBOX_given_shots.Clear()
1104 self.LBOX_active_schedules.Clear()
1105 self.LBOX_missing_shots.Clear()
1106
1107 emr = self.__pat.get_emr()
1108
1109 t1 = time.time()
1110
1111
1112
1113 status, indications = emr.get_vaccinated_indications()
1114
1115
1116
1117 for indication in indications:
1118 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1119
1120
1121 print "vaccinated indications took", time.time()-t1, "seconds"
1122
1123 t1 = time.time()
1124
1125 scheds = emr.get_scheduled_vaccination_regimes()
1126 if scheds is None:
1127 label = _('ERROR: cannot retrieve active vaccination schedules')
1128 self.LBOX_active_schedules.Append(label)
1129 elif len(scheds) == 0:
1130 label = _('no active vaccination schedules')
1131 self.LBOX_active_schedules.Append(label)
1132 else:
1133 for sched in scheds:
1134 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1135 self.LBOX_active_schedules.Append(label)
1136 print "active schedules took", time.time()-t1, "seconds"
1137
1138 t1 = time.time()
1139
1140 missing_shots = emr.get_missing_vaccinations()
1141 print "getting missing shots took", time.time()-t1, "seconds"
1142 if missing_shots is None:
1143 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1144 self.LBOX_missing_shots.Append(label, None)
1145 return True
1146
1147 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1148 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1149 for shot in missing_shots['due']:
1150 if shot['overdue']:
1151 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1152 weeks = days_left / 7
1153
1154 label = overdue_template % (
1155 years,
1156 weeks,
1157 shot['seq_no'],
1158 shot['l10n_indication'],
1159 shot['regime'],
1160 shot['vacc_comment']
1161 )
1162 self.LBOX_missing_shots.Append(label, shot)
1163 else:
1164
1165 label = due_template % (
1166 shot['time_left'].days / 7,
1167 shot['seq_no'],
1168 shot['indication'],
1169 shot['regime'],
1170 shot['latest_due'].strftime('%m/%Y'),
1171 shot['vacc_comment']
1172 )
1173 self.LBOX_missing_shots.Append(label, shot)
1174
1175 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1176 for shot in missing_shots['boosters']:
1177
1178 label = lbl_template % (
1179 shot['l10n_indication'],
1180 shot['regime'],
1181 shot['vacc_comment']
1182 )
1183 self.LBOX_missing_shots.Append(label, shot)
1184 print "displaying missing shots took", time.time()-t1, "seconds"
1185
1186 return True
1187
1188 - def _on_post_patient_selection(self, **kwargs):
1190
1191
1192
1193
1194
1195
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207 if __name__ == "__main__":
1208
1209 if len(sys.argv) < 2:
1210 sys.exit()
1211
1212 if sys.argv[1] != u'test':
1213 sys.exit()
1214
1215 app = wx.PyWidgetTester(size = (600, 600))
1216 app.SetWidget(cATCPhraseWheel, -1)
1217 app.MainLoop()
1218
1219