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
577 template = gmFormWidgets.manage_form_templates (
578 parent = parent,
579 active_only = True,
580 template_types = [u'Medical statement', u'vaccination report', u'vaccination record']
581 )
582
583 if template is None:
584 gmDispatcher.send(signal = 'statustext', msg = _('No vaccination document template selected.'), beep = False)
585 return None
586
587
588 try:
589 vaccs_printout = template.instantiate()
590 except KeyError:
591 _log.exception('cannot instantiate vaccinations printout template [%s]', template)
592 gmGuiHelpers.gm_show_error (
593 aMessage = _('Invalid vaccinations printout template [%s - %s (%s)]') % (name, ver, template['engine']),
594 aTitle = _('Printing vaccinations')
595 )
596 return False
597
598 ph = gmMacro.gmPlaceholderHandler()
599
600 vaccs_printout.substitute_placeholders(data_source = ph)
601 pdf_name = vaccs_printout.generate_output()
602 if pdf_name is None:
603 gmGuiHelpers.gm_show_error (
604 aMessage = _('Error generating the vaccinations printout.'),
605 aTitle = _('Printing vaccinations')
606 )
607 return False
608
609
610 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'vaccinations')
611 if not printed:
612 gmGuiHelpers.gm_show_error (
613 aMessage = _('Error printing vaccinations.'),
614 aTitle = _('Printing vaccinations')
615 )
616 return False
617
618 pat = gmPerson.gmCurrentPatient()
619 emr = pat.get_emr()
620 epi = emr.add_episode(episode_name = 'administration', is_open = False)
621 emr.add_clin_narrative (
622 soap_cat = None,
623 note = _('vaccinations printed from template [%s - %s]') % (template['name_long'], template['external_version']),
624 episode = epi
625 )
626
627 return True
628
629
643
644
664
665 def print_vaccs(vaccination=None):
666 print_vaccinations(parent = parent)
667 return False
668
669 def add_recall(vaccination=None):
670 if vaccination is None:
671 subject = _('vaccination recall')
672 else:
673 subject = _('vaccination recall (%s)') % vaccination['vaccine']
674
675 recall = gmProviderInbox.create_inbox_message (
676 message_type = _('Vaccination'),
677 subject = subject,
678 patient = pat.ID,
679 staff = None
680 )
681
682 if vaccination is not None:
683 recall['data'] = _('Existing vaccination:\n\n%s') % u'\n'.join(vaccination.format(
684 with_indications = True,
685 with_comment = True,
686 with_reaction = False,
687 date_format = '%Y %b %d'
688 ))
689 recall.save()
690
691 from Gnumed.wxpython import gmProviderInboxWidgets
692 gmProviderInboxWidgets.edit_inbox_message (
693 parent = parent,
694 message = recall,
695 single_entry = False
696 )
697
698 return False
699
700 def get_tooltip(vaccination):
701 if vaccination is None:
702 return None
703 return u'\n'.join(vaccination.format (
704 with_indications = True,
705 with_comment = True,
706 with_reaction = True,
707 date_format = '%Y %b %d'
708 ))
709
710 def edit(vaccination=None):
711 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
712
713 def delete(vaccination=None):
714 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
715 return True
716
717 def refresh(lctrl):
718
719 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
720
721 items = [ [
722 gmDateTime.pydt_strftime(v['date_given'], '%Y %b %d'),
723 v['vaccine'],
724 u', '.join(v['l10n_indications']),
725 v['batch_no'],
726 gmTools.coalesce(v['site'], u''),
727 gmTools.coalesce(v['reaction'], u''),
728 gmTools.coalesce(v['comment'], u'')
729 ] for v in vaccs ]
730
731 lctrl.set_string_items(items)
732 lctrl.set_data(vaccs)
733
734 gmListWidgets.get_choices_from_list (
735 parent = parent,
736 msg = _('\nComplete vaccination history for this patient.\n'),
737 caption = _('Showing vaccinations.'),
738 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
739 single_selection = True,
740 refresh_callback = refresh,
741 new_callback = edit,
742 edit_callback = edit,
743 delete_callback = delete,
744 list_tooltip_callback = get_tooltip,
745 left_extra_button = (_('Print'), _('Print vaccinations using a template.'), print_vaccs),
746 middle_extra_button = (_('Recall'), _('Add a recall for a vaccination'), add_recall),
747 right_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
748 )
749
750 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
751
752 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
753 """
754 - warn on apparent duplicates
755 - ask if "missing" (= previous, non-recorded) vaccinations
756 should be estimated and saved (add note "auto-generated")
757
758 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
759 """
777
779
780 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
781 self._PRW_provider.selection_only = False
782 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
783 if self.mode == 'edit':
784 self._BTN_select_indications.Disable()
785
787
788 vaccine = self._PRW_vaccine.GetData(as_instance=True)
789
790
791 if self.mode == u'edit':
792 if vaccine is None:
793 self._PRW_batch.unset_context(context = 'pk_vaccine')
794 self.__indications = []
795 else:
796 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
797 self.__indications = vaccine.indications
798
799 else:
800 if vaccine is None:
801 self._PRW_batch.unset_context(context = 'pk_vaccine')
802 self.__indications = []
803 self._BTN_select_indications.Enable()
804 else:
805 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
806 self.__indications = vaccine.indications
807 self._BTN_select_indications.Disable()
808
809 self.__refresh_indications()
810
812 if self._PRW_reaction.GetValue().strip() == u'':
813 self._BTN_report.Enable(False)
814 else:
815 self._BTN_report.Enable(True)
816
818 self._TCTRL_indications.SetValue(u'')
819 if len(self.__indications) == 0:
820 return
821 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
822
823
824
862
877
897
922
924
925 if self._CHBOX_anamnestic.GetValue() is True:
926 self.data['soap_cat'] = u's'
927 else:
928 self.data['soap_cat'] = u'p'
929
930 self.data['date_given'] = self._PRW_date_given.GetData()
931 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
932 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
933 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
934 self.data['site'] = self._PRW_site.GetValue().strip()
935 self.data['pk_provider'] = self._PRW_provider.GetData()
936 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
937 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
938
939 self.data.save()
940
941 return True
942
944 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
945 self._CHBOX_anamnestic.SetValue(False)
946 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
947 self._PRW_batch.unset_context(context = 'pk_vaccine')
948 self._PRW_batch.SetValue(u'')
949 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
950 self._PRW_site.SetValue(u'')
951 self._PRW_provider.SetData(data = None)
952 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
953 self._BTN_report.Enable(False)
954 self._TCTRL_comment.SetValue(u'')
955
956 self.__indications = []
957 self.__refresh_indications()
958 self._BTN_select_indications.Enable()
959
960 self._PRW_date_given.SetFocus()
961
986
1007
1008
1009
1027
1030
1031
1046
1047
1048
1049
1050
1052
1054 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
1055 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1056 self.__pat = gmPerson.gmCurrentPatient()
1057
1058 self.ID_VaccinatedIndicationsList = wx.NewId()
1059 self.ID_VaccinationsPerRegimeList = wx.NewId()
1060 self.ID_MissingShots = wx.NewId()
1061 self.ID_ActiveSchedules = wx.NewId()
1062 self.__do_layout()
1063 self.__register_interests()
1064 self.__reset_ui_content()
1065
1067
1068
1069
1070 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
1071 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
1072
1073
1074
1075
1076
1077 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
1078 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
1079 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
1080 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
1081 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
1082 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
1083 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
1084
1085
1086 self.LBOX_vaccinated_indications = wx.ListBox(
1087 parent = self,
1088 id = self.ID_VaccinatedIndicationsList,
1089 choices = [],
1090 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1091 )
1092 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1093
1094
1095
1096 self.LBOX_given_shots = wx.ListBox(
1097 parent = self,
1098 id = self.ID_VaccinationsPerRegimeList,
1099 choices = [],
1100 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1101 )
1102 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1103
1104 self.LBOX_active_schedules = wx.ListBox (
1105 parent = self,
1106 id = self.ID_ActiveSchedules,
1107 choices = [],
1108 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1109 )
1110 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1111
1112 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1113 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1114 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1115 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1116
1117
1118
1119
1120 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1121 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1122 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1123
1124 self.LBOX_missing_shots = wx.ListBox (
1125 parent = self,
1126 id = self.ID_MissingShots,
1127 choices = [],
1128 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1129 )
1130 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1131
1132 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1133 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1134
1135
1136 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1137
1138
1139
1140
1141 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1142 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1143 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1144 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1145 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1146 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1147 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1148 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1149
1150 self.SetAutoLayout(True)
1151 self.SetSizer(self.mainsizer)
1152 self.mainsizer.Fit(self)
1153
1155
1156 wx.EVT_SIZE(self, self.OnSize)
1157 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1158 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1159 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1160
1161
1162
1163 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1164 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1165
1166
1167
1169 w, h = event.GetSize()
1170 self.mainsizer.SetDimension (0, 0, w, h)
1171
1173 """Paste previously given shot into edit area.
1174 """
1175 self.editarea.set_data(aVacc=event.GetClientData())
1176
1179
1181 """Update right hand middle list to show vaccinations given for selected indication."""
1182 ind_list = event.GetEventObject()
1183 selected_item = ind_list.GetSelection()
1184 ind = ind_list.GetClientData(selected_item)
1185
1186 self.LBOX_given_shots.Set([])
1187 emr = self.__pat.get_emr()
1188 shots = emr.get_vaccinations(indications = [ind])
1189
1190 for shot in shots:
1191 if shot['is_booster']:
1192 marker = 'B'
1193 else:
1194 marker = '#%s' % shot['seq_no']
1195 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1196 self.LBOX_given_shots.Append(label, shot)
1197
1199
1200 self.editarea.set_data()
1201
1202 self.LBOX_vaccinated_indications.Clear()
1203 self.LBOX_given_shots.Clear()
1204 self.LBOX_active_schedules.Clear()
1205 self.LBOX_missing_shots.Clear()
1206
1208
1209 self.LBOX_vaccinated_indications.Clear()
1210 self.LBOX_given_shots.Clear()
1211 self.LBOX_active_schedules.Clear()
1212 self.LBOX_missing_shots.Clear()
1213
1214 emr = self.__pat.get_emr()
1215
1216 t1 = time.time()
1217
1218
1219
1220 status, indications = emr.get_vaccinated_indications()
1221
1222
1223
1224 for indication in indications:
1225 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1226
1227
1228 print "vaccinated indications took", time.time()-t1, "seconds"
1229
1230 t1 = time.time()
1231
1232 scheds = emr.get_scheduled_vaccination_regimes()
1233 if scheds is None:
1234 label = _('ERROR: cannot retrieve active vaccination schedules')
1235 self.LBOX_active_schedules.Append(label)
1236 elif len(scheds) == 0:
1237 label = _('no active vaccination schedules')
1238 self.LBOX_active_schedules.Append(label)
1239 else:
1240 for sched in scheds:
1241 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1242 self.LBOX_active_schedules.Append(label)
1243 print "active schedules took", time.time()-t1, "seconds"
1244
1245 t1 = time.time()
1246
1247 missing_shots = emr.get_missing_vaccinations()
1248 print "getting missing shots took", time.time()-t1, "seconds"
1249 if missing_shots is None:
1250 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1251 self.LBOX_missing_shots.Append(label, None)
1252 return True
1253
1254 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1255 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1256 for shot in missing_shots['due']:
1257 if shot['overdue']:
1258 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1259 weeks = days_left / 7
1260
1261 label = overdue_template % (
1262 years,
1263 weeks,
1264 shot['seq_no'],
1265 shot['l10n_indication'],
1266 shot['regime'],
1267 shot['vacc_comment']
1268 )
1269 self.LBOX_missing_shots.Append(label, shot)
1270 else:
1271
1272 label = due_template % (
1273 shot['time_left'].days / 7,
1274 shot['seq_no'],
1275 shot['indication'],
1276 shot['regime'],
1277 shot['latest_due'].strftime('%m/%Y'),
1278 shot['vacc_comment']
1279 )
1280 self.LBOX_missing_shots.Append(label, shot)
1281
1282 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1283 for shot in missing_shots['boosters']:
1284
1285 label = lbl_template % (
1286 shot['l10n_indication'],
1287 shot['regime'],
1288 shot['vacc_comment']
1289 )
1290 self.LBOX_missing_shots.Append(label, shot)
1291 print "displaying missing shots took", time.time()-t1, "seconds"
1292
1293 return True
1294
1295 - def _on_post_patient_selection(self, **kwargs):
1297
1298
1299
1300
1301
1302
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314 if __name__ == "__main__":
1315
1316 if len(sys.argv) < 2:
1317 sys.exit()
1318
1319 if sys.argv[1] != u'test':
1320 sys.exit()
1321
1322 app = wx.PyWidgetTester(size = (600, 600))
1323 app.SetWidget(cATCPhraseWheel, -1)
1324 app.MainLoop()
1325