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
17 from Gnumed.business import gmMedication
18
19
20 _log = logging.getLogger('gm.vaccination')
21 _log.info(__version__)
22
23 _sql_fetch_vaccine = u"""SELECT *, xmin_vaccine FROM clin.v_vaccines WHERE %s"""
24
25 -class cVaccine(gmBusinessDBObject.cBusinessDBObject):
26 """Represents one vaccine."""
27
28 _cmd_fetch_payload = _sql_fetch_vaccine % "pk = %s"
29
30 _cmds_store_payload = [
31 u"""UPDATE clin.vaccine SET
32 -- internal_name = gm.nullify_empty_string(%(internal_name)s),
33 WHERE
34 pk = %(pk_vaccine)s
35 AND
36 xmin = %(xmin_vaccine)s
37 RETURNING
38 xmin as xmin_vaccine
39 """
40 ]
41
42 _updatable_fields = [
43 u'id_route',
44 u'is_live',
45 u'min_age',
46 u'max_age',
47 u'comment'
48
49 ]
50
51 - def __init__(self, aPK_obj=None, row=None):
52 super(cVaccine, self).__init__(aPK_obj = aPK_obj, row = row)
53
54 self.__brand = None
55
56
57
59 if self.__brand is None:
60 self.__brand = gmMedication.cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
61 return self.__brand
62
63 brand = property(_get_brand, lambda x:x)
64
75
76
77
78
79
81 """Represents one vaccination event.
82 """
83 _cmd_fetch_payload = """
84 select *, NULL as is_booster, -1 as seq_no, xmin_vaccination from clin.v_pat_vaccinations4indication
85 where pk_vaccination=%s
86 order by date desc"""
87 _cmds_lock_rows_for_update = [
88 """select 1 from clin.vaccination where id=%(pk_vaccination)s and xmin=%(xmin_vaccination)s for update"""
89 ]
90 _cmds_store_payload = [
91 """update clin.vaccination set
92 clin_when=%(date)s,
93 narrative=%(narrative)s,
94 fk_provider=%(pk_provider)s,
95 fk_vaccine=(select pk from clin.vaccine where trade_name=%(vaccine)s),
96 site=%(site)s,
97 batch_no=%(batch_no)s
98 where id=%(pk_vaccination)s""",
99 """select xmin_vaccination from clin.v_pat_vaccinations4indication where pk_vaccination=%(pk_vaccination)s"""
100 ]
101 _updatable_fields = [
102 'date',
103 'narrative',
104 'pk_provider',
105 'vaccine',
106 'site',
107 'batch_no',
108
109
110 'is_booster',
111 'seq_no'
112 ]
113
115 """Make sure we have is_booster/seq_no when loading from row data."""
116 gmBusinessDBObject.cBusinessDBObject._init_from_row_data(self, row=row)
117 try:
118 idx = self._idx['is_booster']
119 except KeyError:
120 idx = len(self._payload)
121 self._payload.append(False)
122
123
124 self._idx = copy.copy(self._idx)
125 self._idx['is_booster'] = idx
126 try:
127 idx = self._idx['seq_no']
128 except KeyError:
129 idx = len(self._payload)
130 self._payload.append(False)
131 self._idx = copy.copy(self._idx)
132 self._idx['seq_no'] = -1
133
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
155 """Represents one missing vaccination.
156
157 - can be due or overdue
158 """
159 _cmd_fetch_payload = """
160 (select *, False as overdue
161 from clin.v_pat_missing_vaccs vpmv
162 where
163 pk_patient=%(pat_id)s
164 and
165 (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
166 and
167 indication=%(indication)s
168 and
169 seq_no=%(seq_no)s
170 order by time_left)
171
172 UNION
173
174 (select *, True as overdue
175 from clin.v_pat_missing_vaccs vpmv
176 where
177 pk_patient=%(pat_id)s
178 and
179 now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
180 and
181 indication=%(indication)s
182 and
183 seq_no=%(seq_no)s
184 order by amount_overdue)"""
185 _cmds_lock_rows_for_update = []
186 _cmds_store_payload = ["""select 1"""]
187 _updatable_fields = []
188
190 return self['overdue']
191
193
194
195
196
197 return (False, 'not implemented')
198
213
221
223 """Represents one vaccination course.
224 """
225 _cmd_fetch_payload = """
226 select *, xmin_vaccination_course from clin.v_vaccination_courses
227 where pk_course=%s"""
228 _cmds_lock_rows_for_update = [
229 """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
230 ]
231 _cmds_store_payload = [
232 """update clin.vaccination_course set
233 name=%(course)s,
234 fk_recommended_by=%(pk_recommended_by)s,
235 fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
236 comment=%(comment)s
237 where id=%(pk_course)s""",
238 """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
239 ]
240 _updatable_fields = [
241 'course',
242 'pk_recommended_by',
243 'indication',
244 'comment'
245 ]
246
249
250
251
252 -def create_vaccination(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
253
254
255
256 cmd = """
257 select pk_patient
258 from clin.v_pat_episodes
259 where pk_episode=%s
260 union
261 select pk_patient
262 from clin.v_pat_encounters
263 where pk_encounter=%s"""
264 rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
265 if (rows is None) or (len(rows) == 0):
266 _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
267 return (False, _('internal error, check log'))
268 if len(rows) > 1:
269 _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
270 return (False, _('consistency error, check log'))
271
272 queries = []
273 if type(vaccine) == types.IntType:
274 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
275 values (%s, %s, %s, %s, %s)"""
276 else:
277 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
278 values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
279 vaccine = str(vaccine)
280 queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
281
282 cmd = "select currval('clin.vaccination_id_seq')"
283 queries.append((cmd, []))
284 result, msg = gmPG.run_commit('historica', queries, True)
285 if (result is None) or (len(result) == 0):
286 return (False, msg)
287 try:
288 vacc = cVaccination(aPK_obj = result[0][0])
289 except gmExceptions.ConstructorError:
290 _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
291 return (False, _('internal error, check log'))
292
293 return (True, vacc)
294
296
297 cmd = 'select name from clin.vaccination_course'
298 rows = gmPG.run_ro_query('historica', cmd)
299 if rows is None:
300 return None
301 if len(rows) == 0:
302 return []
303 data = []
304 for row in rows:
305 data.extend(rows)
306 return data
307
309
310 int(pk_patient)
311
312 cmd = """
313 select fk_regime
314 from clin.lnk_pat2vacc_reg l
315 where l.fk_patient = %s""" % pk_patient
316
317 rows = gmPG.run_ro_query('historica', cmd)
318 active = []
319 if rows and len(rows):
320 active = [ r[0] for r in rows]
321
322
323
324
325
326
327
328 r = ( {}, [] )
329
330
331 cmd = """
332 select
333 r.pk_regime ,
334 r.pk_recommended_by ,
335 r.indication,
336 r.regime ,
337 extract (epoch from d.min_age_due) /60/60/24,
338 extract (epoch from d.max_age_due) /60/60/24,
339 extract (epoch from d.min_interval ) /60/60/24,
340 d.seq_no
341 from
342 clin.v_vaccination_courses r, clin.vacc_def d
343 where
344 d.fk_regime = r.pk_regime
345 order by
346 r.pk_recommended_by, d.min_age_due"""
347
348
349
350
351 rows = gmPG.run_ro_query('historica', cmd)
352 if rows is None:
353 VaccByRecommender._recommended_regimes = r
354 return r, active
355
356 row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
357
358 for row in rows:
359 m = {}
360 for k, i in zip(row_fields, range(len(row))):
361 m[k] = row[i]
362 pk_recommender = m['pk_recommender']
363
364 if not pk_recommender in r[0].keys():
365 r[0][pk_recommender] = []
366 r[1].append(pk_recommender)
367 r[0][pk_recommender].append(m)
368
369 for k, v in r[0].items():
370 print k
371 for x in v:
372 print '\t', x
373
374 VaccByRecommender._recommended_regimes = r
375 return r, active
376
378
379 int(pk_patient)
380
381 cmd = """
382 select
383 indication, regime,
384 pk_regime,
385 pk_recommended_by,
386 seq_no ,
387 extract(epoch from age_due_min) /60/60/24 as age_due_min,
388 extract(epoch from age_due_max) /60/60/24 as age_due_max,
389 extract(epoch from min_interval)/60/60/24 as min_interval
390 from
391 clin.v_pat_missing_vaccs
392 where pk_patient = %s
393 order by age_due_min, pk_recommended_by, indication
394 """ % pk_patient
395
396 rows = gmPG.run_ro_query('historica', cmd)
397
398 return rows
399
401 """Retrieves vaccination bundle indications list.
402
403 * vaccinations = list of any type of vaccination
404 - indicated
405 - due vacc
406 - overdue vaccs
407 - due boosters
408 - arbitrary
409 """
410
411
412
413 if vaccinations is None:
414 _log.error('list of vaccinations must be supplied')
415 return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
416 if len(vaccinations) == 0:
417 return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
418 inds = []
419 for vacc in vaccinations:
420 try:
421 inds.append([vacc['indication'], vacc['l10n_indication']])
422 except KeyError:
423 try:
424 inds.append([vacc['indication'], vacc['indication']])
425 except KeyError:
426 inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
427 return (True, inds)
428
430 """
431 Schedules a vaccination course for a patient
432
433 * patient_id = Patient's PK
434 * course = course object or Vaccination course's PK
435 """
436
437 if isinstance(course, cVaccinationCourse):
438 course_id = course['pk_course']
439 else:
440 course_id = course
441
442
443 queries = []
444 cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
445 values (%s, %s)"""
446 queries.append((cmd, [patient_id, course_id]))
447 result, msg = gmPG.run_commit('historica', queries, True)
448 if result is None:
449 return (False, msg)
450 return (True, msg)
451
453 """unSchedules a vaccination course for a patient
454
455 * patient_id = Patient's PK
456 * course = course object or Vaccination course's PK
457 """
458
459 if isinstance(course, cVaccinationCourse):
460 course_id = course['pk_course']
461 else:
462 course_id = course
463
464
465 queries = []
466 cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
467
468 queries.append((cmd, [patient_id, course_id]))
469 result, msg = gmPG.run_commit('historica', queries, True)
470 if result is None:
471 return (False, msg)
472 return (True, msg)
473
475
476 quoted_inds = [ "'"+x + "%'" for x in all_ind]
477
478
479
480
481
482
483
484
485
486
487
488 cmd_inds_per_vaccine = """
489 select
490 count(trade_name),
491 trade_name
492 from clin.v_inds4vaccine
493 group by trade_name"""
494
495 cmd_presence_in_vaccine = """
496 select count(v.trade_name) , v.trade_name
497
498 from
499 clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
500 where
501 v.pk = l.fk_vaccine and l.fk_indication = i.id
502 and
503 i.description like any ( array [ %s ] )
504 group
505
506 by trade_name
507
508 """ % ', '.join( quoted_inds )
509
510 inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
511
512 presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
513
514 map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
515
516 matched_vaccines = []
517 for (presence, vaccine) in presence_in_vaccine:
518 if presence == len ( all_ind) :
519
520
521 if map_vacc_count_inds[vaccine] == presence:
522 matched_vaccines.append(vaccine)
523 return matched_vaccines
524
525
526
527 if __name__ == '__main__':
528
529 if len(sys.argv) < 2:
530 sys.exit()
531
532 if sys.argv[1] != u'test':
533 sys.exit()
534
535
536
544
546
547 pk_args = {
548 'pat_id': 12,
549 'indication': 'meningococcus C',
550 'seq_no': 1
551 }
552 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
553 fields = missing_vacc.get_fields()
554 print "\nDue vaccination:"
555 print missing_vacc
556 for field in fields:
557 print field, ':', missing_vacc[field]
558
559 pk_args = {
560 'pat_id': 12,
561 'indication': 'haemophilus influenzae b',
562 'seq_no': 2
563 }
564 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
565 fields = missing_vacc.get_fields()
566 print "\nOverdue vaccination (?):"
567 print missing_vacc
568 for field in fields:
569 print field, ':', missing_vacc[field]
570
572 pk_args = {
573 'pat_id': 12,
574 'indication': 'tetanus'
575 }
576 missing_booster = cMissingBooster(aPK_obj=pk_args)
577 fields = missing_booster.get_fields()
578 print "\nDue booster:"
579 print missing_booster
580 for field in fields:
581 print field, ':', missing_booster[field]
582
584 scheduled_vacc = cScheduledVaccination(aPK_obj=20)
585 print "\nScheduled vaccination:"
586 print scheduled_vacc
587 fields = scheduled_vacc.get_fields()
588 for field in fields:
589 print field, ':', scheduled_vacc[field]
590 print "updatable:", scheduled_vacc.get_updatable_fields()
591
593 vaccination_course = cVaccinationCourse(aPK_obj=7)
594 print "\nVaccination course:"
595 print vaccination_course
596 fields = vaccination_course.get_fields()
597 for field in fields:
598 print field, ':', vaccination_course[field]
599 print "updatable:", vaccination_course.get_updatable_fields()
600
602 result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
603 print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
604
609
610
611
612
613
614
615
616
617
618 test_get_vaccines()
619
620