← All manuals Operator Guide for this screen IM2

Settings

Settings
Technical Spec Ver 1 Updated 2026-09-06 Matches the live screen

Settings — Technical Spec

app/im2.py, template app/templates/settings.html.

Routes

MethodPathAuthNotes
GET/settingsrole == 'admin' (403 "Admins only")Renders scalar settings (left card) and LIST_SETTINGS textareas (right cards; gen_locs gets its own card).
POST/api/settingsadminWhole-form save. Returns {ok:true, changed:N}.

Storage and resolution

Save semantics (POST /api/settings)

Per key in SETTING_KEYS, skipped entirely if absent from the form (so a partial form only touches what it posts):

  1. trim; list keys re-serialized through setting_list; bool keys coerced to Yes/No; uoms upper-cased; default_lead_time_days must parse as a number → stored as int, else 400 "Default lead time must be a whole number of days".
  2. Unchanged vs settings(conn) → skipped, not counted.
  3. val == ""delete from app_settings where key = %s (revert to code default; an empty override is never stored).
  4. Otherwise upsert with updated_by, updated_at = now().
  5. One audit_log row per change: sku = NULL, field_name = key, old→new, source='settings'.

Consumers

allow_fp_watcherro_watch.py; allow_auto_po + wb_count_before_releasepo.py workbench/buy list; ro_classes → RO screens and ro_post.py; uoms → grid, new item, RO lines; income_gl/expense_gl + hidden account ids → qb.py new-item push; default_lead_time_days → Purchasing Workbench; rush_notify_*notify.py.

Known limits / defects

  1. Account names are free text and never validated against QuickBooks; a typo surfaces later as a rejected item push.
  2. ro_classes ids are not validated either — a wrong id posts to the wrong QB class silently.
  3. settings() / setting_bool() open a fresh connection per call when no conn is passed (notify.py and several route paths do exactly that). Cheap per request, but it is a real DB round trip inside best-effort notification code.
  4. No CSRF token; cookie auth + samesite=lax only. A single POST can change every setting, including turning allow_auto_po on.
  5. scripts/schema.sql in this package does not contain app_settings; the live DB has it. Replaying that DDL clean would not produce a working Settings screen.
  6. updated_at.strftime is called unguarded in the template — a row with a NULL updated_at (only reachable by hand-written SQL) would 500 the screen.