Not Finished Yet — IM2 Open Items
Built-but-unfinished, switched-off or unreachable code as of 2026-09-06. One line each, with where it lives. Verified by reading the deployed modules, not the briefs.
Posting
POSTING_ENABLED = Falseinapp/ro_pick.py(withPOST_BLOCKED_MSG) —_do_postreturns 403 before touching QuickBooks, so no pick has ever posted from the UI and the wholero_post.post()path is untested in production.- The
SURPLUSbucket inapp/ro_post.py(line_type/ro_line_type == 'SURPLUS'→ro_txnrow with no QB doc) is unreachable:save_addition_qtyinro_pick.pyalways writesline_type='INV'. - Option B in
app/ro_pick.py—OPTION_A_MIXED_POST = True, so the negative-qty rejection branch atapply_qty_entryis retained dead code. ro_txn.operatoris written fromro_pick.operator(the picker) even thoughro_pick.posted_bynow records who pressed Post (ro_post.post(posted_by=…)).- If the invoice fails after the credit memo posted and
qb.delete_doc()also fails, the QB credit memo survives while the DB transaction rolls back — no reconciliation job exists, only the operator message.
Purchasing (app/po.py, app/notify.py)
- Create POs is a disabled placeholder —
po.pymakes no QuickBooks calls at all; the button only reflects theallow_auto_posyscon (setting_bool("allow_auto_po")→auto_po_enabledin thepo_buylist.htmlbanner). No PO is ever written. po_buy_list.released_atis a real column that nothing writes, so the derived status Ordered inbuy_list_display_status()is dormant.notify.py's rush "RO … ordered — PO … — vendor" SMS function is complete and called from nowhere; its intended trigger is the futurereleased_atstamp.
RO intake (app/ro_watch.py, app/ro_parse.py, app/ro_fp.py)
- No schedule. Neither the watcher nor the line parser has a cron/systemd timer; both default to a dry run and have only ever been run by hand.
- The
allow_fp_watchersyscon (im2.pysettings defaults, default "No") exists but no code reads it; wiring it is a prerequisite for the intended hourly run. - No Dropbox intake code exists anywhere in
app/orscripts/— the design-era/SA_Operations/Requirement DB/To Processfolder was never implemented (only the unrelated Item Master seeder touches Dropbox). - BuilderTrend staging (
ro_fp.stage_bt_job) reads thebt_documentcache only; the cache is filled by the out-of-app scriptskills/requirements_orders/scripts/bt_bom_sync.py, not by the app. - The "all three stubs raise NotImplementedError" comment above the stub block in
app/ro_import.pyis stale —stage_source_jobandpromote_inbox_to_roare implemented and delegate toro_fp.
Items (app/im2.py)
GET /api/items/pendingstill selectsqb_status in ('pending','error','sent'), but nothing produces'sent'any more (the/api/items/new-syncsheet endpoint was removed 2026-09-06) andretry-qbignores those rows — historical 'sent' rows are display-only leftovers.
Pick screens (app/ro_pick.py)
_PICK_ITEM_COOKIE/_PICK_ITEM_PICK_COOKIEare not scoped per user, so a shared handheld carries the previous operator's job forward until Change RO / customer or the new Menu button is used.save_order_line_qty()returnsNoneonrowcount == 0— a staleline_keyis silently ignored with no operator message._CLASS_TRIEDis a per-process in-memory set that is never cleared: class derivation retries only after a restart.
To-do list accepted by Dave 2026-09-06
- Gate
/handheld(nginx static alias) and/docsbehind the session cookie — needs an app route or an nginx auth_request, since both bypass FastAPI today. RUSH_SLACK_WEBHOOK_URLunset whilerush_notify_slackis True — every Slack rush alert fails (now audited asrush_notifywith slack=False). Needs a Slack Incoming Webhook for the logistics channel.- Turn on
rush_notify_smsand add rows torush_alert_contact; ClickSend credentials are already in/opt/im2/env. - Auto PO create (
po.pymakes no QB calls,released_atnever written,allow_auto_podrives only a banner) and the untested post path (POSTING_ENABLED = False).
Sign-in hardening shipped 2026-09-06
im2.py: login_attempt table (email, ip, username, ok, tried_at) created on demand; _login_locked() counts failures in the last LOGIN_FAIL_WINDOW_MIN (15) minutes for that email only and blocks for LOGIN_LOCK_MIN (15) after LOGIN_FAIL_LIMIT (5). Deliberately not IP-based: all traffic arrives through one nginx proxy and one warehouse WAN IP, so an IP lock would be a self-inflicted denial of service (this was observed while testing). Real client IP is taken from X-Forwarded-For and stored for forensics. Sessions moved from URLSafeSerializer to URLSafeTimedSerializer with SESSION_MAX_AGE 14 days, enforced in current_user(); pre-change unstamped cookies are still accepted by falling back to the old serializer so nobody was signed out. Cookie now secure=True (http already 301s to https). CSRF closed 2026-09-06 by the same_origin_only middleware (see tech/login); set_pin now audits the target user. No known open security items on sign-in.
Scope trim (Dave, 2026-09-06)
The operator page is a to-do list, not a change log, so three things came off it:
- The old heading "Posting to QuickBooks" read as if no QuickBooks posting worked at all. It is now "Posting material issues to QuickBooks" and says outright that item master writes (create item, item edits) do post — only the pick/issue post path is off (
POSTING_ENABLED = False). - The Dropbox intake bullet, the sign-in security section and the "Small ones" section were FYI, not open work, and were removed. The sign-in changes stay documented in the login help and tech pages.
Added instead: no manual line entry on a buy list. po.py exposes no add-line route — every po_buy_line row is created by POST /po/workbench/save from checked RO demand rows, so a non-inventory item, freight, or a one-off buy that is not on an RO cannot be put on a buy list or carried onto the PO it will eventually create. Needs an add-line route plus a line_type that is not sourced from demand.