From 1d6693adb933ae83c1797f32559006a3ee0e5499 Mon Sep 17 00:00:00 2001 From: justin Date: Tue, 16 Jun 2026 05:00:31 -0500 Subject: [PATCH] govfee: itemize the estimate in the email + add a 'fix my fee' dispute path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gov-fee email now lists exactly what the amount covers (full breakdown) so the customer can check it for accuracy, with two clear actions: a ✅ pay link and a ❓ 'something looks wrong' link to /order/dispute. New /order/dispute page shows the fee breakdown and lets the customer describe what's wrong; it opens an 'issue' support ticket pre-tagged with the order (amount + label + their note) via /api/v1/tickets, so ops corrects the fee before any payment is taken. The /order/pay page also shows the itemized breakdown and a dispute link. --- scripts/workers/services/gov_fee.py | 34 ++++-- site/public/order/dispute/index.html | 149 +++++++++++++++++++++++++++ site/public/order/pay/index.html | 9 ++ 3 files changed, 183 insertions(+), 9 deletions(-) create mode 100644 site/public/order/dispute/index.html diff --git a/scripts/workers/services/gov_fee.py b/scripts/workers/services/gov_fee.py index 721fdae..f882064 100644 --- a/scripts/workers/services/gov_fee.py +++ b/scripts/workers/services/gov_fee.py @@ -243,16 +243,28 @@ def gov_fee_payment_url(child_order_number: str) -> str: return f"{SITE}/order/pay?order={child_order_number}" +def gov_fee_dispute_url(child_order_number: str) -> str: + """Public 'this estimate looks wrong' page that opens a support ticket + pre-tagged with the order so ops can correct the fee.""" + return f"{SITE}/order/dispute?order={child_order_number}" + + def send_gov_fee_payment_email(customer_email: str, customer_name: str, service_label: str, entity_name: str, estimate: GovFeeEstimate, child_order_number: str) -> bool: - """Email the customer a payment link for the government fee.""" + """Email the customer an itemized government-fee bill + payment link, plus a + link to dispute the amount if it looks wrong.""" if not customer_email: return False url = gov_fee_payment_url(child_order_number) + dispute = gov_fee_dispute_url(child_order_number) amt = f"${estimate.cents / 100:,.2f}" - qualifier = "" if estimate.exact else ( - " This is an estimate billed at cost; if the state's final fee differs we " + # Itemized breakdown so the customer can check it for accuracy. + items = "\n".join(f" - {line}" for line in (estimate.breakdown or [estimate.label])) + qualifier = ( + "This amount is the state's confirmed fee." + if estimate.exact else + "This is an estimate billed at cost. If the state's final fee differs we " "refund any overage or bill the small difference.") try: import smtplib @@ -260,13 +272,17 @@ def send_gov_fee_payment_email(customer_email: str, customer_name: str, body = ( f"Hi {customer_name or 'there'},\n\n" f"Your {service_label} for {entity_name} is ready to file. The only " - f"remaining step is the government/state fee, which we collect at cost:\n\n" - f" {service_label}\n" - f" Government fee: {amt}\n" - f" {estimate.label}\n\n" - f"Pay securely here (choose your preferred method — bank transfer/ACH " - f"has no processing fee):\n{url}\n\n" + f"remaining step is the government/state fee, which we collect at cost.\n\n" + f"Here is exactly what the {amt} covers — please review it for accuracy:\n\n" + f" {estimate.label}\n" + f"{items}\n" + f" ----------------------------------------\n" + f" Total government fee: {amt}\n\n" f"{qualifier}\n\n" + f"✅ If this looks right, pay securely here (choose your method — " + f"bank transfer/ACH has no processing fee):\n{url}\n\n" + f"❓ If something looks wrong (wrong fleet size, states, weight, or " + f"amount), tell us here and we'll fix it before you pay:\n{dispute}\n\n" f"As soon as the fee is paid we file with the state and send your " f"confirmation.\n\n" f"Order: {child_order_number}\n" diff --git a/site/public/order/dispute/index.html b/site/public/order/dispute/index.html new file mode 100644 index 0000000..6169f97 --- /dev/null +++ b/site/public/order/dispute/index.html @@ -0,0 +1,149 @@ + + + + + + + Review your fee | Performance West + + + + + + +
+
+
+ +

Review your government fee

+

Loading…

+
+
+
Loading…
+ + +
+
+
+ + + + diff --git a/site/public/order/pay/index.html b/site/public/order/pay/index.html index b28890a..86da795 100644 --- a/site/public/order/pay/index.html +++ b/site/public/order/pay/index.html @@ -140,8 +140,17 @@ const rows = []; if (svc > 0) rows.push(`
${o.service_name || "Service"}${money(svc)}
`); if (gov > 0) rows.push(`
${o.gov_fee_label || "Government fee"}${money(gov)}
`); + // Itemized gov-fee breakdown (so the customer can check it for accuracy). + const intake = (o.intake_data && typeof o.intake_data === "object") ? o.intake_data : {}; + if (Array.isArray(intake.breakdown)) { + intake.breakdown.forEach((b) => rows.push(`
  ${String(b).replace(/
`)); + } if (disc > 0) rows.push(`
Discount-${money(disc)}
`); $("summary").innerHTML = rows.join(""); + // Dispute link for gov-fee orders. + if (gov > 0) { + $("summary").innerHTML += `
Something look wrong with this fee? Tell us before paying →
`; + } $("subtitle").textContent = `${o.customer_name || ""} · ${o.order_number}`; $("loading").style.display = "none"; $("content").style.display = "block";