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
608
610
611 pat = gmPerson.gmCurrentPatient()
612 emr = pat.get_emr()
613
614 if parent is None:
615 parent = wx.GetApp().GetTopWindow()
616
617 def browse2schedules(vaccination=None):
618 dbcfg = gmCfg.cCfgSQL()
619 url = dbcfg.get2 (
620 option = 'external.urls.vaccination_plans',
621 workplace = gmSurgery.gmCurrentPractice().active_workplace,
622 bias = 'user',
623 default = u'http://www.bundesaerztekammer.de/downloads/ImpfempfehlungenRKI2009.pdf'
624 )
625
626 webbrowser.open (
627 url = url,
628 new = False,
629 autoraise = True
630 )
631 return False
632
633 def edit(vaccination=None):
634 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
635
636 def delete(vaccination=None):
637 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
638 return True
639
640 def refresh(lctrl):
641
642 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
643
644 items = [ [
645 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
646 v['vaccine'],
647 u', '.join(v['l10n_indications']),
648 v['batch_no'],
649 gmTools.coalesce(v['site'], u''),
650 gmTools.coalesce(v['reaction'], u''),
651 gmTools.coalesce(v['comment'], u'')
652 ] for v in vaccs ]
653
654 lctrl.set_string_items(items)
655 lctrl.set_data(vaccs)
656
657 gmListWidgets.get_choices_from_list (
658 parent = parent,
659 msg = _('\nComplete vaccination history for this patient.\n'),
660 caption = _('Showing vaccinations.'),
661 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
662 single_selection = True,
663 refresh_callback = refresh,
664 new_callback = edit,
665 edit_callback = edit,
666 delete_callback = delete,
667 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
668 )
669
670 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
671
672 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
673 """
674 - warn on apparent duplicates
675 - ask if "missing" (= previous, non-recorded) vaccinations
676 should be estimated and saved (add note "auto-generated")
677
678 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
679 """
697
704
706
707 vaccine = self._PRW_vaccine.GetData(as_instance=True)
708
709
710 if self.mode == u'edit':
711 self._PNL_indications.clear_all()
712 if vaccine is None:
713 self._PRW_batch.unset_context(context = 'pk_vaccine')
714 else:
715 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
716 self._PNL_indications.select(indications = vaccine['indications'])
717 self._PNL_indications.disable_all()
718
719
720 else:
721 if vaccine is None:
722 self._PRW_batch.unset_context(context = 'pk_vaccine')
723 self._PNL_indications.enable_all()
724 else:
725 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
726 self._PNL_indications.clear_all()
727 self._PNL_indications.select(indications = vaccine['indications'])
728 self._PNL_indications.disable_all()
729
731 if self._PRW_reaction.GetValue().strip() == u'':
732 self._BTN_report.Enable(False)
733 else:
734 self._BTN_report.Enable(True)
735
736
737
739
740 has_errors = False
741
742 if not self._DP_date_given.is_valid_timestamp(allow_none = False):
743 has_errors = True
744
745 vaccine = self._PRW_vaccine.GetData(as_instance = True)
746
747
748 if self.mode == u'edit':
749 if vaccine is None:
750 has_errors = True
751 self._PRW_vaccine.display_as_valid(False)
752 else:
753 self._PRW_vaccine.display_as_valid(True)
754 self._PNL_indications.clear_all()
755 self._PNL_indications.select(indications = vaccine['indications'])
756 self._PNL_indications.disable_all()
757
758 else:
759 if vaccine is None:
760 if self._PNL_indications.has_selection:
761 self._PRW_vaccine.display_as_valid(True)
762 else:
763 has_errors = True
764 self._PRW_vaccine.display_as_valid(False)
765 else:
766 self._PRW_vaccine.display_as_valid(True)
767
768 if self._PRW_batch.GetValue().strip() == u'':
769 has_errors = True
770 self._PRW_batch.display_as_valid(False)
771 else:
772 self._PRW_batch.display_as_valid(True)
773
774 if self._PRW_episode.GetValue().strip() == u'':
775 self._PRW_episode.SetText(value = _('prevention'))
776
777 return (has_errors is False)
778
780
781 vaccine = self._PRW_vaccine.GetData()
782 if vaccine is None:
783 data = self.__save_new_from_indications()
784 else:
785 data = self.__save_new_from_vaccine(vaccine = vaccine)
786
787
788
789
790 self.data = data
791
792 return True
793
807
832
834
835 if self._CHBOX_anamnestic.GetValue() is True:
836 self.data['soap_cat'] = u's'
837 else:
838 self.data['soap_cat'] = u'p'
839
840 self.data['date_given'] = self._DP_date_given.get_pydt()
841 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
842 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
843 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
844 self.data['site'] = self._PRW_site.GetValue().strip()
845 self.data['pk_provider'] = self._PRW_provider.GetData()
846 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
847 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
848
849 self.data.save()
850
851 return True
852
870
895
917
918
919
941
944
945
946
948
950 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
951 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
952 self.__pat = gmPerson.gmCurrentPatient()
953
954 self.ID_VaccinatedIndicationsList = wx.NewId()
955 self.ID_VaccinationsPerRegimeList = wx.NewId()
956 self.ID_MissingShots = wx.NewId()
957 self.ID_ActiveSchedules = wx.NewId()
958 self.__do_layout()
959 self.__register_interests()
960 self.__reset_ui_content()
961
963
964
965
966 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
967 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
968
969
970
971
972
973 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
974 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
975 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
976 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
977 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
978 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
979 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
980
981
982 self.LBOX_vaccinated_indications = wx.ListBox(
983 parent = self,
984 id = self.ID_VaccinatedIndicationsList,
985 choices = [],
986 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
987 )
988 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
989
990
991
992 self.LBOX_given_shots = wx.ListBox(
993 parent = self,
994 id = self.ID_VaccinationsPerRegimeList,
995 choices = [],
996 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
997 )
998 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
999
1000 self.LBOX_active_schedules = wx.ListBox (
1001 parent = self,
1002 id = self.ID_ActiveSchedules,
1003 choices = [],
1004 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1005 )
1006 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1007
1008 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1009 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1010 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1011 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1012
1013
1014
1015
1016 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1017 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1018 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1019
1020 self.LBOX_missing_shots = wx.ListBox (
1021 parent = self,
1022 id = self.ID_MissingShots,
1023 choices = [],
1024 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1025 )
1026 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1027
1028 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1029 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1030
1031
1032 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1033
1034
1035
1036
1037 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1038 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1039 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1040 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1041 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1042 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1043 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1044 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1045
1046 self.SetAutoLayout(True)
1047 self.SetSizer(self.mainsizer)
1048 self.mainsizer.Fit(self)
1049
1051
1052 wx.EVT_SIZE(self, self.OnSize)
1053 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1054 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1055 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1056
1057
1058
1059 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1060 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1061
1062
1063
1065 w, h = event.GetSize()
1066 self.mainsizer.SetDimension (0, 0, w, h)
1067
1069 """Paste previously given shot into edit area.
1070 """
1071 self.editarea.set_data(aVacc=event.GetClientData())
1072
1074 self.editarea.set_data(aVacc = event.GetClientData())
1075
1077 """Update right hand middle list to show vaccinations given for selected indication."""
1078 ind_list = event.GetEventObject()
1079 selected_item = ind_list.GetSelection()
1080 ind = ind_list.GetClientData(selected_item)
1081
1082 self.LBOX_given_shots.Set([])
1083 emr = self.__pat.get_emr()
1084 shots = emr.get_vaccinations(indications = [ind])
1085
1086 for shot in shots:
1087 if shot['is_booster']:
1088 marker = 'B'
1089 else:
1090 marker = '#%s' % shot['seq_no']
1091 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1092 self.LBOX_given_shots.Append(label, shot)
1093
1095
1096 self.editarea.set_data()
1097
1098 self.LBOX_vaccinated_indications.Clear()
1099 self.LBOX_given_shots.Clear()
1100 self.LBOX_active_schedules.Clear()
1101 self.LBOX_missing_shots.Clear()
1102
1104
1105 self.LBOX_vaccinated_indications.Clear()
1106 self.LBOX_given_shots.Clear()
1107 self.LBOX_active_schedules.Clear()
1108 self.LBOX_missing_shots.Clear()
1109
1110 emr = self.__pat.get_emr()
1111
1112 t1 = time.time()
1113
1114
1115
1116 status, indications = emr.get_vaccinated_indications()
1117
1118
1119
1120 for indication in indications:
1121 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1122
1123
1124 print "vaccinated indications took", time.time()-t1, "seconds"
1125
1126 t1 = time.time()
1127
1128 scheds = emr.get_scheduled_vaccination_regimes()
1129 if scheds is None:
1130 label = _('ERROR: cannot retrieve active vaccination schedules')
1131 self.LBOX_active_schedules.Append(label)
1132 elif len(scheds) == 0:
1133 label = _('no active vaccination schedules')
1134 self.LBOX_active_schedules.Append(label)
1135 else:
1136 for sched in scheds:
1137 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1138 self.LBOX_active_schedules.Append(label)
1139 print "active schedules took", time.time()-t1, "seconds"
1140
1141 t1 = time.time()
1142
1143 missing_shots = emr.get_missing_vaccinations()
1144 print "getting missing shots took", time.time()-t1, "seconds"
1145 if missing_shots is None:
1146 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1147 self.LBOX_missing_shots.Append(label, None)
1148 return True
1149
1150 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1151 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1152 for shot in missing_shots['due']:
1153 if shot['overdue']:
1154 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1155 weeks = days_left / 7
1156
1157 label = overdue_template % (
1158 years,
1159 weeks,
1160 shot['seq_no'],
1161 shot['l10n_indication'],
1162 shot['regime'],
1163 shot['vacc_comment']
1164 )
1165 self.LBOX_missing_shots.Append(label, shot)
1166 else:
1167
1168 label = due_template % (
1169 shot['time_left'].days / 7,
1170 shot['seq_no'],
1171 shot['indication'],
1172 shot['regime'],
1173 shot['latest_due'].strftime('%m/%Y'),
1174 shot['vacc_comment']
1175 )
1176 self.LBOX_missing_shots.Append(label, shot)
1177
1178 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1179 for shot in missing_shots['boosters']:
1180
1181 label = lbl_template % (
1182 shot['l10n_indication'],
1183 shot['regime'],
1184 shot['vacc_comment']
1185 )
1186 self.LBOX_missing_shots.Append(label, shot)
1187 print "displaying missing shots took", time.time()-t1, "seconds"
1188
1189 return True
1190
1191 - def _on_post_patient_selection(self, **kwargs):
1193
1194
1195
1196
1197
1198
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210 if __name__ == "__main__":
1211
1212 if len(sys.argv) < 2:
1213 sys.exit()
1214
1215 if sys.argv[1] != u'test':
1216 sys.exit()
1217
1218 app = wx.PyWidgetTester(size = (600, 600))
1219 app.SetWidget(cATCPhraseWheel, -1)
1220 app.MainLoop()
1221
1222