Package Gnumed :: Package business :: Module gmAllergy
[frames] | no frames]

Source Code for Module Gnumed.business.gmAllergy

  1  # -*- coding: utf-8 -*- 
  2  """GNUmed allergy related business object.""" 
  3  #============================================================ 
  4  __author__ = "Carlos Moro <cfmoro1976@yahoo.es>" 
  5  __license__ = "GPL v2 or later" 
  6   
  7  import types, sys, logging, datetime as pyDT 
  8   
  9   
 10  if __name__ == '__main__': 
 11          sys.path.insert(0, '../../') 
 12  from Gnumed.pycommon import gmPG2 
 13  from Gnumed.pycommon import gmI18N 
 14  from Gnumed.pycommon import gmBusinessDBObject 
 15  from Gnumed.pycommon import gmDateTime 
 16  from Gnumed.pycommon import gmTools 
 17   
 18   
 19  _log = logging.getLogger('gm.domain') 
 20  #============================================================ 
 21  # allergy state related code 
 22  #============================================================ 
 23  allergy_states = [ 
 24          None,           # unknown 
 25          0,                      # no allergies 
 26          1                       # some allergies 
 27  ] 
 28  #------------------------------------------------------------ 
29 -def ensure_has_allergy_state(encounter=None):
30 31 _log.debug('checking allergy state for identity of encounter [%s]', encounter) 32 33 args = {'enc': encounter} 34 cmd_create = """ 35 INSERT INTO clin.allergy_state ( 36 fk_encounter, 37 has_allergy 38 ) SELECT 39 %(enc)s, 40 NULL 41 WHERE NOT EXISTS ( 42 SELECT 1 FROM clin.v_pat_allergy_state 43 WHERE pk_patient = ( 44 SELECT fk_patient FROM clin.encounter WHERE pk = %(enc)s 45 ) 46 ) 47 """ 48 cmd_search = """ 49 SELECT pk_allergy_state FROM clin.v_pat_allergy_state 50 WHERE pk_patient = ( 51 SELECT fk_patient FROM clin.encounter WHERE pk = %(enc)s 52 ) 53 """ 54 rows, idx = gmPG2.run_rw_queries ( 55 queries = [ 56 {'cmd': cmd_create, 'args': args}, 57 {'cmd': cmd_search, 'args': args} 58 ], 59 return_data = True 60 ) 61 62 return cAllergyState(aPK_obj = rows[0][0])
63 64 #------------------------------------------------------------
65 -class cAllergyState(gmBusinessDBObject.cBusinessDBObject):
66 """Represents the allergy state of one patient.""" 67 68 _cmd_fetch_payload = "select * from clin.v_pat_allergy_state where pk_allergy_state = %s" 69 _cmds_store_payload = [ 70 """update clin.allergy_state set 71 last_confirmed = %(last_confirmed)s, 72 has_allergy = %(has_allergy)s, 73 comment = gm.nullify_empty_string(%(comment)s) 74 where 75 pk = %(pk_allergy_state)s and 76 xmin = %(xmin_allergy_state)s""", 77 """select xmin_allergy_state from clin.v_pat_allergy_state where pk_allergy_state = %(pk_allergy_state)s""" 78 ] 79 _updatable_fields = [ 80 'last_confirmed', # special value u'now' will set to datetime.datetime.now() in the local time zone 81 'has_allergy', # verified against allergy_states (see above) 82 'comment' # u'' maps to None / NULL 83 ] 84 85 #--------------------------------------------------------
86 - def format_maximum_information(self, patient=None):
87 lines = [] 88 lines.append('%s (%s)' % ( 89 self.state_string, 90 gmDateTime.pydt_strftime(self['last_confirmed'], '%Y %b %d', none_str = '?') 91 )) 92 if self._payload[self._idx['comment']] is not None: 93 lines.append(' %s' % self._payload[self._idx['comment']]) 94 return lines
95 96 #-------------------------------------------------------- 97 # properties 98 #--------------------------------------------------------
99 - def _get_as_string(self):
100 if self._payload[self._idx['has_allergy']] is None: 101 return _('unknown allergy state') 102 if self._payload[self._idx['has_allergy']] == 0: 103 return _('no known allergies') 104 if self._payload[self._idx['has_allergy']] == 1: 105 return _('*does* have allergies') 106 _log.error('unknown allergy state [%s]', self._payload[self._idx['has_allergy']]) 107 return _('ERROR: unknown allergy state [%s]') % self._payload[self._idx['has_allergy']]
108
109 - def _set_string(self, value):
110 raise AttributeError('invalid to set allergy state string')
111 112 state_string = property(_get_as_string, _set_string) 113 114 #--------------------------------------------------------
115 - def _get_as_symbol(self):
116 if self._payload[self._idx['has_allergy']] is None: 117 if self._payload[self._idx['comment']] is None: 118 return '?' 119 else: 120 return '?!' 121 if self._payload[self._idx['has_allergy']] == 0: 122 if self._payload[self._idx['comment']] is None: 123 return '\u2300' 124 else: 125 return '\u2300!' 126 if self._payload[self._idx['has_allergy']] == 1: 127 return '!' 128 _log.error('unknown allergy state [%s]', self._payload[self._idx['has_allergy']]) 129 return _('ERROR: unknown allergy state [%s]') % self._payload[self._idx['has_allergy']]
130 131 state_symbol = property(_get_as_symbol, lambda x:x) 132 133 #--------------------------------------------------------
134 - def _get_as_amts_latex(self, strict=True):
135 table_rows = [] 136 # Trennzeile als leere Zeile für bessere Lesbarkeit 137 table_rows.append('\\multicolumn{11}{l}{}\\tabularnewline') 138 # Zwischenüberschrift: 31 Zeichen, $..., 14pt, no frame, \textwidth 139 state = '%s (%s)' % ( 140 self.state_string, 141 gmDateTime.pydt_strftime(self['last_confirmed'], '%b %Y', none_str = '?') 142 ) 143 if strict: 144 state = state[:31] 145 table_rows.append('\\multicolumn{11}{>{\\RaggedRight}p{27.9cm}}{\\rule{0pt}{4.5mm} \\fontsize{14pt}{16pt}\selectfont %s\label{AnchorAllergieDetails}}\\tabularnewline' % gmTools.tex_escape_string(state)) 146 # Freitextzeile: 200 Zeichen, @..., \textwidth 147 if self['comment'] is not None: 148 if strict: 149 cmt = self['comment'].strip()[:200] 150 else: 151 cmt = self['comment'].strip() 152 table_rows.append('\\multicolumn{11}{>{\\RaggedRight}p{27.9cm}}{%s}\\tabularnewline') % gmTools.tex_escape_string(cmt) 153 return table_rows
154 155 as_amts_latex = property(_get_as_amts_latex, lambda x:x) 156 157 #--------------------------------------------------------
158 - def _get_as_amts_data_v_2_0(self, strict=True):
159 lines = [] 160 # Trennzeile für bessere Lesbarkeit als leere Zwischenüberschrift 161 lines.append('$ ') 162 # Zwischenüberschrift: 31 Zeichen, $..., \textwidth 163 txt = '$%s (%s)' % ( 164 self.state_string, 165 gmDateTime.pydt_strftime(self['last_confirmed'], '%b %Y', none_str = '?') 166 ) 167 if strict: 168 lines.append(txt[:32]) 169 else: 170 lines.append(txt) 171 # Freitextzeile: 200 Zeichen, @..., \textwidth 172 if self['comment'] is not None: 173 if strict: 174 lines.append('@%s' % self['comment'][:200]) 175 else: 176 lines.append('@%s' % self['comment']) 177 return lines
178 179 #--------------------------------------------------------
180 - def _get_as_amts_data(self, strict=True):
181 # Zwischenüberschrift 182 state = '%s (%s)' % (self.state_string, gmDateTime.pydt_strftime(self['last_confirmed'], '%b %Y', none_str = '?')) 183 if strict: 184 state = state[:32] 185 # Freitextzeile 186 if self['comment'] is None: 187 comment = '' 188 else: 189 comment = '<X t="%s"/>' % self['comment'] 190 if strict: 191 comment = '<X t="%s"/>' % self['comment'][:200] 192 return '<S t="%s">%s%%s</S>' % (state, comment)
193 194 as_amts_data = property(_get_as_amts_data, lambda x:x) 195 196 #--------------------------------------------------------
197 - def __setitem__(self, attribute, value):
198 if attribute == 'comment': 199 if value is not None: 200 if value.strip() == '': 201 value = None 202 203 elif attribute == 'last_confirmed': 204 if value == 'now': 205 value = pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone) 206 207 elif attribute == 'has_allergy': 208 if value not in allergy_states: 209 raise ValueError('invalid allergy state [%s]' % value) 210 211 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
212 213 #============================================================
214 -class cAllergy(gmBusinessDBObject.cBusinessDBObject):
215 """Represents one allergy item. 216 217 Actually, those things are really things to "avoid". 218 Allergy is just one of several reasons for that. 219 See Adrian's post on gm-dev. 220 221 Another word might be Therapeutic Precautions. 222 """ 223 _cmd_fetch_payload = "SELECT * FROM clin.v_pat_allergies WHERE pk_allergy = %s" 224 _cmds_store_payload = [ 225 """UPDATE clin.allergy SET 226 clin_when = %(date)s, 227 substance = %(substance)s, 228 substance_code = %(substance_code)s, 229 generics = %(generics)s, 230 allergene = %(allergene)s, 231 atc_code = %(atc_code)s, 232 fk_type = %(pk_type)s, 233 generic_specific = %(generic_specific)s::boolean, 234 definite = %(definite)s::boolean, 235 narrative = %(reaction)s 236 WHERE 237 pk = %(pk_allergy)s AND 238 xmin = %(xmin_allergy)s""", 239 """SELECT xmin_allergy FROM clin.v_pat_allergies WHERE pk_allergy=%(pk_allergy)s""" 240 ] 241 _updatable_fields = [ 242 'date', 243 'substance', 244 'substance_code', 245 'generics', 246 'allergene', 247 'atc_code', 248 'pk_type', 249 'generic_specific', 250 'definite', 251 'reaction' 252 ] 253 #--------------------------------------------------------
254 - def format_maximum_information(self, patient=None):
255 lines = [] 256 lines.append('%s%s: %s [#%s]' % ( 257 self._payload[self._idx['l10n_type']], 258 gmTools.bool2subst ( 259 self._payload[self._idx['definite']], 260 ' (%s)' % _('definite'), 261 ' (%s)' % _('indefinite'), 262 '' 263 ), 264 self._payload[self._idx['descriptor']], 265 self._payload[self._idx['pk_allergy']] 266 )) 267 if self._payload[self._idx['reaction']] is not None: 268 lines.append(' ' + _('Reaction:') + ' ' + self._payload[self._idx['reaction']]) 269 if self._payload[self._idx['date']] is not None: 270 lines.append(' ' + _('Noted:') + ' ' + gmDateTime.pydt_strftime(self._payload[self._idx['date']], '%Y %b %d')) 271 if self._payload[self._idx['allergene']] is not None: 272 lines.append(' ' + _('Allergene:') + ' ' + self._payload[self._idx['allergene']]) 273 if self._payload[self._idx['substance']] is not None: 274 lines.append(' ' + _('Substance:') + ' ' + self._payload[self._idx['substance']]) 275 if self._payload[self._idx['substance_code']] is not None: 276 lines.append(' ' + _('Code:') + ' ' + self._payload[self._idx['substance_code']]) 277 if self._payload[self._idx['atc_code']] is not None: 278 lines.append(' ' + _('ATC:') + ' ' + self._payload[self._idx['atc_code']]) 279 lines.append(' ' + _('Specific to:') + ' ' + gmTools.bool2subst ( 280 self._payload[self._idx['generic_specific']], 281 _('this substance only'), 282 _('drug class'), 283 _('unknown') 284 )) 285 if self._payload[self._idx['generics']] is not None: 286 lines.append(' ' + _('Generics:') + ' ' + self._payload[self._idx['generics']]) 287 288 return lines
289 290 #--------------------------------------------------------
291 - def __setitem__(self, attribute, value):
292 if attribute == 'pk_type': 293 if value in ['allergy', 'sensitivity']: 294 cmd = 'select pk from clin._enum_allergy_type where value=%s' 295 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [value]}]) 296 value = rows[0][0] 297 298 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
299 300 #--------------------------------------------------------
301 - def _get_as_amts_latex(self, strict=True):
302 # Freitextzeile: 200 Zeichen, @... 303 cells = ['\\multicolumn{1}{>{\\RaggedRight}p{4cm}}{%s}' % gmTools.tex_escape_string(self['descriptor'])] 304 txt = '%s%s' % ( 305 self['l10n_type'], 306 gmTools.coalesce(self['reaction'], '', ': %s') 307 ) 308 if strict: 309 txt = txt[:(200-len(self['descriptor']))] 310 cells.append('\\multicolumn{10}{>{\\RaggedRight}p{23.9cm}}{%s}' % gmTools.tex_escape_string(txt)) 311 table_row = ' & '.join(cells) 312 table_row += '\\tabularnewline' 313 return table_row
314 315 as_amts_latex = property(_get_as_amts_latex, lambda x:x) 316 317 #--------------------------------------------------------
318 - def _get_as_amts_data_v_2_0(self, strict=True):
319 # Freitextzeile: 200 Zeichen, @..., \textwidth 320 txt = '@%s %s%s' % ( 321 self['descriptor'], 322 self['l10n_type'], 323 gmTools.coalesce(self['reaction'], '', ': %s') 324 ) 325 if strict: 326 return txt[:200] 327 return txt
328 329 #--------------------------------------------------------
330 - def _get_as_amts_data(self, strict=True):
331 txt = '%s %s%s' % ( 332 self['descriptor'], 333 self['l10n_type'], 334 gmTools.coalesce(self['reaction'], '', ': %s') 335 ) 336 if strict: 337 txt = txt[:200] 338 # Freitextzeile: 200 Zeichen 339 return '<X t="%s"/>' % txt
340 341 as_amts_data = property(_get_as_amts_data, lambda x:x)
342 343 #============================================================ 344 # convenience functions 345 #------------------------------------------------------------
346 -def create_allergy(allergene=None, allg_type=None, episode_id=None, encounter_id=None):
347 """Creates a new allergy clinical item. 348 349 allergene - allergic substance 350 allg_type - allergy or sensitivity, pk or string 351 encounter_id - encounter's primary key 352 episode_id - episode's primary key 353 """ 354 cmd = """ 355 SELECT pk_allergy 356 FROM clin.v_pat_allergies 357 WHERE 358 pk_patient = (SELECT fk_patient FROM clin.encounter WHERE pk = %(enc)s) 359 AND 360 allergene = %(allergene)s 361 """ 362 #args = {'enc': encounter_id, 'substance': substance} 363 args = {'enc': encounter_id, 'allergene': allergene} 364 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 365 if len(rows) > 0: 366 # don't implicitely change existing data 367 return cAllergy(aPK_obj = rows[0][0]) 368 369 # insert new allergy 370 queries = [] 371 372 if type(allg_type) == int: 373 cmd = """ 374 insert into clin.allergy (fk_type, fk_encounter, fk_episode, allergene, substance) 375 values (%s, %s, %s, %s, %s)""" 376 else: 377 cmd = """ 378 insert into clin.allergy (fk_type, fk_encounter, fk_episode, allergene, substance) 379 values ((select pk from clin._enum_allergy_type where value = %s), %s, %s, %s, %s)""" 380 queries.append({'cmd': cmd, 'args': [allg_type, encounter_id, episode_id, allergene, allergene]}) 381 382 cmd = "select currval('clin.allergy_id_seq')" 383 queries.append({'cmd': cmd}) 384 385 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True) 386 allergy = cAllergy(aPK_obj = rows[0][0]) 387 388 return allergy
389 390 #============================================================ 391 # main - unit testing 392 #------------------------------------------------------------ 393 if __name__ == '__main__': 394 395 allg = cAllergy(aPK_obj=1) 396 print(allg) 397 fields = allg.get_fields() 398 for field in fields: 399 print(field, ':', allg[field]) 400 print("updatable:", allg.get_updatable_fields()) 401 enc_id = allg['pk_encounter'] 402 epi_id = allg['pk_episode'] 403 status, allg = create_allergy ( 404 allergene = 'test substance', 405 allg_type = 1, 406 episode_id = epi_id, 407 encounter_id = enc_id 408 ) 409 print(allg) 410 allg['reaction'] = 'hehehe' 411 status, data = allg.save_payload() 412 print('status:', status) 413 print('data:', data) 414 print(allg) 415