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