{% extends "base.html" %} {% block title %}{{ title }}{% endblock %} {# Laid out to match the single-tenant scheduled-inspection form: one narrow card, Contract → Facility cascade at the top, then what/who, then when. MT keeps three fields ST does not have — the schedule NAME (required by inspection_schedules.name), the AREA (a schedule may target one area) and the auto/plan MODE. They are placed next to the field they qualify rather than in a block of their own. #} {% block content %} {# ── Sticky values ──────────────────────────────────────────────────────── This form is hand-built (no WTForms), so a re-render after a validation error would otherwise come back blank and the user would retype everything. On POST every field reads back from request.form; otherwise from the saved schedule (edit) or its default (create). ST gets this free from WTForms — this is the equivalent. #} {% set posted = request.form if request.method == 'POST' else None %} {% set v_name = posted.get('name') if posted else (schedule.name if schedule else '') %} {% set v_facility = (posted.get('facility_id')|int(0)) if posted else (schedule.facility_id if schedule else 0) %} {% set v_area = (posted.get('area_id')|int(0)) if posted else (schedule.area_id if schedule and schedule.area_id else 0) %} {% set v_template = (posted.get('template_id')|int(0)) if posted else (schedule.template_id if schedule else 0) %} {% set v_inspector = (posted.get('inspector_id')|int(0)) if posted else (schedule.inspector_id if schedule else 0) %} {% set v_frequency = posted.get('frequency') if posted else (schedule.frequency if schedule else 'weekly') %} {% set v_due = posted.get('next_due_date') if posted else (schedule.due_date.isoformat() if schedule and schedule.due_date else '') %} {% set v_end = posted.get('end_date') if posted else (schedule.end_date.isoformat() if schedule and schedule.end_date else '') %} {% set v_mode = posted.get('mode') if posted else (schedule.mode if schedule else 'auto') %} {% set v_notes = posted.get('notes') if posted else (schedule.notes if schedule and schedule.notes else '') %} {% set v_month_mode = posted.get('month_mode') if posted else (schedule.month_mode if schedule else 'day_of_month') %} {% set v_dom = posted.get('day_of_month') if posted else (schedule.day_of_month if schedule and schedule.day_of_month else '') %} {% set v_nth_week = (posted.get('nth_week')|int(0)) if posted else (schedule.nth_week if schedule and schedule.nth_week else 0) %} {% set v_nth_weekday = (posted.get('nth_weekday')|int(-1)) if posted else (schedule.nth_weekday if schedule and schedule.nth_weekday is not none else -1) %} {% set v_weekdays = (posted.getlist('weekdays')|map('int')|list) if posted else (schedule.weekday_list if schedule else []) %} {% set v_active = (posted.get('active') is not none) if posted else (schedule.active if schedule else True) %}
{{ title }}
Shown in the schedule list and in the inspector's reminder.
{# Contract selector — UI only; narrows the facility list via AJAX. It carries no name attribute and is never submitted: the facility is what the route validates (rule 61). #}
Shared forms plus any built for this contract. A form belonging to another contract is rejected on save, not merely hidden here.
{% if schedule %} Snapped forward to the first matching day. Leave it unchanged and saving will not move it. {% else %} Snapped forward to the first matching day. Leave blank to start one full period from now. {% endif %}
{# ── End date ── Hidden for one-time schedules, which end by deactivating when completed. syncFrequency() toggles it; the route clears the column for 'once', so a stale DOM value cannot survive a frequency change. #} {# ── Weekly: which days of the week ──────────────────────────── #} {# ── Monthly: day-of-month OR nth weekday ────────────────────── #}
Auto drops an in-progress inspection into the inspector's queue on schedule. Plan assigns a due date and reminds them the day before, on the day, and alerts managers once it's overdue.
Shown to the assigned inspector when they open this inspection, on the web and on the iPad.
{% if schedule %}
{% endif %}
Cancel

Recurring schedules automatically roll their due date forward each time the inspection is completed. The assigned inspector is reminded the day before and on the due date; managers are alerted if it becomes overdue. {% if schedule %}
Current {{ 'due date' if schedule.mode == 'plan' else 'run' }}: {{ schedule.next_run_at.strftime('%Y-%m-%d %H:%M') if schedule.next_run_at else '—' }} {% if schedule.last_completed_at %} · last completed {{ schedule.last_completed_at.strftime('%Y-%m-%d %H:%M') }} {% endif %} {% if schedule.end_date %}· ends {{ schedule.end_date.strftime('%Y-%m-%d') }}{% endif %}. Reminders for this occurrence are only reset if the due date actually moves, so renaming or re-noting a schedule will not re-send them. {% endif %}

{% endblock %} {% block extra_js %} {% endblock %}