| Home | Trees | Indices | Help |
|
|---|
|
|
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 # from Gnumed.pycommon import #, gmDateTime, gmLog2
14 # gmDateTime.init()
15 # gmI18N.activate_locale()
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
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 -- internal_name = gm.nullify_empty_string(%(internal_name)s),
44 WHERE
45 pk = %(pk_vaccine)s
46 AND
47 xmin = %(xmin_vaccine)s
48 RETURNING
49 xmin as xmin_vaccine
50 """
51 ]
52
53 _updatable_fields = [
54 u'id_route',
55 u'is_live',
56 u'min_age',
57 u'max_age',
58 u'comment'
59 # forward fields to brand and include brand in save()
60 ]
61 #--------------------------------------------------------
66 #--------------------------------------------------------
67 # properties
68 #--------------------------------------------------------
70 if self.__brand is None:
71 self.__brand = gmMedication.cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
72 return self.__brand
73
74 brand = property(_get_brand, lambda x:x)
75 #------------------------------------------------------------
77
78 if order_by is None:
79 cmd = _sql_fetch_vaccine % u'TRUE'
80 else:
81 cmd = _sql_fetch_vaccine % (u'TRUE\nORDER BY %s' % order_by)
82
83 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
84
85 return [ cVaccine(row = {'data': r, 'idx': idx, 'pk_field': 'pk_vaccine'}) for r in rows ]
86 #------------------------------------------------------------
88
89 args = {'inds': indications}
90 cmd = _sql_fetch_vaccine % (u'is_fake_vaccine is True AND indications @> %(inds)s AND %(inds)s @> indications')
91
92 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
93
94 if len(rows) == 0:
95 _log.warning('no fake, generic vaccine found for [%s]', indications)
96 return None
97
98 return cVaccine(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_vaccine'})
99 #------------------------------------------------------------
101
102 cmd = u'select gm.create_generic_monovalent_vaccines()'
103 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
104
105 cmd = u'select gm.create_generic_combi_vaccines()'
106 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd}], return_data = True)
107
108 return rows[0][0]
109 #============================================================
110 # vaccination related classes
111 #============================================================
112 sql_fetch_vaccination = u"""SELECT * FROM clin.v_pat_vaccinations WHERE %s"""
113
115
116 _cmd_fetch_payload = sql_fetch_vaccination % u"pk_vaccination = %s"
117
118 _cmds_store_payload = [
119 u"""UPDATE clin.vaccination SET
120 soap_cat = %(soap_cat)s,
121 clin_when = %(date_given)s,
122 site = gm.nullify_empty_string(%(site)s),
123 batch_no = gm.nullify_empty_string(%(batch_no)s),
124 reaction = gm.nullify_empty_string(%(reaction)s),
125 narrative = gm.nullify_empty_string(%(comment)s),
126 fk_vaccine = %(pk_vaccine)s,
127 fk_provider = %(pk_provider)s,
128 fk_encounter = %(pk_encounter)s,
129 fk_episode = %(pk_episode)s
130 WHERE
131 pk = %(pk_vaccination)s
132 AND
133 xmin = %(xmin_vaccination)s
134 RETURNING
135 xmin as xmin_vaccination
136 """
137 ]
138
139 _updatable_fields = [
140 u'soap_cat',
141 u'date_given',
142 u'site',
143 u'batch_no',
144 u'reaction',
145 u'comment',
146 u'pk_vaccine',
147 u'pk_provider',
148 u'pk_encounter',
149 u'pk_episode'
150 ]
151 #--------------------------------------------------------
152 - def format(self, with_indications=False, with_comment=False, with_reaction=False, date_format='%Y-%m-%d'):
153
154 lines = []
155
156 lines.append (u' %s: %s [%s]%s' % (
157 self._payload[self._idx['date_given']].strftime(date_format).decode(gmI18N.get_encoding()),
158 self._payload[self._idx['vaccine']],
159 self._payload[self._idx['batch_no']],
160 gmTools.coalesce(self._payload[self._idx['site']], u'', u' (%s)')
161 ))
162
163 if with_comment:
164 if self._payload[self._idx['comment']] is not None:
165 lines.append(u' %s' % self._payload[self._idx['comment']])
166
167 if with_reaction:
168 if self._payload[self._idx['reaction']] is not None:
169 lines.append(u' %s' % self._payload[self._idx['reaction']])
170
171 if with_indications:
172 lines.append(u' %s' % u' / '.join(self._payload[self._idx['indications']]))
173
174 return lines
175 #------------------------------------------------------------
177
178 cmd = u"""
179 INSERT INTO clin.vaccination (
180 fk_encounter,
181 fk_episode,
182 fk_vaccine,
183 batch_no
184 ) VALUES (
185 %(enc)s,
186 %(epi)s,
187 %(vacc)s,
188 %(batch)s
189 ) RETURNING pk;
190 """
191 args = {
192 u'enc': encounter,
193 u'epi': episode,
194 u'vacc': vaccine,
195 u'batch': batch_no
196 }
197
198 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True)
199
200 return cVaccination(aPK_obj = rows[0][0])
201 #------------------------------------------------------------
203 cmd = u"""DELETE FROM clin.vaccination WHERE pk = %(pk)s"""
204 args = {'pk': vaccination}
205
206 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
207 #============================================================
208 #============================================================
209 #============================================================
210 #============================================================
211 # old code
212 #============================================================
214 """Represents one missing vaccination.
215
216 - can be due or overdue
217 """
218 _cmd_fetch_payload = """
219 (select *, False as overdue
220 from clin.v_pat_missing_vaccs vpmv
221 where
222 pk_patient=%(pat_id)s
223 and
224 (select dob from dem.identity where pk=%(pat_id)s) between (now() - age_due_min) and (now() - coalesce(age_due_max, '115 years'::interval))
225 and
226 indication=%(indication)s
227 and
228 seq_no=%(seq_no)s
229 order by time_left)
230
231 UNION
232
233 (select *, True as overdue
234 from clin.v_pat_missing_vaccs vpmv
235 where
236 pk_patient=%(pat_id)s
237 and
238 now() - ((select dob from dem.identity where pk=%(pat_id)s)) > coalesce(age_due_max, '115 years'::interval)
239 and
240 indication=%(indication)s
241 and
242 seq_no=%(seq_no)s
243 order by amount_overdue)"""
244 _cmds_lock_rows_for_update = []
245 _cmds_store_payload = ["""select 1"""]
246 _updatable_fields = []
247 #--------------------------------------------------------
250 #--------------------------------------------------------
257 #============================================================
259 """Represents one due booster.
260 """
261 _cmd_fetch_payload = """
262 select *, now() - amount_overdue as latest_due
263 from clin.v_pat_missing_boosters vpmb
264 where
265 pk_patient=%(pat_id)s
266 and
267 indication=%(indication)s
268 order by amount_overdue"""
269 _cmds_lock_rows_for_update = []
270 _cmds_store_payload = ["""select 1"""]
271 _updatable_fields = []
272 #============================================================
274 """Represents one vaccination scheduled following a course.
275 """
276 _cmd_fetch_payload = u"select * from clin.v_vaccs_scheduled4pat where pk_vacc_def=%s"
277 _cmds_lock_rows_for_update = []
278 _cmds_store_payload = ["""select 1"""]
279 _updatable_fields = []
280 #============================================================
282 """Represents one vaccination course.
283 """
284 _cmd_fetch_payload = """
285 select *, xmin_vaccination_course from clin.v_vaccination_courses
286 where pk_course=%s"""
287 _cmds_lock_rows_for_update = [
288 """select 1 from clin.vaccination_course where id=%(pk_course)s and xmin=%(xmin_vaccination_course)s for update"""
289 ]
290 _cmds_store_payload = [
291 """update clin.vaccination_course set
292 name=%(course)s,
293 fk_recommended_by=%(pk_recommended_by)s,
294 fk_indication=(select id from clin.vacc_indication where description=%(indication)s),
295 comment=%(comment)s
296 where id=%(pk_course)s""",
297 """select xmin_vaccination_course from clin.v_vaccination_courses where pk_course=%(pk_course)s"""
298 ]
299 _updatable_fields = [
300 'course',
301 'pk_recommended_by',
302 'indication',
303 'comment'
304 ]
305 #============================================================
306 #============================================================
307 # convenience functions
308 #------------------------------------------------------------
309 -def create_vaccination_old(patient_id=None, episode_id=None, encounter_id=None, staff_id = None, vaccine=None):
310 # sanity check
311 # 1) any of the args being None should fail the SQL code
312 # 2) do episode/encounter belong to the patient ?
313 cmd = """
314 select pk_patient
315 from clin.v_pat_episodes
316 where pk_episode=%s
317 union
318 select pk_patient
319 from clin.v_pat_encounters
320 where pk_encounter=%s"""
321 rows = gmPG.run_ro_query('historica', cmd, None, episode_id, encounter_id)
322 if (rows is None) or (len(rows) == 0):
323 _log.error('error checking episode [%s] <-> encounter [%s] consistency' % (episode_id, encounter_id))
324 return (False, _('internal error, check log'))
325 if len(rows) > 1:
326 _log.error('episode [%s] and encounter [%s] belong to more than one patient !?!' % (episode_id, encounter_id))
327 return (False, _('consistency error, check log'))
328 # insert new vaccination
329 queries = []
330 if type(vaccine) == types.IntType:
331 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
332 values (%s, %s, %s, %s, %s)"""
333 else:
334 cmd = """insert into clin.vaccination (fk_encounter, fk_episode, fk_patient, fk_provider, fk_vaccine)
335 values (%s, %s, %s, %s, (select pk from clin.vaccine where trade_name=%s))"""
336 vaccine = str(vaccine)
337 queries.append((cmd, [encounter_id, episode_id, patient_id, staff_id, vaccine]))
338 # get PK of inserted row
339 cmd = "select currval('clin.vaccination_id_seq')"
340 queries.append((cmd, []))
341 result, msg = gmPG.run_commit('historica', queries, True)
342 if (result is None) or (len(result) == 0):
343 return (False, msg)
344 try:
345 vacc = cVaccination(aPK_obj = result[0][0])
346 except gmExceptions.ConstructorError:
347 _log.exception('cannot instantiate vaccination' % (result[0][0]), sys.exc_info, verbose=0)
348 return (False, _('internal error, check log'))
349
350 return (True, vacc)
351 #--------------------------------------------------------
353 # FIXME: use cVaccinationCourse
354 cmd = 'select name from clin.vaccination_course'
355 rows = gmPG.run_ro_query('historica', cmd)
356 if rows is None:
357 return None
358 if len(rows) == 0:
359 return []
360 data = []
361 for row in rows:
362 data.extend(rows)
363 return data
364 #--------------------------------------------------------
366 # check DbC, if it fails exception is due
367 int(pk_patient)
368
369 cmd = """
370 select fk_regime
371 from clin.lnk_pat2vacc_reg l
372 where l.fk_patient = %s""" % pk_patient
373
374 rows = gmPG.run_ro_query('historica', cmd)
375 active = []
376 if rows and len(rows):
377 active = [ r[0] for r in rows]
378
379 # FIXME: this is patient dependant so how would a cache
380 # FIXME: work that's not taking into account pk_patient ?
381 # recommended_regimes = VaccByRecommender._recommended_regimes
382 # if not clear_cache and recommended_regimes:
383 # return recommended_regimes, active
384
385 r = ( {}, [] )
386
387 # FIXME: use views ?
388 cmd = """
389 select
390 r.pk_regime ,
391 r.pk_recommended_by ,
392 r.indication,
393 r.regime ,
394 extract (epoch from d.min_age_due) /60/60/24,
395 extract (epoch from d.max_age_due) /60/60/24,
396 extract (epoch from d.min_interval ) /60/60/24,
397 d.seq_no
398 from
399 clin.v_vaccination_courses r, clin.vacc_def d
400 where
401 d.fk_regime = r.pk_regime
402 order by
403 r.pk_recommended_by, d.min_age_due"""
404 #print cmd
405 #import pdb
406 #pdb.set_trace()
407 #
408 rows = gmPG.run_ro_query('historica', cmd)
409 if rows is None:
410 VaccByRecommender._recommended_regimes = r
411 return r, active
412
413 row_fields = ['pk_regime', 'pk_recommender', 'indication' , 'regime', 'min_age_due', 'max_age_due', 'min_interval', 'seq_no' ]
414
415 for row in rows:
416 m = {}
417 for k, i in zip(row_fields, range(len(row))):
418 m[k] = row[i]
419 pk_recommender = m['pk_recommender']
420
421 if not pk_recommender in r[0].keys():
422 r[0][pk_recommender] = []
423 r[1].append(pk_recommender)
424 r[0][pk_recommender].append(m)
425
426 for k, v in r[0].items():
427 print k
428 for x in v:
429 print '\t', x
430
431 VaccByRecommender._recommended_regimes = r
432 return r, active
433 #--------------------------------------------------------
435 # DbC
436 int(pk_patient)
437
438 cmd = """
439 select
440 indication, regime,
441 pk_regime,
442 pk_recommended_by,
443 seq_no ,
444 extract(epoch from age_due_min) /60/60/24 as age_due_min,
445 extract(epoch from age_due_max) /60/60/24 as age_due_max,
446 extract(epoch from min_interval)/60/60/24 as min_interval
447 from
448 clin.v_pat_missing_vaccs
449 where pk_patient = %s
450 order by age_due_min, pk_recommended_by, indication
451 """ % pk_patient
452
453 rows = gmPG.run_ro_query('historica', cmd)
454
455 return rows
456 #--------------------------------------------------------
458 """Retrieves vaccination bundle indications list.
459
460 * vaccinations = list of any type of vaccination
461 - indicated
462 - due vacc
463 - overdue vaccs
464 - due boosters
465 - arbitrary
466 """
467 # FIXME: can we not achieve this by:
468 # [lambda [vacc['indication'], ['l10n_indication']] for vacc in vaccination_list]
469 # I think we could, but we would be lacking error handling
470 if vaccinations is None:
471 _log.error('list of vaccinations must be supplied')
472 return (False, [['ERROR: list of vaccinations not supplied', _('ERROR: list of vaccinations not supplied')]])
473 if len(vaccinations) == 0:
474 return (True, [['empty list of vaccinations', _('empty list of vaccinations')]])
475 inds = []
476 for vacc in vaccinations:
477 try:
478 inds.append([vacc['indication'], vacc['l10n_indication']])
479 except KeyError:
480 try:
481 inds.append([vacc['indication'], vacc['indication']])
482 except KeyError:
483 inds.append(['vacc -> ind error: %s' % str(vacc), _('vacc -> ind error: %s') % str(vacc)])
484 return (True, inds)
485 #--------------------------------------------------------
487 """
488 Schedules a vaccination course for a patient
489
490 * patient_id = Patient's PK
491 * course = course object or Vaccination course's PK
492 """
493 # FIXME: add method schedule_vaccination_course() to gmPerson.cPatient
494 if isinstance(course, cVaccinationCourse):
495 course_id = course['pk_course']
496 else:
497 course_id = course
498
499 # insert new patient - vaccination course relation
500 queries = []
501 cmd = """insert into clin.lnk_pat2vacc_reg (fk_patient, fk_course)
502 values (%s, %s)"""
503 queries.append((cmd, [patient_id, course_id]))
504 result, msg = gmPG.run_commit('historica', queries, True)
505 if result is None:
506 return (False, msg)
507 return (True, msg)
508 #--------------------------------------------------------
510 """unSchedules a vaccination course for a patient
511
512 * patient_id = Patient's PK
513 * course = course object or Vaccination course's PK
514 """
515 # FIXME: add method schedule_vaccination_course() to gmPerson.cPatient
516 if isinstance(course, cVaccinationCourse):
517 course_id = course['pk_course']
518 else:
519 course_id = course
520
521 # delete patient - vaccination course relation
522 queries = []
523 cmd = """delete from clin.lnk_pat2vacc_reg where fk_patient = %s and fk_course = %s"""
524
525 queries.append((cmd, [patient_id, course_id]))
526 result, msg = gmPG.run_commit('historica', queries, True)
527 if result is None:
528 return (False, msg)
529 return (True, msg)
530 #--------------------------------------------------------
532
533 quoted_inds = [ "'"+x + "%'" for x in all_ind]
534
535 # cmd_inds_per_vaccine = """
536 # select count(v.trade_name) , v.trade_name
537 # from
538 # clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
539 # where
540 # v.pk = l.fk_vaccine and l.fk_indication = i.id
541 # group
542 # by trade_name
543 # """
544
545 cmd_inds_per_vaccine = """
546 select
547 count(trade_name),
548 trade_name
549 from clin.v_inds4vaccine
550 group by trade_name"""
551
552 cmd_presence_in_vaccine = """
553 select count(v.trade_name) , v.trade_name
554
555 from
556 clin.vaccine v, clin.lnk_vaccine2inds l, clin.vacc_indication i
557 where
558 v.pk = l.fk_vaccine and l.fk_indication = i.id
559 and
560 i.description like any ( array [ %s ] )
561 group
562
563 by trade_name
564
565 """ % ', '.join( quoted_inds )
566
567 inds_per_vaccine = gmPG.run_ro_query( 'historica', cmd_inds_per_vaccine)
568
569 presence_in_vaccine = gmPG.run_ro_query( 'historica', cmd_presence_in_vaccine)
570
571 map_vacc_count_inds = dict ( [ (x[1], x[0]) for x in inds_per_vaccine ] )
572
573 matched_vaccines = []
574 for (presence, vaccine) in presence_in_vaccine:
575 if presence == len ( all_ind) :
576 # matched the number of indications selected with a vaccine
577 # is this also ALL the vaccine's indications ?
578 if map_vacc_count_inds[vaccine] == presence:
579 matched_vaccines.append(vaccine)
580 return matched_vaccines
581 #============================================================
582 # main - unit testing
583 #------------------------------------------------------------
584 if __name__ == '__main__':
585
586 if len(sys.argv) < 2:
587 sys.exit()
588
589 if sys.argv[1] != u'test':
590 sys.exit()
591
592 # from Gnumed.pycommon import gmPG
593 #--------------------------------------------------------
595 vacc = cVaccination(aPK_obj=1)
596 print vacc
597 fields = vacc.get_fields()
598 for field in fields:
599 print field, ':', vacc[field]
600 print "updatable:", vacc.get_updatable_fields()
601 #--------------------------------------------------------
603 # Test for a due vaccination
604 pk_args = {
605 'pat_id': 12,
606 'indication': 'meningococcus C',
607 'seq_no': 1
608 }
609 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
610 fields = missing_vacc.get_fields()
611 print "\nDue vaccination:"
612 print missing_vacc
613 for field in fields:
614 print field, ':', missing_vacc[field]
615 # Test for an overdue vaccination
616 pk_args = {
617 'pat_id': 12,
618 'indication': 'haemophilus influenzae b',
619 'seq_no': 2
620 }
621 missing_vacc = cMissingVaccination(aPK_obj=pk_args)
622 fields = missing_vacc.get_fields()
623 print "\nOverdue vaccination (?):"
624 print missing_vacc
625 for field in fields:
626 print field, ':', missing_vacc[field]
627 #--------------------------------------------------------
629 pk_args = {
630 'pat_id': 12,
631 'indication': 'tetanus'
632 }
633 missing_booster = cMissingBooster(aPK_obj=pk_args)
634 fields = missing_booster.get_fields()
635 print "\nDue booster:"
636 print missing_booster
637 for field in fields:
638 print field, ':', missing_booster[field]
639 #--------------------------------------------------------
641 scheduled_vacc = cScheduledVaccination(aPK_obj=20)
642 print "\nScheduled vaccination:"
643 print scheduled_vacc
644 fields = scheduled_vacc.get_fields()
645 for field in fields:
646 print field, ':', scheduled_vacc[field]
647 print "updatable:", scheduled_vacc.get_updatable_fields()
648 #--------------------------------------------------------
650 vaccination_course = cVaccinationCourse(aPK_obj=7)
651 print "\nVaccination course:"
652 print vaccination_course
653 fields = vaccination_course.get_fields()
654 for field in fields:
655 print field, ':', vaccination_course[field]
656 print "updatable:", vaccination_course.get_updatable_fields()
657 #--------------------------------------------------------
659 result, msg = put_patient_on_schedule(patient_id=12, course_id=1)
660 print '\nPutting patient id 12 on schedule id 1... %s (%s)' % (result, msg)
661 #--------------------------------------------------------
666
667 #--------------------------------------------------------
668 #test_vaccination_course()
669 #test_put_patient_on_schedule()
670 #test_scheduled_vacc()
671 #test_vacc()
672 #test_due_vacc()
673 #test_due_booster()
674
675 test_get_vaccines()
676 #============================================================
677
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 28 04:11:54 2010 | http://epydoc.sourceforge.net |