| Home | Trees | Indices | Help |
|
|---|
|
|
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 gmSurgery
31
32 from Gnumed.wxpython import gmPhraseWheel
33 from Gnumed.wxpython import gmTerryGuiParts
34 from Gnumed.wxpython import gmRegetMixin
35 from Gnumed.wxpython import gmGuiHelpers
36 from Gnumed.wxpython import gmEditArea
37 from Gnumed.wxpython import gmListWidgets
38 from Gnumed.wxpython import gmFormWidgets
39 from Gnumed.wxpython import gmMacro
40
41
42 _log = logging.getLogger('gm.vaccination')
43
44 #======================================================================
45 # vaccination indication related widgets
46 #----------------------------------------------------------------------
48
49 if parent is None:
50 parent = wx.GetApp().GetTopWindow()
51 #------------------------------------------------------------
52 def refresh(lctrl):
53 inds = gmVaccination.get_indications(order_by = 'l10n_description')
54
55 items = [ [
56 i['l10n_description'],
57 gmTools.coalesce (
58 i['atcs_single_indication'],
59 u'',
60 u'%s'
61 ),
62 gmTools.coalesce (
63 i['atcs_combi_indication'],
64 u'',
65 u'%s'
66 ),
67 u'%s' % i['id']
68 ] for i in inds ]
69
70 lctrl.set_string_items(items)
71 lctrl.set_data(inds)
72 #------------------------------------------------------------
73 gmListWidgets.get_choices_from_list (
74 parent = parent,
75 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
76 caption = _('Showing vaccination preventable conditions.'),
77 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
78 single_selection = True,
79 refresh_callback = refresh
80 )
81 #----------------------------------------------------------------------
83
84 if parent is None:
85 parent = wx.GetApp().GetTopWindow()
86
87 if msg is None:
88 msg = _('Pick the relevant indications.')
89
90 if right_column is None:
91 right_columns = ['This vaccine']
92 else:
93 right_columns = [right_column]
94
95 picker = gmListWidgets.cItemPickerDlg(parent, -1, msg = msg)
96 picker.set_columns(columns = [_('Known indications')], columns_right = right_columns)
97 inds = gmVaccination.get_indications(order_by = 'l10n_description')
98 picker.set_choices (
99 choices = [ i['l10n_description'] for i in inds ],
100 data = inds
101 )
102 picker.set_picks (
103 picks = [ p['l10n_description'] for p in picks ],
104 data = picks
105 )
106 result = picker.ShowModal()
107
108 if result == wx.ID_CANCEL:
109 picker.Destroy()
110 return None
111
112 picks = picker.picks
113 picker.Destroy()
114 return picks
115
116 #======================================================================
117 # vaccines related widgets
118 #----------------------------------------------------------------------
120 ea = cVaccineEAPnl(parent = parent, id = -1)
121 ea.data = vaccine
122 ea.mode = gmTools.coalesce(vaccine, 'new', 'edit')
123 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
124 dlg.SetTitle(gmTools.coalesce(vaccine, _('Adding new vaccine'), _('Editing vaccine')))
125 if dlg.ShowModal() == wx.ID_OK:
126 dlg.Destroy()
127 return True
128 dlg.Destroy()
129 return False
130 #----------------------------------------------------------------------
132
133 if parent is None:
134 parent = wx.GetApp().GetTopWindow()
135 #------------------------------------------------------------
136 def delete(vaccine=None):
137 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
138 if deleted:
139 return True
140
141 gmGuiHelpers.gm_show_info (
142 _(
143 'Cannot delete vaccine\n'
144 '\n'
145 ' %s - %s (#%s)\n'
146 '\n'
147 'It is probably documented in a vaccination.'
148 ) % (
149 vaccine['vaccine'],
150 vaccine['preparation'],
151 vaccine['pk_vaccine']
152 ),
153 _('Deleting vaccine')
154 )
155
156 return False
157 #------------------------------------------------------------
158 def edit(vaccine=None):
159 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
160 #------------------------------------------------------------
161 def refresh(lctrl):
162 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
163
164 items = [ [
165 u'%s' % v['pk_brand'],
166 u'%s%s' % (
167 v['vaccine'],
168 gmTools.bool2subst (
169 v['is_fake_vaccine'],
170 u' (%s)' % _('fake'),
171 u''
172 )
173 ),
174 v['preparation'],
175 #u'%s (%s)' % (v['route_abbreviation'], v['route_description']),
176 #gmTools.bool2subst(v['is_live'], gmTools.u_checkmark_thin, u'', u'?'),
177 gmTools.coalesce(v['atc_code'], u''),
178 u'%s%s' % (
179 gmTools.coalesce(v['min_age'], u'?'),
180 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
181 ),
182 gmTools.coalesce(v['comment'], u'')
183 ] for v in vaccines ]
184 lctrl.set_string_items(items)
185 lctrl.set_data(vaccines)
186 #------------------------------------------------------------
187 gmListWidgets.get_choices_from_list (
188 parent = parent,
189 msg = _('\nThe vaccines currently known to GNUmed.\n'),
190 caption = _('Showing vaccines.'),
191 #columns = [ u'#', _('Brand'), _('Preparation'), _(u'Route'), _('Live'), _('ATC'), _('Age range'), _('Comment') ],
192 columns = [ u'#', _('Brand'), _('Preparation'), _('ATC'), _('Age range'), _('Comment') ],
193 single_selection = True,
194 refresh_callback = refresh,
195 edit_callback = edit,
196 new_callback = edit,
197 delete_callback = delete
198 )
199 #----------------------------------------------------------------------
201
203
204 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
205
206 context = {
207 u'ctxt_vaccine': {
208 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
209 u'placeholder': u'pk_vaccine'
210 }
211 }
212
213 query = u"""
214 SELECT data, field_label, list_label FROM (
215
216 SELECT distinct on (field_label)
217 data,
218 field_label,
219 list_label,
220 rank
221 FROM ((
222 -- batch_no by vaccine
223 SELECT
224 batch_no AS data,
225 batch_no AS field_label,
226 batch_no || ' (' || vaccine || ')' AS list_label,
227 1 as rank
228 FROM
229 clin.v_pat_vaccinations
230 WHERE
231 batch_no %(fragment_condition)s
232 %(ctxt_vaccine)s
233 ) UNION ALL (
234 -- batch_no for any vaccine
235 SELECT
236 batch_no AS data,
237 batch_no AS field_label,
238 batch_no || ' (' || vaccine || ')' AS list_label,
239 2 AS rank
240 FROM
241 clin.v_pat_vaccinations
242 WHERE
243 batch_no %(fragment_condition)s
244 )
245
246 ) AS matching_batch_nos
247
248 ) as unique_matches
249
250 ORDER BY rank, list_label
251 LIMIT 25
252 """
253 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
254 mp.setThresholds(1, 2, 3)
255 self.matcher = mp
256
257 self.unset_context(context = u'pk_vaccine')
258 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
259 self.selection_only = False
260 #----------------------------------------------------------------------
262
264
265 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
266
267 # consider ATCs in ref.branded_drug and vacc_indication
268 query = u"""
269 SELECT data, list_label, field_label FROM (
270
271 SELECT DISTINCT ON (data)
272 data,
273 list_label,
274 field_label
275 FROM ((
276 -- fragment -> vaccine
277 SELECT
278 pk_vaccine AS data,
279 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
280 vaccine AS field_label
281 FROM
282 clin.v_vaccines
283 WHERE
284 vaccine %(fragment_condition)s
285
286 ) union all (
287
288 -- fragment -> localized indication -> vaccines
289 SELECT
290 pk_vaccine AS data,
291 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')' AS list_label,
292 vaccine AS field_label
293 FROM
294 clin.v_indications4vaccine
295 WHERE
296 l10n_indication %(fragment_condition)s
297
298 ) union all (
299
300 -- fragment -> indication -> vaccines
301 SELECT
302 pk_vaccine AS data,
303 vaccine || ' (' || array_to_string(indications, ', ') || ')' AS list_label,
304 vaccine AS field_label
305 FROM
306 clin.v_indications4vaccine
307 WHERE
308 indication %(fragment_condition)s
309 )
310 ) AS distinct_total
311
312 ) AS total
313
314 ORDER by list_label
315 LIMIT 25
316 """
317 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
318 mp.setThresholds(1, 2, 3)
319 self.matcher = mp
320
321 self.selection_only = True
322 #------------------------------------------------------------------
325 #----------------------------------------------------------------------
326 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
327
329
331 try:
332 data = kwargs['vaccine']
333 del kwargs['vaccine']
334 except KeyError:
335 data = None
336
337 wxgVaccineEAPnl.wxgVaccineEAPnl.__init__(self, *args, **kwargs)
338 gmEditArea.cGenericEditAreaMixin.__init__(self)
339
340 self.mode = 'new'
341 self.data = data
342 if data is not None:
343 self.mode = 'edit'
344 #----------------------------------------------------------------
346 self._TCTRL_indications.SetValue(u'')
347 if len(self.__indications) == 0:
348 return
349 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
350 #----------------------------------------------------------------
351 # generic Edit Area mixin API
352 #----------------------------------------------------------------
354
355 has_errors = False
356
357 if self._PRW_brand.GetValue().strip() == u'':
358 has_errors = True
359 self._PRW_brand.display_as_valid(False)
360 else:
361 self._PRW_brand.display_as_valid(True)
362
363 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
364 self._PRW_atc.display_as_valid(True)
365 else:
366 if self._PRW_atc.GetData() is None:
367 self._PRW_atc.display_as_valid(True)
368 else:
369 has_errors = True
370 self._PRW_atc.display_as_valid(False)
371
372 val = self._PRW_age_min.GetValue().strip()
373 if val == u'':
374 self._PRW_age_min.display_as_valid(True)
375 else:
376 if gmDateTime.str2interval(val) is None:
377 has_errors = True
378 self._PRW_age_min.display_as_valid(False)
379 else:
380 self._PRW_age_min.display_as_valid(True)
381
382 val = self._PRW_age_max.GetValue().strip()
383 if val == u'':
384 self._PRW_age_max.display_as_valid(True)
385 else:
386 if gmDateTime.str2interval(val) is None:
387 has_errors = True
388 self._PRW_age_max.display_as_valid(False)
389 else:
390 self._PRW_age_max.display_as_valid(True)
391
392 # are we editing ?
393 ask_user = (self.mode == 'edit')
394 # is this vaccine in use ?
395 ask_user = (ask_user and self.data.is_in_use)
396 # a change ...
397 ask_user = ask_user and (
398 # ... of brand ...
399 (self.data['pk_brand'] != self._PRW_route.GetData())
400 or
401 # ... or indications ?
402 (set(self.data['pk_indications']) != set([ i['id'] for i in self.__indications ]))
403 )
404
405 if ask_user:
406 do_it = gmGuiHelpers.gm_show_question (
407 aTitle = _('Saving vaccine'),
408 aMessage = _(
409 u'This vaccine is already in use:\n'
410 u'\n'
411 u' "%s"\n'
412 u' (%s)\n'
413 u'\n'
414 u'Are you absolutely positively sure that\n'
415 u'you really want to edit this vaccine ?\n'
416 '\n'
417 u'This will change the vaccine name and/or target\n'
418 u'conditions in each patient this vaccine was\n'
419 u'used in to document a vaccination with.\n'
420 ) % (
421 self._PRW_brand.GetValue().strip(),
422 u', '.join(self.data['l10n_indications'])
423 )
424 )
425 if not do_it:
426 has_errors = True
427
428 return (has_errors is False)
429 #----------------------------------------------------------------
431
432 if len(self.__indications) == 0:
433 gmGuiHelpers.gm_show_info (
434 aTitle = _('Saving vaccine'),
435 aMessage = _('You must select at least one indication.')
436 )
437 return False
438
439 # save the data as a new instance
440 data = gmVaccination.create_vaccine (
441 pk_brand = self._PRW_brand.GetData(),
442 brand_name = self._PRW_brand.GetValue(),
443 pk_indications = [ i['id'] for i in self.__indications ]
444 )
445
446 # data['is_live'] = self._CHBOX_live.GetValue()
447 val = self._PRW_age_min.GetValue().strip()
448 if val != u'':
449 data['min_age'] = gmDateTime.str2interval(val)
450 val = self._PRW_age_max.GetValue().strip()
451 if val != u'':
452 data['max_age'] = gmDateTime.str2interval(val)
453 val = self._TCTRL_comment.GetValue().strip()
454 if val != u'':
455 data['comment'] = val
456
457 data.save()
458
459 drug = data.brand
460 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
461 val = self._PRW_atc.GetData()
462 if val is not None:
463 if val != u'J07':
464 drug['atc'] = val.strip()
465 drug.save()
466
467 # must be done very late or else the property access
468 # will refresh the display such that later field
469 # access will return empty values
470 self.data = data
471
472 return True
473 #----------------------------------------------------------------
475
476 if len(self.__indications) == 0:
477 gmGuiHelpers.gm_show_info (
478 aTitle = _('Saving vaccine'),
479 aMessage = _('You must select at least one indication.')
480 )
481 return False
482
483 drug = self.data.brand
484 drug['brand'] = self._PRW_brand.GetValue().strip()
485 drug['is_fake_brand'] = self._CHBOX_fake.GetValue()
486 val = self._PRW_atc.GetData()
487 if val is not None:
488 if val != u'J07':
489 drug['atc'] = val.strip()
490 drug.save()
491
492 # the validator already asked for changes so just do it
493 self.data.set_indications(pk_indications = [ i['id'] for i in self.__indications ])
494
495 # self.data['is_live'] = self._CHBOX_live.GetValue()
496 val = self._PRW_age_min.GetValue().strip()
497 if val != u'':
498 self.data['min_age'] = gmDateTime.str2interval(val)
499 if val != u'':
500 self.data['max_age'] = gmDateTime.str2interval(val)
501 val = self._TCTRL_comment.GetValue().strip()
502 if val != u'':
503 self.data['comment'] = val
504
505 self.data.save()
506 return True
507 #----------------------------------------------------------------
509 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True)
510 # self._CHBOX_live.SetValue(True)
511 self._CHBOX_fake.SetValue(False)
512 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True)
513 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
514 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
515 self._TCTRL_comment.SetValue(u'')
516
517 self.__indications = []
518 self.__refresh_indications()
519
520 self._PRW_brand.SetFocus()
521 #----------------------------------------------------------------
523 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
524 # self._CHBOX_live.SetValue(self.data['is_live'])
525 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
526 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
527 if self.data['min_age'] is None:
528 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
529 else:
530 self._PRW_age_min.SetText (
531 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
532 data = self.data['min_age']
533 )
534 if self.data['max_age'] is None:
535 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
536 else:
537 self._PRW_age_max.SetText (
538 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
539 data = self.data['max_age']
540 )
541 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
542
543 self.__indications = self.data.indications
544 self.__refresh_indications()
545
546 self._PRW_brand.SetFocus()
547 #----------------------------------------------------------------
550 #----------------------------------------------------------------
551 #----------------------------------------------------------------
566
567 #======================================================================
568 # vaccination related widgets
569 #----------------------------------------------------------------------
571
572 if parent is None:
573 parent = wx.GetApp().GetTopWindow()
574
575 # 1) get template
576 template = gmFormWidgets.manage_form_templates (
577 parent = parent,
578 active_only = True,
579 template_types = [u'Medical statement', u'vaccination report', u'vaccination record']
580 )
581
582 if template is None:
583 gmDispatcher.send(signal = 'statustext', msg = _('No vaccination document template selected.'), beep = False)
584 return None
585
586 # 2) process template
587 try:
588 vaccs_printout = template.instantiate()
589 except KeyError:
590 _log.exception('cannot instantiate vaccinations printout template [%s]', template)
591 gmGuiHelpers.gm_show_error (
592 aMessage = _('Invalid vaccinations printout template [%s - %s (%s)]') % (name, ver, template['engine']),
593 aTitle = _('Printing vaccinations')
594 )
595 return False
596
597 ph = gmMacro.gmPlaceholderHandler()
598 #ph.debug = True
599 vaccs_printout.substitute_placeholders(data_source = ph)
600 pdf_name = vaccs_printout.generate_output()
601 if pdf_name is None:
602 gmGuiHelpers.gm_show_error (
603 aMessage = _('Error generating the vaccinations printout.'),
604 aTitle = _('Printing vaccinations')
605 )
606 return False
607
608 # 3) print template
609 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'vaccinations')
610 if not printed:
611 gmGuiHelpers.gm_show_error (
612 aMessage = _('Error printing vaccinations.'),
613 aTitle = _('Printing vaccinations')
614 )
615 return False
616
617 pat = gmPerson.gmCurrentPatient()
618 emr = pat.get_emr()
619 epi = emr.add_episode(episode_name = 'administration', is_open = False)
620 emr.add_clin_narrative (
621 soap_cat = None,
622 note = _('vaccinations printed from template [%s - %s]') % (template['name_long'], template['external_version']),
623 episode = epi
624 )
625
626 return True
627
628 #----------------------------------------------------------------------
630 ea = cVaccinationEAPnl(parent = parent, id = -1)
631 ea.data = vaccination
632 ea.mode = gmTools.coalesce(vaccination, 'new', 'edit')
633 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
634 dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccinations'), _('Editing vaccination')))
635 if dlg.ShowModal() == wx.ID_OK:
636 dlg.Destroy()
637 return True
638 dlg.Destroy()
639 if not single_entry:
640 return True
641 return False
642
643 #----------------------------------------------------------------------
645
646 pat = gmPerson.gmCurrentPatient()
647 emr = pat.get_emr()
648
649 if parent is None:
650 parent = wx.GetApp().GetTopWindow()
651 #------------------------------------------------------------
652 def browse2schedules(vaccination=None):
653 dbcfg = gmCfg.cCfgSQL()
654 url = dbcfg.get2 (
655 option = 'external.urls.vaccination_plans',
656 workplace = gmSurgery.gmCurrentPractice().active_workplace,
657 bias = 'user',
658 default = u'http://www.bundesaerztekammer.de/downloads/STIKOEmpf2011.pdf'
659 )
660
661 gmNetworkTools.open_url_in_browser(url = url)
662 return False
663 #------------------------------------------------------------
664 def print_vaccs(vaccination=None):
665 print_vaccinations(parent = parent)
666 return False
667 #------------------------------------------------------------
668 def edit(vaccination=None):
669 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = (vaccination is not None))
670 #------------------------------------------------------------
671 def delete(vaccination=None):
672 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
673 return True
674 #------------------------------------------------------------
675 def refresh(lctrl):
676
677 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
678
679 items = [ [
680 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
681 v['vaccine'],
682 u', '.join(v['l10n_indications']),
683 v['batch_no'],
684 gmTools.coalesce(v['site'], u''),
685 gmTools.coalesce(v['reaction'], u''),
686 gmTools.coalesce(v['comment'], u'')
687 ] for v in vaccs ]
688
689 lctrl.set_string_items(items)
690 lctrl.set_data(vaccs)
691 #------------------------------------------------------------
692 gmListWidgets.get_choices_from_list (
693 parent = parent,
694 msg = _('\nComplete vaccination history for this patient.\n'),
695 caption = _('Showing vaccinations.'),
696 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
697 single_selection = True,
698 refresh_callback = refresh,
699 new_callback = edit,
700 edit_callback = edit,
701 delete_callback = delete,
702 left_extra_button = (_('Print'), _('Print vaccinations using a template.'), print_vaccs),
703 right_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
704 )
705 #----------------------------------------------------------------------
706 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
707
708 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
709 """
710 - warn on apparent duplicates
711 - ask if "missing" (= previous, non-recorded) vaccinations
712 should be estimated and saved (add note "auto-generated")
713
714 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
715 """
717
718 try:
719 data = kwargs['vaccination']
720 del kwargs['vaccination']
721 except KeyError:
722 data = None
723
724 wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs)
725 gmEditArea.cGenericEditAreaMixin.__init__(self)
726
727 self.mode = 'new'
728 self.data = data
729 if data is not None:
730 self.mode = 'edit'
731
732 self.__init_ui()
733 #----------------------------------------------------------------
735 # adjust phrasewheels etc
736 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
737 self._PRW_provider.selection_only = False
738 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
739 if self.mode == 'edit':
740 self._BTN_select_indications.Disable()
741 #----------------------------------------------------------------
743
744 vaccine = self._PRW_vaccine.GetData(as_instance=True)
745
746 # if we are editing we do not allow using indications rather than a vaccine
747 if self.mode == u'edit':
748 if vaccine is None:
749 self._PRW_batch.unset_context(context = 'pk_vaccine')
750 self.__indications = []
751 else:
752 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
753 self.__indications = vaccine.indications
754 # we are entering a new vaccination
755 else:
756 if vaccine is None:
757 self._PRW_batch.unset_context(context = 'pk_vaccine')
758 self.__indications = []
759 self._BTN_select_indications.Enable()
760 else:
761 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
762 self.__indications = vaccine.indications
763 self._BTN_select_indications.Disable()
764
765 self.__refresh_indications()
766 #----------------------------------------------------------------
768 if self._PRW_reaction.GetValue().strip() == u'':
769 self._BTN_report.Enable(False)
770 else:
771 self._BTN_report.Enable(True)
772 #----------------------------------------------------------------
774 self._TCTRL_indications.SetValue(u'')
775 if len(self.__indications) == 0:
776 return
777 self._TCTRL_indications.SetValue(u'- ' + u'\n- '.join([ i['l10n_description'] for i in self.__indications ]))
778 #----------------------------------------------------------------
779 # generic Edit Area mixin API
780 #----------------------------------------------------------------
782
783 has_errors = False
784
785 if not self._PRW_date_given.is_valid_timestamp(allow_empty = False):
786 has_errors = True
787
788 vaccine = self._PRW_vaccine.GetData(as_instance = True)
789
790 # we are editing, require vaccine rather than indications
791 if self.mode == u'edit':
792 if vaccine is None:
793 has_errors = True
794 self._PRW_vaccine.display_as_valid(False)
795 else:
796 self._PRW_vaccine.display_as_valid(True)
797 # we are creating, allow either vaccine or indications
798 else:
799 if vaccine is None:
800 if len(self.__indications) == 0:
801 self._PRW_vaccine.display_as_valid(False)
802 has_errors = True
803 else:
804 self._PRW_vaccine.display_as_valid(True)
805 else:
806 self._PRW_vaccine.display_as_valid(True)
807
808 if self._PRW_batch.GetValue().strip() == u'':
809 has_errors = True
810 self._PRW_batch.display_as_valid(False)
811 else:
812 self._PRW_batch.display_as_valid(True)
813
814 if self._PRW_episode.GetValue().strip() == u'':
815 self._PRW_episode.SetText(value = _('prevention'))
816
817 return (has_errors is False)
818 #----------------------------------------------------------------
820
821 vaccine = self._PRW_vaccine.GetData()
822 if vaccine is None:
823 data = self.__save_new_from_indications()
824 else:
825 data = self.__save_new_from_vaccine(vaccine = vaccine)
826
827 # must be done very late or else the property access
828 # will refresh the display such that later field
829 # access will return empty values
830 self.data = data
831
832 return True
833 #----------------------------------------------------------------
835
836 if len(self.__indications) == 0:
837 gmGuiHelpers.gm_show_info (
838 aTitle = _('Saving vaccination'),
839 aMessage = _('You must select at least one indication.')
840 )
841 return False
842
843 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ i['description'] for i in self.__indications ])
844
845 if vaccine is None:
846 for ind in self.__indications:
847 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ind['description']])
848 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
849 else:
850 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
851
852 return data
853 #----------------------------------------------------------------
855
856 emr = gmPerson.gmCurrentPatient().get_emr()
857
858 data = emr.add_vaccination (
859 episode = self._PRW_episode.GetData(can_create = True, is_open = False),
860 vaccine = vaccine,
861 batch_no = self._PRW_batch.GetValue().strip()
862 )
863
864 if self._CHBOX_anamnestic.GetValue() is True:
865 data['soap_cat'] = u's'
866 else:
867 data['soap_cat'] = u'p'
868
869 data['date_given'] = self._PRW_date_given.GetData()
870 data['site'] = self._PRW_site.GetValue().strip()
871 data['pk_provider'] = self._PRW_provider.GetData()
872 data['reaction'] = self._PRW_reaction.GetValue().strip()
873 data['comment'] = self._TCTRL_comment.GetValue().strip()
874
875 data.save()
876
877 return data
878 #----------------------------------------------------------------
880
881 if self._CHBOX_anamnestic.GetValue() is True:
882 self.data['soap_cat'] = u's'
883 else:
884 self.data['soap_cat'] = u'p'
885
886 self.data['date_given'] = self._PRW_date_given.GetData()
887 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
888 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
889 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
890 self.data['site'] = self._PRW_site.GetValue().strip()
891 self.data['pk_provider'] = self._PRW_provider.GetData()
892 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
893 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
894
895 self.data.save()
896
897 return True
898 #----------------------------------------------------------------
900 self._PRW_date_given.SetText(data = gmDateTime.pydt_now_here())
901 self._CHBOX_anamnestic.SetValue(False)
902 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
903 self._PRW_batch.unset_context(context = 'pk_vaccine')
904 self._PRW_batch.SetValue(u'')
905 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
906 self._PRW_site.SetValue(u'')
907 self._PRW_provider.SetData(data = None)
908 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
909 self._BTN_report.Enable(False)
910 self._TCTRL_comment.SetValue(u'')
911
912 self.__indications = []
913 self.__refresh_indications()
914 self._BTN_select_indications.Enable()
915
916 self._PRW_date_given.SetFocus()
917 #----------------------------------------------------------------
919 self._PRW_date_given.SetText(data = self.data['date_given'])
920 if self.data['soap_cat'] == u's':
921 self._CHBOX_anamnestic.SetValue(True)
922 else:
923 self._CHBOX_anamnestic.SetValue(False)
924 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
925
926 self._PRW_batch.SetValue(self.data['batch_no'])
927 self._PRW_episode.SetData(data = self.data['pk_episode'])
928 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
929 self._PRW_provider.SetData(self.data['pk_provider'])
930 self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], u''))
931 if self.data['reaction'] is None:
932 self._BTN_report.Enable(False)
933 else:
934 self._BTN_report.Enable(True)
935 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
936
937 self.__indications = self.data.vaccine.indications
938 self.__refresh_indications()
939 self._BTN_select_indications.Disable()
940
941 self._PRW_date_given.SetFocus()
942 #----------------------------------------------------------------
944 self._PRW_date_given.SetText(data = self.data['date_given'])
945 #self._CHBOX_anamnestic.SetValue(False)
946 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
947
948 self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine'])
949 self._PRW_batch.SetValue(u'')
950
951 self._PRW_episode.SetData(data = self.data['pk_episode'])
952 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
953 self._PRW_provider.SetData(self.data['pk_provider'])
954 self._PRW_reaction.SetValue(u'')
955 self._BTN_report.Enable(False)
956 self._TCTRL_comment.SetValue(u'')
957
958 self.__indications = self.data.vaccine.indications
959 self.__refresh_indications()
960 self._BTN_select_indications.Enable()
961
962 self._PRW_date_given.SetFocus()
963 #----------------------------------------------------------------
964 # event handlers
965 #----------------------------------------------------------------
983 #----------------------------------------------------------------
986 # FIXME: could set newly generated vaccine here
987 #----------------------------------------------------------------
1002
1003 #======================================================================
1004 #======================================================================
1005 #======================================================================
1006 #======================================================================
1008
1010 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
1011 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1012 self.__pat = gmPerson.gmCurrentPatient()
1013 # do this here so "import cImmunisationsPanel from gmVaccWidgets" works
1014 self.ID_VaccinatedIndicationsList = wx.NewId()
1015 self.ID_VaccinationsPerRegimeList = wx.NewId()
1016 self.ID_MissingShots = wx.NewId()
1017 self.ID_ActiveSchedules = wx.NewId()
1018 self.__do_layout()
1019 self.__register_interests()
1020 self.__reset_ui_content()
1021 #----------------------------------------------------
1023 #-----------------------------------------------
1024 # top part
1025 #-----------------------------------------------
1026 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
1027 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
1028
1029 #-----------------------------------------------
1030 # middle part
1031 #-----------------------------------------------
1032 # divider headings below editing area
1033 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
1034 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
1035 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
1036 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
1037 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
1038 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
1039 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
1040
1041 # left list: indications for which vaccinations have been given
1042 self.LBOX_vaccinated_indications = wx.ListBox(
1043 parent = self,
1044 id = self.ID_VaccinatedIndicationsList,
1045 choices = [],
1046 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1047 )
1048 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1049
1050 # right list: when an indication has been selected on the left
1051 # display the corresponding vaccinations on the right
1052 self.LBOX_given_shots = wx.ListBox(
1053 parent = self,
1054 id = self.ID_VaccinationsPerRegimeList,
1055 choices = [],
1056 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1057 )
1058 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1059
1060 self.LBOX_active_schedules = wx.ListBox (
1061 parent = self,
1062 id = self.ID_ActiveSchedules,
1063 choices = [],
1064 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1065 )
1066 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1067
1068 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1069 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1070 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1071 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1072
1073 #---------------------------------------------
1074 # bottom part
1075 #---------------------------------------------
1076 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1077 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1078 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1079
1080 self.LBOX_missing_shots = wx.ListBox (
1081 parent = self,
1082 id = self.ID_MissingShots,
1083 choices = [],
1084 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1085 )
1086 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1087
1088 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1089 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1090
1091 # alert caption
1092 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1093
1094 #---------------------------------------------
1095 # add all elements to the main background sizer
1096 #---------------------------------------------
1097 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1098 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1099 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1100 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1101 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1102 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1103 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1104 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1105
1106 self.SetAutoLayout(True)
1107 self.SetSizer(self.mainsizer)
1108 self.mainsizer.Fit(self)
1109 #----------------------------------------------------
1111 # wxPython events
1112 wx.EVT_SIZE(self, self.OnSize)
1113 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1114 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1115 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1116 # wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton)
1117
1118 # client internal signals
1119 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1120 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1121 #----------------------------------------------------
1122 # event handlers
1123 #----------------------------------------------------
1127 #----------------------------------------------------
1129 """Paste previously given shot into edit area.
1130 """
1131 self.editarea.set_data(aVacc=event.GetClientData())
1132 #----------------------------------------------------
1134 self.editarea.set_data(aVacc = event.GetClientData())
1135 #----------------------------------------------------
1137 """Update right hand middle list to show vaccinations given for selected indication."""
1138 ind_list = event.GetEventObject()
1139 selected_item = ind_list.GetSelection()
1140 ind = ind_list.GetClientData(selected_item)
1141 # clear list
1142 self.LBOX_given_shots.Set([])
1143 emr = self.__pat.get_emr()
1144 shots = emr.get_vaccinations(indications = [ind])
1145 # FIXME: use Set() for entire array (but problem with client_data)
1146 for shot in shots:
1147 if shot['is_booster']:
1148 marker = 'B'
1149 else:
1150 marker = '#%s' % shot['seq_no']
1151 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1152 self.LBOX_given_shots.Append(label, shot)
1153 #----------------------------------------------------
1155 # clear edit area
1156 self.editarea.set_data()
1157 # clear lists
1158 self.LBOX_vaccinated_indications.Clear()
1159 self.LBOX_given_shots.Clear()
1160 self.LBOX_active_schedules.Clear()
1161 self.LBOX_missing_shots.Clear()
1162 #----------------------------------------------------
1164 # clear lists
1165 self.LBOX_vaccinated_indications.Clear()
1166 self.LBOX_given_shots.Clear()
1167 self.LBOX_active_schedules.Clear()
1168 self.LBOX_missing_shots.Clear()
1169
1170 emr = self.__pat.get_emr()
1171
1172 t1 = time.time()
1173 # populate vaccinated-indications list
1174 # FIXME: consider adding virtual indication "most recent" to
1175 # FIXME: display most recent of all indications as suggested by Syan
1176 status, indications = emr.get_vaccinated_indications()
1177 # FIXME: would be faster to use Set() but can't
1178 # use Set(labels, client_data), and have to know
1179 # line position in SetClientData :-(
1180 for indication in indications:
1181 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1182 # self.LBOX_vaccinated_indications.Set(lines)
1183 # self.LBOX_vaccinated_indications.SetClientData(data)
1184 print "vaccinated indications took", time.time()-t1, "seconds"
1185
1186 t1 = time.time()
1187 # populate active schedules list
1188 scheds = emr.get_scheduled_vaccination_regimes()
1189 if scheds is None:
1190 label = _('ERROR: cannot retrieve active vaccination schedules')
1191 self.LBOX_active_schedules.Append(label)
1192 elif len(scheds) == 0:
1193 label = _('no active vaccination schedules')
1194 self.LBOX_active_schedules.Append(label)
1195 else:
1196 for sched in scheds:
1197 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1198 self.LBOX_active_schedules.Append(label)
1199 print "active schedules took", time.time()-t1, "seconds"
1200
1201 t1 = time.time()
1202 # populate missing-shots list
1203 missing_shots = emr.get_missing_vaccinations()
1204 print "getting missing shots took", time.time()-t1, "seconds"
1205 if missing_shots is None:
1206 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1207 self.LBOX_missing_shots.Append(label, None)
1208 return True
1209 # due
1210 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1211 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1212 for shot in missing_shots['due']:
1213 if shot['overdue']:
1214 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1215 weeks = days_left / 7
1216 # amount_overdue, seq_no, indication, regime, vacc_comment
1217 label = overdue_template % (
1218 years,
1219 weeks,
1220 shot['seq_no'],
1221 shot['l10n_indication'],
1222 shot['regime'],
1223 shot['vacc_comment']
1224 )
1225 self.LBOX_missing_shots.Append(label, shot)
1226 else:
1227 # time_left, seq_no, regime, latest_due, vacc_comment
1228 label = due_template % (
1229 shot['time_left'].days / 7,
1230 shot['seq_no'],
1231 shot['indication'],
1232 shot['regime'],
1233 shot['latest_due'].strftime('%m/%Y'),
1234 shot['vacc_comment']
1235 )
1236 self.LBOX_missing_shots.Append(label, shot)
1237 # booster
1238 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1239 for shot in missing_shots['boosters']:
1240 # indication, regime, vacc_comment
1241 label = lbl_template % (
1242 shot['l10n_indication'],
1243 shot['regime'],
1244 shot['vacc_comment']
1245 )
1246 self.LBOX_missing_shots.Append(label, shot)
1247 print "displaying missing shots took", time.time()-t1, "seconds"
1248
1249 return True
1250 #----------------------------------------------------
1253 # FIXME:
1254 # if has_focus:
1255 # wxCallAfter(self.__reset_ui_content)
1256 # else:
1257 # return 1
1258 #----------------------------------------------------
1261 # FIXME:
1262 # if has_focus:
1263 # wxCallAfter(self.__reset_ui_content)
1264 # else:
1265 # is_stale == True
1266 # return 1
1267 #======================================================================
1268 # main
1269 #----------------------------------------------------------------------
1270 if __name__ == "__main__":
1271
1272 if len(sys.argv) < 2:
1273 sys.exit()
1274
1275 if sys.argv[1] != u'test':
1276 sys.exit()
1277
1278 app = wx.PyWidgetTester(size = (600, 600))
1279 app.SetWidget(cATCPhraseWheel, -1)
1280 app.MainLoop()
1281
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Feb 1 03:56:44 2013 | http://epydoc.sourceforge.net |