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 u'id_route',
60 u'is_live',
61 u'min_age',
62 u'max_age',
63 u'comment',
64 u'pk_brand'
65
66 ]
67
68
69
70
71
72
75
76 brand = property(_get_brand, lambda x:x)
77
79
80 if pk_brand is None:
81 _log.debug('creating branded drug [%s %s]', brand_name, preparation)
82 drug = gmMedication.create_branded_drug (
83 brand_name = brand_name,
84 preparation = _('vaccine'),
85 return_existing = True
86 )
87 drug['atc_code'] = u'J07'
88 drug.save()
89 pk_brand = drug['pk']
90
91 cmd = u'INSERT INTO clin.vaccine (fk_brand) values (%(pk_brand)s) RETURNING pk'
92 queries = [{'cmd': cmd, 'args': {'pk_brand': pk_brand}}]
93
94 for indication in indications:
95 cmd = u"""
96 INSERT INTO into clin.lnk_vaccine2inds (
97 fk_vaccine,
98 fk_indication
99 ) VALUES (
100 currval(pg_get_serial_sequence('clin.vaccine', 'pk')),
101 (SELECT id
102 FROM clin.vacc_indication
103 WHERE
104 lower(description) = lower(%(ind)s)
105 LIMIT 1
106 )
107 RETURNING fk_vaccine
108 """
109 queries.append({'cmd': cmd, 'args': {'ind': indication}})
110
111 rows, idx = gmPG2.run_rw_queries(queries = queries, get_col_idx = False, return_data = True)
112
113 return cVaccine(aPK_obj = rows[0]['fk_vaccine'])
114
116
117 cmd = u'DELETE FROM clin.vaccine WHERE pk = %(pk)s'
118 args = {'pk': vaccine}
119
120 try:
121 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
122 except gmPG2.dbapi.IntegrityError:
123 _log.exception('cannot delete vaccine [%s]', vaccine)
124 return False
125
126 return True
127
138
140
141 args = {'inds': indications}
142 cmd = _sql_fetch_vaccine % (u'is_fake_vaccine is True AND indications @> %(inds)s AND %(inds)s @> indications')
143
144 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
145
146 if len(rows) == 0:
147 _log.warning('no fake, generic vaccine found for [%s]', indications)
148 return None
149
150 return cVaccine(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_vaccine'})
151
153
154 cmd = u'select gm.create_generic_monovalent_vaccines()'
155 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
156
157 cmd = u'select gm.create_generic_combi_vaccines()'
158 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
159
160 return rows[0][0]
161
162
163
164 sql_fetch_vaccination = u"""SELECT * FROM clin.v_pat_vaccinations WHERE %s"""
165
167
168 _cmd_fetch_payload = sql_fetch_vaccination % u"pk_vaccination = %s"
169
170 _cmds_store_payload = [
171 u"""UPDATE clin.vaccination SET
172 soap_cat = %(soap_cat)s,
173 clin_when = %(date_given)s,
174 site = gm.nullify_empty_string(%(site)s),
175 batch_no = gm.nullify_empty_string(%(batch_no)s),
176 reaction = gm.nullify_empty_string(%(reaction)s),
177 narrative = gm.nullify_empty_string(%(comment)s),
178 fk_vaccine = %(pk_vaccine)s,
179 fk_provider = %(pk_provider)s,
180 fk_encounter = %(pk_encounter)s,
181 fk_episode = %(pk_episode)s
182 WHERE
183 pk = %(pk_vaccination)s
184 AND
185 xmin = %(xmin_vaccination)s
186 RETURNING
187 xmin as xmin_vaccination
188 """
189 ]
190
191 _updatable_fields = [
192 u'soap_cat',
193 u'date_given',
194 u'site',
195 u'batch_no',
196 u'reaction',
197 u'comment',
198 u'pk_vaccine',
199 u'pk_provider',
200 u'pk_encounter',
201 u'pk_episode'
202 ]
203
227
229
230 cmd = u"""
231 INSERT INTO clin.vaccination (
232 fk_encounter,
233 fk_episode,
234 fk_vaccine,
235 batch_no
236 ) VALUES (
237 %(enc)s,
238 %(epi)s,
239 %(vacc)s,
240 %(batch)s
241 ) RETURNING pk;
242 """
243 args = {
244 u'enc': encounter,
245 u'epi': episode,
246 u'vacc': vaccine,
247 u'batch': batch_no
248 }
249
250 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
251
252 return cVaccination(aPK_obj = rows[0][0])
253
255 cmd = u"""DELETE FROM clin.vaccination WHERE pk = %(pk)s"""
256 args = {'pk': vaccination}
257
258 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
259
260
261
262
263
264
266 """Represents one missing vaccination.
267
268 - can be due or overdue
269 """
270 _cmd_fetch_payload = """
271 (select *, False as overdue
272 from clin.v_pat_missing_vaccs vpmv
273 where
274 pk_patient=%(pat_id)s
275 and
276 (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
277 and
278 indication=%(indication)s
279 and
280 seq_no=%(seq_no)s
281 order by time_left)
282
283 UNION
284
285 (select *, True as overdue
286 from clin.v_pat_missing_vaccs vpmv
287 where
288 pk_patient=%(pat_id)s
289 and
290 now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
291 and
292 indication=%(indication)s
293 and
294 seq_no=%(seq_no)s
295 order by amount_overdue)"""
296 _cmds_lock_rows_for_update = []
297 _cmds_store_payload = ["""select 1"""]
298 _updatable_fields = []
299
301 return self['overdue']
302
304
305
306
307
308 return (False, 'not implemented')
309
324
332
334 """Represents one vaccination course.
335 """
336 _cmd_fetch_payload = """
337 select *, xmin_vaccination_course from clin.v_vaccination_courses
338 where pk_course=%s"""
339 _cmds_lock_rows_for_update = [
340 """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
341 ]
342 _cmds_store_payload = [
343 """update clin.vaccination_course set
344 name=%(course)s,
345 fk_recommended_by=%(pk_recommended_by)s,
346 fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
347 comment=%(comment)s
348 where id=%(pk_course)s""",
349 """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
350 ]
351 _updatable_fields = [
352 'course',
353 'pk_recommended_by',
354 'indication',
355 'comment'
356 ]
357
358
359
360
361 -def create_vaccination_old(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
362
363
364
365 cmd = """
366 select pk_patient
367 from clin.v_pat_episodes
368 where pk_episode=%s
369 union
370 select pk_patient
371 from clin.v_pat_encounters
372 where pk_encounter=%s"""
373 rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
374 if (rows is None) or (len(rows) == 0):
375 _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
376 return (False, _('internal error, check log'))
377 if len(rows) > 1:
378 _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
379 return (False, _('consistency error, check log'))
380
381 queries = []
382 if type(vaccine) == types.IntType:
383 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
384 values (%s, %s, %s, %s, %s)"""
385 else:
386 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
387 values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
388 vaccine = str(vaccine)
389 queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
390
391 cmd = "select currval('clin.vaccination_id_seq')"
392 queries.append((cmd, []))
393 result, msg = gmPG.run_commit('historica', queries, True)
394 if (result is None) or (len(result) == 0):
395 return (False, msg)
396 try:
397 vacc = cVaccination(aPK_obj = result[0][0])
398 except gmExceptions.ConstructorError:
399 _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
400 return (False, _('internal error, check log'))
401
402 return (True, vacc)
403
405
406 cmd = 'select name from clin.vaccination_course'
407 rows = gmPG.run_ro_query('historica', cmd)
408 if rows is None:
409 return None
410 if len(rows) == 0:
411 return []
412 data = []
413 for row in rows:
414 data.extend(rows)
415 return data
416
418
419 int(pk_patient)
420
421 cmd = """
422 select fk_regime
423 from clin.lnk_pat2vacc_reg l
424 where l.fk_patient = %s""" % pk_patient
425
426 rows = gmPG.run_ro_query('historica', cmd)
427 active = []
428 if rows and len(rows):
429 active = [ r[0] for r in rows]
430
431
432
433
434
435
436
437 r = ( {}, [] )
438
439
440 cmd = """
441 select
442 r.pk_regime ,
443 r.pk_recommended_by ,
444 r.indication,
445 r.regime ,
446 extract (epoch from d.min_age_due) /60/60/24,
447 extract (epoch from d.max_age_due) /60/60/24,
448 extract (epoch from d.min_interval ) /60/60/24,
449 d.seq_no
450 from
451 clin.v_vaccination_courses r, clin.vacc_def d
452 where
453 d.fk_regime = r.pk_regime
454 order by
455 r.pk_recommended_by, d.min_age_due"""
456
457
458
459
460 rows = gmPG.run_ro_query('historica', cmd)
461 if rows is None:
462 VaccByRecommender._recommended_regimes = r
463 return r, active
464
465 row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
466
467 for row in rows:
468 m = {}
469 for k, i in zip(row_fields, range(len(row))):
470 m[k] = row[i]
471 pk_recommender = m['pk_recommender']
472
473 if not pk_recommender in r[0].keys():
474 r[0][pk_recommender] = []
475 r[1].append(pk_recommender)
476 r[0][pk_recommender].append(m)
477
478 for k, v in r[0].items():
479 print k
480 for x in v:
481 print '\t', x
482
483 VaccByRecommender._recommended_regimes = r
484 return r, active
485
487
488 int(pk_patient)
489
490 cmd = """
491 select
492 indication, regime,
493 pk_regime,
494 pk_recommended_by,
495 seq_no ,
496 extract(epoch from age_due_min) /60/60/24 as age_due_min,
497 extract(epoch from age_due_max) /60/60/24 as age_due_max,
498 extract(epoch from min_interval)/60/60/24 as min_interval
499 from
500 clin.v_pat_missing_vaccs
501 where pk_patient = %s
502 order by age_due_min, pk_recommended_by, indication
503 """ % pk_patient
504
505 rows = gmPG.run_ro_query('historica', cmd)
506
507 return rows
508
510 """Retrieves vaccination bundle indications list.
511
512 * vaccinations = list of any type of vaccination
513 - indicated
514 - due vacc
515 - overdue vaccs
516 - due boosters
517 - arbitrary
518 """
519
520
521
522 if vaccinations is None:
523 _log.error('list of vaccinations must be supplied')
524 return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
525 if len(vaccinations) == 0:
526 return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
527 inds = []
528 for vacc in vaccinations:
529 try:
530 inds.append([vacc['indication'], vacc['l10n_indication']])
531 except KeyError:
532 try:
533 inds.append([vacc['indication'], vacc['indication']])
534 except KeyError:
535 inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
536 return (True, inds)
537
539 """
540 Schedules a vaccination course for a patient
541
542 * patient_id = Patient's PK
543 * course = course object or Vaccination course's PK
544 """
545
546 if isinstance(course, cVaccinationCourse):
547 course_id = course['pk_course']
548 else:
549 course_id = course
550
551
552 queries = []
553 cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
554 values (%s, %s)"""
555 queries.append((cmd, [patient_id, course_id]))
556 result, msg = gmPG.run_commit('historica', queries, True)
557 if result is None:
558 return (False, msg)
559 return (True, msg)
560
562 """unSchedules a vaccination course for a patient
563
564 * patient_id = Patient's PK
565 * course = course object or Vaccination course's PK
566 """
567
568 if isinstance(course, cVaccinationCourse):
569 course_id = course['pk_course']
570 else:
571 course_id = course
572
573
574 queries = []
575 cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
576
577 queries.append((cmd, [patient_id, course_id]))
578 result, msg = gmPG.run_commit('historica', queries, True)
579 if result is None:
580 return (False, msg)
581 return (True, msg)
582
584
585 quoted_inds = [ "'"+x + "%'" for x in all_ind]
586
587
588
589
590
591
592
593
594
595
596
597 cmd_inds_per_vaccine = """
598 select
599 count(trade_name),
600 trade_name
601 from clin.v_inds4vaccine
602 group by trade_name"""
603
604 cmd_presence_in_vaccine = """
605 select count(v.trade_name) , v.trade_name
606
607 from
608 clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
609 where
610 v.pk = l.fk_vaccine and l.fk_indication = i.id
611 and
612 i.description like any ( array [ %s ] )
613 group
614
615 by trade_name
616
617 """ % ', '.join( quoted_inds )
618
619 inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
620
621 presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
622
623 map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
624
625 matched_vaccines = []
626 for (presence, vaccine) in presence_in_vaccine:
627 if presence == len ( all_ind) :
628
629
630 if map_vacc_count_inds[vaccine] == presence:
631 matched_vaccines.append(vaccine)
632 return matched_vaccines
633
634
635
636 if __name__ == '__main__':
637
638 if len(sys.argv) < 2:
639 sys.exit()
640
641 if sys.argv[1] != u'test':
642 sys.exit()
643
644
645
653
655
656 pk_args = {
657 'pat_id': 12,
658 'indication': 'meningococcus C',
659 'seq_no': 1
660 }
661 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
662 fields = missing_vacc.get_fields()
663 print "\nDue vaccination:"
664 print missing_vacc
665 for field in fields:
666 print field, ':', missing_vacc[field]
667
668 pk_args = {
669 'pat_id': 12,
670 'indication': 'haemophilus influenzae b',
671 'seq_no': 2
672 }
673 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
674 fields = missing_vacc.get_fields()
675 print "\nOverdue vaccination (?):"
676 print missing_vacc
677 for field in fields:
678 print field, ':', missing_vacc[field]
679
681 pk_args = {
682 'pat_id': 12,
683 'indication': 'tetanus'
684 }
685 missing_booster = cMissingBooster(aPK_obj=pk_args)
686 fields = missing_booster.get_fields()
687 print "\nDue booster:"
688 print missing_booster
689 for field in fields:
690 print field, ':', missing_booster[field]
691
693 scheduled_vacc = cScheduledVaccination(aPK_obj=20)
694 print "\nScheduled vaccination:"
695 print scheduled_vacc
696 fields = scheduled_vacc.get_fields()
697 for field in fields:
698 print field, ':', scheduled_vacc[field]
699 print "updatable:", scheduled_vacc.get_updatable_fields()
700
702 vaccination_course = cVaccinationCourse(aPK_obj=7)
703 print "\nVaccination course:"
704 print vaccination_course
705 fields = vaccination_course.get_fields()
706 for field in fields:
707 print field, ':', vaccination_course[field]
708 print "updatable:", vaccination_course.get_updatable_fields()
709
711 result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
712 print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
713
718
719
720
721
722
723
724
725
726
727 test_get_vaccines()
728
729