1 """GNUmed vaccination related business objects.
2 """
3
4
5
6 __version__ = "$Revision: 1.38 $"
7 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
8 __license__ = "GPL"
9
10 import types, copy, logging
11
12
13 from Gnumed.pycommon import gmExceptions, gmI18N, gmBusinessDBObject
14
15
16 _log = logging.getLogger('gm.vaccination')
17 _log.info(__version__)
18
20 """Represents one vaccination event.
21 """
22 _cmd_fetch_payload = """
23 select *, NULL as is_booster, -1 as seq_no, xmin_vaccination from clin.v_pat_vaccinations4indication
24 where pk_vaccination=%s
25 order by date desc"""
26 _cmds_lock_rows_for_update = [
27 """select 1 from clin.vaccination where id=%(pk_vaccination)s and xmin=%(xmin_vaccination)s for update"""
28 ]
29 _cmds_store_payload = [
30 """update clin.vaccination set
31 clin_when=%(date)s,
32 narrative=%(narrative)s,
33 fk_provider=%(pk_provider)s,
34 fk_vaccine=(select pk from clin.vaccine where trade_name=%(vaccine)s),
35 site=%(site)s,
36 batch_no=%(batch_no)s
37 where id=%(pk_vaccination)s""",
38 """select xmin_vaccination from clin.v_pat_vaccinations4indication where pk_vaccination=%(pk_vaccination)s"""
39 ]
40 _updatable_fields = [
41 'date',
42 'narrative',
43 'pk_provider',
44 'vaccine',
45 'site',
46 'batch_no',
47
48
49 'is_booster',
50 'seq_no'
51 ]
52
54 """Make sure we have is_booster/seq_no when loading from row data."""
55 gmBusinessDBObject.cBusinessDBObject._init_from_row_data(self, row=row)
56 try:
57 idx = self._idx['is_booster']
58 except KeyError:
59 idx = len(self._payload)
60 self._payload.append(False)
61
62
63 self._idx = copy.copy(self._idx)
64 self._idx['is_booster'] = idx
65 try:
66 idx = self._idx['seq_no']
67 except KeyError:
68 idx = len(self._payload)
69 self._payload.append(False)
70 self._idx = copy.copy(self._idx)
71 self._idx['seq_no'] = -1
72
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
94 """Represents one missing vaccination.
95
96 - can be due or overdue
97 """
98 _cmd_fetch_payload = """
99 (select *, False as overdue
100 from clin.v_pat_missing_vaccs vpmv
101 where
102 pk_patient=%(pat_id)s
103 and
104 (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
105 and
106 indication=%(indication)s
107 and
108 seq_no=%(seq_no)s
109 order by time_left)
110
111 UNION
112
113 (select *, True as overdue
114 from clin.v_pat_missing_vaccs vpmv
115 where
116 pk_patient=%(pat_id)s
117 and
118 now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
119 and
120 indication=%(indication)s
121 and
122 seq_no=%(seq_no)s
123 order by amount_overdue)"""
124 _cmds_lock_rows_for_update = []
125 _cmds_store_payload = ["""select 1"""]
126 _updatable_fields = []
127
129 return self['overdue']
130
132
133
134
135
136 return (False, 'not implemented')
137
152
160
162 """Represents one vaccination course.
163 """
164 _cmd_fetch_payload = """
165 select *, xmin_vaccination_course from clin.v_vaccination_courses
166 where pk_course=%s"""
167 _cmds_lock_rows_for_update = [
168 """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
169 ]
170 _cmds_store_payload = [
171 """update clin.vaccination_course set
172 name=%(course)s,
173 fk_recommended_by=%(pk_recommended_by)s,
174 fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
175 comment=%(comment)s
176 where id=%(pk_course)s""",
177 """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
178 ]
179 _updatable_fields = [
180 'course',
181 'pk_recommended_by',
182 'indication',
183 'comment'
184 ]
185
188
189
190
191 -def create_vaccination(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
192
193
194
195 cmd = """
196 select pk_patient
197 from clin.v_pat_episodes
198 where pk_episode=%s
199 union
200 select pk_patient
201 from clin.v_pat_encounters
202 where pk_encounter=%s"""
203 rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
204 if (rows is None) or (len(rows) == 0):
205 _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
206 return (False, _('internal error, check log'))
207 if len(rows) > 1:
208 _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
209 return (False, _('consistency error, check log'))
210
211 queries = []
212 if type(vaccine) == types.IntType:
213 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
214 values (%s, %s, %s, %s, %s)"""
215 else:
216 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
217 values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
218 vaccine = str(vaccine)
219 queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
220
221 cmd = "select currval('clin.vaccination_id_seq')"
222 queries.append((cmd, []))
223 result, msg = gmPG.run_commit('historica', queries, True)
224 if (result is None) or (len(result) == 0):
225 return (False, msg)
226 try:
227 vacc = cVaccination(aPK_obj = result[0][0])
228 except gmExceptions.ConstructorError:
229 _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
230 return (False, _('internal error, check log'))
231
232 return (True, vacc)
233
235
236 cmd = 'select name from clin.vaccination_course'
237 rows = gmPG.run_ro_query('historica', cmd)
238 if rows is None:
239 return None
240 if len(rows) == 0:
241 return []
242 data = []
243 for row in rows:
244 data.extend(rows)
245 return data
246
248
249 int(pk_patient)
250
251 cmd = """
252 select fk_regime
253 from clin.lnk_pat2vacc_reg l
254 where l.fk_patient = %s""" % pk_patient
255
256 rows = gmPG.run_ro_query('historica', cmd)
257 active = []
258 if rows and len(rows):
259 active = [ r[0] for r in rows]
260
261
262
263
264
265
266
267 r = ( {}, [] )
268
269
270 cmd = """
271 select
272 r.pk_regime ,
273 r.pk_recommended_by ,
274 r.indication,
275 r.regime ,
276 extract (epoch from d.min_age_due) /60/60/24,
277 extract (epoch from d.max_age_due) /60/60/24,
278 extract (epoch from d.min_interval ) /60/60/24,
279 d.seq_no
280 from
281 clin.v_vaccination_courses r, clin.vacc_def d
282 where
283 d.fk_regime = r.pk_regime
284 order by
285 r.pk_recommended_by, d.min_age_due"""
286
287
288
289
290 rows = gmPG.run_ro_query('historica', cmd)
291 if rows is None:
292 VaccByRecommender._recommended_regimes = r
293 return r, active
294
295 row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
296
297 for row in rows:
298 m = {}
299 for k, i in zip(row_fields, range(len(row))):
300 m[k] = row[i]
301 pk_recommender = m['pk_recommender']
302
303 if not pk_recommender in r[0].keys():
304 r[0][pk_recommender] = []
305 r[1].append(pk_recommender)
306 r[0][pk_recommender].append(m)
307
308 for k, v in r[0].items():
309 print k
310 for x in v:
311 print '\t', x
312
313 VaccByRecommender._recommended_regimes = r
314 return r, active
315
317
318 int(pk_patient)
319
320 cmd = """
321 select
322 indication, regime,
323 pk_regime,
324 pk_recommended_by,
325 seq_no ,
326 extract(epoch from age_due_min) /60/60/24 as age_due_min,
327 extract(epoch from age_due_max) /60/60/24 as age_due_max,
328 extract(epoch from min_interval)/60/60/24 as min_interval
329 from
330 clin.v_pat_missing_vaccs
331 where pk_patient = %s
332 order by age_due_min, pk_recommended_by, indication
333 """ % pk_patient
334
335 rows = gmPG.run_ro_query('historica', cmd)
336
337 return rows
338
340 """Retrieves vaccination bundle indications list.
341
342 * vaccinations = list of any type of vaccination
343 - indicated
344 - due vacc
345 - overdue vaccs
346 - due boosters
347 - arbitrary
348 """
349
350
351
352 if vaccinations is None:
353 _log.error('list of vaccinations must be supplied')
354 return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
355 if len(vaccinations) == 0:
356 return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
357 inds = []
358 for vacc in vaccinations:
359 try:
360 inds.append([vacc['indication'], vacc['l10n_indication']])
361 except KeyError:
362 try:
363 inds.append([vacc['indication'], vacc['indication']])
364 except KeyError:
365 inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
366 return (True, inds)
367
369 """
370 Schedules a vaccination course for a patient
371
372 * patient_id = Patient's PK
373 * course = course object or Vaccination course's PK
374 """
375
376 if isinstance(course, cVaccinationCourse):
377 course_id = course['pk_course']
378 else:
379 course_id = course
380
381
382 queries = []
383 cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
384 values (%s, %s)"""
385 queries.append((cmd, [patient_id, course_id]))
386 result, msg = gmPG.run_commit('historica', queries, True)
387 if result is None:
388 return (False, msg)
389 return (True, msg)
390
392 """unSchedules a vaccination course for a patient
393
394 * patient_id = Patient's PK
395 * course = course object or Vaccination course's PK
396 """
397
398 if isinstance(course, cVaccinationCourse):
399 course_id = course['pk_course']
400 else:
401 course_id = course
402
403
404 queries = []
405 cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
406
407 queries.append((cmd, [patient_id, course_id]))
408 result, msg = gmPG.run_commit('historica', queries, True)
409 if result is None:
410 return (False, msg)
411 return (True, msg)
412
414
415 quoted_inds = [ "'"+x + "%'" for x in all_ind]
416
417
418
419
420
421
422
423
424
425
426
427 cmd_inds_per_vaccine = """
428 select
429 count(trade_name),
430 trade_name
431 from clin.v_inds4vaccine
432 group by trade_name"""
433
434 cmd_presence_in_vaccine = """
435 select count(v.trade_name) , v.trade_name
436
437 from
438 clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
439 where
440 v.pk = l.fk_vaccine and l.fk_indication = i.id
441 and
442 i.description like any ( array [ %s ] )
443 group
444
445 by trade_name
446
447 """ % ', '.join( quoted_inds )
448
449 inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
450
451 presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
452
453 map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
454
455 matched_vaccines = []
456 for (presence, vaccine) in presence_in_vaccine:
457 if presence == len ( all_ind) :
458
459
460 if map_vacc_count_inds[vaccine] == presence:
461 matched_vaccines.append(vaccine)
462 return matched_vaccines
463
464
465
466 if __name__ == '__main__':
467 import sys
468
469 from Gnumed.pycommon import gmPG
470
478
480
481 pk_args = {
482 'pat_id': 12,
483 'indication': 'meningococcus C',
484 'seq_no': 1
485 }
486 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
487 fields = missing_vacc.get_fields()
488 print "\nDue vaccination:"
489 print missing_vacc
490 for field in fields:
491 print field, ':', missing_vacc[field]
492
493 pk_args = {
494 'pat_id': 12,
495 'indication': 'haemophilus influenzae b',
496 'seq_no': 2
497 }
498 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
499 fields = missing_vacc.get_fields()
500 print "\nOverdue vaccination (?):"
501 print missing_vacc
502 for field in fields:
503 print field, ':', missing_vacc[field]
504
506 pk_args = {
507 'pat_id': 12,
508 'indication': 'tetanus'
509 }
510 missing_booster = cMissingBooster(aPK_obj=pk_args)
511 fields = missing_booster.get_fields()
512 print "\nDue booster:"
513 print missing_booster
514 for field in fields:
515 print field, ':', missing_booster[field]
516
518 scheduled_vacc = cScheduledVaccination(aPK_obj=20)
519 print "\nScheduled vaccination:"
520 print scheduled_vacc
521 fields = scheduled_vacc.get_fields()
522 for field in fields:
523 print field, ':', scheduled_vacc[field]
524 print "updatable:", scheduled_vacc.get_updatable_fields()
525
527 vaccination_course = cVaccinationCourse(aPK_obj=7)
528 print "\nVaccination course:"
529 print vaccination_course
530 fields = vaccination_course.get_fields()
531 for field in fields:
532 print field, ':', vaccination_course[field]
533 print "updatable:", vaccination_course.get_updatable_fields()
534
536 result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
537 print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
538
539
540 test_vaccination_course()
541
542 test_scheduled_vacc()
543 test_vacc()
544 test_due_vacc()
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679