Source code for uw.local.grad.db.status

"""State change implementation.

This module implements the state change form and provides a routine for
changing the state of an application while performing appropriate
notifications.
"""

from datetime import date

from ll.xist.ns import html

from uw.web.html.form import render_hidden, render_select
from uw.web.html.bootstrapform import render_bootstrap_submit, render_bootstrap_date_selector
from uw.local.util.uw_business_day import non_business_days_in_span

from . import notification

from ..webui.list import render_status_select

reason_gso_mapping = {"REJ": "DENY", "RJR": "DENY", "RJS": "DENY"}

MONTH_SELECT_RANGE = 6

[docs]def render_state_change_usual_form (unitapp, action_url="", form_class=None, select_class=None): """Render the form for an application's usual state changes as HTML. :param unitapp: the candidate application. :param action_url: the form's action URL. :param form_class: CSS class to apply to the form :param select_class: CSS class to apply to the select inputs Generates a separate small form for each state change normally permitted from the current state. Each form has a button and if appropriate a date selector for the new deadline. """ state_info = unitapp.cursor.execute_tuples ("select * from work_application_status_change AS wa where %s order by status_sequence" % unitapp.where, **unitapp.vars) result = [] for row in state_info: item = html.p ( render_hidden ("!status", row.new_status_code), render_hidden ("statusdesc", row.new_status_description), render_bootstrap_submit ("%s…" % row.new_status_description, class_ = "default-font") ) if row.new_deadline is not None and not row.fixed_deadline: item.append ( ' (with a deadline of ', render_bootstrap_date_selector ('date', current=row.new_deadline, months=MONTH_SELECT_RANGE, class_=select_class, disable_days=non_business_days_in_span (unitapp.cursor, months=MONTH_SELECT_RANGE, holidays_only=True)), ')', ) if row.new_status_code == "RJR": item.append (render_reason_form ("reason", unitapp.cursor, reason_gso_mapping[row.new_status_code], class_=select_class)) result.append (html.form (item, action=action_url, method="post", class_=form_class)) return result
[docs]def render_reason_form(name, cursor, status, class_=None): """Render an input for the reasons for state entry. :param name: input name :param cursor: Database cursor :param status: GSO Status for which to construct the reasons :param class_: CSS class to apply to the input """ reasons = cursor.execute_tuples("select program_reason_code, format ('%%s (%%s)', program_reason_description, program_reason_code) as descr from uw_program_reason where program_action_code = %(status)s order by descr", status=status) return html.span (" Reason: ", render_select (name, reasons, class_=class_), class_ = "reason-input" )
[docs]def render_state_change_override_form (cursor, form_class=None, select_class=None, blank=False): """Render the form for overriding an application's state as HTML. :param cursor: a database cursor :param form_class: CSS class to apply to the form :param select_class: CSS clss to apply to the form's select :param blank: include blank option Generates a form with a selector to choose a new state and a date selector for the new deadline. """ return ( html.form ( render_hidden ("override", ""), render_bootstrap_submit ("To…"), ' ', render_status_select (cursor, "!status", class_=select_class), ' (with a deadline of ', render_bootstrap_date_selector ('date', current = date.today (), months=MONTH_SELECT_RANGE, class_=select_class, days_of_week_disabled=""), ')', class_=form_class, action="", method="post" ) )
[docs]def change_state (unitapp, remote_identity, status, deadline=None, use_default=False, override=False, reason_code=None): """Change the state of an application, generating notifications. :param unitapp: the candidate application. :param remote_identity: the user's remote identity. :param status: the new status code. :param deadline: the deadline, or None for no new deadline; but the use_default parameter overrides this. :param use_default: whether to use the default deadline for the new state instead of the deadline parameter. :param override: whether the state change is an override. :param reason_code: an optional reason code Changes the state of the application to the given new state and deadline. Uses :mod:`uw.local.grad.db.notification` to generate appropriate notifications depending on the new state. """ if use_default: deadline = unitapp.cursor.execute_required_value ("select uw_business_day_offset (current_date, status_default_deadline) from work_application_status_code where status_code=%(status_code)s", status_code=status) person_id = None if remote_identity is None else remote_identity.person_id unitapp.cursor.execute_none ("insert into work_application_status (uw_id, appl_id, status_code, person_id, deadline, override) values (%(uw_id)s, %(appl_id)s, %(status_code)s, %(person_id)s, %(deadline)s, %(override)s)", status_code=status, person_id=person_id, deadline=deadline or 'infinity', override=override, **unitapp.vars) if reason_code is not None or status not in reason_gso_mapping: unitapp.cursor.execute_none ("update work_application set deny_reason_code=%(reason_code)s where (appl_id, uw_id) = (%(appl_id)s, %(uw_id)s)", reason_code = reason_code, **unitapp.vars) unitapp_url = unitapp.base_url () if status == 'INR': # Notify Director of Admissions notification.notify (unitapp.cursor, unitapp.find_authorized (['DIR']), 'INR', 'The application of %s %s is available for Initial Review.' % (unitapp.applicant.first_name, unitapp.applicant.last_name), unitapp_url) elif status == 'REJ': # Email applicant? pass elif status == 'RJR': # deny requested # Notify Admissions Coordinator notification.notify (unitapp.cursor, unitapp.find_authorized (['ADC']), 'RJR', 'The application of %s %s has been requested to be denied.' % (unitapp.applicant.first_name, unitapp.applicant.last_name), unitapp_url) elif status == 'CIR': # Notify faculty members notification.notify (unitapp.cursor, unitapp.find_concerned (), 'CIR', 'The application of %s %s is now in circulation.' % (unitapp.applicant.first_name, unitapp.applicant.last_name), unitapp_url) elif status == 'FAC': # Email faculty members pass elif status == 'ACP': # Notify Admissions Coordinator notification.notify (unitapp.cursor, unitapp.find_authorized (['ADC']), 'ACP', 'The application of %s %s has been changed to generating offer.' % (unitapp.applicant.first_name, unitapp.applicant.last_name), unitapp_url) elif status == 'INO': # Email supervisor(s) notification.notify (unitapp.cursor, unitapp.find_supervisors(), 'INO', 'An inital offer has been sent to %s %s.' % (unitapp.applicant.first_name, unitapp.applicant.last_name), unitapp_url) elif status == 'DEC' or status == 'OFA': # Notify Director of Admissions and Faculty notification.notify (unitapp.cursor, unitapp.find_authorized (['DIR']) | unitapp.find_interested (), 'SRP', 'Applicant %s %s has %s our offer.' % (unitapp.applicant.first_name, unitapp.applicant.last_name, 'accepted' if status=='OFA' else 'declined'), unitapp_url) elif status == 'ACR': # Email GSO? pass