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
23 from Gnumed.business import gmVaccination
24 from Gnumed.business import gmSurgery
25 from Gnumed.wxpython import gmPhraseWheel, gmTerryGuiParts, gmRegetMixin, gmGuiHelpers
26 from Gnumed.wxpython import gmEditArea
27 from Gnumed.wxpython import gmListWidgets
28
29
30 _log = logging.getLogger('gm.vaccination')
31 _log.info(__version__)
32
33
34
35
37
38 if parent is None:
39 parent = wx.GetApp().GetTopWindow()
40
41 def refresh(lctrl):
42 inds = gmVaccination.get_indications(order_by = 'l10n_description')
43
44 items = [ [
45 i['l10n_description'],
46 gmTools.coalesce (
47 i['atcs_single_indication'],
48 u'',
49 u'%s'
50 ),
51 gmTools.coalesce (
52 i['atcs_combi_indication'],
53 u'',
54 u'%s'
55 ),
56 u'%s' % i['id']
57 ] for i in inds ]
58
59 lctrl.set_string_items(items)
60 lctrl.set_data(inds)
61
62 gmListWidgets.get_choices_from_list (
63 parent = parent,
64 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
65 caption = _('Showing vaccination preventable conditions.'),
66 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
67 single_selection = True,
68 refresh_callback = refresh
69 )
70
72
73 if parent is None:
74 parent = wx.GetApp().GetTopWindow()
75
76 if msg is None:
77 msg = _('Pick the relevant indications.')
78
79 if right_column is None:
80 right_columns = ['This vaccine']
81 else:
82 right_columns = [right_column]
83
84 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
85 picker.set_columns(columns = [_('Known indications')], columns_right = right_columns)
86 inds = gmVaccination.get_indications(order_by = 'l10n_description')
87 picker.set_choices (
88 choices = [ i['l10n_description'] for i in inds ],
89 data = inds
90 )
91 picker.set_picks (
92 picks = [ p['l10n_description'] for p in picks ],
93 data = picks
94 )
95 result = picker.ShowModal()
96
97 if result == wx.ID_CANCEL:
98 picker.Destroy()
99 return None
100
101 picks = picker.picks
102 picker.Destroy()
103 return picks
104
105
106
107
108 -def edit_vaccine(parent=None, vaccine=None, single_entry=True):
119
121
122 if parent is None:
123 parent = wx.GetApp().GetTopWindow()
124
125 def delete(vaccine=None):
126 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
127 if deleted:
128 return True
129
130 gmGuiHelpers.gm_show_info (
131 _(
132 'Cannot delete vaccine\n'
133 '\n'
134 ' %s - %s (#%s)\n'
135 '\n'
136 'It is probably documented in a vaccination.'
137 ) % (
138 vaccine['vaccine'],
139 vaccine['preparation'],
140 vaccine['pk_vaccine']
141 ),
142 _('Deleting vaccine')
143 )
144
145 return False
146
147 def edit(vaccine=None):
148 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
149
150 def refresh(lctrl):
151 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
152
153 items = [ [
154 u'%s' % v['pk_brand'],
155 u'%s%s' % (
156 v['vaccine'],
157 gmTools.bool2subst (
158 v['is_fake_vaccine'],
159 u' (%s)' % _('fake'),
160 u''
161 )
162 ),
163 v['preparation'],
164
165
166 gmTools.coalesce(v['atc_code'], u''),
167 u'%s%s' % (
168 gmTools.coalesce(v['min_age'], u'?'),
169 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
170 ),
171 gmTools.coalesce(v['comment'], u'')
172 ] for v in vaccines ]
173 lctrl.set_string_items(items)
174 lctrl.set_data(vaccines)
175
176 gmListWidgets.get_choices_from_list (
177 parent = parent,
178 msg = _('\nThe vaccines currently known to GNUmed.\n'),
179 caption = _('Showing vaccines.'),
180
181 columns = [ u'#', _('Brand'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ],
182 single_selection = True,
183 refresh_callback = refresh,
184 edit_callback = edit,
185 new_callback = edit,
186 delete_callback = delete
187 )
188
190
192
193 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
194
195 context = {
196 u'ctxt_vaccine': {
197 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
198 u'placeholder': u'pk_vaccine'
199 }
200 }
201
202 query = u"""
203 SELECT data, field_label, list_label FROM (
204
205 SELECT distinct on (field_label)
206 data,
207 field_label,
208 list_label,
209 rank
210 FROM ((
211 -- batch_no by vaccine
212 SELECT
213 batch_no AS data,
214 batch_no AS field_label,
215 batch_no || ' (' || vaccine || ')' AS list_label,
216 1 as rank
217 FROM
218 clin.v_pat_vaccinations
219 WHERE
220 batch_no %(fragment_condition)s
221 %(ctxt_vaccine)s
222 ) UNION ALL (
223 -- batch_no for any vaccine
224 SELECT
225 batch_no AS data,
226 batch_no AS field_label,
227 batch_no || ' (' || vaccine || ')' AS list_label,
228 2 AS rank
229 FROM
230 clin.v_pat_vaccinations
231 WHERE
232 batch_no %(fragment_condition)s
233 )
234
235 ) AS matching_batch_nos
236
237 ) as unique_matches
238
239 ORDER BY rank, list_label
240 LIMIT 25
241 """
242 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
243 mp.setThresholds(1, 2, 3)
244 self.matcher = mp
245
246 self.unset_context(context = u'pk_vaccine')
247 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
248 self.selection_only = False
249
251
253
254 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
255
256
257 query = u"""
258 SELECT data, list_label, field_label FROM (
259
260 SELECT DISTINCT ON (data)
261 data,
262 list_label,
263 field_label
264 FROM ((
265 -- fragment -> vaccine
266 SELECT
267 pk_vaccine AS data,
268 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
269 vaccine AS field_label
270 FROM
271 clin.v_vaccines
272 WHERE
273 vaccine %(fragment_condition)s
274
275 ) union all (
276
277 -- fragment -> localized indication -> vaccines
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_indications4vaccine
284 WHERE
285 l10n_indication %(fragment_condition)s
286
287 ) union all (
288
289 -- fragment -> indication -> vaccines
290 SELECT
291 pk_vaccine AS data,
292 vaccine || ' (' || array_to_string(indications, ', ') || ')' AS list_label,
293 vaccine AS field_label
294 FROM
295 clin.v_indications4vaccine
296 WHERE
297 indication %(fragment_condition)s
298 )
299 ) AS distinct_total
300
301 ) AS total
302
303 ORDER by list_label
304 LIMIT 25
305 """
306 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
307 mp.setThresholds(1, 2, 3)
308 self.matcher = mp
309
310 self.selection_only = True
311
314
315 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
316
317 -class cVaccineEAPnl(wxgVaccineEAPnl.wxgVaccineEAPnl, gmEditArea.cGenericEditAreaMixin):
318
333
335 self._TCTRL_indications.SetValue(u'')
336 if len(self.__indications) == 0:
337 return
338 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
339
340
341
343
344 has_errors = False
345
346 if self._PRW_brand.GetValue().strip() == u'':
347 has_errors = True
348 self._PRW_brand.display_as_valid(False)
349 else:
350 self._PRW_brand.display_as_valid(True)
351
352 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
353 self._PRW_atc.display_as_valid(True)
354 else:
355 if self._PRW_atc.GetData() is None:
356 self._PRW_atc.display_as_valid(True)
357 else:
358 has_errors = True
359 self._PRW_atc.display_as_valid(False)
360
361 val = self._PRW_age_min.GetValue().strip()
362 if val == u'':
363 self._PRW_age_min.display_as_valid(True)
364 else:
365 if gmDateTime.str2interval(val) is None:
366 has_errors = True
367 self._PRW_age_min.display_as_valid(False)
368 else:
369 self._PRW_age_min.display_as_valid(True)
370
371 val = self._PRW_age_max.GetValue().strip()
372 if val == u'':
373 self._PRW_age_max.display_as_valid(True)
374 else:
375 if gmDateTime.str2interval(val) is None:
376 has_errors = True
377 self._PRW_age_max.display_as_valid(False)
378 else:
379 self._PRW_age_max.display_as_valid(True)
380
381
382 ask_user = (self.mode == 'edit')
383
384 ask_user = (ask_user and self.data.is_in_use)
385
386 ask_user = ask_user and (
387
388 (self.data['pk_brand'] != self._PRW_route.GetData())
389 or
390
391 (set(self.data['pk_indications']) != set([ i['id'] for i in self.__indications ]))
392 )
393
394 if ask_user:
395 do_it = gmGuiHelpers.gm_show_question (
396 aTitle = _('Saving vaccine'),
397 aMessage = _(
398 u'This vaccine is already in use:\n'
399 u'\n'
400 u' "%s"\n'
401 u' (%s)\n'
402 u'\n'
403 u'Are you absolutely positively sure that\n'
404 u'you really want to edit this vaccine ?\n'
405 '\n'
406 u'This will change the vaccine name and/or target\n'
407 u'conditions in each patient this vaccine was\n'
408 u'used in to document a vaccination with.\n'
409 ) % (
410 self._PRW_brand.GetValue().strip(),
411 u', '.join(self.data['l10n_indications'])
412 )
413 )
414 if not do_it:
415 has_errors = True
416
417 return (has_errors is False)
418
420
421 if len(self.__indications) == 0:
422 gmGuiHelpers.gm_show_info (
423 aTitle = _('Saving vaccine'),
424 aMessage = _('You must select at least one indication.')
425 )
426 return False
427
428
429 data = gmVaccination.create_vaccine (
430 pk_brand = self._PRW_brand.GetData(),
431 brand_name = self._PRW_brand.GetValue(),
432 pk_indications = [ i['id'] for i in self.__indications ]
433 )
434
435
436 val = self._PRW_age_min.GetValue().strip()
437 if val != u'':
438 data['min_age'] = gmDateTime.str2interval(val)
439 val = self._PRW_age_max.GetValue().strip()
440 if val != u'':
441 data['max_age'] = gmDateTime.str2interval(val)
442 val = self._TCTRL_comment.GetValue().strip()
443 if val != u'':
444 data['comment'] = val
445
446 data.save()
447
448 drug = data.brand
449 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
450 val = self._PRW_atc.GetData()
451 if val is not None:
452 if val != u'J07':
453 drug['atc'] = val.strip()
454 drug.save()
455
456
457
458
459 self.data = data
460
461 return True
462
464
465 if len(self.__indications) == 0:
466 gmGuiHelpers.gm_show_info (
467 aTitle = _('Saving vaccine'),
468 aMessage = _('You must select at least one indication.')
469 )
470 return False
471
472 drug = self.data.brand
473 drug['brand'] = self._PRW_brand.GetValue().strip()
474 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
475 val = self._PRW_atc.GetData()
476 if val is not None:
477 if val != u'J07':
478 drug['atc'] = val.strip()
479 drug.save()
480
481
482 self.data.set_indications(pk_indications = [ i['id'] for i in self.__indications ])
483
484
485 val = self._PRW_age_min.GetValue().strip()
486 if val != u'':
487 self.data['min_age'] = gmDateTime.str2interval(val)
488 if val != u'':
489 self.data['max_age'] = gmDateTime.str2interval(val)
490 val = self._TCTRL_comment.GetValue().strip()
491 if val != u'':
492 self.data['comment'] = val
493
494 self.data.save()
495 return True
496
498 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True)
499
500 self._CHBOX_fake.SetValue(False)
501 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True)
502 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
503 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
504 self._TCTRL_comment.SetValue(u'')
505
506 self.__indications = []
507 self.__refresh_indications()
508
509 self._PRW_brand.SetFocus()
510
512 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
513
514 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
515 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
516 if self.data['min_age'] is None:
517 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
518 else:
519 self._PRW_age_min.SetText (
520 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
521 data = self.data['min_age']
522 )
523 if self.data['max_age'] is None:
524 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
525 else:
526 self._PRW_age_max.SetText (
527 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
528 data = self.data['max_age']
529 )
530 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
531
532 self.__indications = self.data.indications
533 self.__refresh_indications()
534
535 self._PRW_brand.SetFocus()
536
538 self._refresh_as_new()
539
540
555
556
557
571
591
592 def edit(vaccination=None):
593 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
594
595 def delete(vaccination=None):
596 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
597 return True
598
599 def refresh(lctrl):
600
601 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
602
603 items = [ [
604 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
605 v['vaccine'],
606 u', '.join(v['l10n_indications']),
607 v['batch_no'],
608 gmTools.coalesce(v['site'], u''),
609 gmTools.coalesce(v['reaction'], u''),
610 gmTools.coalesce(v['comment'], u'')
611 ] for v in vaccs ]
612
613 lctrl.set_string_items(items)
614 lctrl.set_data(vaccs)
615
616 gmListWidgets.get_choices_from_list (
617 parent = parent,
618 msg = _('\nComplete vaccination history for this patient.\n'),
619 caption = _('Showing vaccinations.'),
620 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
621 single_selection = True,
622 refresh_callback = refresh,
623 new_callback = edit,
624 edit_callback = edit,
625 delete_callback = delete,
626 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
627 )
628
629 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
630
631 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
632 """
633 - warn on apparent duplicates
634 - ask if "missing" (= previous, non-recorded) vaccinations
635 should be estimated and saved (add note "auto-generated")
636
637 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
638 """
656
658
659 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
660 self._PRW_provider.selection_only = False
661 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
662 if self.mode == 'edit':
663 self._BTN_select_indications.Disable()
664
666
667 vaccine = self._PRW_vaccine.GetData(as_instance=True)
668
669
670 if self.mode == u'edit':
671 if vaccine is None:
672 self._PRW_batch.unset_context(context = 'pk_vaccine')
673 self.__indications = []
674 else:
675 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
676 self.__indications = vaccine.indications
677
678 else:
679 if vaccine is None:
680 self._PRW_batch.unset_context(context = 'pk_vaccine')
681 self.__indications = []
682 self._BTN_select_indications.Enable()
683 else:
684 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
685 self.__indications = vaccine.indications
686 self._BTN_select_indications.Disable()
687
688 self.__refresh_indications()
689
691 if self._PRW_reaction.GetValue().strip() == u'':
692 self._BTN_report.Enable(False)
693 else:
694 self._BTN_report.Enable(True)
695
697 self._TCTRL_indications.SetValue(u'')
698 if len(self.__indications) == 0:
699 return
700 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
701
702
703
741
756
776
801
803
804 if self._CHBOX_anamnestic.GetValue() is True:
805 self.data['soap_cat'] = u's'
806 else:
807 self.data['soap_cat'] = u'p'
808
809 self.data['date_given'] = self._PRW_date_given.GetData()
810 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
811 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
812 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
813 self.data['site'] = self._PRW_site.GetValue().strip()
814 self.data['pk_provider'] = self._PRW_provider.GetData()
815 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
816 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
817
818 self.data.save()
819
820 return True
821
823 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
824 self._CHBOX_anamnestic.SetValue(False)
825 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
826 self._PRW_batch.unset_context(context = 'pk_vaccine')
827 self._PRW_batch.SetValue(u'')
828 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
829 self._PRW_site.SetValue(u'')
830 self._PRW_provider.SetData(data = None)
831 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
832 self._BTN_report.Enable(False)
833 self._TCTRL_comment.SetValue(u'')
834
835 self.__indications = []
836 self.__refresh_indications()
837 self._BTN_select_indications.Enable()
838
839 self._PRW_date_given.SetFocus()
840
865
886
887
888
906
909
910
925
926
928
930 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
931 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
932 self.__pat = gmPerson.gmCurrentPatient()
933
934 self.ID_VaccinatedIndicationsList = wx.NewId()
935 self.ID_VaccinationsPerRegimeList = wx.NewId()
936 self.ID_MissingShots = wx.NewId()
937 self.ID_ActiveSchedules = wx.NewId()
938 self.__do_layout()
939 self.__register_interests()
940 self.__reset_ui_content()
941
943
944
945
946 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
947 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
948
949
950
951
952
953 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
954 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
955 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
956 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
957 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
958 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
959 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
960
961
962 self.LBOX_vaccinated_indications = wx.ListBox(
963 parent = self,
964 id = self.ID_VaccinatedIndicationsList,
965 choices = [],
966 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
967 )
968 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
969
970
971
972 self.LBOX_given_shots = wx.ListBox(
973 parent = self,
974 id = self.ID_VaccinationsPerRegimeList,
975 choices = [],
976 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
977 )
978 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
979
980 self.LBOX_active_schedules = wx.ListBox (
981 parent = self,
982 id = self.ID_ActiveSchedules,
983 choices = [],
984 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
985 )
986 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
987
988 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
989 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
990 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
991 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
992
993
994
995
996 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
997 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
998 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
999
1000 self.LBOX_missing_shots = wx.ListBox (
1001 parent = self,
1002 id = self.ID_MissingShots,
1003 choices = [],
1004 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1005 )
1006 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1007
1008 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1009 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1010
1011
1012 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1013
1014
1015
1016
1017 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1018 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1019 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1020 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1021 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1022 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1023 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1024 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1025
1026 self.SetAutoLayout(True)
1027 self.SetSizer(self.mainsizer)
1028 self.mainsizer.Fit(self)
1029
1031
1032 wx.EVT_SIZE(self, self.OnSize)
1033 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1034 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1035 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1036
1037
1038
1039 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1040 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1041
1042
1043
1045 w, h = event.GetSize()
1046 self.mainsizer.SetDimension (0, 0, w, h)
1047
1049 """Paste previously given shot into edit area.
1050 """
1051 self.editarea.set_data(aVacc=event.GetClientData())
1052
1054 self.editarea.set_data(aVacc = event.GetClientData())
1055
1057 """Update right hand middle list to show vaccinations given for selected indication."""
1058 ind_list = event.GetEventObject()
1059 selected_item = ind_list.GetSelection()
1060 ind = ind_list.GetClientData(selected_item)
1061
1062 self.LBOX_given_shots.Set([])
1063 emr = self.__pat.get_emr()
1064 shots = emr.get_vaccinations(indications = [ind])
1065
1066 for shot in shots:
1067 if shot['is_booster']:
1068 marker = 'B'
1069 else:
1070 marker = '#%s' % shot['seq_no']
1071 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1072 self.LBOX_given_shots.Append(label, shot)
1073
1075
1076 self.editarea.set_data()
1077
1078 self.LBOX_vaccinated_indications.Clear()
1079 self.LBOX_given_shots.Clear()
1080 self.LBOX_active_schedules.Clear()
1081 self.LBOX_missing_shots.Clear()
1082
1084
1085 self.LBOX_vaccinated_indications.Clear()
1086 self.LBOX_given_shots.Clear()
1087 self.LBOX_active_schedules.Clear()
1088 self.LBOX_missing_shots.Clear()
1089
1090 emr = self.__pat.get_emr()
1091
1092 t1 = time.time()
1093
1094
1095
1096 status, indications = emr.get_vaccinated_indications()
1097
1098
1099
1100 for indication in indications:
1101 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1102
1103
1104 print "vaccinated indications took", time.time()-t1, "seconds"
1105
1106 t1 = time.time()
1107
1108 scheds = emr.get_scheduled_vaccination_regimes()
1109 if scheds is None:
1110 label = _('ERROR: cannot retrieve active vaccination schedules')
1111 self.LBOX_active_schedules.Append(label)
1112 elif len(scheds) == 0:
1113 label = _('no active vaccination schedules')
1114 self.LBOX_active_schedules.Append(label)
1115 else:
1116 for sched in scheds:
1117 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1118 self.LBOX_active_schedules.Append(label)
1119 print "active schedules took", time.time()-t1, "seconds"
1120
1121 t1 = time.time()
1122
1123 missing_shots = emr.get_missing_vaccinations()
1124 print "getting missing shots took", time.time()-t1, "seconds"
1125 if missing_shots is None:
1126 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1127 self.LBOX_missing_shots.Append(label, None)
1128 return True
1129
1130 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1131 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1132 for shot in missing_shots['due']:
1133 if shot['overdue']:
1134 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1135 weeks = days_left / 7
1136
1137 label = overdue_template % (
1138 years,
1139 weeks,
1140 shot['seq_no'],
1141 shot['l10n_indication'],
1142 shot['regime'],
1143 shot['vacc_comment']
1144 )
1145 self.LBOX_missing_shots.Append(label, shot)
1146 else:
1147
1148 label = due_template % (
1149 shot['time_left'].days / 7,
1150 shot['seq_no'],
1151 shot['indication'],
1152 shot['regime'],
1153 shot['latest_due'].strftime('%m/%Y'),
1154 shot['vacc_comment']
1155 )
1156 self.LBOX_missing_shots.Append(label, shot)
1157
1158 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1159 for shot in missing_shots['boosters']:
1160
1161 label = lbl_template % (
1162 shot['l10n_indication'],
1163 shot['regime'],
1164 shot['vacc_comment']
1165 )
1166 self.LBOX_missing_shots.Append(label, shot)
1167 print "displaying missing shots took", time.time()-t1, "seconds"
1168
1169 return True
1170
1171 - def _on_post_patient_selection(self, **kwargs):
1173
1174
1175
1176
1177
1178
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190 if __name__ == "__main__":
1191
1192 if len(sys.argv) < 2:
1193 sys.exit()
1194
1195 if sys.argv[1] != u'test':
1196 sys.exit()
1197
1198 app = wx.PyWidgetTester(size = (600, 600))
1199 app.SetWidget(cATCPhraseWheel, -1)
1200 app.MainLoop()
1201
1202