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