feat(govfee): exact fees + agency processing fees; IRP email/invoice reconciliation

- gov_fee: add AGENCY_PROCESSING_FEE (per-service card/convenience fee passed
  through so the customer pays the true all-in cost); estimate_gov_fee now folds
  it into the billed total. IFTA/intrastate/UCR fees are published/near-exact.

- IRP fees can't be looked up — only the base state computes them. New
  irp_filing.py: emails the base-state IRP unit a Schedule A/B request (Reply-To
  the IRP filings mailbox, [PW-IRP CO-...] subject tag), and a 15-min cron
  (irp_invoice_poller) scans the mailbox for the state's invoice reply, parses
  the exact apportioned fee, Telegram-alerts you, and bills the customer the
  EXACT amount via a gov-fee child order + payment link. Then it proceeds to
  ready_to_file for your final approval.

- state_trucking gov-fee gate now routes IRP to the email/invoice path and
  IFTA/intrastate to immediate exact-fee billing.

- Mailbox is configurable (IRP_FILINGS_IMAP_* in app.env.j2); falls back to
  OPS_IMAP_* filtered by the [PW-IRP] tag until a dedicated mailbox exists.

Telegram alerts fire on IRP submission sent, invoice received (billed), and
un-parseable replies (so you can read + enter the fee manually).
This commit is contained in:
justin 2026-06-16 04:58:14 -05:00
parent 861f2fbfd4
commit ea695d6828
6 changed files with 406 additions and 3 deletions

View file

@ -106,6 +106,19 @@ RELAY_IMAP_FOLDER={{ vault_relay_imap_folder | default('INBOX') }}
RELAY_FILING_CARD_ID={{ vault_relay_filing_card_id | default('') }}
CRYPTO_FILING_CARD_ID={{ vault_crypto_filing_card_id | default('') }}
# ── IRP filings mailbox (state apportioned-fee invoice replies) ──────────────
# Dedicated mailbox the IRP submission Reply-To points at; the irp-invoice-poller
# cron scans it for state fee invoices and bills customers the exact amount.
# Leave the IMAP_USER blank to fall back to OPS_IMAP_* and filter by the
# [PW-IRP ...] subject tag.
IRP_FILINGS_IMAP_HOST={{ vault_irp_filings_imap_host | default(smtp_host) }}
IRP_FILINGS_IMAP_PORT={{ vault_irp_filings_imap_port | default('993') }}
IRP_FILINGS_IMAP_USER={{ vault_irp_filings_imap_user | default('') }}
IRP_FILINGS_IMAP_PASS={{ vault_irp_filings_imap_pass | default('') }}
IRP_FILINGS_IMAP_FOLDER={{ vault_irp_filings_imap_folder | default('INBOX') }}
IRP_FILINGS_FROM={{ vault_irp_filings_from | default('filings@performancewest.net') }}
IRP_SC_EMAIL={{ vault_irp_sc_email | default('MCS@scdmv.net') }}
# ── Porkbun (.ca domain registration) ────────────────────────────────────────
PORKBUN_API_KEY={{ vault_porkbun_api_key | default('') }}
PORKBUN_SECRET_KEY={{ vault_porkbun_secret_key | default('') }}

View file

@ -220,6 +220,16 @@ worker_crons:
on_calendar: "*-*-* 16:00:00 UTC"
persistent: true
# IRP apportioned-fee invoice poller — every 15 min. Scans the IRP filings
# mailbox for state replies to our IRP submissions, parses the apportioned fee,
# bills the customer the EXACT amount (gov-fee child order + payment link), and
# Telegram-alerts the operator. See scripts/workers/services/irp_filing.py.
- name: pw-irp-invoice-poller
description: Poll IRP filings mailbox for state fee invoices and bill customers
module: scripts.workers.irp_invoice_poller
on_calendar: "*-*-* *:00/15:00 UTC"
persistent: true
# Daily paper-filing batch (Standard no-login CMS filing path) — weekday
# mornings 13:30 UTC (08:30 CT). Groups all signed, not-yet-mailed CMS filings
# by destination agency (provider's MAC; NPI Enumerator in Fargo for NPPES)