| 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 __version__ = "$Revision: 1.36 $"
9 __author__ = "R.Terry, S.J.Tan, K.Hilbert"
10 __license__ = "GPL (details at http://www.gnu.org)"
11
12 import sys, time, logging, webbrowser
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
22 from Gnumed.business import gmPerson, gmVaccination, gmSurgery
23 from Gnumed.wxpython import gmPhraseWheel, gmTerryGuiParts, gmRegetMixin, gmGuiHelpers
24 from Gnumed.wxpython import gmEditArea, gmListWidgets
25
26
27 _log = logging.getLogger('gm.vaccination')
28 _log.info(__version__)
29
30 #======================================================================
31 # vaccination indication related widgets
32 #----------------------------------------------------------------------
34
35 if parent is None:
36 parent = wx.GetApp().GetTopWindow()
37 #------------------------------------------------------------
38 def refresh(lctrl):
39 inds = gmVaccination.get_indications(order_by = 'description')
40
41 items = [ [
42 i['description'],
43 gmTools.coalesce (
44 i['atcs_single_indication'],
45 u'',
46 u'%s'
47 ),
48 gmTools.coalesce (
49 i['atcs_combi_indication'],
50 u'',
51 u'%s'
52 ),
53 u'%s' % i['id']
54 ] for i in inds ]
55
56 lctrl.set_string_items(items)
57 lctrl.set_data(inds)
58 #------------------------------------------------------------
59 gmListWidgets.get_choices_from_list (
60 parent = parent,
61 msg = _('\nConditions preventable by vaccination as currently known to GNUmed.\n'),
62 caption = _('Showing vaccination preventable conditions.'),
63 columns = [ _('Condition'), _('ATCs: single-condition vaccines'), _('ATCs: multi-condition vaccines'), u'#' ],
64 single_selection = True,
65 refresh_callback = refresh
66 )
67 #----------------------------------------------------------------------
68 from Gnumed.wxGladeWidgets import wxgVaccinationIndicationsPnl
69
71
73
74 wxgVaccinationIndicationsPnl.wxgVaccinationIndicationsPnl.__init__(self, *args, **kwargs)
75
76 self.__indication2field = {
77 u'coxiella burnetii (Q fever)': self._CHBOX_coxq,
78 u'salmonella typhi (typhoid)': self._CHBOX_typhoid,
79 u'varicella (chickenpox, shingles)': self._CHBOX_varicella,
80 u'influenza (seasonal)': self._CHBOX_influenza,
81 u'bacillus anthracis (Anthrax)': self._CHBOX_anthrax,
82 u'human papillomavirus': self._CHBOX_hpv,
83 u'rotavirus': self._CHBOX_rota,
84 u'tuberculosis': self._CHBOX_tuberculosis,
85 u'variola virus (smallpox)': self._CHBOX_smallpox,
86 u'influenza (H1N1)': self._CHBOX_h1n1,
87 u'cholera': self._CHBOX_cholera,
88 u'diphtheria': self._CHBOX_diphtheria,
89 u'haemophilus influenzae b': self._CHBOX_hib,
90 u'hepatitis A': self._CHBOX_hepA,
91 u'hepatitis B': self._CHBOX_hepB,
92 u'japanese B encephalitis': self._CHBOX_japanese,
93 u'measles': self._CHBOX_measles,
94 u'meningococcus A': self._CHBOX_menA,
95 u'meningococcus C': self._CHBOX_menC,
96 u'meningococcus W': self._CHBOX_menW,
97 u'meningococcus Y': self._CHBOX_menY,
98 u'mumps': self._CHBOX_mumps,
99 u'pertussis': self._CHBOX_pertussis,
100 u'pneumococcus': self._CHBOX_pneumococcus,
101 u'poliomyelitis': self._CHBOX_polio,
102 u'rabies': self._CHBOX_rabies,
103 u'rubella': self._CHBOX_rubella,
104 u'tetanus': self._CHBOX_tetanus,
105 u'tick-borne meningoencephalitis': self._CHBOX_fsme,
106 u'yellow fever': self._CHBOX_yellow_fever,
107 u'yersinia pestis': self._CHBOX_yersinia_pestis
108 }
109 #------------------------------------------------------------------
111 for field in self.__dict__.keys():
112 if field.startswith('_CHBOX_'):
113 self.__dict__[field].Enable()
114 self.Enable()
115 #------------------------------------------------------------------
117 for field in self.__dict__.keys():
118 if field.startswith('_CHBOX_'):
119 self.__dict__[field].Disable()
120 self.Disable()
121 #------------------------------------------------------------------
123 for field in self.__dict__.keys():
124 if field.startswith('_CHBOX_'):
125 self.__dict__[field].SetValue(False)
126 #------------------------------------------------------------------
130 #------------------------------------------------------------------
132 indications = []
133 for indication in self.__indication2field.keys():
134 if self.__indication2field[indication].IsChecked():
135 indications.append(indication)
136 return indications
137
138 selected_indications = property(_get_selected_indications, lambda x:x)
139 #------------------------------------------------------------------
141 for indication in self.__indication2field.keys():
142 if self.__indication2field[indication].IsChecked():
143 return True
144 return False
145
146 has_selection = property(_get_has_selection, lambda x:x)
147
148 #======================================================================
149 # vaccines related widgets
150 #----------------------------------------------------------------------
152 ea = cVaccineEAPnl(parent = parent, id = -1)
153 ea.data = vaccine
154 ea.mode = gmTools.coalesce(vaccine, 'new', 'edit')
155 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
156 dlg.SetTitle(gmTools.coalesce(vaccine, _('Adding new vaccine'), _('Editing vaccine')))
157 if dlg.ShowModal() == wx.ID_OK:
158 dlg.Destroy()
159 return True
160 dlg.Destroy()
161 return False
162 #----------------------------------------------------------------------
164
165 if parent is None:
166 parent = wx.GetApp().GetTopWindow()
167 #------------------------------------------------------------
168 def delete(vaccine=None):
169 deleted = gmVaccination.delete_vaccine(vaccine = vaccine['pk_vaccine'])
170 if deleted:
171 return True
172
173 gmGuiHelpers.gm_show_info (
174 _(
175 'Cannot delete vaccine\n'
176 '\n'
177 ' %s - %s (#%s)\n'
178 '\n'
179 'It is probably documented in a vaccination.'
180 ) % (
181 vaccine['vaccine'],
182 vaccine['preparation'],
183 vaccine['pk_vaccine']
184 ),
185 _('Deleting vaccine')
186 )
187
188 return False
189 #------------------------------------------------------------
190 def edit(vaccine=None):
191 return edit_vaccine(parent = parent, vaccine = vaccine, single_entry = True)
192 #------------------------------------------------------------
193 def refresh(lctrl):
194 vaccines = gmVaccination.get_vaccines(order_by = 'vaccine')
195
196 items = [ [
197 u'%s' % v['pk_brand'],
198 u'%s%s' % (
199 v['vaccine'],
200 gmTools.bool2subst (
201 v['is_fake_vaccine'],
202 u' (%s)' % _('fake'),
203 u''
204 )
205 ),
206 v['preparation'],
207 u'%s (%s)' % (v['route_abbreviation'], v['route_description']),
208 gmTools.bool2subst(v['is_live'], gmTools.u_checkmark_thin, u''),
209 gmTools.coalesce(v['atc_code'], u''),
210 u'%s%s' % (
211 gmTools.coalesce(v['min_age'], u'?'),
212 gmTools.coalesce(v['max_age'], u'?', u' - %s'),
213 ),
214 gmTools.coalesce(v['comment'], u'')
215 ] for v in vaccines ]
216 lctrl.set_string_items(items)
217 lctrl.set_data(vaccines)
218 #------------------------------------------------------------
219 gmListWidgets.get_choices_from_list (
220 parent = parent,
221 msg = _('\nThe vaccines currently known to GNUmed.\n'),
222 caption = _('Showing vaccines.'),
223 columns = [ u'#', _('Brand'), _('Preparation'), _(u'Route'), _('Live'), _('ATC'), _('Age range'), _('Comment') ],
224 single_selection = True,
225 refresh_callback = refresh,
226 edit_callback = edit,
227 new_callback = edit,
228 delete_callback = delete
229 )
230 #----------------------------------------------------------------------
232
234
235 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
236
237 context = {
238 u'ctxt_vaccine': {
239 u'where_part': u'AND pk_vaccine = %(pk_vaccine)s',
240 u'placeholder': u'pk_vaccine'
241 }
242 }
243
244 query = u"""
245 SELECT code, batch_no FROM (
246
247 SELECT distinct on (batch_no) code, batch_no, rank FROM (
248
249 (
250 -- batch_no by vaccine
251 SELECT
252 batch_no AS code,
253 batch_no,
254 1 AS rank
255 FROM
256 clin.v_pat_vaccinations
257 WHERE
258 batch_no %(fragment_condition)s
259 %(ctxt_vaccine)s
260 ) UNION ALL (
261 -- batch_no for any vaccine
262 SELECT
263 batch_no AS code,
264 batch_no,
265 2 AS rank
266 FROM
267 clin.v_pat_vaccinations
268 WHERE
269 batch_no %(fragment_condition)s
270 )
271
272 ) AS matching_batch_nos
273
274 ) as unique_matches
275
276 ORDER BY rank, batch_no
277 LIMIT 25
278 """
279 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
280 mp.setThresholds(1, 2, 3)
281 self.matcher = mp
282
283 self.unset_context(context = u'pk_vaccine')
284 self.SetToolTipString(_('Enter or select the batch/lot number of the vaccine used.'))
285 self.selection_only = False
286 #----------------------------------------------------------------------
288
290
291 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
292
293 # consider ATCs in ref.branded_drug and vacc_indication
294 query = u"""
295 SELECT pk_vaccine, description FROM (
296
297 SELECT DISTINCT ON (pk_vaccine) pk_vaccine, description FROM (
298
299 (
300 -- fragment -> vaccine
301 SELECT
302 pk_vaccine,
303 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')'
304 AS description
305 FROM
306 clin.v_vaccines
307 WHERE
308 vaccine %(fragment_condition)s
309
310 ) union all (
311
312 -- fragment -> localized indication -> vaccines
313 SELECT
314 pk_vaccine,
315 vaccine || ' (' || array_to_string(l10n_indications, ', ') || ')'
316 AS description
317 FROM
318 clin.v_indications4vaccine
319 WHERE
320 l10n_indication %(fragment_condition)s
321
322 ) union all (
323
324 -- fragment -> indication -> vaccines
325 SELECT
326 pk_vaccine,
327 vaccine || ' (' || array_to_string(indications, ', ') || ')'
328 AS description
329 FROM
330 clin.v_indications4vaccine
331 WHERE
332 indication %(fragment_condition)s
333 )
334 ) AS distinct_total
335
336 ) AS total
337
338 ORDER by description
339 LIMIT 25
340 """
341 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
342 mp.setThresholds(1, 2, 3)
343 self.matcher = mp
344
345 self.selection_only = True
346 #------------------------------------------------------------------
349 #----------------------------------------------------------------------
350 from Gnumed.wxGladeWidgets import wxgVaccineEAPnl
351
353
355
356 try:
357 data = kwargs['vaccine']
358 del kwargs['vaccine']
359 except KeyError:
360 data = None
361
362 wxgVaccineEAPnl.wxgVaccineEAPnl.__init__(self, *args, **kwargs)
363 gmEditArea.cGenericEditAreaMixin.__init__(self)
364
365 self.mode = 'new'
366 self.data = data
367 if data is not None:
368 self.mode = 'edit'
369
370 self.__init_ui()
371 #----------------------------------------------------------------
373
374 # route
375 query = u"""
376 SELECT DISTINCT ON (abbreviation)
377 id,
378 abbreviation || ' (' || _(description) || ')'
379 FROM
380 clin.vacc_route
381 WHERE
382 abbreviation %(fragment_condition)s
383 OR
384 description %(fragment_condition)s
385 ORDER BY
386 abbreviation
387 """
388 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query)
389 mp.setThresholds(1, 2, 3)
390 self._PRW_route.matcher = mp
391 self._PRW_route.selection_only = True
392
393 #self._PRW_age_min = gmPhraseWheel.cPhraseWheel(self, -1, "", style=wx.NO_BORDER)
394 #self._PRW_age_max = gmPhraseWheel.cPhraseWheel(self, -1, "", style=wx.NO_BORDER)
395
396 self.Layout()
397 self.Fit()
398 #----------------------------------------------------------------
399 # generic Edit Area mixin API
400 #----------------------------------------------------------------
402
403 has_errors = False
404
405 if self._PRW_brand.GetValue().strip() == u'':
406 has_errors = True
407 self._PRW_brand.display_as_valid(False)
408 else:
409 self._PRW_brand.display_as_valid(True)
410
411 if self._PRW_route.GetData() is None:
412 has_errors = True
413 self._PRW_route.display_as_valid(False)
414 else:
415 self._PRW_route.display_as_valid(True)
416
417 if not self._PNL_indications.has_selection:
418 has_errors = True
419
420 if self._PRW_atc.GetValue().strip() in [u'', u'J07']:
421 self._PRW_atc.display_as_valid(True)
422 else:
423 if self._PRW_atc.GetData() is None:
424 self._PRW_atc.display_as_valid(True)
425 else:
426 has_errors = True
427 self._PRW_atc.display_as_valid(False)
428
429 val = self._PRW_age_min.GetValue().strip()
430 if val == u'':
431 self._PRW_age_min.display_as_valid(True)
432 else:
433 if gmDateTime.str2interval(val) is None:
434 has_errors = True
435 self._PRW_age_min.display_as_valid(False)
436 else:
437 self._PRW_age_min.display_as_valid(True)
438
439 val = self._PRW_age_max.GetValue().strip()
440 if val == u'':
441 self._PRW_age_max.display_as_valid(True)
442 else:
443 if gmDateTime.str2interval(val) is None:
444 has_errors = True
445 self._PRW_age_max.display_as_valid(False)
446 else:
447 self._PRW_age_max.display_as_valid(True)
448
449 # are we editing ?
450 ask_user = (self.mode == 'edit')
451 # is this vaccine in use ?
452 ask_user = (ask_user and self.data.is_in_use)
453 # a change ...
454 ask_user = ask_user and (
455 # ... of brand ...
456 (self.data['pk_brand'] != self._PRW_route.GetData())
457 or
458 # ... or indications ?
459 (self.data['indications'] != self._PNL_indications.selected_indications)
460 )
461
462 if ask_user:
463 do_it = gmGuiHelpers.gm_show_question (
464 aTitle = _('Saving vaccine'),
465 aMessage = _(
466 u'This vaccine is already in use:\n'
467 u'\n'
468 u' "%s"\n'
469 u' (%s)\n'
470 u'\n'
471 u'Are you absolutely positively sure that\n'
472 u'you really want to edit this vaccine ?\n'
473 '\n'
474 u'This will change the vaccine name and/or target\n'
475 u'conditions in each patient this vaccine was\n'
476 u'used in to document a vaccination with.\n'
477 ) % (
478 self._PRW_brand.GetValue().strip(),
479 u', '.join(self.data['l10n_indications'])
480 )
481 )
482 if not do_it:
483 has_errors = True
484
485 return (has_errors is False)
486 #----------------------------------------------------------------
488 # save the data as a new instance
489 data = gmVaccination.create_vaccine (
490 pk_brand = self._PRW_brand.GetData(),
491 brand_name = self._PRW_brand.GetValue(),
492 indications = self._PNL_indications.selected_indications
493 )
494
495 data['pk_route'] = self._PRW_route.GetData()
496 data['is_live'] = self._CHBOX_live.GetValue()
497 val = self._PRW_age_min.GetValue().strip()
498 if val != u'':
499 data['min_age'] = gmDateTime.str2interval(val)
500 val = self._PRW_age_max.GetValue().strip()
501 if val != u'':
502 data['max_age'] = gmDateTime.str2interval(val)
503 val = self._TCTRL_comment.GetValue().strip()
504 if val != u'':
505 data['comment'] = val
506
507 data.save()
508
509 drug = data.brand
510 drug['is_fake'] = self._CHBOX_fake.GetValue()
511 val = self._PRW_atc.GetData()
512 if val is not None:
513 if val != u'J07':
514 drug['atc_code'] = val.strip()
515 drug.save()
516
517 # must be done very late or else the property access
518 # will refresh the display such that later field
519 # access will return empty values
520 self.data = data
521
522 return True
523 #----------------------------------------------------------------
525
526 drug = self.data.brand
527 drug['description'] = self._PRW_brand.GetValue().strip()
528 drug['is_fake'] = self._CHBOX_fake.GetValue()
529 val = self._PRW_atc.GetData()
530 if val is not None:
531 if val != u'J07':
532 drug['atc_code'] = val.strip()
533 drug.save()
534
535 # the validator already asked for changes so just do it
536 self.data.set_indications(indications = self._PNL_indications.selected_indications)
537
538 self.data['pk_route'] = self._PRW_route.GetData()
539 self.data['is_live'] = self._CHBOX_live.GetValue()
540 val = self._PRW_age_min.GetValue().strip()
541 if val != u'':
542 self.data['min_age'] = gmDateTime.str2interval(val)
543 if val != u'':
544 self.data['max_age'] = gmDateTime.str2interval(val)
545 val = self._TCTRL_comment.GetValue().strip()
546 if val != u'':
547 self.data['comment'] = val
548
549 self.data.save()
550 return True
551 #----------------------------------------------------------------
553 self._PRW_brand.SetText(value = u'', data = None, suppress_smarts = True)
554 self._PRW_route.SetText(value = u'intramuscular')
555 self._CHBOX_live.SetValue(False)
556 self._CHBOX_fake.SetValue(False)
557 self._PNL_indications.clear_all()
558 self._PRW_atc.SetText(value = u'', data = None, suppress_smarts = True)
559 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
560 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
561 self._TCTRL_comment.SetValue(u'')
562
563 self._PRW_brand.SetFocus()
564 #----------------------------------------------------------------
566 self._PRW_brand.SetText(value = self.data['vaccine'], data = self.data['pk_brand'])
567 self._PRW_route.SetText(value = self.data['route_description'], data = self.data['pk_route'])
568 self._CHBOX_live.SetValue(self.data['is_live'])
569 self._CHBOX_fake.SetValue(self.data['is_fake_vaccine'])
570 self._PNL_indications.select(self.data['indications'])
571 self._PRW_atc.SetText(value = self.data['atc_code'], data = self.data['atc_code'])
572 if self.data['min_age'] is None:
573 self._PRW_age_min.SetText(value = u'', data = None, suppress_smarts = True)
574 else:
575 self._PRW_age_min.SetText (
576 value = gmDateTime.format_interval(self.data['min_age'], gmDateTime.acc_years),
577 data = self.data['min_age']
578 )
579 if self.data['max_age'] is None:
580 self._PRW_age_max.SetText(value = u'', data = None, suppress_smarts = True)
581 else:
582 self._PRW_age_max.SetText (
583 value = gmDateTime.format_interval(self.data['max_age'], gmDateTime.acc_years),
584 data = self.data['max_age']
585 )
586 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
587
588 self._PRW_brand.SetFocus()
589 #----------------------------------------------------------------
592 #======================================================================
593 # vaccination related widgets
594 #----------------------------------------------------------------------
596 ea = cVaccinationEAPnl(parent = parent, id = -1)
597 ea.data = vaccination
598 ea.mode = gmTools.coalesce(vaccination, 'new', 'edit')
599 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
600 dlg.SetTitle(gmTools.coalesce(vaccination, _('Adding new vaccination'), _('Editing vaccination')))
601 if dlg.ShowModal() == wx.ID_OK:
602 dlg.Destroy()
603 return True
604 dlg.Destroy()
605 return False
606 #----------------------------------------------------------------------
608
609 pat = gmPerson.gmCurrentPatient()
610 emr = pat.get_emr()
611
612 if parent is None:
613 parent = wx.GetApp().GetTopWindow()
614 #------------------------------------------------------------
615 def browse2schedules(vaccination=None):
616 dbcfg = gmCfg.cCfgSQL()
617 url = dbcfg.get2 (
618 option = 'external.urls.vaccination_plans',
619 workplace = gmSurgery.gmCurrentPractice().active_workplace,
620 bias = 'user',
621 default = u'http://www.bundesaerztekammer.de/downloads/ImpfempfehlungenRKI2009.pdf'
622 )
623
624 webbrowser.open (
625 url = url,
626 new = False,
627 autoraise = True
628 )
629 return False
630 #------------------------------------------------------------
631 def edit(vaccination=None):
632 return edit_vaccination(parent = parent, vaccination = vaccination, single_entry = True)
633 #------------------------------------------------------------
634 def delete(vaccination=None):
635 gmVaccination.delete_vaccination(vaccination = vaccination['pk_vaccination'])
636 return True
637 #------------------------------------------------------------
638 def refresh(lctrl):
639
640 vaccs = emr.get_vaccinations(order_by = 'date_given DESC, pk_vaccination')
641
642 items = [ [
643 v['date_given'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
644 v['vaccine'],
645 u', '.join(v['l10n_indications']),
646 v['batch_no'],
647 gmTools.coalesce(v['site'], u''),
648 gmTools.coalesce(v['reaction'], u''),
649 gmTools.coalesce(v['comment'], u'')
650 ] for v in vaccs ]
651
652 lctrl.set_string_items(items)
653 lctrl.set_data(vaccs)
654 #------------------------------------------------------------
655 gmListWidgets.get_choices_from_list (
656 parent = parent,
657 msg = _('\nComplete vaccination history for this patient.\n'),
658 caption = _('Showing vaccinations.'),
659 columns = [ _('Date'), _('Vaccine'), _(u'Intended to protect from'), _('Batch'), _('Site'), _('Reaction'), _('Comment') ],
660 single_selection = True,
661 refresh_callback = refresh,
662 new_callback = edit,
663 edit_callback = edit,
664 delete_callback = delete,
665 left_extra_button = (_('Vaccination Plans'), _('Open a browser showing vaccination schedules.'), browse2schedules)
666 )
667 #----------------------------------------------------------------------
668 from Gnumed.wxGladeWidgets import wxgVaccinationEAPnl
669
670 -class cVaccinationEAPnl(wxgVaccinationEAPnl.wxgVaccinationEAPnl, gmEditArea.cGenericEditAreaMixin):
671 """
672 - warn on apparent duplicates
673 - ask if "missing" (= previous, non-recorded) vaccinations
674 should be estimated and saved (add note "auto-generated")
675
676 Batch No (http://www.fao.org/docrep/003/v9952E12.htm)
677 """
679
680 try:
681 data = kwargs['vaccination']
682 del kwargs['vaccination']
683 except KeyError:
684 data = None
685
686 wxgVaccinationEAPnl.wxgVaccinationEAPnl.__init__(self, *args, **kwargs)
687 gmEditArea.cGenericEditAreaMixin.__init__(self)
688
689 self.mode = 'new'
690 self.data = data
691 if data is not None:
692 self.mode = 'edit'
693
694 self.__init_ui()
695 #----------------------------------------------------------------
697 # adjust phrasewheels etc
698 self._PRW_vaccine.add_callback_on_lose_focus(self._on_PRW_vaccine_lost_focus)
699 self._PRW_provider.selection_only = False
700 # self._PRW_batch.unset_context(context = 'pk_vaccine') # done in PRW init()
701 self._PRW_reaction.add_callback_on_lose_focus(self._on_PRW_reaction_lost_focus)
702 #----------------------------------------------------------------
704
705 vaccine = self._PRW_vaccine.GetData(as_instance=True)
706
707 # if we are editing we do not allow using indications rather than a vaccine
708 if self.mode == u'edit':
709 self._PNL_indications.clear_all()
710 if vaccine is None:
711 self._PRW_batch.unset_context(context = 'pk_vaccine')
712 else:
713 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
714 self._PNL_indications.select(indications = vaccine['indications'])
715 self._PNL_indications.disable_all()
716
717 # we are entering a new vaccination
718 else:
719 if vaccine is None:
720 self._PRW_batch.unset_context(context = 'pk_vaccine')
721 self._PNL_indications.enable_all()
722 else:
723 self._PRW_batch.set_context(context = 'pk_vaccine', val = vaccine['pk_vaccine'])
724 self._PNL_indications.clear_all()
725 self._PNL_indications.select(indications = vaccine['indications'])
726 self._PNL_indications.disable_all()
727 #----------------------------------------------------------------
729 if self._PRW_reaction.GetValue().strip() == u'':
730 self._BTN_report.Enable(False)
731 else:
732 self._BTN_report.Enable(True)
733 #----------------------------------------------------------------
734 # generic Edit Area mixin API
735 #----------------------------------------------------------------
737
738 has_errors = False
739
740 if not self._DP_date_given.is_valid_timestamp(allow_none = False):
741 has_errors = True
742
743 vaccine = self._PRW_vaccine.GetData(as_instance = True)
744
745 # we are editing, require vaccine rather than indications
746 if self.mode == u'edit':
747 if vaccine is None:
748 has_errors = True
749 self._PRW_vaccine.display_as_valid(False)
750 else:
751 self._PRW_vaccine.display_as_valid(True)
752 self._PNL_indications.clear_all()
753 self._PNL_indications.select(indications = vaccine['indications'])
754 self._PNL_indications.disable_all()
755 # we are creating, allow either vaccine or indications
756 else:
757 if vaccine is None:
758 if self._PNL_indications.has_selection:
759 self._PRW_vaccine.display_as_valid(True)
760 else:
761 has_errors = True
762 self._PRW_vaccine.display_as_valid(False)
763 else:
764 self._PRW_vaccine.display_as_valid(True)
765
766 if self._PRW_batch.GetValue().strip() == u'':
767 has_errors = True
768 self._PRW_batch.display_as_valid(False)
769 else:
770 self._PRW_batch.display_as_valid(True)
771
772 if self._PRW_episode.GetValue().strip() == u'':
773 self._PRW_episode.SetText(value = _('prevention'))
774
775 return (has_errors is False)
776 #----------------------------------------------------------------
778
779 vaccine = self._PRW_vaccine.GetData()
780 if vaccine is None:
781 data = self.__save_new_from_indications()
782 else:
783 data = self.__save_new_from_vaccine(vaccine = vaccine)
784
785 # must be done very late or else the property access
786 # will refresh the display such that later field
787 # access will return empty values
788 self.data = data
789
790 return True
791 #----------------------------------------------------------------
793
794 inds = self._PNL_indications.selected_indications
795 vaccine = gmVaccination.map_indications2generic_vaccine(indications = inds)
796
797 if vaccine is None:
798 for ind in inds:
799 vaccine = gmVaccination.map_indications2generic_vaccine(indications = [ind])
800 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
801 else:
802 data = self.__save_new_from_vaccine(vaccine = vaccine['pk_vaccine'])
803
804 return data
805 #----------------------------------------------------------------
807
808 emr = gmPerson.gmCurrentPatient().get_emr()
809
810 data = emr.add_vaccination (
811 episode = self._PRW_episode.GetData(can_create = True, is_open = False),
812 vaccine = vaccine,
813 batch_no = self._PRW_batch.GetValue().strip()
814 )
815
816 if self._CHBOX_anamnestic.GetValue() is True:
817 data['soap_cat'] = u's'
818 else:
819 data['soap_cat'] = u'p'
820
821 data['date_given'] = self._DP_date_given.get_pydt()
822 data['site'] = self._PRW_site.GetValue().strip()
823 data['pk_provider'] = self._PRW_provider.GetData()
824 data['reaction'] = self._PRW_reaction.GetValue().strip()
825 data['comment'] = self._TCTRL_comment.GetValue().strip()
826
827 data.save()
828
829 return data
830 #----------------------------------------------------------------
832
833 if self._CHBOX_anamnestic.GetValue() is True:
834 self.data['soap_cat'] = u's'
835 else:
836 self.data['soap_cat'] = u'p'
837
838 self.data['date_given'] = self._DP_date_given.get_pydt()
839 self.data['pk_vaccine'] = self._PRW_vaccine.GetData()
840 self.data['batch_no'] = self._PRW_batch.GetValue().strip()
841 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True, is_open = False)
842 self.data['site'] = self._PRW_site.GetValue().strip()
843 self.data['pk_provider'] = self._PRW_provider.GetData()
844 self.data['reaction'] = self._PRW_reaction.GetValue().strip()
845 self.data['comment'] = self._TCTRL_comment.GetValue().strip()
846
847 self.data.save()
848
849 return True
850 #----------------------------------------------------------------
852 self._DP_date_given.SetValue(gmDateTime.pydt_now_here())
853 self._CHBOX_anamnestic.SetValue(True)
854 self._PRW_vaccine.SetText(value = u'', data = None, suppress_smarts = True)
855
856 self._PNL_indications.clear_all()
857 self._PRW_batch.unset_context(context = 'pk_vaccine')
858 self._PRW_batch.SetValue(u'')
859
860 self._PRW_episode.SetText(value = u'', data = None, suppress_smarts = True)
861 self._PRW_site.SetValue(u'')
862 self._PRW_provider.SetData(data = None)
863 self._PRW_reaction.SetText(value = u'', data = None, suppress_smarts = True)
864 self._BTN_report.Enable(False)
865 self._TCTRL_comment.SetValue(u'')
866
867 self._DP_date_given.SetFocus()
868 #----------------------------------------------------------------
870 self._DP_date_given.SetValue(self.data['date_given'])
871 if self.data['soap_cat'] == u's':
872 self._CHBOX_anamnestic.SetValue(True)
873 else:
874 self._CHBOX_anamnestic.SetValue(False)
875 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
876
877 self._PNL_indications.clear_all()
878 self._PNL_indications.select(indications = self.data['indications'])
879 self._PNL_indications.disable_all()
880
881 self._PRW_batch.SetValue(self.data['batch_no'])
882 self._PRW_episode.SetData(data = self.data['pk_episode'])
883 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
884 self._PRW_provider.SetData(self.data['pk_provider'])
885 self._PRW_reaction.SetValue(gmTools.coalesce(self.data['reaction'], u''))
886 if self.data['reaction'] is None:
887 self._BTN_report.Enable(False)
888 else:
889 self._BTN_report.Enable(True)
890 self._TCTRL_comment.SetValue(gmTools.coalesce(self.data['comment'], u''))
891
892 self._DP_date_given.SetFocus()
893 #----------------------------------------------------------------
895 self._DP_date_given.SetValue(gmDateTime.pydt_now_here())
896 self._CHBOX_anamnestic.SetValue(True)
897 self._PRW_vaccine.SetText(value = self.data['vaccine'], data = self.data['pk_vaccine'])
898
899 self._PNL_indications.clear_all()
900 self._PNL_indications.select(indications = self.data['indications'])
901 self._PNL_indications.disable_all()
902
903 self._PRW_batch.set_context(context = 'pk_vaccine', val = self.data['pk_vaccine'])
904 self._PRW_batch.SetValue(u'')
905
906 self._PRW_episode.SetData(data = self.data['pk_episode'])
907 self._PRW_site.SetValue(gmTools.coalesce(self.data['site'], u''))
908 self._PRW_provider.SetData(self.data['pk_provider'])
909 self._PRW_reaction.SetValue(u'')
910 self._BTN_report.Enable(False)
911 self._TCTRL_comment.SetValue(u'')
912
913 self._DP_date_given.SetFocus()
914 #----------------------------------------------------------------
915 # event handlers
916 #----------------------------------------------------------------
938 #----------------------------------------------------------------
941 # FIXME: could set newly generated vaccine here
942 #======================================================================
943 #======================================================================
945
947 wx.Panel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, wx.RAISED_BORDER)
948 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
949 self.__pat = gmPerson.gmCurrentPatient()
950 # do this here so "import cImmunisationsPanel from gmVaccWidgets" works
951 self.ID_VaccinatedIndicationsList = wx.NewId()
952 self.ID_VaccinationsPerRegimeList = wx.NewId()
953 self.ID_MissingShots = wx.NewId()
954 self.ID_ActiveSchedules = wx.NewId()
955 self.__do_layout()
956 self.__register_interests()
957 self.__reset_ui_content()
958 #----------------------------------------------------
960 #-----------------------------------------------
961 # top part
962 #-----------------------------------------------
963 pnl_UpperCaption = gmTerryGuiParts.cHeadingCaption(self, -1, _(" IMMUNISATIONS "))
964 self.editarea = cVaccinationEditArea(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.NO_BORDER)
965
966 #-----------------------------------------------
967 # middle part
968 #-----------------------------------------------
969 # divider headings below editing area
970 indications_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Indications"))
971 vaccinations_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Vaccinations"))
972 schedules_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Active Schedules"))
973 szr_MiddleCap = wx.BoxSizer(wx.HORIZONTAL)
974 szr_MiddleCap.Add(indications_heading, 4, wx.EXPAND)
975 szr_MiddleCap.Add(vaccinations_heading, 6, wx.EXPAND)
976 szr_MiddleCap.Add(schedules_heading, 10, wx.EXPAND)
977
978 # left list: indications for which vaccinations have been given
979 self.LBOX_vaccinated_indications = wx.ListBox(
980 parent = self,
981 id = self.ID_VaccinatedIndicationsList,
982 choices = [],
983 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
984 )
985 self.LBOX_vaccinated_indications.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
986
987 # right list: when an indication has been selected on the left
988 # display the corresponding vaccinations on the right
989 self.LBOX_given_shots = wx.ListBox(
990 parent = self,
991 id = self.ID_VaccinationsPerRegimeList,
992 choices = [],
993 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
994 )
995 self.LBOX_given_shots.SetFont(wx.Font(12,wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
996
997 self.LBOX_active_schedules = wx.ListBox (
998 parent = self,
999 id = self.ID_ActiveSchedules,
1000 choices = [],
1001 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1002 )
1003 self.LBOX_active_schedules.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1004
1005 szr_MiddleLists = wx.BoxSizer(wx.HORIZONTAL)
1006 szr_MiddleLists.Add(self.LBOX_vaccinated_indications, 4, wx.EXPAND)
1007 szr_MiddleLists.Add(self.LBOX_given_shots, 6, wx.EXPAND)
1008 szr_MiddleLists.Add(self.LBOX_active_schedules, 10, wx.EXPAND)
1009
1010 #---------------------------------------------
1011 # bottom part
1012 #---------------------------------------------
1013 missing_heading = gmTerryGuiParts.cDividerCaption(self, -1, _("Missing Immunisations"))
1014 szr_BottomCap = wx.BoxSizer(wx.HORIZONTAL)
1015 szr_BottomCap.Add(missing_heading, 1, wx.EXPAND)
1016
1017 self.LBOX_missing_shots = wx.ListBox (
1018 parent = self,
1019 id = self.ID_MissingShots,
1020 choices = [],
1021 style = wx.LB_HSCROLL | wx.LB_NEEDED_SB | wx.SUNKEN_BORDER
1022 )
1023 self.LBOX_missing_shots.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.NORMAL, False, ''))
1024
1025 szr_BottomLists = wx.BoxSizer(wx.HORIZONTAL)
1026 szr_BottomLists.Add(self.LBOX_missing_shots, 1, wx.EXPAND)
1027
1028 # alert caption
1029 pnl_AlertCaption = gmTerryGuiParts.cAlertCaption(self, -1, _(' Alerts '))
1030
1031 #---------------------------------------------
1032 # add all elements to the main background sizer
1033 #---------------------------------------------
1034 self.mainsizer = wx.BoxSizer(wx.VERTICAL)
1035 self.mainsizer.Add(pnl_UpperCaption, 0, wx.EXPAND)
1036 self.mainsizer.Add(self.editarea, 6, wx.EXPAND)
1037 self.mainsizer.Add(szr_MiddleCap, 0, wx.EXPAND)
1038 self.mainsizer.Add(szr_MiddleLists, 4, wx.EXPAND)
1039 self.mainsizer.Add(szr_BottomCap, 0, wx.EXPAND)
1040 self.mainsizer.Add(szr_BottomLists, 4, wx.EXPAND)
1041 self.mainsizer.Add(pnl_AlertCaption, 0, wx.EXPAND)
1042
1043 self.SetAutoLayout(True)
1044 self.SetSizer(self.mainsizer)
1045 self.mainsizer.Fit(self)
1046 #----------------------------------------------------
1048 # wxPython events
1049 wx.EVT_SIZE(self, self.OnSize)
1050 wx.EVT_LISTBOX(self, self.ID_VaccinatedIndicationsList, self._on_vaccinated_indication_selected)
1051 wx.EVT_LISTBOX_DCLICK(self, self.ID_VaccinationsPerRegimeList, self._on_given_shot_selected)
1052 wx.EVT_LISTBOX_DCLICK(self, self.ID_MissingShots, self._on_missing_shot_selected)
1053 # wx.EVT_RIGHT_UP(self.lb1, self.EvtRightButton)
1054
1055 # client internal signals
1056 gmDispatcher.connect(signal= u'post_patient_selection', receiver=self._schedule_data_reget)
1057 gmDispatcher.connect(signal= u'vaccinations_updated', receiver=self._schedule_data_reget)
1058 #----------------------------------------------------
1059 # event handlers
1060 #----------------------------------------------------
1064 #----------------------------------------------------
1066 """Paste previously given shot into edit area.
1067 """
1068 self.editarea.set_data(aVacc=event.GetClientData())
1069 #----------------------------------------------------
1071 self.editarea.set_data(aVacc = event.GetClientData())
1072 #----------------------------------------------------
1074 """Update right hand middle list to show vaccinations given for selected indication."""
1075 ind_list = event.GetEventObject()
1076 selected_item = ind_list.GetSelection()
1077 ind = ind_list.GetClientData(selected_item)
1078 # clear list
1079 self.LBOX_given_shots.Set([])
1080 emr = self.__pat.get_emr()
1081 shots = emr.get_vaccinations(indications = [ind])
1082 # FIXME: use Set() for entire array (but problem with client_data)
1083 for shot in shots:
1084 if shot['is_booster']:
1085 marker = 'B'
1086 else:
1087 marker = '#%s' % shot['seq_no']
1088 label = '%s - %s: %s' % (marker, shot['date'].strftime('%m/%Y'), shot['vaccine'])
1089 self.LBOX_given_shots.Append(label, shot)
1090 #----------------------------------------------------
1092 # clear edit area
1093 self.editarea.set_data()
1094 # clear lists
1095 self.LBOX_vaccinated_indications.Clear()
1096 self.LBOX_given_shots.Clear()
1097 self.LBOX_active_schedules.Clear()
1098 self.LBOX_missing_shots.Clear()
1099 #----------------------------------------------------
1101 # clear lists
1102 self.LBOX_vaccinated_indications.Clear()
1103 self.LBOX_given_shots.Clear()
1104 self.LBOX_active_schedules.Clear()
1105 self.LBOX_missing_shots.Clear()
1106
1107 emr = self.__pat.get_emr()
1108
1109 t1 = time.time()
1110 # populate vaccinated-indications list
1111 # FIXME: consider adding virtual indication "most recent" to
1112 # FIXME: display most recent of all indications as suggested by Syan
1113 status, indications = emr.get_vaccinated_indications()
1114 # FIXME: would be faster to use Set() but can't
1115 # use Set(labels, client_data), and have to know
1116 # line position in SetClientData :-(
1117 for indication in indications:
1118 self.LBOX_vaccinated_indications.Append(indication[1], indication[0])
1119 # self.LBOX_vaccinated_indications.Set(lines)
1120 # self.LBOX_vaccinated_indications.SetClientData(data)
1121 print "vaccinated indications took", time.time()-t1, "seconds"
1122
1123 t1 = time.time()
1124 # populate active schedules list
1125 scheds = emr.get_scheduled_vaccination_regimes()
1126 if scheds is None:
1127 label = _('ERROR: cannot retrieve active vaccination schedules')
1128 self.LBOX_active_schedules.Append(label)
1129 elif len(scheds) == 0:
1130 label = _('no active vaccination schedules')
1131 self.LBOX_active_schedules.Append(label)
1132 else:
1133 for sched in scheds:
1134 label = _('%s for %s (%s shots): %s') % (sched['regime'], sched['l10n_indication'], sched['shots'], sched['comment'])
1135 self.LBOX_active_schedules.Append(label)
1136 print "active schedules took", time.time()-t1, "seconds"
1137
1138 t1 = time.time()
1139 # populate missing-shots list
1140 missing_shots = emr.get_missing_vaccinations()
1141 print "getting missing shots took", time.time()-t1, "seconds"
1142 if missing_shots is None:
1143 label = _('ERROR: cannot retrieve due/overdue vaccinations')
1144 self.LBOX_missing_shots.Append(label, None)
1145 return True
1146 # due
1147 due_template = _('%.0d weeks left: shot %s for %s in %s, due %s (%s)')
1148 overdue_template = _('overdue %.0dyrs %.0dwks: shot %s for %s in schedule "%s" (%s)')
1149 for shot in missing_shots['due']:
1150 if shot['overdue']:
1151 years, days_left = divmod(shot['amount_overdue'].days, 364.25)
1152 weeks = days_left / 7
1153 # amount_overdue, seq_no, indication, regime, vacc_comment
1154 label = overdue_template % (
1155 years,
1156 weeks,
1157 shot['seq_no'],
1158 shot['l10n_indication'],
1159 shot['regime'],
1160 shot['vacc_comment']
1161 )
1162 self.LBOX_missing_shots.Append(label, shot)
1163 else:
1164 # time_left, seq_no, regime, latest_due, vacc_comment
1165 label = due_template % (
1166 shot['time_left'].days / 7,
1167 shot['seq_no'],
1168 shot['indication'],
1169 shot['regime'],
1170 shot['latest_due'].strftime('%m/%Y'),
1171 shot['vacc_comment']
1172 )
1173 self.LBOX_missing_shots.Append(label, shot)
1174 # booster
1175 lbl_template = _('due now: booster for %s in schedule "%s" (%s)')
1176 for shot in missing_shots['boosters']:
1177 # indication, regime, vacc_comment
1178 label = lbl_template % (
1179 shot['l10n_indication'],
1180 shot['regime'],
1181 shot['vacc_comment']
1182 )
1183 self.LBOX_missing_shots.Append(label, shot)
1184 print "displaying missing shots took", time.time()-t1, "seconds"
1185
1186 return True
1187 #----------------------------------------------------
1190 # FIXME:
1191 # if has_focus:
1192 # wxCallAfter(self.__reset_ui_content)
1193 # else:
1194 # return 1
1195 #----------------------------------------------------
1198 # FIXME:
1199 # if has_focus:
1200 # wxCallAfter(self.__reset_ui_content)
1201 # else:
1202 # is_stale == True
1203 # return 1
1204 #======================================================================
1205 # main
1206 #----------------------------------------------------------------------
1207 if __name__ == "__main__":
1208
1209 if len(sys.argv) < 2:
1210 sys.exit()
1211
1212 if sys.argv[1] != u'test':
1213 sys.exit()
1214
1215 app = wx.PyWidgetTester(size = (600, 600))
1216 app.SetWidget(cATCPhraseWheel, -1)
1217 app.MainLoop()
1218 #======================================================================
1219
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Sep 9 04:06:44 2010 | http://epydoc.sourceforge.net |