Source code for pbp

# -*- coding: utf-8 -*-
# Part of Open eObs. See LICENSE file for full copyright and licensing details.
"""
`pbp.py` defines the postural blood pressure observation class and its
standard behaviour and policy triggers.
"""
from openerp.osv import orm, fields
from datetime import datetime as dt, timedelta as td
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DTF
import logging
from openerp import SUPERUSER_ID


_logger = logging.getLogger(__name__)


[docs]class nh_clinical_patient_observation_pbp(orm.Model): """ Represents a Postural Blood Pressure :class:`observation<observations.nh_clinical_patient_observation>` for postural hypotension detection, storing the systolic and dyastolic blood pressure for both standing and sitting postures. """ _name = 'nh.clinical.patient.observation.pbp' _inherit = ['nh.clinical.patient.observation'] _required = ['systolic_sitting', 'diastolic_sitting', 'systolic_standing', 'diastolic_standing'] _description = "Postural Blood Pressure" _POLICY = {'schedule': [[6, 0], [18, 0]], 'notifications': [ [], [{'model': 'nurse', 'summary': 'Inform FY2', 'groups': ['nurse', 'hca']}, {'model': 'hca', 'summary': 'Inform registered nurse', 'groups': ['hca']}, {'model': 'nurse', 'summary': 'Informed about patient status (Postural Blood Pressure)', 'groups': ['hca']}] ]} def _get_pbp_result(self, cr, uid, ids, field_name, arg, context=None): res = {} for pbp in self.browse(cr, uid, ids, context=context): if int(pbp.systolic_sitting - pbp.systolic_standing) > 20: res[pbp.id] = 'yes' else: res[pbp.id] = 'no' return res _columns = { 'systolic_sitting': fields.integer('Sitting Blood Pressure Systolic'), 'systolic_standing': fields.integer( 'Standing Blood Pressure Systolic'), 'diastolic_sitting': fields.integer( 'Sitting Blood Pressure Diastolic'), 'diastolic_standing': fields.integer( 'Standing Blood Pressure Diastolic'), 'result': fields.function(_get_pbp_result, type='char', string='>20 mm/Hg', size=5, store=False) } _form_description = [ { 'name': 'systolic_sitting', 'type': 'integer', 'label': 'Sitting Blood Pressure Systolic', 'min': 1, 'max': 300, 'on_change': [ { 'fields': ['systolic_standing', 'diastolic_standing'], 'condition': [['systolic_sitting', '!=', ''], ['diastolic_sitting', '!=', '']], 'action': 'show', 'type': 'value' }, { 'fields': ['systolic_standing', 'diastolic_standing'], 'condition': ['||', ['systolic_sitting', '==', ''], ['diastolic_sitting', '==', '']], 'action': 'hide', 'type': 'value' } ], 'validation': [ { 'condition': { 'target': 'systolic_sitting', 'operator': '>', 'value': 'diastolic_sitting' }, 'message': { 'target': 'Sitting Systolic BP must be more than ' 'Sitting Diastolic BP', 'value': 'Sitting Diastolic BP must be less than ' 'Sitting Systolic BP' } } ], 'initially_hidden': False }, { 'name': 'diastolic_sitting', 'type': 'integer', 'label': 'Sitting Blood Pressure Diastolic', 'min': 1, 'max': 280, 'on_change': [ { 'fields': ['systolic_standing', 'diastolic_standing'], 'condition': [['systolic_sitting', '!=', ''], ['diastolic_sitting', '!=', '']], 'action': 'show', 'type': 'value' }, { 'fields': ['systolic_standing', 'diastolic_standing'], 'condition': ['||', ['systolic_sitting', '==', ''], ['diastolic_sitting', '==', '']], 'action': 'hide', 'type': 'value' } ], 'validation': [ { 'condition': { 'target': 'diastolic_sitting', 'operator': '<', 'value': 'systolic_sitting' }, 'message': { 'target': 'Sitting Diastolic BP must be less than ' 'Sitting Systolic BP', 'value': 'Sitting Systolic BP must be more than ' 'Sitting Diastolic BP' } } ], 'initially_hidden': False }, { 'name': 'systolic_standing', 'type': 'integer', 'label': 'Standing Blood Pressure Systolic', 'min': 1, 'max': 300, 'validation': [ { 'condition': { 'target': 'systolic_standing', 'operator': '>', 'value': 'diastolic_standing' }, 'message': { 'target': 'Standing Systolic BP must be more than ' 'Standing Diastolic BP', 'value': 'Standing Diastolic BP must be less than ' 'Standing Systolic BP' } } ], 'initially_hidden': True }, { 'name': 'diastolic_standing', 'type': 'integer', 'label': 'Standing Blood Pressure Diastolic', 'min': 1, 'max': 280, 'validation': [ { 'condition': { 'target': 'diastolic_standing', 'operator': '<', 'value': 'systolic_standing' }, 'message': { 'target': 'Standing Diastolic BP must be less than ' 'Standing Systolic BP', 'value': 'Standing Systolic BP must be more than ' 'Standing Diastolic BP' } } ], 'initially_hidden': True } ]
[docs] def schedule(self, cr, uid, activity_id, date_scheduled=None, context=None): """ If a specific ``date_scheduled`` parameter is not specified. The `_POLICY['schedule']` dictionary value will be used to find the closest time to the current time from the ones specified (0 to 23 hours) Then it will call :meth:`schedule<activity.nh_activity.schedule>` :returns: ``True`` :rtype: bool """ hour = td(hours=1) schedule_times = [] for s in self._POLICY['schedule']: schedule_times.append( dt.now().replace( hour=s[0], minute=s[1], second=0, microsecond=0)) date_schedule = date_scheduled if date_scheduled else dt.now().replace( minute=0, second=0, microsecond=0) utctimes = [fields.datetime.utc_timestamp( cr, uid, t, context=context) for t in schedule_times] while all([date_schedule.hour != date_schedule.strptime( ut, DTF).hour for ut in utctimes]): date_schedule += hour return super(nh_clinical_patient_observation_pbp, self).schedule( cr, uid, activity_id, date_schedule.strftime(DTF), context=context)
[docs] def complete(self, cr, uid, activity_id, context=None): """ It determines which acuity case the current observation is in with the stored data and responds to the different policy triggers accordingly defined on the ``_POLICY`` dictionary. Calls :meth:`complete<activity.nh_activity.complete>` and then creates and schedules a new postural blood pressure observation if the current :mod:`pbp monitoring<parameters.nh_clinical_patient_pbp_monitoring>` parameter is ``True``. :returns: ``True`` :rtype: bool """ activity_pool = self.pool['nh.activity'] api_pool = self.pool['nh.clinical.api'] groups_pool = self.pool['res.groups'] activity = activity_pool.browse(cr, uid, activity_id, context=context) case = int(activity.data_ref.result == 'yes') hcagroup_ids = groups_pool.search( cr, uid, [('users', 'in', [uid]), ('name', '=', 'NH Clinical HCA Group')]) nursegroup_ids = groups_pool.search( cr, uid, [('users', 'in', [uid]), ('name', '=', 'NH Clinical Nurse Group')]) group = nursegroup_ids and 'nurse' or hcagroup_ids and 'hca' or False # TRIGGER NOTIFICATIONS api_pool.trigger_notifications(cr, uid, { 'notifications': self._POLICY['notifications'][case], 'parent_id': activity.parent_id.id, 'creator_id': activity_id, 'patient_id': activity.data_ref.patient_id.id, 'model': self._name, 'group': group }, context=context) res = super(nh_clinical_patient_observation_pbp, self).complete( cr, uid, activity_id, context) activity_pool.cancel_open_activities( cr, uid, activity.parent_id.id, self._name, context=context) # create next PBP (schedule) domain = [ ['data_model', '=', 'nh.clinical.patient.pbp_monitoring'], ['state', '=', 'completed'], ['patient_id', '=', activity.data_ref.patient_id.id] ] pbp_monitoring_ids = activity_pool.search( cr, uid, domain, order="date_terminated desc, sequence desc", context=context) monitoring_active = pbp_monitoring_ids and activity_pool.browse( cr, uid, pbp_monitoring_ids[0], context=context).data_ref.status if monitoring_active: next_activity_id = self.create_activity( cr, SUPERUSER_ID, {'creator_id': activity_id, 'parent_id': activity.parent_id.id}, {'patient_id': activity.data_ref.patient_id.id}) date_schedule = dt.now().replace( minute=0, second=0, microsecond=0) + td(hours=2) activity_pool.schedule( cr, uid, next_activity_id, date_schedule, context=context) return res