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

Source Code for Module Gnumed.business.gmOrganization

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