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
310 pk = %(pk)s
311 AND
312 NOT EXISTS (
313 SELECT 1 FROM clin.encounter where fk_location = %(pk)s
314 )
315 """
316 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
317 return True
318
320
321 if order_by is None:
322 order_by = u''
323 else:
324 order_by = u' ORDER BY %s' % order_by
325
326 if org is None:
327 where_part = u'TRUE'
328 else:
329 where_part = u'pk_org = %(org)s'
330
331 args = {'org': org}
332 cmd = (_SQL_get_org_unit % where_part) + order_by
333 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
334
335 return [ cOrgUnit(row = {'data': r, 'idx': idx, 'pk_field': u'pk_org_unit'}) for r in rows ]
336
337
338
339
340 if __name__ == "__main__":
341
342 if len(sys.argv) < 2:
343 sys.exit()
344
345 if sys.argv[1] != u'test':
346 sys.exit()
347
348
349 for unit in get_org_units():
350 print unit
351
352 sys.exit(0)
353
354
355
356
357
358
359
360
361
362
363
364
366 """gets comm_channels for a list of org_id.
367 returns a map keyed by org_id with lists of comm_channel data (url, type).
368 this allows a single fetch of comm_channel data for multiple orgs"""
369
370 ids = ", ".join( [ str(x) for x in idList])
371 cmd = """select l.id_org, id_type, url
372 from dem.comm_channel c, dem.lnk_org2comm_channel l
373 where
374 c.id = l.id_comm and
375 l.id_org in ( select id from dem.org where id in (%s) )
376 """ % ids
377 result = gmPG.run_ro_query("personalia", cmd)
378 if result == None:
379 _log.error("Unable to load comm channels for org" )
380 return None
381 m = {}
382 for (id_org, id_type, url) in result:
383 if not m.has_key(id_org):
384 m[id_org] = []
385 m[id_org].append( (id_type, url) )
386
387 return m
388
390 """gets addresses for a list of valid id values for orgs.
391 returns a map keyed by org_id with the address data
392 """
393
394 ids = ", ".join( [ str(x) for x in idList])
395 cmd = """select l.id_org, number, street, city, postcode, state, country
396 from dem.v_basic_address v , dem.lnk_org2address l
397 where v.addr_id = l.id_address and
398 l.id_org in ( select id from dem.org where id in (%s) ) """ % ids
399 result = gmPG.run_ro_query( "personalia", cmd)
400
401 if result == None:
402 _log.error("failure in org address load" )
403 return None
404 m = {}
405 for (id_org, n,s,ci,p,st,co) in result:
406 m[id_org] = (n,s,ci,p,st,co)
407 return m
408
410 """ for a given list of org id values ,
411 returns a map of id_org vs. org attributes: description, id_category"""
412
413 ids = ", ".join( [ str(x) for x in idList])
414 cmd = """select id, description, id_category from dem.org
415 where id in ( select id from dem.org where id in( %s) )""" % ids
416
417 print cmd
418
419 result = gmPG.run_ro_query("personalia", cmd, )
420 if result is None:
421 _log.error("Unable to load orgs with ids (%s)" %ids)
422 return None
423 m = {}
424 for (id_org, d, id_cat) in result:
425 m[id_org] = (d, id_cat)
426 return m
427
428
429
430
431
432
433 if __name__ == '__main__':
434 print "Please enter a write-enabled user e.g. _test-doc "
435
437 print "running test listOrg"
438 for (f,a) in get_test_data():
439 h = cOrgImpl1()
440 h.set(*f)
441 h.setAddress(*a)
442 if not h.save():
443 print "did not save ", f
444
445 orgs = cOrgHelperImpl1().findAllOrganizations()
446
447 for org in orgs:
448 print "Found org ", org.get(), org.getAddress()
449 if not org.shallow_del():
450 print "Unable to delete above org"
451
452
453
454
455
456
458 """test org data for unit testing in testOrg()"""
459 return [
460 ( ["Box Hill Hospital", "", "", "Eastern", "hospital", "0398953333", "111-1111","bhh@oz", ""], ["33", "Nelson Rd", "Box Hill", "3128", None , None] ),
461 ( ["Frankston Hospital", "", "", "Peninsula", "hospital", "0397847777", "03784-3111","fh@oz", ""], ["21", "Hastings Rd", "Frankston", "3199", None , None] )
462 ]
463
465 return { "Box Hill Hospital":
466 [
467 ['Dr.', 'Bill' , 'Smith', '123-4567', '0417 111 222'],
468 ['Ms.', 'Anita', 'Jones', '124-5544', '0413 222 444'],
469 ['Dr.', 'Will', 'Stryker', '999-4444', '0402 333 111'] ],
470 "Frankston Hospital":
471 [ [ "Dr.", "Jason", "Boathead", "444-5555", "0403 444 2222" ],
472 [ "Mr.", "Barnie", "Commuter", "222-1111", "0444 999 3333"],
473 [ "Ms.", "Morita", "Traveller", "999-1111", "0222 333 1111"]] }
474
476 m = get_test_persons()
477 d = dict( [ (f[0] , (f, a)) for (f, a) in get_test_data() ] )
478 for orgName , personList in m.items():
479 f1 , a1 = d[orgName][0], d[orgName][1]
480 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1)
481 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1)
482 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create)
483 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create)
484 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create)
485 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl3().create, getTestIdentityUsing_cOrgDemographicAdapter)
486
487
489 m = org.getPersonMap()
490
491 if m== []:
492 print "NO persons were found unfortunately"
493
494 print """ TestOrgPersonRun got back for """
495 a = org.getAddress()
496 print org["name"], a["number"], a["street"], a["urb"], a["postcode"] , " phone=", org['phone']
497
498 for id, r in m.items():
499 print "\t",", ".join( [ " ".join(r.get_names().values()),
500 "work no=", r.getCommChannel(gmDemographicRecord.WORK_PHONE),
501 "mobile no=", r.getCommChannel(gmDemographicRecord.MOBILE)
502 ] )
503
504
506 print "Using test data :f1 = ", f1, "and a1 = ", a1 , " and lp = ", personList
507 print "-" * 50
508 _testOrgClassPersonRun( f1, a1, personList, cOrgImpl1)
509 _testOrgClassPersonRun( f1, a1, personList, cCompositeOrgImpl1)
510 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl1().create)
511 _testOrgClassPersonRun( f1, a1, personList, cOrgHelperImpl2().create)
512
513
519
525
527 helper = cOrgHelperImpl3()
528 orgPerson= helper.createOrgPerson()
529 orgPerson.setParent(org)
530 orgPerson['name'] = ' '.join( [data[0], data[1], data[2]])
531 orgPerson['phone'] = data[3]
532 orgPerson['mobile'] = data[4]
533 orgPerson.save()
534 return orgPerson.getDemographicRecord()
535
536
537 - def _testOrgClassPersonRun(f1, a1, personList, orgCreate, identityCreator = getTestIdentityUsingDirectDemographicRecord):
538 print "-" * 50
539 print "Testing org creator ", orgCreate
540 print " and identity creator ", identityCreator
541 print "-" * 50
542 h = orgCreate()
543 h.set(*f1)
544 h.setAddress(*a1)
545 if not h.save():
546 print "Unable to save org for person test"
547 h.shallow_del()
548 return False
549
550 for lp in personList:
551 identity = identityCreator(lp, h)
552 result , msg = h.linkPerson(identity)
553 print msg
554
555 _outputPersons(h)
556 deletePersons(h)
557
558 if h.shallow_del():
559 print "Managed to dispose of org"
560 else:
561 print "unable to dispose of org"
562
563 return True
564
565
566
568 cmds = [ ( "delete from dem.lnk_identity2comm_chan where fk_identity=%d"%id,[]),
569 ("delete from dem.names where id_identity=%d"%id,[]),
570 ("delete from dem.identity where id = %d"%id,[]) ]
571 result = gmPG.run_commit("personalia", cmds)
572 return result
573
575 map = org.getPersonMap()
576 for id, r in map.items():
577 org.unlinkPerson(r)
578
579 result = deletePerson(r.getID())
580 if result == None:
581 _log.error("FAILED TO CLEANUP PERSON %d" %r.getID() )
582
583
584
586 """runs a test of load, save , shallow_del on items in from get_test_data"""
587 l = get_test_data()
588 results = []
589 for (f, a) in l:
590 result, obj = _testOrgRun(f, a)
591 results.append( (result, obj) )
592 return results
593
594
595
597
598 print """testing single level orgs"""
599 f = [ "name", "office", "subtype", "memo", "category", "phone", "fax", "email","mobile"]
600 a = ["number", "street", "urb", "postcode", "state", "country"]
601 h = cOrgImpl1()
602
603 h.set(*f1)
604 h.setAddress(*a1)
605
606 print "testing get, getAddress"
607 print h.get()
608 print h.getAddressDict()
609
610 import sys
611 if not h.save():
612 print "failed to save first time. Is an old test org needing manual removal?"
613 return False, h
614 print "saved pk =", h.getId()
615
616
617 pk = h.getId()
618 if h.shallow_del():
619 print "shallow deleted ", h['name']
620 else:
621 print "failed shallow delete of ", h['name']
622
623
624
625 h2 = cOrgImpl1()
626
627 print "testing load"
628
629 print "should fail"
630 if not h2.load(pk):
631 print "Failed as expected"
632
633 if h.save():
634 print "saved ", h['name'] , "again"
635 else:
636 print "failed re-save"
637 return False, h
638
639 h['fax'] = '222-1111'
640 print "using update save"
641
642 if h.save():
643 print "saved updated passed"
644 print "Test reload next"
645 else:
646 print "failed save of updated data"
647 print "continuing to reload"
648
649
650 if not h2.load(h.getId()):
651 print "failed load"
652 return False, h
653 print "reloaded values"
654 print h2.get()
655 print h2.getAddressDict()
656
657 print "** End of Test org"
658
659 if h2.shallow_del():
660 print "cleaned up"
661 else:
662 print "Test org needs to be manually removed"
663
664 return True, h2
665
667 l = get_test_data()
668
669 names = [ "".join( ["'" ,str(org[0]), "'"] ) for ( org, address) in l]
670 names += [ "'John Hunter Hospital'", "'Belmont District Hospital'"]
671 nameList = ",".join(names)
672 categoryList = "'hospital'"
673
674 cmds = [ ( """create temp table del_org as
675 select id from dem.org
676 where description in(%s) or
677 id_category in ( select id from dem.org_category c
678 where c.description in (%s))
679 """ % (nameList, categoryList), [] ),
680 ("""create temp table del_identity as
681 select id from dem.identity
682 where id in
683 (
684 select id_identity from dem.lnk_person_org_address
685 where id_org in ( select id from del_org)
686 )""",[] ),
687 ("""create temp table del_comm as
688 (select id_comm from dem.lnk_org2comm_channel where
689 id_org in ( select id from del_org)
690 ) UNION
691 (select id_comm from dem.lnk_identity2comm_chan where
692 id_identity in ( select id from del_identity)
693 )""", [] ),
694 ("""delete from dem.names where id_identity in
695 (select id from del_identity)""",[]),
696 ("""delete from dem.lnk_person_org_address where
697 id_org in (select id from del_org )""",[]),
698 ("""delete from dem.lnk_person_org_address where
699 id_identity in (select id from del_identity)""", []),
700 ("""delete from dem.lnk_org2comm_channel
701 where id_org in (select id from del_org) """,[]),
702 ("""delete from dem.lnk_identity2comm_chan
703 where id_identity in (select id from del_identity)""",[] ),
704 ("""delete from dem.comm_channel where id in ( select id_comm from del_comm)""",[]),
705 ("""delete from dem.lnk_job2person where id_identity in (select id from del_identity)""", []),
706 ("""delete from dem.identity where id in (select id from del_identity)""",[] ),
707 ("""delete from dem.org where id in ( select id from del_org) """ , [] ),
708 ("""drop table del_comm""",[]),
709 ("""drop table del_identity""",[]),
710 ("""drop table del_org""", [])
711
712 ]
713 result = gmPG.run_commit("personalia", cmds) <> None
714
715 return result
716
717
718 - def login_user_and_test(logintest, service = 'personalia', msg = "failed test" , use_prefix_rw= False):
719 """ tries to get and verify a read-write connection
720 which has permission to write to org tables, so the test case
721 can run.
722 """
723 login2 = gmPG.request_login_params()
724
725
726 p = gmPG.ConnectionPool( login2)
727 if use_prefix_rw:
728 conn = p.GetConnection( service, readonly = 0)
729 else:
730 conn = p.GetConnection(service)
731 result = logintest(conn)
732
733 if result is False:
734 print msg
735
736 p.ReleaseConnection(service)
737 return result, login2
738
740
741 try:
742 c.reload("org_category")
743 cursor = conn.cursor()
744
745 cursor.execute("select last_value from dem.org_id_seq")
746 [org_id_seq] = cursor.fetchone()
747
748 cursor.execute("""
749 insert into dem.org ( description, id_category, id)
750 values ( 'xxxDEFAULTxxx', %d,
751 %d)
752 """ % ( c.getId('org_category', 'hospital') , org_id_seq + 1 ) )
753 cursor.execute("""
754 delete from dem.org where id = %d""" % ( org_id_seq + 1) )
755
756 conn.commit()
757 except:
758 _log.exception("Test of Update Permission failed")
759 return False
760 return True
761
763 try:
764 cursor = conn.cursor()
765
766 cursor.execute("select last_value from dem.org_category_id_seq")
767 [org_cat_id_seq] = cursor.fetchone()
768
769 cursor.execute("""
770 insert into dem.org_category ( description, id)
771 values ( 'xxxDEFAULTxxx',%d)
772 """ % (org_cat_id_seq + 1 ) )
773 cursor.execute("""
774 delete from dem.org_category where description like 'xxxDEFAULTxxx' """ )
775
776 conn.commit()
777 except:
778 _log.exception("Test of Update Permission failed")
779 return False
780 return True
781
783 return login_user_and_test( test_rw_user, "login cannot update org", use_prefix_rw = True)
784
785
787 return login_user_and_test( test_admin_user, "login cannot update org_category" )
788
789
791 print "NEED TO CREATE TEMPORARY ORG_CATEGORY.\n\n ** PLEASE ENTER administrator login : e.g user 'gm-dbo' and his password"
792
793 for i in xrange(0, 4):
794 result ,tmplogin = login_admin_user()
795 if result:
796 break
797 if i == 4:
798 print "Failed to login"
799 return categories
800
801
802 from Gnumed.pycommon import gmLoginInfo
803 adminlogin = gmLoginInfo.LoginInfo(*tmplogin.GetInfo())
804
805
806 p = gmPG.ConnectionPool( tmplogin)
807 conn = p.GetConnection("personalia")
808
809
810 cursor = conn.cursor()
811
812 failed_categories = []
813 n =1
814 for cat in categories:
815 cursor.execute("select last_value from dem.org_category_id_seq")
816 [org_cat_id_seq] = cursor.fetchone()
817
818 cursor.execute( "insert into dem.org_category(description, id) values('%s', %d)" % (cat, org_cat_id_seq + n) )
819 cursor.execute("select id from dem.org_category where description in ('%s')" % cat)
820
821 result = cursor.fetchone()
822 if result == None or len(result) == 0:
823 failed_categories.append(cat)
824 print "Failed insert of category", cat
825 conn.rollback()
826 else:
827 conn.commit()
828 n += 1
829
830 conn.commit()
831 p.ReleaseConnection('personalia')
832 return failed_categories, adminlogin
833
835
836 print"""
837
838 The temporary category(s) will now
839 need to be removed under an administrator login
840 e.g. gm-dbo
841 Please enter login for administrator:
842 """
843 if adminlogin is None:
844 for i in xrange(0, 4):
845 result, adminlogin = login_admin_user()
846 if result:
847 break
848 if i == 4:
849 print "FAILED TO LOGIN"
850 return categories
851
852 p = gmPG.ConnectionPool(adminlogin)
853 conn = p.GetConnection(service)
854 failed_remove = []
855 for cat in categories:
856 try:
857 cursor = conn.cursor()
858 cursor.execute( "delete from dem.org_category where description in ('%s')"%cat)
859 conn.commit()
860 cursor.execute("select id from dem.org_category where description in ('%s')"%cat)
861 if cursor.fetchone() == None:
862 print "Succeeded in removing temporary org_category"
863 else:
864 print "*** Unable to remove temporary org_category"
865 failed_remove .append(cat)
866 except:
867 import sys
868 print sys.exc_info()[0], sys.exc_info()[1]
869 import traceback
870 traceback.print_tb(sys.exc_info()[2])
871
872 failed_remove.append(cat)
873
874 conn = None
875 p.ReleaseConnection(service)
876 if failed_remove <> []:
877 print "FAILED TO REMOVE ", failed_remove
878 return failed_remove
879
881 print "TESTING cCatFinder"
882
883 print """c = cCatFinder("org_category")"""
884 c = cCatFinder("org_category")
885
886 print c.getCategories("org_category")
887
888 print """c = cCatFinder("enum_comm_types")"""
889 c = cCatFinder("enum_comm_types")
890
891 l = c.getCategories("enum_comm_types")
892 print "testing getId()"
893 l2 = []
894 for x in l:
895 l2.append((x, c.getId("enum_comm_types", x)))
896 print l2
897
898 print """testing borg behaviour of cCatFinder"""
899
900 print c.getCategories("org_category")
901
902
904 print """\nNB If imports not found , try:
905
906 change to gnumed/client directory , then
907
908 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py
909
910 --clean , cleans the test data and categories
911
912 --gui sets up as for no arguments, then runs the client.
913 on normal exit of client, normal tests run, and
914 then cleanup of entered data.
915
916 using the gui,
917
918 the 'list organisations' toolbar button , loads all organisations
919 in the database, and display suborgs and persons associated
920 with each organisation.
921
922 the 'add organisation' button will add a top-level organisation.
923 the 'add branch/division' button will work when the last selected
924 org was a top level org.
925
926 the 'add person M|F' button works if an org is selected.
927
928 the save button works when entry is finished.
929
930 selecting on an item, will bring it into the editing area.
931
932 No test yet for dirtied edit data, to query whether to
933 save or discard. (30/5/2004)
934 """
935 print
936 print "In the connection query, please enter"
937 print "a WRITE-ENABLED user e.g. _test-doc (not test-doc), and the right password"
938 print
939 print "Run the unit test with cmdline argument '--clean' if trying to clean out test data"
940 print
941
942 print """You can get a sermon by running
943 export PYTHONPATH=$PYTHONPATH:../;python business/gmOrganization.py --sermon
944 """
945 print """
946 Pre-requisite data in database is :
947 gnumed=# select * from org_category ;
948 id | description
949 ----+-------------
950 1 | hospital
951 (1 row)
952
953 gnumed=# select * from enum_comm_types ;
954 id | description
955 ----+-------------
956 1 | email
957 2 | fax
958 3 | homephone
959 4 | workphone
960 5 | mobile
961 6 | web
962 7 | jabber
963 (7 rows)
964 """
965
967 print"""
968 This test case shows how many things can go wrong , even with just a test case.
969 Problem areas include:
970 - postgres administration : pg_ctl state, pg_hba.conf, postgres.conf config files .
971 - 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.
972
973
974 - 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
975 without calling the backend for each object.
976
977 - error and exception handling - at what point in the call stack to handle an error.
978 Better to use error return values and log exceptions near where they occur, vs. wrapping inside try: except: blocks and catching typed exceptions.
979
980
981 - test-case construction: test data is needed often, and the issue
982 is whether it is better to keep the test data volatile in the test-case,
983 which handles both its creation and deletion, or to add it to test data
984 server configuration files, which may involve running backend scripts
985 for loading and removing test data.
986
987
988
989 - Database connection problems:
990 -Is the problem in :
991 - pg_ctl start -D /...mydata-directory is wrong, and gnumed isn't existing there.
992
993 - ..mydata-directory/pg_hba.conf
994 - can psql connect locally and remotely with the username and password.
995 - Am I using md5 authenentication and I've forgotten the password.
996 - I need to su postgres, alter pg_hba.conf to use trust for
997 the gnumed database, pg_ctl restart -D .., su normal_user, psql gnumed, alter user my_username password 'doh'
998 - might be helpful: the default password for _test-doc is test-doc
999
1000 - ../mydata-directory/postgres.conf
1001 - tcp connect flag isn't set to true
1002
1003 - remote/local mixup :
1004 a different set of user passwords on different hosts. e.g the password
1005 for _test-doc is 'pass' on localhost and 'test-doc' for the serverhost.
1006 - In the prompts for admin and user login, local host was used for one, and
1007 remote host for the other
1008
1009
1010
1011 - test data won't go away :
1012 - 'hospital' category in org_category : the test case failed in a previous run
1013 and the test data was left there; now the test case won't try to delete it
1014 because it exists as a pre-existing category;
1015 soln : run with --clean option
1016
1017 - test-case failed unexpectedly, or break key was hit in the middle of a test-case run.
1018 Soln: run with --clean option,
1019
1020
1021 """
1022
1023
1024
1025
1026 import sys
1027 testgui = False
1028 if len(sys.argv) > 1:
1029 if sys.argv[1] == '--clean':
1030 result = clean_test_org()
1031 p = gmPG.ConnectionPool()
1032 p.ReleaseConnection('personalia')
1033 if result:
1034 print "probably succeeded in cleaning orgs"
1035 else: print "failed to clean orgs"
1036
1037 clean_org_categories()
1038 sys.exit(1)
1039
1040 if sys.argv[1] == "--sermon":
1041 sermon()
1042
1043 if sys.argv[1] == "--help":
1044 help()
1045
1046 if sys.argv[1] =="--gui":
1047 testgui = True
1048
1049 print "*" * 50
1050 print "RUNNING UNIT TEST of gmOrganization "
1051
1052
1053 test_CatFinder()
1054 tmp_category = False
1055
1056
1057 c = cCatFinder()
1058 if not "hospital" in c.getCategories("org_category") :
1059 print "FAILED in prerequisite for org_category : test categories are not present."
1060
1061 tmp_category = True
1062
1063 if tmp_category:
1064
1065
1066 print """You will need to switch login identity to database administrator in order
1067 to have permission to write to the org_category table,
1068 and then switch back to the ordinary write-enabled user in order
1069 to run the test cases.
1070 Finally you will need to switch back to administrator login to
1071 remove the temporary org_categories.
1072 """
1073 categories = ['hospital']
1074 result, adminlogin = create_temp_categories(categories)
1075 if result == categories:
1076 print "Unable to create temporary org_category. Test aborted"
1077 sys.exit(-1)
1078 if result <> []:
1079 print "UNABLE TO CREATE THESE CATEGORIES"
1080 if not raw_input("Continue ?") in ['y', 'Y'] :
1081 sys.exit(-1)
1082
1083 try:
1084 results = []
1085 if tmp_category:
1086 print "succeeded in creating temporary org_category"
1087 print
1088 print "** Now ** RESUME LOGIN ** of write-enabled user (e.g. _test-doc) "
1089 while (1):
1090
1091 if login_rw_user():
1092 break
1093
1094 if testgui:
1095 if cCatFinder().getId('org_category','hospital') == None:
1096 print "Needed to set up temporary org_category 'hospital"
1097 sys.exit(-1)
1098 import os
1099 print os.environ['PWD']
1100 os.spawnl(os.P_WAIT, "/usr/bin/python", "/usr/bin/python","wxpython/gnumed.py", "--debug")
1101
1102
1103
1104
1105 results = testOrg()
1106
1107
1108 for (result , org) in results:
1109 if not result and org.getId() <> None:
1110 print "trying cleanup"
1111 if org.shallow_del(): print " may have succeeded"
1112 else:
1113 print "May need manual removal of org id =", org.getId()
1114
1115 testOrgPersons()
1116
1117 testListOrgs()
1118
1119 except:
1120 import sys
1121 print sys.exc_info()[0], sys.exc_info()[1]
1122 _log.exception( "Fatal exception")
1123
1124
1125 if tmp_category:
1126 try:
1127 clean_org_categories(adminlogin)
1128 except:
1129 while(not login_rw_user()[0]):
1130 pass
1131 clean_test_org()
1132 clean_org_categories(adminlogin)
1133
1134
1135
1137 """convenience method for urb and postcode phrasewheel interaction.
1138 never called without both arguments, but need to check that id_urb
1139 is not invalid"""
1140
1141
1142 if postcodeWidget is None or id_urb is None:
1143 return False
1144 postcode = getPostcodeForUrbId(id_urb)
1145 if postcode is None:
1146 return False
1147 if len(postcode) == 0:
1148 return True
1149 postcodeWidget.SetValue(postcode)
1150 postcodeWidget.input_was_selected= 1
1151 return True
1152
1153
1154
1156 """convenience method for common postcode to urb phrasewheel collaboration.
1157 there is no default args for these utility functions,
1158 This function is never called without both arguments, otherwise
1159 there is no intention (= modify the urb phrasewheel with postcode value).
1160 """
1161
1162
1163
1164 if pwheel is None:
1165 return False
1166 if postcode == '':
1167 pwheel.set_context("postcode", "%")
1168 return True
1169 urbs = getUrbsForPostcode(postcode)
1170 if urbs is None:
1171 return False
1172 if len(urbs) == 0:
1173 return True
1174 pwheel.SetValue(urbs[0])
1175 pwheel.input_was_selected = 1
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 pwheel.set_context("postcode", postcode)
1189 return True
1190
1191
1192