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

Source Code for Module Gnumed.business.gmDemographicRecord

   1  # -*- coding: utf8 -*- 
   2  """GNUmed demographics object. 
   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  license: GPL v2 or later 
   8  """ 
   9  #============================================================ 
  10  __version__ = "$Revision: 1.106 $" 
  11  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>, I.Haywood <ihaywood@gnu.org>" 
  12   
  13  # stdlib 
  14  import sys 
  15  import os 
  16  import os.path 
  17  import logging 
  18   
  19   
  20  # GNUmed 
  21  if __name__ == '__main__': 
  22          sys.path.insert(0, '../../') 
  23  from Gnumed.pycommon import gmDispatcher 
  24  from Gnumed.pycommon import gmBusinessDBObject 
  25  from Gnumed.pycommon import gmPG2 
  26  from Gnumed.pycommon import gmTools 
  27   
  28   
  29  _log = logging.getLogger('gm.business') 
  30  _log.info(__version__) 
  31   
  32  try: 
  33          _ 
  34  except NameError: 
  35          _ = lambda x:x 
  36   
  37  #============================================================ 
  38  # occupation handling 
  39  #------------------------------------------------------------ 
40 -def get_occupations(pk_identity=None):
41 cmd = u""" 42 SELECT * 43 FROM dem.v_person_jobs 44 WHERE pk_identity = %(pk)s 45 ORDER BY l10n_occupation 46 """ 47 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_identity}}]) 48 return rows
49 #============================================================ 50 # text+image tags 51 #------------------------------------------------------------ 52 _SQL_get_tag_image = u"SELECT * FROM ref.v_tag_images_no_data WHERE %s" 53
54 -class cTagImage(gmBusinessDBObject.cBusinessDBObject):
55 56 _cmd_fetch_payload = _SQL_get_tag_image % u"pk_tag_image = %s" 57 _cmds_store_payload = [ 58 u""" 59 UPDATE ref.tag_image SET 60 description = gm.nullify_empty_string(%(description)s), 61 filename = gm.nullify_empty_string(%(filename)s) 62 WHERE 63 pk = %(pk_tag_image)s 64 AND 65 xmin = %(xmin_tag_image)s 66 RETURNING 67 pk as pk_tag_image, 68 xmin as xmin_tag_image 69 """ 70 ] 71 _updatable_fields = [u'description', u'filename'] 72 #--------------------------------------------------------
73 - def export_image2file(self, aChunkSize=0, filename=None):
74 75 if self._payload[self._idx['size']] == 0: 76 return None 77 78 if filename is None: 79 suffix = None 80 # preserve original filename extension if available 81 if self._payload[self._idx['filename']] is not None: 82 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 83 suffix = suffix.strip() 84 if suffix == u'': 85 suffix = None 86 # get unique filename 87 filename = gmTools.get_unique_filename ( 88 prefix = 'gm-tag_image-', 89 suffix = suffix 90 ) 91 92 success = gmPG2.bytea2file ( 93 data_query = { 94 'cmd': u'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s', 95 'args': {'pk': self.pk_obj} 96 }, 97 filename = filename, 98 chunk_size = aChunkSize, 99 data_size = self._payload[self._idx['size']] 100 ) 101 102 if success: 103 return filename 104 105 return None
106 #--------------------------------------------------------
107 - def update_image_from_file(self, filename=None):
108 # sanity check 109 if not (os.access(filename, os.R_OK) and os.path.isfile(filename)): 110 _log.error('[%s] is not a readable file' % filename) 111 return False 112 113 gmPG2.file2bytea ( 114 query = u"UPDATE ref.tag_image SET image = %(data)s::bytea WHERE pk = %(pk)s", 115 filename = filename, 116 args = {'pk': self.pk_obj} 117 ) 118 119 # must update XMIN now ... 120 self.refetch_payload() 121 return True
122 #------------------------------------------------------------
123 -def get_tag_images(order_by=None):
124 if order_by is None: 125 order_by = u'true' 126 else: 127 order_by = 'true ORDER BY %s' % order_by 128 129 cmd = _SQL_get_tag_image % order_by 130 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 131 return [ cTagImage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_tag_image'}) for r in rows ]
132 #------------------------------------------------------------
133 -def create_tag_image(description=None, link_obj=None):
134 135 args = {u'desc': description, u'img': u''} 136 cmd = u""" 137 INSERT INTO ref.tag_image ( 138 description, 139 image 140 ) VALUES ( 141 %(desc)s, 142 %(img)s::bytea 143 ) 144 RETURNING pk 145 """ 146 rows, idx = gmPG2.run_rw_queries ( 147 link_obj = link_obj, 148 queries = [{'cmd': cmd, 'args': args}], 149 end_tx = True, 150 return_data = True, 151 get_col_idx = False 152 ) 153 154 return cTagImage(aPK_obj = rows[0]['pk'])
155 #------------------------------------------------------------
156 -def delete_tag_image(tag_image=None):
157 args = {'pk': tag_image} 158 cmd = u""" 159 DELETE FROM ref.tag_image 160 WHERE 161 pk = %(pk)s 162 AND 163 NOT EXISTS ( 164 SELECT 1 165 FROM dem.identity_tag 166 WHERE fk_tag = %(pk)s 167 LIMIT 1 168 ) 169 RETURNING 1 170 """ 171 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 172 if len(rows) == 0: 173 return False 174 return True
175 176 #============================================================ 177 _SQL_get_identity_tags = u"""SELECT * FROM dem.v_identity_tags WHERE %s""" 178
179 -class cIdentityTag(gmBusinessDBObject.cBusinessDBObject):
180 181 _cmd_fetch_payload = _SQL_get_identity_tags % u"pk_identity_tag = %s" 182 _cmds_store_payload = [ 183 u""" 184 UPDATE dem.identity_tag SET 185 fk_tag = %(pk_tag_image)s, 186 comment = gm.nullify_empty_string(%(comment)s) 187 WHERE 188 pk = %(pk_identity_tag)s 189 AND 190 xmin = %(xmin_identity_tag)s 191 RETURNING 192 pk as pk_identity_tag, 193 xmin as xmin_identity_tag 194 """ 195 ] 196 _updatable_fields = [u'fk_tag', u'comment'] 197 #--------------------------------------------------------
198 - def export_image2file(self, aChunkSize=0, filename=None):
199 200 if self._payload[self._idx['image_size']] == 0: 201 return None 202 203 if filename is None: 204 suffix = None 205 # preserve original filename extension if available 206 if self._payload[self._idx['filename']] is not None: 207 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 208 suffix = suffix.strip() 209 if suffix == u'': 210 suffix = None 211 # get unique filename 212 filename = gmTools.get_unique_filename ( 213 prefix = 'gm-identity_tag-', 214 suffix = suffix 215 ) 216 217 exported = gmPG2.bytea2file ( 218 data_query = { 219 'cmd': u'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s', 220 'args': {'pk': self._payload[self._idx['pk_tag_image']]} 221 }, 222 filename = filename, 223 chunk_size = aChunkSize, 224 data_size = self._payload[self._idx['image_size']] 225 ) 226 if exported: 227 return filename 228 229 return None
230 #============================================================ 231 #============================================================
232 -def get_countries():
233 cmd = u""" 234 select 235 _(name) as l10n_country, name, code, deprecated 236 from dem.country 237 order by l10n_country""" 238 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 239 return rows
240 #============================================================
241 -def get_country_for_region(region=None):
242 cmd = u""" 243 SELECT code_country, l10n_country FROM dem.v_state WHERE l10n_state = %(region)s 244 union 245 SELECT code_country, l10n_country FROM dem.v_state WHERE state = %(region)s 246 """ 247 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'region': region}}]) 248 return rows
249 #============================================================
250 -def delete_province(province=None, delete_urbs=False):
251 252 args = {'prov': province} 253 254 queries = [] 255 if delete_urbs: 256 queries.append ({ 257 'cmd': u""" 258 delete from dem.urb du 259 where 260 du.id_state = %(prov)s 261 and 262 not exists (select 1 from dem.street ds where ds.id_urb = du.id)""", 263 'args': args 264 }) 265 266 queries.append ({ 267 'cmd': u""" 268 delete from dem.state ds 269 where 270 ds.id = %(prov)s 271 and 272 not exists (select 1 from dem.urb du where du.id_state = ds.id)""", 273 'args': args 274 }) 275 276 gmPG2.run_rw_queries(queries = queries) 277 278 return True
279 #------------------------------------------------------------
280 -def create_province(name=None, code=None, country=None):
281 282 args = {'code': code, 'country': country, 'name': name} 283 284 cmd = u"""SELECT EXISTS (SELECT 1 FROM dem.state WHERE name = %(name)s)""" 285 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 286 287 if rows[0][0]: 288 return 289 290 cmd = u""" 291 INSERT INTO dem.state ( 292 code, country, name 293 ) VALUES ( 294 %(code)s, %(country)s, %(name)s 295 )""" 296 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
297 #------------------------------------------------------------
298 -def get_provinces():
299 cmd = u""" 300 select 301 l10n_state, l10n_country, state, code_state, code_country, pk_state, country_deprecated 302 from dem.v_state 303 order by l10n_country, l10n_state""" 304 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 305 return rows
306 #============================================================ 307 # address related classes 308 #------------------------------------------------------------
309 -class cAddress(gmBusinessDBObject.cBusinessDBObject):
310 """A class representing an address as an entity in itself. 311 312 We consider addresses to be self-complete "labels" for locations. 313 It does not depend on any people actually living there. Thus 314 an address can get attached to as many people as we want to 315 signify that that is their place of residence/work/... 316 317 This class acts on the address as an entity. Therefore it can 318 modify the address fields. Think carefully about *modifying* 319 addresses attached to people, though. Most times when you think 320 person.modify_address() what you *really* want is as sequence of 321 person.unlink_address(old) and person.link_address(new). 322 323 Modifying an address may or may not be the proper thing to do as 324 it will transparently modify the address for *all* the people to 325 whom it is attached. In many cases you will want to create a *new* 326 address and link it to a person instead of the old address. 327 """ 328 _cmd_fetch_payload = u"select * from dem.v_address where pk_address = %s" 329 _cmds_store_payload = [ 330 u"""UPDATE dem.address SET 331 aux_street = %(notes_street)s, 332 subunit = %(subunit)s, 333 addendum = %(notes_subunit)s, 334 lat_lon = %(lat_lon_street)s 335 WHERE 336 id = %(pk_address)s 337 AND 338 xmin = %(xmin_address)s 339 RETURNING 340 xmin AS xmin_address""" 341 ] 342 _updatable_fields = [ 343 'notes_street', 344 'subunit', 345 'notes_subunit', 346 'lat_lon_address' 347 ] 348 #--------------------------------------------------------
349 - def format(self, single_line=False, verbose=False, show_type=False):
350 if single_line: 351 return format_address_single_line(address = self, show_type = False, verbose = verbose) 352 return format_address(address = self, show_type = False)
353 #------------------------------------------------------------
354 -def address_exists(country=None, state=None, urb=None, postcode=None, street=None, number=None, subunit=None):
355 356 cmd = u"""SELECT dem.address_exists(%(country)s, %(state)s, %(urb)s, %(postcode)s, %(street)s, %(number)s, %(subunit)s)""" 357 args = { 358 'country': country, 359 'state': state, 360 'urb': urb, 361 'postcode': postcode, 362 'street': street, 363 'number': number, 364 'subunit': subunit 365 } 366 367 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 368 if rows[0][0] is None: 369 _log.debug('address does not exist') 370 for key, val in args.items(): 371 _log.debug('%s: %s', key, val) 372 return None 373 374 return rows[0][0]
375 #------------------------------------------------------------
376 -def create_address(country=None, state=None, urb=None, suburb=None, postcode=None, street=None, number=None, subunit=None):
377 378 if suburb is not None: 379 suburb = gmTools.none_if(suburb.strip(), u'') 380 381 pk_address = address_exists ( 382 country = country, 383 state = state, 384 urb = urb, 385 # suburb = suburb, 386 postcode = postcode, 387 street = street, 388 number = number, 389 subunit = subunit 390 ) 391 if pk_address is not None: 392 return cAddress(aPK_obj=pk_address) 393 394 cmd = u""" 395 SELECT dem.create_address ( 396 %(number)s, 397 %(street)s, 398 %(postcode)s, 399 %(urb)s, 400 %(state)s, 401 %(country)s, 402 %(subunit)s 403 )""" 404 args = { 405 'number': number, 406 'street': street, 407 'postcode': postcode, 408 'urb': urb, 409 'state': state, 410 'country': country, 411 'subunit': subunit 412 } 413 queries = [{'cmd': cmd, 'args': args}] 414 415 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True) 416 adr = cAddress(aPK_obj = rows[0][0]) 417 418 if suburb is not None: 419 queries = [{ 420 # CAVE: suburb will be ignored if there already is one 421 'cmd': u"update dem.street set suburb = %(suburb)s where id=%(pk_street)s and suburb is Null", 422 'args': {'suburb': suburb, 'pk_street': adr['pk_street']} 423 }] 424 rows, idx = gmPG2.run_rw_queries(queries = queries) 425 426 return adr
427 #------------------------------------------------------------
428 -def delete_address(pk_address=None):
429 cmd = u""" 430 DELETE FROM dem.address 431 WHERE 432 id = %(pk)s 433 AND 434 NOT EXISTS (( 435 SELECT 1 FROM dem.org_unit WHERE fk_address = %(pk)s LIMIT 1 436 ) UNION ( 437 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_address = %(pk)s LIMIT 1 438 ) UNION ( 439 SELECT 1 FROM dem.lnk_person_org_address WHERE id_address = %(pk)s LIMIT 1 440 )) 441 """ 442 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_address}}]) 443 return True
444 #------------------------------------------------------------
445 -def format_address_single_line(address=None, verbose=False, show_type=False):
446 data = { 447 'pk_adr': address['pk_address'], 448 'street': address['street'], 449 'notes_street': gmTools.coalesce(address['notes_street'], u'', u' (%s)'), 450 'number': address['number'], 451 'subunit': gmTools.coalesce(address['subunit'], u'', u'/%s'), 452 'notes_subunit': gmTools.coalesce(address['notes_subunit'], u'', u' (%s)'), 453 'zip': address['postcode'], 454 'urb': address['urb'], 455 'suburb': gmTools.coalesce(address['suburb'], u'', u' (%s)'), 456 'l10n_state': address['l10n_state'], 457 'code_state': address['code_state'], 458 'l10n_country': address['l10n_country'], 459 'code_country': address['code_country'] 460 } 461 if show_type: 462 data['type'] = address['l10n_address_type'] 463 464 if verbose: 465 if show_type: 466 template = _('%(type)s: %(street)s %(number)s%(subunit)s, %(zip)s %(urb)s %(suburb)s, %(code_state)s, %(code_country)s') 467 else: 468 template = _('%(street)s %(number)s%(subunit)s, %(zip)s %(urb)s %(suburb)s, %(code_state)s, %(code_country)s') 469 else: 470 if show_type: 471 template = _('%(type)s: %(street)s %(number)s%(subunit)s, %(zip)s %(urb)s, %(code_state)s, %(code_country)s') 472 else: 473 template = _('%(street)s %(number)s%(subunit)s, %(zip)s %(urb)s, %(code_state)s, %(code_country)s') 474 475 return template % data
476 #------------------------------------------------------------
477 -def format_address(address=None, show_type=False):
478 data = { 479 'pk_adr': address['pk_address'], 480 'street': address['street'], 481 'notes_street': gmTools.coalesce(address['notes_street'], u'', u' (%s)'), 482 'number': address['number'], 483 'subunit': gmTools.coalesce(address['subunit'], u'', u'/%s'), 484 'notes_subunit': gmTools.coalesce(address['notes_subunit'], u'', u' (%s)'), 485 'zip': address['postcode'], 486 'urb': address['urb'], 487 'suburb': gmTools.coalesce(address['suburb'], u'', u' (%s)'), 488 'l10n_state': address['l10n_state'], 489 'code_state': address['code_state'], 490 'l10n_country': address['l10n_country'], 491 'code_country': address['code_country'] 492 } 493 if show_type: 494 data['type'] = address['l10n_address_type'] 495 template = _( 496 'Address (%(type)s) [#%(pk_adr)s]\n' 497 ' Street: %(street)s%(notes_street)s\n' 498 ' Number/Unit: %(number)s%(subunit)s%(notes_subunit)s\n' 499 ' Location: %(zip)s %(urb)s%(suburb)s\n' 500 ' Region: %(l10n_state)s, %(code_state)s\n' 501 ' Country: %(l10n_country)s, %(code_country)s' 502 ) 503 else: 504 template = _( 505 'Address [#%(pk_adr)s]\n' 506 ' Street: %(street)s%(notes_street)s\n' 507 ' Number/Unit: %(number)s%(subunit)s%(notes_subunit)s\n' 508 ' Location: %(zip)s %(urb)s%(suburb)s\n' 509 ' Region: %(l10n_state)s, %(code_state)s\n' 510 ' Country: %(l10n_country)s, %(code_country)s' 511 ) 512 txt = template % data 513 return txt.split('\n')
514 #------------------------------------------------------------
515 -def get_address_types(identity=None):
516 cmd = u'select id as pk, name, _(name) as l10n_name from dem.address_type' 517 rows, idx = gmPG2.run_rw_queries(queries=[{'cmd': cmd}]) 518 return rows
519 #------------------------------------------------------------
520 -def get_addresses(order_by=None):
521 522 if order_by is None: 523 order_by = u'' 524 else: 525 order_by = u'ORDER BY %s' % order_by 526 527 cmd = u"SELECT * FROM dem.v_address %s" % order_by 528 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 529 return [ cAddress(row = {'data': r, 'idx': idx, 'pk_field': u'pk_address'}) for r in rows ]
530 #------------------------------------------------------------
531 -def get_address_from_patient_address_pk(pk_patient_address=None):
532 cmd = u""" 533 SELECT * FROM dem.v_address WHERE 534 pk_address = ( 535 SELECT id_address 536 FROM dem.lnk_person_org_address 537 WHERE id = %(pk_pat_adr)s 538 ) 539 """ 540 args = {'pk_pat_adr': pk_patient_address} 541 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 542 if len(rows) == 0: 543 return None 544 return cAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': u'pk_address'})
545 546 #===================================================================
547 -def get_patient_address(pk_patient_address=None):
548 cmd = u'SELECT * FROM dem.v_pat_addresses WHERE pk_lnk_person_org_address = %(pk)s' 549 args = {'pk': pk_patient_address} 550 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 551 if len(rows) == 0: 552 return None 553 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': u'pk_address'})
554 #-------------------------------------------------------------------
555 -def get_patient_address_by_type(pk_patient=None, adr_type=None):
556 cmd = u'SELECT * FROM dem.v_pat_addresses WHERE pk_identity = %(pat)s AND address_type = %(typ)s' 557 args = {'pat': pk_patient, 'typ': adr_type} 558 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 559 if len(rows) == 0: 560 return None 561 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': u'pk_address'})
562 #-------------------------------------------------------------------
563 -class cPatientAddress(gmBusinessDBObject.cBusinessDBObject):
564 565 _cmd_fetch_payload = u"SELECT * FROM dem.v_pat_addresses WHERE pk_address = %s" 566 _cmds_store_payload = [ 567 u"""UPDATE dem.lnk_person_org_address SET 568 id_type = %(pk_address_type)s 569 WHERE 570 id = %(pk_lnk_person_org_address)s 571 AND 572 xmin = %(xmin_lnk_person_org_address)s 573 RETURNING 574 xmin AS xmin_lnk_person_org_address 575 """ 576 ] 577 _updatable_fields = ['pk_address_type'] 578 #---------------------------------------------------------------
579 - def get_identities(self, same_lastname=False):
580 pass
581 #--------------------------------------------------------
582 - def format(self, single_line=False, verbose=False, show_type=True):
583 if single_line: 584 return format_address_single_line(address = self, verbose = verbose, show_type = show_type) 585 txt = format_address(address = self, show_type = show_type) 586 return txt
587 #=================================================================== 588 # communication channels API 589 #-------------------------------------------------------------------
590 -class cCommChannel(gmBusinessDBObject.cBusinessDBObject):
591 592 _cmd_fetch_payload = u"SELECT * FROM dem.v_person_comms WHERE pk_lnk_identity2comm = %s" 593 _cmds_store_payload = [ 594 u"""UPDATE dem.lnk_identity2comm SET 595 --fk_address = %(pk_address)s, 596 fk_type = dem.create_comm_type(%(comm_type)s), 597 url = %(url)s, 598 is_confidential = %(is_confidential)s, 599 comment = gm.nullify_empty_string(%(comment)s) 600 WHERE 601 pk = %(pk_lnk_identity2comm)s 602 AND 603 xmin = %(xmin_lnk_identity2comm)s 604 RETURNING 605 xmin AS xmin_lnk_identity2comm 606 """ 607 ] 608 _updatable_fields = [ 609 #'pk_address', 610 'url', 611 'comm_type', 612 'is_confidential', 613 'comment' 614 ]
615 #-------------------------------------------------------------------
616 -class cOrgCommChannel(gmBusinessDBObject.cBusinessDBObject):
617 618 _cmd_fetch_payload = u"SELECT * FROM dem.v_org_unit_comms WHERE pk_lnk_org_unit2comm = %s" 619 _cmds_store_payload = [ 620 u"""UPDATE dem.lnk_org_unit2comm SET 621 fk_type = dem.create_comm_type(%(comm_type)s), 622 url = %(url)s, 623 is_confidential = %(is_confidential)s 624 WHERE 625 pk = %(pk_lnk_org_unit2comm)s 626 AND 627 xmin = %(xmin_lnk_org_unit2comm)s 628 RETURNING 629 xmin AS xmin_lnk_org_unit2comm 630 """ 631 ] 632 _updatable_fields = [ 633 'url', 634 'comm_type', 635 'is_confidential' 636 ]
637 #-------------------------------------------------------------------
638 -def create_comm_channel(comm_medium=None, url=None, is_confidential=False, pk_channel_type=None, pk_identity=None, pk_org_unit=None):
639 """Create a communications channel for a patient.""" 640 641 if url is None: 642 return None 643 644 args = { 645 'url': url, 646 'secret': is_confidential, 647 'pk_type': pk_channel_type, 648 'type': comm_medium 649 } 650 651 if pk_identity is not None: 652 args['pk_owner'] = pk_identity 653 tbl = u'dem.lnk_identity2comm' 654 col = u'fk_identity' 655 view = u'dem.v_person_comms' 656 view_pk = u'pk_lnk_identity2comm' 657 channel_class = cCommChannel 658 if pk_org_unit is not None: 659 args['pk_owner'] = pk_org_unit 660 tbl = u'dem.lnk_org_unit2comm' 661 col = u'fk_org_unit' 662 view = u'dem.v_org_unit_comms' 663 view_pk = u'pk_lnk_org_unit2comm' 664 channel_class = cOrgCommChannel 665 666 if pk_channel_type is None: 667 cmd = u"""INSERT INTO %s ( 668 %s, 669 url, 670 fk_type, 671 is_confidential 672 ) VALUES ( 673 %%(pk_owner)s, 674 %%(url)s, 675 dem.create_comm_type(%%(type)s), 676 %%(secret)s 677 )""" % (tbl, col) 678 else: 679 cmd = u"""INSERT INTO %s ( 680 %s, 681 url, 682 fk_type, 683 is_confidential 684 ) VALUES ( 685 %%(pk_owner)s, 686 %%(url)s, 687 %%(pk_type)s, 688 %%(secret)s 689 )""" % (tbl, col) 690 691 queries = [{'cmd': cmd, 'args': args}] 692 cmd = u"SELECT * FROM %s WHERE %s = currval(pg_get_serial_sequence('%s', 'pk'))" % (view, view_pk, tbl) 693 queries.append({'cmd': cmd}) 694 695 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True) 696 697 if pk_identity is not None: 698 return cCommChannel(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx}) 699 700 return channel_class(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
701 #-------------------------------------------------------------------
702 -def delete_comm_channel(pk=None, pk_patient=None, pk_org_unit=None):
703 if pk_patient is not None: 704 query = { 705 'cmd': u"DELETE FROM dem.lnk_identity2comm WHERE pk = %(pk)s AND fk_identity = %(pat)s", 706 'args': {'pk': pk, 'pat': pk_patient} 707 } 708 if pk_org_unit is not None: 709 query = { 710 'cmd': u"DELETE FROM dem.lnk_org_unit2comm WHERE pk = %(pk)s AND fk_org_unit = %(unit)s", 711 'args': {'pk': pk, 'unit': pk_org_unit} 712 } 713 gmPG2.run_rw_queries(queries = [query])
714 #-------------------------------------------------------------------
715 -def get_comm_channel_types():
716 cmd = u"SELECT pk, _(description) AS l10n_description, description FROM dem.enum_comm_types" 717 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 718 return rows
719 #-------------------------------------------------------------------
720 -def delete_comm_channel_type(pk_channel_type=None):
721 cmd = u""" 722 DELETE FROM dem.enum_comm_types 723 WHERE 724 pk = %(pk)s 725 AND NOT EXISTS ( 726 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_type = %(pk)s 727 ) 728 AND NOT EXISTS ( 729 SELECT 1 FROM dem.lnk_org_unit2comm WHERE fk_type = %(pk)s 730 ) 731 """ 732 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_channel_type}}]) 733 return True
734 #=================================================================== 735 #------------------------------------------------------------------- 736
737 -class cOrg (gmBusinessDBObject.cBusinessDBObject):
738 """ 739 Organisations 740 741 This is also the common ancestor of cIdentity, self._table is used to 742 hide the difference. 743 The aim is to be able to sanely write code which doesn't care whether 744 its talking to an organisation or an individual""" 745 _table = "org" 746 747 _cmd_fetch_payload = "select *, xmin from dem.org where id=%s" 748 _cmds_lock_rows_for_update = ["select 1 from dem.org where id=%(id)s and xmin=%(xmin)s"] 749 _cmds_store_payload = [ 750 """update dem.org set 751 description=%(description)s, 752 id_category=(select id from dem.org_category where description=%(occupation)s) 753 where id=%(id)s""", 754 "select xmin from dem.org where id=%(id)s" 755 ] 756 _updatable_fields = ["description", "occupation"] 757 _service = 'personalia' 758 #------------------------------------------------------------------
759 - def cleanup (self):
760 pass
761 #------------------------------------------------------------------
762 - def export_demographics (self):
763 if not self.__cache.has_key ('addresses'): 764 self['addresses'] 765 if not self.__cache.has_key ('comms'): 766 self['comms'] 767 return self.__cache
768 #--------------------------------------------------------------------
769 - def get_members (self):
770 """ 771 Returns a list of (address dict, cIdentity) tuples 772 """ 773 cmd = """select 774 vba.id, 775 vba.number, 776 vba.addendum, 777 vba.street, 778 vba.urb, 779 vba.postcode, 780 at.name, 781 lpoa.id_type, 782 vbp.pk_identity, 783 title, 784 firstnames, 785 lastnames, 786 dob, 787 cob, 788 gender, 789 pupic, 790 pk_marital_status, 791 marital_status, 792 karyotype, 793 xmin_identity, 794 preferred 795 from 796 dem.v_basic_address vba, 797 dem.lnk_person_org_address lpoa, 798 dem.address_type at, 799 dem.v_basic_person vbp 800 where 801 lpoa.id_address = vba.id 802 and lpoa.id_type = at.id 803 and lpoa.id_identity = vbp.pk_identity 804 and lpoa.id_org = %%s 805 """ 806 807 rows, idx = gmPG.run_ro_query('personalia', cmd, 1, self.getId ()) 808 if rows is None: 809 return [] 810 elif len(rows) == 0: 811 return [] 812 else: 813 return [({'pk':i[0], 'number':i[1], 'addendum':i[2], 'street':i[3], 'city':i[4], 'postcode':i[5], 'type':i[6], 'id_type':i[7]}, cIdentity (row = {'data':i[8:], 'id':idx[8:], 'pk_field':'id'})) for i in rows]
814 #------------------------------------------------------------
815 - def set_member (self, person, address):
816 """ 817 Binds a person to this organisation at this address. 818 person is a cIdentity object 819 address is a dict of {'number', 'street', 'addendum', 'city', 'postcode', 'type'} 820 type is one of the IDs returned by getAddressTypes 821 """ 822 cmd = "insert into dem.lnk_person_org_address (id_type, id_address, id_org, id_identity) values (%(type)s, dem.create_address (%(number)s, %(addendum)s, %(street)s, %(city)s, %(postcode)s), %(org_id)s, %(pk_identity)s)" 823 address['pk_identity'] = person['pk_identity'] 824 address['org_id'] = self.getId() 825 if not id_addr: 826 return (False, None) 827 return gmPG.run_commit2 ('personalia', [(cmd, [address])])
828 #------------------------------------------------------------ 832 #----------------------------------------------------------------------
833 - def getId (self):
834 """ 835 Hide the difference between org.id and v_basic_person.pk_identity 836 """ 837 return self['id']
838 #==============================================================================
839 -def get_time_tuple (mx):
840 """ 841 wrap mx.DateTime brokenness 842 Returns 9-tuple for use with pyhon time functions 843 """ 844 return [ int(x) for x in str(mx).split(' ')[0].split('-') ] + [0,0,0, 0,0,0]
845 #----------------------------------------------------------------
846 -def getAddressTypes():
847 """Gets a dict matching address types to their ID""" 848 row_list = gmPG.run_ro_query('personalia', "select name, id from dem.address_type") 849 if row_list is None: 850 return {} 851 if len(row_list) == 0: 852 return {} 853 return dict (row_list)
854 #----------------------------------------------------------------
855 -def getMaritalStatusTypes():
856 """Gets a dictionary matching marital status types to their internal ID""" 857 row_list = gmPG.run_ro_query('personalia', "select name, pk from dem.marital_status") 858 if row_list is None: 859 return {} 860 if len(row_list) == 0: 861 return {} 862 return dict(row_list)
863 #------------------------------------------------------------------
864 -def getRelationshipTypes():
865 """Gets a dictionary of relationship types to internal id""" 866 row_list = gmPG.run_ro_query('personalia', "select description, id from dem.relation_types") 867 if row_list is None: 868 return None 869 if len (row_list) == 0: 870 return None 871 return dict(row_list)
872 873 #----------------------------------------------------------------
874 -def getUrb (id_urb):
875 cmd = """ 876 select 877 dem.state.name, 878 dem.urb.postcode 879 from 880 dem.urb, 881 dem.state 882 where 883 dem.urb.id = %s and 884 dem.urb.id_state = dem.state.id""" 885 row_list = gmPG.run_ro_query('personalia', cmd, None, id_urb) 886 if not row_list: 887 return None 888 else: 889 return (row_list[0][0], row_list[0][1])
890
891 -def getStreet (id_street):
892 cmd = """ 893 select 894 dem.state.name, 895 coalesce (dem.street.postcode, dem.urb.postcode), 896 dem.urb.name 897 from 898 dem.urb, 899 dem.state, 900 dem.street 901 where 902 dem.street.id = %s and 903 dem.street.id_urb = dem.urb.id and 904 dem.urb.id_state = dem.state.id 905 """ 906 row_list = gmPG.run_ro_query('personalia', cmd, None, id_street) 907 if not row_list: 908 return None 909 else: 910 return (row_list[0][0], row_list[0][1], row_list[0][2])
911
912 -def getCountry (country_code):
913 row_list = gmPG.run_ro_query('personalia', "select name from dem.country where code = %s", None, country_code) 914 if not row_list: 915 return None 916 else: 917 return row_list[0][0]
918 #-------------------------------------------------------------------------------
919 -def get_town_data (town):
920 row_list = gmPG.run_ro_query ('personalia', """ 921 select 922 dem.urb.postcode, 923 dem.state.code, 924 dem.state.name, 925 dem.country.code, 926 dem.country.name 927 from 928 dem.urb, 929 dem.state, 930 dem.country 931 where 932 dem.urb.name = %s and 933 dem.urb.id_state = dem.state.id and 934 dem.state.country = dem.country.code""", None, town) 935 if not row_list: 936 return (None, None, None, None, None) 937 else: 938 return tuple (row_list[0])
939 #============================================================ 940 # callbacks 941 #------------------------------------------------------------
942 -def _post_patient_selection(**kwargs):
943 print "received post_patient_selection notification" 944 print kwargs['kwds']
945 #============================================================ 946 947 #============================================================ 948 # main 949 #------------------------------------------------------------ 950 if __name__ == "__main__": 951 952 if len(sys.argv) < 2: 953 sys.exit() 954 955 if sys.argv[1] != 'test': 956 sys.exit() 957 958 import random 959 #--------------------------------------------------------
960 - def test_address_exists():
961 962 addresses = [ 963 { 964 'country': 'Germany', 965 'state': 'Sachsen', 966 'urb': 'Leipzig', 967 'postcode': '04318', 968 'street': u'Cunnersdorfer Strasse', 969 'number': '11' 970 }, 971 { 972 'country': 'DE', 973 'state': 'SN', 974 'urb': 'Leipzig', 975 'postcode': '04317', 976 'street': u'Riebeckstraße', 977 'number': '65', 978 'subunit': 'Parterre' 979 }, 980 { 981 'country': 'DE', 982 'state': 'SN', 983 'urb': 'Leipzig', 984 'postcode': '04317', 985 'street': u'Riebeckstraße', 986 'number': '65', 987 'subunit': '1. Stock' 988 }, 989 { 990 'country': 'DE', 991 'state': 'SN', 992 'urb': 'Leipzig', 993 'postcode': '04317', 994 'street': u'Riebeckstraße', 995 'number': '65', 996 'subunit': '1. Stock' 997 }, 998 { 999 # 'country': 'DE', 1000 # 'state': 'SN', 1001 'urb': 'Leipzig', 1002 'postcode': '04317', 1003 'street': u'Riebeckstraße', 1004 'number': '65', 1005 'subunit': '1. Stock' 1006 }, 1007 ] 1008 1009 for adr in addresses: 1010 print adr 1011 exists = address_exists(**adr) 1012 if exists is None: 1013 print "address does not exist" 1014 else: 1015 print "address exists, primary key:", exists
1016 1017 #--------------------------------------------------------
1018 - def test_create_address():
1019 address = create_address ( 1020 country ='DE', 1021 state ='SN', 1022 urb ='Leipzig', 1023 suburb ='Sellerhausen', 1024 postcode ='04318', 1025 street = u'Cunnersdorfer Strasse', 1026 number = '11' 1027 # ,notes_subunit = '4.Stock rechts' 1028 ) 1029 print "created existing address" 1030 print address.format() 1031 1032 su = str(random.random()) 1033 1034 address = create_address ( 1035 country ='DE', 1036 state = 'SN', 1037 urb ='Leipzig', 1038 suburb ='Sellerhausen', 1039 postcode ='04318', 1040 street = u'Cunnersdorfer Strasse', 1041 number = '11', 1042 # notes_subunit = '4.Stock rechts', 1043 subunit = su 1044 ) 1045 print "created new address with subunit", su 1046 print address 1047 print address.format() 1048 print "deleted address:", delete_address(pk_address = address['pk_address'])
1049 #--------------------------------------------------------
1050 - def test_get_countries():
1051 for c in get_countries(): 1052 print c
1053 #--------------------------------------------------------
1054 - def test_get_country_for_region():
1055 region = raw_input("Please enter a region: ") 1056 print "country for region [%s] is: %s" % (region, get_country_for_region(region = region))
1057 #--------------------------------------------------------
1058 - def test_delete_tag():
1059 if delete_tag_image(tag_image = 9999): 1060 print "deleted tag 9999" 1061 else: 1062 print "did not delete tag 9999" 1063 if delete_tag_image(tag_image = 1): 1064 print "deleted tag 1" 1065 else: 1066 print "did not delete tag 1"
1067 #--------------------------------------------------------
1068 - def test_tag_images():
1069 tag = cTagImage(aPK_obj = 1) 1070 print tag
1071 #print get_tag_images() 1072 #--------------------------------------------------------
1073 - def test_get_billing_address():
1074 print get_patient_address_by_type(pk_patient = 12, adr_type = u'billing')
1075 #-------------------------------------------------------- 1076 #gmPG2.get_connection() 1077 1078 #test_address_exists() 1079 #test_create_address() 1080 #test_get_countries() 1081 #test_get_country_for_region() 1082 #test_delete_tag() 1083 test_tag_images() 1084 #test_get_billing_address() 1085 1086 sys.exit() 1087 #============================================================ 1088