#!/usr/bin/env python3 """ Fix Subscription DocField restrictions so the REST API can update all fields. Frappe's standard PUT /api/resource/Subscription/{name} silently ignores fields marked read_only=1, set_only_once=1, etc. These restrictions make sense for the desk UI but block our Ops frontend from managing subscriptions. Changes applied (idempotent): 1. status : read_only 1 -> 0 (so we can cancel/reactivate) 2. cancelation_date : read_only 1 -> 0 (set when cancelling) 3. end_date : set_only_once 1 -> 0 (editable for renewals) 4. start_date : set_only_once 1 -> 0 (editable for corrections) 5. follow_calendar_months : set_only_once 1 -> 0 Also disables follow_calendar_months on all subs (conflicts with annual billing unless end_date is set). Run via direct PostgreSQL (no bench CLI needed): python3 scripts/migration/setup_subscription_api.py """ import psycopg2 PG = {"host": "db", "port": 5432, "user": "postgres", "password": "123", "dbname": "_eb65bdc0c4b1b2d6"} def main(): pg = psycopg2.connect(**PG) pgc = pg.cursor() # 1. Remove read_only on status and cancelation_date pgc.execute(""" UPDATE "tabDocField" SET read_only = 0 WHERE parent = 'Subscription' AND fieldname IN ('status', 'cancelation_date') AND read_only = 1 """) n1 = pgc.rowcount print(f" read_only removed: {n1} fields") # 2. Remove set_only_once on end_date, start_date, follow_calendar_months pgc.execute(""" UPDATE "tabDocField" SET set_only_once = 0 WHERE parent = 'Subscription' AND fieldname IN ('end_date', 'start_date', 'follow_calendar_months') AND set_only_once = 1 """) n2 = pgc.rowcount print(f" set_only_once removed: {n2} fields") # 3. Disable follow_calendar_months on all subscriptions # (it requires end_date + monthly billing; breaks annual subs) pgc.execute(""" UPDATE "tabSubscription" SET follow_calendar_months = 0 WHERE follow_calendar_months = 1 """) n3 = pgc.rowcount print(f" follow_calendar_months disabled on {n3} subscriptions") # 4. Fix company name (legacy migration used wrong name) pgc.execute(""" UPDATE "tabSubscription" SET company = 'TARGO' WHERE company != 'TARGO' OR company IS NULL """) n4 = pgc.rowcount print(f" company fixed to TARGO on {n4} subscriptions") pg.commit() pg.close() print() print("Done. Clear Frappe cache to apply DocField changes:") print(" bench --site clear-cache") print(" OR restart the backend container") if __name__ == "__main__": main()