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