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