1 """GNUmed vaccination related business objects.
2 """
3
4 __version__ = "$Revision: 1.38 $"
5 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
6 __license__ = "GPL"
7
8 import sys, copy, logging
9
10
11 if __name__ == '__main__':
12 sys.path.insert(0, '../../')
13
14
15
16 from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmI18N, gmTools
17 from Gnumed.business import gmMedication
18
19
20 _log = logging.getLogger('gm.vaccination')
21 _log.info(__version__)
22
23
25 cmd = u'SELECT * from clin.vacc_indication'
26
27 if order_by is not None:
28 cmd = u'%s ORDER BY %s' % (cmd, order_by)
29
30 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
31
32 return rows
33
34 _sql_fetch_vaccine = u"""SELECT *, xmin_vaccine FROM clin.v_vaccines WHERE %s"""
35
36 -class cVaccine(gmBusinessDBObject.cBusinessDBObject):
37 """Represents one vaccine."""
38
39 _cmd_fetch_payload = _sql_fetch_vaccine % u"pk_vaccine = %s"
40
41 _cmds_store_payload = [
42 u"""UPDATE clin.vaccine SET
43 --id_route = %(pk_route)s,
44 --is_live = %(is_live)s,
45 min_age = %(min_age)s,
46 max_age = %(max_age)s,
47 comment = gm.nullify_empty_string(%(comment)s),
48 fk_brand = %(pk_brand)s
49 WHERE
50 pk = %(pk_vaccine)s
51 AND
52 xmin = %(xmin_vaccine)s
53 RETURNING
54 xmin as xmin_vaccine
55 """
56 ]
57
58 _updatable_fields = [
59
60
61 u'min_age',
62 u'max_age',
63 u'comment',
64 u'pk_brand'
65 ]
66
68 queries = [{
69 'cmd': u'DELETE FROM clin.lnk_vaccine2inds WHERE fk_vaccine = %(pk_vacc)s',
70 'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']]}
71 }]
72
73 if pk_indications is None:
74 if set(self._payload[self._idx['indications']]) == set(indications):
75 return
76
77 for ind in indications:
78 queries.append ({
79 'cmd': u"""
80 INSERT INTO clin.lnk_vaccine2inds (
81 fk_vaccine,
82 fk_indication
83 ) VALUES (
84 %(pk_vacc)s,
85 (SELECT id FROM clin.vacc_indication WHERE description = %(ind)s)
86 )""",
87 'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']], 'ind': ind}
88 })
89 else:
90 if set(self._payload[self._idx['pk_indications']]) == set(pk_indications):
91 return
92
93 for pk_ind in pk_indications:
94 queries.append ({
95 'cmd': u"""
96 INSERT INTO clin.lnk_vaccine2inds (
97 fk_vaccine,
98 fk_indication
99 ) VALUES (
100 %(pk_vacc)s,
101 %(pk_ind)s
102 )""",
103 'args': {'pk_vacc': self._payload[self._idx['pk_vaccine']], 'pk_ind': pk_ind}
104 })
105
106 gmPG2.run_rw_queries(queries = queries)
107 self.refetch_payload()
108
109
110
113
114 brand = property(_get_brand, lambda x:x)
115
117 cmd = u'SELECT EXISTS(SELECT 1 FROM clin.vaccination WHERE fk_vaccine = %(pk)s)'
118 args = {'pk': self._payload[self._idx['pk_vaccine']]}
119 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
120 return rows[0][0]
121
122 is_in_use = property(_get_is_in_use, lambda x:x)
123
125
126 if pk_brand is None:
127 prep = _('vaccine')
128 _log.debug('creating branded drug [%s %s]', brand_name, prep)
129 drug = gmMedication.create_branded_drug (
130 brand_name = brand_name,
131 preparation = prep,
132 return_existing = True
133 )
134 drug['atc'] = u'J07'
135 drug.save()
136 pk_brand = drug['pk_brand']
137
138 cmd = u'INSERT INTO clin.vaccine (fk_brand) values (%(pk_brand)s) RETURNING pk'
139 queries = [{'cmd': cmd, 'args': {'pk_brand': pk_brand}}]
140
141 for indication in indications:
142 cmd = u"""
143 INSERT INTO clin.lnk_vaccine2inds (
144 fk_vaccine,
145 fk_indication
146 ) VALUES (
147 currval(pg_get_serial_sequence('clin.vaccine', 'pk')),
148 (SELECT id
149 FROM clin.vacc_indication
150 WHERE
151 lower(description) = lower(%(ind)s)
152 LIMIT 1
153 )
154 )
155 RETURNING fk_vaccine
156 """
157 queries.append({'cmd': cmd, 'args': {'ind': indication}})
158
159 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = False, return_data = True)
160
161 return cVaccine(aPK_obj = rows[0]['fk_vaccine'])
162
164
165 cmd = u'DELETE FROM clin.vaccine WHERE pk = %(pk)s'
166 args = {'pk': vaccine}
167
168 try:
169 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
170 except gmPG2.dbapi.IntegrityError:
171 _log.exception('cannot delete vaccine [%s]', vaccine)
172 return False
173
174 return True
175
186
188
189 args = {'inds': indications}
190 cmd = _sql_fetch_vaccine % (u'is_fake_vaccine is True AND indications @> %(inds)s AND %(inds)s @> indications')
191
192 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
193
194 if len(rows) == 0:
195 _log.warning('no fake, generic vaccine found for [%s]', indications)
196 return None
197
198 return cVaccine(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_vaccine'})
199
201
202 cmd = u'select gm.create_generic_monovalent_vaccines()'
203 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
204
205 cmd = u'select gm.create_generic_combi_vaccines()'
206 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
207
208 return rows[0][0]
209
210
211
212 sql_fetch_vaccination = u"""SELECT * FROM clin.v_pat_vaccinations WHERE %s"""
213
215
216 _cmd_fetch_payload = sql_fetch_vaccination % u"pk_vaccination = %s"
217
218 _cmds_store_payload = [
219 u"""UPDATE clin.vaccination SET
220 soap_cat = %(soap_cat)s,
221 clin_when = %(date_given)s,
222 site = gm.nullify_empty_string(%(site)s),
223 batch_no = gm.nullify_empty_string(%(batch_no)s),
224 reaction = gm.nullify_empty_string(%(reaction)s),
225 narrative = gm.nullify_empty_string(%(comment)s),
226 fk_vaccine = %(pk_vaccine)s,
227 fk_provider = %(pk_provider)s,
228 fk_encounter = %(pk_encounter)s,
229 fk_episode = %(pk_episode)s
230 WHERE
231 pk = %(pk_vaccination)s
232 AND
233 xmin = %(xmin_vaccination)s
234 RETURNING
235 xmin as xmin_vaccination
236 """
237 ]
238
239 _updatable_fields = [
240 u'soap_cat',
241 u'date_given',
242 u'site',
243 u'batch_no',
244 u'reaction',
245 u'comment',
246 u'pk_vaccine',
247 u'pk_provider',
248 u'pk_encounter',
249 u'pk_episode'
250 ]
251
275
277
278 cmd = u"""
279 INSERT INTO clin.vaccination (
280 fk_encounter,
281 fk_episode,
282 fk_vaccine,
283 batch_no
284 ) VALUES (
285 %(enc)s,
286 %(epi)s,
287 %(vacc)s,
288 %(batch)s
289 ) RETURNING pk;
290 """
291 args = {
292 u'enc': encounter,
293 u'epi': episode,
294 u'vacc': vaccine,
295 u'batch': batch_no
296 }
297
298 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
299
300 return cVaccination(aPK_obj = rows[0][0])
301
302
303
305 cmd = u"""DELETE FROM clin.vaccination WHERE pk = %(pk)s"""
306 args = {'pk': vaccination}
307
308 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
309
310
311
324
325
326
379
380
381
382
383
384
386 """Represents one missing vaccination.
387
388 - can be due or overdue
389 """
390 _cmd_fetch_payload = """
391 (select *, False as overdue
392 from clin.v_pat_missing_vaccs vpmv
393 where
394 pk_patient=%(pat_id)s
395 and
396 (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
397 and
398 indication=%(indication)s
399 and
400 seq_no=%(seq_no)s
401 order by time_left)
402
403 UNION
404
405 (select *, True as overdue
406 from clin.v_pat_missing_vaccs vpmv
407 where
408 pk_patient=%(pat_id)s
409 and
410 now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
411 and
412 indication=%(indication)s
413 and
414 seq_no=%(seq_no)s
415 order by amount_overdue)"""
416 _cmds_lock_rows_for_update = []
417 _cmds_store_payload = ["""select 1"""]
418 _updatable_fields = []
419
421 return self['overdue']
422
424
425
426
427
428 return (False, 'not implemented')
429
444
452
454 """Represents one vaccination course.
455 """
456 _cmd_fetch_payload = """
457 select *, xmin_vaccination_course from clin.v_vaccination_courses
458 where pk_course=%s"""
459 _cmds_lock_rows_for_update = [
460 """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
461 ]
462 _cmds_store_payload = [
463 """update clin.vaccination_course set
464 name=%(course)s,
465 fk_recommended_by=%(pk_recommended_by)s,
466 fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
467 comment=%(comment)s
468 where id=%(pk_course)s""",
469 """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
470 ]
471 _updatable_fields = [
472 'course',
473 'pk_recommended_by',
474 'indication',
475 'comment'
476 ]
477
478
479
480
481 -def create_vaccination_old(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
482
483
484
485 cmd = """
486 select pk_patient
487 from clin.v_pat_episodes
488 where pk_episode=%s
489 union
490 select pk_patient
491 from clin.v_pat_encounters
492 where pk_encounter=%s"""
493 rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
494 if (rows is None) or (len(rows) == 0):
495 _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
496 return (False, _('internal error, check log'))
497 if len(rows) > 1:
498 _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
499 return (False, _('consistency error, check log'))
500
501 queries = []
502 if type(vaccine) == types.IntType:
503 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
504 values (%s, %s, %s, %s, %s)"""
505 else:
506 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
507 values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
508 vaccine = str(vaccine)
509 queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
510
511 cmd = "select currval('clin.vaccination_id_seq')"
512 queries.append((cmd, []))
513 result, msg = gmPG.run_commit('historica', queries, True)
514 if (result is None) or (len(result) == 0):
515 return (False, msg)
516 try:
517 vacc = cVaccination(aPK_obj = result[0][0])
518 except gmExceptions.ConstructorError:
519 _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
520 return (False, _('internal error, check log'))
521
522 return (True, vacc)
523
525
526 cmd = 'select name from clin.vaccination_course'
527 rows = gmPG.run_ro_query('historica', cmd)
528 if rows is None:
529 return None
530 if len(rows) == 0:
531 return []
532 data = []
533 for row in rows:
534 data.extend(rows)
535 return data
536
538
539 int(pk_patient)
540
541 cmd = """
542 select fk_regime
543 from clin.lnk_pat2vacc_reg l
544 where l.fk_patient = %s""" % pk_patient
545
546 rows = gmPG.run_ro_query('historica', cmd)
547 active = []
548 if rows and len(rows):
549 active = [ r[0] for r in rows]
550
551
552
553
554
555
556
557 r = ( {}, [] )
558
559
560 cmd = """
561 select
562 r.pk_regime ,
563 r.pk_recommended_by ,
564 r.indication,
565 r.regime ,
566 extract (epoch from d.min_age_due) /60/60/24,
567 extract (epoch from d.max_age_due) /60/60/24,
568 extract (epoch from d.min_interval ) /60/60/24,
569 d.seq_no
570 from
571 clin.v_vaccination_courses r, clin.vacc_def d
572 where
573 d.fk_regime = r.pk_regime
574 order by
575 r.pk_recommended_by, d.min_age_due"""
576
577
578
579
580 rows = gmPG.run_ro_query('historica', cmd)
581 if rows is None:
582 VaccByRecommender._recommended_regimes = r
583 return r, active
584
585 row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
586
587 for row in rows:
588 m = {}
589 for k, i in zip(row_fields, range(len(row))):
590 m[k] = row[i]
591 pk_recommender = m['pk_recommender']
592
593 if not pk_recommender in r[0].keys():
594 r[0][pk_recommender] = []
595 r[1].append(pk_recommender)
596 r[0][pk_recommender].append(m)
597
598 for k, v in r[0].items():
599 print k
600 for x in v:
601 print '\t', x
602
603 VaccByRecommender._recommended_regimes = r
604 return r, active
605
607
608 int(pk_patient)
609
610 cmd = """
611 select
612 indication, regime,
613 pk_regime,
614 pk_recommended_by,
615 seq_no ,
616 extract(epoch from age_due_min) /60/60/24 as age_due_min,
617 extract(epoch from age_due_max) /60/60/24 as age_due_max,
618 extract(epoch from min_interval)/60/60/24 as min_interval
619 from
620 clin.v_pat_missing_vaccs
621 where pk_patient = %s
622 order by age_due_min, pk_recommended_by, indication
623 """ % pk_patient
624
625 rows = gmPG.run_ro_query('historica', cmd)
626
627 return rows
628
630 """Retrieves vaccination bundle indications list.
631
632 * vaccinations = list of any type of vaccination
633 - indicated
634 - due vacc
635 - overdue vaccs
636 - due boosters
637 - arbitrary
638 """
639
640
641
642 if vaccinations is None:
643 _log.error('list of vaccinations must be supplied')
644 return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
645 if len(vaccinations) == 0:
646 return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
647 inds = []
648 for vacc in vaccinations:
649 try:
650 inds.append([vacc['indication'], vacc['l10n_indication']])
651 except KeyError:
652 try:
653 inds.append([vacc['indication'], vacc['indication']])
654 except KeyError:
655 inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
656 return (True, inds)
657
659 """
660 Schedules a vaccination course for a patient
661
662 * patient_id = Patient's PK
663 * course = course object or Vaccination course's PK
664 """
665
666 if isinstance(course, cVaccinationCourse):
667 course_id = course['pk_course']
668 else:
669 course_id = course
670
671
672 queries = []
673 cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
674 values (%s, %s)"""
675 queries.append((cmd, [patient_id, course_id]))
676 result, msg = gmPG.run_commit('historica', queries, True)
677 if result is None:
678 return (False, msg)
679 return (True, msg)
680
682 """unSchedules a vaccination course for a patient
683
684 * patient_id = Patient's PK
685 * course = course object or Vaccination course's PK
686 """
687
688 if isinstance(course, cVaccinationCourse):
689 course_id = course['pk_course']
690 else:
691 course_id = course
692
693
694 queries = []
695 cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
696
697 queries.append((cmd, [patient_id, course_id]))
698 result, msg = gmPG.run_commit('historica', queries, True)
699 if result is None:
700 return (False, msg)
701 return (True, msg)
702
704
705 quoted_inds = [ "'"+x + "%'" for x in all_ind]
706
707
708
709
710
711
712
713
714
715
716
717 cmd_inds_per_vaccine = """
718 select
719 count(trade_name),
720 trade_name
721 from clin.v_inds4vaccine
722 group by trade_name"""
723
724 cmd_presence_in_vaccine = """
725 select count(v.trade_name) , v.trade_name
726
727 from
728 clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
729 where
730 v.pk = l.fk_vaccine and l.fk_indication = i.id
731 and
732 i.description like any ( array [ %s ] )
733 group
734
735 by trade_name
736
737 """ % ', '.join( quoted_inds )
738
739 inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
740
741 presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
742
743 map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
744
745 matched_vaccines = []
746 for (presence, vaccine) in presence_in_vaccine:
747 if presence == len ( all_ind) :
748
749
750 if map_vacc_count_inds[vaccine] == presence:
751 matched_vaccines.append(vaccine)
752 return matched_vaccines
753
754
755
756 if __name__ == '__main__':
757
758 if len(sys.argv) < 2:
759 sys.exit()
760
761 if sys.argv[1] != u'test':
762 sys.exit()
763
764
765
773
775
776 pk_args = {
777 'pat_id': 12,
778 'indication': 'meningococcus C',
779 'seq_no': 1
780 }
781 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
782 fields = missing_vacc.get_fields()
783 print "\nDue vaccination:"
784 print missing_vacc
785 for field in fields:
786 print field, ':', missing_vacc[field]
787
788 pk_args = {
789 'pat_id': 12,
790 'indication': 'haemophilus influenzae b',
791 'seq_no': 2
792 }
793 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
794 fields = missing_vacc.get_fields()
795 print "\nOverdue vaccination (?):"
796 print missing_vacc
797 for field in fields:
798 print field, ':', missing_vacc[field]
799
801 pk_args = {
802 'pat_id': 12,
803 'indication': 'tetanus'
804 }
805 missing_booster = cMissingBooster(aPK_obj=pk_args)
806 fields = missing_booster.get_fields()
807 print "\nDue booster:"
808 print missing_booster
809 for field in fields:
810 print field, ':', missing_booster[field]
811
813 scheduled_vacc = cScheduledVaccination(aPK_obj=20)
814 print "\nScheduled vaccination:"
815 print scheduled_vacc
816 fields = scheduled_vacc.get_fields()
817 for field in fields:
818 print field, ':', scheduled_vacc[field]
819 print "updatable:", scheduled_vacc.get_updatable_fields()
820
822 vaccination_course = cVaccinationCourse(aPK_obj=7)
823 print "\nVaccination course:"
824 print vaccination_course
825 fields = vaccination_course.get_fields()
826 for field in fields:
827 print field, ':', vaccination_course[field]
828 print "updatable:", vaccination_course.get_updatable_fields()
829
831 result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
832 print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
833
838
839
840
841
842
843
844
845
846
847 test_get_vaccines()
848
849