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, 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 try:
130 self.__indication2field[indication].SetValue(True)
131 except KeyError:
132 pass
133
135 indications = []
136 for indication in self.__indication2field.keys():
137 if self.__indication2field[indication].IsChecked():
138 indications.append(indication)
139 return indications
140
141 selected_indications = property(_get_selected_indications, lambda x:x)
142
144 for indication in self.__indication2field.keys():
145 if self.__indication2field[indication].IsChecked():
146 return True
147 return False
148
149 has_selection = property(_get_has_selection, lambda x:x)
150
151
152
153
154 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
165
167
168 if parent is None:
169 parent = wx.GetApp().GetTopWindow()
170
171 def delete(vaccine=None):
172 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
173 if deleted:
174 return True
175
176 gmGuiHelpers.gm_show_info (
177 _(
178 'Cannot delete vaccine\n'
179 '\n'
180 ' %s - %s (#%s)\n'
181 '\n'
182 'It is probably documented in a vaccination.'
183 ) % (
184 vaccine['vaccine'],
185 vaccine['preparation'],
186 vaccine['pk_vaccine']
187 ),
188 _('Deleting vaccine')
189 )
190
191 return False
192
193 def edit(vaccine=None):
194 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
195
196 def refresh(lctrl):
197 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
198
199 items = [ [
200 u'%s' % v['pk_brand'],
201 u'%s%s' % (
202 v['vaccine'],
203 gmTools.bool2subst (
204 v['is_fake_vaccine'],
205 u' (%s)' % _('fake'),
206 u''
207 )
208 ),
209 v['preparation'],
210
211
212 gmTools.coalesce(v['atc_code'], u''),
213 u'%s%s' % (
214 gmTools.coalesce(v['min_age'], u'?'),
215 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
216 ),
217 gmTools.coalesce(v['comment'], u'')
218 ] for v in vaccines ]
219 lctrl.set_string_items(items)
220 lctrl.set_data(vaccines)
221
222 gmListWidgets.get_choices_from_list (
223 parent = parent,
224 msg = _('\nThe vaccines currently known to GNUmed.\n'),
225 caption = _('Showing vaccines.'),
226
227 columns = [ u'#', _('Brand'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ],
228 single_selection = True,
229 refresh_callback = refresh,
230 edit_callback = edit,
231 new_callback = edit,
232 delete_callback = delete
233 )
234
236
238
239 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
240
241 context = {
242 u'ctxt_vaccine': {
243 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
244 u'placeholder': u'pk_vaccine'
245 }
246 }
247
248 query = u"""
249 SELECT data, field_label, list_label FROM (
250
251 SELECT distinct on (field_label)
252 data,
253 field_label,
254 list_label,
255 rank
256 FROM ((
257 -- batch_no by vaccine
258 SELECT
259 batch_no AS data,
260 batch_no AS field_label,
261 batch_no || ' (' || vaccine || ')' AS list_label,
262 1 as rank
263 FROM
264 clin.v_pat_vaccinations
265 WHERE
266 batch_no %(fragment_condition)s
267 %(ctxt_vaccine)s
268 ) UNION ALL (
269 -- batch_no for any vaccine
270 SELECT
271 batch_no AS data,
272 batch_no AS field_label,
273 batch_no || ' (' || vaccine || ')' AS list_label,
274 2 AS rank
275 FROM
276 clin.v_pat_vaccinations
277 WHERE
278 batch_no %(fragment_condition)s
279 )
280
281 ) AS matching_batch_nos
282
283 ) as unique_matches
284
285 ORDER BY rank, list_label
286 LIMIT 25
287 """
288 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
289 mp.setThresholds(1, 2, 3)
290 self.matcher = mp
291
292 self.unset_context(context = u'pk_vaccine')
293 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
294 self.selection_only = False
295
297
299
300 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
301
302
303 query = u"""
304 SELECT data, list_label, field_label FROM (
305
306 SELECT DISTINCT ON (data)
307 data,
308 list_label,
309 field_label
310 FROM ((
311 -- fragment -> vaccine
312 SELECT
313 pk_vaccine AS data,
314 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
315 vaccine AS field_label
316 FROM
317 clin.v_vaccines
318 WHERE
319 vaccine %(fragment_condition)s
320
321 ) union all (
322
323 -- fragment -> localized indication -> vaccines
324 SELECT
325 pk_vaccine AS data,
326 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
327 vaccine AS field_label
328 FROM
329 clin.v_indications4vaccine
330 WHERE
331 l10n_indication %(fragment_condition)s
332
333 ) union all (
334
335 -- fragment -> indication -> vaccines
336 SELECT
337 pk_vaccine AS data,
338 vaccine || ' (' || array_to_string(indications, ', ') || ')' AS list_label,
339 vaccine AS field_label
340 FROM
341 clin.v_indications4vaccine
342 WHERE
343 indication %(fragment_condition)s
344 )
345 ) AS distinct_total
346
347 ) AS total
348
349 ORDER by list_label
350 LIMIT 25
351 """
352 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
353 mp.setThresholds(1, 2, 3)
354 self.matcher = mp
355
356 self.selection_only = True
357
360
361 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
362
363 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
364
382
384
385
386 query = u"""
387 SELECT DISTINCT ON (abbreviation)
388 id,
389 abbreviation || ' (' || _(description) || ')'
390 FROM
391 clin.vacc_route
392 WHERE
393 abbreviation %(fragment_condition)s
394 OR
395 description %(fragment_condition)s
396 ORDER BY
397 abbreviation
398 """
399 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
400 mp.setThresholds(1, 2, 3)
401 self._PRW_route.matcher = mp
402 self._PRW_route.selection_only = True
403
404
405
406
407 self.Layout()
408 self.Fit()
409
410
411
413
414 has_errors = False
415
416 if self._PRW_brand.GetValue().strip() == u'':
417 has_errors = True
418 self._PRW_brand.display_as_valid(False)
419 else:
420 self._PRW_brand.display_as_valid(True)
421
422 if self._PRW_route.GetData() is None:
423 has_errors = True
424 self._PRW_route.display_as_valid(False)
425 else:
426 self._PRW_route.display_as_valid(True)
427
428 if not self._PNL_indications.has_selection:
429 has_errors = True
430
431 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
432 self._PRW_atc.display_as_valid(True)
433 else:
434 if self._PRW_atc.GetData() is None:
435 self._PRW_atc.display_as_valid(True)
436 else:
437 has_errors = True
438 self._PRW_atc.display_as_valid(False)
439
440 val = self._PRW_age_min.GetValue().strip()
441 if val == u'':
442 self._PRW_age_min.display_as_valid(True)
443 else:
444 if gmDateTime.str2interval(val) is None:
445 has_errors = True
446 self._PRW_age_min.display_as_valid(False)
447 else:
448 self._PRW_age_min.display_as_valid(True)
449
450 val = self._PRW_age_max.GetValue().strip()
451 if val == u'':
452 self._PRW_age_max.display_as_valid(True)
453 else:
454 if gmDateTime.str2interval(val) is None:
455 has_errors = True
456 self._PRW_age_max.display_as_valid(False)
457 else:
458 self._PRW_age_max.display_as_valid(True)
459
460
461 ask_user = (self.mode == 'edit')
462
463 ask_user = (ask_user and self.data.is_in_use)
464
465 ask_user = ask_user and (
466
467 (self.data['pk_brand'] != self._PRW_route.GetData())
468 or
469
470 (self.data['indications'] != self._PNL_indications.selected_indications)
471 )
472
473 if ask_user:
474 do_it = gmGuiHelpers.gm_show_question (
475 aTitle = _('Saving vaccine'),
476 aMessage = _(
477 u'This vaccine is already in use:\n'
478 u'\n'
479 u' "%s"\n'
480 u' (%s)\n'
481 u'\n'
482 u'Are you absolutely positively sure that\n'
483 u'you really want to edit this vaccine ?\n'
484 '\n'
485 u'This will change the vaccine name and/or target\n'
486 u'conditions in each patient this vaccine was\n'
487 u'used in to document a vaccination with.\n'
488 ) % (
489 self._PRW_brand.GetValue().strip(),
490 u', '.join(self.data['l10n_indications'])
491 )
492 )
493 if not do_it:
494 has_errors = True
495
496 return (has_errors is False)
497
534
562
575
577 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
578
579
580 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
581 self._PNL_indications.select(self.data['indications'])
582 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
583 if self.data['min_age'] is None:
584 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
585 else:
586 self._PRW_age_min.SetText (
587 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
588 data = self.data['min_age']
589 )
590 if self.data['max_age'] is None:
591 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
592 else:
593 self._PRW_age_max.SetText (
594 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
595 data = self.data['max_age']
596 )
597 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
598
599 self._PRW_brand.SetFocus()
600
602 self._refresh_as_new()
603
604
605
619
621
622 pat = gmPerson.gmCurrentPatient()
623 emr = pat.get_emr()
624
625 if parent is None:
626 parent = wx.GetApp().GetTopWindow()
627
628 def browse2schedules(vaccination=None):
629 dbcfg = gmCfg.cCfgSQL()
630 url = dbcfg.get2 (
631 option = 'external.urls.vaccination_plans',
632 workplace = gmSurgery.gmCurrentPractice().active_workplace,
633 bias = 'user',
634 default = u'http://www.bundesaerztekammer.de/downloads/ImpfempfehlungenRKI2009.pdf'
635 )
636
637 webbrowser.open (
638 url = url,
639 new = False,
640 autoraise = True
641 )
642 return False
643
644 def edit(vaccination=None):
645 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
646
647 def delete(vaccination=None):
648 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
649 return True
650
651 def refresh(lctrl):
652
653 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
654
655 items = [ [
656 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
657 v['vaccine'],
658 u', '.join(v['l10n_indications']),
659 v['batch_no'],
660 gmTools.coalesce(v['site'], u''),
661 gmTools.coalesce(v['reaction'], u''),
662 gmTools.coalesce(v['comment'], u'')
663 ] for v in vaccs ]
664
665 lctrl.set_string_items(items)
666 lctrl.set_data(vaccs)
667
668 gmListWidgets.get_choices_from_list (
669 parent = parent,
670 msg = _('\nComplete vaccination history for this patient.\n'),
671 caption = _('Showing vaccinations.'),
672 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
673 single_selection = True,
674 refresh_callback = refresh,
675 new_callback = edit,
676 edit_callback = edit,
677 delete_callback = delete,
678 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
679 )
680
681 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
682
683 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
684 """
685 - warn on apparent duplicates
686 - ask if "missing" (= previous, non-recorded) vaccinations
687 should be estimated and saved (add note "auto-generated")
688
689 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
690 """
708
715
717
718 vaccine = self._PRW_vaccine.GetData(as_instance=True)
719
720
721 if self.mode == u'edit':
722 self._PNL_indications.clear_all()
723 if vaccine is None:
724 self._PRW_batch.unset_context(context = 'pk_vaccine')
725 else:
726 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
727 self._PNL_indications.select(indications = vaccine['indications'])
728 self._PNL_indications.disable_all()
729
730
731 else:
732 if vaccine is None:
733 self._PRW_batch.unset_context(context = 'pk_vaccine')
734 self._PNL_indications.enable_all()
735 else:
736 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
737 self._PNL_indications.clear_all()
738 self._PNL_indications.select(indications = vaccine['indications'])
739 self._PNL_indications.disable_all()
740
742 if self._PRW_reaction.GetValue().strip() == u'':
743 self._BTN_report.Enable(False)
744 else:
745 self._BTN_report.Enable(True)
746
747
748
750
751 has_errors = False
752
753 if not self._PRW_date_given.is_valid_timestamp(allow_empty = False):
754 has_errors = True
755
756 vaccine = self._PRW_vaccine.GetData(as_instance = True)
757
758
759 if self.mode == u'edit':
760 if vaccine is None:
761 has_errors = True
762 self._PRW_vaccine.display_as_valid(False)
763 else:
764 self._PRW_vaccine.display_as_valid(True)
765 self._PNL_indications.clear_all()
766 self._PNL_indications.select(indications = vaccine['indications'])
767 self._PNL_indications.disable_all()
768
769 else:
770 if vaccine is None:
771 if self._PNL_indications.has_selection:
772 self._PRW_vaccine.display_as_valid(True)
773 else:
774 has_errors = True
775 self._PRW_vaccine.display_as_valid(False)
776 else:
777 self._PRW_vaccine.display_as_valid(True)
778
779 if self._PRW_batch.GetValue().strip() == u'':
780 has_errors = True
781 self._PRW_batch.display_as_valid(False)
782 else:
783 self._PRW_batch.display_as_valid(True)
784
785 if self._PRW_episode.GetValue().strip() == u'':
786 self._PRW_episode.SetText(value = _('prevention'))
787
788 return (has_errors is False)
789
791
792 vaccine = self._PRW_vaccine.GetData()
793 if vaccine is None:
794 data = self.__save_new_from_indications()
795 else:
796 data = self.__save_new_from_vaccine(vaccine = vaccine)
797
798
799
800
801 self.data = data
802
803 return True
804
818
843
845
846 if self._CHBOX_anamnestic.GetValue() is True:
847 self.data['soap_cat'] = u's'
848 else:
849 self.data['soap_cat'] = u'p'
850
851 self.data['date_given'] = self._PRW_date_given.GetData()
852 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
853 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
854 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
855 self.data['site'] = self._PRW_site.GetValue().strip()
856 self.data['pk_provider'] = self._PRW_provider.GetData()
857 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
858 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
859
860 self.data.save()
861
862 return True
863
881
906
927
928
929
951
954
955
956
958
960 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
961 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
962 self.__pat = gmPerson.gmCurrentPatient()
963
964 self.ID_VaccinatedIndicationsList = wx.NewId()
965 self.ID_VaccinationsPerRegimeList = wx.NewId()
966 self.ID_MissingShots = wx.NewId()
967 self.ID_ActiveSchedules = wx.NewId()
968 self.__do_layout()
969 self.__register_interests()
970 self.__reset_ui_content()
971
973
974
975
976 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
977 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
978
979
980
981
982
983 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
984 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
985 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
986 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
987 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
988 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
989 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
990
991
992 self.LBOX_vaccinated_indications = wx.ListBox(
993 parent = self,
994 id = self.ID_VaccinatedIndicationsList,
995 choices = [],
996 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
997 )
998 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
999
1000
1001
1002 self.LBOX_given_shots = wx.ListBox(
1003 parent = self,
1004 id = self.ID_VaccinationsPerRegimeList,
1005 choices = [],
1006 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1007 )
1008 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1009
1010 self.LBOX_active_schedules = wx.ListBox (
1011 parent = self,
1012 id = self.ID_ActiveSchedules,
1013 choices = [],
1014 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1015 )
1016 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1017
1018 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1019 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1020 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1021 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1022
1023
1024
1025
1026 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1027 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1028 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1029
1030 self.LBOX_missing_shots = wx.ListBox (
1031 parent = self,
1032 id = self.ID_MissingShots,
1033 choices = [],
1034 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1035 )
1036 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1037
1038 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1039 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1040
1041
1042 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1043
1044
1045
1046
1047 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1048 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1049 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1050 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1051 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1052 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1053 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1054 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1055
1056 self.SetAutoLayout(True)
1057 self.SetSizer(self.mainsizer)
1058 self.mainsizer.Fit(self)
1059
1061
1062 wx.EVT_SIZE(self, self.OnSize)
1063 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1064 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1065 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1066
1067
1068
1069 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1070 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1071
1072
1073
1075 w, h = event.GetSize()
1076 self.mainsizer.SetDimension (0, 0, w, h)
1077
1079 """Paste previously given shot into edit area.
1080 """
1081 self.editarea.set_data(aVacc=event.GetClientData())
1082
1084 self.editarea.set_data(aVacc = event.GetClientData())
1085
1087 """Update right hand middle list to show vaccinations given for selected indication."""
1088 ind_list = event.GetEventObject()
1089 selected_item = ind_list.GetSelection()
1090 ind = ind_list.GetClientData(selected_item)
1091
1092 self.LBOX_given_shots.Set([])
1093 emr = self.__pat.get_emr()
1094 shots = emr.get_vaccinations(indications = [ind])
1095
1096 for shot in shots:
1097 if shot['is_booster']:
1098 marker = 'B'
1099 else:
1100 marker = '#%s' % shot['seq_no']
1101 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1102 self.LBOX_given_shots.Append(label, shot)
1103
1105
1106 self.editarea.set_data()
1107
1108 self.LBOX_vaccinated_indications.Clear()
1109 self.LBOX_given_shots.Clear()
1110 self.LBOX_active_schedules.Clear()
1111 self.LBOX_missing_shots.Clear()
1112
1114
1115 self.LBOX_vaccinated_indications.Clear()
1116 self.LBOX_given_shots.Clear()
1117 self.LBOX_active_schedules.Clear()
1118 self.LBOX_missing_shots.Clear()
1119
1120 emr = self.__pat.get_emr()
1121
1122 t1 = time.time()
1123
1124
1125
1126 status, indications = emr.get_vaccinated_indications()
1127
1128
1129
1130 for indication in indications:
1131 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1132
1133
1134 print "vaccinated indications took", time.time()-t1, "seconds"
1135
1136 t1 = time.time()
1137
1138 scheds = emr.get_scheduled_vaccination_regimes()
1139 if scheds is None:
1140 label = _('ERROR: cannot retrieve active vaccination schedules')
1141 self.LBOX_active_schedules.Append(label)
1142 elif len(scheds) == 0:
1143 label = _('no active vaccination schedules')
1144 self.LBOX_active_schedules.Append(label)
1145 else:
1146 for sched in scheds:
1147 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1148 self.LBOX_active_schedules.Append(label)
1149 print "active schedules took", time.time()-t1, "seconds"
1150
1151 t1 = time.time()
1152
1153 missing_shots = emr.get_missing_vaccinations()
1154 print "getting missing shots took", time.time()-t1, "seconds"
1155 if missing_shots is None:
1156 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1157 self.LBOX_missing_shots.Append(label, None)
1158 return True
1159
1160 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1161 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1162 for shot in missing_shots['due']:
1163 if shot['overdue']:
1164 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1165 weeks = days_left / 7
1166
1167 label = overdue_template % (
1168 years,
1169 weeks,
1170 shot['seq_no'],
1171 shot['l10n_indication'],
1172 shot['regime'],
1173 shot['vacc_comment']
1174 )
1175 self.LBOX_missing_shots.Append(label, shot)
1176 else:
1177
1178 label = due_template % (
1179 shot['time_left'].days / 7,
1180 shot['seq_no'],
1181 shot['indication'],
1182 shot['regime'],
1183 shot['latest_due'].strftime('%m/%Y'),
1184 shot['vacc_comment']
1185 )
1186 self.LBOX_missing_shots.Append(label, shot)
1187
1188 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1189 for shot in missing_shots['boosters']:
1190
1191 label = lbl_template % (
1192 shot['l10n_indication'],
1193 shot['regime'],
1194 shot['vacc_comment']
1195 )
1196 self.LBOX_missing_shots.Append(label, shot)
1197 print "displaying missing shots took", time.time()-t1, "seconds"
1198
1199 return True
1200
1201 - def _on_post_patient_selection(self, **kwargs):
1203
1204
1205
1206
1207
1208
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 if __name__ == "__main__":
1221
1222 if len(sys.argv) < 2:
1223 sys.exit()
1224
1225 if sys.argv[1] != u'test':
1226 sys.exit()
1227
1228 app = wx.PyWidgetTester(size = (600, 600))
1229 app.SetWidget(cATCPhraseWheel, -1)
1230 app.MainLoop()
1231
1232