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

Source Code for Module Gnumed.business.gmDemographicRecord

   1  # -*- coding: utf-8 -*- 
   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  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>, I.Haywood <ihaywood@gnu.org>" 
  11   
  12  # stdlib 
  13  import sys 
  14  import os 
  15  import os.path 
  16  import logging 
  17  import urllib.parse 
  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   
  31  #============================================================ 
  32  # occupation handling 
  33  #------------------------------------------------------------ 
34 -def get_occupations(pk_identity=None):
35 cmd = """ 36 SELECT * 37 FROM dem.v_person_jobs 38 WHERE pk_identity = %(pk)s 39 ORDER BY l10n_occupation 40 """ 41 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_identity}}]) 42 return rows
43 #============================================================ 44 # text+image tags 45 #------------------------------------------------------------ 46 _SQL_get_tag_image = "SELECT * FROM ref.v_tag_images_no_data WHERE %s" 47
48 -class cTagImage(gmBusinessDBObject.cBusinessDBObject):
49 50 _cmd_fetch_payload = _SQL_get_tag_image % "pk_tag_image = %s" 51 _cmds_store_payload = [ 52 """ 53 UPDATE ref.tag_image SET 54 description = gm.nullify_empty_string(%(description)s), 55 filename = gm.nullify_empty_string(%(filename)s) 56 WHERE 57 pk = %(pk_tag_image)s 58 AND 59 xmin = %(xmin_tag_image)s 60 RETURNING 61 pk as pk_tag_image, 62 xmin as xmin_tag_image 63 """ 64 ] 65 _updatable_fields = ['description', 'filename'] 66 #--------------------------------------------------------
67 - def export_image2file(self, aChunkSize=0, filename=None):
68 69 if self._payload[self._idx['size']] == 0: 70 return None 71 72 if filename is None: 73 suffix = None 74 # preserve original filename extension if available 75 if self._payload[self._idx['filename']] is not None: 76 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 77 suffix = suffix.strip() 78 if suffix == '': 79 suffix = None 80 # get unique filename 81 filename = gmTools.get_unique_filename ( 82 prefix = 'gm-tag_image-', 83 suffix = suffix 84 ) 85 86 success = gmPG2.bytea2file ( 87 data_query = { 88 'cmd': 'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s', 89 'args': {'pk': self.pk_obj} 90 }, 91 filename = filename, 92 chunk_size = aChunkSize, 93 data_size = self._payload[self._idx['size']] 94 ) 95 96 if success: 97 return filename 98 99 return None
100 #--------------------------------------------------------
101 - def update_image_from_file(self, filename=None):
102 # sanity check 103 if not (os.access(filename, os.R_OK) and os.path.isfile(filename)): 104 _log.error('[%s] is not a readable file' % filename) 105 return False 106 107 gmPG2.file2bytea ( 108 query = "UPDATE ref.tag_image SET image = %(data)s::bytea WHERE pk = %(pk)s", 109 filename = filename, 110 args = {'pk': self.pk_obj} 111 ) 112 113 # must update XMIN now ... 114 self.refetch_payload() 115 return True
116 #------------------------------------------------------------
117 -def get_tag_images(order_by=None):
118 if order_by is None: 119 order_by = 'true' 120 else: 121 order_by = 'true ORDER BY %s' % order_by 122 123 cmd = _SQL_get_tag_image % order_by 124 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 125 return [ cTagImage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_tag_image'}) for r in rows ]
126 #------------------------------------------------------------
127 -def create_tag_image(description=None, link_obj=None):
128 129 args = {'desc': description, 'img': ''} 130 cmd = """ 131 INSERT INTO ref.tag_image ( 132 description, 133 image 134 ) VALUES ( 135 %(desc)s, 136 %(img)s::bytea 137 ) 138 RETURNING pk 139 """ 140 rows, idx = gmPG2.run_rw_queries ( 141 link_obj = link_obj, 142 queries = [{'cmd': cmd, 'args': args}], 143 end_tx = True, 144 return_data = True, 145 get_col_idx = False 146 ) 147 148 return cTagImage(aPK_obj = rows[0]['pk'])
149 #------------------------------------------------------------
150 -def delete_tag_image(tag_image=None):
151 args = {'pk': tag_image} 152 cmd = """ 153 DELETE FROM ref.tag_image 154 WHERE 155 pk = %(pk)s 156 AND 157 NOT EXISTS ( 158 SELECT 1 159 FROM dem.identity_tag 160 WHERE fk_tag = %(pk)s 161 LIMIT 1 162 ) 163 RETURNING 1 164 """ 165 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 166 if len(rows) == 0: 167 return False 168 return True
169 170 #============================================================ 171 _SQL_get_person_tags = """SELECT * FROM dem.v_identity_tags WHERE %s""" 172
173 -class cPersonTag(gmBusinessDBObject.cBusinessDBObject):
174 175 _cmd_fetch_payload = _SQL_get_person_tags % "pk_identity_tag = %s" 176 _cmds_store_payload = [ 177 """ 178 UPDATE dem.identity_tag SET 179 fk_tag = %(pk_tag_image)s, 180 comment = gm.nullify_empty_string(%(comment)s) 181 WHERE 182 pk = %(pk_identity_tag)s 183 AND 184 xmin = %(xmin_identity_tag)s 185 RETURNING 186 pk as pk_identity_tag, 187 xmin as xmin_identity_tag 188 """ 189 ] 190 _updatable_fields = ['fk_tag', 'comment'] 191 #--------------------------------------------------------
192 - def export_image2file(self, aChunkSize=0, filename=None):
193 194 if self._payload[self._idx['image_size']] == 0: 195 return None 196 197 if filename is None: 198 suffix = None 199 # preserve original filename extension if available 200 if self._payload[self._idx['filename']] is not None: 201 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 202 suffix = suffix.strip() 203 if suffix == '': 204 suffix = None 205 # get unique filename 206 filename = gmTools.get_unique_filename ( 207 prefix = 'gm-person_tag-', 208 suffix = suffix 209 ) 210 211 exported = gmPG2.bytea2file ( 212 data_query = { 213 'cmd': 'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s', 214 'args': {'pk': self._payload[self._idx['pk_tag_image']]} 215 }, 216 filename = filename, 217 chunk_size = aChunkSize, 218 data_size = self._payload[self._idx['image_size']] 219 ) 220 if exported: 221 return filename 222 223 return None
224 225 #============================================================ 226 # country/region related 227 #============================================================
228 -def get_countries():
229 cmd = """ 230 SELECT 231 _(name) AS l10n_country, name, code, deprecated 232 FROM dem.country 233 ORDER BY l10n_country""" 234 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 235 return rows
236 237 #------------------------------------------------------------
238 -def get_country_for_region(region=None):
239 cmd = """ 240 SELECT code_country, l10n_country FROM dem.v_region WHERE lower(l10n_region) = lower(%(region)s) 241 union 242 SELECT code_country, l10n_country FROM dem.v_region WHERE lower(region) = lower(%(region)s) 243 """ 244 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'region': region}}]) 245 return rows
246 247 #------------------------------------------------------------
248 -def map_country2code(country=None):
249 cmd = """ 250 SELECT code FROM dem.country WHERE lower(_(name)) = lower(%(country)s) 251 UNION 252 SELECT code FROM dem.country WHERE lower(name) = lower(%(country)s) 253 """ 254 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'country': country}}], get_col_idx = False) 255 if len(rows) == 0: 256 return None 257 return rows[0][0]
258 259 #------------------------------------------------------------
260 -def map_urb_zip_region2country(urb=None, zip=None, region=None):
261 262 args = {'urb': urb, 'zip': zip, 'region': region} 263 cmd = """( 264 -- find by using all known details 265 SELECT 266 1 AS rank, 267 country, 268 l10n_country, 269 code_country 270 FROM dem.v_urb WHERE 271 postcode_urb = %(zip)s 272 AND 273 lower(urb) = lower(%(urb)s) 274 AND 275 ( 276 (lower(region) = lower(coalesce(%(region)s, 'state/territory/province/region not available'))) 277 OR 278 (lower(l10n_region) = lower(coalesce(%(region)s, _('state/territory/province/region not available')))) 279 ) 280 281 ) UNION ( 282 283 -- find by using zip/urb 284 SELECT 285 2 AS rank, 286 country, 287 l10n_country, 288 code_country 289 FROM dem.v_urb WHERE 290 postcode_urb = %(zip)s 291 AND 292 lower(urb) = lower(%(urb)s) 293 294 ) UNION ( 295 296 -- find by using zip/region 297 SELECT 298 2 AS rank, 299 country, 300 l10n_country, 301 code_country 302 FROM dem.v_urb WHERE 303 postcode_urb = %(zip)s 304 AND 305 ( 306 (lower(region) = lower(%(region)s)) 307 OR 308 (lower(l10n_region) = lower(%(region)s)) 309 ) 310 311 ) UNION ( 312 313 -- find by using urb/region 314 SELECT 315 2 AS rank, 316 country, 317 l10n_country, 318 code_country 319 FROM dem.v_urb WHERE 320 lower(urb) = lower(%(urb)s) 321 AND 322 ((lower(region) = lower(%(region)s)) 323 OR 324 (lower(l10n_region) = lower(%(region)s))) 325 326 ) UNION ( 327 328 -- find by region 329 SELECT 330 2 AS rank, 331 country, 332 l10n_country, 333 code_country 334 FROM dem.v_region WHERE 335 lower(region) = lower(%(region)s) 336 OR 337 lower(l10n_region) = lower(%(region)s) 338 339 ) ORDER BY rank""" 340 341 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 342 if len(rows) == 0: 343 _log.debug('zip [%s] / urb [%s] / region [%s] => ??', zip, urb, region) 344 return None 345 if len(rows) > 2: 346 _log.debug('zip [%s] / urb [%s] / region [%s] => [%s]', zip, urb, region, rows) 347 return None 348 country = rows[0] 349 _log.debug('zip [%s] / urb [%s] / region [%s] => [%s]', zip, urb, region, country) 350 return country
351 352 #------------------------------------------------------------
353 -def map_urb_zip_country2region(urb=None, zip=None, country=None, country_code=None):
354 355 args = {'urb': urb, 'zip': zip, 'country': country, 'country_code': country_code} 356 cmd = """( 357 -- find by using all known details 358 SELECT 359 1 AS rank, 360 region, 361 l10n_region, 362 code_region 363 FROM dem.v_urb WHERE 364 postcode_urb = %(zip)s 365 AND 366 lower(urb) = lower(%(urb)s) 367 AND 368 ( 369 (lower(country) = lower(%(country)s)) 370 OR 371 (lower(l10n_country) = lower(%(country)s)) 372 OR 373 (code_country = %(country_code)s) 374 ) 375 376 ) UNION ( 377 378 -- find by zip / urb 379 SELECT 380 2 AS rank, 381 region, 382 l10n_region, 383 code_region 384 FROM dem.v_urb WHERE 385 postcode_urb = %(zip)s 386 AND 387 lower(urb) = lower(%(urb)s) 388 389 ) UNION ( 390 391 -- find by zip / country 392 SELECT 393 2 AS rank, 394 region, 395 l10n_region, 396 code_region 397 FROM dem.v_urb WHERE 398 postcode_urb = %(zip)s 399 AND 400 ( 401 (lower(country) = lower(%(country)s)) 402 OR 403 (lower(l10n_country) = lower(%(country)s)) 404 OR 405 (code_country = %(country_code)s) 406 ) 407 408 ) UNION ( 409 410 -- find by urb / country 411 SELECT 412 2 AS rank, 413 region, 414 l10n_region, 415 code_region 416 FROM dem.v_urb WHERE 417 lower(urb) = lower(%(urb)s) 418 AND 419 ( 420 (lower(country) = lower(%(country)s)) 421 OR 422 (lower(l10n_country) = lower(%(country)s)) 423 OR 424 (code_country = %(country_code)s) 425 ) 426 427 ) ORDER BY rank""" 428 429 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 430 431 if len(rows) == 0: 432 cmd = """ 433 -- find by country (some countries will only have one region) 434 SELECT 435 1 AS rank, -- dummy to conform with function result structure at Python level 436 region, 437 l10n_region, 438 code_region 439 FROM dem.v_region WHERE 440 (lower(country) = lower(%(country)s)) 441 OR 442 (lower(l10n_country) = lower(%(country)s)) 443 OR 444 (code_country = %(country_code)s) 445 """ 446 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 447 if len(rows) == 1: 448 region = rows[0] 449 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, region) 450 return region 451 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [??]', zip, urb, country, country_code) 452 return None 453 454 if len(rows) > 2: 455 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, rows) 456 return None 457 458 region = rows[0] 459 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, region) 460 return region
461 462 #------------------------------------------------------------
463 -def map_region2code(region=None, country_code=None):
464 if country_code is None: 465 cmd = """ 466 SELECT code FROM dem.region WHERE lower(_(name)) = lower(%(region)s) 467 UNION 468 SELECT code FROM dem.region WHERE lower(name) = lower(%(region)s) 469 """ 470 else: 471 cmd = """ 472 SELECT code FROM dem.region WHERE lower(_(name)) = lower(%(region)s) AND lower(country) = lower(%(country_code)s) 473 UNION 474 SELECT code FROM dem.region WHERE lower(name) = %(region)s AND lower(country) = lower(%(country_code)s) 475 """ 476 args = { 477 'country_code': country_code, 478 'region': region 479 } 480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 481 if len(rows) == 0: 482 return None 483 return rows[0][0]
484 485 #------------------------------------------------------------
486 -def delete_region(region=None, delete_urbs=False):
487 488 args = {'region': region} 489 490 queries = [] 491 if delete_urbs: 492 queries.append ({ 493 'cmd': """ 494 delete from dem.urb du 495 where 496 du.fk_region = %(region)s 497 and 498 not exists (select 1 from dem.street ds where ds.id_urb = du.id)""", 499 'args': args 500 }) 501 502 queries.append ({ 503 'cmd': """ 504 DELETE FROM dem.region d_r 505 WHERE 506 d_r.pk = %(region)s 507 AND 508 NOT EXISTS (SELECT 1 FROM dem.urb du WHERE du.fk_region = d_r.pk)""", 509 'args': args 510 }) 511 512 gmPG2.run_rw_queries(queries = queries) 513 514 return True
515 516 #------------------------------------------------------------
517 -def create_region(name=None, code=None, country=None):
518 519 args = {'code': code, 'country': country, 'name': name} 520 521 cmd = """SELECT EXISTS (SELECT 1 FROM dem.region WHERE name = %(name)s)""" 522 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 523 524 if rows[0][0]: 525 return 526 527 cmd = """ 528 INSERT INTO dem.region ( 529 code, country, name 530 ) VALUES ( 531 %(code)s, %(country)s, %(name)s 532 )""" 533 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
534 #------------------------------------------------------------
535 -def get_regions():
536 cmd = """ 537 select 538 l10n_region, l10n_country, region, code_region, code_country, pk_region, country_deprecated 539 from dem.v_region 540 order by l10n_country, l10n_region""" 541 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}]) 542 return rows
543 544 #============================================================ 545 # address related classes 546 #------------------------------------------------------------
547 -class cAddress(gmBusinessDBObject.cBusinessDBObject):
548 """A class representing an address as an entity in itself. 549 550 We consider addresses to be self-complete "labels" for locations. 551 It does not depend on any people actually living there. Thus 552 an address can get attached to as many people as we want to 553 signify that that is their place of residence/work/... 554 555 This class acts on the address as an entity. Therefore it can 556 modify the address fields. Think carefully about *modifying* 557 addresses attached to people, though. Most times when you think 558 person.modify_address() what you *really* want is as sequence of 559 person.unlink_address(old) and person.link_address(new). 560 561 Modifying an address may or may not be the proper thing to do as 562 it will transparently modify the address for *all* the people to 563 whom it is attached. In many cases you will want to create a *new* 564 address and link it to a person instead of the old address. 565 """ 566 _cmd_fetch_payload = "SELECT * FROM dem.v_address WHERE pk_address = %s" 567 _cmds_store_payload = [ 568 """UPDATE dem.address SET 569 aux_street = %(notes_street)s, 570 subunit = %(subunit)s, 571 addendum = %(notes_subunit)s, 572 lat_lon = %(lat_lon_street)s 573 WHERE 574 id = %(pk_address)s 575 AND 576 xmin = %(xmin_address)s 577 RETURNING 578 xmin AS xmin_address""" 579 ] 580 _updatable_fields = [ 581 'notes_street', 582 'subunit', 583 'notes_subunit', 584 'lat_lon_address' 585 ] 586 #--------------------------------------------------------
587 - def format(self, single_line=False, verbose=False, show_type=False):
588 if single_line: 589 return format_address_single_line(address = self, show_type = False, verbose = verbose) 590 return format_address(address = self, show_type = False)
591 592 #--------------------------------------------------------
593 - def _get_as_map_url(self):
594 url = 'http://nominatim.openstreetmap.org/search/%s/%s/%s/%s?limit=3' % ( 595 urllib.parse.quote(self['country'].encode('utf8')), 596 urllib.parse.quote(self['urb'].encode('utf8')), 597 urllib.parse.quote(self['street'].encode('utf8')), 598 urllib.parse.quote(self['number'].encode('utf8')) 599 ) 600 return url
601 602 as_map_url = property(_get_as_map_url, lambda x:x)
603 604 #------------------------------------------------------------
605 -def address_exists(country_code=None, region_code=None, urb=None, postcode=None, street=None, number=None, subunit=None):
606 607 cmd = """SELECT dem.address_exists(%(country_code)s, %(region_code)s, %(urb)s, %(postcode)s, %(street)s, %(number)s, %(subunit)s)""" 608 args = { 609 'country_code': country_code, 610 'region_code': region_code, 611 'urb': urb, 612 'postcode': postcode, 613 'street': street, 614 'number': number, 615 'subunit': subunit 616 } 617 618 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 619 if rows[0][0] is None: 620 _log.debug('address does not exist') 621 for key, val in args.items(): 622 _log.debug('%s: %s', key, val) 623 return None 624 625 return rows[0][0]
626 627 #------------------------------------------------------------
628 -def create_address(country_code=None, region_code=None, urb=None, suburb=None, postcode=None, street=None, number=None, subunit=None):
629 630 if suburb is not None: 631 suburb = gmTools.none_if(suburb.strip(), '') 632 633 pk_address = address_exists ( 634 country_code = country_code, 635 region_code = region_code, 636 urb = urb, 637 # suburb = suburb, 638 postcode = postcode, 639 street = street, 640 number = number, 641 subunit = subunit 642 ) 643 if pk_address is not None: 644 return cAddress(aPK_obj = pk_address) 645 646 cmd = """ 647 SELECT dem.create_address ( 648 %(number)s, 649 %(street)s, 650 %(postcode)s, 651 %(urb)s, 652 %(region_code)s, 653 %(country_code)s, 654 %(subunit)s 655 )""" 656 args = { 657 'number': number, 658 'street': street, 659 'postcode': postcode, 660 'urb': urb, 661 'region_code': region_code, 662 'country_code': country_code, 663 'subunit': subunit 664 } 665 queries = [{'cmd': cmd, 'args': args}] 666 667 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True) 668 adr = cAddress(aPK_obj = rows[0][0]) 669 670 if suburb is not None: 671 queries = [{ 672 # CAVE: suburb will be ignored if there already is one 673 'cmd': "UPDATE dem.street SET suburb = %(suburb)s WHERE id = %(pk_street)s AND suburb IS NULL", 674 'args': {'suburb': suburb, 'pk_street': adr['pk_street']} 675 }] 676 rows, idx = gmPG2.run_rw_queries(queries = queries) 677 678 return adr
679 #------------------------------------------------------------
680 -def delete_address(pk_address=None):
681 cmd = """ 682 DELETE FROM dem.address 683 WHERE 684 id = %(pk)s 685 AND 686 NOT EXISTS (( 687 SELECT 1 FROM dem.org_unit WHERE fk_address = %(pk)s LIMIT 1 688 ) UNION ( 689 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_address = %(pk)s LIMIT 1 690 ) UNION ( 691 SELECT 1 FROM dem.lnk_person_org_address WHERE id_address = %(pk)s LIMIT 1 692 )) 693 """ 694 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_address}}]) 695 return True
696 697 #------------------------------------------------------------
698 -def format_address_single_line(address=None, verbose=False, show_type=False):
699 data = { 700 'pk_adr': address['pk_address'], 701 'street': address['street'], 702 'notes_street': gmTools.coalesce(address['notes_street'], '', ' (%s)'), 703 'number': address['number'], 704 'subunit': gmTools.coalesce(address['subunit'], '', '/%s'), 705 'notes_subunit': gmTools.coalesce(address['notes_subunit'], '', ' (%s)'), 706 'zip': address['postcode'], 707 'urb': address['urb'], 708 'suburb': gmTools.coalesce(address['suburb'], '', ' (%s)'), 709 'l10n_region': address['l10n_region'], 710 'code_region': address['code_region'], 711 'l10n_country': address['l10n_country'], 712 'code_country': address['code_country'] 713 } 714 if show_type: 715 data['type'] = address['l10n_address_type'] 716 717 if verbose: 718 if show_type: 719 template = _('%(type)s: %(street)s %(number)s%(subunit)s, %(zip)s %(urb)s %(suburb)s, %(code_region)s, %(code_country)s (%(l10n_region)s, %(l10n_country)s)') 720 else: 721 template = _('%(street)s %(number)s%(subunit)s, %(zip)s %(urb)s %(suburb)s, %(code_region)s, %(code_country)s (%(l10n_region)s, %(l10n_country)s)') 722 else: 723 if show_type: 724 template = _('%(type)s: %(street)s %(number)s%(subunit)s, %(zip)s %(urb)s, %(code_region)s, %(code_country)s (%(l10n_region)s, %(l10n_country)s)') 725 else: 726 template = _('%(street)s %(number)s%(subunit)s, %(zip)s %(urb)s, %(code_region)s, %(code_country)s (%(l10n_region)s, %(l10n_country)s)') 727 728 return template % data
729 730 #------------------------------------------------------------
731 -def format_address(address=None, show_type=False):
732 data = { 733 'pk_adr': address['pk_address'], 734 'street': address['street'], 735 'notes_street': gmTools.coalesce(address['notes_street'], '', ' (%s)'), 736 'number': address['number'], 737 'subunit': gmTools.coalesce(address['subunit'], '', '/%s'), 738 'notes_subunit': gmTools.coalesce(address['notes_subunit'], '', ' (%s)'), 739 'zip': address['postcode'], 740 'urb': address['urb'], 741 'suburb': gmTools.coalesce(address['suburb'], '', ' (%s)'), 742 'l10n_region': address['l10n_region'], 743 'code_region': address['code_region'], 744 'l10n_country': address['l10n_country'], 745 'code_country': address['code_country'] 746 } 747 if show_type: 748 data['type'] = address['l10n_address_type'] 749 template = _( 750 'Address (%(type)s) [#%(pk_adr)s]\n' 751 ' Street: %(street)s%(notes_street)s\n' 752 ' Number/Unit: %(number)s%(subunit)s%(notes_subunit)s\n' 753 ' Location: %(zip)s %(urb)s%(suburb)s\n' 754 ' Region: %(l10n_region)s, %(code_region)s\n' 755 ' Country: %(l10n_country)s, %(code_country)s' 756 ) 757 else: 758 template = _( 759 'Address [#%(pk_adr)s]\n' 760 ' Street: %(street)s%(notes_street)s\n' 761 ' Number/Unit: %(number)s%(subunit)s%(notes_subunit)s\n' 762 ' Location: %(zip)s %(urb)s%(suburb)s\n' 763 ' Region: %(l10n_region)s, %(code_region)s\n' 764 ' Country: %(l10n_country)s, %(code_country)s' 765 ) 766 txt = template % data 767 return txt.split('\n')
768 769 #------------------------------------------------------------
770 -def create_address_type(address_type=None):
771 args = {'typ': address_type} 772 cmd = 'INSERT INTO dem.address_type (name) SELECT %(typ)s WHERE NOT EXISTS (SELECT 1 FROM dem.address_type WHERE name = %(typ)s OR _(name) = %(typ)s)' 773 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 774 cmd = 'SELECT id FROM dem.address_type WHERE name = %(typ)s OR _(name) = %(typ)s' 775 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 776 return rows[0][0]
777 778 #------------------------------------------------------------
779 -def get_address_types(identity=None):
780 cmd = 'select id as pk, name, _(name) as l10n_name from dem.address_type' 781 rows, idx = gmPG2.run_rw_queries(queries=[{'cmd': cmd}]) 782 return rows
783 #------------------------------------------------------------
784 -def get_addresses(order_by=None):
785 786 if order_by is None: 787 order_by = '' 788 else: 789 order_by = 'ORDER BY %s' % order_by 790 791 cmd = "SELECT * FROM dem.v_address %s" % order_by 792 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 793 return [ cAddress(row = {'data': r, 'idx': idx, 'pk_field': 'pk_address'}) for r in rows ]
794 #------------------------------------------------------------
795 -def get_address_from_patient_address_pk(pk_patient_address=None):
796 cmd = """ 797 SELECT * FROM dem.v_address WHERE 798 pk_address = ( 799 SELECT id_address 800 FROM dem.lnk_person_org_address 801 WHERE id = %(pk_pat_adr)s 802 ) 803 """ 804 args = {'pk_pat_adr': pk_patient_address} 805 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 806 if len(rows) == 0: 807 return None 808 return cAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
809 810 #===================================================================
811 -def get_patient_address(pk_patient_address=None):
812 cmd = 'SELECT * FROM dem.v_pat_addresses WHERE pk_lnk_person_org_address = %(pk)s' 813 args = {'pk': pk_patient_address} 814 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 815 if len(rows) == 0: 816 return None 817 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
818 819 #-------------------------------------------------------------------
820 -def get_patient_address_by_type(pk_patient=None, adr_type=None):
821 cmd = 'SELECT * FROM dem.v_pat_addresses WHERE pk_identity = %(pat)s AND (address_type = %(typ)s OR l10n_address_type = %(typ)s)' 822 args = {'pat': pk_patient, 'typ': adr_type} 823 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 824 if len(rows) == 0: 825 return None 826 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
827 828 #-------------------------------------------------------------------
829 -class cPatientAddress(gmBusinessDBObject.cBusinessDBObject):
830 831 _cmd_fetch_payload = "SELECT * FROM dem.v_pat_addresses WHERE pk_address = %s" 832 _cmds_store_payload = [ 833 """UPDATE dem.lnk_person_org_address SET 834 id_type = %(pk_address_type)s 835 WHERE 836 id = %(pk_lnk_person_org_address)s 837 AND 838 xmin = %(xmin_lnk_person_org_address)s 839 RETURNING 840 xmin AS xmin_lnk_person_org_address 841 """ 842 ] 843 _updatable_fields = ['pk_address_type'] 844 #---------------------------------------------------------------
845 - def get_identities(self, same_lastname=False):
846 pass
847 #--------------------------------------------------------
848 - def format(self, single_line=False, verbose=False, show_type=True):
849 if single_line: 850 return format_address_single_line(address = self, verbose = verbose, show_type = show_type) 851 txt = format_address(address = self, show_type = show_type) 852 return txt
853 #--------------------------------------------------------
854 - def _get_address(self):
855 return cAddress(aPK_obj = self._payload[self._idx['pk_address']])
856 857 address = property(_get_address, lambda x:x) 858 859 #--------------------------------------------------------
860 - def _get_as_map_url(self):
861 return self.address.as_map_url
862 863 as_map_url = property(_get_as_map_url, lambda x:x)
864 865 #=================================================================== 866 # communication channels API 867 #-------------------------------------------------------------------
868 -class cCommChannel(gmBusinessDBObject.cBusinessDBObject):
869 870 _cmd_fetch_payload = "SELECT * FROM dem.v_person_comms WHERE pk_lnk_identity2comm = %s" 871 _cmds_store_payload = [ 872 """UPDATE dem.lnk_identity2comm SET 873 --fk_address = %(pk_address)s, 874 fk_type = dem.create_comm_type(%(comm_type)s), 875 url = %(url)s, 876 is_confidential = %(is_confidential)s, 877 comment = gm.nullify_empty_string(%(comment)s) 878 WHERE 879 pk = %(pk_lnk_identity2comm)s 880 AND 881 xmin = %(xmin_lnk_identity2comm)s 882 RETURNING 883 xmin AS xmin_lnk_identity2comm 884 """ 885 ] 886 _updatable_fields = [ 887 'url', 888 'comm_type', 889 'is_confidential', 890 'comment' 891 ]
892 893 #-------------------------------------------------------------------
894 -class cOrgCommChannel(gmBusinessDBObject.cBusinessDBObject):
895 896 _cmd_fetch_payload = "SELECT * FROM dem.v_org_unit_comms WHERE pk_lnk_org_unit2comm = %s" 897 _cmds_store_payload = [ 898 """UPDATE dem.lnk_org_unit2comm SET 899 fk_type = dem.create_comm_type(%(comm_type)s), 900 url = %(url)s, 901 is_confidential = %(is_confidential)s, 902 comment = gm.nullify_empty_string(%(comment)s) 903 WHERE 904 pk = %(pk_lnk_org_unit2comm)s 905 AND 906 xmin = %(xmin_lnk_org_unit2comm)s 907 RETURNING 908 xmin AS xmin_lnk_org_unit2comm 909 """ 910 ] 911 _updatable_fields = [ 912 'url', 913 'comm_type', 914 'is_confidential', 915 'comment' 916 ]
917 918 #-------------------------------------------------------------------
919 -def create_comm_channel(comm_medium=None, url=None, is_confidential=False, pk_channel_type=None, pk_identity=None, pk_org_unit=None):
920 """Create a communications channel for a patient.""" 921 922 if url is None: 923 return None 924 925 args = { 926 'url': url, 927 'secret': is_confidential, 928 'pk_type': pk_channel_type, 929 'type': comm_medium 930 } 931 932 if pk_identity is not None: 933 args['pk_owner'] = pk_identity 934 tbl = 'dem.lnk_identity2comm' 935 col = 'fk_identity' 936 view = 'dem.v_person_comms' 937 view_pk = 'pk_lnk_identity2comm' 938 channel_class = cCommChannel 939 if pk_org_unit is not None: 940 args['pk_owner'] = pk_org_unit 941 tbl = 'dem.lnk_org_unit2comm' 942 col = 'fk_org_unit' 943 view = 'dem.v_org_unit_comms' 944 view_pk = 'pk_lnk_org_unit2comm' 945 channel_class = cOrgCommChannel 946 947 if pk_channel_type is None: 948 cmd = """INSERT INTO %s ( 949 %s, 950 url, 951 fk_type, 952 is_confidential 953 ) VALUES ( 954 %%(pk_owner)s, 955 %%(url)s, 956 dem.create_comm_type(%%(type)s), 957 %%(secret)s 958 )""" % (tbl, col) 959 else: 960 cmd = """INSERT INTO %s ( 961 %s, 962 url, 963 fk_type, 964 is_confidential 965 ) VALUES ( 966 %%(pk_owner)s, 967 %%(url)s, 968 %%(pk_type)s, 969 %%(secret)s 970 )""" % (tbl, col) 971 972 queries = [{'cmd': cmd, 'args': args}] 973 cmd = "SELECT * FROM %s WHERE %s = currval(pg_get_serial_sequence('%s', 'pk'))" % (view, view_pk, tbl) 974 queries.append({'cmd': cmd}) 975 976 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True) 977 978 if pk_identity is not None: 979 return cCommChannel(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx}) 980 981 return channel_class(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
982 #-------------------------------------------------------------------
983 -def delete_comm_channel(pk=None, pk_patient=None, pk_org_unit=None):
984 if pk_patient is not None: 985 query = { 986 'cmd': "DELETE FROM dem.lnk_identity2comm WHERE pk = %(pk)s AND fk_identity = %(pat)s", 987 'args': {'pk': pk, 'pat': pk_patient} 988 } 989 if pk_org_unit is not None: 990 query = { 991 'cmd': "DELETE FROM dem.lnk_org_unit2comm WHERE pk = %(pk)s AND fk_org_unit = %(unit)s", 992 'args': {'pk': pk, 'unit': pk_org_unit} 993 } 994 gmPG2.run_rw_queries(queries = [query])
995 #-------------------------------------------------------------------
996 -def get_comm_channel_types():
997 cmd = "SELECT pk, _(description) AS l10n_description, description FROM dem.enum_comm_types" 998 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False) 999 return rows
1000 #-------------------------------------------------------------------
1001 -def delete_comm_channel_type(pk_channel_type=None):
1002 cmd = """ 1003 DELETE FROM dem.enum_comm_types 1004 WHERE 1005 pk = %(pk)s 1006 AND NOT EXISTS ( 1007 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_type = %(pk)s 1008 ) 1009 AND NOT EXISTS ( 1010 SELECT 1 FROM dem.lnk_org_unit2comm WHERE fk_type = %(pk)s 1011 ) 1012 """ 1013 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_channel_type}}]) 1014 return True
1015 #=================================================================== 1016 #------------------------------------------------------------------- 1017 1018 #==============================================================================
1019 -def get_time_tuple (mx):
1020 """ 1021 wrap mx.DateTime brokenness 1022 Returns 9-tuple for use with pyhon time functions 1023 """ 1024 return [ int(x) for x in str(mx).split(' ')[0].split('-') ] + [0,0,0, 0,0,0]
1025 #----------------------------------------------------------------
1026 -def getAddressTypes():
1027 """Gets a dict matching address types to their ID""" 1028 row_list = gmPG.run_ro_query('personalia', "select name, id from dem.address_type") 1029 if row_list is None: 1030 return {} 1031 if len(row_list) == 0: 1032 return {} 1033 return dict (row_list)
1034 #----------------------------------------------------------------
1035 -def getMaritalStatusTypes():
1036 """Gets a dictionary matching marital status types to their internal ID""" 1037 row_list = gmPG.run_ro_query('personalia', "select name, pk from dem.marital_status") 1038 if row_list is None: 1039 return {} 1040 if len(row_list) == 0: 1041 return {} 1042 return dict(row_list)
1043 #------------------------------------------------------------------
1044 -def getRelationshipTypes():
1045 """Gets a dictionary of relationship types to internal id""" 1046 row_list = gmPG.run_ro_query('personalia', "select description, id from dem.relation_types") 1047 if row_list is None: 1048 return None 1049 if len (row_list) == 0: 1050 return None 1051 return dict(row_list)
1052 1053 #----------------------------------------------------------------
1054 -def getUrb (id_urb):
1055 cmd = """ 1056 select 1057 dem.region.name, 1058 dem.urb.postcode 1059 from 1060 dem.urb, 1061 dem.region 1062 where 1063 dem.urb.id = %s and 1064 dem.urb.fk_region = dem.region.pk""" 1065 row_list = gmPG.run_ro_query('personalia', cmd, None, id_urb) 1066 if not row_list: 1067 return None 1068 else: 1069 return (row_list[0][0], row_list[0][1])
1070
1071 -def getStreet (id_street):
1072 cmd = """ 1073 select 1074 dem.region.name, 1075 coalesce (dem.street.postcode, dem.urb.postcode), 1076 dem.urb.name 1077 from 1078 dem.urb, 1079 dem.region, 1080 dem.street 1081 where 1082 dem.street.id = %s and 1083 dem.street.id_urb = dem.urb.id and 1084 dem.urb.fk_region = dem.region.pk 1085 """ 1086 row_list = gmPG.run_ro_query('personalia', cmd, None, id_street) 1087 if not row_list: 1088 return None 1089 else: 1090 return (row_list[0][0], row_list[0][1], row_list[0][2])
1091
1092 -def getCountry (country_code):
1093 row_list = gmPG.run_ro_query('personalia', "select name from dem.country where code = %s", None, country_code) 1094 if not row_list: 1095 return None 1096 else: 1097 return row_list[0][0]
1098 #-------------------------------------------------------------------------------
1099 -def get_town_data (town):
1100 row_list = gmPG.run_ro_query ('personalia', """ 1101 select 1102 dem.urb.postcode, 1103 dem.region.code, 1104 dem.region.name, 1105 dem.country.code, 1106 dem.country.name 1107 from 1108 dem.urb, 1109 dem.region, 1110 dem.country 1111 where 1112 dem.urb.name = %s and 1113 dem.urb.fk_region = dem.region.pk and 1114 dem.region.country = dem.country.code""", None, town) 1115 if not row_list: 1116 return (None, None, None, None, None) 1117 else: 1118 return tuple (row_list[0])
1119 #============================================================ 1120 # callbacks 1121 #------------------------------------------------------------
1122 -def _post_patient_selection(**kwargs):
1123 print("received post_patient_selection notification") 1124 print(kwargs['kwds'])
1125 #============================================================ 1126 1127 #============================================================ 1128 # main 1129 #------------------------------------------------------------ 1130 if __name__ == "__main__": 1131 1132 if len(sys.argv) < 2: 1133 sys.exit() 1134 1135 if sys.argv[1] != 'test': 1136 sys.exit() 1137 1138 import random 1139 #--------------------------------------------------------
1140 - def test_address_exists():
1141 1142 addresses = [ 1143 { 1144 'country': 'Germany', 1145 'region_code': 'Sachsen', 1146 'urb': 'Hannover', 1147 'postcode': '06672', 1148 'street': 'Rommelsberger Strasse', 1149 'number': '11' 1150 }, 1151 { 1152 'country': 'DE', 1153 'region_code': 'SN', 1154 'urb': 'Hannover', 1155 'postcode': '06671', 1156 'street': 'Tonnenstraße', 1157 'number': '65', 1158 'subunit': 'Parterre' 1159 }, 1160 { 1161 'country': 'DE', 1162 'region_code': 'SN', 1163 'urb': 'Hannover', 1164 'postcode': '06671', 1165 'street': 'Tonnenstraße', 1166 'number': '65', 1167 'subunit': '1. Stock' 1168 }, 1169 { 1170 'country': 'DE', 1171 'region_code': 'SN', 1172 'urb': 'Hannover', 1173 'postcode': '06671', 1174 'street': 'Tonnenstraße', 1175 'number': '65', 1176 'subunit': '1. Stock' 1177 }, 1178 { 1179 # 'country': 'DE', 1180 # 'region_code': 'HV', 1181 'urb': 'Hannover', 1182 'postcode': '06671', 1183 'street': 'Tonnenstraße', 1184 'number': '65', 1185 'subunit': '1. Stock' 1186 }, 1187 ] 1188 1189 for adr in addresses: 1190 print(adr) 1191 exists = address_exists(**adr) 1192 if exists is None: 1193 print("address does not exist") 1194 else: 1195 print("address exists, primary key:", exists)
1196 1197 #--------------------------------------------------------
1198 - def test_create_address():
1199 address = create_address ( 1200 country_code = 'DE', 1201 region_code = 'SN', 1202 urb ='Hannover', 1203 suburb ='Grabenthal', 1204 postcode ='06672', 1205 street = 'Rommelsberger Strasse', 1206 number = '11' 1207 # ,notes_subunit = '2.Stock oben' 1208 ) 1209 print("created existing address") 1210 print(address.format()) 1211 1212 su = str(random.random()) 1213 1214 address = create_address ( 1215 country_code = 'DE', 1216 region_code = 'SN', 1217 urb ='Hannover', 1218 suburb ='Grabenthal', 1219 postcode ='06672', 1220 street = 'Rommelsberger Strasse', 1221 number = '11', 1222 # notes_subunit = '2.Stock oben', 1223 subunit = su 1224 ) 1225 print("created new address with subunit", su) 1226 print(address) 1227 print(address.format()) 1228 print(address.as_map_url) 1229 print("deleted address:", delete_address(pk_address = address['pk_address']))
1230 #--------------------------------------------------------
1231 - def test_get_countries():
1232 for c in get_countries(): 1233 print(c)
1234 #--------------------------------------------------------
1235 - def test_get_country_for_region():
1236 region = input("Please enter a region: ") 1237 print("country for region [%s] is: %s" % (region, get_country_for_region(region = region)))
1238 #--------------------------------------------------------
1239 - def test_delete_tag():
1240 if delete_tag_image(tag_image = 9999): 1241 print("deleted tag 9999") 1242 else: 1243 print("did not delete tag 9999") 1244 if delete_tag_image(tag_image = 1): 1245 print("deleted tag 1") 1246 else: 1247 print("did not delete tag 1")
1248 #--------------------------------------------------------
1249 - def test_tag_images():
1250 tag = cTagImage(aPK_obj = 1) 1251 print(tag)
1252 #print get_tag_images() 1253 #--------------------------------------------------------
1254 - def test_get_billing_address():
1255 print(get_patient_address_by_type(pk_patient = 12, adr_type = 'billing'))
1256 #--------------------------------------------------------
1257 - def test_map_urb_zip_region2country():
1258 print(map_urb_zip_region2country(urb = 'Kassel', zip = '34119', region = 'Hessen')) 1259 print(map_urb_zip_region2country(urb = 'Kassel', zip = None, region = 'Hessen')) 1260 print(map_urb_zip_region2country(urb = None, zip = '34119', region = 'Hessen')) 1261 print(map_urb_zip_region2country(urb = 'Kassel', zip = '34119', region = None))
1262 #--------------------------------------------------------
1263 - def test_map_urb_zip_country2region():
1264 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = 'DE')) 1265 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = None)) 1266 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = 'DE')) 1267 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = None)) 1268 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = 'DE')) 1269 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = None))
1270 1271 # print map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = u'Deutschland', country_code = 'DE') 1272 # print map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = u'Deutschland', country_code = 'DE') 1273 # print map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = u'Deutschland', country_code = 'DE') 1274 # print map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = u'Deutschland', country_code = 'DE') 1275 1276 #-------------------------------------------------------- 1277 #gmPG2.get_connection() 1278 1279 #test_address_exists() 1280 test_create_address() 1281 #test_get_countries() 1282 #test_get_country_for_region() 1283 #test_delete_tag() 1284 #test_tag_images() 1285 #test_get_billing_address() 1286 #test_map_urb_zip_region2country() 1287 #test_map_urb_zip_country2region() 1288