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

Source Code for Module Gnumed.business.gmOrganization

   1  """Organization classes 
   2   
   3  author: Karsten Hilbert et al 
   4  """ 
   5  #============================================================ 
   6  __license__ = "GPL" 
   7   
   8   
   9  import sys, logging 
  10   
  11   
  12  if __name__ == '__main__': 
  13          sys.path.insert(0, '../../') 
  14  from Gnumed.pycommon import gmPG2 
  15  from Gnumed.pycommon import gmTools 
  16  from Gnumed.pycommon import gmBusinessDBObject 
  17   
  18  from Gnumed.business import gmDemographicRecord 
  19   
  20   
  21  _log = logging.getLogger('gm.org') 
  22   
  23  #============================================================ 
24 -def create_org_category(category=None, link_obj=None):
25 args = {'cat': category} 26 cmd1 = """INSERT INTO dem.org_category (description) SELECT %(cat)s 27 WHERE NOT EXISTS ( 28 SELECT 1 FROM dem.org_category WHERE description = %(cat)s or _(description) = %(cat)s 29 )""" 30 cmd2 = """SELECT pk FROM dem.org_category WHERE description = %(cat)s or _(description) = %(cat)s LIMIT 1""" 31 queries = [ 32 {'cmd': cmd1, 'args': args}, 33 {'cmd': cmd2, 'args': args} 34 ] 35 rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, get_col_idx = False, return_data = True) 36 return rows[0][0]
37 38 #============================================================ 39 # organization API 40 #------------------------------------------------------------ 41 _SQL_get_org = 'SELECT * FROM dem.v_orgs WHERE %s' 42
43 -class cOrg(gmBusinessDBObject.cBusinessDBObject):
44 45 _cmd_fetch_payload = _SQL_get_org % 'pk_org = %s' 46 _cmds_store_payload = [ 47 """UPDATE dem.org SET 48 description = %(organization)s, 49 fk_category = %(pk_category_org)s 50 WHERE 51 pk = %(pk_org)s 52 AND 53 xmin = %(xmin_org)s 54 RETURNING 55 xmin AS xmin_org""" 56 ] 57 _updatable_fields = [ 58 'organization', 59 'pk_category_org' 60 ] 61 #--------------------------------------------------------
62 - def add_unit(self, unit=None):
63 return create_org_unit(pk_organization = self._payload[self._idx['pk_org']], unit = unit)
64 #--------------------------------------------------------
65 - def format(self):
66 lines = [] 67 lines.append(_('Organization #%s') % self._payload[self._idx['pk_org']]) 68 lines.append('') 69 lines.append(' %s "%s"' % ( 70 self._payload[self._idx['l10n_category']], 71 self._payload[self._idx['organization']] 72 )) 73 if self._payload[self._idx['is_praxis']]: 74 lines.append('') 75 lines.append(' ' + _('This is your praxis !')) 76 return '\n'.join(lines)
77 #-------------------------------------------------------- 78 # properties 79 #--------------------------------------------------------
80 - def _get_units(self):
81 return get_org_units(order_by = 'unit', org = self._payload[self._idx['pk_org']])
82 83 units = property(_get_units, lambda x:x)
84 85 #------------------------------------------------------------
86 -def org_exists(organization=None, category=None, link_obj=None):
87 args = {'desc': organization, 'cat': category} 88 89 if isinstance(category, str): 90 cat_part = 'fk_category = (SELECT pk FROM dem.org_category WHERE description = %(cat)s)' 91 elif category is None: 92 cat_part = 'True' 93 else: 94 cat_part = 'fk_category = %(cat)s' 95 96 cmd = 'SELECT pk FROM dem.org WHERE description = %%(desc)s AND %s' % cat_part 97 rows, idx = gmPG2.run_ro_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 98 if len(rows) > 0: 99 return cOrg(aPK_obj = rows[0][0]) 100 101 return None
102 #------------------------------------------------------------
103 -def create_org(organization=None, category=None, link_obj=None):
104 105 org = org_exists(link_obj = link_obj, organization = organization, category = category) 106 if org is not None: 107 return org 108 109 args = {'desc': organization, 'cat': category} 110 111 if isinstance(category, str): 112 cat_part = '(SELECT pk FROM dem.org_category WHERE description = %(cat)s)' 113 else: 114 cat_part = '%(cat)s' 115 116 cmd = 'INSERT INTO dem.org (description, fk_category) VALUES (%%(desc)s, %s) RETURNING pk' % cat_part 117 rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True) 118 119 return cOrg(aPK_obj = rows[0][0], link_obj = link_obj)
120 #------------------------------------------------------------
121 -def delete_org(organization=None):
122 args = {'pk': organization} 123 cmd = """ 124 DELETE FROM dem.org 125 WHERE 126 pk = %(pk)s 127 AND NOT EXISTS ( 128 SELECT 1 FROM dem.org_unit WHERE fk_org = %(pk)s 129 ) 130 """ 131 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 132 return True
133 #------------------------------------------------------------
134 -def get_orgs(order_by=None, return_pks=False):
135 136 if order_by is None: 137 order_by = '' 138 else: 139 order_by = 'ORDER BY %s' % order_by 140 141 cmd = _SQL_get_org % ('TRUE %s' % order_by) 142 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 143 if return_pks: 144 return [ r['pk_org'] for r in rows ] 145 return [ cOrg(row = {'data': r, 'idx': idx, 'pk_field': 'pk_org'}) for r in rows ]
146 147 #============================================================ 148 # organizational units API 149 #------------------------------------------------------------ 150 _SQL_get_org_unit = 'SELECT * FROM dem.v_org_units WHERE %s' 151
152 -class cOrgUnit(gmBusinessDBObject.cBusinessDBObject):
153 154 _cmd_fetch_payload = _SQL_get_org_unit % 'pk_org_unit = %s' 155 _cmds_store_payload = [ 156 """UPDATE dem.org_unit SET 157 description = %(unit)s, 158 fk_org = %(pk_org)s, 159 fk_category = %(pk_category_unit)s, 160 fk_address = %(pk_address)s 161 WHERE 162 pk = %(pk_org_unit)s 163 AND 164 xmin = %(xmin_org_unit)s 165 RETURNING 166 xmin AS xmin_org_unit""" 167 ] 168 _updatable_fields = [ 169 'unit', 170 'pk_org', 171 'pk_category_unit', 172 'pk_address' 173 ] 174 #-------------------------------------------------------- 175 # comms API 176 #--------------------------------------------------------
177 - def get_comm_channels(self, comm_medium=None):
178 179 args = {'pk': self.pk_obj, 'medium': comm_medium} 180 181 if comm_medium is None: 182 cmd = """ 183 SELECT * 184 FROM dem.v_org_unit_comms 185 WHERE 186 pk_org_unit = %(pk)s 187 """ 188 else: 189 cmd = """ 190 SELECT * 191 FROM dem.v_org_unit_comms 192 WHERE 193 pk_org_unit = %(pk)s 194 AND 195 comm_type = %(medium)s 196 """ 197 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 198 199 return [ gmDemographicRecord.cOrgCommChannel(row = { 200 'pk_field': 'pk_lnk_org_unit2comm', 201 'data': r, 202 'idx': idx 203 }) for r in rows 204 ]
205 206 comm_channels = property(get_comm_channels, lambda x:x) 207 208 #-------------------------------------------------------- 225 #-------------------------------------------------------- 231 #-------------------------------------------------------- 232 # external IDs 233 #--------------------------------------------------------
234 - def get_external_ids(self, id_type=None, issuer=None):
235 where_parts = ['pk_org_unit = %(unit)s'] 236 args = {'unit': self.pk_obj} 237 238 if id_type is not None: 239 where_parts.append('name = %(name)s') 240 args['name'] = id_type.strip() 241 242 if issuer is not None: 243 where_parts.append('issuer = %(issuer)s') 244 args['issuer'] = issuer.strip() 245 246 cmd = "SELECT * FROM dem.v_external_ids4org_unit WHERE %s" % ' AND '.join(where_parts) 247 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 248 249 return rows
250 251 external_ids = property(get_external_ids, lambda x:x) 252 #--------------------------------------------------------
253 - def add_external_id(self, type_name=None, value=None, issuer=None, comment=None, pk_type=None):
254 """Adds an external ID to an org unit. 255 256 creates ID type if necessary 257 """ 258 args = { 259 'unit': self.pk_obj, 260 'val': value, 261 'type_name': type_name, 262 'pk_type': pk_type, 263 'issuer': issuer, 264 'comment': comment 265 } 266 # check for existing ID 267 if pk_type is not None: 268 cmd = """ 269 SELECT * FROM dem.v_external_ids4org_unit WHERE 270 pk_org_unit = %(unit)s 271 AND 272 pk_type = %(pk_type)s 273 AND 274 value = %(val)s""" 275 else: 276 # by type/value/issuer 277 if issuer is None: 278 cmd = """ 279 SELECT * FROM dem.v_external_ids4org_unit WHERE 280 pk_org_unit = %(unit)s 281 AND 282 name = %(type_name)s 283 AND 284 value = %(val)s""" 285 else: 286 cmd = """ 287 SELECT * FROM dem.v_external_ids4org_unit WHERE 288 pk_org_unit = %(unit)s 289 AND 290 name = %(type_name)s 291 AND 292 value = %(val)s 293 AND 294 issuer = %(issuer)s""" 295 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 296 297 # create new ID if not found 298 if len(rows) == 0: 299 if pk_type is None: 300 cmd = """INSERT INTO dem.lnk_org_unit2ext_id (external_id, fk_type, comment, fk_org_unit) VALUES ( 301 %(val)s, 302 (SELECT dem.add_external_id_type(%(type_name)s, %(issuer)s)), 303 %(comment)s, 304 %(unit)s 305 )""" 306 else: 307 cmd = """INSERT INTO dem.lnk_org_unit2ext_id (external_id, fk_type, comment, fk_org_unit) VALUES ( 308 %(val)s, 309 %(pk_type)s, 310 %(comment)s, 311 %(unit)s 312 )""" 313 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 314 315 # or update comment of existing ID 316 else: 317 row = rows[0] 318 if comment is not None: 319 # comment not already there ? 320 if gmTools.coalesce(row['comment'], '').find(comment.strip()) == -1: 321 comment = '%s%s' % (gmTools.coalesce(row['comment'], '', '%s // '), comment.strip) 322 cmd = "UPDATE dem.lnk_org_unit2ext_id SET comment = %(comment)s WHERE pk = %(pk)s" 323 args = {'comment': comment, 'pk': row['pk_id']} 324 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
325 326 #--------------------------------------------------------
327 - def update_external_id(self, pk_id=None, type=None, value=None, issuer=None, comment=None):
328 """Edits an existing external ID. 329 330 Creates ID type if necessary. 331 """ 332 cmd = """ 333 UPDATE dem.lnk_org_unit2ext_id SET 334 fk_type = (SELECT dem.add_external_id_type(%(type)s, %(issuer)s)), 335 external_id = %(value)s, 336 comment = gm.nullify_empty_string(%(comment)s) 337 WHERE 338 pk = %(pk)s 339 """ 340 args = {'pk': pk_id, 'value': value, 'type': type, 'issuer': issuer, 'comment': comment} 341 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
342 343 #--------------------------------------------------------
344 - def delete_external_id(self, pk_ext_id=None):
345 cmd = """ 346 DELETE FROM dem.lnk_org_unit2ext_id 347 WHERE fk_org_unit = %(unit)s AND pk = %(pk)s 348 """ 349 args = {'unit': self.pk_obj, 'pk': pk_ext_id} 350 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
351 352 #-------------------------------------------------------- 353 # address API 354 #-------------------------------------------------------- 358 #-------------------------------------------------------- 366 #--------------------------------------------------------
367 - def format(self, with_address=False, with_org=True, with_comms=False):
368 lines = [] 369 lines.append(_('Unit%s: %s%s') % ( 370 gmTools.bool2subst ( 371 self._payload[self._idx['is_praxis_branch']], 372 _(' (of your praxis)'), 373 '' 374 ), 375 self._payload[self._idx['unit']], 376 gmTools.coalesce(self._payload[self._idx['l10n_unit_category']], '', ' (%s)') 377 )) 378 if with_org: 379 lines.append(_('Organization: %s (%s)') % ( 380 self._payload[self._idx['organization']], 381 self._payload[self._idx['l10n_organization_category']] 382 )) 383 if with_address: 384 adr = self.address 385 if adr is not None: 386 lines.extend(adr.format()) 387 if with_comms: 388 for comm in self.comm_channels: 389 lines.append('%s: %s%s' % ( 390 comm['l10n_comm_type'], 391 comm['url'], 392 gmTools.bool2subst(comm['is_confidential'], _(' (confidential)'), '', '') 393 )) 394 return lines
395 396 #-------------------------------------------------------- 397 # properties 398 #--------------------------------------------------------
399 - def _get_address(self):
400 if self._payload[self._idx['pk_address']] is None: 401 return None 402 return gmDemographicRecord.cAddress(aPK_obj = self._payload[self._idx['pk_address']])
403
404 - def _set_address(self, address):
405 self['pk_address'] = address['pk_address'] 406 self.save()
407 408 address = property(_get_address, _set_address) 409 410 #--------------------------------------------------------
411 - def _get_org(self):
412 return cOrg(aPK_obj = self._payload[self._idx['pk_org']])
413 414 organization = property(_get_org, lambda x:x) 415 org = property(_get_org, lambda x:x) 416 417 comm_channels = property(get_comm_channels, lambda x:x)
418 419 #------------------------------------------------------------
420 -def create_org_unit(pk_organization=None, unit=None, link_obj=None):
421 _log.debug('creating org unit [%s:%s]', unit, pk_organization) 422 args = {'desc': unit, 'pk_org': pk_organization} 423 cmd1 = """ 424 INSERT INTO dem.org_unit (description, fk_org) SELECT 425 %(desc)s, 426 %(pk_org)s 427 WHERE NOT EXISTS ( 428 SELECT 1 FROM dem.org_unit WHERE description = %(desc)s AND fk_org = %(pk_org)s 429 )""" 430 cmd2 = _SQL_get_org_unit % 'unit = %(desc)s AND pk_org = %(pk_org)s' 431 queries = [ 432 {'cmd': cmd1, 'args': args}, 433 {'cmd': cmd2, 'args': args} 434 ] 435 rows, idx = gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, get_col_idx = True, return_data = True) 436 return cOrgUnit(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_org_unit'})
437 438 #------------------------------------------------------------
439 -def delete_org_unit(unit=None):
440 args = {'pk': unit} 441 cmd = """DELETE FROM dem.org_unit WHERE 442 pk = %(pk)s 443 AND 444 NOT EXISTS ( 445 SELECT 1 FROM clin.encounter where fk_location = %(pk)s 446 ) AND 447 NOT EXISTS ( 448 SELECT 1 FROM clin.hospital_stay where fk_org_unit = %(pk)s 449 ) AND 450 NOT EXISTS ( 451 SELECT 1 FROM clin.procedure where fk_org_unit = %(pk)s 452 ) AND 453 NOT EXISTS ( 454 SELECT 1 FROM clin.test_org where fk_org_unit = %(pk)s 455 ) AND 456 NOT EXISTS ( 457 SELECT 1 FROM dem.lnk_org_unit2comm where fk_org_unit = %(pk)s 458 ) AND 459 NOT EXISTS ( 460 SELECT 1 FROM dem.lnk_org_unit2ext_id where fk_org_unit = %(pk)s 461 ) 462 """ 463 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 464 return True
465 #------------------------------------------------------------
466 -def get_org_units(order_by=None, org=None, return_pks=False):
467 468 if order_by is None: 469 order_by = '' 470 else: 471 order_by = ' ORDER BY %s' % order_by 472 473 if org is None: 474 where_part = 'TRUE' 475 else: 476 where_part = 'pk_org = %(org)s' 477 478 args = {'org': org} 479 cmd = (_SQL_get_org_unit % where_part) + order_by 480 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 481 if return_pks: 482 return [ r['pk_org_unit'] for r in rows ] 483 return [ cOrgUnit(row = {'data': r, 'idx': idx, 'pk_field': 'pk_org_unit'}) for r in rows ]
484 485 #====================================================================== 486 # main 487 #---------------------------------------------------------------------- 488 if __name__ == "__main__": 489 490 if len(sys.argv) < 2: 491 sys.exit() 492 493 if sys.argv[1] != 'test': 494 sys.exit() 495 496 497 print(cOrgUnit(aPK_obj = 21825)) 498 499 500 # for unit in get_org_units(): 501 # print unit 502 503 sys.exit(0) 504 #============================================================ 505 #============================================================ 506 # outdated code below ======================================= 507 #============================================================ 508 #============================================================ 509 #============================================================ 510 #============================================================ 511 #============================================================ 512 #============================================================ 513 #============================================================ 514 #============================================================ 515 #============================================================
516 -def get_comm_channels_data_for_org_ids( idList):
517 """gets comm_channels for a list of org_id. 518 returns a map keyed by org_id with lists of comm_channel data (url, type). 519 this allows a single fetch of comm_channel data for multiple orgs""" 520 521 ids = ", ".join( [ str(x) for x in idList]) 522 cmd = """select l.id_org, id_type, url 523 from dem.comm_channel c, dem.lnk_org2comm_channel l 524 where 525 c.id = l.id_comm and 526 l.id_org in ( select id from dem.org where id in (%s) ) 527 """ % ids 528 result = gmPG.run_ro_query("personalia", cmd) 529 if result == None: 530 _log.error("Unable to load comm channels for org" ) 531 return None 532 m = {} 533 for (id_org, id_type, url) in result: 534 if id_org not in m: 535 m[id_org] = [] 536 m[id_org].append( (id_type, url) ) 537 538 return m # is a Map[id_org] = list of comm_channel data 539
540 -def get_address_data_for_org_ids( idList):
541 """gets addresses for a list of valid id values for orgs. 542 returns a map keyed by org_id with the address data 543 """ 544 545 ids = ", ".join( [ str(x) for x in idList]) 546 cmd = """select l.id_org, number, street, city, postcode, region, country 547 from dem.v_basic_address v , dem.lnk_org2address l 548 where v.addr_id = l.id_address and 549 l.id_org in ( select id from dem.org where id in (%s) ) """ % ids 550 result = gmPG.run_ro_query( "personalia", cmd) 551 552 if result == None: 553 _log.error("failure in org address load" ) 554 return None 555 m = {} 556 for (id_org, n,s,ci,p,st,co) in result: 557 m[id_org] = (n,s,ci,p,st,co) 558 return m
559
560 -def get_org_data_for_org_ids(idList):
561 """ for a given list of org id values , 562 returns a map of id_org vs. org attributes: description, id_category""" 563 564 ids = ", ".join( [ str(x) for x in idList]) 565 cmd = """select id, description, id_category from dem.org 566 where id in ( select id from dem.org where id in( %s) )""" % ids 567 #<DEBUG> 568 print(cmd) 569 #</DEBUG> 570 result = gmPG.run_ro_query("personalia", cmd, ) 571 if result is None: 572 _log.error("Unable to load orgs with ids (%s)" %ids) 573 return None 574 m = {} 575 for (id_org, d, id_cat) in result: 576 m[id_org] = (d, id_cat) 577 return m
578 #============================================================ 579 # 580 # IGNORE THE FOLLOWING, IF NOT INTERESTED IN TEST CODE 581 # 582 # 583 584 if __name__ == '__main__': 585 print("Please enter a write-enabled user e.g. _test-doc ") 586
587 - def testListOrgs():
588 print("running test listOrg") 589 for (f,a) in get_test_data(): 590 h = cOrgImpl1() 591 h.set(*f) 592 h.setAddress(*a) 593 if not h.save(): 594 print("did not save ", f) 595 596 orgs = cOrgHelperImpl1().findAllOrganizations() 597 598 for org in orgs: 599 print("Found org ", org.get(), org.getAddress()) 600 if not org.shallow_del(): 601 print("Unable to delete above org")
602 603 604 605 606 607
608 - def get_test_data():
609 """test org data for unit testing in testOrg()""" 610 return [ 611 ( ["Box Hill Hospital", "", "", "Eastern", "hospital", "0398953333", "111-1111","bhh@oz", ""], ["33", "Nelson Rd", "Box Hill", "3128", None , None] ), 612 ( ["Frankston Hospital", "", "", "Peninsula", "hospital", "0397847777", "03784-3111","fh@oz", ""], ["21", "Hastings Rd", "Frankston", "3199", None , None] ) 613 ]
614
615 - def get_test_persons():
616 return { "Box Hill Hospital": 617 [ 618 ['Dr.', 'Bill' , 'Smith', '123-4567', '0417 111 222'], 619 ['Ms.', 'Anita', 'Jones', '124-5544', '0413 222 444'], 620 ['Dr.', 'Will', 'Stryker', '999-4444', '0402 333 111'] ], 621 "Frankston Hospital": 622 [ [ "Dr.", "Jason", "Boathead", "444-5555", "0403 444 2222" ], 623 [ "Mr.", "Barnie", "Commuter", "222-1111", "0444 999 3333"], 624 [ "Ms.", "Morita", "Traveller", "999-1111", "0222 333 1111"]] }
625
626 - def testOrgPersons():
627 m = get_test_persons() 628 d = dict( [ (f[0] , (f, a)) for (f, a) in get_test_data() ] ) 629 for orgName , personList in m.items(): 630 f1 , a1 = d[orgName][0], d[orgName][1] 631 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 632 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 633 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 634 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create) 635 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create) 636 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create, getTestIdentityUsing_cOrgDemographicAdapter)
637 638
639 - def _outputPersons( org):
640 m = org.getPersonMap() 641 642 if m== []: 643 print("NO persons were found unfortunately") 644 645 print(""" TestOrgPersonRun got back for """) 646 a = org.getAddress() 647 print(org["name"], a["number"], a["street"], a["urb"], a["postcode"] , " phone=", org['phone']) 648 649 for id, r in m.items(): 650 print("\t",", ".join( [ " ".join(r.get_names().values()), 651 "work no=", r.getCommChannel(gmDemographicRecord.WORK_PHONE), 652 "mobile no=", r.getCommChannel(gmDemographicRecord.MOBILE) 653 ] ))
654 655
656 - def _testOrgPersonRun(f1, a1, personList):
657 print("Using test data :f1 = ", f1, "and a1 = ", a1 , " and lp = ", personList) 658 print("-" * 50) 659 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 660 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 661 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 662 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create)
663 664
665 - def _setIdentityTestData(identity, data):
666 identity.addName(data[1], data[2], True) 667 identity.setTitle(data[0]) 668 identity.linkCommChannel( gmDemographicRecord.WORK_PHONE, data[3]) 669 identity.linkCommChannel( gmDemographicRecord.MOBILE, data[4])
670
671 - def getTestIdentityUsingDirectDemographicRecord( data, org):
672 id = gmPerson.create_dummy_identity() 673 identity = gmDemographicRecord.cDemographicRecord_SQL(id) 674 _setIdentityTestData(identity, data) 675 return identity
676
677 - def getTestIdentityUsing_cOrgDemographicAdapter( data, org):
678 helper = cOrgHelperImpl3() 679 orgPerson= helper.createOrgPerson() 680 orgPerson.setParent(org) 681 orgPerson['name'] = ' '.join( [data[0], data[1], data[2]]) 682 orgPerson['phone'] = data[3] 683 orgPerson['mobile'] = data[4] 684 orgPerson.save() 685 return orgPerson.getDemographicRecord()
686 687
688 - def _testOrgClassPersonRun(f1, a1, personList, orgCreate, identityCreator = getTestIdentityUsingDirectDemographicRecord):
689 print("-" * 50) 690 print("Testing org creator ", orgCreate) 691 print(" and identity creator ", identityCreator) 692 print("-" * 50) 693 h = orgCreate() 694 h.set(*f1) 695 h.setAddress(*a1) 696 if not h.save(): 697 print("Unable to save org for person test") 698 h.shallow_del() 699 return False 700 # use gmDemographicRecord to convert person list 701 for lp in personList: 702 identity = identityCreator(lp, h) 703 result , msg = h.linkPerson(identity) 704 print(msg) 705 706 _outputPersons(h) 707 deletePersons(h) 708 709 if h.shallow_del(): 710 print("Managed to dispose of org") 711 else: 712 print("unable to dispose of org") 713 714 return True
715 716 # def testOrgPerson(f1, a1, personList): 717
718 - def deletePerson(id):
719 cmds = [ ( "delete from dem.lnk_identity2comm_chan where fk_identity=%d"%id,[]), 720 ("delete from dem.names where id_identity=%d"%id,[]), 721 ("delete from dem.identity where id = %d"%id,[]) ] 722 result = gmPG.run_commit("personalia", cmds) 723 return result
724
725 - def deletePersons( org):
726 map = org.getPersonMap() 727 for id, r in map.items(): 728 org.unlinkPerson(r) 729 730 result = deletePerson(r.getID()) 731 if result == None: 732 _log.error("FAILED TO CLEANUP PERSON %d" %r.getID() )
733 734 735
736 - def testOrg():
737 """runs a test of load, save , shallow_del on items in from get_test_data""" 738 l = get_test_data() 739 results = [] 740 for (f, a) in l: 741 result, obj = _testOrgRun(f, a) 742 results.append( (result, obj) ) 743 return results
744 745 746
747 - def _testOrgRun( f1, a1):
748 749 print("""testing single level orgs""") 750 f = [ "name", "office", "subtype", "memo", "category", "phone", "fax", "email","mobile"] 751 a = ["number", "street", "urb", "postcode", 'region', "country"] 752 h = cOrgImpl1() 753 754 h.set(*f1) 755 h.setAddress(*a1) 756 757 print("testing get, getAddress") 758 print(h.get()) 759 print(h.getAddressDict()) 760 761 import sys 762 if not h.save(): 763 print("failed to save first time. Is an old test org needing manual removal?") 764 return False, h 765 print("saved pk =", h.getId()) 766 767 768 pk = h.getId() 769 if h.shallow_del(): 770 print("shallow deleted ", h['name']) 771 else: 772 print("failed shallow delete of ", h['name']) 773 774 775 776 h2 = cOrgImpl1() 777 778 print("testing load") 779 780 print("should fail") 781 if not h2.load(pk): 782 print("Failed as expected") 783 784 if h.save(): 785 print("saved ", h['name'] , "again") 786 else: 787 print("failed re-save") 788 return False, h 789 790 h['fax'] = '222-1111' 791 print("using update save") 792 793 if h.save(): 794 print("saved updated passed") 795 print("Test reload next") 796 else: 797 print("failed save of updated data") 798 print("continuing to reload") 799 800 801 if not h2.load(h.getId()): 802 print("failed load") 803 return False, h 804 print("reloaded values") 805 print(h2.get()) 806 print(h2.getAddressDict()) 807 808 print("** End of Test org") 809 810 if h2.shallow_del(): 811 print("cleaned up") 812 else: 813 print("Test org needs to be manually removed") 814 815 return True, h2
816
817 - def clean_test_org():
818 l = get_test_data() 819 820 names = [ "".join( ["'" ,str(org[0]), "'"] ) for ( org, address) in l] 821 names += [ "'John Hunter Hospital'", "'Belmont District Hospital'"] 822 nameList = ",".join(names) 823 categoryList = "'hospital'" 824 825 cmds = [ ( """create temp table del_org as 826 select id from dem.org 827 where description in(%s) or 828 id_category in ( select id from dem.org_category c 829 where c.description in (%s)) 830 """ % (nameList, categoryList), [] ), 831 ("""create temp table del_identity as 832 select id from dem.identity 833 where id in 834 ( 835 select id_identity from dem.lnk_person_org_address 836 where id_org in ( select id from del_org) 837 )""",[] ), 838 ("""create temp table del_comm as 839 (select id_comm from dem.lnk_org2comm_channel where 840 id_org in ( select id from del_org) 841 ) UNION 842 (select id_comm from dem.lnk_identity2comm_chan where 843 id_identity in ( select id from del_identity) 844 )""", [] ), 845 ("""delete from dem.names where id_identity in 846 (select id from del_identity)""",[]), 847 ("""delete from dem.lnk_person_org_address where 848 id_org in (select id from del_org )""",[]), 849 ("""delete from dem.lnk_person_org_address where 850 id_identity in (select id from del_identity)""", []), 851 ("""delete from dem.lnk_org2comm_channel 852 where id_org in (select id from del_org) """,[]), 853 ("""delete from dem.lnk_identity2comm_chan 854 where id_identity in (select id from del_identity)""",[] ), 855 ("""delete from dem.comm_channel where id in ( select id_comm from del_comm)""",[]), 856 ("""delete from dem.lnk_job2person where id_identity in (select id from del_identity)""", []), 857 ("""delete from dem.identity where id in (select id from del_identity)""",[] ), 858 ("""delete from dem.org where id in ( select id from del_org) """ , [] ), 859 ("""drop table del_comm""",[]), 860 ("""drop table del_identity""",[]), 861 ("""drop table del_org""", []) 862 863 ] 864 result = (gmPG.run_commit("personalia", cmds) is not None) 865 866 return result
867 868
869 - def login_user_and_test(logintest, service = 'personalia', msg = "failed test" , use_prefix_rw= False):
870 """ tries to get and verify a read-write connection 871 which has permission to write to org tables, so the test case 872 can run. 873 """ 874 login2 = gmPG.request_login_params() 875 876 #login as the RW user 877 p = gmPG.ConnectionPool( login2) 878 if use_prefix_rw: 879 conn = p.GetConnection( service, readonly = 0) 880 else: 881 conn = p.GetConnection(service) 882 result = logintest(conn) 883 884 if result is False: 885 print(msg) 886 887 p.ReleaseConnection(service) 888 return result, login2
889
890 - def test_rw_user(conn):
891 # test it is a RW user, by making a entry and deleting it 892 try: 893 c.reload("org_category") 894 cursor = conn.cursor() 895 896 cursor.execute("select last_value from dem.org_id_seq") 897 [org_id_seq] = cursor.fetchone() 898 899 cursor.execute(""" 900 insert into dem.org ( description, id_category, id) 901 values ( 'xxxDEFAULTxxx', %d, 902 %d) 903 """ % ( c.getId('org_category', 'hospital') , org_id_seq + 1 ) ) 904 cursor.execute(""" 905 delete from dem.org where id = %d""" % ( org_id_seq + 1) ) 906 # make sure this exercise is committed, else a deadlock will occur 907 conn.commit() 908 except Exception: 909 _log.exception("Test of Update Permission failed") 910 return False 911 return True
912
913 - def test_admin_user(conn):
914 try: 915 cursor = conn.cursor() 916 917 cursor.execute("select last_value from dem.org_category_id_seq") 918 [org_cat_id_seq] = cursor.fetchone() 919 920 cursor.execute(""" 921 insert into dem.org_category ( description, id) 922 values ( 'xxxDEFAULTxxx',%d) 923 """ % (org_cat_id_seq + 1 ) ) 924 cursor.execute(""" 925 delete from dem.org_category where description like 'xxxDEFAULTxxx' """ ) 926 # make sure this exercise is committed, else a deadlock will occur 927 conn.commit() 928 except Exception: 929 _log.exception("Test of Update Permission failed") 930 return False 931 return True
932
933 - def login_rw_user():
934 return login_user_and_test( test_rw_user, "login cannot update org", use_prefix_rw = True)
935 936
937 - def login_admin_user():
938 return login_user_and_test( test_admin_user, "login cannot update org_category" )
939 940
941 - def create_temp_categories( categories = ['hospital']):
942 print("NEED TO CREATE TEMPORARY ORG_CATEGORY.\n\n ** PLEASE ENTER administrator login : e.g user 'gm-dbo' and his password") 943 #get a admin login 944 for i in range(0, 4): 945 result ,tmplogin = login_admin_user() 946 if result: 947 break 948 if i == 4: 949 print("Failed to login") 950 return categories 951 952 # and save it , for later removal of test categories. 953 from Gnumed.pycommon import gmLoginInfo 954 adminlogin = gmLoginInfo.LoginInfo(*tmplogin.GetInfo()) 955 956 #login as admin 957 p = gmPG.ConnectionPool( tmplogin) 958 conn = p.GetConnection("personalia") 959 960 # use the last value + 1 of the relevant sequence, but don't increment it 961 cursor = conn.cursor() 962 963 failed_categories = [] 964 n =1 965 for cat in categories: 966 cursor.execute("select last_value from dem.org_category_id_seq") 967 [org_cat_id_seq] = cursor.fetchone() 968 969 cursor.execute( "insert into dem.org_category(description, id) values('%s', %d)" % (cat, org_cat_id_seq + n) ) 970 cursor.execute("select id from dem.org_category where description in ('%s')" % cat) 971 972 result = cursor.fetchone() 973 if result == None or len(result) == 0: 974 failed_categories.append(cat) 975 print("Failed insert of category", cat) 976 conn.rollback() 977 else: 978 conn.commit() 979 n += 1 980 981 conn.commit() 982 p.ReleaseConnection('personalia') 983 return failed_categories, adminlogin
984
985 - def clean_org_categories(adminlogin = None, categories = ['hospital'], service='personalia'):
986 987 print(""" 988 989 The temporary category(s) will now 990 need to be removed under an administrator login 991 e.g. gm-dbo 992 Please enter login for administrator: 993 """) 994 if adminlogin is None: 995 for i in range(0, 4): 996 result, adminlogin = login_admin_user() 997 if result: 998 break 999 if i == 4: 1000 print("FAILED TO LOGIN") 1001 return categories 1002 1003 p = gmPG.ConnectionPool(adminlogin) 1004 conn = p.GetConnection(service) 1005 failed_remove = [] 1006 for cat in categories: 1007 try: 1008 cursor = conn.cursor() 1009 cursor.execute( "delete from dem.org_category where description in ('%s')"%cat) 1010 conn.commit() 1011 cursor.execute("select id from dem.org_category where description in ('%s')"%cat) 1012 if cursor.fetchone() == None: 1013 print("Succeeded in removing temporary org_category") 1014 else: 1015 print("*** Unable to remove temporary org_category") 1016 failed_remove .append(cat) 1017 except Exception: 1018 import sys 1019 print(sys.exc_info()[0], sys.exc_info()[1]) 1020 import traceback 1021 traceback.print_tb(sys.exc_info()[2]) 1022 1023 failed_remove.append(cat) 1024 1025 conn = None 1026 p.ReleaseConnection(service) 1027 if failed_remove != []: 1028 print("FAILED TO REMOVE ", failed_remove) 1029 return failed_remove
1030
1031 - def test_CatFinder():
1032 print("TESTING cCatFinder") 1033 1034 print("""c = cCatFinder("org_category")""") 1035 c = cCatFinder("org_category") 1036 1037 print(c.getCategories("org_category")) 1038 1039 print("""c = cCatFinder("enum_comm_types")""") 1040 c = cCatFinder("enum_comm_types") 1041 1042 l = c.getCategories("enum_comm_types") 1043 print("testing getId()") 1044 l2 = [] 1045 for x in l: 1046 l2.append((x, c.getId("enum_comm_types", x))) 1047 print(l2) 1048 1049 print("""testing borg behaviour of cCatFinder""") 1050 1051 print(c.getCategories("org_category"))
1052 1053
1054 - def help():
1055 print("""\nNB If imports not found , try: 1056 1057 change to gnumed/client directory , then 1058 1059 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py 1060 1061 --clean , cleans the test data and categories 1062 1063 --gui sets up as for no arguments, then runs the client. 1064 on normal exit of client, normal tests run, and 1065 then cleanup of entered data. 1066 1067 using the gui, 1068 1069 the 'list organisations' toolbar button , loads all organisations 1070 in the database, and display suborgs and persons associated 1071 with each organisation. 1072 1073 the 'add organisation' button will add a top-level organisation. 1074 the 'add branch/division' button will work when the last selected 1075 org was a top level org. 1076 1077 the 'add person M|F' button works if an org is selected. 1078 1079 the save button works when entry is finished. 1080 1081 selecting on an item, will bring it into the editing area. 1082 1083 No test yet for dirtied edit data, to query whether to 1084 save or discard. (30/5/2004) 1085 """) 1086 print() 1087 print("In the connection query, please enter") 1088 print("a WRITE-ENABLED user e.g. _test-doc (not test-doc), and the right password") 1089 print() 1090 print("Run the unit test with cmdline argument '--clean' if trying to clean out test data") 1091 print() 1092 1093 print("""You can get a sermon by running 1094 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py --sermon 1095 """) 1096 print(""" 1097 Pre-requisite data in database is : 1098 gnumed=# select * from org_category ; 1099 id | description 1100 ----+------------- 1101 1 | hospital 1102 (1 row) 1103 1104 gnumed=# select * from enum_comm_types ; 1105 id | description 1106 ----+------------- 1107 1 | email 1108 2 | fax 1109 3 | homephone 1110 4 | workphone 1111 5 | mobile 1112 6 | web 1113 7 | jabber 1114 (7 rows) 1115 """)
1116
1117 - def sermon():
1118 print(""" 1119 This test case shows how many things can go wrong , even with just a test case. 1120 Problem areas include: 1121 - postgres administration : pg_ctl state, pg_hba.conf, postgres.conf config files . 1122 - schema integrity constraints : deletion of table entries which are subject to foreign keys, no input for no default value and no null value columns, input with duplicated values where unique key constraint applies to non-primary key columns, dealing with access control by connection identity management. 1123 1124 1125 - efficiency trade-offs -e.g. using db objects for localising code with data and easier function call interface ( then hopefully, easier to program with) , vs. need to access many objects at once 1126 without calling the backend for each object. 1127 1128 - error and exception handling - at what point in the call stack to handle an error. 1129 Better to use error return values and log exceptions near where they occur, vs. wrapping inside try: except Exception: blocks and catching typed exceptions. 1130 1131 1132 - test-case construction: test data is needed often, and the issue 1133 is whether it is better to keep the test data volatile in the test-case, 1134 which handles both its creation and deletion, or to add it to test data 1135 server configuration files, which may involve running backend scripts 1136 for loading and removing test data. 1137 1138 1139 1140 - Database connection problems: 1141 -Is the problem in : 1142 - pg_ctl start -D /...mydata-directory is wrong, and gnumed isn't existing there. 1143 1144 - ..mydata-directory/pg_hba.conf 1145 - can psql connect locally and remotely with the username and password. 1146 - Am I using md5 authenentication and I've forgotten the password. 1147 - I need to su postgres, alter pg_hba.conf to use trust for 1148 the gnumed database, pg_ctl restart -D .., su normal_user, psql gnumed, alter user my_username password 'doh' 1149 - might be helpful: the default password for _test-doc is test-doc 1150 1151 - ../mydata-directory/postgres.conf 1152 - tcp connect flag isn't set to true 1153 1154 - remote/local mixup : 1155 a different set of user passwords on different hosts. e.g the password 1156 for _test-doc is 'pass' on localhost and 'test-doc' for the serverhost. 1157 - In the prompts for admin and user login, local host was used for one, and 1158 remote host for the other 1159 1160 1161 1162 - test data won't go away : 1163 - 'hospital' category in org_category : the test case failed in a previous run 1164 and the test data was left there; now the test case won't try to delete it 1165 because it exists as a pre-existing category; 1166 soln : run with --clean option 1167 1168 - test-case failed unexpectedly, or break key was hit in the middle of a test-case run. 1169 Soln: run with --clean option, 1170 1171 1172 """)
1173 1174 1175 #============================================================ 1176 1177 import sys 1178 testgui = False 1179 if len(sys.argv) > 1: 1180 if sys.argv[1] == '--clean': 1181 result = clean_test_org() 1182 p = gmPG.ConnectionPool() 1183 p.ReleaseConnection('personalia') 1184 if result: 1185 print("probably succeeded in cleaning orgs") 1186 else: print("failed to clean orgs") 1187 1188 clean_org_categories() 1189 sys.exit(1) 1190 1191 if sys.argv[1] == "--sermon": 1192 sermon() 1193 1194 if sys.argv[1] == "--help": 1195 help() 1196 1197 if sys.argv[1] =="--gui": 1198 testgui = True 1199 1200 print("*" * 50) 1201 print("RUNNING UNIT TEST of gmOrganization ") 1202 1203 1204 test_CatFinder() 1205 tmp_category = False # tmp_category means test data will need to be added and removed 1206 # for org_category . 1207 1208 c = cCatFinder() 1209 if not "hospital" in c.getCategories("org_category") : 1210 print("FAILED in prerequisite for org_category : test categories are not present.") 1211 1212 tmp_category = True 1213 1214 if tmp_category: 1215 # test data in a categorical table (restricted access) is needed 1216 1217 print("""You will need to switch login identity to database administrator in order 1218 to have permission to write to the org_category table, 1219 and then switch back to the ordinary write-enabled user in order 1220 to run the test cases. 1221 Finally you will need to switch back to administrator login to 1222 remove the temporary org_categories. 1223 """) 1224 categories = ['hospital'] 1225 result, adminlogin = create_temp_categories(categories) 1226 if result == categories: 1227 print("Unable to create temporary org_category. Test aborted") 1228 sys.exit(-1) 1229 if result != []: 1230 print("UNABLE TO CREATE THESE CATEGORIES") 1231 if not input("Continue ?") in ['y', 'Y'] : 1232 sys.exit(-1) 1233 1234 try: 1235 results = [] 1236 if tmp_category: 1237 print("succeeded in creating temporary org_category") 1238 print() 1239 print("** Now ** RESUME LOGIN ** of write-enabled user (e.g. _test-doc) ") 1240 while (1): 1241 # get the RW user for org tables (again) 1242 if login_rw_user(): 1243 break 1244 1245 if testgui: 1246 if cCatFinder().getId('org_category','hospital') == None: 1247 print("Needed to set up temporary org_category 'hospital") 1248 sys.exit(-1) 1249 import os 1250 print(os.environ['PWD']) 1251 os.spawnl(os.P_WAIT, "/usr/bin/python", "/usr/bin/python","wxpython/gnumed.py", "--debug") 1252 1253 #os.popen2('python client/wxpython/gnumed.py --debug') 1254 1255 # run the test case 1256 results = testOrg() 1257 1258 # cleanup after the test case 1259 for (result , org) in results: 1260 if not result and org.getId() is not None: 1261 print("trying cleanup") 1262 if org.shallow_del(): print(" may have succeeded") 1263 else: 1264 print("May need manual removal of org id =", org.getId()) 1265 1266 testOrgPersons() 1267 1268 testListOrgs() 1269 1270 except Exception: 1271 import sys 1272 print(sys.exc_info()[0], sys.exc_info()[1]) 1273 _log.exception( "Fatal exception") 1274 1275 # clean-up any temporary categories. 1276 if tmp_category: 1277 try: 1278 clean_org_categories(adminlogin) 1279 except Exception: 1280 while(not login_rw_user()[0]): 1281 pass 1282 clean_test_org() 1283 clean_org_categories(adminlogin) 1284