1 """GNUmed immunisation/vaccination widgets.
2
3 Modelled after Richard Terry's design document.
4
5 copyright: authors
6 """
7
8 __author__ = "R.Terry, S.J.Tan, K.Hilbert"
9 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
10
11 import sys, time, logging
12
13
14 import wx
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.pycommon import gmDispatcher
20 from Gnumed.pycommon import gmMatchProvider
21 from Gnumed.pycommon import gmTools
22 from Gnumed.pycommon import gmI18N
23 from Gnumed.pycommon import gmCfg
24 from Gnumed.pycommon import gmDateTime
25 from Gnumed.pycommon import gmNetworkTools
26 from Gnumed.pycommon import gmPrinting
27
28 from Gnumed.business import gmPerson
29 from Gnumed.business import gmVaccination
30 from Gnumed.business import gmPraxis
31 from Gnumed.business import gmProviderInbox
32
33 from Gnumed.wxpython import gmPhraseWheel
34 from Gnumed.wxpython import gmTerryGuiParts
35 from Gnumed.wxpython import gmRegetMixin
36 from Gnumed.wxpython import gmGuiHelpers
37 from Gnumed.wxpython import gmEditArea
38 from Gnumed.wxpython import gmListWidgets
39 from Gnumed.wxpython import gmFormWidgets
40 from Gnumed.wxpython import gmMacro
41
42
43 _log = logging.getLogger('gm.vaccination')
44
45
46
47
73
74 gmListWidgets.get_choices_from_list (
75 parent = parent,
76 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
77 caption = _('Showing vaccination preventable conditions.'),
78 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
79 single_selection = True,
80 refresh_callback = refresh
81 )
82
84
85 if parent is None:
86 parent = wx.GetApp().GetTopWindow()
87
88 if msg is None:
89 msg = _('Pick the relevant indications.')
90
91 if right_column is None:
92 right_columns = ['This vaccine']
93 else:
94 right_columns = [right_column]
95
96 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
97 picker.set_columns(columns = [_('Known indications')], columns_right = right_columns)
98 inds = gmVaccination.get_indications(order_by = 'l10n_description')
99 picker.set_choices (
100 choices = [ i['l10n_description'] for i in inds ],
101 data = inds
102 )
103 picker.set_picks (
104 picks = [ p['l10n_description'] for p in picks ],
105 data = picks
106 )
107 result = picker.ShowModal()
108
109 if result == wx.ID_CANCEL:
110 picker.Destroy()
111 return None
112
113 picks = picker.picks
114 picker.Destroy()
115 return picks
116
117
118
119
120 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
131
133
134 if parent is None:
135 parent = wx.GetApp().GetTopWindow()
136
137 def delete(vaccine=None):
138 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
139 if deleted:
140 return True
141
142 gmGuiHelpers.gm_show_info (
143 _(
144 'Cannot delete vaccine\n'
145 '\n'
146 ' %s - %s (#%s)\n'
147 '\n'
148 'It is probably documented in a vaccination.'
149 ) % (
150 vaccine['vaccine'],
151 vaccine['preparation'],
152 vaccine['pk_vaccine']
153 ),
154 _('Deleting vaccine')
155 )
156
157 return False
158
159 def edit(vaccine=None):
160 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
161
162 def refresh(lctrl):
163 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
164
165 items = [ [
166 u'%s' % v['pk_brand'],
167 u'%s%s' % (
168 v['vaccine'],
169 gmTools.bool2subst (
170 v['is_fake_vaccine'],
171 u' (%s)' % _('fake'),
172 u''
173 )
174 ),
175 v['preparation'],
176
177
178 gmTools.coalesce(v['atc_code'], u''),
179 u'%s%s' % (
180 gmTools.coalesce(v['min_age'], u'?'),
181 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
182 ),
183 gmTools.coalesce(v['comment'], u'')
184 ] for v in vaccines ]
185 lctrl.set_string_items(items)
186 lctrl.set_data(vaccines)
187
188 gmListWidgets.get_choices_from_list (
189 parent = parent,
190 msg = _('\nThe vaccines currently known to GNUmed.\n'),
191 caption = _('Showing vaccines.'),
192
193 columns = [ u'#', _('Brand'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ],
194 single_selection = True,
195 refresh_callback = refresh,
196 edit_callback = edit,
197 new_callback = edit,
198 delete_callback = delete
199 )
200
202
204
205 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
206
207 context = {
208 u'ctxt_vaccine': {
209 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
210 u'placeholder': u'pk_vaccine'
211 }
212 }
213
214 query = u"""
215 SELECT data, field_label, list_label FROM (
216
217 SELECT distinct on (field_label)
218 data,
219 field_label,
220 list_label,
221 rank
222 FROM ((
223 -- batch_no by vaccine
224 SELECT
225 batch_no AS data,
226 batch_no AS field_label,
227 batch_no || ' (' || vaccine || ')' AS list_label,
228 1 as rank
229 FROM
230 clin.v_pat_vaccinations
231 WHERE
232 batch_no %(fragment_condition)s
233 %(ctxt_vaccine)s
234 ) UNION ALL (
235 -- batch_no for any vaccine
236 SELECT
237 batch_no AS data,
238 batch_no AS field_label,
239 batch_no || ' (' || vaccine || ')' AS list_label,
240 2 AS rank
241 FROM
242 clin.v_pat_vaccinations
243 WHERE
244 batch_no %(fragment_condition)s
245 )
246
247 ) AS matching_batch_nos
248
249 ) as unique_matches
250
251 ORDER BY rank, list_label
252 LIMIT 25
253 """
254 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
255 mp.setThresholds(1, 2, 3)
256 self.matcher = mp
257
258 self.unset_context(context = u'pk_vaccine')
259 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
260 self.selection_only = False
261
263
265
266 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
267
268
269 query = u"""
270 SELECT data, list_label, field_label FROM (
271
272 SELECT DISTINCT ON (data)
273 data,
274 list_label,
275 field_label
276 FROM ((
277 -- fragment -> vaccine
278 SELECT
279 pk_vaccine AS data,
280 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
281 vaccine AS field_label
282 FROM
283 clin.v_vaccines
284 WHERE
285 vaccine %(fragment_condition)s
286
287 ) union all (
288
289 -- fragment -> localized indication -> vaccines
290 SELECT
291 pk_vaccine AS data,
292 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
293 vaccine AS field_label
294 FROM
295 clin.v_indications4vaccine
296 WHERE
297 l10n_indication %(fragment_condition)s
298
299 ) union all (
300
301 -- fragment -> indication -> vaccines
302 SELECT
303 pk_vaccine AS data,
304 vaccine || ' (' || array_to_string(indications, ', ') || ')' AS list_label,
305 vaccine AS field_label
306 FROM
307 clin.v_indications4vaccine
308 WHERE
309 indication %(fragment_condition)s
310 )
311 ) AS distinct_total
312
313 ) AS total
314
315 ORDER by list_label
316 LIMIT 25
317 """
318 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
319 mp.setThresholds(1, 2, 3)
320 self.matcher = mp
321
322 self.selection_only = True
323
326
327 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
328
329 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
330
345
347 self._TCTRL_indications.SetValue(u'')
348 if len(self.__indications) == 0:
349 return
350 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
351
352
353
355
356 has_errors = False
357
358 if self._PRW_brand.GetValue().strip() == u'':
359 has_errors = True
360 self._PRW_brand.display_as_valid(False)
361 else:
362 self._PRW_brand.display_as_valid(True)
363
364 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
365 self._PRW_atc.display_as_valid(True)
366 else:
367 if self._PRW_atc.GetData() is None:
368 self._PRW_atc.display_as_valid(True)
369 else:
370 has_errors = True
371 self._PRW_atc.display_as_valid(False)
372
373 val = self._PRW_age_min.GetValue().strip()
374 if val == u'':
375 self._PRW_age_min.display_as_valid(True)
376 else:
377 if gmDateTime.str2interval(val) is None:
378 has_errors = True
379 self._PRW_age_min.display_as_valid(False)
380 else:
381 self._PRW_age_min.display_as_valid(True)
382
383 val = self._PRW_age_max.GetValue().strip()
384 if val == u'':
385 self._PRW_age_max.display_as_valid(True)
386 else:
387 if gmDateTime.str2interval(val) is None:
388 has_errors = True
389 self._PRW_age_max.display_as_valid(False)
390 else:
391 self._PRW_age_max.display_as_valid(True)
392
393
394 ask_user = (self.mode == 'edit')
395
396 ask_user = (ask_user and self.data.is_in_use)
397
398 ask_user = ask_user and (
399
400 (self.data['pk_brand'] != self._PRW_route.GetData())
401 or
402
403 (set(self.data['pk_indications']) != set([ i['id'] for i in self.__indications ]))
404 )
405
406 if ask_user:
407 do_it = gmGuiHelpers.gm_show_question (
408 aTitle = _('Saving vaccine'),
409 aMessage = _(
410 u'This vaccine is already in use:\n'
411 u'\n'
412 u' "%s"\n'
413 u' (%s)\n'
414 u'\n'
415 u'Are you absolutely positively sure that\n'
416 u'you really want to edit this vaccine ?\n'
417 '\n'
418 u'This will change the vaccine name and/or target\n'
419 u'conditions in each patient this vaccine was\n'
420 u'used in to document a vaccination with.\n'
421 ) % (
422 self._PRW_brand.GetValue().strip(),
423 u', '.join(self.data['l10n_indications'])
424 )
425 )
426 if not do_it:
427 has_errors = True
428
429 return (has_errors is False)
430
432
433 if len(self.__indications) == 0:
434 gmGuiHelpers.gm_show_info (
435 aTitle = _('Saving vaccine'),
436 aMessage = _('You must select at least one indication.')
437 )
438 return False
439
440
441 data = gmVaccination.create_vaccine (
442 pk_brand = self._PRW_brand.GetData(),
443 brand_name = self._PRW_brand.GetValue(),
444 pk_indications = [ i['id'] for i in self.__indications ]
445 )
446
447
448 val = self._PRW_age_min.GetValue().strip()
449 if val != u'':
450 data['min_age'] = gmDateTime.str2interval(val)
451 val = self._PRW_age_max.GetValue().strip()
452 if val != u'':
453 data['max_age'] = gmDateTime.str2interval(val)
454 val = self._TCTRL_comment.GetValue().strip()
455 if val != u'':
456 data['comment'] = val
457
458 data.save()
459
460 drug = data.brand
461 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
462 val = self._PRW_atc.GetData()
463 if val is not None:
464 if val != u'J07':
465 drug['atc'] = val.strip()
466 drug.save()
467
468
469
470
471 self.data = data
472
473 return True
474
476
477 if len(self.__indications) == 0:
478 gmGuiHelpers.gm_show_info (
479 aTitle = _('Saving vaccine'),
480 aMessage = _('You must select at least one indication.')
481 )
482 return False
483
484 drug = self.data.brand
485 drug['brand'] = self._PRW_brand.GetValue().strip()
486 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
487 val = self._PRW_atc.GetData()
488 if val is not None:
489 if val != u'J07':
490 drug['atc'] = val.strip()
491 drug.save()
492
493
494 self.data.set_indications(pk_indications = [ i['id'] for i in self.__indications ])
495
496
497 val = self._PRW_age_min.GetValue().strip()
498 if val != u'':
499 self.data['min_age'] = gmDateTime.str2interval(val)
500 if val != u'':
501 self.data['max_age'] = gmDateTime.str2interval(val)
502 val = self._TCTRL_comment.GetValue().strip()
503 if val != u'':
504 self.data['comment'] = val
505
506 self.data.save()
507 return True
508
510 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True)
511
512 self._CHBOX_fake.SetValue(False)
513 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True)
514 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
515 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
516 self._TCTRL_comment.SetValue(u'')
517
518 self.__indications = []
519 self.__refresh_indications()
520
521 self._PRW_brand.SetFocus()
522
524 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
525
526 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
527 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
528 if self.data['min_age'] is None:
529 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
530 else:
531 self._PRW_age_min.SetText (
532 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
533 data = self.data['min_age']
534 )
535 if self.data['max_age'] is None:
536 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
537 else:
538 self._PRW_age_max.SetText (
539 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
540 data = self.data['max_age']
541 )
542 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
543
544 self.__indications = self.data.indications
545 self.__refresh_indications()
546
547 self._PRW_brand.SetFocus()
548
550 self._refresh_as_new()
551
552
567
568
569
570
572
573 if parent is None:
574 parent = wx.GetApp().GetTopWindow()
575
576 vaccs_printout = gmFormWidgets.generate_form_from_template (
577 parent = parent,
578 template_types = [
579 u'Medical statement',
580 u'vaccination report',
581 u'vaccination record',
582 u'reminder'
583 ],
584 edit = False
585 )
586
587 if vaccs_printout is None:
588 return False
589
590 return gmFormWidgets.act_on_generated_forms (
591 parent = parent,
592 forms = [vaccs_printout],
593 jobtype = 'vaccinations',
594 episode_name = u'administration',
595 review_copy_as_normal = True
596 )
597
598
612
613
633
634 def print_vaccs(vaccination=None):
635 print_vaccinations(parent = parent)
636 return False
637
638 def add_recall(vaccination=None):
639 if vaccination is None:
640 subject = _('vaccination recall')
641 else:
642 subject = _('vaccination recall (%s)') % vaccination['vaccine']
643
644 recall = gmProviderInbox.create_inbox_message (
645 message_type = _('Vaccination'),
646 subject = subject,
647 patient = pat.ID,
648 staff = None
649 )
650
651 if vaccination is not None:
652 recall['data'] = _('Existing vaccination:\n\n%s') % u'\n'.join(vaccination.format(
653 with_indications = True,
654 with_comment = True,
655 with_reaction = False,
656 date_format = '%Y %b %d'
657 ))
658 recall.save()
659
660 from Gnumed.wxpython import gmProviderInboxWidgets
661 gmProviderInboxWidgets.edit_inbox_message (
662 parent = parent,
663 message = recall,
664 single_entry = False
665 )
666
667 return False
668
669 def get_tooltip(vaccination):
670 if vaccination is None:
671 return None
672 return u'\n'.join(vaccination.format (
673 with_indications = True,
674 with_comment = True,
675 with_reaction = True,
676 date_format = '%Y %b %d'
677 ))
678
679 def edit(vaccination=None):
680 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
681
682 def delete(vaccination=None):
683 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
684 return True
685
686 def refresh(lctrl):
687
688 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
689
690 items = [ [
691 gmDateTime.pydt_strftime(v['date_given'], '%Y %b %d'),
692 v['vaccine'],
693 u', '.join(v['l10n_indications']),
694 v['batch_no'],
695 gmTools.coalesce(v['site'], u''),
696 gmTools.coalesce(v['reaction'], u''),
697 gmTools.coalesce(v['comment'], u'')
698 ] for v in vaccs ]
699
700 lctrl.set_string_items(items)
701 lctrl.set_data(vaccs)
702
703 gmListWidgets.get_choices_from_list (
704 parent = parent,
705 msg = _('\nComplete vaccination history for this patient.\n'),
706 caption = _('Showing vaccinations.'),
707 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
708 single_selection = True,
709 refresh_callback = refresh,
710 new_callback = edit,
711 edit_callback = edit,
712 delete_callback = delete,
713 list_tooltip_callback = get_tooltip,
714 left_extra_button = (_('Print'), _('Print vaccinations or recalls.'), print_vaccs),
715 middle_extra_button = (_('Recall'), _('Add a recall for a vaccination'), add_recall),
716 right_extra_button = (_('Vx schedules'), _('Open a browser showing vaccination schedules.'), browse2schedules)
717 )
718
719 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
720
721 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
722 """
723 - warn on apparent duplicates
724 - ask if "missing" (= previous, non-recorded) vaccinations
725 should be estimated and saved (add note "auto-generated")
726
727 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
728 """
746
748
749 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
750 self._PRW_provider.selection_only = False
751 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
752 if self.mode == 'edit':
753 self._BTN_select_indications.Disable()
754
756
757 vaccine = self._PRW_vaccine.GetData(as_instance=True)
758
759
760 if self.mode == u'edit':
761 if vaccine is None:
762 self._PRW_batch.unset_context(context = 'pk_vaccine')
763 self.__indications = []
764 else:
765 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
766 self.__indications = vaccine.indications
767
768 else:
769 if vaccine is None:
770 self._PRW_batch.unset_context(context = 'pk_vaccine')
771 self.__indications = []
772 self._BTN_select_indications.Enable()
773 else:
774 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
775 self.__indications = vaccine.indications
776 self._BTN_select_indications.Disable()
777
778 self.__refresh_indications()
779
781 if self._PRW_reaction.GetValue().strip() == u'':
782 self._BTN_report.Enable(False)
783 else:
784 self._BTN_report.Enable(True)
785
787 self._TCTRL_indications.SetValue(u'')
788 if len(self.__indications) == 0:
789 return
790 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
791
792
793
831
846
866
891
893
894 if self._CHBOX_anamnestic.GetValue() is True:
895 self.data['soap_cat'] = u's'
896 else:
897 self.data['soap_cat'] = u'p'
898
899 self.data['date_given'] = self._PRW_date_given.GetData()
900 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
901 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
902 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
903 self.data['site'] = self._PRW_site.GetValue().strip()
904 self.data['pk_provider'] = self._PRW_provider.GetData()
905 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
906 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
907
908 self.data.save()
909
910 return True
911
913 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
914 self._CHBOX_anamnestic.SetValue(False)
915 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
916 self._PRW_batch.unset_context(context = 'pk_vaccine')
917 self._PRW_batch.SetValue(u'')
918 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
919 self._PRW_site.SetValue(u'')
920 self._PRW_provider.SetData(data = None)
921 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
922 self._BTN_report.Enable(False)
923 self._TCTRL_comment.SetValue(u'')
924
925 self.__indications = []
926 self.__refresh_indications()
927 self._BTN_select_indications.Enable()
928
929 self._PRW_date_given.SetFocus()
930
955
976
977
978
996
999
1000
1015
1016
1017
1018
1019
1021
1023 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
1024 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1025 self.__pat = gmPerson.gmCurrentPatient()
1026
1027 self.ID_VaccinatedIndicationsList = wx.NewId()
1028 self.ID_VaccinationsPerRegimeList = wx.NewId()
1029 self.ID_MissingShots = wx.NewId()
1030 self.ID_ActiveSchedules = wx.NewId()
1031 self.__do_layout()
1032 self.__register_interests()
1033 self.__reset_ui_content()
1034
1036
1037
1038
1039 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
1040 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
1041
1042
1043
1044
1045
1046 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
1047 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
1048 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
1049 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
1050 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
1051 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
1052 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
1053
1054
1055 self.LBOX_vaccinated_indications = wx.ListBox(
1056 parent = self,
1057 id = self.ID_VaccinatedIndicationsList,
1058 choices = [],
1059 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1060 )
1061 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1062
1063
1064
1065 self.LBOX_given_shots = wx.ListBox(
1066 parent = self,
1067 id = self.ID_VaccinationsPerRegimeList,
1068 choices = [],
1069 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1070 )
1071 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1072
1073 self.LBOX_active_schedules = wx.ListBox (
1074 parent = self,
1075 id = self.ID_ActiveSchedules,
1076 choices = [],
1077 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1078 )
1079 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1080
1081 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1082 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1083 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1084 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1085
1086
1087
1088
1089 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1090 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1091 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1092
1093 self.LBOX_missing_shots = wx.ListBox (
1094 parent = self,
1095 id = self.ID_MissingShots,
1096 choices = [],
1097 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1098 )
1099 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1100
1101 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1102 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1103
1104
1105 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1106
1107
1108
1109
1110 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1111 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1112 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1113 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1114 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1115 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1116 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1117 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1118
1119 self.SetAutoLayout(True)
1120 self.SetSizer(self.mainsizer)
1121 self.mainsizer.Fit(self)
1122
1124
1125 wx.EVT_SIZE(self, self.OnSize)
1126 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1127 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1128 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1129
1130
1131
1132 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1133 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1134
1135
1136
1138 w, h = event.GetSize()
1139 self.mainsizer.SetDimension (0, 0, w, h)
1140
1142 """Paste previously given shot into edit area.
1143 """
1144 self.editarea.set_data(aVacc=event.GetClientData())
1145
1148
1150 """Update right hand middle list to show vaccinations given for selected indication."""
1151 ind_list = event.GetEventObject()
1152 selected_item = ind_list.GetSelection()
1153 ind = ind_list.GetClientData(selected_item)
1154
1155 self.LBOX_given_shots.Set([])
1156 emr = self.__pat.get_emr()
1157 shots = emr.get_vaccinations(indications = [ind])
1158
1159 for shot in shots:
1160 if shot['is_booster']:
1161 marker = 'B'
1162 else:
1163 marker = '#%s' % shot['seq_no']
1164 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1165 self.LBOX_given_shots.Append(label, shot)
1166
1168
1169 self.editarea.set_data()
1170
1171 self.LBOX_vaccinated_indications.Clear()
1172 self.LBOX_given_shots.Clear()
1173 self.LBOX_active_schedules.Clear()
1174 self.LBOX_missing_shots.Clear()
1175
1177
1178 self.LBOX_vaccinated_indications.Clear()
1179 self.LBOX_given_shots.Clear()
1180 self.LBOX_active_schedules.Clear()
1181 self.LBOX_missing_shots.Clear()
1182
1183 emr = self.__pat.get_emr()
1184
1185 t1 = time.time()
1186
1187
1188
1189 status, indications = emr.get_vaccinated_indications()
1190
1191
1192
1193 for indication in indications:
1194 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1195
1196
1197 print "vaccinated indications took", time.time()-t1, "seconds"
1198
1199 t1 = time.time()
1200
1201 scheds = emr.get_scheduled_vaccination_regimes()
1202 if scheds is None:
1203 label = _('ERROR: cannot retrieve active vaccination schedules')
1204 self.LBOX_active_schedules.Append(label)
1205 elif len(scheds) == 0:
1206 label = _('no active vaccination schedules')
1207 self.LBOX_active_schedules.Append(label)
1208 else:
1209 for sched in scheds:
1210 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1211 self.LBOX_active_schedules.Append(label)
1212 print "active schedules took", time.time()-t1, "seconds"
1213
1214 t1 = time.time()
1215
1216 missing_shots = emr.get_missing_vaccinations()
1217 print "getting missing shots took", time.time()-t1, "seconds"
1218 if missing_shots is None:
1219 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1220 self.LBOX_missing_shots.Append(label, None)
1221 return True
1222
1223 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1224 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1225 for shot in missing_shots['due']:
1226 if shot['overdue']:
1227 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1228 weeks = days_left / 7
1229
1230 label = overdue_template % (
1231 years,
1232 weeks,
1233 shot['seq_no'],
1234 shot['l10n_indication'],
1235 shot['regime'],
1236 shot['vacc_comment']
1237 )
1238 self.LBOX_missing_shots.Append(label, shot)
1239 else:
1240
1241 label = due_template % (
1242 shot['time_left'].days / 7,
1243 shot['seq_no'],
1244 shot['indication'],
1245 shot['regime'],
1246 shot['latest_due'].strftime('%m/%Y'),
1247 shot['vacc_comment']
1248 )
1249 self.LBOX_missing_shots.Append(label, shot)
1250
1251 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1252 for shot in missing_shots['boosters']:
1253
1254 label = lbl_template % (
1255 shot['l10n_indication'],
1256 shot['regime'],
1257 shot['vacc_comment']
1258 )
1259 self.LBOX_missing_shots.Append(label, shot)
1260 print "displaying missing shots took", time.time()-t1, "seconds"
1261
1262 return True
1263
1264 - def _on_post_patient_selection(self, **kwargs):
1266
1267
1268
1269
1270
1271
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 if __name__ == "__main__":
1284
1285 if len(sys.argv) < 2:
1286 sys.exit()
1287
1288 if sys.argv[1] != u'test':
1289 sys.exit()
1290
1291 app = wx.PyWidgetTester(size = (600, 600))
1292 app.SetWidget(cATCPhraseWheel, -1)
1293 app.MainLoop()
1294