Jul 30 - Update backend for iPad - inspector can re-inspect and create follow-up
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""phase45 — scheduled follow-up: link a schedule back to its parent inspection
|
||||
|
||||
Adds `parent_inspection_id` to `scheduled_inspections`:
|
||||
|
||||
parent_inspection_id INT NULL -- inspection this schedule is a follow-up of
|
||||
|
||||
Lets a follow-up be *planned for a later date* rather than started immediately.
|
||||
The iPad's inspection history detail gains a "Schedule Follow-up" action next to
|
||||
"Re-inspect Now": it creates a one-time schedule carrying this column, and when
|
||||
the inspector eventually starts it the resulting inspection inherits
|
||||
`parent_inspection_id` — so it lands as a true linked re-inspection (pre-filled
|
||||
from the parent, clearing the parent's `follow_up_required` on submit) exactly
|
||||
as if they had tapped "Re-inspect Now" on the day.
|
||||
|
||||
Without the column the scheduled run would be an ordinary inspection: no link,
|
||||
no prefill, and the parent's follow-up flag would stay set forever.
|
||||
|
||||
NULL means "not a follow-up", which is what every existing row is, so there is
|
||||
no backfill and no schedule changes behaviour on deploy.
|
||||
|
||||
ON DELETE SET NULL: deleting the parent inspection must not cascade away a
|
||||
schedule the inspector still has to perform — it just stops being a follow-up.
|
||||
|
||||
Uses an INFORMATION_SCHEMA existence check — safe to re-run. Additive only.
|
||||
"""
|
||||
|
||||
revision = 'phase45_sched_parent_insp'
|
||||
down_revision = 'phase44_sched_end_date'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def _column_exists(conn, table, column):
|
||||
result = conn.execute(sa.text(
|
||||
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS "
|
||||
"WHERE TABLE_SCHEMA = DATABASE() "
|
||||
"AND TABLE_NAME = :t AND COLUMN_NAME = :c"
|
||||
), {"t": table, "c": column})
|
||||
return result.scalar() > 0
|
||||
|
||||
|
||||
def _constraint_exists(conn, table, name):
|
||||
result = conn.execute(sa.text(
|
||||
"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS "
|
||||
"WHERE TABLE_SCHEMA = DATABASE() "
|
||||
"AND TABLE_NAME = :t AND CONSTRAINT_NAME = :n"
|
||||
), {"t": table, "n": name})
|
||||
return result.scalar() > 0
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
if not _column_exists(bind, 'scheduled_inspections', 'parent_inspection_id'):
|
||||
op.execute(sa.text(
|
||||
"ALTER TABLE scheduled_inspections "
|
||||
"ADD COLUMN parent_inspection_id INT NULL AFTER notes"
|
||||
))
|
||||
if not _constraint_exists(bind, 'scheduled_inspections',
|
||||
'fk_sched_insp_parent_inspection'):
|
||||
op.execute(sa.text(
|
||||
"ALTER TABLE scheduled_inspections "
|
||||
"ADD CONSTRAINT fk_sched_insp_parent_inspection "
|
||||
"FOREIGN KEY (parent_inspection_id) REFERENCES inspections(id) "
|
||||
"ON DELETE SET NULL"
|
||||
))
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
if _constraint_exists(bind, 'scheduled_inspections',
|
||||
'fk_sched_insp_parent_inspection'):
|
||||
op.execute(sa.text(
|
||||
"ALTER TABLE scheduled_inspections "
|
||||
"DROP FOREIGN KEY fk_sched_insp_parent_inspection"
|
||||
))
|
||||
if _column_exists(bind, 'scheduled_inspections', 'parent_inspection_id'):
|
||||
op.execute(sa.text(
|
||||
"ALTER TABLE scheduled_inspections DROP COLUMN parent_inspection_id"
|
||||
))
|
||||
Reference in New Issue
Block a user