Jul 8 - Update scheduled inspection 2

This commit is contained in:
2026-07-08 15:51:18 -04:00
parent 4d661e9776
commit 3cee604abf
2 changed files with 96 additions and 3 deletions
+29 -2
View File
@@ -23,6 +23,7 @@ from app import db
from app.models.scheduled_inspection import ScheduledInspection
from app.models.facility import Facility
from app.models.inspection import Inspection, InspectionTemplate
from app.models.project import Project
from app.models.user import User
from app.utils.forms import ScheduledInspectionForm
from app.utils.decorators import project_manager_required
@@ -37,6 +38,9 @@ bp = Blueprint('scheduled_inspections', __name__, url_prefix='/scheduled-inspect
def _populate_choices(form):
# facility_id choices are ALL active facilities so POST validation passes
# regardless of which contract the UI-only contract selector had chosen
# (CLAUDE.md rule 61). The contract selector narrows the list client-side.
facilities = Facility.query.filter_by(active=True).order_by(Facility.name).all()
templates = (InspectionTemplate.query
.filter_by(active=True).order_by(InspectionTemplate.name).all())
@@ -47,6 +51,20 @@ def _populate_choices(form):
form.inspector_id.choices = [(u.id, u.display_name) for u in inspectors]
def _active_contracts():
return Project.query.filter_by(active=True).order_by(Project.name).all()
def _selected_project_id(form):
"""Contract of the submitted facility (for restoring the selector on
re-render), or None."""
if form.facility_id.data:
fac = db.session.get(Facility, form.facility_id.data)
if fac:
return fac.project_id
return None
# ── List ──────────────────────────────────────────────────────────────────────
@bp.route('/')
@@ -103,7 +121,9 @@ def create():
return redirect(url_for('scheduled_inspections.index'))
return render_template('scheduled_inspections/form.html',
form=form, title='New Scheduled Inspection')
form=form, title='New Scheduled Inspection',
projects=_active_contracts(),
selected_project_id=_selected_project_id(form))
# ── Edit ──────────────────────────────────────────────────────────────────────
@@ -133,8 +153,15 @@ def edit(schedule_id):
flash('Scheduled inspection updated.', 'success')
return redirect(url_for('scheduled_inspections.index'))
# Restore the contract selector: submitted facility's contract on error,
# otherwise the schedule's current facility's contract.
sel_pid = _selected_project_id(form)
if sel_pid is None and sched.facility:
sel_pid = sched.facility.project_id
return render_template('scheduled_inspections/form.html',
form=form, title='Edit Scheduled Inspection', schedule=sched)
form=form, title='Edit Scheduled Inspection', schedule=sched,
projects=_active_contracts(),
selected_project_id=sel_pid)
# ── Delete ────────────────────────────────────────────────────────────────────
+67 -1
View File
@@ -10,9 +10,21 @@
<form method="POST" novalidate>
{{ form.hidden_tag() }}
{# Contract selector — UI only; narrows the facility list via AJAX #}
<div class="mb-3">
<label class="form-label fw-semibold" for="contract_select">Contract</label>
<select id="contract_select" class="form-select">
<option value="">— Select Contract —</option>
{% for p in projects %}
<option value="{{ p.id }}">{{ p.name }}</option>
{% endfor %}
</select>
</div>
{# Facility — populated by JS once a contract is chosen #}
<div class="mb-3">
{{ form.facility_id.label(class="form-label fw-semibold") }}
{{ form.facility_id(class="form-select") }}
{{ form.facility_id(class="form-select", id="facility_id") }}
{% for e in form.facility_id.errors %}<div class="text-danger small">{{ e }}</div>{% endfor %}
</div>
@@ -65,3 +77,57 @@
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
(function () {
'use strict';
var contractSel = document.getElementById('contract_select');
var facilitySel = document.getElementById('facility_id');
if (!contractSel || !facilitySel) { return; }
var FACILITIES_URL = '{{ url_for("inspections.facilities_for_project", project_id=0) }}'.replace('/0', '/');
var preProjectId = {{ selected_project_id | tojson }};
var preFacilityId = {{ form.facility_id.data | tojson }};
function setPlaceholder() {
facilitySel.innerHTML = '<option value="">— Select a Contract first —</option>';
facilitySel.disabled = true;
}
function loadFacilities(projectId, restoreFacilityId) {
facilitySel.disabled = true;
facilitySel.innerHTML = '<option value="">Loading…</option>';
fetch(FACILITIES_URL + projectId)
.then(function (r) { return r.json(); })
.then(function (data) {
facilitySel.innerHTML = '<option value="">— Select Facility —</option>';
data.forEach(function (f) {
var opt = document.createElement('option');
opt.value = f.id;
opt.textContent = f.name;
if (restoreFacilityId && f.id === restoreFacilityId) { opt.selected = true; }
facilitySel.appendChild(opt);
});
facilitySel.disabled = false;
})
.catch(function () {
facilitySel.innerHTML = '<option value="">Could not load facilities</option>';
});
}
contractSel.addEventListener('change', function () {
if (this.value) { loadFacilities(this.value, null); }
else { setPlaceholder(); }
});
// Initial state: restore the contract + facility on edit / validation error.
if (preProjectId) {
contractSel.value = String(preProjectId);
loadFacilities(preProjectId, preFacilityId);
} else {
setPlaceholder();
}
}());
</script>
{% endblock %}