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

Source Code for Module Gnumed.business.gmPerson

   1  # -*- coding: utf8 -*- 
   2  """GNUmed patient objects. 
   3   
   4  This is a patient object intended to let a useful client-side 
   5  API crystallize from actual use in true XP fashion. 
   6  """ 
   7  #============================================================ 
   8  __version__ = "$Revision: 1.198 $" 
   9  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
  10  __license__ = "GPL" 
  11   
  12  # std lib 
  13  import sys, os.path, time, re as regex, string, types, datetime as pyDT, codecs, threading, logging 
  14   
  15   
  16  # GNUmed 
  17  if __name__ == '__main__': 
  18          sys.path.insert(0, '../../') 
  19  from Gnumed.pycommon import gmExceptions, gmDispatcher, gmBorg, gmI18N, gmNull, gmBusinessDBObject, gmTools 
  20  from Gnumed.pycommon import gmPG2, gmMatchProvider, gmDateTime, gmLog2 
  21  from Gnumed.business import gmDocuments, gmDemographicRecord, gmProviderInbox, gmXdtMappings, gmClinicalRecord 
  22   
  23   
  24  _log = logging.getLogger('gm.person') 
  25  _log.info(__version__) 
  26   
  27  __gender_list = None 
  28  __gender_idx = None 
  29   
  30  __gender2salutation_map = None 
  31   
  32  #============================================================ 
33 -class cDTO_person(object):
34 35 # FIXME: make this work as a mapping type, too 36 37 #-------------------------------------------------------- 38 # external API 39 #--------------------------------------------------------
40 - def keys(self):
41 return 'firstnames lastnames dob gender'.split()
42 #--------------------------------------------------------
43 - def delete_from_source(self):
44 pass
45 #--------------------------------------------------------
46 - def get_candidate_identities(self, can_create=False):
47 """Generate generic queries. 48 49 - not locale dependant 50 - data -> firstnames, lastnames, dob, gender 51 52 shall we mogrify name parts ? probably not as external 53 sources should know what they do 54 55 finds by inactive name, too, but then shows 56 the corresponding active name ;-) 57 58 Returns list of matching identities (may be empty) 59 or None if it was told to create an identity but couldn't. 60 """ 61 where_snippets = [] 62 args = {} 63 64 where_snippets.append(u'firstnames = %(first)s') 65 args['first'] = self.firstnames 66 67 where_snippets.append(u'lastnames = %(last)s') 68 args['last'] = self.lastnames 69 70 if self.dob is not None: 71 where_snippets.append(u"dem.date_trunc_utc('day'::text, dob) = dem.date_trunc_utc('day'::text, %(dob)s)") 72 args['dob'] = self.dob 73 74 if self.gender is not None: 75 where_snippets.append('gender = %(sex)s') 76 args['sex'] = self.gender 77 78 cmd = u""" 79 select *, '%s' as match_type from dem.v_basic_person 80 where pk_identity in ( 81 select id_identity from dem.names where %s 82 ) order by lastnames, firstnames, dob""" % ( 83 _('external patient source (name, gender, date of birth)'), 84 ' and '.join(where_snippets) 85 ) 86 87 try: 88 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx=True) 89 except: 90 _log.error(u'cannot get candidate identities for dto "%s"' % self) 91 _log.exception('query %s' % cmd) 92 rows = [] 93 94 if len(rows) == 0: 95 if not can_create: 96 return [] 97 ident = self.import_into_database() 98 if ident is None: 99 return None 100 identities = [ident] 101 else: 102 identities = [ cIdentity(row = {'pk_field': 'pk_identity', 'data': row, 'idx': idx}) for row in rows ] 103 104 return identities
105 #--------------------------------------------------------
106 - def import_into_database(self):
107 """Imports self into the database. 108 109 Child classes can override this to provide more extensive import. 110 """ 111 ident = create_identity ( 112 firstnames = self.firstnames, 113 lastnames = self.lastnames, 114 gender = self.gender, 115 dob = self.dob 116 ) 117 return ident
118 #--------------------------------------------------------
119 - def import_extra_data(self, *args, **kwargs):
120 pass
121 #-------------------------------------------------------- 122 # customizing behaviour 123 #--------------------------------------------------------
124 - def __str__(self):
125 return u'<%s @ %s: %s %s (%s) %s>' % ( 126 self.__class__.__name__, 127 id(self), 128 self.firstnames, 129 self.lastnames, 130 self.gender, 131 self.dob 132 )
133 #--------------------------------------------------------
134 - def __setattr__(self, attr, val):
135 """Do some sanity checks on self.* access.""" 136 137 if attr == 'gender': 138 glist, idx = get_gender_list() 139 for gender in glist: 140 if str(val) in [gender[0], gender[1], gender[2], gender[3]]: 141 val = gender[idx['tag']] 142 object.__setattr__(self, attr, val) 143 return 144 raise ValueError('invalid gender: [%s]' % val) 145 146 if attr == 'dob': 147 if val is not None: 148 if not isinstance(val, pyDT.datetime): 149 raise TypeError('invalid type for DOB (must be datetime.datetime): %s [%s]' % (type(val), val)) 150 if val.tzinfo is None: 151 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % val.isoformat()) 152 153 object.__setattr__(self, attr, val) 154 return
155 #--------------------------------------------------------
156 - def __getitem__(self, attr):
157 return getattr(self, attr)
158 #============================================================
159 -class cPersonName(gmBusinessDBObject.cBusinessDBObject):
160 _cmd_fetch_payload = u"select * from dem.v_person_names where pk_name = %s" 161 _cmds_store_payload = [ 162 u"""update dem.names set 163 active = False 164 where 165 %(active_name)s is True and -- act only when needed and only 166 id_identity = %(pk_identity)s and -- on names of this identity 167 active is True and -- which are active 168 id != %(pk_name)s -- but NOT *this* name 169 """, 170 u"""update dem.names set 171 active = %(active_name)s, 172 preferred = %(preferred)s, 173 comment = %(comment)s 174 where 175 id = %(pk_name)s and 176 id_identity = %(pk_identity)s and -- belt and suspenders 177 xmin = %(xmin_name)s""", 178 u"""select xmin as xmin_name from dem.names where id = %(pk_name)s""" 179 ] 180 _updatable_fields = ['active_name', 'preferred', 'comment'] 181 #--------------------------------------------------------
182 - def __setitem__(self, attribute, value):
183 if attribute == 'active_name': 184 # cannot *directly* deactivate a name, only indirectly 185 # by activating another one 186 # FIXME: should be done at DB level 187 if self._payload[self._idx['active_name']] is True: 188 return 189 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
190 #--------------------------------------------------------
191 - def _get_description(self):
192 return '%(last)s, %(title)s %(first)s%(nick)s' % { 193 'last': self._payload[self._idx['lastnames']], 194 'title': gmTools.coalesce ( 195 self._payload[self._idx['title']], 196 map_gender2salutation(self._payload[self._idx['gender']]) 197 ), 198 'first': self._payload[self._idx['firstnames']], 199 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' "%s"', u'%s') 200 }
201 202 description = property(_get_description, lambda x:x)
203 #============================================================
204 -class cStaff(gmBusinessDBObject.cBusinessDBObject):
205 _cmd_fetch_payload = u"select * from dem.v_staff where pk_staff=%s" 206 _cmds_store_payload = [ 207 u"""update dem.staff set 208 fk_role = %(pk_role)s, 209 short_alias = %(short_alias)s, 210 comment = gm.nullify_empty_string(%(comment)s), 211 is_active = %(is_active)s, 212 db_user = %(db_user)s 213 where 214 pk=%(pk_staff)s and 215 xmin = %(xmin_staff)s""", 216 u"""select xmin_staff from dem.v_staff where pk_identity=%(pk_identity)s""" 217 ] 218 _updatable_fields = ['pk_role', 'short_alias', 'comment', 'is_active', 'db_user'] 219 #--------------------------------------------------------
220 - def __init__(self, aPK_obj=None, row=None):
221 # by default get staff corresponding to CURRENT_USER 222 if (aPK_obj is None) and (row is None): 223 cmd = u"select * from dem.v_staff where db_user = CURRENT_USER" 224 try: 225 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True) 226 except: 227 _log.exception('cannot instantiate staff instance') 228 gmLog2.log_stack_trace() 229 raise ValueError('cannot instantiate staff instance for database account CURRENT_USER') 230 if len(rows) == 0: 231 raise ValueError('no staff record for database account CURRENT_USER') 232 row = { 233 'pk_field': 'pk_staff', 234 'idx': idx, 235 'data': rows[0] 236 } 237 gmBusinessDBObject.cBusinessDBObject.__init__(self, row = row) 238 else: 239 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj = aPK_obj, row = row) 240 241 # are we SELF ? 242 self.__is_current_user = (gmPG2.get_current_user() == self._payload[self._idx['db_user']]) 243 244 self.__inbox = None
245 #--------------------------------------------------------
246 - def __setitem__(self, attribute, value):
247 if attribute == 'db_user': 248 if self.__is_current_user: 249 _log.debug('will not modify database account association of CURRENT_USER staff member') 250 return 251 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
252 #--------------------------------------------------------
253 - def _get_db_lang(self):
254 rows, idx = gmPG2.run_ro_queries ( 255 queries = [{ 256 'cmd': u'select i18n.get_curr_lang(%(usr)s)', 257 'args': {'usr': self._payload[self._idx['db_user']]} 258 }] 259 ) 260 return rows[0][0]
261
262 - def _set_db_lang(self, language):
263 if not gmPG2.set_user_language(language = language): 264 raise ValueError ( 265 u'Cannot set database language to [%s] for user [%s].' % (language, self._payload[self._idx['db_user']]) 266 ) 267 return
268 269 database_language = property(_get_db_lang, _set_db_lang) 270 #--------------------------------------------------------
271 - def _get_inbox(self):
272 if self.__inbox is None: 273 self.__inbox = gmProviderInbox.cProviderInbox(provider_id = self._payload[self._idx['pk_staff']]) 274 return self.__inbox
275
276 - def _set_inbox(self, inbox):
277 return
278 279 inbox = property(_get_inbox, _set_inbox)
280 #============================================================
281 -def set_current_provider_to_logged_on_user():
282 gmCurrentProvider(provider = cStaff())
283 #============================================================
284 -class gmCurrentProvider(gmBorg.cBorg):
285 """Staff member Borg to hold currently logged on provider. 286 287 There may be many instances of this but they all share state. 288 """
289 - def __init__(self, provider=None):
290 """Change or get currently logged on provider. 291 292 provider: 293 * None: get copy of current instance 294 * cStaff instance: change logged on provider (role) 295 """ 296 # make sure we do have a provider pointer 297 try: 298 self.provider 299 except AttributeError: 300 self.provider = gmNull.cNull() 301 302 # user wants copy of currently logged on provider 303 if provider is None: 304 return None 305 306 # must be cStaff instance, then 307 if not isinstance(provider, cStaff): 308 raise ValueError, 'cannot set logged on provider to [%s], must be either None or cStaff instance' % str(provider) 309 310 # same ID, no change needed 311 if self.provider['pk_staff'] == provider['pk_staff']: 312 return None 313 314 # first invocation 315 if isinstance(self.provider, gmNull.cNull): 316 self.provider = provider 317 return None 318 319 # user wants different provider 320 raise ValueError, 'provider change [%s] -> [%s] not yet supported' % (self.provider['pk_staff'], provider['pk_staff'])
321 322 #--------------------------------------------------------
323 - def get_staff(self):
324 return self.provider
325 #-------------------------------------------------------- 326 # __getitem__ handling 327 #--------------------------------------------------------
328 - def __getitem__(self, aVar):
329 """Return any attribute if known how to retrieve it by proxy. 330 """ 331 return self.provider[aVar]
332 #-------------------------------------------------------- 333 # __s/getattr__ handling 334 #--------------------------------------------------------
335 - def __getattr__(self, attribute):
336 if attribute == 'provider': # so we can __init__ ourselves 337 raise AttributeError 338 if not isinstance(self.provider, gmNull.cNull): 339 return getattr(self.provider, attribute)
340 # raise AttributeError 341 #============================================================
342 -class cIdentity(gmBusinessDBObject.cBusinessDBObject):
343 _cmd_fetch_payload = u"select * from dem.v_basic_person where pk_identity = %s" 344 _cmds_store_payload = [ 345 u"""update dem.identity set 346 gender = %(gender)s, 347 dob = %(dob)s, 348 tob = %(tob)s, 349 cob = gm.nullify_empty_string(%(cob)s), 350 title = gm.nullify_empty_string(%(title)s), 351 fk_marital_status = %(pk_marital_status)s, 352 karyotype = gm.nullify_empty_string(%(karyotype)s), 353 pupic = gm.nullify_empty_string(%(pupic)s), 354 deceased = %(deceased)s, 355 emergency_contact = gm.nullify_empty_string(%(emergency_contact)s), 356 fk_emergency_contact = %(pk_emergency_contact)s, 357 fk_primary_provider = %(pk_primary_provider)s, 358 comment = gm.nullify_empty_string(%(comment)s) 359 where 360 pk = %(pk_identity)s and 361 xmin = %(xmin_identity)s""", 362 u"""select xmin_identity from dem.v_basic_person where pk_identity = %(pk_identity)s""" 363 ] 364 _updatable_fields = [ 365 "title", 366 "dob", 367 "tob", 368 "cob", 369 "gender", 370 "pk_marital_status", 371 "karyotype", 372 "pupic", 373 'deceased', 374 'emergency_contact', 375 'pk_emergency_contact', 376 'pk_primary_provider', 377 'comment' 378 ] 379 #--------------------------------------------------------
380 - def _get_ID(self):
381 return self._payload[self._idx['pk_identity']]
382 - def _set_ID(self, value):
383 raise AttributeError('setting ID of identity is not allowed')
384 ID = property(_get_ID, _set_ID) 385 #--------------------------------------------------------
386 - def __setitem__(self, attribute, value):
387 388 if attribute == 'dob': 389 if value is not None: 390 391 if isinstance(value, pyDT.datetime): 392 if value.tzinfo is None: 393 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % dt.isoformat()) 394 else: 395 raise TypeError, '[%s]: type [%s] (%s) invalid for attribute [dob], must be datetime.datetime or None' % (self.__class__.__name__, type(value), value) 396 397 # compare DOB at seconds level 398 if self._payload[self._idx['dob']] is not None: 399 old_dob = self._payload[self._idx['dob']].strftime('%Y %m %d %H %M %S') 400 new_dob = value.strftime('%Y %m %d %H %M %S') 401 if new_dob == old_dob: 402 return 403 404 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
405 #--------------------------------------------------------
406 - def cleanup(self):
407 pass
408 #--------------------------------------------------------
409 - def _get_is_patient(self):
410 cmd = u""" 411 select exists ( 412 select 1 413 from clin.v_emr_journal 414 where 415 pk_patient = %(pat)s 416 and 417 soap_cat is not null 418 )""" 419 args = {'pat': self._payload[self._idx['pk_identity']]} 420 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 421 return rows[0][0]
422
423 - def _set_is_patient(self, value):
424 raise AttributeError('setting is_patient status of identity is not allowed')
425 426 is_patient = property(_get_is_patient, _set_is_patient) 427 #-------------------------------------------------------- 428 # identity API 429 #--------------------------------------------------------
430 - def get_active_name(self):
431 for name in self.get_names(): 432 if name['active_name'] is True: 433 return name 434 435 _log.error('cannot retrieve active name for patient [%s]' % self._payload[self._idx['pk_identity']]) 436 return None
437 #--------------------------------------------------------
438 - def get_names(self):
439 cmd = u"select * from dem.v_person_names where pk_identity = %(pk_pat)s" 440 rows, idx = gmPG2.run_ro_queries ( 441 queries = [{ 442 'cmd': cmd, 443 'args': {'pk_pat': self._payload[self._idx['pk_identity']]} 444 }], 445 get_col_idx = True 446 ) 447 448 if len(rows) == 0: 449 # no names registered for patient 450 return [] 451 452 names = [ cPersonName(row = {'idx': idx, 'data': r, 'pk_field': 'pk_name'}) for r in rows ] 453 return names
454 #--------------------------------------------------------
455 - def get_formatted_dob(self, format='%x', encoding=None):
456 if self._payload[self._idx['dob']] is None: 457 return _('** DOB unknown **') 458 459 if encoding is None: 460 encoding = gmI18N.get_encoding() 461 462 return self._payload[self._idx['dob']].strftime(format).decode(encoding)
463 #--------------------------------------------------------
464 - def get_description_gender(self):
465 return '%(sex)s%(title)s %(last)s, %(first)s%(nick)s' % { 466 'last': self._payload[self._idx['lastnames']], 467 'first': self._payload[self._idx['firstnames']], 468 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s'), 469 'sex': map_gender2salutation(self._payload[self._idx['gender']]), 470 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s') 471 }
472 #--------------------------------------------------------
473 - def get_description(self):
474 return '%(last)s,%(title)s %(first)s%(nick)s' % { 475 'last': self._payload[self._idx['lastnames']], 476 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s'), 477 'first': self._payload[self._idx['firstnames']], 478 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s') 479 }
480 #--------------------------------------------------------
481 - def add_name(self, firstnames, lastnames, active=True):
482 """Add a name. 483 484 @param firstnames The first names. 485 @param lastnames The last names. 486 @param active When True, the new name will become the active one (hence setting other names to inactive) 487 @type active A types.BooleanType instance 488 """ 489 name = create_name(self.ID, firstnames, lastnames, active) 490 if active: 491 self.refetch_payload() 492 return name
493 #--------------------------------------------------------
494 - def delete_name(self, name=None):
495 cmd = u"delete from dem.names where id = %(name)s and id_identity = %(pat)s" 496 args = {'name': name['pk_name'], 'pat': self.ID} 497 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
498 # can't have been the active name as that would raise an 499 # exception (since no active name would be left) so no 500 # data refetch needed 501 #--------------------------------------------------------
502 - def set_nickname(self, nickname=None):
503 """ 504 Set the nickname. Setting the nickname only makes sense for the currently 505 active name. 506 @param nickname The preferred/nick/warrior name to set. 507 """ 508 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': u"select dem.set_nickname(%s, %s)", 'args': [self.ID, nickname]}]) 509 self.refetch_payload() 510 return True
511 #-------------------------------------------------------- 512 # external ID API 513 # 514 # since external IDs are not treated as first class 515 # citizens (classes in their own right, that is), we 516 # handle them *entirely* within cIdentity, also they 517 # only make sense with one single person (like names) 518 # and are not reused (like addresses), so they are 519 # truly added/deleted, not just linked/unlinked 520 #--------------------------------------------------------
521 - def add_external_id(self, type_name=None, value=None, issuer=None, comment=None, pk_type=None):
522 """Adds an external ID to the patient. 523 524 creates ID type if necessary 525 """ 526 527 # check for existing ID 528 if pk_type is not None: 529 cmd = u""" 530 select * from dem.v_external_ids4identity where 531 pk_identity = %(pat)s and 532 pk_type = %(pk_type)s and 533 value = %(val)s""" 534 else: 535 # by type/value/issuer 536 if issuer is None: 537 cmd = u""" 538 select * from dem.v_external_ids4identity where 539 pk_identity = %(pat)s and 540 name = %(name)s and 541 value = %(val)s""" 542 else: 543 cmd = u""" 544 select * from dem.v_external_ids4identity where 545 pk_identity = %(pat)s and 546 name = %(name)s and 547 value = %(val)s and 548 issuer = %(issuer)s""" 549 args = { 550 'pat': self.ID, 551 'name': type_name, 552 'val': value, 553 'issuer': issuer, 554 'pk_type': pk_type 555 } 556 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 557 558 # create new ID if not found 559 if len(rows) == 0: 560 561 args = { 562 'pat': self.ID, 563 'val': value, 564 'type_name': type_name, 565 'pk_type': pk_type, 566 'issuer': issuer, 567 'comment': comment 568 } 569 570 if pk_type is None: 571 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values ( 572 %(val)s, 573 (select dem.add_external_id_type(%(type_name)s, %(issuer)s)), 574 %(comment)s, 575 %(pat)s 576 )""" 577 else: 578 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values ( 579 %(val)s, 580 %(pk_type)s, 581 %(comment)s, 582 %(pat)s 583 )""" 584 585 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 586 587 # or update comment of existing ID 588 else: 589 row = rows[0] 590 if comment is not None: 591 # comment not already there ? 592 if gmTools.coalesce(row['comment'], '').find(comment.strip()) == -1: 593 comment = '%s%s' % (gmTools.coalesce(row['comment'], '', '%s // '), comment.strip) 594 cmd = u"update dem.lnk_identity2ext_id set comment = %(comment)s where id=%(pk)s" 595 args = {'comment': comment, 'pk': row['pk_id']} 596 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
597 #--------------------------------------------------------
598 - def update_external_id(self, pk_id=None, type=None, value=None, issuer=None, comment=None):
599 """Edits an existing external ID. 600 601 creates ID type if necessary 602 """ 603 cmd = u""" 604 update dem.lnk_identity2ext_id set 605 fk_origin = (select dem.add_external_id_type(%(type)s, %(issuer)s)), 606 external_id = %(value)s, 607 comment = %(comment)s 608 where id = %(pk)s""" 609 args = {'pk': pk_id, 'value': value, 'type': type, 'issuer': issuer, 'comment': comment} 610 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
611 #--------------------------------------------------------
612 - def get_external_ids(self, id_type=None, issuer=None):
613 where_parts = ['pk_identity = %(pat)s'] 614 args = {'pat': self.ID} 615 616 if id_type is not None: 617 where_parts.append(u'name = %(name)s') 618 args['name'] = id_type.strip() 619 620 if issuer is not None: 621 where_parts.append(u'issuer = %(issuer)s') 622 args['issuer'] = issuer.strip() 623 624 cmd = u"select * from dem.v_external_ids4identity where %s" % ' and '.join(where_parts) 625 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 626 627 return rows
628 #--------------------------------------------------------
629 - def delete_external_id(self, pk_ext_id=None):
630 cmd = u""" 631 delete from dem.lnk_identity2ext_id 632 where id_identity = %(pat)s and id = %(pk)s""" 633 args = {'pat': self.ID, 'pk': pk_ext_id} 634 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
635 #--------------------------------------------------------
636 - def assimilate_identity(self, other_identity=None, link_obj=None):
637 """Merge another identity into this one. 638 639 Keep this one. Delete other one.""" 640 641 if other_identity.ID == self.ID: 642 return True, None 643 644 curr_pat = gmCurrentPatient() 645 if curr_pat.connected: 646 if other_identity.ID == curr_pat.ID: 647 return False, _('Cannot merge active patient into another patient.') 648 649 queries = [] 650 args = {'old_pat': other_identity.ID, 'new_pat': self.ID} 651 652 # delete old allergy state 653 queries.append ({ 654 'cmd': u'delete from clin.allergy_state where pk = (select pk_allergy_state from clin.v_pat_allergy_state where pk_patient = %(old_pat)s)', 655 'args': args 656 }) 657 # FIXME: adjust allergy_state in kept patient 658 659 # deactivate all names of old patient 660 queries.append ({ 661 'cmd': u'update dem.names set active = False where id_identity = %(old_pat)s', 662 'args': args 663 }) 664 665 # find FKs pointing to identity 666 FKs = gmPG2.get_foreign_keys2column ( 667 schema = u'dem', 668 table = u'identity', 669 column = u'pk' 670 ) 671 672 # generate UPDATEs 673 cmd_template = u'update %s set %s = %%(new_pat)s where %s = %%(old_pat)s' 674 for FK in FKs: 675 queries.append ({ 676 'cmd': cmd_template % (FK['referencing_table'], FK['referencing_column'], FK['referencing_column']), 677 'args': args 678 }) 679 680 # remove old identity entry 681 queries.append ({ 682 'cmd': u'delete from dem.identity where pk = %(old_pat)s', 683 'args': args 684 }) 685 686 _log.warning('identity [%s] is about to assimilate identity [%s]', self.ID, other_identity.ID) 687 688 gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, end_tx = True) 689 690 self.add_external_id ( 691 type_name = u'merged GNUmed identity primary key', 692 value = u'GNUmed::pk::%s' % other_identity.ID, 693 issuer = u'GNUmed' 694 ) 695 696 return True, None
697 #-------------------------------------------------------- 698 #--------------------------------------------------------
699 - def put_on_waiting_list(self, urgency=0, comment=None, zone=None):
700 cmd = u""" 701 insert into clin.waiting_list (fk_patient, urgency, comment, area, list_position) 702 values ( 703 %(pat)s, 704 %(urg)s, 705 %(cmt)s, 706 %(area)s, 707 (select coalesce((max(list_position) + 1), 1) from clin.waiting_list) 708 )""" 709 args = {'pat': self.ID, 'urg': urgency, 'cmt': comment, 'area': zone} 710 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], verbose=True)
711 #--------------------------------------------------------
712 - def export_as_gdt(self, filename=None, encoding='iso-8859-15', external_id_type=None):
713 714 template = u'%s%s%s\r\n' 715 716 file = codecs.open ( 717 filename = filename, 718 mode = 'wb', 719 encoding = encoding, 720 errors = 'strict' 721 ) 722 723 file.write(template % (u'013', u'8000', u'6301')) 724 file.write(template % (u'013', u'9218', u'2.10')) 725 if external_id_type is None: 726 file.write(template % (u'%03d' % (9 + len(str(self.ID))), u'3000', self.ID)) 727 else: 728 ext_ids = self.get_external_ids(id_type = external_id_type) 729 if len(ext_ids) > 0: 730 file.write(template % (u'%03d' % (9 + len(ext_ids[0]['value'])), u'3000', ext_ids[0]['value'])) 731 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['lastnames']])), u'3101', self._payload[self._idx['lastnames']])) 732 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['firstnames']])), u'3102', self._payload[self._idx['firstnames']])) 733 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['dob']].strftime('%d%m%Y'))), u'3103', self._payload[self._idx['dob']].strftime('%d%m%Y'))) 734 file.write(template % (u'010', u'3110', gmXdtMappings.map_gender_gm2xdt[self._payload[self._idx['gender']]])) 735 file.write(template % (u'025', u'6330', 'GNUmed::9206::encoding')) 736 file.write(template % (u'%03d' % (9 + len(encoding)), u'6331', encoding)) 737 if external_id_type is None: 738 file.write(template % (u'029', u'6332', u'GNUmed::3000::source')) 739 file.write(template % (u'017', u'6333', u'internal')) 740 else: 741 if len(ext_ids) > 0: 742 file.write(template % (u'029', u'6332', u'GNUmed::3000::source')) 743 file.write(template % (u'%03d' % (9 + len(external_id_type)), u'6333', external_id_type)) 744 745 file.close()
746 #-------------------------------------------------------- 747 # occupations API 748 #--------------------------------------------------------
749 - def get_occupations(self):
750 cmd = u"select * from dem.v_person_jobs where pk_identity=%s" 751 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 752 return rows
753 #-------------------------------------------------------- 790 #-------------------------------------------------------- 798 #-------------------------------------------------------- 799 # comms API 800 #--------------------------------------------------------
801 - def get_comm_channels(self, comm_medium=None):
802 cmd = u"select * from dem.v_person_comms where pk_identity = %s" 803 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx = True) 804 805 filtered = rows 806 807 if comm_medium is not None: 808 filtered = [] 809 for row in rows: 810 if row['comm_type'] == comm_medium: 811 filtered.append(row) 812 813 return [ gmDemographicRecord.cCommChannel(row = { 814 'pk_field': 'pk_lnk_identity2comm', 815 'data': r, 816 'idx': idx 817 }) for r in filtered 818 ]
819 #-------------------------------------------------------- 837 #-------------------------------------------------------- 843 #-------------------------------------------------------- 844 # contacts API 845 #--------------------------------------------------------
846 - def get_addresses(self, address_type=None):
847 cmd = u"select * from dem.v_pat_addresses where pk_identity=%s" 848 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx=True) 849 addresses = [] 850 for r in rows: 851 addresses.append(gmDemographicRecord.cPatientAddress(row={'idx': idx, 'data': r, 'pk_field': 'pk_address'})) 852 853 filtered = addresses 854 855 if address_type is not None: 856 filtered = [] 857 for adr in addresses: 858 if adr['address_type'] == address_type: 859 filtered.append(adr) 860 861 return filtered
862 #-------------------------------------------------------- 910 #---------------------------------------------------------------------- 920 #---------------------------------------------------------------------- 921 # relatives API 922 #----------------------------------------------------------------------
923 - def get_relatives(self):
924 cmd = u""" 925 select 926 t.description, 927 vbp.pk_identity as id, 928 title, 929 firstnames, 930 lastnames, 931 dob, 932 cob, 933 gender, 934 karyotype, 935 pupic, 936 pk_marital_status, 937 marital_status,+ 938 xmin_identity, 939 preferred 940 from 941 dem.v_basic_person vbp, dem.relation_types t, dem.lnk_person2relative l 942 where 943 ( 944 l.id_identity = %(pk)s and 945 vbp.pk_identity = l.id_relative and 946 t.id = l.id_relation_type 947 ) or ( 948 l.id_relative = %(pk)s and 949 vbp.pk_identity = l.id_identity and 950 t.inverse = l.id_relation_type 951 )""" 952 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}]) 953 if len(rows) == 0: 954 return [] 955 return [(row[0], cIdentity(row = {'data': row[1:], 'idx':idx, 'pk_field': 'pk'})) for row in rows]
956 #-------------------------------------------------------- 976 #----------------------------------------------------------------------
977 - def delete_relative(self, relation):
978 # unlink only, don't delete relative itself 979 self.set_relative(None, relation)
980 #---------------------------------------------------------------------- 981 # age/dob related 982 #----------------------------------------------------------------------
983 - def get_medical_age(self):
984 dob = self['dob'] 985 986 if dob is None: 987 return u'??' 988 989 if self['deceased'] is None: 990 # return gmDateTime.format_interval_medically ( 991 # pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone) - dob 992 # ) 993 return gmDateTime.format_apparent_age_medically ( 994 age = gmDateTime.calculate_apparent_age(start = dob) 995 ) 996 997 return u'%s%s' % ( 998 gmTools.u_latin_cross, 999 # gmDateTime.format_interval_medically(self['deceased'] - dob) 1000 gmDateTime.format_apparent_age_medically ( 1001 age = gmDateTime.calculate_apparent_age ( 1002 start = dob, 1003 end = self['deceased'] 1004 ) 1005 ) 1006 )
1007 #----------------------------------------------------------------------
1008 - def dob_in_range(self, min_distance=u'1 week', max_distance=u'1 week'):
1009 cmd = u'select dem.dob_is_in_range(%(dob)s, %(min)s, %(max)s)' 1010 rows, idx = gmPG2.run_ro_queries ( 1011 queries = [{ 1012 'cmd': cmd, 1013 'args': {'dob': self['dob'], 'min': min_distance, 'max': max_distance} 1014 }] 1015 ) 1016 return rows[0][0]
1017 #---------------------------------------------------------------------- 1018 # practice related 1019 #----------------------------------------------------------------------
1020 - def get_last_encounter(self):
1021 cmd = u'select * from clin.v_most_recent_encounters where pk_patient=%s' 1022 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self._payload[self._idx['pk_identity']]]}]) 1023 if len(rows) > 0: 1024 return rows[0] 1025 else: 1026 return None
1027 #--------------------------------------------------------
1028 - def _get_messages(self):
1029 return gmProviderInbox.get_inbox_messages(pk_patient = self._payload[self._idx['pk_identity']])
1030
1031 - def _set_messages(self, messages):
1032 return
1033 1034 messages = property(_get_messages, _set_messages) 1035 #--------------------------------------------------------
1036 - def delete_message(self, pk=None):
1038 #---------------------------------------------------------------------- 1039 # convenience 1040 #----------------------------------------------------------------------
1041 - def get_dirname(self):
1042 """Format patient demographics into patient specific path name fragment.""" 1043 return '%s-%s%s-%s' % ( 1044 self._payload[self._idx['lastnames']].replace(u' ', u'_'), 1045 self._payload[self._idx['firstnames']].replace(u' ', u'_'), 1046 gmTools.coalesce(self._payload[self._idx['preferred']], u'', template_initial = u'-(%s)'), 1047 self.get_formatted_dob(format = '%Y-%m-%d', encoding = gmI18N.get_encoding()) 1048 )
1049 #============================================================
1050 -class cStaffMember(cIdentity):
1051 """Represents a staff member which is a person. 1052 1053 - a specializing subclass of cIdentity turning it into a staff member 1054 """
1055 - def __init__(self, identity = None):
1056 cIdentity.__init__(self, identity=identity) 1057 self.__db_cache = {}
1058 #--------------------------------------------------------
1059 - def get_inbox(self):
1060 return gmProviderInbox.cProviderInbox(provider_id = self.ID)
1061 #============================================================
1062 -class cPatient(cIdentity):
1063 """Represents a person which is a patient. 1064 1065 - a specializing subclass of cIdentity turning it into a patient 1066 - its use is to cache subobjects like EMR and document folder 1067 """
1068 - def __init__(self, aPK_obj=None, row=None):
1069 cIdentity.__init__(self, aPK_obj=aPK_obj, row=row) 1070 self.__db_cache = {} 1071 self.__emr_access_lock = threading.Lock()
1072 #--------------------------------------------------------
1073 - def cleanup(self):
1074 """Do cleanups before dying. 1075 1076 - note that this may be called in a thread 1077 """ 1078 if self.__db_cache.has_key('clinical record'): 1079 self.__db_cache['clinical record'].cleanup() 1080 if self.__db_cache.has_key('document folder'): 1081 self.__db_cache['document folder'].cleanup() 1082 cIdentity.cleanup(self)
1083 #----------------------------------------------------------
1084 - def get_emr(self):
1085 if not self.__emr_access_lock.acquire(False): 1086 raise AttributeError('cannot access EMR') 1087 try: 1088 emr = self.__db_cache['clinical record'] 1089 self.__emr_access_lock.release() 1090 return emr 1091 except KeyError: 1092 pass 1093 1094 self.__db_cache['clinical record'] = gmClinicalRecord.cClinicalRecord(aPKey = self._payload[self._idx['pk_identity']]) 1095 self.__emr_access_lock.release() 1096 return self.__db_cache['clinical record']
1097 #--------------------------------------------------------
1098 - def get_document_folder(self):
1099 try: 1100 return self.__db_cache['document folder'] 1101 except KeyError: 1102 pass 1103 1104 self.__db_cache['document folder'] = gmDocuments.cDocumentFolder(aPKey = self._payload[self._idx['pk_identity']]) 1105 return self.__db_cache['document folder']
1106 #============================================================
1107 -class gmCurrentPatient(gmBorg.cBorg):
1108 """Patient Borg to hold currently active patient. 1109 1110 There may be many instances of this but they all share state. 1111 """
1112 - def __init__(self, patient=None, forced_reload=False):
1113 """Change or get currently active patient. 1114 1115 patient: 1116 * None: get currently active patient 1117 * -1: unset currently active patient 1118 * cPatient instance: set active patient if possible 1119 """ 1120 # make sure we do have a patient pointer 1121 try: 1122 tmp = self.patient 1123 except AttributeError: 1124 self.patient = gmNull.cNull() 1125 self.__register_interests() 1126 # set initial lock state, 1127 # this lock protects against activating another patient 1128 # when we are controlled from a remote application 1129 self.__lock_depth = 0 1130 # initialize callback state 1131 self.__pre_selection_callbacks = [] 1132 1133 # user wants copy of current patient 1134 if patient is None: 1135 return None 1136 1137 # do nothing if patient is locked 1138 if self.locked: 1139 _log.error('patient [%s] is locked, cannot change to [%s]' % (self.patient['pk_identity'], patient)) 1140 return None 1141 1142 # user wants to explicitly unset current patient 1143 if patient == -1: 1144 _log.debug('explicitly unsetting current patient') 1145 if not self.__run_pre_selection_callbacks(): 1146 _log.debug('not unsetting current patient') 1147 return None 1148 self.__send_pre_selection_notification() 1149 self.patient.cleanup() 1150 self.patient = gmNull.cNull() 1151 self.__send_selection_notification() 1152 return None 1153 1154 # must be cPatient instance, then 1155 if not isinstance(patient, cPatient): 1156 _log.error('cannot set active patient to [%s], must be either None, -1 or cPatient instance' % str(patient)) 1157 raise TypeError, 'gmPerson.gmCurrentPatient.__init__(): <patient> must be None, -1 or cPatient instance but is: %s' % str(patient) 1158 1159 # same ID, no change needed 1160 if (self.patient['pk_identity'] == patient['pk_identity']) and not forced_reload: 1161 return None 1162 1163 # user wants different patient 1164 _log.debug('patient change [%s] -> [%s] requested', self.patient['pk_identity'], patient['pk_identity']) 1165 1166 # everything seems swell 1167 if not self.__run_pre_selection_callbacks(): 1168 _log.debug('not changing current patient') 1169 return None 1170 self.__send_pre_selection_notification() 1171 self.patient.cleanup() 1172 self.patient = patient 1173 self.patient.get_emr() 1174 self.__send_selection_notification() 1175 1176 return None
1177 #--------------------------------------------------------
1178 - def __register_interests(self):
1179 gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_identity_change) 1180 gmDispatcher.connect(signal = u'name_mod_db', receiver = self._on_identity_change)
1181 #--------------------------------------------------------
1182 - def _on_identity_change(self):
1183 """Listen for patient *data* change.""" 1184 self.patient.refetch_payload()
1185 #-------------------------------------------------------- 1186 # external API 1187 #--------------------------------------------------------
1188 - def register_pre_selection_callback(self, callback=None):
1189 if not callable(callback): 1190 raise TypeError(u'callback [%s] not callable' % callback) 1191 1192 self.__pre_selection_callbacks.append(callback)
1193 #--------------------------------------------------------
1194 - def _get_connected(self):
1195 return (not isinstance(self.patient, gmNull.cNull))
1196
1197 - def _set_connected(self):
1198 raise AttributeError(u'invalid to set <connected> state')
1199 1200 connected = property(_get_connected, _set_connected) 1201 #--------------------------------------------------------
1202 - def _get_locked(self):
1203 return (self.__lock_depth > 0)
1204
1205 - def _set_locked(self, locked):
1206 if locked: 1207 self.__lock_depth = self.__lock_depth + 1 1208 gmDispatcher.send(signal='patient_locked') 1209 else: 1210 if self.__lock_depth == 0: 1211 _log.error('lock/unlock imbalance, trying to refcount lock depth below 0') 1212 return 1213 else: 1214 self.__lock_depth = self.__lock_depth - 1 1215 gmDispatcher.send(signal='patient_unlocked')
1216 1217 locked = property(_get_locked, _set_locked) 1218 #--------------------------------------------------------
1219 - def force_unlock(self):
1220 _log.info('forced patient unlock at lock depth [%s]' % self.__lock_depth) 1221 self.__lock_depth = 0 1222 gmDispatcher.send(signal='patient_unlocked')
1223 #-------------------------------------------------------- 1224 # patient change handling 1225 #--------------------------------------------------------
1227 if isinstance(self.patient, gmNull.cNull): 1228 return True 1229 1230 for call_back in self.__pre_selection_callbacks: 1231 try: 1232 successful = call_back() 1233 except: 1234 _log.exception('callback [%s] failed', call_back) 1235 print "*** pre-selection callback failed ***" 1236 print type(call_back) 1237 print call_back 1238 return False 1239 1240 if not successful: 1241 _log.debug('callback [%s] returned False', call_back) 1242 return False 1243 1244 return True
1245 #--------------------------------------------------------
1247 """Sends signal when another patient is about to become active. 1248 1249 This does NOT wait for signal handlers to complete. 1250 """ 1251 kwargs = { 1252 'signal': u'pre_patient_selection', 1253 'sender': id(self.__class__), 1254 'pk_identity': self.patient['pk_identity'] 1255 } 1256 gmDispatcher.send(**kwargs)
1257 #--------------------------------------------------------
1259 """Sends signal when another patient has actually been made active.""" 1260 kwargs = { 1261 'signal': u'post_patient_selection', 1262 'sender': id(self.__class__), 1263 'pk_identity': self.patient['pk_identity'] 1264 } 1265 gmDispatcher.send(**kwargs)
1266 #-------------------------------------------------------- 1267 # __getattr__ handling 1268 #--------------------------------------------------------
1269 - def __getattr__(self, attribute):
1270 if attribute == 'patient': 1271 raise AttributeError 1272 if not isinstance(self.patient, gmNull.cNull): 1273 return getattr(self.patient, attribute)
1274 #-------------------------------------------------------- 1275 # __get/setitem__ handling 1276 #--------------------------------------------------------
1277 - def __getitem__(self, attribute = None):
1278 """Return any attribute if known how to retrieve it by proxy. 1279 """ 1280 return self.patient[attribute]
1281 #--------------------------------------------------------
1282 - def __setitem__(self, attribute, value):
1283 self.patient[attribute] = value
1284 #============================================================ 1285 # match providers 1286 #============================================================
1287 -class cMatchProvider_Provider(gmMatchProvider.cMatchProvider_SQL2):
1288 - def __init__(self):
1289 gmMatchProvider.cMatchProvider_SQL2.__init__( 1290 self, 1291 queries = [ 1292 u"""select 1293 pk_staff, 1294 short_alias || ' (' || coalesce(title, '') || firstnames || ' ' || lastnames || ')', 1295 1 1296 from dem.v_staff 1297 where 1298 is_active and ( 1299 short_alias %(fragment_condition)s or 1300 firstnames %(fragment_condition)s or 1301 lastnames %(fragment_condition)s or 1302 db_user %(fragment_condition)s 1303 )""" 1304 ] 1305 ) 1306 self.setThresholds(1, 2, 3)
1307 #============================================================ 1308 # convenience functions 1309 #============================================================
1310 -def create_name(pk_person, firstnames, lastnames, active=False):
1311 queries = [{ 1312 'cmd': u"select dem.add_name(%s, %s, %s, %s)", 1313 'args': [pk_person, firstnames, lastnames, active] 1314 }] 1315 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True) 1316 name = cPersonName(aPK_obj = rows[0][0]) 1317 return name
1318 #============================================================
1319 -def create_identity(gender=None, dob=None, lastnames=None, firstnames=None):
1320 1321 cmd1 = u"""insert into dem.identity (gender, dob) values (%s, %s)""" 1322 1323 cmd2 = u""" 1324 insert into dem.names ( 1325 id_identity, lastnames, firstnames 1326 ) values ( 1327 currval('dem.identity_pk_seq'), coalesce(%s, 'xxxDEFAULTxxx'), coalesce(%s, 'xxxDEFAULTxxx') 1328 )""" 1329 1330 rows, idx = gmPG2.run_rw_queries ( 1331 queries = [ 1332 {'cmd': cmd1, 'args': [gender, dob]}, 1333 {'cmd': cmd2, 'args': [lastnames, firstnames]}, 1334 {'cmd': u"select currval('dem.identity_pk_seq')"} 1335 ], 1336 return_data = True 1337 ) 1338 return cIdentity(aPK_obj=rows[0][0])
1339 #============================================================
1340 -def create_dummy_identity():
1341 cmd1 = u"insert into dem.identity(gender) values('xxxDEFAULTxxx')" 1342 cmd2 = u"select currval('dem.identity_pk_seq')" 1343 1344 rows, idx = gmPG2.run_rw_queries ( 1345 queries = [ 1346 {'cmd': cmd1}, 1347 {'cmd': cmd2} 1348 ], 1349 return_data = True 1350 ) 1351 return gmDemographicRecord.cIdentity(aPK_obj = rows[0][0])
1352 #============================================================
1353 -def set_active_patient(patient=None, forced_reload=False):
1354 """Set active patient. 1355 1356 If patient is -1 the active patient will be UNset. 1357 """ 1358 if isinstance(patient, cPatient): 1359 pat = patient 1360 elif isinstance(patient, cIdentity): 1361 pat = cPatient(aPK_obj=patient['pk_identity']) 1362 elif isinstance(patient, cStaff): 1363 pat = cPatient(aPK_obj=patient['pk_identity']) 1364 elif isinstance(patient, gmCurrentPatient): 1365 pat = patient.patient 1366 elif patient == -1: 1367 pat = patient 1368 else: 1369 raise ValueError('<patient> must be either -1, cPatient, cStaff, cIdentity or gmCurrentPatient instance, is: %s' % patient) 1370 1371 # attempt to switch 1372 try: 1373 gmCurrentPatient(patient = pat, forced_reload = forced_reload) 1374 except: 1375 _log.exception('error changing active patient to [%s]' % patient) 1376 return False 1377 1378 return True
1379 #============================================================ 1380 # gender related 1381 #------------------------------------------------------------
1382 -def get_gender_list():
1383 """Retrieves the list of known genders from the database.""" 1384 global __gender_idx 1385 global __gender_list 1386 1387 if __gender_list is None: 1388 cmd = u"select tag, l10n_tag, label, l10n_label, sort_weight from dem.v_gender_labels order by sort_weight desc" 1389 __gender_list, __gender_idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 1390 1391 return (__gender_list, __gender_idx)
1392 #------------------------------------------------------------ 1393 map_gender2mf = { 1394 'm': u'm', 1395 'f': u'f', 1396 'tf': u'f', 1397 'tm': u'm', 1398 'h': u'mf' 1399 } 1400 #------------------------------------------------------------ 1401 # Maps GNUmed related i18n-aware gender specifiers to a unicode symbol. 1402 map_gender2symbol = { 1403 'm': u'\u2642', 1404 'f': u'\u2640', 1405 'tf': u'\u26A5\u2640', 1406 'tm': u'\u26A5\u2642', 1407 'h': u'\u26A5' 1408 # 'tf': u'\u2642\u2640-\u2640', 1409 # 'tm': u'\u2642\u2640-\u2642', 1410 # 'h': u'\u2642\u2640' 1411 } 1412 #------------------------------------------------------------
1413 -def map_gender2salutation(gender=None):
1414 """Maps GNUmed related i18n-aware gender specifiers to a human-readable salutation.""" 1415 1416 global __gender2salutation_map 1417 1418 if __gender2salutation_map is None: 1419 genders, idx = get_gender_list() 1420 __gender2salutation_map = { 1421 'm': _('Mr'), 1422 'f': _('Mrs'), 1423 'tf': u'', 1424 'tm': u'', 1425 'h': u'' 1426 } 1427 for g in genders: 1428 __gender2salutation_map[g[idx['l10n_tag']]] = __gender2salutation_map[g[idx['tag']]] 1429 __gender2salutation_map[g[idx['label']]] = __gender2salutation_map[g[idx['tag']]] 1430 __gender2salutation_map[g[idx['l10n_label']]] = __gender2salutation_map[g[idx['tag']]] 1431 1432 return __gender2salutation_map[gender]
1433 #------------------------------------------------------------
1434 -def map_firstnames2gender(firstnames=None):
1435 """Try getting the gender for the given first name.""" 1436 1437 if firstnames is None: 1438 return None 1439 1440 rows, idx = gmPG2.run_ro_queries(queries = [{ 1441 'cmd': u"select gender from dem.name_gender_map where name ilike %(fn)s limit 1", 1442 'args': {'fn': firstnames} 1443 }]) 1444 1445 if len(rows) == 0: 1446 return None 1447 1448 return rows[0][0]
1449 #============================================================
1450 -def get_staff_list(active_only=False):
1451 if active_only: 1452 cmd = u"select * from dem.v_staff where is_active order by can_login desc, short_alias asc" 1453 else: 1454 cmd = u"select * from dem.v_staff order by can_login desc, is_active desc, short_alias asc" 1455 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True) 1456 staff_list = [] 1457 for row in rows: 1458 obj_row = { 1459 'idx': idx, 1460 'data': row, 1461 'pk_field': 'pk_staff' 1462 } 1463 staff_list.append(cStaff(row=obj_row)) 1464 return staff_list
1465 #============================================================
1466 -def get_persons_from_pks(pks=None):
1467 return [ cIdentity(aPK_obj = pk) for pk in pks ]
1468 #============================================================
1469 -def get_person_from_xdt(filename=None, encoding=None, dob_format=None):
1470 from Gnumed.business import gmXdtObjects 1471 return gmXdtObjects.read_person_from_xdt(filename=filename, encoding=encoding, dob_format=dob_format)
1472 #============================================================
1473 -def get_persons_from_pracsoft_file(filename=None, encoding='ascii'):
1474 from Gnumed.business import gmPracSoftAU 1475 return gmPracSoftAU.read_persons_from_pracsoft_file(filename=filename, encoding=encoding)
1476 #============================================================ 1477 # main/testing 1478 #============================================================ 1479 if __name__ == '__main__': 1480 1481 if len(sys.argv) == 1: 1482 sys.exit() 1483 1484 if sys.argv[1] != 'test': 1485 sys.exit() 1486 1487 import datetime 1488 1489 gmI18N.activate_locale() 1490 gmI18N.install_domain() 1491 gmDateTime.init() 1492 1493 #--------------------------------------------------------
1494 - def test_set_active_pat():
1495 1496 ident = cIdentity(1) 1497 print "setting active patient with", ident 1498 set_active_patient(patient=ident) 1499 1500 patient = cPatient(12) 1501 print "setting active patient with", patient 1502 set_active_patient(patient=patient) 1503 1504 pat = gmCurrentPatient() 1505 print pat['dob'] 1506 #pat['dob'] = 'test' 1507 1508 staff = cStaff() 1509 print "setting active patient with", staff 1510 set_active_patient(patient=staff) 1511 1512 print "setting active patient with -1" 1513 set_active_patient(patient=-1)
1514 #--------------------------------------------------------
1515 - def test_dto_person():
1516 dto = cDTO_person() 1517 dto.firstnames = 'Sepp' 1518 dto.lastnames = 'Herberger' 1519 dto.gender = 'male' 1520 dto.dob = pyDT.datetime.now(tz=gmDateTime.gmCurrentLocalTimezone) 1521 print dto 1522 1523 print dto['firstnames'] 1524 print dto['lastnames'] 1525 print dto['gender'] 1526 print dto['dob'] 1527 1528 for key in dto.keys(): 1529 print key
1530 #--------------------------------------------------------
1531 - def test_staff():
1532 staff = cStaff() 1533 print staff 1534 print staff.inbox 1535 print staff.inbox.messages
1536 #--------------------------------------------------------
1537 - def test_current_provider():
1538 staff = cStaff() 1539 provider = gmCurrentProvider(provider = staff) 1540 print provider 1541 print provider.inbox 1542 print provider.inbox.messages 1543 print provider.database_language 1544 tmp = provider.database_language 1545 provider.database_language = None 1546 print provider.database_language 1547 provider.database_language = tmp 1548 print provider.database_language
1549 #--------------------------------------------------------
1550 - def test_identity():
1551 # create patient 1552 print '\n\nCreating identity...' 1553 new_identity = create_identity(gender='m', dob='2005-01-01', lastnames='test lastnames', firstnames='test firstnames') 1554 print 'Identity created: %s' % new_identity 1555 1556 print '\nSetting title and gender...' 1557 new_identity['title'] = 'test title'; 1558 new_identity['gender'] = 'f'; 1559 new_identity.save_payload() 1560 print 'Refetching identity from db: %s' % cIdentity(aPK_obj=new_identity['pk_identity']) 1561 1562 print '\nGetting all names...' 1563 for a_name in new_identity.get_names(): 1564 print a_name 1565 print 'Active name: %s' % (new_identity.get_active_name()) 1566 print 'Setting nickname...' 1567 new_identity.set_nickname(nickname='test nickname') 1568 print 'Refetching all names...' 1569 for a_name in new_identity.get_names(): 1570 print a_name 1571 print 'Active name: %s' % (new_identity.get_active_name()) 1572 1573 print '\nIdentity occupations: %s' % new_identity['occupations'] 1574 print 'Creating identity occupation...' 1575 new_identity.link_occupation('test occupation') 1576 print 'Identity occupations: %s' % new_identity['occupations'] 1577 1578 print '\nIdentity addresses: %s' % new_identity.get_addresses() 1579 print 'Creating identity address...' 1580 # make sure the state exists in the backend 1581 new_identity.link_address ( 1582 number = 'test 1234', 1583 street = 'test street', 1584 postcode = 'test postcode', 1585 urb = 'test urb', 1586 state = 'SN', 1587 country = 'DE' 1588 ) 1589 print 'Identity addresses: %s' % new_identity.get_addresses() 1590 1591 print '\nIdentity communications: %s' % new_identity.get_comm_channels() 1592 print 'Creating identity communication...' 1593 new_identity.link_comm_channel('homephone', '1234566') 1594 print 'Identity communications: %s' % new_identity.get_comm_channels()
1595 #--------------------------------------------------------
1596 - def test_name():
1597 for pk in range(1,16): 1598 name = cPersonName(aPK_obj=pk) 1599 print name.description 1600 print ' ', name
1601 #-------------------------------------------------------- 1602 #test_dto_person() 1603 #test_identity() 1604 #test_set_active_pat() 1605 #test_search_by_dto() 1606 #test_staff() 1607 test_current_provider() 1608 #test_name() 1609 1610 #map_gender2salutation('m') 1611 # module functions 1612 #genders, idx = get_gender_list() 1613 #print "\n\nRetrieving gender enum (tag, label, weight):" 1614 #for gender in genders: 1615 # print "%s, %s, %s" % (gender[idx['tag']], gender[idx['l10n_label']], gender[idx['sort_weight']]) 1616 1617 #comms = get_comm_list() 1618 #print "\n\nRetrieving communication media enum (id, description): %s" % comms 1619 1620 #============================================================ 1621