Source code for adt

# Part of NHClinical. See LICENSE file for full copyright and licensing details
# -*- coding: utf-8 -*-
"""
``adt.py`` defines a set of activity types to deal with patient
management systems operations.
"""
import logging
from datetime import datetime as dt

from openerp.osv import orm, fields, osv
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DTF
from openerp import SUPERUSER_ID

_logger = logging.getLogger(__name__)


[docs]class nh_clinical_adt_patient_register(orm.Model): """ Represents the patient register operation in the patient management system. (A28 Message) """ _name = 'nh.clinical.adt.patient.register' _inherit = ['nh.activity.data'] _description = 'ADT Patient Register' _gender = [['BOTH', 'Both'], ['F', 'Female'], ['I', 'Intermediate'], ['M', 'Male'], ['NSP', 'Not Specified'], ['U', 'Unknown']] _ethnicity = [ ['A', 'White - British'], ['B', 'White - Irish'], ['C', 'White - Other background'], ['D', 'Mixed - White and Black Caribbean'], ['E', 'Mixed - White and Black African'], ['F', 'Mixed - White and Asian'], ['G', 'Mixed - Other background'], ['H', 'Asian - Indian'], ['J', 'Asian - Pakistani'], ['K', 'Asian - Bangladeshi'], ['L', 'Asian - Other background'], ['M', 'Black - Caribbean'], ['N', 'Black - African'], ['P', 'Black - Other background'], ['R', 'Chinese'], ['S', 'Other ethnic group'], ['Z', 'Not stated'] ] _columns = { 'patient_id': fields.many2one('nh.clinical.patient', 'Patient'), 'patient_identifier': fields.char('NHS Number', size=10), 'other_identifier': fields.char('Hospital Number', size=50), 'family_name': fields.char('Last Name', size=200), 'given_name': fields.char('First Name', size=200), 'middle_names': fields.char('Middle Names', size=200), 'dob': fields.datetime('Date of Birth'), 'gender': fields.selection(_gender, string='Gender'), 'sex': fields.selection(_gender, string='Sex'), 'ethnicity': fields.selection(_ethnicity, string='Ethnicity'), 'title': fields.many2one('res.partner.title', 'Title') }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the patient data is correct and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ data = vals.copy() patient_pool = self.pool['nh.clinical.patient'] patient_pool.check_data(cr, uid, data, context=context) return super(nh_clinical_adt_patient_register, self).submit(
cr, uid, activity_id, data, context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Creates a new instance of :mod:`patient<base.nh_clinical_patient>` and then calls :meth:`complete<activity.nh_activity.complete>`. :returns: :mod:`patient<base.nh_clinical_patient>` id :rtype: int """ activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) patient_pool = self.pool['nh.clinical.patient'] vals = { 'title': activity.data_ref.title.id, 'patient_identifier': activity.data_ref.patient_identifier, 'other_identifier': activity.data_ref.other_identifier, 'family_name': activity.data_ref.family_name, 'given_name': activity.data_ref.given_name, 'middle_names': activity.data_ref.middle_names, 'dob': activity.data_ref.dob, 'gender': activity.data_ref.gender, 'sex': activity.data_ref.sex, 'ethnicity': activity.data_ref.ethnicity } patient_id = patient_pool.create(cr, uid, vals, context) activity_pool.write(cr, uid, activity_id, {'patient_id': patient_id}, context=context) self.write(cr, uid, activity.data_ref.id, {'patient_id': patient_id}, context=context) super(nh_clinical_adt_patient_register, self).complete( cr, uid, activity_id, context)
return patient_id
[docs]class nh_clinical_adt_patient_update(orm.Model): """ Represents the patient update operation in the patient management system. (A31 Message) """ _name = 'nh.clinical.adt.patient.update' _inherit = ['nh.activity.data'] _description = 'ADT Patient Update' _gender = [['BOTH', 'Both'], ['F', 'Female'], ['I', 'Intermediate'], ['M', 'Male'], ['NSP', 'Not Specified'], ['U', 'Unknown']] _ethnicity = [ ['A', 'White - British'], ['B', 'White - Irish'], ['C', 'White - Other background'], ['D', 'Mixed - White and Black Caribbean'], ['E', 'Mixed - White and Black African'], ['F', 'Mixed - White and Asian'], ['G', 'Mixed - Other background'], ['H', 'Asian - Indian'], ['J', 'Asian - Pakistani'], ['K', 'Asian - Bangladeshi'], ['L', 'Asian - Other background'], ['M', 'Black - Caribbean'], ['N', 'Black - African'], ['P', 'Black - Other background'], ['R', 'Chinese'], ['S', 'Other ethnic group'], ['Z', 'Not stated'] ] _columns = { 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'patient_identifier': fields.char('NHS Number', size=10), 'other_identifier': fields.char('Hospital Number', size=50), 'family_name': fields.char('Last Name', size=200), 'given_name': fields.char('First Name', size=200), 'middle_names': fields.char('Middle Names', size=200), 'dob': fields.datetime('Date of Birth'), 'gender': fields.selection(_gender, string='Gender'), 'sex': fields.selection(_gender, string='Sex'), 'ethnicity': fields.selection(_ethnicity, string='Ethnicity'), 'title': fields.many2one('res.partner.title', 'Title') }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the patient data is correct and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ data = vals.copy() patient_pool = self.pool['nh.clinical.patient'] patient_pool.check_data(cr, uid, data, create=False, context=context) return super(nh_clinical_adt_patient_update, self).submit(
cr, uid, activity_id, data, context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Overwrites the target :mod:`patient<base.nh_clinical_patient>` instance information and then calls :meth:`complete<activity.nh_activity.complete>`. :returns: ``True`` :rtype: bool """ activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) patient_pool = self.pool['nh.clinical.patient'] vals = { 'title': activity.data_ref.title.id, 'patient_identifier': activity.data_ref.patient_identifier, 'other_identifier': activity.data_ref.other_identifier, 'family_name': activity.data_ref.family_name, 'given_name': activity.data_ref.given_name, 'middle_names': activity.data_ref.middle_names, 'dob': activity.data_ref.dob, 'gender': activity.data_ref.gender, 'sex': activity.data_ref.sex, 'ethnicity': activity.data_ref.ethnicity } res = patient_pool.write( cr, uid, activity.data_ref.patient_id.id, vals, context=context) super(nh_clinical_adt_patient_update, self).complete( cr, uid, activity_id, context)
return res
[docs]class nh_clinical_adt_patient_admit(orm.Model): """ Represents the patient admission operation in the patient management system. (A01 Message) Consulting and referring doctors are expected in the submitted values in the following format:: [... { 'type': 'c' or 'r', 'code': 'code_string, 'title': 'Mr', 'given_name': 'John', 'family_name': 'Smith' }... ] If doctor doesn't exist, then a partner is created (but no user is created). """ _name = 'nh.clinical.adt.patient.admit' _inherit = ['nh.activity.data'] _description = 'ADT Patient Admit' _columns = { 'location_id': fields.many2one('nh.clinical.location', 'Admission Location'), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'pos_id': fields.many2one('nh.clinical.pos', 'POS', required=True), 'location': fields.char('Location', size=256), 'code': fields.char("Code", size=256), 'start_date': fields.datetime("Admission Date"), 'other_identifier': fields.char('Hospital Number', size=100), 'patient_identifier': fields.char('NHS Number', size=100), 'doctors': fields.text("Doctors") }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data and then calls :meth:`submit<activity.nh_activity.submit>`. If a `ward` :mod:`location<base.nh_clinical_location>` with the provided code does not exist, it will create a new one. Due to this behaviour the user submitting the data must be related to a :mod:`point of service<base.nh_clinical_pos>` linked to a valid :mod:`location<base.nh_clinical_location>` instance of `pos` type, as new Wards will need to be assigned to a point of service. :returns: ``True`` :rtype: bool """ user = self.pool['res.users'].browse(cr, uid, uid, context=context) if not user.pos_ids: raise osv.except_osv('POS Missing Error!', "POS location is not set for user.login = %s!" % user.login) if not vals.get('location'): raise osv.except_osv('Admission Error!', 'Location must be set for admission!') if not vals.get('other_identifier'): if not vals.get('patient_identifier'): raise osv.except_osv('Admission Error!', 'Patient must be set for admission!') location_pool = self.pool['nh.clinical.location'] location_id = location_pool.get_by_code( cr, uid, vals['location'], auto_create=True, context=context) location = location_pool.browse(cr, uid, location_id, context=context) patient_pool = self.pool['nh.clinical.patient'] if vals.get('other_identifier'): patient_pool.check_hospital_number( cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] else: patient_pool.check_nhs_number(cr, uid, vals['patient_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['patient_identifier', '=', vals['patient_identifier']]], context=context)[0] data = vals.copy() data.update({'location_id': location_id, 'patient_id': patient_id, 'pos_id': location.pos_id.id}) return super(nh_clinical_adt_patient_admit, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then creates and completes a new :mod:`admission<operations.nh_clinical_patient_admission>` to the provided location. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_admit, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] admission_pool = self.pool['nh.clinical.patient.admission'] activity = activity_pool.browse(cr, uid, activity_id, context=context) admission_data = { 'pos_id': activity.data_ref.pos_id.id, 'patient_id': activity.data_ref.patient_id.id, 'location_id': activity.data_ref.location_id.id, 'code': activity.data_ref.code, 'start_date': activity.data_ref.start_date } if activity.data_ref.doctors: doctor_pool = self.pool['nh.clinical.doctor'] admission_data.update({'doctors': activity.data_ref.doctors}) doctor_pool.evaluate_doctors_dict(cr, uid, admission_data, context=context) del admission_data['doctors'] admission_id = admission_pool.create_activity( cr, uid, {'creator_id': activity_id}, admission_data, context=context) activity_pool.complete(cr, uid, admission_id, context=context) spell_id = activity_pool.search(cr, uid, [ ['data_model', '=', 'nh.clinical.spell'], ['creator_id', '=', admission_id]], context=context)[0] activity_pool.write(cr, SUPERUSER_ID, activity_id, {'parent_id': spell_id})
return res
[docs]class nh_clinical_adt_patient_cancel_admit(orm.Model): """ Represents the cancel admission operation in the patient management system. (A11 Message) """ _name = 'nh.clinical.adt.patient.cancel_admit' _inherit = ['nh.activity.data'] _description = 'ADT Cancel Patient Admit' _columns = { 'other_identifier': fields.char('Hospital Number', size=50, required=True), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'admission_id': fields.many2one('nh.activity', 'Admission Activity') }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data is correct, finding the last completed instance of :mod:`admission<operations.nh_clinical_patient_admission>` and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ if not vals.get('other_identifier'): raise osv.except_osv('Cancel Admit Error!', 'Patient must be set!') patient_pool = self.pool['nh.clinical.patient'] patient_pool.check_hospital_number(cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] spell_pool = self.pool['nh.clinical.spell'] activity_pool = self.pool['nh.activity'] spell_id = spell_pool.get_by_patient_id( cr, uid, patient_id, exception='False', context=context) spell = spell_pool.browse(cr, uid, spell_id, context=context) activity_pool.write(cr, uid, activity_id, {'parent_id': spell.activity_id.id}, context=context) admission_pool = self.pool['nh.clinical.patient.admission'] admission_id = admission_pool.get_last( cr, uid, patient_id, exception='False', context=context) data = vals.copy() data.update({'patient_id': patient_id, 'admission_id': admission_id}) return super(nh_clinical_adt_patient_cancel_admit, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then cancels the last `completed` :mod:`admission<operations.nh_clinical_patient_admission>` for the provided patient. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_cancel_admit, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) activity_pool.cancel(cr, uid, activity.data_ref.admission_id.id, context=context)
return res
[docs]class nh_clinical_adt_patient_discharge(orm.Model): """ Represents the patient discharge operation in the patient management system. (A03 Message) """ _name = 'nh.clinical.adt.patient.discharge' _inherit = ['nh.activity.data'] _description = 'ADT Patient Discharge' _columns = { 'other_identifier': fields.char('Hospital Number', size=100), 'patient_identifier': fields.char('NHS Number', size=100), 'location': fields.char('Pre-Discharge Location', size=256), 'location_id': fields.many2one('nh.clinical.location', 'Pre-Discharge Location'), 'discharge_date': fields.datetime('Discharge Date'), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True) }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data and then calls :meth:`submit<activity.nh_activity.submit>`. Creates a new :mod:`spell<spell.nh_clinical_spell>` for the provided patient if there is not an open instance related to it. Requires the user to be linked to a :mod:`point of service<base.nh_clinical_pos>` due to similar behaviour as the admission in this particular scenario. :returns: ``True`` :rtype: bool """ user = self.pool['res.users'].browse(cr, uid, uid, context=context) if not user.pos_ids: raise osv.except_osv('POS Missing Error!', "POS location is not set for user.login = %s!" % user.login) if not vals.get('other_identifier'): if not vals.get('patient_identifier'): raise osv.except_osv('Discharge Error!', 'Patient must be set!') data = vals.copy() patient_pool = self.pool['nh.clinical.patient'] if vals.get('other_identifier'): patient_pool.check_hospital_number( cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] else: patient_pool.check_nhs_number( cr, uid, vals['patient_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['patient_identifier', '=', vals['patient_identifier']]], context=context)[0] if vals.get('discharge_date'): discharge_date = vals.get('discharge_date') else: discharge_date = dt.now().strftime(DTF) spell_pool = self.pool['nh.clinical.spell'] activity_pool = self.pool['nh.activity'] spell_id = spell_pool.get_by_patient_id(cr, uid, patient_id, context=context) if not spell_id: if not vals.get('location'): raise osv.except_osv( 'Discharge Error!', 'Missing location and patient is not admitted!') discharged = activity_pool.search( cr, uid, [ ['data_model', '=', 'nh.clinical.spell'], ['patient_id', '=', patient_id], ['state', '=', 'completed'] ], context=context) if discharged: raise osv.except_osv('Discharge Error!', 'Patient is already discharged!') _logger.warn("Patient admitted from a discharge call!") location_pool = self.pool['nh.clinical.location'] location_id = location_pool.get_by_code( cr, uid, vals['location'], auto_create=True, context=context) location = location_pool.browse( cr, uid, location_id, context=context) data.update({'location_id': location_id}) admission_pool = self.pool['nh.clinical.patient.admission'] admission_data = { 'pos_id': location.pos_id.id, 'patient_id': patient_id, 'location_id': location_id, } admission_id = admission_pool.create_activity( cr, uid, {'creator_id': activity_id}, admission_data, context=context) activity_pool.complete(cr, uid, admission_id, context=context) spell_id = spell_pool.get_by_patient_id( cr, uid, patient_id, exception='False', context=context) spell = spell_pool.browse(cr, uid, spell_id, context=context) data.update({'patient_id': patient_id, 'discharge_date': discharge_date}) activity_pool.write( cr, uid, activity_id, {'parent_id': spell.activity_id.id}, context=context) return super(nh_clinical_adt_patient_discharge, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then creates and completes a new :mod:`discharge<operations.nh_clinical_patient_discharge>` for the provided patient. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_discharge, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] discharge_pool = self.pool['nh.clinical.patient.discharge'] activity = activity_pool.browse(cr, uid, activity_id, context=context) discharge_data = { 'patient_id': activity.data_ref.patient_id.id, 'discharge_date': activity.data_ref.discharge_date } discharge_id = discharge_pool.create_activity( cr, uid, {'creator_id': activity_id}, discharge_data, context=context) activity_pool.complete(cr, uid, discharge_id, context=context)
return res
[docs]class nh_clinical_adt_patient_cancel_discharge(orm.Model): """ Represents the cancel discharge operation in the patient management system. (A13 Message) """ _name = 'nh.clinical.adt.patient.cancel_discharge' _inherit = ['nh.activity.data'] _description = 'ADT Cancel Patient Discharge' _columns = { 'other_identifier': fields.char('Hospital Number', size=50, required=True), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'discharge_id': fields.many2one('nh.activity', 'Discharge Activity') }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data is correct, finding the last `completed` instance of :mod:`discharge<operations.nh_clinical_patient_discharge>` and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ if not vals.get('other_identifier'): raise osv.except_osv('Cancel Discharge Error!', 'Patient must be set!') patient_pool = self.pool['nh.clinical.patient'] patient_pool.check_hospital_number(cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] discharge_pool = self.pool['nh.clinical.patient.discharge'] discharge_id = discharge_pool.get_last( cr, uid, patient_id, exception='False', context=context) data = vals.copy() data.update({'patient_id': patient_id, 'discharge_id': discharge_id}) return super(nh_clinical_adt_patient_cancel_discharge, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then cancels the last `completed` :mod:`discharge<operations.nh_clinical_patient_discharge>` for the provided patient. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_cancel_discharge, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) activity_pool.cancel(cr, uid, activity.data_ref.discharge_id.id, context=context) activity_pool.write( cr, uid, activity_id, {'parent_id': activity.data_ref.discharge_id.parent_id.id}, context=context)
return res
[docs]class nh_clinical_adt_patient_transfer(orm.Model): """ Represents the patient transfer operation in the patient management system. (A02 Message) """ _name = 'nh.clinical.adt.patient.transfer' _inherit = ['nh.activity.data'] _description = 'ADT Patient Transfer' _columns = { 'other_identifier': fields.char('Hospital Number', size=100), 'patient_identifier': fields.char('NHS Number', size=100), 'original_location': fields.char('Location of Origin', size=256), 'origin_location_id': fields.many2one('nh.clinical.location', 'Origin Location'), 'location': fields.char('Location', size=256), 'location_id': fields.many2one('nh.clinical.location', 'Transfer Location'), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True) }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data and then calls :meth:`submit<activity.nh_activity.submit>`. Creates a new :mod:`spell<spell.nh_clinical_spell>` for the provided patient if there is not an open instance related to it and an origin location for the transfer was provided. Requires the user to be linked to a :mod:`point of service<base.nh_clinical_pos>` due to similar behaviour as the admission in this particular scenario. :returns: ``True`` :rtype: bool """ user = self.pool['res.users'].browse(cr, uid, uid, context=context) if not user.pos_ids: raise osv.except_osv('POS Missing Error!', "POS location is not set for user.login = %s!" % user.login) if not vals.get('location'): raise osv.except_osv('Transfer Error!', 'Location must be set for transfer!') if not vals.get('other_identifier'): if not vals.get('patient_identifier'): raise osv.except_osv('Transfer Error!', 'Patient must be set for transfer!') location_pool = self.pool['nh.clinical.location'] location_id = location_pool.get_by_code( cr, uid, vals['location'], auto_create=True, context=context) if vals.get('original_location'): olocation_id = location_pool.get_by_code( cr, uid, vals.get('original_location'), auto_create=True, context=context) else: olocation_id = False patient_pool = self.pool['nh.clinical.patient'] if vals.get('other_identifier'): patient_pool.check_hospital_number( cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] else: patient_pool.check_nhs_number( cr, uid, vals['patient_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['patient_identifier', '=', vals['patient_identifier']]], context=context)[0] spell_pool = self.pool['nh.clinical.spell'] activity_pool = self.pool['nh.activity'] spell_id = spell_pool.get_by_patient_id(cr, uid, patient_id, context=context) if not spell_id: if olocation_id: api = self.pool['nh.clinical.api'] api.admit(cr, uid, vals['other_identifier'], {'location': vals['original_location']}, context=context) spell_id = spell_pool.get_by_patient_id(cr, uid, patient_id, context=context) else: raise osv.except_osv( 'Transfer Error!', 'Patient does not have an open spell.' 'No origin location provided.') spell = spell_pool.browse(cr, uid, spell_id, context=context) activity_pool.write( cr, uid, activity_id, {'parent_id': spell.activity_id.id}, context=context) data = vals.copy() data.update({ 'location_id': location_id, 'origin_location_id': olocation_id, 'patient_id': patient_id }) return super(nh_clinical_adt_patient_transfer, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then creates and completes a new :mod:`transfer<operations.nh_clinical_patient_transfer>` for the provided patient. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_transfer, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] transfer_pool = self.pool['nh.clinical.patient.transfer'] activity = activity_pool.browse(cr, uid, activity_id, context=context) transfer = activity.data_ref transfer_data = { 'patient_id': transfer.patient_id.id, 'location_id': transfer.location_id.id } transfer_id = transfer_pool.create_activity( cr, uid, {'creator_id': activity_id}, transfer_data, context=context) activity_pool.complete(cr, uid, transfer_id, context=context)
return res
[docs]class nh_clinical_adt_patient_cancel_transfer(orm.Model): """ Represents the cancel transfer operation in the patient management system. (A12 Message) """ _name = 'nh.clinical.adt.patient.cancel_transfer' _inherit = ['nh.activity.data'] _description = 'ADT Cancel Patient Transfer' _columns = { 'other_identifier': fields.char('Hospital Number', size=100), 'patient_identifier': fields.char('NHS Number', size=100), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'transfer_id': fields.many2one('nh.activity', 'Transfer Activity') }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data is correct, finding the last `completed` instance of :mod:`transfer<operations.nh_clinical_patient_transfer>` and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ if not vals.get('other_identifier'): raise osv.except_osv('Cancel Transfer Error!', 'Patient must be set!') patient_pool = self.pool['nh.clinical.patient'] patient_pool.check_hospital_number(cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] transfer_pool = self.pool['nh.clinical.patient.transfer'] transfer_id = transfer_pool.get_last( cr, uid, patient_id, exception='False', context=context) data = vals.copy() data.update({'patient_id': patient_id, 'transfer_id': transfer_id}) return super(nh_clinical_adt_patient_cancel_transfer, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then cancels the last `completed` :mod:`transfer<operations.nh_clinical_patient_transfer>` for the provided patient. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_patient_cancel_transfer, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) cancel = activity.data_ref activity_pool.cancel(cr, uid, cancel.transfer_id.id, context=context) activity_pool.write(cr, uid, activity_id, {'parent_id': cancel.transfer_id.parent_id.id}, context=context)
return res
[docs]class nh_clinical_adt_spell_update(orm.Model): """ Represents the admission update operation in the patient management system. (A08 Message) """ _name = 'nh.clinical.adt.spell.update' _inherit = ['nh.activity.data'] _description = 'ADT Spell Update' _columns = { 'location_id': fields.many2one('nh.clinical.location', 'Admission Location'), 'patient_id': fields.many2one('nh.clinical.patient', 'Patient', required=True), 'pos_id': fields.many2one('nh.clinical.pos', 'POS', required=True), 'location': fields.char('Location', size=256), 'code': fields.char("Code", size=256), 'start_date': fields.datetime("Admission Date"), 'other_identifier': fields.char('Hospital Number', size=100), 'patient_identifier': fields.char('NHS Number', size=100), 'doctors': fields.text("Doctors"), }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data and then calls :meth:`submit<activity.nh_activity.submit>`. If a :mod:`location<base.nh_clinical_location>` of `ward` usage with the provided code does not exist, it will create a new one. Due to this behaviour the user submitting the data must be related to a :mod:`point of service<base.nh_clinical_pos>` linked to a valid :mod:`location<base.nh_clinical_location>` instance of `pos` type, as new Wards will need to be assigned to a point of service. :returns: ``True`` :rtype: bool """ user = self.pool['res.users'].browse(cr, uid, uid, context=context) if not user.pos_ids: raise osv.except_osv('POS Missing Error!', "POS location is not set for user.login = %s!" % user.login) if not vals.get('location'): raise osv.except_osv('Update Error!', 'Location must be set for spell update!') if not vals.get('other_identifier'): if not vals.get('patient_identifier'): raise osv.except_osv('Update Error!', 'Patient must be set for spell update!') location_pool = self.pool['nh.clinical.location'] location_id = location_pool.get_by_code( cr, uid, vals['location'], auto_create=True, context=context) location = location_pool.browse(cr, uid, location_id, context=context) patient_pool = self.pool['nh.clinical.patient'] if vals.get('other_identifier'): patient_pool.check_hospital_number( cr, uid, vals['other_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['other_identifier', '=', vals['other_identifier']]], context=context)[0] else: patient_pool.check_nhs_number( cr, uid, vals['patient_identifier'], exception='False', context=context) patient_id = patient_pool.search( cr, uid, [['patient_identifier', '=', vals['patient_identifier']]], context=context)[0] spell_pool = self.pool['nh.clinical.spell'] activity_pool = self.pool['nh.activity'] spell_id = spell_pool.get_by_patient_id(cr, uid, patient_id, context=context) if not spell_id: raise osv.except_osv('Update Error!', 'The patient does not have an open spell!') spell = spell_pool.browse(cr, uid, spell_id, context=context) activity_pool.write(cr, uid, activity_id, {'parent_id': spell.activity_id.id}, context=context) data = vals.copy() data.update({ 'location_id': location_id, 'patient_id': patient_id, 'pos_id': location.pos_id.id }) return super(nh_clinical_adt_spell_update, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Overwrites the target :mod:`spell<spell.nh_clinical_spell>` information and then calls :meth:`complete<activity.nh_activity.complete>`. If location information needs to be updated a new instance of :mod:`movement<operations.nh_clinical_patient_move>` is created and completed. If the new location is located in a different Ward than the current spell location, a :meth:`policy trigger<activity.nh_activity_data.trigger_policy>` will be kicked off. As that is technically a transfer movement. :returns: ``True`` :rtype: bool """ res = super(nh_clinical_adt_spell_update, self).complete( cr, uid, activity_id, context=context) activity_pool = self.pool['nh.activity'] activity = activity_pool.browse(cr, uid, activity_id, context=context) update = activity.data_ref update_data = { 'pos_id': update.pos_id.id, 'code': update.code, 'start_date': update.start_date } if update.doctors: doctor_pool = self.pool['nh.clinical.doctor'] update_data.update({'doctors': update.doctors}) doctor_pool.evaluate_doctors_dict(cr, uid, update_data, context=context) del update_data['doctors'] else: update_data.update( {'con_doctor_ids': [[5]], 'ref_doctor_ids': [[5]]}) activity_pool.submit(cr, uid, activity.parent_id.id, update_data, context=context) location_pool = self.pool['nh.clinical.location'] if not location_pool.is_child_of( cr, uid, activity.parent_id.location_id.id, update.location, context=context): move_pool = self.pool['nh.clinical.patient.move'] move_activity_id = move_pool.create_activity(cr, SUPERUSER_ID, { 'parent_id': activity.parent_id.id, 'creator_id': activity_id }, { 'patient_id': update.patient_id.id, 'location_id': update.location_id.id }, context=context) activity_pool.complete(cr, SUPERUSER_ID, move_activity_id, context=context) # trigger transfer policy activities self.trigger_policy( cr, uid, activity_id, location_id=update.location_id.id, context=context)
return res
[docs]class nh_clinical_adt_patient_merge(orm.Model): """ Represents the patient merge operation in the patient management system. (A40 Message) Merges a patient into another patient making the resulting patient own all activities. """ _name = 'nh.clinical.adt.patient.merge' _inherit = ['nh.activity.data'] _description = 'ADT Patient Merge' _columns = { 'from_identifier': fields.char('Source Identifier', size=100), 'source_patient_id': fields.many2one('nh.clinical.patient', 'Source Patient'), 'into_identifier': fields.char('Destination Identifier', size=100), 'dest_patient_id': fields.many2one('nh.clinical.patient', 'Destination Patient'), }
[docs] def submit(self, cr, uid, activity_id, vals, context=None): """ Checks the submitted data and then calls :meth:`submit<activity.nh_activity.submit>`. :returns: ``True`` :rtype: bool """ patient_pool = self.pool['nh.clinical.patient'] data = vals.copy() if data.get('from_identifier'): patient_pool.check_hospital_number( cr, uid, data['from_identifier'], exception='False', context=context) from_id = patient_pool.search( cr, uid, [('other_identifier', '=', data['from_identifier'])] )[0] data.update({'source_patient_id': from_id}) if data.get('into_identifier'): patient_pool.check_hospital_number( cr, uid, data['into_identifier'], exception='False', context=context) into_id = patient_pool.search( cr, uid, [('other_identifier', '=', data['into_identifier'])] )[0] data.update({'dest_patient_id': into_id}) return super(nh_clinical_adt_patient_merge, self).submit(
cr, uid, activity_id, data, context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ Calls :meth:`complete<activity.nh_activity.complete>` and then adds every piece of information that the source patient has and the destination patient lacks into the destination patient. The destination patient ends up being linked to all the :class:`activities<activity.nh_activity>` both patients were linked to. :returns: ``True`` :rtype: bool """ res = {} activity_pool = self.pool['nh.activity'] merge_activity = activity_pool.browse( cr, SUPERUSER_ID, activity_id, context=context) if not merge_activity.data_ref.source_patient_id: raise osv.except_osv( 'Patient Merge Error!', "Source patient not found in submitted data!") if not merge_activity.data_ref.dest_patient_id: raise osv.except_osv( 'Patient Merge Error!', "Destination patient not found in submitted data!") super(nh_clinical_adt_patient_merge, self).complete( cr, uid, activity_id, context=context) patient_pool = self.pool['nh.clinical.patient'] from_id = merge_activity.data_ref.source_patient_id.id into_id = merge_activity.data_ref.dest_patient_id.id for model_name in self.pool.models.keys(): model_pool = self.pool[model_name] if model_name.startswith("nh.clinical") and model_pool._auto and \ 'patient_id' in model_pool._columns.keys() and \ model_name != self._name and \ model_name != 'nh.clinical.notification' and model_name != \ 'nh.clinical.patient.observation': ids = model_pool.search( cr, uid, [('patient_id', '=', from_id)], context=context) if ids: model_pool.write(cr, uid, ids, {'patient_id': into_id}, context=context) activity_ids = activity_pool.search( cr, uid, [('patient_id', '=', from_id)], context=context) activity_pool.write(cr, uid, activity_ids, {'patient_id': into_id}, context=context) from_data = patient_pool.read(cr, uid, from_id, context) into_data = patient_pool.read(cr, uid, into_id, context) vals_into = {} for key, value in from_data.iteritems(): if not value: continue if value and into_data[key] and value != into_data[key]: pass if value and not into_data[key]: if '_id' == key[-3:]: vals_into.update({key: value[0]}) else: vals_into.update({key: value}) res['merge_into_update'] = patient_pool.write( cr, uid, into_id, vals_into, context=context) res['merge_from_deactivate'] = patient_pool.write( cr, uid, from_id, {'active': False}, context=context) activity_pool.write(cr, uid, activity_id, {'patient_id': into_id}, context=context)
return res