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