Source code for lib_openmolar.client.db_orm.client_patient

#! /usr/bin/env python
# -*- coding: utf-8 -*-

###############################################################################
##                                                                           ##
##  Copyright 2010, Neil Wallace <rowinggolfer@googlemail.com>               ##
##                                                                           ##
##  This program is free software: you can redistribute it and/or modify     ##
##  it under the terms of the GNU General Public License as published by     ##
##  the Free Software Foundation, either version 3 of the License, or        ##
##  (at your option) any later version.                                      ##
##                                                                           ##
##  This program is distributed in the hope that it will be useful,          ##
##  but WITHOUT ANY WARRANTY; without even the implied warranty of           ##
##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            ##
##  GNU General Public License for more details.                             ##
##                                                                           ##
##  You should have received a copy of the GNU General Public License        ##
##  along with this program.  If not, see <http://www.gnu.org/licenses/>.    ##
##                                                                           ##
###############################################################################

'''
This module provides the PatientDB Class
(for client interaction with records in the patients table)
'''

from PyQt4 import QtCore, QtSql

from lib_openmolar.common.datatypes import EditableField

from lib_openmolar.common import common_db_orm

TABLENAME = "patients"

[docs]class PatientNotFoundError(Exception): pass
[docs]class DuckPatient(object): ''' a duck type of the Patient Record '''
[docs] def __init__(self): #: self.patient_id = None #: self.title = "" #: self.last_name = "" #: self.first_name = "" #: self.preferred_name = "" #: self.correspondence_name = "" #: self.sex = "M" #: self.dob = QtCore.QDate(1900,1,1) #: self.status = "Active" #: self.modified_by = "" #: self.time_stamp = None
@property
[docs] def full_name(self): ''' returns the :attr:`correspondence_name` (if it exists) or "%s %s %s"% (title, fname, sname) .. note:: appends the :attr:`preferred_name` (if it exists) ''' if self.correspondence_name != "": return self.correspondence_name fn = u'%s %s %s'% (self.title, self.first_name, self.last_name) if self.preferred_name: fn = u'%s "%s"'% (fn, self.preferred_name) return fn
def __repr__(self): return u"patient - %s"% self.full_name
[docs]class PatientDB(QtSql.QSqlRecord):
[docs] def __init__(self, patient_id): #: self.patient_id = patient_id query = 'SELECT * from %s WHERE ix = ?'% TABLENAME q_query = QtSql.QSqlQuery(SETTINGS.psql_conn) q_query.prepare(query) q_query.addBindValue(patient_id) q_query.exec_() if not q_query.next(): raise PatientNotFoundError else: record = q_query.record() QtSql.QSqlQuery.__init__(self, record) ## make a copy (a marker of database state) self.orig = QtSql.QSqlRecord() QtSql.QSqlQuery.__init__(self.orig, record)
@property
[docs] def is_dirty(self): return self != self.orig
[docs] def commit_changes(self): if not self.is_dirty: return changes, values = "", [] for i in range(self.count()): if self.field(i) != self.orig.field(i): changes += "%s = ?,"% self.field(i).name() values.append(self.field(i).value()) changes = changes.rstrip(",") query = "UPDATE %s set %s WHERE ix=?"% (TABLENAME, changes) q_query = QtSql.QSqlQuery(SETTINGS.psql_conn) q_query.prepare(query) for value in values+[self.patient_id]: q_query.addBindValue(value) q_query.exec_() if not q_query.lastError().isValid(): return True else: print q_query.lastError().text() SETTINGS.psql_conn.emit_caught_error(q_query.lastError())
@property
[docs] def full_name(self): correspondence_name = self.value('correspondence_name').toString() if correspondence_name != "": return correspondence_name fn = u"%s %s %s"% (self.value('title').toString(), self.value('first_name').toString(), self.value('last_name').toString()) preferred = self.value('preferred_name').toString() if preferred != "": fn = u'%s<br />"%s"'% (fn, preferred) return fn.title()
[docs] def details_html(self): html = u'''<div><a href="edit_pt">%s</a>Patient %d<br /><b>%s</b><br /> %s %s</div>'''% (SETTINGS.PENCIL, self.value('ix').toInt()[0], self.full_name, self.value('dob').toDate().toString(SETTINGS.QDATE_FORMAT), self._display_age) status = unicode(self.value('status').toString()) if status != "active": html += u"<h3>%s</h3>"% ( SETTINGS.OM_TYPES['pt_status'].readable_dict.get(status, "????")) return html
[docs] def age_tuple(self): ''' return the age in form (year(int), months(int), isToday(bool)) ''' dob = self.value('dob').toDate() try: today = QtCore.QDate.currentDate() nextbirthday = QtCore.QDate(today.year(), dob.month(),dob.day()) age_years = today.year() - dob.year() if nextbirthday > today: age_years -= 1 months = (12 - dob.month()) + today.month() else: months = today.month() - dob.month() if dob.day() > today.day(): months -= 1 isToday = nextbirthday == today return (age_years, months, isToday) except Exception, e: print "error calculating patient's age", e return (0,0,False)
@property def _display_age(self): ''' display the patient's age in human readable form ''' years, months, is_today = self.age_tuple() if is_today: return "<h5>%s TODAY!</h5>"% years if years > 18: return "(%syo)"% years else: retarg = "<br />%s years"% years if years == 1: retarg = retarg.strip("s") retarg += " %s months"% months if months == 1: retarg = retarg.strip("s") return retarg @property
[docs] def editable_fields(self): ''' a property called by dialogs which edit this class hence the order is important! a list of tuples. item0 in the tuple is the field name used by the db item) is the string displayed to the user. ''' sex_field = EditableField('sex', _('Sex'), True) sex_field.set_type(SETTINGS.OM_TYPES['sex']) status_field = EditableField('status', _('Status'), True) status_field.set_type(SETTINGS.OM_TYPES['pt_status']) status_field.set_advanced(True) preferred_field = EditableField( 'preferred_name', u"<i>%s</i>"% _("Preferred Name")) preferred_field.set_advanced(True) qualifications_field = EditableField( 'qualifications', u"<i>%s</i>"% _("Qualifications")) qualifications_field.set_advanced(True) return [ EditableField('title', _("Title"), required=True), EditableField('first_name', _("First Name"), True), EditableField('last_name', _("Surname"), True), preferred_field, qualifications_field, EditableField('dob', _('Date of Birth'), True), sex_field, status_field ]
[docs]class NewPatientDB(PatientDB, common_db_orm.InsertableRecord):
[docs] def __init__(self): common_db_orm.InsertableRecord.__init__(self, SETTINGS.psql_conn, TABLENAME) self.patient_id = None self.orig = None
if __name__ == "__main__": from lib_openmolar.client.connect import DemoClientConnection cc = DemoClientConnection() cc.connect() object = PatientDB(1) print object.details_html() for i in range(object.count()): field = object.field(i) print u"%s:%s"% (field.name(), field.value().toString()) print object.full_name print "dirty object?", object.is_dirty object.setValue('title', 'Ms') print "dirty object?", object.is_dirty