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