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