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