gnumed-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnumed-devel] new gmDemographicRecord


From: Ian Haywood
Subject: [Gnumed-devel] new gmDemographicRecord
Date: Wed, 15 Dec 2004 14:39:25 +1100
User-agent: Mozilla Thunderbird 0.8 (X11/20041012)

I have rewritten a lot of gmDemographicRecord, this is to improve speed by caching and using few big queries, also it makes the interface look more like cClinItem.

This is not fully tested, I just want comments on the general design.

Ian
"""GnuMed demographics object.

This is a patient object intended to let a useful client-side
API crystallize from actual use in true XP fashion.

license: GPL
"""
#============================================================
# $Source: 
/cvsroot/gnumed/gnumed/gnumed/client/business/gmDemographicRecord.py,v $
# $Id: gmDemographicRecord.py,v 1.54 2004/08/18 09:05:07 ncq Exp $
__version__ = "$Revision: 1.54 $"
__author__ = "K.Hilbert <address@hidden>, I.Haywood"

# access our modules
import sys, os.path, time, string

from Gnumed.pycommon import gmLog, gmExceptions, gmPG, gmSignals, gmDispatcher, 
gmMatchProvider, gmI18N
from Gnumed.business import gmMedDoc
from Gnumed.pycommon.gmPyCompat import *

_log = gmLog.gmDefLog
_log.Log(gmLog.lInfo, __version__)

# 3rd party
import mx.DateTime as mxDT


#============================================================
# map gender abbreviations in a GnuMed demographic service
# to a meaningful localised string
map_gender_gm2long = {
        'm': _('male'),
        'f': _('female'),
        'tf': _('transsexual, female phenotype'),
        'tm': _('transsexual, male phenotype')
}

#============================================================
class cCoreDemoObject_SQL:
        """This is the analogue of cClinIem
        """
        
        def __init__(self, aPKey = None, aRow = None):
                """Fails if

                - no connection to database possible
                - patient referenced by aPKey does not exist
                """
                self.__cache = {}
                if aPKey:
                        aRow = self._get_row (aPKey)
                        if aRow is None:
                                raise gmExceptions.ConstructorError, "no 
patient with ID [%s] in database" % aPKey
                if aRow:
                        i = 0
                        for idx in self._idx:
                                self.__cache[idx] = aRow[i]
                                i += 1
                        self.__to_commit = []
                        self.__to_update = []
                        self.__cache['pk'] = self.__cache['id']
                        self.is_new = 0
                        _log.Log(gmLog.lData, 'instantiated from backend object 
table %s ID %s' % (self._table, self.__cache['id']))
                else:
                        # new object
                        self.__cache['id'] = "(select curr_val ('%s_id_seq'))" 
% self._table
                        self.is_new = 1
                        _log.Log(gmLog.lData, 'created backend demographic 
object %s ID %s' % (self._table, self.__cache['id']))
        #--------------------------------------------------------
        def cleanup(self):
                """Do cleanups before dying.

                - note that this may be called in a thread
                """
                _log.Log(gmLog.lData, 'cleaning up after patient [%s]' % 
self.ID)
                # FIXME: unlisten from signals etc.
        #--------------------------------------------------------
        # internal helper
        #--------------------------------------------------------
        def _get_row(self, key):
                """Return the database row for core data
                """
                cmd = "select %s from %s where id = %%s" % (string.join 
(self._idx, ","), self._view)
                res = gmPG.run_ro_query('personalia', cmd, None, key)
                if not res:
                        _log.Log(gmLog.lErr, 'check for person ID [%s] 
existence failed' % key)
                        return None
                return res[0]
        #--------------------------------------------------------
        # messaging
        #--------------------------------------------------------
        def _register_interests(self):
                # backend
                self._backend.Listen(
                        service = 'personalia',
                        signal = '"%s.%s"' % (gmSignals.patient_modified(), 
self.ID),
                        callback = self._patient_modified
                )
        #--------------------------------------------------------
        def _patient_modified(self):
                # <DEBUG>
                _log.Log(gmLog.lData, "patient_modified signal received from 
backend")
                # </DEBUG>
        #--------------------------------------------------------
        # core API
        #--------------------------------------------------------
        def __getitem__ (self, key):
                if self.__cache.has_key (key):
                        return self.__cache[key]
                else:
                        func = getattr (self, "get_%s" % key)
                        self.__cache[key] = func ()
                        return self.__cache[key]
        #-----------------------------------------------------------
        def __setitem__ (self, key, val):
                if key in self._updateable_fields:
                        self.to_update.append ((key, val))
                        self.__cache[key] = val
                else:
                        func = getattr (self, "set_%s" % key, None)
                        if func is None:
                                raise KeyError
                        if type (val) is types.TupleType:
                                func (*val)
                        else:
                                func (val)
        #-----------------------------------------------------------
        def save_payload (self):
                if self.is_new:
                        cmd = "insert into %s (%s) values (%s)" % (self._table, 
string.join ([key for key, val in self.to_update], ","), string.join ([val for 
key, val in self.to_update], ","))
                else:
                        cmd = "update %s set %s where id = %%s" % (string.join 
(["%s=%%s" % key for key, val in self.to_update], ","), self._table)
                args = [val for key, val in self.to_update]
                args.append (self.__cache['id'])
                self.to_commit.append ((cmd, args))
                if self.is_new:
                        post_insert = []
                        for i in range (0, len (self.to_commit)-1):
                                x = 0
                                # grab all the commands which refer to our id 
                                for j in range (0, len (self.to_commit[i][1])):
                                        if self._table in 
self.to_commit[i][1][j]:
                                                x = 1
                                if x:
                                        post_insert.append (self.to_commit[i])
                                        # remove this command from the list
                                        del self.to_commit[i]
                        # and put then *after* the insert added above
                        self.to_commit.extend (post_insert)
                        self.to_commit.append (("select curr_val ('%s_id_seq')" 
% self._table, []))
                        result, data = gmPG.run_commit2 ('personalia', 
self.to_commit)
                        if result:
                                self.__cache['id'] = data[0][0]
                else:
                        result, data = gmPG.run_commit2 ('personalia', 
self.to_commit)
                return (result, data)
        #------------------------------------------------------------
        def delete (self):
                cmd = "delete from %s where id = %%s" % self._table
                self.to_commit.append ((cmd,[self.__cache['id']]))
        #------------------------------------------------------------
#===================================================================
class cAddress (cCoreDemoObject_SQL):
        _table = "v_basic_address"
        _view = "v_basic_address"
        _updateable_fields = ['number', 'street2', 'street', 'city', 
'postcode', 'state']
        _idx = ['id', 'number', 'street2', 'street', 'city', 'postcode', 
'state']
        #-------------------------------------------------------------
        def set_type (self, typ):
                self.__cache['type'] = typ
        #-------------------------------------------------------------
        def __init__ (self, aPKey = None, aRow = None):
                cCoreDemoObject_SQL.__init__ (aPkey, aRow)
                if aRow and len (aRow) == 8:
                        # add in type even though its not part of our backend 
table
                        self.__cache['type'] = aRow[7]
        #-------------------------------------------------------------
        def __str__ (self):
                return _("%(number)s %(street)s, %(urb)s %(postcode)s") % self
#===================================================================
class cComm (cCoreDemoObject_SQL):
        _table = "comm_channel"
        _view = "comm_channel"
        _idx = ["id", "id_type", "url"]
        _updateable_fields = ["url", "id_type"]
#===================================================================
class cOrg (cCoreDemoObject_SQL):
        """
        Organisations

        This is also the common anscestor of cPerson, self._table is used to
        hide the difference.
        The aim is to be able to sanely write code which doesn't care whether
        its talking to an organisation or an individual"""
        _table = "org"
        _view = "org"
        _idx = ["id_category", "description"]
        #------------------------------------------------------------------
        def export_demographics (self):
                if not self.__cache.has_key ('addresses'):
                        self['addresses']
                if not self.__cache.has_key ('comms'):
                        self['comms']
                return self.__cache
        #------------------------------------------------------------------
        def get_addresses (self):
                """Returns a list of cAddress objects"""
                cmd = """select
                                vba.addr_id,
                                vba.number,
                                vba.addendum, 
                                vba.street,
                                vba.city,
                                vba.postcode,
                                at.type
                        from
                                v_basic_address vba,
                                lnk_person_org_address lpoa,
                                address_type at
                        where
                                lpoa.id_address = vba.addr_id
                                and lpoa.id_type = at.id
                                and lpoa.id_%s = %%s  -- double %% lets us 
survive 
                                """ % self._table     # this operator, then 
passed to SQL layer
                rows, idx = gmPG.run_ro_query('personalia', cmd, 1, self['id'])
                if rows is None:
                        return []
                elif len(rows) == 0:
                        return []
                else:
                        return [cAddress (i) for i in rows]
        #--------------------------------------------------------------------
        def get_members (self):
                """
                Returns a list of (cAddress, cPerson) tuples 
                """
                cmd = """select
                                vba.addr_id,
                                vba.number,
                                vba.addendum, 
                                vba.street,
                                vba.city,
                                vba.postcode,
                                at.type,
                                vbp.i_id,
                                vbp.title,
                                vbp.firstnames,
                                vbp.lastnames,
                                vbp.dob,
                                vbp.cob,
                                vbp.gender
                        from
                                v_basic_address vba,
                                lnk_person_org_address lpoa,
                                address_type at,
                                v_basic_person vbp
                        where
                                lpoa.id_address = vba.addr_id
                                and lpoa.id_type = at.id
                                and lpoa.id_identity = vbp.i_id
                                and lpoa.id_org = %%s
                                """
                rows, idx = gmPG.run_ro_query('personalia', cmd, 1, self['id'])
                if rows is None:
                        return []
                elif len(rows) == 0:
                        return []
                else:
                        return [(cAddress (i[:7]), cPerson (i[7:])) for i in 
rows]      
        #-------------------------------------------------------
        def get_names (self):
                """
                Conscious imitation of cPerson.
                """
                return self.__cache['description']
        #------------------------------------------------------------
        def set_member (self, person, address):
                """
                Binds a person to this organisation at this address
                """
                cmd = "insert into lnk_person_org_address ((select id from 
address_type where type = %s), id_address, id_org, id_identity) values (%s, %s, 
%s, %s)"
                self.to_commit.append ((cmd, [address['type'], address['id'], 
self.__cache['id'], person['id']]))
        #------------------------------------------------------------
        def unlink_person (self, person):
                cmd = "delete from lnk_person_org_address where id_org = %s and 
id_identity = %s"
                self.to_commit.append ((cmd, [self.__cache['id'], 
person['id']]))
        #------------------------------------------------------------
        def unlink_address (self, address):
                cmd = "delete from lnk_person_org_address where id_address = %s 
and id_%s = %%s" % self._table
                self.to_commit.append ((cmd, [address['id'], 
self.__cache['id']]))
        #------------------------------------------------------------
        def get_ext_ids (self):
                """
                Returns a list of dictionaries of external IDs
                Fields:
                - origin [the origin code as returned by getExternalIDTypes]
                - comment [a user comment]
                - external_id [the actual external ID]
                """
                cmd = "select fk_origin, comment, external_id from 
lnk_%s2ext_id where id_%s = %%s" % (self._table, self._table)
                rows = gmPG.run_ro_query ('personalia', cmd, None, 
self.__cache['id'])
                if rows is None:
                        return []
                return [{'origin':row[0], 'comment':row[1], 
'external_id':row[2]} for row in rows]
        #----------------------------------------------------------------
        def set_ext_id (self, fk_origin, ext_id, comment=None):
                """
                Set ext_id to None to delete an external id
                Remember comment matters if you have several IDs on one origin
                [which is legal in AU, remember I have 5 provider numbers -- IH]
                """
                if comment:
                        cmd = """delete from lnk_%s2ext_id where
                        id_%s = %%s and fk_origin = %%s
                        and comment = %%s""" % (self._table, self._table)
                        self.to_commit.append ((cmd, [self.__cache['id'], 
fk_origin, comment]))
                else:
                        cmd = """delete from lnk_%s2ext_id where
                        id_%s = %%s and fk_origin = %%s""" % (self._table, 
self._table)
                        self.to_commit.append ((cmd, [self.__cache['id'], 
fk_origin]))
                if ext_id:
                        cmd = """insert into lnk_%s2ext_id (id_%s, fk_origin, 
comment)
                        values (%%s, %%s, %%s)""" % (self._table, self._table)
                        self.to_commit.append ((cmd, [self.__cache['id'], 
ext_id, comment]))
        #-------------------------------------------------------        
        def get_comms (self):
                """A list of cComm objects"""
                cmd = """select
                                cc.id,
                                cc.id_type,
                                cc.url
                        from
                                comm_channel cc,
                                lnk_%s_comm_channel lcc
                        where
                                lcc.id_%s = %%s and
                                lcc.id_comm_channel = cc.id
                                """ (self._table, self._table)
                rows, idx = gmPG.run_ro_query('personalia', cmd, 1, self['id'])
                if rows is None:
                        return []
                elif len(rows) == 0:
                        return []
                else:
                        return [cComm (i) for i in rows]
        #--------------------------------------------------------------
        def set_comm (self, comm):
                """
                adds a new cComm object
                """
                cmd = """insert into lnk_%s_comm_chan (id_%s, id_comm_chan) 
values (%%s, %%s)
                """ % (self._table, self._table)
                self.to_commit.append ((cmd,[self.__cache[id], comm['id']]))
        #---------------------------------------------------------------
        def unlink_comm (self, comm):
                cmd = "delete lnk_%s_comm_chan where id_%s = %%s and 
id_comm_chan = %%s" % (self._table, self._table)
                self.to_commit.append ((cmd,[self.__cache[id], comm['id']]))
#==============================================================================
class cPerson (cOrg):
        _table = "identity"
        _view = "v_basic_person"
        _idx = ["id", "title", "firstnames", "lastnames", "dob", "cob", 
"gender"]
        _updateable_fields = ["title", "dob", "cob", "gender"]  
        #--------------------------------------------------------
        def get_names(self, all =False):
                if all:
                        cmd = """
                                select n.firstnames, n.lastnames, i.title
                                from names n, identity i
                                where n.id_identity=%s and i.id=%s"""
                else:
                        return {'first': self.__cache['firstnames'], 'last': 
self.__cache['lastnames'], 'title': self.__cache['title']}
                rows, idx = gmPG.run_ro_query('personalia', cmd, 1, 
self._cache['id'], self.__cache['id'])
                if rows is None:
                        return None
                if len(rows) == 0:
                        return [{'first': '**?**', 'last': '**?**', 'title': 
'**?**'}]
                else:
                        names = []
                        for row in rows:
                                names.append({'first': row[0], 'last': row[1], 
'title': row[2]})
                        return names
        #--------------------------------------------------------
        def set_names(self, firstnames, lastnames, active=True):
                """Add a name """
                cmd = "select add_name(%s, %s, %s, %s)"
                active = (active and 't') or 'f'
                self.to_commit.append ((cmd, [self.__cache['id'], firstnames, 
lastnames, active]))
                self.__cache['firstnames'] = firstnames
                self.__cache['lastnames'] = lastnames
        #------------------------------------------------------------
        def set_address (self, address):
                """
                Binds an address to this person
                """
                cmd = "insert into lnk_person_org_address ((select id from 
address_types where type = %s), id_address, id_identity) values (%s, %s, %s)"
                self.to_commit.append ((cmd, [address['type'], address['id'], 
self.__cache['id']]))
        #----------------------------------------------------------------------
        def get_marital_status (self):
                cmd = "select name from marital_status, identity where 
marital_status.id = identity.id_marital_status and identity.id = %s"
                data = gmPG.run_ro_query ('personalia', cmd, None, 
self.__cache['id'])
                return data and data[0][0]
        #--------------------------------------------------------------------
        def set_marital_status (self, status):
                cmd = "update identity set id_marital_status = (select id from 
marital_status where name = %s) where id = %s"
                self.to_commit.append ((cmd, [status, self.__cache['id']]))
        #---------------------------------------------------------------------
        def get_occupation (self):
                """
                Currently we do not support more than one occupation
                """
                cmd = "select o.name from occupation o, lnk_job2person lj2p 
where o.id = lj2p.id_occupation and lj2p.id_identity = %s"
                data = gmPG.run_ro_query ('personalia', cmd, None, self.ID)
                return data and data[0][0]
        #--------------------------------------------------------------------
        def set_occupation (self, occupation):
                # does occupation already exist ?
                cmd = "select o.id from occupation o where o.name = %s"
                data = gmPG.run_ro_query ('personalia', cmd, None, occupation)
                # error
                if data is None:
                        gmLog.gmDefLog.Log(gmLog.lErr, 'cannnot check for 
occupation')
                        return None
                # none found
                if len(data) == 0:
                        (cmd1, [occupation])
                # delete pre-existing link as required
                cmd1 = """
                delete from
                        lnk_job2person
                where
                        id_identity = %s"""
                # creating new link
                cmd2 = """insert into lnk_job2person (id_identity, 
id_occupation) values (%s, (select currval('occupation_id_seq')))"""
                self.to_commit.extend([
                        (cmd1, [self.__cache['id']]),
                        (cmd2, [self.__cache['id'], id_occupation])
                ])
        #----------------------------------------------------------------------
        def get_relatives(self):
                cmd = """
select
        t.description, v.i_id, v.title, v.firstnames, v.lastnames, v.dob, 
v.cob, v.gender
from
        v_basic_person v, relation_types t, lnk_person2relative l
where
        l.id_identity = %s and
        v.id = l.id_relative and
        t.id = l.id_relation_type
"""
                data, idx = gmPG.run_ro_query('personalia', cmd, 1, 
self.__cache['id'])
                if data is None:
                        return []
                if len(data) == 0:
                        return []
                return [(r[0], cPerson (r[1:])) for r in data ]
        #--------------------------------------------------------
        def set_relative(self, rel_type, relation):
                # and link the two
                cmd = """
                        insert into lnk_person2relative (
                                id_identity, id_relative, id_relation_type
                        ) values (
                                %s, %s, (select id from relation_types where 
description = %s)
                        )"""
                self.to_commit.append ((cmd, [relation['id'], 
self.__cache['id'], rel_type]))
                if success:
                        return relative_demographics
                return None
        #----------------------------------------------------------------------
        def get_medical_age(self):
                dob = self.__cache['dob']
                if dob is None:
                        return '??'
                return dob2medical_age(dob)
        #----------------------------------------------------------------------
#================================================================
# convenience functions
#================================================================
def dob2medical_age(dob):
        """format patient age in a hopefully meaningful way"""

        age = mxDT.Age(mxDT.now(), dob)

        if age.years > 0:
                return "%sy%sm" % (age.years, age.months)
        weeks = age.days / 7
        if weeks > 4:
                return "%sm%sw" % (age.months, age.weeks)
        if weeks > 1:
                return "%sd" % age.days
        if age.days > 1:
                return "%sd (%sh)" % (age.days, age.hours)
        if age.hours > 3:
                return "%sh" % age.hours
        if age.hours > 0:
                return "%sh%sm" % (age.hours, age.minutes)
        if age.minutes > 5:
                return "%sm" % (age.minutes)
        return "%sm%ss" % (age.minutes, age.seconds)
#----------------------------------------------------------------
def getAddressTypes():
        """Gets a simple list of address types."""
        row_list = gmPG.run_ro_query('personalia', "select name from 
address_type")
        if row_list is None:
                return []
        if len(row_list) == 0:
                return []
        return [row[0] for row in row_list]
#----------------------------------------------------------------
def getMaritalStatusTypes():
        """Gets a simple list of types of marital status."""
        row_list = gmPG.run_ro_query('personalia', "select name from 
marital_status")
        if row_list is None:
                return []
        if len(row_list) == 0:
                return []
        return [row[0] for row in row_list]
#------------------------------------------------------------------
def getExtIDTypes (context = 'p'):
        """Gets list of [code, ID type] from the backend for the given context
        """
        # FIXME: error handling
        rl = gmPG.run_ro_query('personalia', "select pk, name from 
enum_ext_id_types where context = %s", None, context)
        if rl is None:
                return []
        return rl
#----------------------------------------------------------------
def getCommChannelTypes():
        """Gets the dictionary of ID->comm channels"""
        row_list = gmPG.run_ro_query('personalia', "select id, description from 
enum_comm_types")
        if row_list is None:
                return None
        if len (row_list) == 0:
                return None
        return dict(row_list)

EMAIL=1
FAX=2
HOME_PHONE=3
WORK_PHONE=4
MOBILE=5
WEB=6
JABBER=7
#----------------------------------------------------------------

def guess_state_country( urb, postcode):
        """parameters are urb.name, urb.postcode;
           outputs are urb.id_state,  country.code"""

        cmd = """
select state.code, state.country
from urb, state
where
        lower(urb.name) = lower(%s) and
        upper(urb.postcode) = upper(%s) and
        urb.id_state = state.id
"""
        data = gmPG.run_ro_query ('personalia', cmd, None,  urb, postcode)
        if data is None:
                return "", ""
        if len(data) == 0:
                return '', ''
        return data[0]
#----------------------------------------------------------------
def getPostcodeForUrbId(urb_id):
        # FIXME: get from views
        cmd = "select postcode from urb where id = %s"
        data = gmPG.run_ro_query ('personalia', cmd, None, urb_id)
        if data is None:
                _log.Log(gmLog.lErr, 'cannot get postcode for urb [%s]' % 
urb_id)
                return None
        if len(data) == 0:
                return ''
        return data[0][0]
#----------------------------------------------------------------
def getUrbsForPostcode(pcode=None):
        cmd = "select name from urb where postcode=%s"
        data = gmPG.run_ro_query('personalia', cmd, None, pcode)
        if data is None:
                _log.Log(gmLog.lErr, 'cannot get urbs from postcode [%s]' % 
pcode)
                return None
        if len(data) == 0:
                return []
        return [x[0] for x in data]
#----------------------------------------------------------------
class PostcodeMP (gmMatchProvider.cMatchProvider_SQL):
        """Returns a list of valid postcodes,
        Accepts two contexts : "urb" and "street" being the **IDs** of urb and 
street
        """
        def __init__ (self):
                # we search two tables here, as in some jurisdictions (UK, 
Germany, US)
                # postcodes are tied to streets or small groups of streets,
                # and in others (Australia) postcodes refer to an entire town

                # reviewers' comments:
                # - pk this will be the data return to the id_callback() 
function passed 
                #   as  gmPhrasewheel.__init__ last parameter , so the event 
data  will be 
                #   the postcode for urb or street , not the id of those tables.
                #   This is in the cMatchProvider.__findMatches code.

                source = [{
                        'column':'postcode',
                        'pk':'postcode',
                        'limit':10,
                        'table':'urb',
                        'extra conditions':{'urb':'id = %s', 
'default':'postcode is not null'}
                        , 'service': 'personalia'
                        },{
                        'column':'postcode',
                        'table':'street',
                        'limit':10,
                        'pk':'postcode',
                        'extra conditions':{'urb':'id_urb = %s', 'street': 'id 
= %s', 'default':'postcode is not null'}
                        , 'service': 'personalia'
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__(self, source)
                        
#----------------------------------------------------------------
class StreetMP (gmMatchProvider.cMatchProvider_SQL):
        """Returns a list of streets

        accepts "urb" and "postcode" contexts  
                e.g.
                        using cMatchProvider_SQL's  self.setContext("urb",...) 
                                        
        """
        def __init__ (self):
                source = [{
                        'service': 'personlia',
                        'table': 'street',
                        'column': 'name',
                        'limit': 10,
                        'extra conditions': {
                                'urb': 'id_urb = %s',
                                'postcode': 'postcode = %s or postcode is null'
                                }
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__(self, source)
#------------------------------------------------------------
class MP_urb_by_zip (gmMatchProvider.cMatchProvider_SQL):
        """Returns a list of urbs

        accepts "postcode" context
        """
        def __init__ (self):
                source = [{
                        'service': 'personalia',
                        'table': 'urb',
                        'column': 'name',
                        'limit': 15,
                        'extra conditions': {'postcode': '(postcode = %s or 
postcode is null)'}
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__(self, source)

class CountryMP (gmMatchProvider.cMatchProvider_SQL):
        """
        Returns a list of countries
        """
        def __init__ (self):
                source = [{
                        'service':'personalia',
                        'table':'country',
                        'pk':'code',
                        'column':'name',
                        'limit':5
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__ (self, source)

class OccupationMP (gmMatchProvider.cMatchProvider_SQL):
        """
        Returns a list of occupations
        """
        def __init__ (self):
                source = [{
                        'service':'personalia',
                        'table':'occupation',
                        'pk':'id',
                        'column':'name',
                        'limit':7
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__ (self, source)

class NameMP (gmMatchProvider.cMatchProvider_SQL):
        """
        List of names
        """
        def __init__ (self):
                source =[{
                        'service':'personalia',
                        'table':'names',
                        'pk':'id_identity',
                        'column':'lastnames',
                        'result':"lastnames || ', ' || firstnames || ' (' || 
dob || ')'",
                        'limit':5,
                        'extra conditions':{'occupation':'exists (select 1 from 
lnk_job2person where id_occupation = %s and lnk_job2person.id_identity = 
names.id_identity)'}
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__ (self, source)

#------------------------------------------------------------
class OrgCategoryMP (gmMatchProvider.cMatchProvider_SQL):
        """
        List of org categories.
        """
        def __init__(self):
                source = [ {
                        'service': 'personalia',
                        'table' : 'org_category',
                        'pk'    : 'id',
                        'column': 'description',
                        'result': 'description' ,
                        'limit' : 5,
                        }]
                gmMatchProvider.cMatchProvider_SQL.__init__(self, source)
#------------------------------------------------------------

#============================================================
# callbacks
#------------------------------------------------------------
def _patient_selected(**kwargs):
        print "received patient_selected notification"
        print kwargs['kwds']
#============================================================
if __name__ == "__main__":
        _log.SetAllLogLevels(gmLog.lData)
        gmDispatcher.connect(_patient_selected, gmSignals.patient_selected())
        while 1:
                pID = raw_input('a patient ID: ')
                if pID == '-1':
                        break
                try:
                        myPatient = cPerson(aPKey = pID)
                except:
                        _log.LogException('Unable to set up patient with ID 
[%s]' % pID, sys.exc_info())
                        print "patient", pID, "can not be set up"
                        continue
                print "ID       ", myPatient['id']
                print "name     ", myPatient['names']
                print "title    ", myPatient['title']
                print "dob      ", myPatient['dob']
                print "med age  ", myPatient['medical_age']
                for adr in myPatient['addresses']:
                        print "address  ", adr  
                print "--------------------------------------"
#============================================================
# $Log: gmDemographicRecord.py,v $
# Revision 1.54  2004/08/18 09:05:07  ncq
# - just some cleanup, double-check _ is defined for epydoc
#
# Revision 1.53  2004/07/26 14:34:49  sjtan
#
# numbering correction from labels in gmDemograpics.
#
# Revision 1.52  2004/06/25 12:37:19  ncq
# - eventually fix the import gmI18N issue
#
# Revision 1.51  2004/06/21 16:02:08  ncq
# - cleanup, trying to make epydoc fix do the right thing
#
# Revision 1.50  2004/06/21 14:48:25  sjtan
#
# restored some methods that gmContacts depends on, after they were booted
# out from gmDemographicRecord with no home to go , works again ;
# removed cCatFinder('occupation') instantiating in main module scope
# which was a source of complaint , as it still will lazy load anyway.
#
# Revision 1.49  2004/06/20 15:38:00  ncq
# - remove import gettext/_ = gettext.gettext
# - import gmI18N handles that if __main__
# - else the importer of gmDemographicRecord has
#   to handle setting _
# - this is the Right Way as per the docs !
#
# Revision 1.48  2004/06/20 06:49:21  ihaywood
# changes required due to Epydoc's OCD
#
# Revision 1.47  2004/06/17 11:36:12  ihaywood
# Changes to the forms layer.
# Now forms can have arbitrary Python expressions embedded in @..@ markup.
# A proper forms HOWTO will appear in the wiki soon
#
# Revision 1.46  2004/05/30 03:50:41  sjtan
#
# gmContacts can create/update org, one level of sub-org, org persons, sub-org 
persons.
# pre-alpha or alpha ? Needs cache tune-up .
#
# Revision 1.45  2004/05/29 12:03:47  sjtan
#
# OrgCategoryMP for gmContact's category field
#
# Revision 1.44  2004/05/28 15:05:10  sjtan
#
# utility functions only called with exactly 2 args in order to fulfill 
function intent, but do some checking for invalid args.
#
# Revision 1.43  2004/05/26 12:58:14  ncq
# - cleanup, error handling
#
# Revision 1.42  2004/05/25 16:18:13  sjtan
#
# move methods for postcode -> urb interaction to gmDemographics so gmContacts 
can use it.
#
# Revision 1.41  2004/05/25 16:00:34  sjtan
#
# move common urb/postcode collaboration  to business class.
#
# Revision 1.40  2004/05/19 11:16:08  sjtan
#
# allow selecting the postcode for restricting the urb's picklist, and resetting
# the postcode for unrestricting the urb picklist.
#
# Revision 1.39  2004/04/15 09:46:56  ncq
# - cleanup, get_lab_data -> get_lab_results
#
# Revision 1.38  2004/04/11 10:15:56  ncq
# - load title in get_names() and use it superceding getFullName
#
# Revision 1.37  2004/04/10 01:48:31  ihaywood
# can generate referral letters, output to xdvi at present
#
# Revision 1.36  2004/04/07 18:43:47  ncq
# - more gender mappings
# - *comm_channel -> comm_chan
#
# Revision 1.35  2004/03/27 04:37:01  ihaywood
# lnk_person2address now lnk_person_org_address
# sundry bugfixes
#
# Revision 1.34  2004/03/25 11:01:45  ncq
# - getActiveName -> get_names(all=false)
# - export_demographics()
#
# Revision 1.33  2004/03/20 19:43:16  ncq
# - do import gmI18N, we need it
# - gm2long_gender_map -> map_gender_gm2long
# - gmDemo* -> cDemo*
#
# Revision 1.32  2004/03/20 17:53:15  ncq
# - cleanup
#
# Revision 1.31  2004/03/15 15:35:45  ncq
# - optimize getCommChannel() a bit
#
# Revision 1.30  2004/03/10 12:56:01  ihaywood
# fixed sudden loss of main.shadow
# more work on referrals,
#
# Revision 1.29  2004/03/10 00:09:51  ncq
# - cleanup imports
#
# Revision 1.28  2004/03/09 07:34:51  ihaywood
# reactivating plugins
#
# Revision 1.27  2004/03/04 10:41:21  ncq
# - comments, cleanup, adapt to minor schema changes
#
# Revision 1.26  2004/03/03 23:53:22  ihaywood
# GUI now supports external IDs,
# Demographics GUI now ALPHA (feature-complete w.r.t. version 1.0)
# but happy to consider cosmetic changes
#
# Revision 1.25  2004/03/03 05:24:01  ihaywood
# patient photograph support
#
# Revision 1.24  2004/03/02 10:21:09  ihaywood
# gmDemographics now supports comm channels, occupation,
# country of birth and martial status
#
# Revision 1.23  2004/02/26 17:19:59  ncq
# - setCommChannel: arg channel -> channel_type
# - setCommChannel: we need to read currval() within
#   the same transaction as the insert to get consistent
#   results
#
# Revision 1.22  2004/02/26 02:12:00  ihaywood
# comm channel methods
#
# Revision 1.21  2004/02/25 09:46:20  ncq
# - import from pycommon now, not python-common
#
# Revision 1.20  2004/02/18 15:26:39  ncq
# - fix dob2medical_age()
#
# Revision 1.19  2004/02/18 06:36:04  ihaywood
# bugfixes
#
# Revision 1.18  2004/02/17 10:30:14  ncq
# - enhance GetAddresses() to return all types if addr_type is None
#
# Revision 1.17  2004/02/17 04:04:34  ihaywood
# fixed patient creation refeential integrity error
#
# Revision 1.16  2004/02/14 00:37:10  ihaywood
# Bugfixes
#       - weeks = days / 7
#       - create_new_patient to maintain xlnk_identity in historica
#
# Revision 1.15  2003/12/01 01:01:41  ncq
# - get_medical_age -> dob2medical_age
#
# Revision 1.14  2003/11/30 01:06:21  ncq
# - add/remove_external_id()
#
# Revision 1.13  2003/11/23 23:32:01  ncq
# - some cleanup
# - setTitle now works on identity instead of names
#
# Revision 1.12  2003/11/23 14:02:40  sjtan
#
# by setting active=false first, then updating values, side effects from 
triggers can be avoided; see also
# F_active_name trigger function in server sql script,which fires only if 
new.active = true .
#
# Revision 1.11  2003/11/22 14:44:17  ncq
# - setTitle now only operates on active names and also doesn't set the name
#   to active which would trigger the trigger
#
# Revision 1.10  2003/11/22 14:40:59  ncq
# - setActiveName -> addName
#
# Revision 1.9  2003/11/22 12:53:48  sjtan
#
# modified the setActiveName and setTitle so it works as intended in the face 
of insurmountable triggers ;)
#
# Revision 1.8  2003/11/20 07:45:45  ncq
# - update names/identity, not v_basic_person in setTitle et al
#
# Revision 1.7  2003/11/20 02:10:50  sjtan
#
# remove 'self' parameter from functions moved into global module namespace.
#
# Revision 1.6  2003/11/20 01:52:03  ncq
# - actually, make that **?** for good measure
#
# Revision 1.5  2003/11/20 01:50:52  ncq
# - return '?' for missing names in getActiveName()
#
# Revision 1.4  2003/11/18 16:44:24  ncq
# - getAddress -> getAddresses
# - can't verify mxDateTime bug with missing time tuple
# - remove getBirthYear, do getDOB() -> mxDateTime -> format
# - get_relative_list -> get_relatives
# - create_dummy_relative -> link_new_relative
# - cleanup
#
# Revision 1.3  2003/11/17 10:56:34  sjtan
#
# synced and commiting.
#
# Revision 1.2  2003/11/04 10:35:22  ihaywood
# match providers in gmDemographicRecord
#
# Revision 1.1  2003/11/03 23:59:55  ncq
# - renamed to avoid namespace pollution with plugin widget
#
# Revision 1.6  2003/10/31 23:21:20  ncq
# - remove old history
#
# Revision 1.5  2003/10/27 15:52:41  ncq
# - if aFormat is None in getDOB() return datetime object, else return 
formatted string
#
# Revision 1.4  2003/10/26 17:35:04  ncq
# - conceptual cleanup
# - IMHO, patient searching and database stub creation is OUTSIDE
#   THE SCOPE OF gmPerson and gmDemographicRecord
#
# Revision 1.3  2003/10/26 16:35:03  ncq
# - clean up as discussed with Ian, merge conflict resolution
#
# Revision 1.2  2003/10/26 11:27:10  ihaywood
# gmPatient is now the "patient stub", all demographics stuff in gmDemographics.
#
# Ergregious breakages are fixed, but needs more work
#
# Revision 1.1  2003/10/25 08:48:06  ihaywood
# Split from gmTmpPatient
#



# old gmTmpPatient log
# Revision 1.41  2003/10/19 10:42:57  ihaywood
# extra functions
#
# Revision 1.40  2003/09/24 08:45:40  ihaywood
# NewAddress now functional
#
# Revision 1.39  2003/09/23 19:38:03  ncq
# - cleanup
# - moved GetAddressesType out of patient class - it's a generic function
#

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]