Source code for ward_dashboard

# Part of Open eObs. See LICENSE file for full copyright and licensing details.
# -*- coding: utf-8 -*-
"""
Gives an overview of the current state of ward and bed
:class:`locations<base.nh_clinical_location>`.
"""
from openerp.osv import orm, fields
from openerp import api
import logging
_logger = logging.getLogger(__name__)


[docs]class nh_eobs_ward_dashboard(orm.Model): """ Extends :class:`location<base.nh_clinical_location>`, providing an overall state of a ward location. It shows number of related :class:`users<base.res_users>` by type, number of free beds, number of :class:`patients<base.nh_clinical_patient>` by risk, number of waiting patients, etc. """ _name = "nh.eobs.ward.dashboard" _inherits = {'nh.clinical.location': 'location_id'} _description = "Ward Dashboard" _auto = False _table = "nh_eobs_ward_dashboard" def _get_wm_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, user_ids from loc_users where group_name = 'NH Clinical Shift Coordinator Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['user_ids'] for r in cr.dictfetchall()}) return res def _get_dr_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, user_ids from child_loc_users where group_name = 'NH Clinical Doctor Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['user_ids'] for r in cr.dictfetchall()}) return res def _get_bed_ids(self, cr, uid, ids, fiel_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, bed_ids from ward_beds where location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update({r['location_id']: r['bed_ids'] for r in cr.dictfetchall()}) return res def _get_waiting_patient_ids(self, cr, uid, ids, fiel_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, patients_waiting_ids from loc_waiting_patients where location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['patients_waiting_ids'] for r in cr.dictfetchall()}) return res _columns = { 'location_id': fields.many2one('nh.clinical.location', 'Location', required=1, ondelete='restrict'), 'waiting_patients': fields.integer('Waiting Patients'), 'patients_in_bed': fields.integer('Patients in Bed'), 'free_beds': fields.integer('Free Beds'), 'related_hcas': fields.integer('HCAs'), 'related_nurses': fields.integer('Nurses'), 'related_doctors': fields.integer('Doctors'), 'kanban_color': fields.integer('Kanban Color'), 'assigned_wm_ids': fields.function( _get_wm_ids, type='many2many', relation='res.users', string='Shift Coordinators'), 'assigned_doctor_ids': fields.function( _get_dr_ids, type='many2many', relation='res.users', string='Doctors'), 'bed_ids': fields.function( _get_bed_ids, type='many2many', relation='nh.eobs.bed.dashboard', string='Beds'), 'waiting_patient_ids': fields.function( _get_waiting_patient_ids, type='many2many', relation='nh.clinical.patient', string='Waiting Patients'), 'high_risk_patients': fields.integer('High Risk Patients'), 'med_risk_patients': fields.integer('Medium Risk Patients'), 'low_risk_patients': fields.integer('Low Risk Patients'), 'no_risk_patients': fields.integer('No Risk Patients'), 'noscore_patients': fields.integer('No Score Patients') } @api.multi
[docs] def patient_board(self): """ Returns an Odoo `action` which defines a `form` view for a :class:`wardboard<wardboard.nh_clinical_wardboard>` for all :class:`patients<base.nh_clinical_patient>` in an `open` :class:`spell<spell.nh_clinical_spell>` and :class:`placed<operations.nh_clinical_patient_placement>` in a bed :class:`location<base.nh_clinical_location>`. :returns: Odoo `action` definition :rtype: dict """ model_data_model = self.env['ir.model.data'] context = self._context.copy() context.update( { 'search_default_clinical_risk': 1, 'search_default_high_risk': 0, 'search_default_ward_id': self.id } ) kanban_view_id = model_data_model.get_object_reference( 'nh_eobs', 'view_wardboard_kanban')[1] tree_view_id = model_data_model.get_object_reference( 'nh_eobs', 'view_wardboard_tree')[1] form_view_id = model_data_model.get_object_reference( 'nh_eobs', 'view_wardboard_form')[1] return { 'name': 'Acuity Board', 'type': 'ir.actions.act_window', 'res_model': 'nh.clinical.wardboard', 'views': [ (kanban_view_id, 'kanban'), (tree_view_id, 'tree'), (form_view_id, 'form') ], 'domain': [ ('spell_activity_id.user_ids', 'in', [self._uid]), ('spell_state', '=', 'started'), ('location_id.usage', '=', 'bed') ], 'target': 'current', 'context': context }
def init(self, cr): cr.execute(""" drop view if exists wdb_ward_locations cascade; drop view if exists wdb_ews_ranked cascade; drop view if exists wdb_ews cascade; drop view if exists %s cascade; drop view if exists loc_waiting_patients cascade; drop view if exists loc_availability cascade; drop view if exists loc_users cascade; drop view if exists child_loc_users cascade; drop view if exists loc_patients_by_risk cascade; drop view if exists loc_risk_patients_count cascade; drop view if exists ward_beds cascade; create or replace view wdb_ward_locations as( with recursive ward_loc(id, parent_id, path, ward_id) as ( select lc.id, lc.parent_id, ARRAY[lc.id] as path, lc.id as ward_id from nh_clinical_location as lc where lc.usage = 'ward' union all select l.id, l.parent_id, w.path || ARRAY[l.id] as path, w.path[1] as ward_id from ward_loc as w, nh_clinical_location as l where l.parent_id = w.id) select * from ward_loc ); create or replace view -- ews per spell, data_model, state wdb_ews_ranked as( select * from ( select spell.id as spell_id, activity.*, split_part(activity.data_ref, ',', 2)::int as data_id, rank() over (partition by spell.id, activity.data_model, activity.state order by activity.sequence desc) from nh_clinical_spell spell inner join nh_activity activity on activity.spell_activity_id = spell.activity_id and activity.data_model = 'nh.clinical.patient.observation.ews' left join nh_clinical_patient_observation_ews ews on ews.activity_id = activity.id where activity.state = 'scheduled' or (activity.state != 'scheduled' and ews.clinical_risk != 'Unknown')) sub_query where rank < 3 ); create or replace view wdb_ews as( select activity.parent_id as spell_activity_id, activity.patient_id, activity.spell_id, activity.state, activity.date_scheduled, activity.date_terminated, ews.id, ews.score, ews.frequency, ews.clinical_risk, case when activity.date_scheduled < now() at time zone 'UTC' then 'overdue: ' else '' end as next_diff_polarity, case activity.date_scheduled is null when false then justify_hours(greatest(now() at time zone 'UTC',activity.date_scheduled) - least(now() at time zone 'UTC', activity.date_scheduled)) else interval '0s' end as next_diff_interval, activity.rank from wdb_ews_ranked activity inner join nh_clinical_patient_observation_ews ews on activity.data_id = ews.id where activity.rank = 1 and activity.state = 'completed' ); create or replace view loc_patients_by_risk as ( select wl.ward_id as location_id, case when e1.clinical_risk is null then 'NoScore' else e1.clinical_risk end as clinical_risk, count(spell.id) as patients from nh_clinical_spell spell inner join nh_activity activity on activity.id = spell.activity_id and activity.state = 'started' inner join nh_clinical_location location on location.id = spell.location_id and location.usage = 'bed' inner join wdb_ward_locations wl on wl.id = location.id left join wdb_ews e1 on e1.spell_activity_id = activity.id group by wl.ward_id, e1.clinical_risk ); create or replace view loc_risk_patients_count as ( select location.id as location_id, high.patients as high_risk_patients, med.patients as med_risk_patients, low.patients as low_risk_patients, no.patients as no_risk_patients, nos.patients as noscore_patients from nh_clinical_location location left join loc_patients_by_risk high on high.location_id = location.id and high.clinical_risk = 'High' left join loc_patients_by_risk med on med.location_id = location.id and med.clinical_risk = 'Medium' left join loc_patients_by_risk low on low.location_id = location.id and low.clinical_risk = 'Low' left join loc_patients_by_risk no on no.location_id = location.id and no.clinical_risk = 'None' left join loc_patients_by_risk nos on nos.location_id = location.id and nos.clinical_risk = 'NoScore' ); create or replace view loc_availability as ( select wl.ward_id as location_id, count(spell.id) as patients_in_bed, count(location.id) - count(spell.id) as free_beds from nh_clinical_location location inner join wdb_ward_locations wl on wl.id = location.id left join nh_clinical_spell spell on spell.location_id = location.id left join nh_activity activity on activity.id = spell.activity_id and activity.state = 'started' where location.usage = 'bed' and location.active = true group by wl.ward_id ); create or replace view loc_waiting_patients as ( select placement.location_id as location_id, count(distinct placement.patient_id) as waiting_patients, array_agg(distinct placement.patient_id) as patients_waiting_ids from nh_clinical_placement placement inner join nh_activity activity on activity.id = placement.id inner join nh_activity spell_activity on spell_activity.id = activity.parent_id where spell_activity.state = 'started' group by placement.location_id ); create or replace view loc_users as ( select location.id as location_id, groups.name as group_name, array_agg(distinct users.id) as user_ids from res_groups groups left join res_groups_users_rel gurel on gurel.gid = groups.id left join res_users users on users.id = gurel.uid left join user_location_rel ulrel on ulrel.user_id = users.id left join nh_clinical_location location on location.id = ulrel.location_id group by location.id, groups.name ); create or replace view child_loc_users as ( select wl.ward_id as location_id, groups.name as group_name, array_agg(distinct users.id) as user_ids, count(distinct users.id) as related_users from res_groups groups left join res_groups_users_rel gurel on gurel.gid = groups.id left join res_users users on users.id = gurel.uid left join user_location_rel ulrel on ulrel.user_id = users.id left join nh_clinical_location location on location.id = ulrel.location_id left join wdb_ward_locations wl on wl.id = location.id group by wl.ward_id, groups.name ); create or replace view ward_beds as ( select wl.ward_id as location_id, array_agg(distinct location.id) as bed_ids from nh_clinical_location location inner join wdb_ward_locations wl on wl.id = location.id where location.usage = 'bed' group by wl.ward_id ); create or replace view %s as ( select location.id as id, location.id as location_id, lwp.waiting_patients, avail.patients_in_bed, avail.free_beds, clu1.related_users as related_hcas, clu2.related_users as related_nurses, clu3.related_users as related_doctors, rpc.high_risk_patients, rpc.med_risk_patients, rpc.low_risk_patients, rpc.no_risk_patients, rpc.noscore_patients, case when rpc.high_risk_patients > 0 then 2 when rpc.med_risk_patients > 0 then 3 when rpc.low_risk_patients > 0 then 4 when rpc.no_risk_patients > 0 then 0 when rpc.noscore_patients > 0 then 7 else 7 end as kanban_color from nh_clinical_location location left join loc_waiting_patients lwp on lwp.location_id = location.id left join loc_availability avail on avail.location_id = location.id left join child_loc_users clu1 on clu1.location_id = location.id and clu1.group_name = 'NH Clinical HCA Group' left join child_loc_users clu2 on clu2.location_id = location.id and clu2.group_name = 'NH Clinical Nurse Group' left join child_loc_users clu3 on clu3.location_id = location.id and clu3.group_name = 'NH Clinical Doctor Group' left join loc_risk_patients_count rpc on rpc.location_id = location.id where location.usage = 'ward' ) """ % (self._table, self._table))
[docs]class nh_eobs_bed_dashboard(orm.Model): """ Extends :class:`location<base.nh_clinical_location>`, providing an overall state of a bed location. It shows number of `assigned` and `following` nurses and hcas :class:`users<base.res_users>` as well as the :class:`patient<base.nh_clinical_patient>` placed in the bed. """ _name = "nh.eobs.bed.dashboard" _inherits = {'nh.clinical.location': 'location_id'} _description = "Bed Dashboard" _auto = False _table = "nh_eobs_bed_dashboard" def _get_hca_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, user_ids from loc_users where group_name = 'NH Clinical HCA Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['user_ids'] for r in cr.dictfetchall()}) return res def _get_nurse_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, user_ids from loc_users where group_name = 'NH Clinical Nurse Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['user_ids'] for r in cr.dictfetchall()}) return res def _get_patient_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, patient_ids from loc_patients where location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['patient_ids'] for r in cr.dictfetchall()}) return res def _get_nurse_follower_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, follower_ids from loc_followers where group_name = 'NH Clinical Nurse Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['follower_ids'] for r in cr.dictfetchall()}) return res def _get_hca_follower_ids(self, cr, uid, ids, field_name, arg, context=None): res = {}.fromkeys(ids, False) sql = """select location_id, follower_ids from loc_followers where group_name = 'NH Clinical HCA Group' and location_id in (%s)""" % ", ".join( [str(location_id) for location_id in ids]) cr.execute(sql) res.update( {r['location_id']: r['follower_ids'] for r in cr.dictfetchall()}) return res _columns = { 'location_id': fields.many2one('nh.clinical.location', 'Location', required=1, ondelete='restrict'), 'assigned_hca_ids': fields.function( _get_hca_ids, type='many2many', relation='res.users', string='HCAs'), 'assigned_nurse_ids': fields.function( _get_nurse_ids, type='many2many', relation='res.users', string='Nurses'), 'patient_ids': fields.function( _get_patient_ids, type='many2many', relation='nh.clinical.patient', string="Patients"), 'nurse_follower_ids': fields.function( _get_nurse_follower_ids, type='many2many', relation='res.users', string="Nurse Stand-Ins"), 'hca_follower_ids': fields.function( _get_hca_follower_ids, type='many2many', relation='res.users', string="HCA Stand-Ins"), } def init(self, cr): cr.execute(""" drop view if exists loc_patients; drop view if exists loc_followers; drop view if exists %s; create or replace view loc_patients as ( select location.id as location_id, array_agg(distinct patient.id) as patient_ids from nh_clinical_spell spell inner join nh_activity activity on activity.id = spell.activity_id and activity.state = 'started' inner join nh_clinical_patient patient on patient.id = spell.patient_id left join nh_clinical_location location on location.id = spell.location_id group by location.id ); create or replace view loc_followers as ( select location.id as location_id, groups.name as group_name, array_agg(distinct users.id) as follower_ids from nh_clinical_spell spell inner join nh_activity activity on activity.id = spell.activity_id and activity.state = 'started' inner join nh_clinical_patient patient on patient.id = spell.patient_id left join nh_clinical_location location on location.id = spell.location_id left join user_patient_rel uprel on uprel.patient_id = patient.id left join res_users users on users.id = uprel.user_id left join res_groups_users_rel gurel on gurel.uid = users.id left join res_groups groups on groups.id = gurel.gid group by location.id, groups.name ); create or replace view %s as ( select location.id as id, location.id as location_id from nh_clinical_location location where location.usage = 'bed' ) """ % (self._table, self._table))