#!/usr/bin/env python3 """Add `job_start_date` to the SITES collection. `SiteRecord` has declared this field and the site form has posted it for a long time, but it was never created on the collection — so every site falls back to `first_activity` in resolveSiteStartDate(), and burn %, elapsed %, projected final cost and projected profit are all measured from whenever the earliest record happened to land rather than from the real contract start. Idempotent: a field already present is left alone. Existing fields and data are preserved — this PATCHes the collection's field list rather than replacing it. Run `pb-backup-collection.py SITES` first for a schema snapshot to fall back on. Credentials come from .env.local (or the environment): python3 scripts/pb-add-site-job-start-date.py """ import sys from pb_env import http, superuser_token TOKEN = superuser_token() code, sites = http("GET", "/api/collections/SITES", token=TOKEN) if code != 200: sys.exit(f"could not read SITES: {code} {sites}") fields = sites.get("fields", []) if any(f.get("name") == "job_start_date" for f in fields): print(" • job_start_date already present — nothing to do") sys.exit(0) NEW = {"name": "job_start_date", "type": "date", "required": False} code, resp = http( "PATCH", f"/api/collections/{sites['id']}", {"fields": fields + [NEW]}, TOKEN, ) if code != 200: sys.exit(f" ✗ PATCH FAILED: {code} {resp}") print(" ✓ added job_start_date to SITES") print(f" fields now: {', '.join(f['name'] for f in resp.get('fields', []))}") print( "\nNext: set each site's contract start under Edit on the site. Until a\n" "site has one, its burn and projection still date from first activity." )