Files
shopdb-flask/plugins/warranty/migrations/versions/0002_proof_document.py
cproudlock 2fce81f33f Attach proof of cover to a warranty
A provider lookup answers whether a unit is covered. It does not produce the
invoice or the extended-warranty certificate, and a manually entered warranty
had nowhere to keep one - so the proof stayed in somebody's mailbox until they
left.

Two columns rather than one: the served URL of the stored document, and the
name the vendor sent it under, because "Dell invoice 4471.pdf" is what a person
recognises a year later and "warranty-12.pdf" is not. The download route sends
the original name back.

Authenticated in both directions, unlike an asset photo: an invoice carries
pricing and a service tag. One document per warranty, replacing any prior
extension so a re-upload as .pdf does not leave the old .png behind claiming to
be current. Capped at 25MB - a certificate is a document, not a disk image.

Office formats are allowed because purchase records genuinely arrive as .msg
and .xlsx, not only as PDFs.
2026-08-12 11:45:40 -04:00

51 lines
1.4 KiB
Python

"""Add warranties.proofurl / prooffilename (proof-of-cover document).
A provider lookup answers whether a unit is covered. It does not produce the
invoice or the extended-warranty certificate, and a manually entered warranty
had nowhere to keep one - so the proof lived in somebody's mailbox until they
left. Two columns: the served URL of the stored file, and the name the vendor
sent it under, which is what a person recognises months later.
Idempotent; downgrade drops both.
Revision ID: warranty0002proof
Revises: warranty0001anchor
"""
from alembic import op
import sqlalchemy as sa
revision = 'warranty0002proof'
down_revision = 'warranty0001anchor'
branch_labels = None
depends_on = None
_TABLE = 'warranties'
_COLUMNS = (('proofurl', sa.String(500)), ('prooffilename', sa.String(255)))
def _column_names(insp, table):
return {c['name'] for c in insp.get_columns(table)}
def upgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if _TABLE not in insp.get_table_names():
return
existing = _column_names(insp, _TABLE)
for name, coltype in _COLUMNS:
if name not in existing:
op.add_column(_TABLE, sa.Column(name, coltype, nullable=True))
def downgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
if _TABLE not in insp.get_table_names():
return
existing = _column_names(insp, _TABLE)
for name, _ in _COLUMNS:
if name in existing:
op.drop_column(_TABLE, name)