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 gmBusinessDBObject 
  16   
  17  from Gnumed.business import gmDemographicRecord 
  18   
  19   
  20  _log = logging.getLogger('gm.org') 
  21  #============================================================ 
  22  # organization API 
  23  #------------------------------------------------------------ 
  24  _SQL_get_org = u'SELECT * FROM dem.v_orgs WHERE %s' 
  25   
26 -class cOrg(gmBusinessDBObject.cBusinessDBObject):
27 28 _cmd_fetch_payload = _SQL_get_org % u'pk_org = %s' 29 _cmds_store_payload = [ 30 u"""UPDATE dem.org SET 31 description = %(organization)s, 32 fk_category = %(pk_category_org)s, 33 WHERE 34 pk = %(pk_org)s 35 AND 36 xmin = %(xmin_org)s 37 RETURNING 38 xmin AS xmin_org""" 39 ] 40 _updatable_fields = [ 41 u'organization', 42 u'pk_category_org' 43 ]
44 #------------------------------------------------------------
45 -def create_org(organization=None, category=None):
46 47 args = {'desc': organization, 'cat': category} 48 cmd = u'INSERT INTO dem.org (description, fk_category) VALUES (%%(desc)s, %s) RETURNING pk' 49 if isinstance(category, basestring): 50 cmd = cmd % u'(SELECT pk FROM dem.org_category WHERE description = %(cat)s)' 51 else: 52 cmd = cmd % u'%(cat)s' 53 54 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True) 55 56 return cOrg(aPK_obj = rows[0][0])
57 #------------------------------------------------------------
58 -def delete_org(organization=None):
59 args = {'pk': organization} 60 cmd = u""" 61 DELETE FROM dem.org 62 WHERE 63 pk = %(pk)s 64 AND NOT EXISTS ( 65 SELECT 1 FROM dem.org_unit WHERE fk_org = %(pk)s 66 ) 67 """ 68 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 69 return True
70 #------------------------------------------------------------
71 -def get_orgs(order_by=None):
72 73 if order_by is None: 74 order_by = u'' 75 else: 76 order_by = u'ORDER BY %s' % order_by 77 78 cmd = _SQL_get_org % (u'TRUE %s' % order_by) 79 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True) 80 81 return [ cOrg(row = {'data': r, 'idx': idx, 'pk_field': u'pk_org'}) for r in rows ]
82 83 #============================================================ 84 # organizational units API 85 #------------------------------------------------------------ 86 _SQL_get_org_unit = u'SELECT * FROM dem.v_org_units WHERE %s' 87
88 -class cOrgUnit(gmBusinessDBObject.cBusinessDBObject):
89 90 _cmd_fetch_payload = _SQL_get_org_unit % u'pk_org_unit = %s' 91 _cmds_store_payload = [ 92 u"""UPDATE dem.org_unit SET 93 description = %(unit)s, 94 fk_org = %(pk_org)s, 95 fk_category = %(pk_category_unit)s, 96 fk_address = %(pk_address)s 97 WHERE 98 pk = %(pk_org_unit)s 99 AND 100 xmin = %(xmin_org_unit)s 101 RETURNING 102 xmin AS xmin_org_unit""" 103 ] 104 _updatable_fields = [ 105 u'unit', 106 u'pk_org', 107 u'pk_category_unit', 108 u'pk_address' 109 ] 110 #-------------------------------------------------------- 111 # comms API 112 #--------------------------------------------------------
113 - def get_comm_channels(self, comm_medium=None):
114 115 args = {'pk': self.pk_obj, 'medium': comm_medium} 116 117 if comm_medium is None: 118 cmd = u""" 119 SELECT * 120 FROM dem.v_org_unit_comms 121 WHERE 122 pk_org_unit = %(pk)s 123 """ 124 else: 125 cmd = u""" 126 SELECT * 127 FROM dem.v_org_unit_comms 128 WHERE 129 pk_org_unit = %(pk)s 130 AND 131 comm_type = %(medium)s 132 """ 133 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 134 135 return [ gmDemographicRecord.cOrgCommChannel(row = { 136 'pk_field': 'pk_lnk_org_unit2comm', 137 'data': r, 138 'idx': idx 139 }) for r in rows 140 ]
141 #-------------------------------------------------------- 158 #-------------------------------------------------------- 164 #-------------------------------------------------------- 167 #-------------------------------------------------------- 175 #-------------------------------------------------------- 176 # properties 177 #--------------------------------------------------------
178 - def _get_address(self):
179 if self._payload[self._idx['pk_address']] is None: 180 return None 181 return gmDemographicRecord.cAddress(aPK_obj = self._payload[self._idx['pk_address']])
182
183 - def _set_address(self, address):
184 self['pk_address'] = address['pk_address'] 185 self.save()
186 187 address = property(_get_address, _set_address)
188 #------------------------------------------------------------
189 -def create_org_unit(pk_organization=None, unit=None):
190 191 args = {'desc': unit, 'pk_org': pk_organization} 192 cmd = u'INSERT INTO dem.org_unit (description, fk_org) VALUES (%(desc)s, %(pk_org)s) RETURNING pk' 193 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False, return_data = True) 194 195 return cOrgUnit(aPK_obj = rows[0][0])
196 #------------------------------------------------------------
197 -def delete_org_unit(unit=None):
198 args = {'pk': unit} 199 cmd = u"DELETE FROM dem.org_unit WHERE pk = %(pk)s" 200 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 201 return True
202 #------------------------------------------------------------
203 -def get_org_units(order_by=None, org=None):
204 205 if order_by is None: 206 order_by = u'' 207 else: 208 order_by = u' ORDER BY %s' % order_by 209 210 if org is None: 211 where_part = u'TRUE' 212 else: 213 where_part = u'pk_org = %(org)s' 214 215 args = {'org': org} 216 cmd = (_SQL_get_org_unit % where_part) + order_by 217 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 218 219 return [ cOrgUnit(row = {'data': r, 'idx': idx, 'pk_field': u'pk_org_unit'}) for r in rows ]
220 221 #====================================================================== 222 # main 223 #---------------------------------------------------------------------- 224 if __name__ == "__main__": 225 226 if len(sys.argv) < 2: 227 sys.exit() 228 229 if sys.argv[1] != u'test': 230 sys.exit() 231 232 233 for unit in get_org_units(): 234 print unit 235 236 sys.exit(0) 237 #============================================================ 238 #============================================================ 239 # outdated code below ======================================= 240 #============================================================ 241 #============================================================ 242 #============================================================ 243 #============================================================ 244 #============================================================ 245 #============================================================ 246 #============================================================ 247 #============================================================ 248 #============================================================
249 -def get_comm_channels_data_for_org_ids( idList):
250 """gets comm_channels for a list of org_id. 251 returns a map keyed by org_id with lists of comm_channel data (url, type). 252 this allows a single fetch of comm_channel data for multiple orgs""" 253 254 ids = ", ".join( [ str(x) for x in idList]) 255 cmd = """select l.id_org, id_type, url 256 from dem.comm_channel c, dem.lnk_org2comm_channel l 257 where 258 c.id = l.id_comm and 259 l.id_org in ( select id from dem.org where id in (%s) ) 260 """ % ids 261 result = gmPG.run_ro_query("personalia", cmd) 262 if result == None: 263 _log.error("Unable to load comm channels for org" ) 264 return None 265 m = {} 266 for (id_org, id_type, url) in result: 267 if not m.has_key(id_org): 268 m[id_org] = [] 269 m[id_org].append( (id_type, url) ) 270 271 return m # is a Map[id_org] = list of comm_channel data 272
273 -def get_address_data_for_org_ids( idList):
274 """gets addresses for a list of valid id values for orgs. 275 returns a map keyed by org_id with the address data 276 """ 277 278 ids = ", ".join( [ str(x) for x in idList]) 279 cmd = """select l.id_org, number, street, city, postcode, state, country 280 from dem.v_basic_address v , dem.lnk_org2address l 281 where v.addr_id = l.id_address and 282 l.id_org in ( select id from dem.org where id in (%s) ) """ % ids 283 result = gmPG.run_ro_query( "personalia", cmd) 284 285 if result == None: 286 _log.error("failure in org address load" ) 287 return None 288 m = {} 289 for (id_org, n,s,ci,p,st,co) in result: 290 m[id_org] = (n,s,ci,p,st,co) 291 return m
292
293 -def get_org_data_for_org_ids(idList):
294 """ for a given list of org id values , 295 returns a map of id_org vs. org attributes: description, id_category""" 296 297 ids = ", ".join( [ str(x) for x in idList]) 298 cmd = """select id, description, id_category from dem.org 299 where id in ( select id from dem.org where id in( %s) )""" % ids 300 #<DEBUG> 301 print cmd 302 #</DEBUG> 303 result = gmPG.run_ro_query("personalia", cmd, ) 304 if result is None: 305 _log.error("Unable to load orgs with ids (%s)" %ids) 306 return None 307 m = {} 308 for (id_org, d, id_cat) in result: 309 m[id_org] = (d, id_cat) 310 return m
311 #============================================================ 312 # 313 # IGNORE THE FOLLOWING, IF NOT INTERESTED IN TEST CODE 314 # 315 # 316 317 if __name__ == '__main__': 318 print "Please enter a write-enabled user e.g. _test-doc " 319
320 - def testListOrgs():
321 print "running test listOrg" 322 for (f,a) in get_test_data(): 323 h = cOrgImpl1() 324 h.set(*f) 325 h.setAddress(*a) 326 if not h.save(): 327 print "did not save ", f 328 329 orgs = cOrgHelperImpl1().findAllOrganizations() 330 331 for org in orgs: 332 print "Found org ", org.get(), org.getAddress() 333 if not org.shallow_del(): 334 print "Unable to delete above org"
335 336 337 338 339 340
341 - def get_test_data():
342 """test org data for unit testing in testOrg()""" 343 return [ 344 ( ["Box Hill Hospital", "", "", "Eastern", "hospital", "0398953333", "111-1111","bhh@oz", ""], ["33", "Nelson Rd", "Box Hill", "3128", None , None] ), 345 ( ["Frankston Hospital", "", "", "Peninsula", "hospital", "0397847777", "03784-3111","fh@oz", ""], ["21", "Hastings Rd", "Frankston", "3199", None , None] ) 346 ]
347
348 - def get_test_persons():
349 return { "Box Hill Hospital": 350 [ 351 ['Dr.', 'Bill' , 'Smith', '123-4567', '0417 111 222'], 352 ['Ms.', 'Anita', 'Jones', '124-5544', '0413 222 444'], 353 ['Dr.', 'Will', 'Stryker', '999-4444', '0402 333 111'] ], 354 "Frankston Hospital": 355 [ [ "Dr.", "Jason", "Boathead", "444-5555", "0403 444 2222" ], 356 [ "Mr.", "Barnie", "Commuter", "222-1111", "0444 999 3333"], 357 [ "Ms.", "Morita", "Traveller", "999-1111", "0222 333 1111"]] }
358
359 - def testOrgPersons():
360 m = get_test_persons() 361 d = dict( [ (f[0] , (f, a)) for (f, a) in get_test_data() ] ) 362 for orgName , personList in m.items(): 363 f1 , a1 = d[orgName][0], d[orgName][1] 364 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 365 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 366 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 367 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create) 368 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create) 369 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create, getTestIdentityUsing_cOrgDemographicAdapter)
370 371
372 - def _outputPersons( org):
373 m = org.getPersonMap() 374 375 if m== []: 376 print "NO persons were found unfortunately" 377 378 print """ TestOrgPersonRun got back for """ 379 a = org.getAddress() 380 print org["name"], a["number"], a["street"], a["urb"], a["postcode"] , " phone=", org['phone'] 381 382 for id, r in m.items(): 383 print "\t",", ".join( [ " ".join(r.get_names().values()), 384 "work no=", r.getCommChannel(gmDemographicRecord.WORK_PHONE), 385 "mobile no=", r.getCommChannel(gmDemographicRecord.MOBILE) 386 ] )
387 388
389 - def _testOrgPersonRun(f1, a1, personList):
390 print "Using test data :f1 = ", f1, "and a1 = ", a1 , " and lp = ", personList 391 print "-" * 50 392 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1) 393 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1) 394 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create) 395 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create)
396 397
398 - def _setIdentityTestData(identity, data):
399 identity.addName(data[1], data[2], True) 400 identity.setTitle(data[0]) 401 identity.linkCommChannel( gmDemographicRecord.WORK_PHONE, data[3]) 402 identity.linkCommChannel( gmDemographicRecord.MOBILE, data[4])
403
404 - def getTestIdentityUsingDirectDemographicRecord( data, org):
405 id = gmPerson.create_dummy_identity() 406 identity = gmDemographicRecord.cDemographicRecord_SQL(id) 407 _setIdentityTestData(identity, data) 408 return identity
409
410 - def getTestIdentityUsing_cOrgDemographicAdapter( data, org):
411 helper = cOrgHelperImpl3() 412 orgPerson= helper.createOrgPerson() 413 orgPerson.setParent(org) 414 orgPerson['name'] = ' '.join( [data[0], data[1], data[2]]) 415 orgPerson['phone'] = data[3] 416 orgPerson['mobile'] = data[4] 417 orgPerson.save() 418 return orgPerson.getDemographicRecord()
419 420
421 - def _testOrgClassPersonRun(f1, a1, personList, orgCreate, identityCreator = getTestIdentityUsingDirectDemographicRecord):
422 print "-" * 50 423 print "Testing org creator ", orgCreate 424 print " and identity creator ", identityCreator 425 print "-" * 50 426 h = orgCreate() 427 h.set(*f1) 428 h.setAddress(*a1) 429 if not h.save(): 430 print "Unable to save org for person test" 431 h.shallow_del() 432 return False 433 # use gmDemographicRecord to convert person list 434 for lp in personList: 435 identity = identityCreator(lp, h) 436 result , msg = h.linkPerson(identity) 437 print msg 438 439 _outputPersons(h) 440 deletePersons(h) 441 442 if h.shallow_del(): 443 print "Managed to dispose of org" 444 else: 445 print "unable to dispose of org" 446 447 return True
448 449 # def testOrgPerson(f1, a1, personList): 450
451 - def deletePerson(id):
452 cmds = [ ( "delete from dem.lnk_identity2comm_chan where fk_identity=%d"%id,[]), 453 ("delete from dem.names where id_identity=%d"%id,[]), 454 ("delete from dem.identity where id = %d"%id,[]) ] 455 result = gmPG.run_commit("personalia", cmds) 456 return result
457
458 - def deletePersons( org):
459 map = org.getPersonMap() 460 for id, r in map.items(): 461 org.unlinkPerson(r) 462 463 result = deletePerson(r.getID()) 464 if result == None: 465 _log.error("FAILED TO CLEANUP PERSON %d" %r.getID() )
466 467 468
469 - def testOrg():
470 """runs a test of load, save , shallow_del on items in from get_test_data""" 471 l = get_test_data() 472 results = [] 473 for (f, a) in l: 474 result, obj = _testOrgRun(f, a) 475 results.append( (result, obj) ) 476 return results
477 478 479
480 - def _testOrgRun( f1, a1):
481 482 print """testing single level orgs""" 483 f = [ "name", "office", "subtype", "memo", "category", "phone", "fax", "email","mobile"] 484 a = ["number", "street", "urb", "postcode", "state", "country"] 485 h = cOrgImpl1() 486 487 h.set(*f1) 488 h.setAddress(*a1) 489 490 print "testing get, getAddress" 491 print h.get() 492 print h.getAddressDict() 493 494 import sys 495 if not h.save(): 496 print "failed to save first time. Is an old test org needing manual removal?" 497 return False, h 498 print "saved pk =", h.getId() 499 500 501 pk = h.getId() 502 if h.shallow_del(): 503 print "shallow deleted ", h['name'] 504 else: 505 print "failed shallow delete of ", h['name'] 506 507 508 509 h2 = cOrgImpl1() 510 511 print "testing load" 512 513 print "should fail" 514 if not h2.load(pk): 515 print "Failed as expected" 516 517 if h.save(): 518 print "saved ", h['name'] , "again" 519 else: 520 print "failed re-save" 521 return False, h 522 523 h['fax'] = '222-1111' 524 print "using update save" 525 526 if h.save(): 527 print "saved updated passed" 528 print "Test reload next" 529 else: 530 print "failed save of updated data" 531 print "continuing to reload" 532 533 534 if not h2.load(h.getId()): 535 print "failed load" 536 return False, h 537 print "reloaded values" 538 print h2.get() 539 print h2.getAddressDict() 540 541 print "** End of Test org" 542 543 if h2.shallow_del(): 544 print "cleaned up" 545 else: 546 print "Test org needs to be manually removed" 547 548 return True, h2
549
550 - def clean_test_org():
551 l = get_test_data() 552 553 names = [ "".join( ["'" ,str(org[0]), "'"] ) for ( org, address) in l] 554 names += [ "'John Hunter Hospital'", "'Belmont District Hospital'"] 555 nameList = ",".join(names) 556 categoryList = "'hospital'" 557 558 cmds = [ ( """create temp table del_org as 559 select id from dem.org 560 where description in(%s) or 561 id_category in ( select id from dem.org_category c 562 where c.description in (%s)) 563 """ % (nameList, categoryList), [] ), 564 ("""create temp table del_identity as 565 select id from dem.identity 566 where id in 567 ( 568 select id_identity from dem.lnk_person_org_address 569 where id_org in ( select id from del_org) 570 )""",[] ), 571 ("""create temp table del_comm as 572 (select id_comm from dem.lnk_org2comm_channel where 573 id_org in ( select id from del_org) 574 ) UNION 575 (select id_comm from dem.lnk_identity2comm_chan where 576 id_identity in ( select id from del_identity) 577 )""", [] ), 578 ("""delete from dem.names where id_identity in 579 (select id from del_identity)""",[]), 580 ("""delete from dem.lnk_person_org_address where 581 id_org in (select id from del_org )""",[]), 582 ("""delete from dem.lnk_person_org_address where 583 id_identity in (select id from del_identity)""", []), 584 ("""delete from dem.lnk_org2comm_channel 585 where id_org in (select id from del_org) """,[]), 586 ("""delete from dem.lnk_identity2comm_chan 587 where id_identity in (select id from del_identity)""",[] ), 588 ("""delete from dem.comm_channel where id in ( select id_comm from del_comm)""",[]), 589 ("""delete from dem.lnk_job2person where id_identity in (select id from del_identity)""", []), 590 ("""delete from dem.identity where id in (select id from del_identity)""",[] ), 591 ("""delete from dem.org where id in ( select id from del_org) """ , [] ), 592 ("""drop table del_comm""",[]), 593 ("""drop table del_identity""",[]), 594 ("""drop table del_org""", []) 595 596 ] 597 result = gmPG.run_commit("personalia", cmds) <> None 598 599 return result
600 601
602 - def login_user_and_test(logintest, service = 'personalia', msg = "failed test" , use_prefix_rw= False):
603 """ tries to get and verify a read-write connection 604 which has permission to write to org tables, so the test case 605 can run. 606 """ 607 login2 = gmPG.request_login_params() 608 609 #login as the RW user 610 p = gmPG.ConnectionPool( login2) 611 if use_prefix_rw: 612 conn = p.GetConnection( service, readonly = 0) 613 else: 614 conn = p.GetConnection(service) 615 result = logintest(conn) 616 617 if result is False: 618 print msg 619 620 p.ReleaseConnection(service) 621 return result, login2
622
623 - def test_rw_user(conn):
624 # test it is a RW user, by making a entry and deleting it 625 try: 626 c.reload("org_category") 627 cursor = conn.cursor() 628 629 cursor.execute("select last_value from dem.org_id_seq") 630 [org_id_seq] = cursor.fetchone() 631 632 cursor.execute(""" 633 insert into dem.org ( description, id_category, id) 634 values ( 'xxxDEFAULTxxx', %d, 635 %d) 636 """ % ( c.getId('org_category', 'hospital') , org_id_seq + 1 ) ) 637 cursor.execute(""" 638 delete from dem.org where id = %d""" % ( org_id_seq + 1) ) 639 # make sure this exercise is committed, else a deadlock will occur 640 conn.commit() 641 except: 642 _log.exception("Test of Update Permission failed") 643 return False 644 return True
645
646 - def test_admin_user(conn):
647 try: 648 cursor = conn.cursor() 649 650 cursor.execute("select last_value from dem.org_category_id_seq") 651 [org_cat_id_seq] = cursor.fetchone() 652 653 cursor.execute(""" 654 insert into dem.org_category ( description, id) 655 values ( 'xxxDEFAULTxxx',%d) 656 """ % (org_cat_id_seq + 1 ) ) 657 cursor.execute(""" 658 delete from dem.org_category where description like 'xxxDEFAULTxxx' """ ) 659 # make sure this exercise is committed, else a deadlock will occur 660 conn.commit() 661 except: 662 _log.exception("Test of Update Permission failed") 663 return False 664 return True
665
666 - def login_rw_user():
667 return login_user_and_test( test_rw_user, "login cannot update org", use_prefix_rw = True)
668 669
670 - def login_admin_user():
671 return login_user_and_test( test_admin_user, "login cannot update org_category" )
672 673
674 - def create_temp_categories( categories = ['hospital']):
675 print "NEED TO CREATE TEMPORARY ORG_CATEGORY.\n\n ** PLEASE ENTER administrator login : e.g user 'gm-dbo' and his password" 676 #get a admin login 677 for i in xrange(0, 4): 678 result ,tmplogin = login_admin_user() 679 if result: 680 break 681 if i == 4: 682 print "Failed to login" 683 return categories 684 685 # and save it , for later removal of test categories. 686 from Gnumed.pycommon import gmLoginInfo 687 adminlogin = gmLoginInfo.LoginInfo(*tmplogin.GetInfo()) 688 689 #login as admin 690 p = gmPG.ConnectionPool( tmplogin) 691 conn = p.GetConnection("personalia") 692 693 # use the last value + 1 of the relevant sequence, but don't increment it 694 cursor = conn.cursor() 695 696 failed_categories = [] 697 n =1 698 for cat in categories: 699 cursor.execute("select last_value from dem.org_category_id_seq") 700 [org_cat_id_seq] = cursor.fetchone() 701 702 cursor.execute( "insert into dem.org_category(description, id) values('%s', %d)" % (cat, org_cat_id_seq + n) ) 703 cursor.execute("select id from dem.org_category where description in ('%s')" % cat) 704 705 result = cursor.fetchone() 706 if result == None or len(result) == 0: 707 failed_categories.append(cat) 708 print "Failed insert of category", cat 709 conn.rollback() 710 else: 711 conn.commit() 712 n += 1 713 714 conn.commit() 715 p.ReleaseConnection('personalia') 716 return failed_categories, adminlogin
717
718 - def clean_org_categories(adminlogin = None, categories = ['hospital'], service='personalia'):
719 720 print""" 721 722 The temporary category(s) will now 723 need to be removed under an administrator login 724 e.g. gm-dbo 725 Please enter login for administrator: 726 """ 727 if adminlogin is None: 728 for i in xrange(0, 4): 729 result, adminlogin = login_admin_user() 730 if result: 731 break 732 if i == 4: 733 print "FAILED TO LOGIN" 734 return categories 735 736 p = gmPG.ConnectionPool(adminlogin) 737 conn = p.GetConnection(service) 738 failed_remove = [] 739 for cat in categories: 740 try: 741 cursor = conn.cursor() 742 cursor.execute( "delete from dem.org_category where description in ('%s')"%cat) 743 conn.commit() 744 cursor.execute("select id from dem.org_category where description in ('%s')"%cat) 745 if cursor.fetchone() == None: 746 print "Succeeded in removing temporary org_category" 747 else: 748 print "*** Unable to remove temporary org_category" 749 failed_remove .append(cat) 750 except: 751 import sys 752 print sys.exc_info()[0], sys.exc_info()[1] 753 import traceback 754 traceback.print_tb(sys.exc_info()[2]) 755 756 failed_remove.append(cat) 757 758 conn = None 759 p.ReleaseConnection(service) 760 if failed_remove <> []: 761 print "FAILED TO REMOVE ", failed_remove 762 return failed_remove
763
764 - def test_CatFinder():
765 print "TESTING cCatFinder" 766 767 print """c = cCatFinder("org_category")""" 768 c = cCatFinder("org_category") 769 770 print c.getCategories("org_category") 771 772 print """c = cCatFinder("enum_comm_types")""" 773 c = cCatFinder("enum_comm_types") 774 775 l = c.getCategories("enum_comm_types") 776 print "testing getId()" 777 l2 = [] 778 for x in l: 779 l2.append((x, c.getId("enum_comm_types", x))) 780 print l2 781 782 print """testing borg behaviour of cCatFinder""" 783 784 print c.getCategories("org_category")
785 786
787 - def help():
788 print """\nNB If imports not found , try: 789 790 change to gnumed/client directory , then 791 792 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py 793 794 --clean , cleans the test data and categories 795 796 --gui sets up as for no arguments, then runs the client. 797 on normal exit of client, normal tests run, and 798 then cleanup of entered data. 799 800 using the gui, 801 802 the 'list organisations' toolbar button , loads all organisations 803 in the database, and display suborgs and persons associated 804 with each organisation. 805 806 the 'add organisation' button will add a top-level organisation. 807 the 'add branch/division' button will work when the last selected 808 org was a top level org. 809 810 the 'add person M|F' button works if an org is selected. 811 812 the save button works when entry is finished. 813 814 selecting on an item, will bring it into the editing area. 815 816 No test yet for dirtied edit data, to query whether to 817 save or discard. (30/5/2004) 818 """ 819 print 820 print "In the connection query, please enter" 821 print "a WRITE-ENABLED user e.g. _test-doc (not test-doc), and the right password" 822 print 823 print "Run the unit test with cmdline argument '--clean' if trying to clean out test data" 824 print 825 826 print """You can get a sermon by running 827 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py --sermon 828 """ 829 print """ 830 Pre-requisite data in database is : 831 gnumed=# select * from org_category ; 832 id | description 833 ----+------------- 834 1 | hospital 835 (1 row) 836 837 gnumed=# select * from enum_comm_types ; 838 id | description 839 ----+------------- 840 1 | email 841 2 | fax 842 3 | homephone 843 4 | workphone 844 5 | mobile 845 6 | web 846 7 | jabber 847 (7 rows) 848 """
849
850 - def sermon():
851 print""" 852 This test case shows how many things can go wrong , even with just a test case. 853 Problem areas include: 854 - postgres administration : pg_ctl state, pg_hba.conf, postgres.conf config files . 855 - 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. 856 857 858 - 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 859 without calling the backend for each object. 860 861 - error and exception handling - at what point in the call stack to handle an error. 862 Better to use error return values and log exceptions near where they occur, vs. wrapping inside try: except: blocks and catching typed exceptions. 863 864 865 - test-case construction: test data is needed often, and the issue 866 is whether it is better to keep the test data volatile in the test-case, 867 which handles both its creation and deletion, or to add it to test data 868 server configuration files, which may involve running backend scripts 869 for loading and removing test data. 870 871 872 873 - Database connection problems: 874 -Is the problem in : 875 - pg_ctl start -D /...mydata-directory is wrong, and gnumed isn't existing there. 876 877 - ..mydata-directory/pg_hba.conf 878 - can psql connect locally and remotely with the username and password. 879 - Am I using md5 authenentication and I've forgotten the password. 880 - I need to su postgres, alter pg_hba.conf to use trust for 881 the gnumed database, pg_ctl restart -D .., su normal_user, psql gnumed, alter user my_username password 'doh' 882 - might be helpful: the default password for _test-doc is test-doc 883 884 - ../mydata-directory/postgres.conf 885 - tcp connect flag isn't set to true 886 887 - remote/local mixup : 888 a different set of user passwords on different hosts. e.g the password 889 for _test-doc is 'pass' on localhost and 'test-doc' for the serverhost. 890 - In the prompts for admin and user login, local host was used for one, and 891 remote host for the other 892 893 894 895 - test data won't go away : 896 - 'hospital' category in org_category : the test case failed in a previous run 897 and the test data was left there; now the test case won't try to delete it 898 because it exists as a pre-existing category; 899 soln : run with --clean option 900 901 - test-case failed unexpectedly, or break key was hit in the middle of a test-case run. 902 Soln: run with --clean option, 903 904 905 """
906 907 908 #============================================================ 909 910 import sys 911 testgui = False 912 if len(sys.argv) > 1: 913 if sys.argv[1] == '--clean': 914 result = clean_test_org() 915 p = gmPG.ConnectionPool() 916 p.ReleaseConnection('personalia') 917 if result: 918 print "probably succeeded in cleaning orgs" 919 else: print "failed to clean orgs" 920 921 clean_org_categories() 922 sys.exit(1) 923 924 if sys.argv[1] == "--sermon": 925 sermon() 926 927 if sys.argv[1] == "--help": 928 help() 929 930 if sys.argv[1] =="--gui": 931 testgui = True 932 933 print "*" * 50 934 print "RUNNING UNIT TEST of gmOrganization " 935 936 937 test_CatFinder() 938 tmp_category = False # tmp_category means test data will need to be added and removed 939 # for org_category . 940 941 c = cCatFinder() 942 if not "hospital" in c.getCategories("org_category") : 943 print "FAILED in prerequisite for org_category : test categories are not present." 944 945 tmp_category = True 946 947 if tmp_category: 948 # test data in a categorical table (restricted access) is needed 949 950 print """You will need to switch login identity to database administrator in order 951 to have permission to write to the org_category table, 952 and then switch back to the ordinary write-enabled user in order 953 to run the test cases. 954 Finally you will need to switch back to administrator login to 955 remove the temporary org_categories. 956 """ 957 categories = ['hospital'] 958 result, adminlogin = create_temp_categories(categories) 959 if result == categories: 960 print "Unable to create temporary org_category. Test aborted" 961 sys.exit(-1) 962 if result <> []: 963 print "UNABLE TO CREATE THESE CATEGORIES" 964 if not raw_input("Continue ?") in ['y', 'Y'] : 965 sys.exit(-1) 966 967 try: 968 results = [] 969 if tmp_category: 970 print "succeeded in creating temporary org_category" 971 print 972 print "** Now ** RESUME LOGIN ** of write-enabled user (e.g. _test-doc) " 973 while (1): 974 # get the RW user for org tables (again) 975 if login_rw_user(): 976 break 977 978 if testgui: 979 if cCatFinder().getId('org_category','hospital') == None: 980 print "Needed to set up temporary org_category 'hospital" 981 sys.exit(-1) 982 import os 983 print os.environ['PWD'] 984 os.spawnl(os.P_WAIT, "/usr/bin/python", "/usr/bin/python","wxpython/gnumed.py", "--debug") 985 986 #os.popen2('python client/wxpython/gnumed.py --debug') 987 988 # run the test case 989 results = testOrg() 990 991 # cleanup after the test case 992 for (result , org) in results: 993 if not result and org.getId() <> None: 994 print "trying cleanup" 995 if org.shallow_del(): print " may have succeeded" 996 else: 997 print "May need manual removal of org id =", org.getId() 998 999 testOrgPersons() 1000 1001 testListOrgs() 1002 1003 except: 1004 import sys 1005 print sys.exc_info()[0], sys.exc_info()[1] 1006 _log.exception( "Fatal exception") 1007 1008 # clean-up any temporary categories. 1009 if tmp_category: 1010 try: 1011 clean_org_categories(adminlogin) 1012 except: 1013 while(not login_rw_user()[0]): 1014 pass 1015 clean_test_org() 1016 clean_org_categories(adminlogin) 1017 1018 1019
1020 -def setPostcodeWidgetFromUrbId(postcodeWidget, id_urb):
1021 """convenience method for urb and postcode phrasewheel interaction. 1022 never called without both arguments, but need to check that id_urb 1023 is not invalid""" 1024 #TODO type checking that the postcodeWidget is a phrasewheel configured 1025 # with a postcode matcher 1026 if postcodeWidget is None or id_urb is None: 1027 return False 1028 postcode = getPostcodeForUrbId(id_urb) 1029 if postcode is None: 1030 return False 1031 if len(postcode) == 0: 1032 return True 1033 postcodeWidget.SetValue(postcode) 1034 postcodeWidget.input_was_selected= 1 1035 return True
1036 1037 #------------------------------------------------------------ 1038
1039 -def setUrbPhraseWheelFromPostcode(pwheel, postcode):
1040 """convenience method for common postcode to urb phrasewheel collaboration. 1041 there is no default args for these utility functions, 1042 This function is never called without both arguments, otherwise 1043 there is no intention (= modify the urb phrasewheel with postcode value). 1044 """ 1045 # TODO type checking that the pwheel is a urb phrasewheel with a urb matcher 1046 # clearing post code unsets target 1047 # phrasewheel's postcode context 1048 if pwheel is None: 1049 return False 1050 if postcode == '': 1051 pwheel.set_context("postcode", "%") 1052 return True 1053 urbs = getUrbsForPostcode(postcode) 1054 if urbs is None: 1055 return False 1056 if len(urbs) == 0: 1057 return True 1058 pwheel.SetValue(urbs[0]) 1059 pwheel.input_was_selected = 1 1060 1061 # FIXME: once the postcode context is set, 1062 # the urb phrasewheel will only return urbs with 1063 # the same postcode. These can be viewed by clearing 1064 # the urb widget. ?How to unset the postcode context, 1065 # some gui gesture ? clearing the postcode 1066 # (To view all the urbs for a set context, 1067 # put a "*" in the urb box and activate the picklist. 1068 # THE PROBLEM WITH THIS IS IF THE USER CLEARS THE BOX AND SET CONTEXT IS RESET, 1069 # then the "*" will try to pull all thousands of urb names, freezing the app. 1070 # so needs a fixup (? have SQL select ... LIMIT n in Phrasewheel ) 1071 1072 pwheel.set_context("postcode", postcode) 1073 return True
1074 1075 #====================================================================== 1076