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