# Part of Open eObs. See LICENSE file for full copyright and licensing details.
# -*- coding: utf-8 -*-
"""
Defines helper methods and handlers for eObs Mobile.
"""
import logging
from datetime import datetime
import jinja2
import openerp
import os
from openerp import http
from openerp.addons.nh_eobs_api.controllers.route_api import route_manager
from openerp.addons.nh_eobs_api.routing import Route as EobsRoute
from openerp.addons.nh_eobs_mobile.controllers import urls
from openerp.http import request
from openerp.modules.module import get_module_path
from openerp.osv import orm
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT as DTF
from werkzeug import exceptions
from werkzeug import utils
_logger = logging.getLogger(__name__)
URL_PREFIX = '/mobile/'
URLS = urls.URLS
db_list = http.db_list
db_monodb = http.db_monodb
loader = jinja2.FileSystemLoader(get_module_path('nh_eobs_mobile') + '/views/')
env = jinja2.Environment(loader=loader)
single_patient = EobsRoute(
'single_patient',
'/patient/<patient_id>',
methods=['GET'],
url_prefix='/mobile'
)
patient_list = EobsRoute(
'patient_list',
'/patients/',
methods=['GET'],
url_prefix='/mobile'
)
task_list = EobsRoute(
'task_list',
'/tasks/',
methods=['GET'],
url_prefix='/mobile'
)
single_task = EobsRoute(
'single_task',
'/task/<task_id>',
methods=['GET'],
url_prefix='/mobile'
)
if not route_manager.get_route('single_patient'):
route_manager.add_route(single_patient)
if not route_manager.get_route('patient_list'):
route_manager.add_route(patient_list)
if not route_manager.get_route('single_task'):
route_manager.add_route(single_task)
if not route_manager.get_route('task_list'):
route_manager.add_route(task_list)
[docs]def abort_and_redirect(url):
"""
Aborts and redirects to ``url``.
:param url: URL
:type url: str
:returns: `302 Found` status code and redirection to ``url``
"""
r = request.httprequest
response = utils.redirect(url, 302)
response = r.app.get_response(r, response, explicit_session=False)
exceptions.abort(response)
[docs]def ensure_db(redirect=URLS['login']):
"""
Used by client when a :meth:`http.route()<openerp.http.route>` has
authentication method parameter as "none" (``auth='none'``) and if
the route is dependent on a database.
If no database is found, it will redirect to URL assigned to
``redirect`` parameter.
If database name is from a query parameter, it will be checked by
:meth:`http.db_filter()<openerp.http.db_filter>` thus to avoid
database forgery that could lead to xss attacks.
:param redirect: URL to redirect to
:type redirect: str
:returns: ``None``
:rtype: NoneType
"""
db = request.params.get('db')
# Ensure "legitness" of database
if db and db not in http.db_filter([db]):
db = None
if db and not request.session.db:
# User asked a specific database on a new session.
# That mean the nodb router has been used to find the route
# Depending on installed module in the database,
# the rendering of the page
# may depend on data injected by the database route dispatcher.
# Thus, we redirect the user to the same page but
# with the session cookie set.
# This will force using the database route dispatcher...
r = request.httprequest
url_redirect = r.base_url
if r.query_string:
# Can't use werkzeug.wrappers.BaseRequest.url with encoded hashes:
# https://github.com/amigrave/werkzeug/commit/
# b4a62433f2f7678c234cdcac6247a869f90a7eb7
url_redirect += '?' + r.query_string
utils.redirect(url_redirect, 302)
request.session.db = db
abort_and_redirect(url_redirect)
# if db not provided, use the session one
if not db:
db = request.session.db
# if no database provided and no database in session, use monodb
if not db:
db = db_monodb(request.httprequest)
# if no db can be found til here, send to the database selector
# the database selector will redirect to database manager if needed
if not db:
exceptions.abort(utils.redirect(redirect, 303))
# always switch the session to the computed db
if db != request.session.db:
request.session.logout()
abort_and_redirect(request.httprequest.url)
request.session.db = db
[docs]class MobileFrontend(openerp.addons.web.controllers.main.Home):
"""
Defines handler methods for routes defined in :mod:`urls<urls>`.
"""
[docs] @http.route(URLS['stylesheet'], type='http', auth='none')
def get_stylesheet(self, *args, **kw):
"""
Returns /static/src/css/nhc.css (custom stylesheet) response
object.
:returns: /static/src/css/nhc.css
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/css/nhc.css'.format(
get_module_path('nh_eobs_mobile')
), 'r') as stylesheet:
return request.make_response(
stylesheet.read(),
headers={'Content-Type': 'text/css; charset=utf-8'})
[docs] @http.route(URLS['manifest'], type='http', auth='none')
def get_manifest(self, *args, **kw):
"""
Returns /static/src/manifest.json response object.
:returns: /static/src/manifest.json
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/manifest.json'.format(
get_module_path('nh_eobs_mobile')
), 'r') as manifest:
return request.make_response(
manifest.read(),
headers={'Content-Type': 'application/json'})
[docs] @http.route(URLS['small_icon'], type='http', auth='none')
def get_small_icon(self, *args, **kw):
"""
Returns /static/src/icon/hd_small.png response object.
:returns: /static/src/icon/hd_small.png
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/icon/hd_small.png'.format(
get_module_path('nh_eobs_mobile')
), 'r') as icon:
return request.make_response(
icon.read(), headers={'Content-Type': 'image/png'})
[docs] @http.route(URLS['big_icon'], type='http', auth='none')
def get_big_icon(self, *args, **kw):
"""
Returns /static/src/icon/hd_hi.png response object.
:returns: /static/src/icon/hd_hi.png
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/icon/hd_hi.png'.format(
get_module_path('nh_eobs_mobile')
), 'r') as icon:
return request.make_response(
icon.read(), headers={'Content-Type': 'image/png'})
[docs] @http.route('/mobile/src/fonts/<xmlid>', auth='none', type='http')
def get_font(self, xmlid, *args, **kw):
"""
Returns font-woff response object from fonts contained in
/static/srs/font/.
:returns: a Web Open Font Format (WOFF) font
:rtype: :class:`http.Response<openerp.http.Response>`
"""
mod_path = get_module_path('nh_eobs_mobile')
font_file_request = '{0}/static/src/fonts/{1}'.format(
mod_path, xmlid)
# Consider only the file's name (without additional unwanted parts)
# when checking for file's existence
font_file_path = '{0}/static/src/fonts/{1}'.format(
mod_path, xmlid.split('?')[0]
)
if isinstance(xmlid, basestring) and os.path.exists(font_file_path):
with open(font_file_request, 'r') as font:
return request.make_response(
font.read(),
headers={'Content-Type': 'application/font-woff'})
else:
exceptions.abort(404)
[docs] @http.route(URLS['logo'], type='http', auth='none')
def get_logo(self, *args, **kw):
"""
Returns /static/src/img/open_eobs_logo.png response object.
:returns: /static/src/img/open_eobs_logo.png
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/img/open_eobs_logo.png'.format(
get_module_path('nh_eobs_mobile')
), 'r') as logo:
return request.make_response(
logo.read(), headers={'Content-Type': 'image/png'})
[docs] @http.route(URLS['jquery'], type='http', auth='none')
def get_jquery(self, *args, **kw):
"""
Returns /static/src/js/jquery.js response object.
:returns: /static/src/js/jquery.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/js/jquery.js'.format(
get_module_path('nh_eobs_mobile')
), 'r') as jquery:
return request.make_response(
jquery.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URLS['observation_form_js'], type='http', auth='none')
def get_observation_js(self, *args, **kw):
"""
Returns /static/src/js/observation.js response object.
:returns: /static/src/js/observation.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/js/observation.js'.format(
get_module_path('nh_eobs_mobile')
), 'r') as js:
return request.make_response(
js.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URLS['observation_form_validation'], type='http', auth='none')
def get_observation_validation(self, *args, **kw):
"""
Returns /static/src/js/validation.js response object.
:returns: /static/src/js/validation.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/js/validation.js'.format(
get_module_path('nh_eobs_mobile')
), 'r') as js:
return request.make_response(
js.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URLS['graph_lib'], type='http', auth='none')
def graph_lib(self, *args, **kw):
"""
Returns /static/src/js/nh_graphlib.js response object.
:returns: /static/src/js/nh_graphlib.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/js/nh_graphlib.js'.format(
get_module_path('nh_graphs')
), 'r') as pg:
return request.make_response(
pg.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URLS['patient_graph'], type='http', auth='none')
def patient_graph_js(self, *args, **kw):
"""
Returns /static/src/js/draw_ews_graph.js response object.
:returns: /static/src/js/draw_ews_graph.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/src/js/draw_ews_graph.js'.format(
get_module_path('nh_eobs_mobile')
), 'r') as js:
return request.make_response(
js.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URLS['data_driven_documents'], type='http', auth='none')
def d_three(self, *args, **kw):
"""
Returns /static/lib/js/d3.js response object.
:returns: /static/lib/js/d3.js
:rtype: :class:`http.Response<openerp.http.Response>`
"""
with open('{0}/static/lib/js/d3.js'.format(
get_module_path('nh_graphs')
), 'r') as js:
return request.make_response(
js.read(), headers={'Content-Type': 'text/javascript'})
[docs] @http.route(URL_PREFIX, type='http', auth='none')
def index(self, *args, **kw):
"""
Redirects :class:`user<base.res_users>` to task list if logged
in. Otherwise the user will be redirect to login.
:returns: :class:`Response<werkzeug.wrappers.Response>`
:rtype: :class:`werkzeug.wrappers.Response` object
"""
ensure_db()
if request.session.uid:
return utils.redirect(URLS['task_list'], 303)
else:
return utils.redirect(URLS['login'], 303)
[docs] @http.route(URLS['login'], type="http", auth="none")
def mobile_login(self, *args, **kw):
"""
Logs a :class:`user<base.res_users>` in (HTTP POST), redirecting
to the task list. If username or password is invalid, the login
page response is returned with a message. For HTTP GET, the
the login page response is returned.
:returns: Either task list or login response objects
:rtype: :class:`http.Response<openerp.http.Response>`
"""
if not request.uid:
request.uid = openerp.SUPERUSER_ID
values = request.params.copy()
try:
values['databases'] = http.db_list()
except openerp.exceptions.AccessDenied:
values['databases'] = None
if 'database' in values:
database_legit = values['database'] in values['databases']
if database_legit:
values['databases'] = [values['database']]
login_template = env.get_template('login.html')
if request.httprequest.method == 'GET':
response = request.make_response(
login_template.render(
stylesheet=URLS['stylesheet'],
logo=URLS['logo'],
form_action=URLS['login'],
errors='',
databases=values['databases']
)
)
response.set_cookie(
'session_id',
value=request.session_id,
max_age=3600
)
return response
if request.httprequest.method == 'POST':
# TODO: Refactor to better manage the 'card pin' use case
card_pin = request.params.get('card_pin', None)
if card_pin:
nfc_api = request.registry['res.users']
user_id = nfc_api.get_user_id_from_card_pin(
request.cr, request.uid, card_pin)
user_login = nfc_api.get_user_login_from_user_id(
request.cr, request.uid, user_id)
if user_id is not False:
request.session.db = 'nhclinical'
request.session.uid = user_id
request.session.login = user_login
request.session.password = user_login
return utils.redirect(URLS['task_list'], 303)
database = values['database'] if 'database' in values else False
if database:
uid = request.session.authenticate(
database,
request.params['username'],
request.params['password']
)
if uid is not False:
request.uid = uid
return utils.redirect(URLS['task_list'], 303)
response = request.make_response(
login_template.render(
stylesheet=URLS['stylesheet'],
logo=URLS['logo'],
form_action=URLS['login'],
errors='<div class="alert alert-error">'
'Invalid username/password</div>',
databases=values['databases']
)
)
response.set_cookie(
'session_id',
value=request.session_id,
max_age=3600
)
return response
[docs] @http.route(URLS['logout'], type='http', auth="user")
def mobile_logout(self, *args, **kw):
"""
Logs a :class:`user<base.res_users>` out, returning them to the
login page.
:returns: login page response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
api = request.registry['nh.eobs.api']
api.unassign_my_activities(request.cr, request.session.uid)
request.session.logout(keep_db=True)
return utils.redirect(URLS['login'], 303)
[docs] @staticmethod
def calculate_ews_class(score):
"""
Returns the :class:`EWS<nh_clinical_patient_observation_ews>`
class.
:param score: EWS score
:type score: str
:returns: EWS class
:rtype: str
"""
if score == 'None':
return 'level-none'
elif score == 'Low':
return 'level-one'
elif score == 'Medium':
return 'level-two'
elif score == 'High':
return 'level-three'
else:
return 'level-none'
[docs] def process_patient_list(self, cr, uid, patient_list, context=None):
for patient in patient_list:
patient['url'] = '{0}{1}'.format(
URLS['single_patient'], patient['id'])
patient['color'] = self.calculate_ews_class(
patient['clinical_risk'])
patient['trend_icon'] = 'icon-{0}-arrow'.format(
patient['ews_trend'])
patient['deadline_time'] = patient['next_ews_time']
patient['summary'] = patient.get('summary', False)
if patient.get('followers'):
followers = patient['followers']
follow_csv = ', '.join([f['name'] for f in followers])
patient['followers'] = follow_csv
patient['follower_ids'] = [f['id'] for f in followers]
if patient.get('invited_users'):
users = patient['invited_users']
invite_csv = ', '.join([u['name'] for u in users])
patient['invited_users'] = invite_csv
return patient_list
[docs] @http.route(URLS['patient_list'], type='http', auth="user")
def get_patients(self, *args, **kw):
"""
Returns the patient task list for patients.
:returns: patient task list response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
cr, uid, context = request.cr, request.session.uid, request.context
patient_api = request.registry['nh.eobs.api']
patient_api.unassign_my_activities(cr, uid)
follow_activities = patient_api.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context
)
patients = self.process_patient_list(
cr, uid, patient_api.get_patients(
cr, uid, [], context=context), context=context)
patient_api.get_patient_followers(cr, uid, patients, context=context)
following_patients = self.process_patient_list(
cr, uid, patient_api.get_followed_patients(
cr, uid, []), context=context)
return request.render(
'nh_eobs_mobile.patient_task_list',
qcontext={
'notifications': follow_activities,
'items': patients,
'notification_count': len(follow_activities),
'followed_items': following_patients,
'section': 'patient',
'username': request.session['login'],
'urls': URLS}
)
[docs] @http.route(URLS['share_patient_list'], type='http', auth='user')
def get_share_patients(self, *args, **kw):
"""
Renders the shared patient list.
:returns: shared patient list response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
cr, uid, context = request.cr, request.session.uid, request.context
api = request.registry['nh.eobs.api']
api.unassign_my_activities(cr, uid)
patients = api.get_patients(cr, uid, [], context=context)
api.get_patient_followers(cr, uid, patients, context=context)
api.get_invited_users(cr, uid, patients, context=context)
follow_activities = api.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context
)
self.process_patient_list(cr, uid, patients, context=context)
sorted_pts = sorted(
patients,
key=lambda k: cmp(k['followers'], k['invited_users'])
)
return request.render(
'nh_eobs_mobile.share_patients_list',
qcontext={
'items': sorted_pts,
'section': 'patient',
'username': request.session['login'],
'share_list': True,
'notification_count': len(follow_activities),
'urls': URLS,
'user_id': uid
}
)
[docs] def process_task_list(self, cr, uid, task_list, context=None):
"""
Process the task list from nh.eobs.api.get_activities
:param cr: Odoo cursor
:param uid: user id
:param task_list: list of tasks from get_activities
:param context: Odoo context
:return: list of tasks with extra processing
"""
for task in task_list:
task['url'] = '{0}{1}'.format(URLS['single_task'], task['id'])
task['color'] = self.calculate_ews_class(task['clinical_risk'])
return task_list
[docs] @http.route(URLS['task_list'], type='http', auth='user')
def get_tasks(self, *args, **kw):
"""
Renders the patient task list for tasks.
:returns: task list response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
cr, uid, context = request.cr, request.uid, request.context
task_api = request.registry['nh.eobs.api']
task_api.unassign_my_activities(cr, uid)
follow_activities = task_api.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context
)
# grab the patient object and get id?
tasks = self.process_task_list(
cr, uid, task_api.get_activities(
cr, uid, [], context=context),
context=context)
return request.render(
'nh_eobs_mobile.patient_task_list',
qcontext={
'items': tasks,
'section': 'task',
'username': request.session['login'],
'notification_count': len(follow_activities),
'urls': URLS
}
)
[docs] @http.route(URLS['single_task']+'<task_id>', type='http', auth='user')
def get_task(self, task_id, *args, **kw):
"""
Returns a
:class:`notification<notifications.nh_clinical_notification>`,
:class:`observation<observations.nh_clinical_patient_observation>`
or :class:`placement<operations.nh_clinical_patient_placement>`
task. If the task is neither of these then an error is returned.
:param task_id: id of task
:type task_id: int
:returns: task response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
# If invalid task ID redirect back to task list
try:
task_id = int(task_id)
except ValueError:
return utils.redirect(URLS['task_list'], 303)
# Get the bits we need from the request
cr, uid, context = request.cr, request.uid, request.context
activity_reg = request.registry['nh.activity']
api_reg = request.registry['nh.eobs.api']
# Get the task object
task = activity_reg.read(
cr, uid, task_id,
[
'user_id',
'data_model',
'summary',
'patient_id'
],
context=context)
task_rec = activity_reg.browse(cr, uid, task_id).data_ref
# Get the patient object or redirect to task list if none
patient = dict()
if task and task.get('patient_id'):
patient_info = api_reg.get_patients(
cr, uid, [task['patient_id'][0]], context=context)
if not patient_info:
return utils.redirect(URLS['task_list'], 303)
elif len(patient_info) > 0:
patient_info = patient_info[0]
patient['url'] = URLS['single_patient'] + '{0}'.format(
patient_info['id'])
patient['name'] = patient_info['full_name']
patient['id'] = patient_info['id']
else:
return utils.redirect(URLS['task_list'], 303)
# Unassign user from activities and assign them to this activity
api_reg.unassign_my_activities(cr, uid)
try:
api_reg.assign(cr, uid, task_id, {'user_id': uid}, context=context)
except orm.except_orm as e:
except_message = 'Opening the task (id: {task_id}) ' \
'and trying to assign it to the current ' \
'user (id: {user_id}) raises this ' \
'exception: {exception}'
exception_message = except_message.format(
task_id=task_id,
user_id=uid,
exception=e
)
_logger.debug(exception_message)
return utils.redirect(URLS['task_list'], 303)
# Get follow activities for user
follow_activities = api_reg.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context)
is_notification = 'notification' in task['data_model']
is_placement = 'placement' in task['data_model']
is_observation = 'observation' in task['data_model']
form, form_desc = \
self.get_task_form(cr, uid, task, patient, request)
view_desc = task_rec.get_view_description(form_desc)
# TODO EOBS-1388: Extract adding of task valid key from controller
task_valid = True
if is_notification or is_placement:
task_valid = task_rec.is_valid()
cancellable = task_rec.is_cancellable()
form['confirm_url'] = "{0}{1}".format(
URLS['confirm_clinical_notification'], task_id)
form['action'] = "{0}{1}".format(
URLS['confirm_clinical_notification'], task_id)
form['cancellable'] = cancellable
if cancellable:
form['cancel_url'] = "{0}{1}".format(
URLS['cancel_clinical_notification'], task_id)
if is_notification or is_observation or is_placement:
return request.render(
'nh_eobs_mobile.data_input_screen',
qcontext={
'name': task['summary'],
'view_description': view_desc,
'patient': patient,
'form': form,
'section': 'task',
'username': request.session['login'],
'notification_count': len(follow_activities),
'urls': URLS,
'task_valid': task_valid,
'cancellable': form.get('cancellable', False)
}
)
else:
return request.render(
'nh_eobs_mobile.error',
qcontext={
'error_string': 'Task is neither a notification '
'nor an observation',
'section': 'task',
'username': request.session['login'],
'urls': URLS
}
)
# TODO: eventually remove this method, it's no more used: it has
# been replaced by method 'process_ajax_form()'
# This method is still a valid fallback in case Javascript is disabled
# on the client side, but
# due to our current dependency from Javascript,
# that is a very improbable scenario.
[docs] @http.route(URLS['single_patient']+'<patient_id>',
type='http',
auth='user')
def get_patient(self, patient_id, *args, **kw):
"""
Renders the :class:`patient<base.nh_clinical_patient>` view.
:returns: patient response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
try:
patient_id = int(patient_id)
except ValueError:
return utils.redirect(URLS['patient_list'], 303)
cr, uid, context = request.cr, request.uid, request.context
api_pool = request.registry('nh.eobs.api')
patient_list = api_pool.get_patients(
cr, uid, [patient_id], context=context)
if not patient_list:
return utils.redirect(URLS['patient_list'], 303)
elif len(patient_list) > 0:
patient = patient_list[0]
obs = api_pool.get_active_observations(
cr, uid, patient_id, context=context)
for index, ob in enumerate(obs):
if ob['type'] == 'ews':
obs.insert(0, obs.pop(index))
if ob['type'] == 'gcs':
obs.insert(1, obs.pop(index))
if ob['type'] == 'pain':
obs.insert(2, obs.pop(index))
follow_activities = api_pool.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context)
obs_data_vis_list = api_pool.get_data_visualisation_resources(
cr, uid, context=context)
user_group_ids = request.registry('res.users').read(
cr, uid, uid, ['groups_id'])
user_groups = request.registry('res.groups').read(
cr, uid, user_group_ids.get('groups_id'), ['display_name']
)
user_groups = [rec.get('display_name') for rec in user_groups]
return request.render(
'nh_eobs_mobile.patient',
qcontext={
'patient': patient,
'urls': URLS,
'section': 'patient',
'obs_list': obs,
'notification_count': len(follow_activities),
'username': request.session['login'],
'data_vis_list': obs_data_vis_list,
'user_groups': user_groups
}
)
[docs] @http.route(URLS['patient_ob']+'<observation>/<patient_id>',
type='http', auth='user')
def take_patient_observation(self, observation, patient_id, *args, **kw):
"""
Renders the
:class:`observation<observations.nh_clinical_patient_observation>`
entry view.
:returns: observations entry response object
:rtype: :class:`http.Response<openerp.http.Response>`
"""
cr, uid, context = request.cr, request.uid, request.context
api_pool = request.registry('nh.eobs.api')
follow_activities = api_pool.get_assigned_activities(
cr, uid,
activity_type='nh.clinical.patient.follow',
context=context)
patient = dict()
patient_info = api_pool.get_patients(
cr, uid, [int(patient_id)], context=context)
if not patient_info:
exceptions.abort(404)
elif len(patient_info) > 0:
patient_info = patient_info[0]
patient['url'] = URLS['single_patient'] + '{0}'.format(
patient_info['id'])
patient['name'] = patient_info['full_name']
patient['id'] = patient_info['id']
ob_model_name = \
'nh.clinical.patient.observation.{0}'.format(observation)
form_desc, form = self.process_form_fields(
api_pool.get_form_description(
cr, uid, int(patient_id),
ob_model_name,
context=context)
)
ob_rec = request.registry(ob_model_name)
view_desc = ob_rec.new(cr, uid).get_view_description(form_desc)
form['action'] = URLS['patient_form_action'] + '{0}/{1}'.format(
observation, patient_id)
form['type'] = observation
form['task-id'] = False
form['patient-id'] = int(patient_id)
form['source'] = "patient"
form['start'] = datetime.now().strftime('%s')
observation_name_list = []
for ob in api_pool.get_active_observations(cr, uid, patient_id):
if ob['type'] == observation:
observation_name_list.append(ob['name'])
if len(observation_name_list) == 0:
exceptions.abort(404)
return request.render(
'nh_eobs_mobile.data_input_screen',
qcontext={
'view_description': view_desc,
'name': observation_name_list[0],
'patient': patient,
'form': form,
'section': 'patient',
'notification_count': len(follow_activities),
'username': request.session['login'],
'urls': URLS,
'task_valid': True
}
)