| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
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 # std lib
13 import sys, os.path, time, re as regex, string, types, datetime as pyDT, codecs, threading, logging
14
15
16 # GNUmed
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, gmLog2
21 from Gnumed.business import gmDocuments, gmDemographicRecord, gmProviderInbox, gmXdtMappings, gmClinicalRecord
22
23
24 _log = logging.getLogger('gm.person')
25 _log.info(__version__)
26
27 __gender_list = None
28 __gender_idx = None
29
30 __gender2salutation_map = None
31
32 #============================================================
34
35 # FIXME: make this work as a mapping type, too
36
37 #--------------------------------------------------------
38 # external API
39 #--------------------------------------------------------
42 #--------------------------------------------------------
45 #--------------------------------------------------------
47 """Generate generic queries.
48
49 - not locale dependant
50 - data -> firstnames, lastnames, dob, gender
51
52 shall we mogrify name parts ? probably not as external
53 sources should know what they do
54
55 finds by inactive name, too, but then shows
56 the corresponding active name ;-)
57
58 Returns list of matching identities (may be empty)
59 or None if it was told to create an identity but couldn't.
60 """
61 where_snippets = []
62 args = {}
63
64 where_snippets.append(u'firstnames = %(first)s')
65 args['first'] = self.firstnames
66
67 where_snippets.append(u'lastnames = %(last)s')
68 args['last'] = self.lastnames
69
70 if self.dob is not None:
71 where_snippets.append(u"dem.date_trunc_utc('day'::text, dob) = dem.date_trunc_utc('day'::text, %(dob)s)")
72 args['dob'] = self.dob
73
74 if self.gender is not None:
75 where_snippets.append('gender = %(sex)s')
76 args['sex'] = self.gender
77
78 cmd = u"""
79 select *, '%s' as match_type from dem.v_basic_person
80 where pk_identity in (
81 select id_identity from dem.names where %s
82 ) order by lastnames, firstnames, dob""" % (
83 _('external patient source (name, gender, date of birth)'),
84 ' and '.join(where_snippets)
85 )
86
87 try:
88 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx=True)
89 except:
90 _log.error(u'cannot get candidate identities for dto "%s"' % self)
91 _log.exception('query %s' % cmd)
92 rows = []
93
94 if len(rows) == 0:
95 if not can_create:
96 return []
97 ident = self.import_into_database()
98 if ident is None:
99 return None
100 identities = [ident]
101 else:
102 identities = [ cIdentity(row = {'pk_field': 'pk_identity', 'data': row, 'idx': idx}) for row in rows ]
103
104 return identities
105 #--------------------------------------------------------
107 """Imports self into the database.
108
109 Child classes can override this to provide more extensive import.
110 """
111 ident = create_identity (
112 firstnames = self.firstnames,
113 lastnames = self.lastnames,
114 gender = self.gender,
115 dob = self.dob
116 )
117 return ident
118 #--------------------------------------------------------
121 #--------------------------------------------------------
122 # customizing behaviour
123 #--------------------------------------------------------
125 return u'<%s @ %s: %s %s (%s) %s>' % (
126 self.__class__.__name__,
127 id(self),
128 self.firstnames,
129 self.lastnames,
130 self.gender,
131 self.dob
132 )
133 #--------------------------------------------------------
135 """Do some sanity checks on self.* access."""
136
137 if attr == 'gender':
138 glist, idx = get_gender_list()
139 for gender in glist:
140 if str(val) in [gender[0], gender[1], gender[2], gender[3]]:
141 val = gender[idx['tag']]
142 object.__setattr__(self, attr, val)
143 return
144 raise ValueError('invalid gender: [%s]' % val)
145
146 if attr == 'dob':
147 if val is not None:
148 if not isinstance(val, pyDT.datetime):
149 raise TypeError('invalid type for DOB (must be datetime.datetime): %s [%s]' % (type(val), val))
150 if val.tzinfo is None:
151 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % val.isoformat())
152
153 object.__setattr__(self, attr, val)
154 return
155 #--------------------------------------------------------
158 #============================================================
160 _cmd_fetch_payload = u"select * from dem.v_person_names where pk_name = %s"
161 _cmds_store_payload = [
162 u"""update dem.names set
163 active = False
164 where
165 %(active_name)s is True and -- act only when needed and only
166 id_identity = %(pk_identity)s and -- on names of this identity
167 active is True and -- which are active
168 id != %(pk_name)s -- but NOT *this* name
169 """,
170 u"""update dem.names set
171 active = %(active_name)s,
172 preferred = %(preferred)s,
173 comment = %(comment)s
174 where
175 id = %(pk_name)s and
176 id_identity = %(pk_identity)s and -- belt and suspenders
177 xmin = %(xmin_name)s""",
178 u"""select xmin as xmin_name from dem.names where id = %(pk_name)s"""
179 ]
180 _updatable_fields = ['active_name', 'preferred', 'comment']
181 #--------------------------------------------------------
183 if attribute == 'active_name':
184 # cannot *directly* deactivate a name, only indirectly
185 # by activating another one
186 # FIXME: should be done at DB level
187 if self._payload[self._idx['active_name']] is True:
188 return
189 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
190 #--------------------------------------------------------
192 return '%(last)s, %(title)s %(first)s%(nick)s' % {
193 'last': self._payload[self._idx['lastnames']],
194 'title': gmTools.coalesce (
195 self._payload[self._idx['title']],
196 map_gender2salutation(self._payload[self._idx['gender']])
197 ),
198 'first': self._payload[self._idx['firstnames']],
199 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' "%s"', u'%s')
200 }
201
202 description = property(_get_description, lambda x:x)
203 #============================================================
205 _cmd_fetch_payload = u"SELECT * FROM dem.v_staff WHERE pk_staff = %s"
206 _cmds_store_payload = [
207 u"""UPDATE dem.staff SET
208 fk_role = %(pk_role)s,
209 short_alias = %(short_alias)s,
210 comment = gm.nullify_empty_string(%(comment)s),
211 is_active = %(is_active)s,
212 db_user = %(db_user)s
213 WHERE
214 pk = %(pk_staff)s
215 AND
216 xmin = %(xmin_staff)s
217 RETURNING
218 xmin AS xmin_staff"""
219 # ,u"""select xmin_staff from dem.v_staff where pk_identity=%(pk_identity)s"""
220 ]
221 _updatable_fields = ['pk_role', 'short_alias', 'comment', 'is_active', 'db_user']
222 #--------------------------------------------------------
224 # by default get staff corresponding to CURRENT_USER
225 if (aPK_obj is None) and (row is None):
226 cmd = u"select * from dem.v_staff where db_user = CURRENT_USER"
227 try:
228 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
229 except:
230 _log.exception('cannot instantiate staff instance')
231 gmLog2.log_stack_trace()
232 raise ValueError('cannot instantiate staff instance for database account CURRENT_USER')
233 if len(rows) == 0:
234 raise ValueError('no staff record for database account CURRENT_USER')
235 row = {
236 'pk_field': 'pk_staff',
237 'idx': idx,
238 'data': rows[0]
239 }
240 gmBusinessDBObject.cBusinessDBObject.__init__(self, row = row)
241 else:
242 gmBusinessDBObject.cBusinessDBObject.__init__(self, aPK_obj = aPK_obj, row = row)
243
244 # are we SELF ?
245 self.__is_current_user = (gmPG2.get_current_user() == self._payload[self._idx['db_user']])
246
247 self.__inbox = None
248 #--------------------------------------------------------
250 if attribute == 'db_user':
251 if self.__is_current_user:
252 _log.debug('will not modify database account association of CURRENT_USER staff member')
253 return
254 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
255 #--------------------------------------------------------
257 rows, idx = gmPG2.run_ro_queries (
258 queries = [{
259 'cmd': u'select i18n.get_curr_lang(%(usr)s)',
260 'args': {'usr': self._payload[self._idx['db_user']]}
261 }]
262 )
263 return rows[0][0]
264
266 if not gmPG2.set_user_language(language = language):
267 raise ValueError (
268 u'Cannot set database language to [%s] for user [%s].' % (language, self._payload[self._idx['db_user']])
269 )
270 return
271
272 database_language = property(_get_db_lang, _set_db_lang)
273 #--------------------------------------------------------
275 if self.__inbox is None:
276 self.__inbox = gmProviderInbox.cProviderInbox(provider_id = self._payload[self._idx['pk_staff']])
277 return self.__inbox
278
281
282 inbox = property(_get_inbox, _set_inbox)
283 #============================================================
286 #============================================================
288 """Staff member Borg to hold currently logged on provider.
289
290 There may be many instances of this but they all share state.
291 """
293 """Change or get currently logged on provider.
294
295 provider:
296 * None: get copy of current instance
297 * cStaff instance: change logged on provider (role)
298 """
299 # make sure we do have a provider pointer
300 try:
301 self.provider
302 except AttributeError:
303 self.provider = gmNull.cNull()
304
305 # user wants copy of currently logged on provider
306 if provider is None:
307 return None
308
309 # must be cStaff instance, then
310 if not isinstance(provider, cStaff):
311 raise ValueError, 'cannot set logged on provider to [%s], must be either None or cStaff instance' % str(provider)
312
313 # same ID, no change needed
314 if self.provider['pk_staff'] == provider['pk_staff']:
315 return None
316
317 # first invocation
318 if isinstance(self.provider, gmNull.cNull):
319 self.provider = provider
320 return None
321
322 # user wants different provider
323 raise ValueError, 'provider change [%s] -> [%s] not yet supported' % (self.provider['pk_staff'], provider['pk_staff'])
324
325 #--------------------------------------------------------
328 #--------------------------------------------------------
329 # __getitem__ handling
330 #--------------------------------------------------------
332 """Return any attribute if known how to retrieve it by proxy.
333 """
334 return self.provider[aVar]
335 #--------------------------------------------------------
336 # __s/getattr__ handling
337 #--------------------------------------------------------
343 # raise AttributeError
344 #============================================================
346 _cmd_fetch_payload = u"select * from dem.v_basic_person where pk_identity = %s"
347 _cmds_store_payload = [
348 u"""update dem.identity set
349 gender = %(gender)s,
350 dob = %(dob)s,
351 tob = %(tob)s,
352 cob = gm.nullify_empty_string(%(cob)s),
353 title = gm.nullify_empty_string(%(title)s),
354 fk_marital_status = %(pk_marital_status)s,
355 karyotype = gm.nullify_empty_string(%(karyotype)s),
356 pupic = gm.nullify_empty_string(%(pupic)s),
357 deceased = %(deceased)s,
358 emergency_contact = gm.nullify_empty_string(%(emergency_contact)s),
359 fk_emergency_contact = %(pk_emergency_contact)s,
360 fk_primary_provider = %(pk_primary_provider)s,
361 comment = gm.nullify_empty_string(%(comment)s)
362 where
363 pk = %(pk_identity)s and
364 xmin = %(xmin_identity)s""",
365 u"""select xmin_identity from dem.v_basic_person where pk_identity = %(pk_identity)s"""
366 ]
367 _updatable_fields = [
368 "title",
369 "dob",
370 "tob",
371 "cob",
372 "gender",
373 "pk_marital_status",
374 "karyotype",
375 "pupic",
376 'deceased',
377 'emergency_contact',
378 'pk_emergency_contact',
379 'pk_primary_provider',
380 'comment'
381 ]
382 #--------------------------------------------------------
387 ID = property(_get_ID, _set_ID)
388 #--------------------------------------------------------
390
391 if attribute == 'dob':
392 if value is not None:
393
394 if isinstance(value, pyDT.datetime):
395 if value.tzinfo is None:
396 raise ValueError('datetime.datetime instance is lacking a time zone: [%s]' % dt.isoformat())
397 else:
398 raise TypeError, '[%s]: type [%s] (%s) invalid for attribute [dob], must be datetime.datetime or None' % (self.__class__.__name__, type(value), value)
399
400 # compare DOB at seconds level
401 if self._payload[self._idx['dob']] is not None:
402 old_dob = self._payload[self._idx['dob']].strftime('%Y %m %d %H %M %S')
403 new_dob = value.strftime('%Y %m %d %H %M %S')
404 if new_dob == old_dob:
405 return
406
407 gmBusinessDBObject.cBusinessDBObject.__setitem__(self, attribute, value)
408 #--------------------------------------------------------
411 #--------------------------------------------------------
413 cmd = u"""
414 select exists (
415 select 1
416 from clin.v_emr_journal
417 where
418 pk_patient = %(pat)s
419 and
420 soap_cat is not null
421 )"""
422 args = {'pat': self._payload[self._idx['pk_identity']]}
423 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
424 return rows[0][0]
425
428
429 is_patient = property(_get_is_patient, _set_is_patient)
430 #--------------------------------------------------------
431 # identity API
432 #--------------------------------------------------------
434 for name in self.get_names():
435 if name['active_name'] is True:
436 return name
437
438 _log.error('cannot retrieve active name for patient [%s]' % self._payload[self._idx['pk_identity']])
439 return None
440 #--------------------------------------------------------
442 cmd = u"select * from dem.v_person_names where pk_identity = %(pk_pat)s"
443 rows, idx = gmPG2.run_ro_queries (
444 queries = [{
445 'cmd': cmd,
446 'args': {'pk_pat': self._payload[self._idx['pk_identity']]}
447 }],
448 get_col_idx = True
449 )
450
451 if len(rows) == 0:
452 # no names registered for patient
453 return []
454
455 names = [ cPersonName(row = {'idx': idx, 'data': r, 'pk_field': 'pk_name'}) for r in rows ]
456 return names
457 #--------------------------------------------------------
459 if self._payload[self._idx['dob']] is None:
460 return _('** DOB unknown **')
461
462 if encoding is None:
463 encoding = gmI18N.get_encoding()
464
465 return self._payload[self._idx['dob']].strftime(format).decode(encoding)
466 #--------------------------------------------------------
468 return '%(sex)s%(title)s %(last)s, %(first)s%(nick)s' % {
469 'last': self._payload[self._idx['lastnames']],
470 'first': self._payload[self._idx['firstnames']],
471 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s'),
472 'sex': map_gender2salutation(self._payload[self._idx['gender']]),
473 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s')
474 }
475 #--------------------------------------------------------
477 return '%(last)s,%(title)s %(first)s%(nick)s' % {
478 'last': self._payload[self._idx['lastnames']],
479 'title': gmTools.coalesce(self._payload[self._idx['title']], u'', u' %s', u'%s'),
480 'first': self._payload[self._idx['firstnames']],
481 'nick': gmTools.coalesce(self._payload[self._idx['preferred']], u'', u' (%s)', u'%s')
482 }
483 #--------------------------------------------------------
485 """Add a name.
486
487 @param firstnames The first names.
488 @param lastnames The last names.
489 @param active When True, the new name will become the active one (hence setting other names to inactive)
490 @type active A types.BooleanType instance
491 """
492 name = create_name(self.ID, firstnames, lastnames, active)
493 if active:
494 self.refetch_payload()
495 return name
496 #--------------------------------------------------------
498 cmd = u"delete from dem.names where id = %(name)s and id_identity = %(pat)s"
499 args = {'name': name['pk_name'], 'pat': self.ID}
500 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
501 # can't have been the active name as that would raise an
502 # exception (since no active name would be left) so no
503 # data refetch needed
504 #--------------------------------------------------------
506 """
507 Set the nickname. Setting the nickname only makes sense for the currently
508 active name.
509 @param nickname The preferred/nick/warrior name to set.
510 """
511 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': u"select dem.set_nickname(%s, %s)", 'args': [self.ID, nickname]}])
512 self.refetch_payload()
513 return True
514 #--------------------------------------------------------
515 # external ID API
516 #
517 # since external IDs are not treated as first class
518 # citizens (classes in their own right, that is), we
519 # handle them *entirely* within cIdentity, also they
520 # only make sense with one single person (like names)
521 # and are not reused (like addresses), so they are
522 # truly added/deleted, not just linked/unlinked
523 #--------------------------------------------------------
524 - def add_external_id(self, type_name=None, value=None, issuer=None, comment=None, pk_type=None):
525 """Adds an external ID to the patient.
526
527 creates ID type if necessary
528 """
529
530 # check for existing ID
531 if pk_type is not None:
532 cmd = u"""
533 select * from dem.v_external_ids4identity where
534 pk_identity = %(pat)s and
535 pk_type = %(pk_type)s and
536 value = %(val)s"""
537 else:
538 # by type/value/issuer
539 if issuer is None:
540 cmd = u"""
541 select * from dem.v_external_ids4identity where
542 pk_identity = %(pat)s and
543 name = %(name)s and
544 value = %(val)s"""
545 else:
546 cmd = u"""
547 select * from dem.v_external_ids4identity where
548 pk_identity = %(pat)s and
549 name = %(name)s and
550 value = %(val)s and
551 issuer = %(issuer)s"""
552 args = {
553 'pat': self.ID,
554 'name': type_name,
555 'val': value,
556 'issuer': issuer,
557 'pk_type': pk_type
558 }
559 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
560
561 # create new ID if not found
562 if len(rows) == 0:
563
564 args = {
565 'pat': self.ID,
566 'val': value,
567 'type_name': type_name,
568 'pk_type': pk_type,
569 'issuer': issuer,
570 'comment': comment
571 }
572
573 if pk_type is None:
574 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values (
575 %(val)s,
576 (select dem.add_external_id_type(%(type_name)s, %(issuer)s)),
577 %(comment)s,
578 %(pat)s
579 )"""
580 else:
581 cmd = u"""insert into dem.lnk_identity2ext_id (external_id, fk_origin, comment, id_identity) values (
582 %(val)s,
583 %(pk_type)s,
584 %(comment)s,
585 %(pat)s
586 )"""
587
588 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
589
590 # or update comment of existing ID
591 else:
592 row = rows[0]
593 if comment is not None:
594 # comment not already there ?
595 if gmTools.coalesce(row['comment'], '').find(comment.strip()) == -1:
596 comment = '%s%s' % (gmTools.coalesce(row['comment'], '', '%s // '), comment.strip)
597 cmd = u"update dem.lnk_identity2ext_id set comment = %(comment)s where id=%(pk)s"
598 args = {'comment': comment, 'pk': row['pk_id']}
599 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
600 #--------------------------------------------------------
602 """Edits an existing external ID.
603
604 creates ID type if necessary
605 """
606 cmd = u"""
607 update dem.lnk_identity2ext_id set
608 fk_origin = (select dem.add_external_id_type(%(type)s, %(issuer)s)),
609 external_id = %(value)s,
610 comment = %(comment)s
611 where id = %(pk)s"""
612 args = {'pk': pk_id, 'value': value, 'type': type, 'issuer': issuer, 'comment': comment}
613 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
614 #--------------------------------------------------------
616 where_parts = ['pk_identity = %(pat)s']
617 args = {'pat': self.ID}
618
619 if id_type is not None:
620 where_parts.append(u'name = %(name)s')
621 args['name'] = id_type.strip()
622
623 if issuer is not None:
624 where_parts.append(u'issuer = %(issuer)s')
625 args['issuer'] = issuer.strip()
626
627 cmd = u"select * from dem.v_external_ids4identity where %s" % ' and '.join(where_parts)
628 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
629
630 return rows
631 #--------------------------------------------------------
633 cmd = u"""
634 delete from dem.lnk_identity2ext_id
635 where id_identity = %(pat)s and id = %(pk)s"""
636 args = {'pat': self.ID, 'pk': pk_ext_id}
637 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
638 #--------------------------------------------------------
640 """Merge another identity into this one.
641
642 Keep this one. Delete other one."""
643
644 if other_identity.ID == self.ID:
645 return True, None
646
647 curr_pat = gmCurrentPatient()
648 if curr_pat.connected:
649 if other_identity.ID == curr_pat.ID:
650 return False, _('Cannot merge active patient into another patient.')
651
652 queries = []
653 args = {'old_pat': other_identity.ID, 'new_pat': self.ID}
654
655 # delete old allergy state
656 queries.append ({
657 '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)',
658 'args': args
659 })
660 # FIXME: adjust allergy_state in kept patient
661
662 # deactivate all names of old patient
663 queries.append ({
664 'cmd': u'update dem.names set active = False where id_identity = %(old_pat)s',
665 'args': args
666 })
667
668 # find FKs pointing to identity
669 FKs = gmPG2.get_foreign_keys2column (
670 schema = u'dem',
671 table = u'identity',
672 column = u'pk'
673 )
674
675 # generate UPDATEs
676 cmd_template = u'update %s set %s = %%(new_pat)s where %s = %%(old_pat)s'
677 for FK in FKs:
678 queries.append ({
679 'cmd': cmd_template % (FK['referencing_table'], FK['referencing_column'], FK['referencing_column']),
680 'args': args
681 })
682
683 # remove old identity entry
684 queries.append ({
685 'cmd': u'delete from dem.identity where pk = %(old_pat)s',
686 'args': args
687 })
688
689 _log.warning('identity [%s] is about to assimilate identity [%s]', self.ID, other_identity.ID)
690
691 gmPG2.run_rw_queries(link_obj = link_obj, queries = queries, end_tx = True)
692
693 self.add_external_id (
694 type_name = u'merged GNUmed identity primary key',
695 value = u'GNUmed::pk::%s' % other_identity.ID,
696 issuer = u'GNUmed'
697 )
698
699 return True, None
700 #--------------------------------------------------------
701 #--------------------------------------------------------
703 cmd = u"""
704 insert into clin.waiting_list (fk_patient, urgency, comment, area, list_position)
705 values (
706 %(pat)s,
707 %(urg)s,
708 %(cmt)s,
709 %(area)s,
710 (select coalesce((max(list_position) + 1), 1) from clin.waiting_list)
711 )"""
712 args = {'pat': self.ID, 'urg': urgency, 'cmt': comment, 'area': zone}
713 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], verbose=True)
714 #--------------------------------------------------------
716
717 template = u'%s%s%s\r\n'
718
719 file = codecs.open (
720 filename = filename,
721 mode = 'wb',
722 encoding = encoding,
723 errors = 'strict'
724 )
725
726 file.write(template % (u'013', u'8000', u'6301'))
727 file.write(template % (u'013', u'9218', u'2.10'))
728 if external_id_type is None:
729 file.write(template % (u'%03d' % (9 + len(str(self.ID))), u'3000', self.ID))
730 else:
731 ext_ids = self.get_external_ids(id_type = external_id_type)
732 if len(ext_ids) > 0:
733 file.write(template % (u'%03d' % (9 + len(ext_ids[0]['value'])), u'3000', ext_ids[0]['value']))
734 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['lastnames']])), u'3101', self._payload[self._idx['lastnames']]))
735 file.write(template % (u'%03d' % (9 + len(self._payload[self._idx['firstnames']])), u'3102', self._payload[self._idx['firstnames']]))
736 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')))
737 file.write(template % (u'010', u'3110', gmXdtMappings.map_gender_gm2xdt[self._payload[self._idx['gender']]]))
738 file.write(template % (u'025', u'6330', 'GNUmed::9206::encoding'))
739 file.write(template % (u'%03d' % (9 + len(encoding)), u'6331', encoding))
740 if external_id_type is None:
741 file.write(template % (u'029', u'6332', u'GNUmed::3000::source'))
742 file.write(template % (u'017', u'6333', u'internal'))
743 else:
744 if len(ext_ids) > 0:
745 file.write(template % (u'029', u'6332', u'GNUmed::3000::source'))
746 file.write(template % (u'%03d' % (9 + len(external_id_type)), u'6333', external_id_type))
747
748 file.close()
749 #--------------------------------------------------------
750 # occupations API
751 #--------------------------------------------------------
753 cmd = u"select * from dem.v_person_jobs where pk_identity=%s"
754 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}])
755 return rows
756 #--------------------------------------------------------
758 """Link an occupation with a patient, creating the occupation if it does not exists.
759
760 @param occupation The name of the occupation to link the patient to.
761 """
762 if (activities is None) and (occupation is None):
763 return True
764
765 occupation = occupation.strip()
766 if len(occupation) == 0:
767 return True
768
769 if activities is not None:
770 activities = activities.strip()
771
772 args = {'act': activities, 'pat_id': self.pk_obj, 'job': occupation}
773
774 cmd = u"select activities from dem.v_person_jobs where pk_identity = %(pat_id)s and l10n_occupation = _(%(job)s)"
775 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
776
777 queries = []
778 if len(rows) == 0:
779 queries.append ({
780 'cmd': u"INSERT INTO dem.lnk_job2person (fk_identity, fk_occupation, activities) VALUES (%(pat_id)s, dem.create_occupation(%(job)s), %(act)s)",
781 'args': args
782 })
783 else:
784 if rows[0]['activities'] != activities:
785 queries.append ({
786 '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))",
787 'args': args
788 })
789
790 rows, idx = gmPG2.run_rw_queries(queries = queries)
791
792 return True
793 #--------------------------------------------------------
795 if occupation is None:
796 return True
797 occupation = occupation.strip()
798 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))"
799 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj, 'job': occupation}}])
800 return True
801 #--------------------------------------------------------
802 # comms API
803 #--------------------------------------------------------
805 cmd = u"select * from dem.v_person_comms where pk_identity = %s"
806 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx = True)
807
808 filtered = rows
809
810 if comm_medium is not None:
811 filtered = []
812 for row in rows:
813 if row['comm_type'] == comm_medium:
814 filtered.append(row)
815
816 return [ gmDemographicRecord.cCommChannel(row = {
817 'pk_field': 'pk_lnk_identity2comm',
818 'data': r,
819 'idx': idx
820 }) for r in filtered
821 ]
822 #--------------------------------------------------------
823 - def link_comm_channel(self, comm_medium=None, url=None, is_confidential=False, pk_channel_type=None):
824 """Link a communication medium with a patient.
825
826 @param comm_medium The name of the communication medium.
827 @param url The communication resource locator.
828 @type url A types.StringType instance.
829 @param is_confidential Wether the data must be treated as confidential.
830 @type is_confidential A types.BooleanType instance.
831 """
832 comm_channel = gmDemographicRecord.create_comm_channel (
833 comm_medium = comm_medium,
834 url = url,
835 is_confidential = is_confidential,
836 pk_channel_type = pk_channel_type,
837 pk_identity = self.pk_obj
838 )
839 return comm_channel
840 #--------------------------------------------------------
842 gmDemographicRecord.delete_comm_channel (
843 pk = comm_channel['pk_lnk_identity2comm'],
844 pk_patient = self.pk_obj
845 )
846 #--------------------------------------------------------
847 # contacts API
848 #--------------------------------------------------------
850 cmd = u"select * from dem.v_pat_addresses where pk_identity=%s"
851 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx=True)
852 addresses = []
853 for r in rows:
854 addresses.append(gmDemographicRecord.cPatientAddress(row={'idx': idx, 'data': r, 'pk_field': 'pk_address'}))
855
856 filtered = addresses
857
858 if address_type is not None:
859 filtered = []
860 for adr in addresses:
861 if adr['address_type'] == address_type:
862 filtered.append(adr)
863
864 return filtered
865 #--------------------------------------------------------
866 - def link_address(self, number=None, street=None, postcode=None, urb=None, state=None, country=None, subunit=None, suburb=None, id_type=None):
867 """Link an address with a patient, creating the address if it does not exists.
868
869 @param number The number of the address.
870 @param street The name of the street.
871 @param postcode The postal code of the address.
872 @param urb The name of town/city/etc.
873 @param state The code of the state.
874 @param country The code of the country.
875 @param id_type The primary key of the address type.
876 """
877 # create/get address
878 adr = gmDemographicRecord.create_address (
879 country = country,
880 state = state,
881 urb = urb,
882 suburb = suburb,
883 postcode = postcode,
884 street = street,
885 number = number,
886 subunit = subunit
887 )
888
889 # already linked ?
890 cmd = u"select * from dem.lnk_person_org_address where id_identity = %s and id_address = %s"
891 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj, adr['pk_address']]}])
892 # no, link to person
893 if len(rows) == 0:
894 args = {'id': self.pk_obj, 'adr': adr['pk_address'], 'type': id_type}
895 if id_type is None:
896 cmd = u"""
897 insert into dem.lnk_person_org_address(id_identity, id_address)
898 values (%(id)s, %(adr)s)"""
899 else:
900 cmd = u"""
901 insert into dem.lnk_person_org_address(id_identity, id_address, id_type)
902 values (%(id)s, %(adr)s, %(type)s)"""
903 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
904 else:
905 # already linked - but needs to change type ?
906 if id_type is not None:
907 r = rows[0]
908 if r['id_type'] != id_type:
909 cmd = "update dem.lnk_person_org_address set id_type = %(type)s where id = %(id)s"
910 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'type': id_type, 'id': r['id']}}])
911
912 return adr
913 #----------------------------------------------------------------------
915 """Remove an address from the patient.
916
917 The address itself stays in the database.
918 The address can be either cAdress or cPatientAdress.
919 """
920 cmd = u"delete from dem.lnk_person_org_address where id_identity = %(person)s and id_address = %(adr)s"
921 args = {'person': self.pk_obj, 'adr': address['pk_address']}
922 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
923 #----------------------------------------------------------------------
924 # relatives API
925 #----------------------------------------------------------------------
927 cmd = u"""
928 select
929 t.description,
930 vbp.pk_identity as id,
931 title,
932 firstnames,
933 lastnames,
934 dob,
935 cob,
936 gender,
937 karyotype,
938 pupic,
939 pk_marital_status,
940 marital_status,
941 xmin_identity,
942 preferred
943 from
944 dem.v_basic_person vbp, dem.relation_types t, dem.lnk_person2relative l
945 where
946 (
947 l.id_identity = %(pk)s and
948 vbp.pk_identity = l.id_relative and
949 t.id = l.id_relation_type
950 ) or (
951 l.id_relative = %(pk)s and
952 vbp.pk_identity = l.id_identity and
953 t.inverse = l.id_relation_type
954 )"""
955 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}])
956 if len(rows) == 0:
957 return []
958 return [(row[0], cIdentity(row = {'data': row[1:], 'idx':idx, 'pk_field': 'pk'})) for row in rows]
959 #--------------------------------------------------------
961 # create new relative
962 id_new_relative = create_dummy_identity()
963
964 relative = cIdentity(aPK_obj=id_new_relative)
965 # pre-fill with data from ourselves
966 # relative.copy_addresses(self)
967 relative.add_name( '**?**', self.get_names()['lastnames'])
968 # and link the two
969 if self._ext_cache.has_key('relatives'):
970 del self._ext_cache['relatives']
971 cmd = u"""
972 insert into dem.lnk_person2relative (
973 id_identity, id_relative, id_relation_type
974 ) values (
975 %s, %s, (select id from dem.relation_types where description = %s)
976 )"""
977 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [self.ID, id_new_relative, rel_type ]}])
978 return True
979 #----------------------------------------------------------------------
983 #--------------------------------------------------------
985 if self._payload[self._idx['pk_emergency_contact']] is None:
986 return None
987 return cIdentity(aPK_obj = self._payload[self._idx['pk_emergency_contact']])
988
989 emergency_contact_in_database = property(_get_emergency_contact_from_database, lambda x:x)
990 #----------------------------------------------------------------------
991 # age/dob related
992 #----------------------------------------------------------------------
994 dob = self['dob']
995
996 if dob is None:
997 return u'??'
998
999 if self['deceased'] is None:
1000 # return gmDateTime.format_interval_medically (
1001 # pyDT.datetime.now(tz = gmDateTime.gmCurrentLocalTimezone) - dob
1002 # )
1003 return gmDateTime.format_apparent_age_medically (
1004 age = gmDateTime.calculate_apparent_age(start = dob)
1005 )
1006
1007 return u'%s%s' % (
1008 gmTools.u_latin_cross,
1009 # gmDateTime.format_interval_medically(self['deceased'] - dob)
1010 gmDateTime.format_apparent_age_medically (
1011 age = gmDateTime.calculate_apparent_age (
1012 start = dob,
1013 end = self['deceased']
1014 )
1015 )
1016 )
1017 #----------------------------------------------------------------------
1019 cmd = u'select dem.dob_is_in_range(%(dob)s, %(min)s, %(max)s)'
1020 rows, idx = gmPG2.run_ro_queries (
1021 queries = [{
1022 'cmd': cmd,
1023 'args': {'dob': self['dob'], 'min': min_distance, 'max': max_distance}
1024 }]
1025 )
1026 return rows[0][0]
1027 #----------------------------------------------------------------------
1028 # practice related
1029 #----------------------------------------------------------------------
1031 cmd = u'select * from clin.v_most_recent_encounters where pk_patient=%s'
1032 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self._payload[self._idx['pk_identity']]]}])
1033 if len(rows) > 0:
1034 return rows[0]
1035 else:
1036 return None
1037 #--------------------------------------------------------
1039 return gmProviderInbox.get_inbox_messages(pk_patient = self._payload[self._idx['pk_identity']])
1040
1043
1044 messages = property(_get_messages, _set_messages)
1045 #--------------------------------------------------------
1048 #--------------------------------------------------------
1050 if self._payload[self._idx['pk_primary_provider']] is None:
1051 return None
1052 return cStaff(aPK_obj = self._payload[self._idx['pk_primary_provider']])
1053
1054 primary_provider = property(_get_primary_provider, lambda x:x)
1055 #----------------------------------------------------------------------
1056 # convenience
1057 #----------------------------------------------------------------------
1059 """Format patient demographics into patient specific path name fragment."""
1060 return '%s-%s%s-%s' % (
1061 self._payload[self._idx['lastnames']].replace(u' ', u'_'),
1062 self._payload[self._idx['firstnames']].replace(u' ', u'_'),
1063 gmTools.coalesce(self._payload[self._idx['preferred']], u'', template_initial = u'-(%s)'),
1064 self.get_formatted_dob(format = '%Y-%m-%d', encoding = gmI18N.get_encoding())
1065 )
1066 #============================================================
1068 """Represents a staff member which is a person.
1069
1070 - a specializing subclass of cIdentity turning it into a staff member
1071 """
1075 #--------------------------------------------------------
1078 #============================================================
1080 """Represents a person which is a patient.
1081
1082 - a specializing subclass of cIdentity turning it into a patient
1083 - its use is to cache subobjects like EMR and document folder
1084 """
1086 cIdentity.__init__(self, aPK_obj=aPK_obj, row=row)
1087 self.__db_cache = {}
1088 self.__emr_access_lock = threading.Lock()
1089 #--------------------------------------------------------
1091 """Do cleanups before dying.
1092
1093 - note that this may be called in a thread
1094 """
1095 if self.__db_cache.has_key('clinical record'):
1096 self.__db_cache['clinical record'].cleanup()
1097 if self.__db_cache.has_key('document folder'):
1098 self.__db_cache['document folder'].cleanup()
1099 cIdentity.cleanup(self)
1100 #----------------------------------------------------------
1102 if not self.__emr_access_lock.acquire(False):
1103 raise AttributeError('cannot access EMR')
1104 try:
1105 emr = self.__db_cache['clinical record']
1106 self.__emr_access_lock.release()
1107 return emr
1108 except KeyError:
1109 pass
1110
1111 self.__db_cache['clinical record'] = gmClinicalRecord.cClinicalRecord(aPKey = self._payload[self._idx['pk_identity']])
1112 self.__emr_access_lock.release()
1113 return self.__db_cache['clinical record']
1114 #--------------------------------------------------------
1116 try:
1117 return self.__db_cache['document folder']
1118 except KeyError:
1119 pass
1120
1121 self.__db_cache['document folder'] = gmDocuments.cDocumentFolder(aPKey = self._payload[self._idx['pk_identity']])
1122 return self.__db_cache['document folder']
1123 #============================================================
1125 """Patient Borg to hold currently active patient.
1126
1127 There may be many instances of this but they all share state.
1128 """
1130 """Change or get currently active patient.
1131
1132 patient:
1133 * None: get currently active patient
1134 * -1: unset currently active patient
1135 * cPatient instance: set active patient if possible
1136 """
1137 # make sure we do have a patient pointer
1138 try:
1139 tmp = self.patient
1140 except AttributeError:
1141 self.patient = gmNull.cNull()
1142 self.__register_interests()
1143 # set initial lock state,
1144 # this lock protects against activating another patient
1145 # when we are controlled from a remote application
1146 self.__lock_depth = 0
1147 # initialize callback state
1148 self.__pre_selection_callbacks = []
1149
1150 # user wants copy of current patient
1151 if patient is None:
1152 return None
1153
1154 # do nothing if patient is locked
1155 if self.locked:
1156 _log.error('patient [%s] is locked, cannot change to [%s]' % (self.patient['pk_identity'], patient))
1157 return None
1158
1159 # user wants to explicitly unset current patient
1160 if patient == -1:
1161 _log.debug('explicitly unsetting current patient')
1162 if not self.__run_pre_selection_callbacks():
1163 _log.debug('not unsetting current patient')
1164 return None
1165 self.__send_pre_selection_notification()
1166 self.patient.cleanup()
1167 self.patient = gmNull.cNull()
1168 self.__send_selection_notification()
1169 return None
1170
1171 # must be cPatient instance, then
1172 if not isinstance(patient, cPatient):
1173 _log.error('cannot set active patient to [%s], must be either None, -1 or cPatient instance' % str(patient))
1174 raise TypeError, 'gmPerson.gmCurrentPatient.__init__(): <patient> must be None, -1 or cPatient instance but is: %s' % str(patient)
1175
1176 # same ID, no change needed
1177 if (self.patient['pk_identity'] == patient['pk_identity']) and not forced_reload:
1178 return None
1179
1180 # user wants different patient
1181 _log.debug('patient change [%s] -> [%s] requested', self.patient['pk_identity'], patient['pk_identity'])
1182
1183 # everything seems swell
1184 if not self.__run_pre_selection_callbacks():
1185 _log.debug('not changing current patient')
1186 return None
1187 self.__send_pre_selection_notification()
1188 self.patient.cleanup()
1189 self.patient = patient
1190 self.patient.get_emr()
1191 self.__send_selection_notification()
1192
1193 return None
1194 #--------------------------------------------------------
1196 gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_identity_change)
1197 gmDispatcher.connect(signal = u'name_mod_db', receiver = self._on_identity_change)
1198 #--------------------------------------------------------
1202 #--------------------------------------------------------
1203 # external API
1204 #--------------------------------------------------------
1206 if not callable(callback):
1207 raise TypeError(u'callback [%s] not callable' % callback)
1208
1209 self.__pre_selection_callbacks.append(callback)
1210 #--------------------------------------------------------
1213
1216
1217 connected = property(_get_connected, _set_connected)
1218 #--------------------------------------------------------
1221
1223 if locked:
1224 self.__lock_depth = self.__lock_depth + 1
1225 gmDispatcher.send(signal='patient_locked')
1226 else:
1227 if self.__lock_depth == 0:
1228 _log.error('lock/unlock imbalance, trying to refcount lock depth below 0')
1229 return
1230 else:
1231 self.__lock_depth = self.__lock_depth - 1
1232 gmDispatcher.send(signal='patient_unlocked')
1233
1234 locked = property(_get_locked, _set_locked)
1235 #--------------------------------------------------------
1237 _log.info('forced patient unlock at lock depth [%s]' % self.__lock_depth)
1238 self.__lock_depth = 0
1239 gmDispatcher.send(signal='patient_unlocked')
1240 #--------------------------------------------------------
1241 # patient change handling
1242 #--------------------------------------------------------
1244 if isinstance(self.patient, gmNull.cNull):
1245 return True
1246
1247 for call_back in self.__pre_selection_callbacks:
1248 try:
1249 successful = call_back()
1250 except:
1251 _log.exception('callback [%s] failed', call_back)
1252 print "*** pre-selection callback failed ***"
1253 print type(call_back)
1254 print call_back
1255 return False
1256
1257 if not successful:
1258 _log.debug('callback [%s] returned False', call_back)
1259 return False
1260
1261 return True
1262 #--------------------------------------------------------
1264 """Sends signal when another patient is about to become active.
1265
1266 This does NOT wait for signal handlers to complete.
1267 """
1268 kwargs = {
1269 'signal': u'pre_patient_selection',
1270 'sender': id(self.__class__),
1271 'pk_identity': self.patient['pk_identity']
1272 }
1273 gmDispatcher.send(**kwargs)
1274 #--------------------------------------------------------
1276 """Sends signal when another patient has actually been made active."""
1277 kwargs = {
1278 'signal': u'post_patient_selection',
1279 'sender': id(self.__class__),
1280 'pk_identity': self.patient['pk_identity']
1281 }
1282 gmDispatcher.send(**kwargs)
1283 #--------------------------------------------------------
1284 # __getattr__ handling
1285 #--------------------------------------------------------
1287 if attribute == 'patient':
1288 raise AttributeError
1289 if not isinstance(self.patient, gmNull.cNull):
1290 return getattr(self.patient, attribute)
1291 #--------------------------------------------------------
1292 # __get/setitem__ handling
1293 #--------------------------------------------------------
1295 """Return any attribute if known how to retrieve it by proxy.
1296 """
1297 return self.patient[attribute]
1298 #--------------------------------------------------------
1301 #============================================================
1302 # match providers
1303 #============================================================
1306 gmMatchProvider.cMatchProvider_SQL2.__init__(
1307 self,
1308 queries = [
1309 u"""select
1310 pk_staff,
1311 short_alias || ' (' || coalesce(title, '') || firstnames || ' ' || lastnames || ')',
1312 1
1313 from dem.v_staff
1314 where
1315 is_active and (
1316 short_alias %(fragment_condition)s or
1317 firstnames %(fragment_condition)s or
1318 lastnames %(fragment_condition)s or
1319 db_user %(fragment_condition)s
1320 )"""
1321 ]
1322 )
1323 self.setThresholds(1, 2, 3)
1324 #============================================================
1325 # convenience functions
1326 #============================================================
1328 queries = [{
1329 'cmd': u"select dem.add_name(%s, %s, %s, %s)",
1330 'args': [pk_person, firstnames, lastnames, active]
1331 }]
1332 rows, idx = gmPG2.run_rw_queries(queries=queries, return_data=True)
1333 name = cPersonName(aPK_obj = rows[0][0])
1334 return name
1335 #============================================================
1337
1338 cmd1 = u"""insert into dem.identity (gender, dob) values (%s, %s)"""
1339
1340 cmd2 = u"""
1341 insert into dem.names (
1342 id_identity, lastnames, firstnames
1343 ) values (
1344 currval('dem.identity_pk_seq'), coalesce(%s, 'xxxDEFAULTxxx'), coalesce(%s, 'xxxDEFAULTxxx')
1345 )"""
1346
1347 rows, idx = gmPG2.run_rw_queries (
1348 queries = [
1349 {'cmd': cmd1, 'args': [gender, dob]},
1350 {'cmd': cmd2, 'args': [lastnames, firstnames]},
1351 {'cmd': u"select currval('dem.identity_pk_seq')"}
1352 ],
1353 return_data = True
1354 )
1355 return cIdentity(aPK_obj=rows[0][0])
1356 #============================================================
1358 cmd1 = u"insert into dem.identity(gender) values('xxxDEFAULTxxx')"
1359 cmd2 = u"select currval('dem.identity_pk_seq')"
1360
1361 rows, idx = gmPG2.run_rw_queries (
1362 queries = [
1363 {'cmd': cmd1},
1364 {'cmd': cmd2}
1365 ],
1366 return_data = True
1367 )
1368 return gmDemographicRecord.cIdentity(aPK_obj = rows[0][0])
1369 #============================================================
1371 """Set active patient.
1372
1373 If patient is -1 the active patient will be UNset.
1374 """
1375 if isinstance(patient, cPatient):
1376 pat = patient
1377 elif isinstance(patient, cIdentity):
1378 pat = cPatient(aPK_obj=patient['pk_identity'])
1379 elif isinstance(patient, cStaff):
1380 pat = cPatient(aPK_obj=patient['pk_identity'])
1381 elif isinstance(patient, gmCurrentPatient):
1382 pat = patient.patient
1383 elif patient == -1:
1384 pat = patient
1385 else:
1386 raise ValueError('<patient> must be either -1, cPatient, cStaff, cIdentity or gmCurrentPatient instance, is: %s' % patient)
1387
1388 # attempt to switch
1389 try:
1390 gmCurrentPatient(patient = pat, forced_reload = forced_reload)
1391 except:
1392 _log.exception('error changing active patient to [%s]' % patient)
1393 return False
1394
1395 return True
1396 #============================================================
1397 # gender related
1398 #------------------------------------------------------------
1400 """Retrieves the list of known genders from the database."""
1401 global __gender_idx
1402 global __gender_list
1403
1404 if __gender_list is None:
1405 cmd = u"select tag, l10n_tag, label, l10n_label, sort_weight from dem.v_gender_labels order by sort_weight desc"
1406 __gender_list, __gender_idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
1407
1408 return (__gender_list, __gender_idx)
1409 #------------------------------------------------------------
1410 map_gender2mf = {
1411 'm': u'm',
1412 'f': u'f',
1413 'tf': u'f',
1414 'tm': u'm',
1415 'h': u'mf'
1416 }
1417 #------------------------------------------------------------
1418 # Maps GNUmed related i18n-aware gender specifiers to a unicode symbol.
1419 map_gender2symbol = {
1420 'm': u'\u2642',
1421 'f': u'\u2640',
1422 'tf': u'\u26A5\u2640',
1423 'tm': u'\u26A5\u2642',
1424 'h': u'\u26A5'
1425 # 'tf': u'\u2642\u2640-\u2640',
1426 # 'tm': u'\u2642\u2640-\u2642',
1427 # 'h': u'\u2642\u2640'
1428 }
1429 #------------------------------------------------------------
1431 """Maps GNUmed related i18n-aware gender specifiers to a human-readable salutation."""
1432
1433 global __gender2salutation_map
1434
1435 if __gender2salutation_map is None:
1436 genders, idx = get_gender_list()
1437 __gender2salutation_map = {
1438 'm': _('Mr'),
1439 'f': _('Mrs'),
1440 'tf': u'',
1441 'tm': u'',
1442 'h': u''
1443 }
1444 for g in genders:
1445 __gender2salutation_map[g[idx['l10n_tag']]] = __gender2salutation_map[g[idx['tag']]]
1446 __gender2salutation_map[g[idx['label']]] = __gender2salutation_map[g[idx['tag']]]
1447 __gender2salutation_map[g[idx['l10n_label']]] = __gender2salutation_map[g[idx['tag']]]
1448
1449 return __gender2salutation_map[gender]
1450 #------------------------------------------------------------
1452 """Try getting the gender for the given first name."""
1453
1454 if firstnames is None:
1455 return None
1456
1457 rows, idx = gmPG2.run_ro_queries(queries = [{
1458 'cmd': u"select gender from dem.name_gender_map where name ilike %(fn)s limit 1",
1459 'args': {'fn': firstnames}
1460 }])
1461
1462 if len(rows) == 0:
1463 return None
1464
1465 return rows[0][0]
1466 #============================================================
1468 if active_only:
1469 cmd = u"select * from dem.v_staff where is_active order by can_login desc, short_alias asc"
1470 else:
1471 cmd = u"select * from dem.v_staff order by can_login desc, is_active desc, short_alias asc"
1472 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx=True)
1473 staff_list = []
1474 for row in rows:
1475 obj_row = {
1476 'idx': idx,
1477 'data': row,
1478 'pk_field': 'pk_staff'
1479 }
1480 staff_list.append(cStaff(row=obj_row))
1481 return staff_list
1482 #============================================================
1484 return [ cIdentity(aPK_obj = pk) for pk in pks ]
1485 #============================================================
1487 from Gnumed.business import gmXdtObjects
1488 return gmXdtObjects.read_person_from_xdt(filename=filename, encoding=encoding, dob_format=dob_format)
1489 #============================================================
1491 from Gnumed.business import gmPracSoftAU
1492 return gmPracSoftAU.read_persons_from_pracsoft_file(filename=filename, encoding=encoding)
1493 #============================================================
1494 # main/testing
1495 #============================================================
1496 if __name__ == '__main__':
1497
1498 if len(sys.argv) == 1:
1499 sys.exit()
1500
1501 if sys.argv[1] != 'test':
1502 sys.exit()
1503
1504 import datetime
1505
1506 gmI18N.activate_locale()
1507 gmI18N.install_domain()
1508 gmDateTime.init()
1509
1510 #--------------------------------------------------------
1512
1513 ident = cIdentity(1)
1514 print "setting active patient with", ident
1515 set_active_patient(patient=ident)
1516
1517 patient = cPatient(12)
1518 print "setting active patient with", patient
1519 set_active_patient(patient=patient)
1520
1521 pat = gmCurrentPatient()
1522 print pat['dob']
1523 #pat['dob'] = 'test'
1524
1525 staff = cStaff()
1526 print "setting active patient with", staff
1527 set_active_patient(patient=staff)
1528
1529 print "setting active patient with -1"
1530 set_active_patient(patient=-1)
1531 #--------------------------------------------------------
1533 dto = cDTO_person()
1534 dto.firstnames = 'Sepp'
1535 dto.lastnames = 'Herberger'
1536 dto.gender = 'male'
1537 dto.dob = pyDT.datetime.now(tz=gmDateTime.gmCurrentLocalTimezone)
1538 print dto
1539
1540 print dto['firstnames']
1541 print dto['lastnames']
1542 print dto['gender']
1543 print dto['dob']
1544
1545 for key in dto.keys():
1546 print key
1547 #--------------------------------------------------------
1553 #--------------------------------------------------------
1555 staff = cStaff()
1556 provider = gmCurrentProvider(provider = staff)
1557 print provider
1558 print provider.inbox
1559 print provider.inbox.messages
1560 print provider.database_language
1561 tmp = provider.database_language
1562 provider.database_language = None
1563 print provider.database_language
1564 provider.database_language = tmp
1565 print provider.database_language
1566 #--------------------------------------------------------
1568 # create patient
1569 print '\n\nCreating identity...'
1570 new_identity = create_identity(gender='m', dob='2005-01-01', lastnames='test lastnames', firstnames='test firstnames')
1571 print 'Identity created: %s' % new_identity
1572
1573 print '\nSetting title and gender...'
1574 new_identity['title'] = 'test title';
1575 new_identity['gender'] = 'f';
1576 new_identity.save_payload()
1577 print 'Refetching identity from db: %s' % cIdentity(aPK_obj=new_identity['pk_identity'])
1578
1579 print '\nGetting all names...'
1580 for a_name in new_identity.get_names():
1581 print a_name
1582 print 'Active name: %s' % (new_identity.get_active_name())
1583 print 'Setting nickname...'
1584 new_identity.set_nickname(nickname='test nickname')
1585 print 'Refetching all names...'
1586 for a_name in new_identity.get_names():
1587 print a_name
1588 print 'Active name: %s' % (new_identity.get_active_name())
1589
1590 print '\nIdentity occupations: %s' % new_identity['occupations']
1591 print 'Creating identity occupation...'
1592 new_identity.link_occupation('test occupation')
1593 print 'Identity occupations: %s' % new_identity['occupations']
1594
1595 print '\nIdentity addresses: %s' % new_identity.get_addresses()
1596 print 'Creating identity address...'
1597 # make sure the state exists in the backend
1598 new_identity.link_address (
1599 number = 'test 1234',
1600 street = 'test street',
1601 postcode = 'test postcode',
1602 urb = 'test urb',
1603 state = 'SN',
1604 country = 'DE'
1605 )
1606 print 'Identity addresses: %s' % new_identity.get_addresses()
1607
1608 print '\nIdentity communications: %s' % new_identity.get_comm_channels()
1609 print 'Creating identity communication...'
1610 new_identity.link_comm_channel('homephone', '1234566')
1611 print 'Identity communications: %s' % new_identity.get_comm_channels()
1612 #--------------------------------------------------------
1614 for pk in range(1,16):
1615 name = cPersonName(aPK_obj=pk)
1616 print name.description
1617 print ' ', name
1618 #--------------------------------------------------------
1619 #test_dto_person()
1620 #test_identity()
1621 #test_set_active_pat()
1622 #test_search_by_dto()
1623 #test_staff()
1624 test_current_provider()
1625 #test_name()
1626
1627 #map_gender2salutation('m')
1628 # module functions
1629 #genders, idx = get_gender_list()
1630 #print "\n\nRetrieving gender enum (tag, label, weight):"
1631 #for gender in genders:
1632 # print "%s, %s, %s" % (gender[idx['tag']], gender[idx['l10n_label']], gender[idx['sort_weight']])
1633
1634 #comms = get_comm_list()
1635 #print "\n\nRetrieving communication media enum (id, description): %s" % comms
1636
1637 #============================================================
1638
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Oct 1 04:06:20 2010 | http://epydoc.sourceforge.net |