1
2 """GNUmed patient objects.
3
4 This is a patient object intended to let a useful client-side
5 API crystallize from actual use in true XP fashion.
6 """
7
8 __version__ = "$Revision: 1.198 $"
9 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
10 __license__ = "GPL"
11
12
13 import sys, os.path, time, re as regex, string, types, datetime as pyDT, codecs, threading, logging
14
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.pycommon import gmExceptions, gmDispatcher, gmBorg, gmI18N, gmNull, gmBusinessDBObject, gmTools
20 from Gnumed.pycommon import gmPG2, gmMatchProvider, gmDateTime
21 from Gnumed.pycommon import gmLog2
22 from Gnumed.pycommon import gmHooks
23
24 from Gnumed.business import gmDemographicRecord, gmProviderInbox, gmXdtMappings, gmClinicalRecord
25 from Gnumed.business.gmDocuments import cDocumentFolder
26
27
28 _log = logging.getLogger('gm.person')
29 _log.info(__version__)
30
31 __gender_list = None
32 __gender_idx = None
33
34 __gender2salutation_map = None
35
36
37
39
41 self.identity = None
42 self.external_ids = []
43 self.comm_channels = []
44 self.addresses = []
45
46
47
49 return 'firstnames lastnames dob gender'.split()
50
53
55 """Generate generic queries.
56
57 - not locale dependant
58 - data -> firstnames, lastnames, dob, gender
59
60 shall we mogrify name parts ? probably not as external
61 sources should know what they do
62
63 finds by inactive name, too, but then shows
64 the corresponding active name ;-)
65
66 Returns list of matching identities (may be empty)
67 or None if it was told to create an identity but couldn't.
68 """
69 where_snippets = []
70 args = {}
71
72 where_snippets.append(u'firstnames = %(first)s')
73 args['first'] = self.firstnames
74
75 where_snippets.append(u'lastnames = %(last)s')
76 args['last'] = self.lastnames
77
78 if self.dob is not None:
79 where_snippets.append(u"dem.date_trunc_utc('day'::text, dob) = dem.date_trunc_utc('day'::text, %(dob)s)")
80 args['dob'] = self.dob.replace(hour = 23, minute = 59, second = 59)
81
82 if self.gender is not None:
83 where_snippets.append('gender = %(sex)s')
84 args['sex'] = self.gender
85
86 cmd = u"""
87 SELECT *, '%s' AS match_type
88 FROM dem.v_basic_person
89 WHERE
90 pk_identity IN (
91 SELECT pk_identity FROM dem.v_person_names WHERE %s
92 )
93 ORDER BY lastnames, firstnames, dob""" % (
94 _('external patient source (name, gender, date of birth)'),
95 ' AND '.join(where_snippets)
96 )
97
98 try:
99 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx=True)
100 except:
101 _log.error(u'cannot get candidate identities for dto "%s"' % self)
102 _log.exception('query %s' % cmd)
103 rows = []
104
105 if len(rows) == 0:
106 _log.debug('no candidate identity matches found')
107 if not can_create:
108 return []
109 ident = self.import_into_database()
110 if ident is None:
111 return None
112 identities = [ident]
113 else:
114 identities = [ cIdentity(row = {'pk_field': 'pk_identity', 'data': row, 'idx': idx}) for row in rows ]
115
116 return identities
117
119 """Imports self into the database."""
120
121 self.identity = create_identity (
122 firstnames = self.firstnames,
123 lastnames = self.lastnames,
124 gender = self.gender,
125 dob = self.dob
126 )
127
128 if self.identity is None:
129 return None
130
131 for ext_id in self.external_ids:
132 try:
133 self.identity.add_external_id (
134 type_name = ext_id['name'],
135 value = ext_id['value'],
136 issuer = ext_id['issuer'],
137 comment = ext_id['comment']
138 )
139 except StandardError:
140 _log.exception('cannot import <external ID> from external data source')
141 _log.log_stack_trace()
142
143 for comm in self.comm_channels:
144 try:
145 self.identity.link_comm_channel (
146 comm_medium = comm['channel'],
147 url = comm['url']
148 )
149 except StandardError:
150 _log.exception('cannot import <comm channel> from external data source')
151 _log.log_stack_trace()
152
153 for adr in self.addresses:
154 try:
155 self.identity.link_address (
156 number = adr['number'],
157 street = adr['street'],
158 postcode = adr['zip'],
159 urb = adr['urb'],
160 state = adr['region'],
161 country = adr['country']
162 )
163 except StandardError:
164 _log.exception('cannot import <address> from external data source')
165 _log.log_stack_trace()
166
167 return self.identity
168
171
173 value = value.strip()
174 if value == u'':
175 return
176 name = name.strip()
177 if name == u'':
178 raise ValueError(_('<name> cannot be empty'))
179 issuer = issuer.strip()
180 if issuer == u'':
181 raise ValueError(_('<issuer> cannot be empty'))
182 self.external_ids.append({'name': name, 'value': value, 'issuer': issuer, 'comment': comment})
183
185 url = url.strip()
186 if url == u'':
187 return
188 channel = channel.strip()
189 if channel == u'':
190 raise ValueError(_('<channel> cannot be empty'))
191 self.comm_channels.append({'channel': channel, 'url': url})
192
193 - def remember_address(self, number=None, street=None, urb=None, region=None, zip=None, country=None):
194 number = number.strip()
195 if number == u'':
196 raise ValueError(_('<number> cannot be empty'))
197 street = street.strip()
198 if street == u'':
199 raise ValueError(_('<street> cannot be empty'))
200 urb = urb.strip()
201 if urb == u'':
202 raise ValueError(_('<urb> cannot be empty'))
203 zip = zip.strip()
204 if zip == u'':
205 raise ValueError(_('<zip> cannot be empty'))
206 country = country.strip()
207 if country == u'':
208 raise ValueError(_('<country> cannot be empty'))
209 region = region.strip()
210 if region == u'':
211 region = u'??'
212 self.addresses.append ({
213 u'number': number,
214 u'street': street,
215 u'zip': zip,
216 u'urb': urb,
217 u'region': region,
218 u'country': country
219 })
220
221
222
224 return u'<%s @ %s: %s %s (%s) %s>' % (
225 self.__class__.__name__,
226 id(self),
227 self.firstnames,
228 self.lastnames,
229 self.gender,
230 self.dob
231 )
232
234 """Do some sanity checks on self.* access."""
235
236 if attr == 'gender':
237 glist, idx = get_gender_list()
238 for gender in glist:
239 if str(val) in [gender[0], gender[1], gender[2], gender[3]]:
240 val = gender[idx['tag']]
241 object.__setattr__(self, attr, val)
242 return
243 raise ValueError('invalid gender: [%s]' % val)
244
245 if attr == 'dob':
246 if val is not None:
247 if not isinstance(val, pyDT.datetime):
248 raise TypeError('invalid type for DOB (must be datetime.datetime): %s [%s]' % (type(val), val))
249 if val.tzinfo is None:
250 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % val.isoformat())
251
252 object.__setattr__(self, attr, val)
253 return
254
256 return getattr(self, attr)
257
258 -class cPersonName(gmBusinessDBObject.cBusinessDBObject):
259 _cmd_fetch_payload = u"SELECT * FROM dem.v_person_names WHERE pk_name = %s"
260 _cmds_store_payload = [
261 u"""UPDATE dem.names SET
262 active = FALSE
263 WHERE
264 %(active_name)s IS TRUE -- act only when needed and only
265 AND
266 id_identity = %(pk_identity)s -- on names of this identity
267 AND
268 active IS TRUE -- which are active
269 AND
270 id != %(pk_name)s -- but NOT *this* name
271 """,
272 u"""update dem.names set
273 active = %(active_name)s,
274 preferred = %(preferred)s,
275 comment = %(comment)s
276 where
277 id = %(pk_name)s and
278 id_identity = %(pk_identity)s and -- belt and suspenders
279 xmin = %(xmin_name)s""",
280 u"""select xmin as xmin_name from dem.names where id = %(pk_name)s"""
281 ]
282 _updatable_fields = ['active_name', 'preferred', 'comment']
283
292
294 return '%(last)s, %(title)s %(first)s%(nick)s' % {
295 'last': self._payload[self._idx['lastnames']],
296 'title': gmTools.coalesce (
297 self._payload[self._idx['title']],
298 map_gender2salutation(self._payload[self._idx['gender']])
299 ),
300 'first': self._payload[self._idx['firstnames']],
301 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' "%s"', u'%s')
302 }
303
304 description = property(_get_description, lambda x:x)
305
306 -class cStaff(gmBusinessDBObject.cBusinessDBObject):
307 _cmd_fetch_payload = u"SELECT * FROM dem.v_staff WHERE pk_staff = %s"
308 _cmds_store_payload = [
309 u"""UPDATE dem.staff SET
310 fk_role = %(pk_role)s,
311 short_alias = %(short_alias)s,
312 comment = gm.nullify_empty_string(%(comment)s),
313 is_active = %(is_active)s,
314 db_user = %(db_user)s
315 WHERE
316 pk = %(pk_staff)s
317 AND
318 xmin = %(xmin_staff)s
319 RETURNING
320 xmin AS xmin_staff"""
321 ]
322 _updatable_fields = ['pk_role', 'short_alias', 'comment', 'is_active', 'db_user']
323
324 - def __init__(self, aPK_obj=None, row=None):
325
326 if (aPK_obj is None) and (row is None):
327 cmd = u"select * from dem.v_staff where db_user = CURRENT_USER"
328 try:
329 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
330 except:
331 _log.exception('cannot instantiate staff instance')
332 gmLog2.log_stack_trace()
333 raise ValueError('cannot instantiate staff instance for database account CURRENT_USER')
334 if len(rows) == 0:
335 raise ValueError('no staff record for database account CURRENT_USER')
336 row = {
337 'pk_field': 'pk_staff',
338 'idx': idx,
339 'data': rows[0]
340 }
341 gmBusinessDBObject.cBusinessDBObject.__init__(self, row = row)
342 else:
343 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj = aPK_obj, row = row)
344
345
346 self.__is_current_user = (gmPG2.get_current_user() == self._payload[self._idx['db_user']])
347
348 self.__inbox = None
349
356
358 rows, idx = gmPG2.run_ro_queries (
359 queries = [{
360 'cmd': u'select i18n.get_curr_lang(%(usr)s)',
361 'args': {'usr': self._payload[self._idx['db_user']]}
362 }]
363 )
364 return rows[0][0]
365
367 if not gmPG2.set_user_language(language = language):
368 raise ValueError (
369 u'Cannot set database language to [%s] for user [%s].' % (language, self._payload[self._idx['db_user']])
370 )
371 return
372
373 database_language = property(_get_db_lang, _set_db_lang)
374
376 if self.__inbox is None:
377 self.__inbox = gmProviderInbox.cProviderInbox(provider_id = self._payload[self._idx['pk_staff']])
378 return self.__inbox
379
382
383 inbox = property(_get_inbox, _set_inbox)
384
387
389 """Staff member Borg to hold currently logged on provider.
390
391 There may be many instances of this but they all share state.
392 """
394 """Change or get currently logged on provider.
395
396 provider:
397 * None: get copy of current instance
398 * cStaff instance: change logged on provider (role)
399 """
400
401 try:
402 self.provider
403 except AttributeError:
404 self.provider = gmNull.cNull()
405
406
407 if provider is None:
408 return None
409
410
411 if not isinstance(provider, cStaff):
412 raise ValueError, 'cannot set logged on provider to [%s], must be either None or cStaff instance' % str(provider)
413
414
415 if self.provider['pk_staff'] == provider['pk_staff']:
416 return None
417
418
419 if isinstance(self.provider, gmNull.cNull):
420 self.provider = provider
421 return None
422
423
424 raise ValueError, 'provider change [%s] -> [%s] not yet supported' % (self.provider['pk_staff'], provider['pk_staff'])
425
426
429
430
431
433 """Return any attribute if known how to retrieve it by proxy.
434 """
435 return self.provider[aVar]
436
437
438
440 if attribute == 'provider':
441 raise AttributeError
442 if not isinstance(self.provider, gmNull.cNull):
443 return getattr(self.provider, attribute)
444
445
446 -class cIdentity(gmBusinessDBObject.cBusinessDBObject):
447 _cmd_fetch_payload = u"SELECT * FROM dem.v_basic_person WHERE pk_identity = %s"
448 _cmds_store_payload = [
449 u"""UPDATE dem.identity SET
450 gender = %(gender)s,
451 dob = %(dob)s,
452 tob = %(tob)s,
453 cob = gm.nullify_empty_string(%(cob)s),
454 title = gm.nullify_empty_string(%(title)s),
455 fk_marital_status = %(pk_marital_status)s,
456 karyotype = gm.nullify_empty_string(%(karyotype)s),
457 pupic = gm.nullify_empty_string(%(pupic)s),
458 deceased = %(deceased)s,
459 emergency_contact = gm.nullify_empty_string(%(emergency_contact)s),
460 fk_emergency_contact = %(pk_emergency_contact)s,
461 fk_primary_provider = %(pk_primary_provider)s,
462 comment = gm.nullify_empty_string(%(comment)s)
463 WHERE
464 pk = %(pk_identity)s and
465 xmin = %(xmin_identity)s
466 RETURNING
467 xmin AS xmin_identity"""
468 ]
469 _updatable_fields = [
470 "title",
471 "dob",
472 "tob",
473 "cob",
474 "gender",
475 "pk_marital_status",
476 "karyotype",
477 "pupic",
478 'deceased',
479 'emergency_contact',
480 'pk_emergency_contact',
481 'pk_primary_provider',
482 'comment'
483 ]
484
486 return self._payload[self._idx['pk_identity']]
488 raise AttributeError('setting ID of identity is not allowed')
489 ID = property(_get_ID, _set_ID)
490
492
493 if attribute == 'dob':
494 if value is not None:
495
496 if isinstance(value, pyDT.datetime):
497 if value.tzinfo is None:
498 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % dt.isoformat())
499 else:
500 raise TypeError, '[%s]: type [%s] (%s) invalid for attribute [dob], must be datetime.datetime or None' % (self.__class__.__name__, type(value), value)
501
502
503 if self._payload[self._idx['dob']] is not None:
504 old_dob = gmDateTime.pydt_strftime (
505 self._payload[self._idx['dob']],
506 format = '%Y %m %d %H %M %S',
507 accuracy = gmDateTime.acc_seconds
508 )
509 new_dob = gmDateTime.pydt_strftime (
510 value,
511 format = '%Y %m %d %H %M %S',
512 accuracy = gmDateTime.acc_seconds
513 )
514 if new_dob == old_dob:
515 return
516
517 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
518
521
523 cmd = u"""
524 SELECT EXISTS (
525 SELECT 1
526 FROM clin.v_emr_journal
527 WHERE
528 pk_patient = %(pat)s
529 AND
530 soap_cat IS NOT NULL
531 )"""
532 args = {'pat': self._payload[self._idx['pk_identity']]}
533 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
534 return rows[0][0]
535
537 raise AttributeError('setting is_patient status of identity is not allowed')
538
539 is_patient = property(_get_is_patient, _set_is_patient)
540
542 cmd = u"SELECT pk FROM dem.staff WHERE fk_identity = %(pk)s"
543 args = {'pk': self._payload[self._idx['pk_identity']]}
544 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
545 if len(rows) == 0:
546 return None
547 return rows[0][0]
548
549 staff_id = property(_get_staff_id, lambda x:x)
550
551
552
554 for name in self.get_names():
555 if name['active_name'] is True:
556 return name
557
558 _log.error('cannot retrieve active name for patient [%s]' % self._payload[self._idx['pk_identity']])
559 return None
560
562 cmd = u"select * from dem.v_person_names where pk_identity = %(pk_pat)s"
563 rows, idx = gmPG2.run_ro_queries (
564 queries = [{
565 'cmd': cmd,
566 'args': {'pk_pat': self._payload[self._idx['pk_identity']]}
567 }],
568 get_col_idx = True
569 )
570
571 if len(rows) == 0:
572
573 return []
574
575 names = [ cPersonName(row = {'idx': idx, 'data': r, 'pk_field': 'pk_name'}) for r in rows ]
576 return names
577
585
587 return '%(sex)s%(title)s %(last)s, %(first)s%(nick)s' % {
588 'last': self._payload[self._idx['lastnames']],
589 'first': self._payload[self._idx['firstnames']],
590 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s'),
591 'sex': map_gender2salutation(self._payload[self._idx['gender']]),
592 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s')
593 }
594
596 return '%(last)s,%(title)s %(first)s%(nick)s' % {
597 'last': self._payload[self._idx['lastnames']],
598 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s'),
599 'first': self._payload[self._idx['firstnames']],
600 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s')
601 }
602
603 - def add_name(self, firstnames, lastnames, active=True):
604 """Add a name.
605
606 @param firstnames The first names.
607 @param lastnames The last names.
608 @param active When True, the new name will become the active one (hence setting other names to inactive)
609 @type active A types.BooleanType instance
610 """
611 name = create_name(self.ID, firstnames, lastnames, active)
612 if active:
613 self.refetch_payload()
614 return name
615
617 cmd = u"delete from dem.names where id = %(name)s and id_identity = %(pat)s"
618 args = {'name': name['pk_name'], 'pat': self.ID}
619 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
620
621
622
623
625 """
626 Set the nickname. Setting the nickname only makes sense for the currently
627 active name.
628 @param nickname The preferred/nick/warrior name to set.
629 """
630 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': u"select dem.set_nickname(%s, %s)", 'args': [self.ID, nickname]}])
631 self.refetch_payload()
632 return True
633
644
646 args = {
647 u'tag': tag,
648 u'identity': self.ID
649 }
650
651
652 cmd = u"SELECT pk FROM dem.identity_tag WHERE fk_tag = %(tag)s AND fk_identity = %(identity)s"
653 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
654 if len(rows) > 0:
655 return gmDemographicRecord.cIdentityTag(aPK_obj = rows[0]['pk'])
656
657
658 cmd = u"""
659 INSERT INTO dem.identity_tag (
660 fk_tag,
661 fk_identity
662 ) VALUES (
663 %(tag)s,
664 %(identity)s
665 )
666 RETURNING pk
667 """
668 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
669 return gmDemographicRecord.cIdentityTag(aPK_obj = rows[0]['pk'])
670
672 cmd = u"DELETE FROM dem.identity_tag WHERE pk = %(pk)s"
673 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': tag}}])
674
675
676
677
678
679
680
681
682
683
684 - def add_external_id(self, type_name=None, value=None, issuer=None, comment=None, pk_type=None):
685 """Adds an external ID to the patient.
686
687 creates ID type if necessary
688 """
689
690
691 if pk_type is not None:
692 cmd = u"""
693 select * from dem.v_external_ids4identity where
694 pk_identity = %(pat)s and
695 pk_type = %(pk_type)s and
696 value = %(val)s"""
697 else:
698
699 if issuer is None:
700 cmd = u"""
701 select * from dem.v_external_ids4identity where
702 pk_identity = %(pat)s and
703 name = %(name)s and
704 value = %(val)s"""
705 else:
706 cmd = u"""
707 select * from dem.v_external_ids4identity where
708 pk_identity = %(pat)s and
709 name = %(name)s and
710 value = %(val)s and
711 issuer = %(issuer)s"""
712 args = {
713 'pat': self.ID,
714 'name': type_name,
715 'val': value,
716 'issuer': issuer,
717 'pk_type': pk_type
718 }
719 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
720
721
722 if len(rows) == 0:
723
724 args = {
725 'pat': self.ID,
726 'val': value,
727 'type_name': type_name,
728 'pk_type': pk_type,
729 'issuer': issuer,
730 'comment': comment
731 }
732
733 if pk_type is None:
734 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values (
735 %(val)s,
736 (select dem.add_external_id_type(%(type_name)s, %(issuer)s)),
737 %(comment)s,
738 %(pat)s
739 )"""
740 else:
741 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values (
742 %(val)s,
743 %(pk_type)s,
744 %(comment)s,
745 %(pat)s
746 )"""
747
748 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
749
750
751 else:
752 row = rows[0]
753 if comment is not None:
754
755 if gmTools.coalesce(row['comment'], '').find(comment.strip()) == -1:
756 comment = '%s%s' % (gmTools.coalesce(row['comment'], '', '%s // '), comment.strip)
757 cmd = u"update dem.lnk_identity2ext_id set comment = %(comment)s where id=%(pk)s"
758 args = {'comment': comment, 'pk': row['pk_id']}
759 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
760
761 - def update_external_id(self, pk_id=None, type=None, value=None, issuer=None, comment=None):
762 """Edits an existing external ID.
763
764 creates ID type if necessary
765 """
766 cmd = u"""
767 update dem.lnk_identity2ext_id set
768 fk_origin = (select dem.add_external_id_type(%(type)s, %(issuer)s)),
769 external_id = %(value)s,
770 comment = %(comment)s
771 where id = %(pk)s"""
772 args = {'pk': pk_id, 'value': value, 'type': type, 'issuer': issuer, 'comment': comment}
773 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
774
776 where_parts = ['pk_identity = %(pat)s']
777 args = {'pat': self.ID}
778
779 if id_type is not None:
780 where_parts.append(u'name = %(name)s')
781 args['name'] = id_type.strip()
782
783 if issuer is not None:
784 where_parts.append(u'issuer = %(issuer)s')
785 args['issuer'] = issuer.strip()
786
787 cmd = u"select * from dem.v_external_ids4identity where %s" % ' and '.join(where_parts)
788 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
789
790 return rows
791
793 cmd = u"""
794 delete from dem.lnk_identity2ext_id
795 where id_identity = %(pat)s and id = %(pk)s"""
796 args = {'pat': self.ID, 'pk': pk_ext_id}
797 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
798
800 """Merge another identity into this one.
801
802 Keep this one. Delete other one."""
803
804 if other_identity.ID == self.ID:
805 return True, None
806
807 curr_pat = gmCurrentPatient()
808 if curr_pat.connected:
809 if other_identity.ID == curr_pat.ID:
810 return False, _('Cannot merge active patient into another patient.')
811
812 queries = []
813 args = {'old_pat': other_identity.ID, 'new_pat': self.ID}
814
815
816 queries.append ({
817 'cmd': u'delete from clin.allergy_state where pk = (select pk_allergy_state from clin.v_pat_allergy_state where pk_patient = %(old_pat)s)',
818 'args': args
819 })
820
821
822
823 queries.append ({
824 'cmd': u'update dem.names set active = False where id_identity = %(old_pat)s',
825 'args': args
826 })
827
828
829 FKs = gmPG2.get_foreign_keys2column (
830 schema = u'dem',
831 table = u'identity',
832 column = u'pk'
833 )
834
835
836 cmd_template = u'update %s set %s = %%(new_pat)s where %s = %%(old_pat)s'
837 for FK in FKs:
838 queries.append ({
839 'cmd': cmd_template % (FK['referencing_table'], FK['referencing_column'], FK['referencing_column']),
840 'args': args
841 })
842
843
844 queries.append ({
845 'cmd': u'delete from dem.identity where pk = %(old_pat)s',
846 'args': args
847 })
848
849 _log.warning('identity [%s] is about to assimilate identity [%s]', self.ID, other_identity.ID)
850
851 gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, end_tx = True)
852
853 self.add_external_id (
854 type_name = u'merged GNUmed identity primary key',
855 value = u'GNUmed::pk::%s' % other_identity.ID,
856 issuer = u'GNUmed'
857 )
858
859 return True, None
860
861
863 cmd = u"""
864 insert into clin.waiting_list (fk_patient, urgency, comment, area, list_position)
865 values (
866 %(pat)s,
867 %(urg)s,
868 %(cmt)s,
869 %(area)s,
870 (select coalesce((max(list_position) + 1), 1) from clin.waiting_list)
871 )"""
872 args = {'pat': self.ID, 'urg': urgency, 'cmt': comment, 'area': zone}
873 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], verbose=True)
874
875 - def export_as_gdt(self, filename=None, encoding='iso-8859-15', external_id_type=None):
876
877 template = u'%s%s%s\r\n'
878
879 file = codecs.open (
880 filename = filename,
881 mode = 'wb',
882 encoding = encoding,
883 errors = 'strict'
884 )
885
886 file.write(template % (u'013', u'8000', u'6301'))
887 file.write(template % (u'013', u'9218', u'2.10'))
888 if external_id_type is None:
889 file.write(template % (u'%03d' % (9 + len(str(self.ID))), u'3000', self.ID))
890 else:
891 ext_ids = self.get_external_ids(id_type = external_id_type)
892 if len(ext_ids) > 0:
893 file.write(template % (u'%03d' % (9 + len(ext_ids[0]['value'])), u'3000', ext_ids[0]['value']))
894 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['lastnames']])), u'3101', self._payload[self._idx['lastnames']]))
895 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['firstnames']])), u'3102', self._payload[self._idx['firstnames']]))
896 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['dob']].strftime('%d%m%Y'))), u'3103', self._payload[self._idx['dob']].strftime('%d%m%Y')))
897 file.write(template % (u'010', u'3110', gmXdtMappings.map_gender_gm2xdt[self._payload[self._idx['gender']]]))
898 file.write(template % (u'025', u'6330', 'GNUmed::9206::encoding'))
899 file.write(template % (u'%03d' % (9 + len(encoding)), u'6331', encoding))
900 if external_id_type is None:
901 file.write(template % (u'029', u'6332', u'GNUmed::3000::source'))
902 file.write(template % (u'017', u'6333', u'internal'))
903 else:
904 if len(ext_ids) > 0:
905 file.write(template % (u'029', u'6332', u'GNUmed::3000::source'))
906 file.write(template % (u'%03d' % (9 + len(external_id_type)), u'6333', external_id_type))
907
908 file.close()
909
910
911
913 cmd = u"select * from dem.v_person_jobs where pk_identity=%s"
914 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
915 return rows
916
918 """Link an occupation with a patient, creating the occupation if it does not exists.
919
920 @param occupation The name of the occupation to link the patient to.
921 """
922 if (activities is None) and (occupation is None):
923 return True
924
925 occupation = occupation.strip()
926 if len(occupation) == 0:
927 return True
928
929 if activities is not None:
930 activities = activities.strip()
931
932 args = {'act': activities, 'pat_id': self.pk_obj, 'job': occupation}
933
934 cmd = u"select activities from dem.v_person_jobs where pk_identity = %(pat_id)s and l10n_occupation = _(%(job)s)"
935 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
936
937 queries = []
938 if len(rows) == 0:
939 queries.append ({
940 'cmd': u"INSERT INTO dem.lnk_job2person (fk_identity, fk_occupation, activities) VALUES (%(pat_id)s, dem.create_occupation(%(job)s), %(act)s)",
941 'args': args
942 })
943 else:
944 if rows[0]['activities'] != activities:
945 queries.append ({
946 'cmd': u"update dem.lnk_job2person set activities=%(act)s where fk_identity=%(pat_id)s and fk_occupation=(select id from dem.occupation where _(name) = _(%(job)s))",
947 'args': args
948 })
949
950 rows, idx = gmPG2.run_rw_queries(queries = queries)
951
952 return True
953
955 if occupation is None:
956 return True
957 occupation = occupation.strip()
958 cmd = u"delete from dem.lnk_job2person where fk_identity=%(pk)s and fk_occupation in (select id from dem.occupation where _(name) = _(%(job)s))"
959 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj, 'job': occupation}}])
960 return True
961
962
963
965 cmd = u"select * from dem.v_person_comms where pk_identity = %s"
966 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx = True)
967
968 filtered = rows
969
970 if comm_medium is not None:
971 filtered = []
972 for row in rows:
973 if row['comm_type'] == comm_medium:
974 filtered.append(row)
975
976 return [ gmDemographicRecord.cCommChannel(row = {
977 'pk_field': 'pk_lnk_identity2comm',
978 'data': r,
979 'idx': idx
980 }) for r in filtered
981 ]
982
983 - def link_comm_channel(self, comm_medium=None, url=None, is_confidential=False, pk_channel_type=None):
984 """Link a communication medium with a patient.
985
986 @param comm_medium The name of the communication medium.
987 @param url The communication resource locator.
988 @type url A types.StringType instance.
989 @param is_confidential Wether the data must be treated as confidential.
990 @type is_confidential A types.BooleanType instance.
991 """
992 comm_channel = gmDemographicRecord.create_comm_channel (
993 comm_medium = comm_medium,
994 url = url,
995 is_confidential = is_confidential,
996 pk_channel_type = pk_channel_type,
997 pk_identity = self.pk_obj
998 )
999 return comm_channel
1000
1006
1007
1008
1010 cmd = u"select * from dem.v_pat_addresses where pk_identity=%s"
1011 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx=True)
1012 addresses = []
1013 for r in rows:
1014 addresses.append(gmDemographicRecord.cPatientAddress(row={'idx': idx, 'data': r, 'pk_field': 'pk_address'}))
1015
1016 filtered = addresses
1017
1018 if address_type is not None:
1019 filtered = []
1020 for adr in addresses:
1021 if adr['address_type'] == address_type:
1022 filtered.append(adr)
1023
1024 return filtered
1025
1026 - def link_address(self, number=None, street=None, postcode=None, urb=None, state=None, country=None, subunit=None, suburb=None, id_type=None):
1027 """Link an address with a patient, creating the address if it does not exists.
1028
1029 @param number The number of the address.
1030 @param street The name of the street.
1031 @param postcode The postal code of the address.
1032 @param urb The name of town/city/etc.
1033 @param state The code of the state.
1034 @param country The code of the country.
1035 @param id_type The primary key of the address type.
1036 """
1037
1038 adr = gmDemographicRecord.create_address (
1039 country = country,
1040 state = state,
1041 urb = urb,
1042 suburb = suburb,
1043 postcode = postcode,
1044 street = street,
1045 number = number,
1046 subunit = subunit
1047 )
1048
1049
1050 cmd = u"select * from dem.lnk_person_org_address where id_identity = %s and id_address = %s"
1051 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj, adr['pk_address']]}])
1052
1053 if len(rows) == 0:
1054 args = {'id': self.pk_obj, 'adr': adr['pk_address'], 'type': id_type}
1055 if id_type is None:
1056 cmd = u"""
1057 insert into dem.lnk_person_org_address(id_identity, id_address)
1058 values (%(id)s, %(adr)s)"""
1059 else:
1060 cmd = u"""
1061 insert into dem.lnk_person_org_address(id_identity, id_address, id_type)
1062 values (%(id)s, %(adr)s, %(type)s)"""
1063 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1064 else:
1065
1066 if id_type is not None:
1067 r = rows[0]
1068 if r['id_type'] != id_type:
1069 cmd = "update dem.lnk_person_org_address set id_type = %(type)s where id = %(id)s"
1070 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'type': id_type, 'id': r['id']}}])
1071
1072 return adr
1073
1075 """Remove an address from the patient.
1076
1077 The address itself stays in the database.
1078 The address can be either cAdress or cPatientAdress.
1079 """
1080 cmd = u"delete from dem.lnk_person_org_address where id_identity = %(person)s and id_address = %(adr)s"
1081 args = {'person': self.pk_obj, 'adr': address['pk_address']}
1082 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
1083
1084
1085
1087 cmd = u"""
1088 select
1089 t.description,
1090 vbp.pk_identity as id,
1091 title,
1092 firstnames,
1093 lastnames,
1094 dob,
1095 cob,
1096 gender,
1097 karyotype,
1098 pupic,
1099 pk_marital_status,
1100 marital_status,
1101 xmin_identity,
1102 preferred
1103 from
1104 dem.v_basic_person vbp, dem.relation_types t, dem.lnk_person2relative l
1105 where
1106 (
1107 l.id_identity = %(pk)s and
1108 vbp.pk_identity = l.id_relative and
1109 t.id = l.id_relation_type
1110 ) or (
1111 l.id_relative = %(pk)s and
1112 vbp.pk_identity = l.id_identity and
1113 t.inverse = l.id_relation_type
1114 )"""
1115 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
1116 if len(rows) == 0:
1117 return []
1118 return [(row[0], cIdentity(row = {'data': row[1:], 'idx':idx, 'pk_field': 'pk'})) for row in rows]
1119
1121
1122 id_new_relative = create_dummy_identity()
1123
1124 relative = cIdentity(aPK_obj=id_new_relative)
1125
1126
1127 relative.add_name( '**?**', self.get_names()['lastnames'])
1128
1129 if self._ext_cache.has_key('relatives'):
1130 del self._ext_cache['relatives']
1131 cmd = u"""
1132 insert into dem.lnk_person2relative (
1133 id_identity, id_relative, id_relation_type
1134 ) values (
1135 %s, %s, (select id from dem.relation_types where description = %s)
1136 )"""
1137 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [self.ID, id_new_relative, rel_type ]}])
1138 return True
1139
1141
1142 self.set_relative(None, relation)
1143
1148
1149 emergency_contact_in_database = property(_get_emergency_contact_from_database, lambda x:x)
1150
1151
1152
1173
1174 - def dob_in_range(self, min_distance=u'1 week', max_distance=u'1 week'):
1175 cmd = u'select dem.dob_is_in_range(%(dob)s, %(min)s, %(max)s)'
1176 rows, idx = gmPG2.run_ro_queries (
1177 queries = [{
1178 'cmd': cmd,
1179 'args': {'dob': self['dob'], 'min': min_distance, 'max': max_distance}
1180 }]
1181 )
1182 return rows[0][0]
1183
1184
1185
1187 cmd = u'select * from clin.v_most_recent_encounters where pk_patient=%s'
1188 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self._payload[self._idx['pk_identity']]]}])
1189 if len(rows) > 0:
1190 return rows[0]
1191 else:
1192 return None
1193
1196
1199
1200 messages = property(_get_messages, _set_messages)
1201
1204
1206 if self._payload[self._idx['pk_primary_provider']] is None:
1207 return None
1208 return cStaff(aPK_obj = self._payload[self._idx['pk_primary_provider']])
1209
1210 primary_provider = property(_get_primary_provider, lambda x:x)
1211
1212
1213
1215 """Format patient demographics into patient specific path name fragment."""
1216 return '%s-%s%s-%s' % (
1217 self._payload[self._idx['lastnames']].replace(u' ', u'_'),
1218 self._payload[self._idx['firstnames']].replace(u' ', u'_'),
1219 gmTools.coalesce(self._payload[self._idx['preferred']], u'', template_initial = u'-(%s)'),
1220 self.get_formatted_dob(format = '%Y-%m-%d', encoding = gmI18N.get_encoding())
1221 )
1222
1224 """Represents a staff member which is a person.
1225
1226 - a specializing subclass of cIdentity turning it into a staff member
1227 """
1231
1234
1236 """Represents a person which is a patient.
1237
1238 - a specializing subclass of cIdentity turning it into a patient
1239 - its use is to cache subobjects like EMR and document folder
1240 """
1241 - def __init__(self, aPK_obj=None, row=None):
1242 cIdentity.__init__(self, aPK_obj=aPK_obj, row=row)
1243 self.__db_cache = {}
1244 self.__emr_access_lock = threading.Lock()
1245
1247 """Do cleanups before dying.
1248
1249 - note that this may be called in a thread
1250 """
1251 if self.__db_cache.has_key('clinical record'):
1252 self.__db_cache['clinical record'].cleanup()
1253 if self.__db_cache.has_key('document folder'):
1254 self.__db_cache['document folder'].cleanup()
1255 cIdentity.cleanup(self)
1256
1258 if not self.__emr_access_lock.acquire(False):
1259 raise AttributeError('cannot access EMR')
1260 try:
1261 emr = self.__db_cache['clinical record']
1262 self.__emr_access_lock.release()
1263 return emr
1264 except KeyError:
1265 pass
1266
1267 self.__db_cache['clinical record'] = gmClinicalRecord.cClinicalRecord(aPKey = self._payload[self._idx['pk_identity']])
1268 self.__emr_access_lock.release()
1269 return self.__db_cache['clinical record']
1270
1272 try:
1273 return self.__db_cache['document folder']
1274 except KeyError:
1275 pass
1276
1277 self.__db_cache['document folder'] = cDocumentFolder(aPKey = self._payload[self._idx['pk_identity']])
1278 return self.__db_cache['document folder']
1279
1281 """Patient Borg to hold currently active patient.
1282
1283 There may be many instances of this but they all share state.
1284 """
1285 - def __init__(self, patient=None, forced_reload=False):
1286 """Change or get currently active patient.
1287
1288 patient:
1289 * None: get currently active patient
1290 * -1: unset currently active patient
1291 * cPatient instance: set active patient if possible
1292 """
1293
1294 try:
1295 tmp = self.patient
1296 except AttributeError:
1297 self.patient = gmNull.cNull()
1298 self.__register_interests()
1299
1300
1301
1302 self.__lock_depth = 0
1303
1304 self.__pre_selection_callbacks = []
1305
1306
1307 if patient is None:
1308 return None
1309
1310
1311 if self.locked:
1312 _log.error('patient [%s] is locked, cannot change to [%s]' % (self.patient['pk_identity'], patient))
1313 return None
1314
1315
1316 if patient == -1:
1317 _log.debug('explicitly unsetting current patient')
1318 if not self.__run_pre_selection_callbacks():
1319 _log.debug('not unsetting current patient')
1320 return None
1321 self.__send_pre_selection_notification()
1322 self.patient.cleanup()
1323 self.patient = gmNull.cNull()
1324 self.__send_selection_notification()
1325 return None
1326
1327
1328 if not isinstance(patient, cPatient):
1329 _log.error('cannot set active patient to [%s], must be either None, -1 or cPatient instance' % str(patient))
1330 raise TypeError, 'gmPerson.gmCurrentPatient.__init__(): <patient> must be None, -1 or cPatient instance but is: %s' % str(patient)
1331
1332
1333 if (self.patient['pk_identity'] == patient['pk_identity']) and not forced_reload:
1334 return None
1335
1336
1337 _log.debug('patient change [%s] -> [%s] requested', self.patient['pk_identity'], patient['pk_identity'])
1338
1339
1340 if not self.__run_pre_selection_callbacks():
1341 _log.debug('not changing current patient')
1342 return None
1343 self.__send_pre_selection_notification()
1344 self.patient.cleanup()
1345 self.patient = patient
1346 self.patient.get_emr()
1347 self.__send_selection_notification()
1348
1349 return None
1350
1354
1358
1359
1360
1362 if not callable(callback):
1363 raise TypeError(u'callback [%s] not callable' % callback)
1364
1365 self.__pre_selection_callbacks.append(callback)
1366
1369
1371 raise AttributeError(u'invalid to set <connected> state')
1372
1373 connected = property(_get_connected, _set_connected)
1374
1376 return (self.__lock_depth > 0)
1377
1379 if locked:
1380 self.__lock_depth = self.__lock_depth + 1
1381 gmDispatcher.send(signal='patient_locked')
1382 else:
1383 if self.__lock_depth == 0:
1384 _log.error('lock/unlock imbalance, trying to refcount lock depth below 0')
1385 return
1386 else:
1387 self.__lock_depth = self.__lock_depth - 1
1388 gmDispatcher.send(signal='patient_unlocked')
1389
1390 locked = property(_get_locked, _set_locked)
1391
1393 _log.info('forced patient unlock at lock depth [%s]' % self.__lock_depth)
1394 self.__lock_depth = 0
1395 gmDispatcher.send(signal='patient_unlocked')
1396
1397
1398
1400 if isinstance(self.patient, gmNull.cNull):
1401 return True
1402
1403 for call_back in self.__pre_selection_callbacks:
1404 try:
1405 successful = call_back()
1406 except:
1407 _log.exception('callback [%s] failed', call_back)
1408 print "*** pre-selection callback failed ***"
1409 print type(call_back)
1410 print call_back
1411 return False
1412
1413 if not successful:
1414 _log.debug('callback [%s] returned False', call_back)
1415 return False
1416
1417 return True
1418
1420 """Sends signal when another patient is about to become active.
1421
1422 This does NOT wait for signal handlers to complete.
1423 """
1424 kwargs = {
1425 'signal': u'pre_patient_selection',
1426 'sender': id(self.__class__),
1427 'pk_identity': self.patient['pk_identity']
1428 }
1429 gmDispatcher.send(**kwargs)
1430
1432 """Sends signal when another patient has actually been made active."""
1433 kwargs = {
1434 'signal': u'post_patient_selection',
1435 'sender': id(self.__class__),
1436 'pk_identity': self.patient['pk_identity']
1437 }
1438 gmDispatcher.send(**kwargs)
1439
1440
1441
1443 if attribute == 'patient':
1444 raise AttributeError
1445 if not isinstance(self.patient, gmNull.cNull):
1446 return getattr(self.patient, attribute)
1447
1448
1449
1451 """Return any attribute if known how to retrieve it by proxy.
1452 """
1453 return self.patient[attribute]
1454
1457
1458
1459
1462 gmMatchProvider.cMatchProvider_SQL2.__init__(
1463 self,
1464 queries = [
1465 u"""SELECT
1466 pk_staff AS data,
1467 short_alias || ' (' || coalesce(title, '') || firstnames || ' ' || lastnames || ')' AS list_label,
1468 short_alias || ' (' || coalesce(title, '') || firstnames || ' ' || lastnames || ')' AS field_label
1469 FROM dem.v_staff
1470 WHERE
1471 is_active AND (
1472 short_alias %(fragment_condition)s OR
1473 firstnames %(fragment_condition)s OR
1474 lastnames %(fragment_condition)s OR
1475 db_user %(fragment_condition)s
1476 )
1477 """
1478 ]
1479 )
1480 self.setThresholds(1, 2, 3)
1481
1482
1483
1484 -def create_name(pk_person, firstnames, lastnames, active=False):
1485 queries = [{
1486 'cmd': u"select dem.add_name(%s, %s, %s, %s)",
1487 'args': [pk_person, firstnames, lastnames, active]
1488 }]
1489 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True)
1490 name = cPersonName(aPK_obj = rows[0][0])
1491 return name
1492
1493 -def create_identity(gender=None, dob=None, lastnames=None, firstnames=None):
1494
1495 cmd1 = u"""INSERT INTO dem.identity (gender, dob) VALUES (%s, %s)"""
1496 cmd2 = u"""
1497 INSERT INTO dem.names (
1498 id_identity, lastnames, firstnames
1499 ) VALUES (
1500 currval('dem.identity_pk_seq'), coalesce(%s, 'xxxDEFAULTxxx'), coalesce(%s, 'xxxDEFAULTxxx')
1501 ) RETURNING id_identity"""
1502 rows, idx = gmPG2.run_rw_queries (
1503 queries = [
1504 {'cmd': cmd1, 'args': [gender, dob]},
1505 {'cmd': cmd2, 'args': [lastnames, firstnames]}
1506 ],
1507 return_data = True
1508 )
1509 ident = cIdentity(aPK_obj=rows[0][0])
1510 gmHooks.run_hook_script(hook = u'post_person_creation')
1511 return ident
1512
1520
1547
1548
1549
1560
1561 map_gender2mf = {
1562 'm': u'm',
1563 'f': u'f',
1564 'tf': u'f',
1565 'tm': u'm',
1566 'h': u'mf'
1567 }
1568
1569
1570 map_gender2symbol = {
1571 'm': u'\u2642',
1572 'f': u'\u2640',
1573 'tf': u'\u26A5\u2640',
1574 'tm': u'\u26A5\u2642',
1575 'h': u'\u26A5'
1576
1577
1578
1579 }
1580
1601
1603 """Try getting the gender for the given first name."""
1604
1605 if firstnames is None:
1606 return None
1607
1608 rows, idx = gmPG2.run_ro_queries(queries = [{
1609 'cmd': u"select gender from dem.name_gender_map where name ilike %(fn)s limit 1",
1610 'args': {'fn': firstnames}
1611 }])
1612
1613 if len(rows) == 0:
1614 return None
1615
1616 return rows[0][0]
1617
1619 if active_only:
1620 cmd = u"SELECT * FROM dem.v_staff WHERE is_active ORDER BY can_login DESC, short_alias ASC"
1621 else:
1622 cmd = u"SELECT * FROM dem.v_staff ORDER BY can_login desc, is_active desc, short_alias ASC"
1623 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
1624 staff_list = []
1625 for row in rows:
1626 obj_row = {
1627 'idx': idx,
1628 'data': row,
1629 'pk_field': 'pk_staff'
1630 }
1631 staff_list.append(cStaff(row=obj_row))
1632 return staff_list
1633
1635 return [ cIdentity(aPK_obj = pk) for pk in pks ]
1636
1640
1644
1645
1646
1647 if __name__ == '__main__':
1648
1649 if len(sys.argv) == 1:
1650 sys.exit()
1651
1652 if sys.argv[1] != 'test':
1653 sys.exit()
1654
1655 import datetime
1656
1657 gmI18N.activate_locale()
1658 gmI18N.install_domain()
1659 gmDateTime.init()
1660
1661
1682
1684 dto = cDTO_person()
1685 dto.firstnames = 'Sepp'
1686 dto.lastnames = 'Herberger'
1687 dto.gender = 'male'
1688 dto.dob = pyDT.datetime.now(tz=gmDateTime.gmCurrentLocalTimezone)
1689 print dto
1690
1691 print dto['firstnames']
1692 print dto['lastnames']
1693 print dto['gender']
1694 print dto['dob']
1695
1696 for key in dto.keys():
1697 print key
1698
1704
1717
1719
1720 print '\n\nCreating identity...'
1721 new_identity = create_identity(gender='m', dob='2005-01-01', lastnames='test lastnames', firstnames='test firstnames')
1722 print 'Identity created: %s' % new_identity
1723
1724 print '\nSetting title and gender...'
1725 new_identity['title'] = 'test title';
1726 new_identity['gender'] = 'f';
1727 new_identity.save_payload()
1728 print 'Refetching identity from db: %s' % cIdentity(aPK_obj=new_identity['pk_identity'])
1729
1730 print '\nGetting all names...'
1731 for a_name in new_identity.get_names():
1732 print a_name
1733 print 'Active name: %s' % (new_identity.get_active_name())
1734 print 'Setting nickname...'
1735 new_identity.set_nickname(nickname='test nickname')
1736 print 'Refetching all names...'
1737 for a_name in new_identity.get_names():
1738 print a_name
1739 print 'Active name: %s' % (new_identity.get_active_name())
1740
1741 print '\nIdentity occupations: %s' % new_identity['occupations']
1742 print 'Creating identity occupation...'
1743 new_identity.link_occupation('test occupation')
1744 print 'Identity occupations: %s' % new_identity['occupations']
1745
1746 print '\nIdentity addresses: %s' % new_identity.get_addresses()
1747 print 'Creating identity address...'
1748
1749 new_identity.link_address (
1750 number = 'test 1234',
1751 street = 'test street',
1752 postcode = 'test postcode',
1753 urb = 'test urb',
1754 state = 'SN',
1755 country = 'DE'
1756 )
1757 print 'Identity addresses: %s' % new_identity.get_addresses()
1758
1759 print '\nIdentity communications: %s' % new_identity.get_comm_channels()
1760 print 'Creating identity communication...'
1761 new_identity.link_comm_channel('homephone', '1234566')
1762 print 'Identity communications: %s' % new_identity.get_comm_channels()
1763
1769
1770
1771
1772
1773
1774
1775 test_current_provider()
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789