trucking wrap-up: close-out becomes a paid order + workflow
- Checker closing mode now pitches a done-for-you 'Trucking Wrap-Up' ($199) with a buy button to /order/dot-compliance?services=carrier-closeout, instead of a lead form. DIY checklist replaced by what's-included list. - Entity dissolution offered as a paid add-on with the lawsuits/liens/judgments warning before dissolving. - New catalog services: carrier-closeout ($199), entity-dissolution ($199). - CarrierCloseoutHandler orchestrates the sequential shutdown workflow (final MCS-150 out-of-business, MC revoke, UCR cancel, IFTA/IRP + state closures; dissolution branch for the add-on) as admin-tracked tasks. - Sell-your-trucks: single shared form with quick-cash / marketplace / both; name field is now a real first+last name (no corp-name prefill). - tickets categories: add truck_sale_both, drop business_closeout (now an order). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1e34707258
commit
b25d1f5fd3
6 changed files with 202 additions and 105 deletions
|
|
@ -1,7 +1,7 @@
|
|||
-- Widen tickets.category to allow lead-capture categories posted by the DOT
|
||||
-- compliance checker (insurance, business close-out, truck-sale routing).
|
||||
-- The CHECK constraint previously only allowed the support-widget categories,
|
||||
-- so these INSERTs failed with a 500.
|
||||
-- Widen tickets.category to allow the lead-capture categories posted by the DOT
|
||||
-- compliance checker (insurance quote + truck-sale routing). The CHECK constraint
|
||||
-- previously only allowed the support-widget categories, so these INSERTs 500'd.
|
||||
-- (Business close-out is handled as a paid order, not a ticket, so it's not here.)
|
||||
|
||||
ALTER TABLE tickets DROP CONSTRAINT IF EXISTS tickets_category_check;
|
||||
|
||||
|
|
@ -13,8 +13,8 @@ ALTER TABLE tickets ADD CONSTRAINT tickets_category_check CHECK (
|
|||
'service_request',
|
||||
'quote',
|
||||
'insurance_lead',
|
||||
'business_closeout',
|
||||
'truck_sale_quickcash',
|
||||
'truck_sale_marketplace'
|
||||
'truck_sale_marketplace',
|
||||
'truck_sale_both'
|
||||
]::text[])
|
||||
);
|
||||
|
|
|
|||
|
|
@ -281,6 +281,18 @@ const COMPLIANCE_SERVICES: Record<
|
|||
erpnext_item: "DOT-FULL-COMPLIANCE",
|
||||
discountable: true,
|
||||
},
|
||||
"carrier-closeout": {
|
||||
name: "Trucking Wrap-Up (USDOT Shutdown)",
|
||||
price_cents: 19900, // $199 — final MCS-150 (out of business) + MC revoke + UCR cancel + state account closures
|
||||
erpnext_item: "CARRIER-CLOSEOUT",
|
||||
discountable: true,
|
||||
},
|
||||
"entity-dissolution": {
|
||||
name: "Business Entity Dissolution (LLC/Corp)",
|
||||
price_cents: 19900, // $199 add-on — LLC/Corp dissolution + final report; state filing fees billed separately
|
||||
erpnext_item: "ENTITY-DISSOLUTION",
|
||||
discountable: true,
|
||||
},
|
||||
// ── State-Level Trucking Compliance ──────────────────────────────────
|
||||
"irp-registration": {
|
||||
name: "IRP Registration Assistance",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const router = Router();
|
|||
|
||||
const VALID_CATEGORIES = [
|
||||
"question", "support", "issue", "service_request", "quote",
|
||||
"insurance_lead", "business_closeout", "truck_sale_quickcash", "truck_sale_marketplace",
|
||||
"insurance_lead", "truck_sale_quickcash", "truck_sale_marketplace", "truck_sale_both",
|
||||
] as const;
|
||||
|
||||
// POST /api/v1/tickets
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ from .state_trucking import StateTruckingHandler
|
|||
# EIN application + virtual mailbox
|
||||
from .ein_application import EINApplicationHandler
|
||||
from .mailbox_setup import MailboxSetupHandler
|
||||
# Carrier close-out / trucking wrap-up (shutdown) + entity dissolution
|
||||
from .carrier_closeout import CarrierCloseoutHandler
|
||||
|
||||
SERVICE_HANDLERS: dict[str, type] = {
|
||||
"flsa-audit": FLSAAuditHandler,
|
||||
|
|
@ -112,6 +114,8 @@ SERVICE_HANDLERS: dict[str, type] = {
|
|||
"emergency-temporary-authority": MCS150UpdateHandler, # ask.fmcsa.dot.gov type 308
|
||||
"ein-application": EINApplicationHandler,
|
||||
"virtual-mailbox": MailboxSetupHandler,
|
||||
"carrier-closeout": CarrierCloseoutHandler, # trucking wrap-up / USDOT shutdown
|
||||
"entity-dissolution": CarrierCloseoutHandler, # add-on, same handler (dissolution branch)
|
||||
"annual-report-filing": MCS150UpdateHandler, # admin-assisted
|
||||
"registered-agent": MCS150UpdateHandler, # admin-assisted (NWRA/CorpTools)
|
||||
"entity-reinstatement": MCS150UpdateHandler, # admin-assisted
|
||||
|
|
|
|||
89
scripts/workers/services/carrier_closeout.py
Normal file
89
scripts/workers/services/carrier_closeout.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
"""Carrier Close-Out — Trucking Wrap-Up workflow.
|
||||
|
||||
Done-for-you shutdown of a motor carrier. Orchestrates the sequential
|
||||
wind-down as an admin-tracked workflow:
|
||||
final MCS-150 (Out of Business) -> revoke MC authority -> cancel UCR ->
|
||||
close IFTA/IRP + state accounts -> advise on insurance timing.
|
||||
|
||||
The `entity-dissolution` add-on (separate slug, same handler) dissolves the
|
||||
LLC/Corp and files the final report — gated on a no-outstanding-liabilities
|
||||
attestation.
|
||||
|
||||
Intake data:
|
||||
- entity_name / legal_name, dot_number, mc_number
|
||||
- phy_state / state, operating_states
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
|
||||
LOG = logging.getLogger("workers.services.carrier_closeout")
|
||||
|
||||
|
||||
class CarrierCloseoutHandler:
|
||||
SERVICE_SLUG = "carrier-closeout"
|
||||
|
||||
async def process(self, order_data: dict) -> list[str]:
|
||||
order_number = order_data.get("order_number", order_data.get("name", ""))
|
||||
return self.handle(order_data, order_number)
|
||||
|
||||
def handle(self, order_data: dict, order_number: str) -> list[str]:
|
||||
intake = order_data.get("intake_data") or {}
|
||||
if isinstance(intake, str):
|
||||
intake = json.loads(intake)
|
||||
|
||||
slug = order_data.get("service_slug", self.SERVICE_SLUG)
|
||||
name = intake.get("entity_name") or intake.get("legal_name") or "Unknown carrier"
|
||||
dot = intake.get("dot_number") or intake.get("usdot") or "N/A"
|
||||
state = intake.get("phy_state") or intake.get("state") or "N/A"
|
||||
LOG.info("[%s] Carrier close-out (%s) for %s (DOT %s)", order_number, slug, name, dot)
|
||||
|
||||
if slug == "entity-dissolution":
|
||||
steps = [
|
||||
"Confirm NO outstanding lawsuits, liens, or judgments before dissolving (client attestation).",
|
||||
f"File Articles of Dissolution for {name} with the {state} Secretary of State.",
|
||||
"File final state report / franchise tax return; close state tax accounts.",
|
||||
"Notify IRS (final return, check the 'final' box); close the EIN if requested.",
|
||||
]
|
||||
title = f"Entity Dissolution — {name} ({state})"
|
||||
else:
|
||||
steps = [
|
||||
f"File final MCS-150 marking carrier OUT OF BUSINESS — deactivate USDOT {dot}.",
|
||||
"Submit voluntary revocation of operating authority (MC) to FMCSA.",
|
||||
"Cancel UCR registration; confirm marked inactive (no next-year bill).",
|
||||
"Close IFTA account, file final quarterly return, retire decals.",
|
||||
f"Return IRP apportioned plates to base state ({state}); close the account.",
|
||||
"Close state-level accounts/permits (CA MCP/CARB, OR weight-mile, NY HUT, KY KYU, etc.) per operating states.",
|
||||
"Advise client on insurance cancellation timing (only AFTER authority is revoked).",
|
||||
]
|
||||
title = f"Trucking Wrap-Up (Shutdown) — {name} (DOT {dot})"
|
||||
|
||||
description = (
|
||||
f"Carrier: {name}\nUSDOT: {dot}\nMC: {intake.get('mc_number', 'N/A')}\n"
|
||||
f"Base state: {state}\nOperating states: {intake.get('operating_states', 'N/A')}\n\n"
|
||||
"Sequential wind-down steps:\n"
|
||||
+ "\n".join(f" {i + 1}. {s}" for i, s in enumerate(steps))
|
||||
)
|
||||
self._create_todo(order_number, intake, title, description, slug, priority="high")
|
||||
return [f"Close-out workflow queued: {title}"]
|
||||
|
||||
def _create_todo(self, order_number, intake, title, description, slug, priority="normal"):
|
||||
try:
|
||||
import psycopg2
|
||||
conn = psycopg2.connect(os.environ.get("DATABASE_URL", ""))
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO admin_todos (
|
||||
title, category, priority, order_number, service_slug,
|
||||
description, data, status
|
||||
) VALUES (%s, %s, %s, %s, %s, %s, %s, 'pending')
|
||||
""",
|
||||
(title, "filing", priority, order_number, slug, description, json.dumps(intake)),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except Exception as exc:
|
||||
LOG.error("[%s] Failed to create close-out todo: %s", order_number, exc)
|
||||
|
|
@ -286,64 +286,59 @@ Send reset link
|
|||
|
||||
function buildCloseoutHtml(data) {
|
||||
var state = data.phy_state || "";
|
||||
var steps = [];
|
||||
steps.push("<strong>File a final MCS-150</strong> marking your carrier “Out of Business.” This deactivates USDOT " + data.dot_number + " so biennial-update obligations and $1,000/day late penalties stop accruing.");
|
||||
steps.push("<strong>Voluntarily revoke your operating authority (MC)</strong> with FMCSA so it isn’t left active and billable after you stop running.");
|
||||
steps.push("<strong>Cancel your UCR registration</strong> — don’t just skip renewal; confirm you’re marked inactive so you aren’t billed next year.");
|
||||
steps.push("<strong>Close your IFTA account</strong>, file a final quarterly return, and return or destroy your IFTA decals.");
|
||||
steps.push("<strong>Return your IRP apportioned plates</strong>" + (state ? " to your base state (" + state + ")" : "") + " and close the account so registration fees stop.");
|
||||
if (STATE_CLOSEOUT[state]) steps.push("<strong>State requirement:</strong> " + STATE_CLOSEOUT[state]);
|
||||
steps.push("<strong>Cancel your insurance</strong> — but only <em>after</em> your authority is revoked, so FMCSA doesn’t flag an insurance lapse on an active carrier.");
|
||||
steps.push("<strong>Dissolve your LLC / corporation</strong> with the state and file a final tax return so you stop owing annual-report fees and franchise tax.");
|
||||
var orderUrl = "/order/dot-compliance?dot=" + data.dot_number + "&services=carrier-closeout&intent=closing";
|
||||
|
||||
var includes = [];
|
||||
includes.push("File your <strong>final MCS-150 (Out of Business)</strong> to deactivate USDOT " + data.dot_number + " — stops biennial-update obligations and $1,000/day late penalties.");
|
||||
includes.push("<strong>Revoke your operating authority (MC)</strong> with FMCSA so it isn’t left active and billable.");
|
||||
includes.push("<strong>Cancel your UCR registration</strong> and confirm you’re marked inactive so next year’s bill never comes.");
|
||||
includes.push("<strong>Close your IFTA account</strong>, file the final quarterly return, and handle your decals.");
|
||||
includes.push("<strong>Return your IRP plates</strong>" + (state ? " to your base state (" + state + ")" : "") + " and close the account.");
|
||||
if (STATE_CLOSEOUT[state]) includes.push("<strong>Close your state account:</strong> " + STATE_CLOSEOUT[state]);
|
||||
includes.push("We tell you <strong>exactly when to cancel your insurance</strong> so FMCSA doesn’t flag a lapse.");
|
||||
|
||||
var h = '';
|
||||
// Intro
|
||||
h += '<div style="background:#f0fdf4;border:2px solid #86efac;border-radius:12px;padding:24px;margin-top:8px">';
|
||||
h += '<h3 style="font-size:18px;font-weight:700;color:#166534;margin:0 0 6px">Winding down ' + data.legal_name + '? Here’s your exit checklist.</h3>';
|
||||
h += '<p style="font-size:14px;color:#374151;margin:0 0 16px">Closing a trucking business is more than parking the truck. Skip a step and the bills — UCR, IRP, state permits, annual reports — keep coming. Here’s what to wrap up, based on your FMCSA record:</p>';
|
||||
h += '<ol style="margin:0;padding:0;list-style:none;counter-reset:step">';
|
||||
steps.forEach(function(s) {
|
||||
h += '<li style="display:flex;gap:12px;padding:10px 0;border-bottom:1px solid #dcfce7;font-size:14px;color:#374151;line-height:1.6">';
|
||||
h += '<span style="flex-shrink:0;width:24px;height:24px;border-radius:50%;background:#16a34a;color:#fff;font-size:13px;font-weight:700;display:flex;align-items:center;justify-content:center;margin-top:1px">✓</span>';
|
||||
// Done-for-you trucking wrap-up service ($199)
|
||||
h += '<div style="background:#f0fdf4;border:2px solid #16a34a;border-radius:12px;padding:24px;margin-top:8px">';
|
||||
h += '<h3 style="font-size:19px;font-weight:800;color:#166534;margin:0 0 6px">Let us handle your entire trucking wrap-up</h3>';
|
||||
h += '<p style="font-size:14px;color:#374151;margin:0 0 14px">Closing ' + data.legal_name + '? Don’t leave loose ends that keep billing you after you’re off the road. We do the whole shutdown for you — no Login.gov, no government portals:</p>';
|
||||
h += '<ul style="margin:0 0 18px;padding:0;list-style:none">';
|
||||
includes.forEach(function(s) {
|
||||
h += '<li style="display:flex;gap:10px;padding:8px 0;border-bottom:1px solid #dcfce7;font-size:14px;color:#374151;line-height:1.6">';
|
||||
h += '<span style="flex-shrink:0;width:22px;height:22px;border-radius:50%;background:#16a34a;color:#fff;font-size:12px;font-weight:700;display:flex;align-items:center;justify-content:center;margin-top:1px">✓</span>';
|
||||
h += '<span>' + s + '</span></li>';
|
||||
});
|
||||
h += '</ol></div>';
|
||||
|
||||
// "Let us handle it" lead capture (green)
|
||||
h += '<div style="background:#fff;border:2px solid #16a34a;border-radius:12px;padding:24px;margin-top:8px">';
|
||||
h += '<h3 style="font-size:17px;font-weight:700;color:#166534;margin:0 0 4px">Let us handle the shutdown paperwork</h3>';
|
||||
h += '<p style="font-size:14px;color:#374151;margin:0 0 14px">We’ll deactivate your USDOT, revoke your authority, cancel UCR, and close your state accounts — so nothing keeps billing you after you’re out. No Login.gov, no government portals.</p>';
|
||||
h += '<input type="text" id="co-name" placeholder="Your name" value="' + (data.legal_name || '') + '" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box">';
|
||||
h += '<input type="email" id="co-email" placeholder="Email address" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box">';
|
||||
h += '<input type="tel" id="co-phone" placeholder="Phone number" value="' + (data.telephone || '') + '" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:10px;box-sizing:border-box">';
|
||||
h += '<button type="button" id="co-submit" style="padding:11px 28px;background:#16a34a;color:#fff;font-weight:700;border-radius:8px;font-size:14px;border:none;cursor:pointer">Get My Shutdown Handled →</button>';
|
||||
h += '<p id="co-status" class="text-xs hidden" style="margin-top:8px"></p>';
|
||||
h += '</ul>';
|
||||
h += '<div style="display:flex;align-items:center;gap:16px;flex-wrap:wrap">';
|
||||
h += '<a href="' + orderUrl + '" style="display:inline-block;padding:14px 34px;background:#16a34a;color:#fff;font-weight:800;border-radius:8px;text-decoration:none;font-size:16px;box-shadow:0 4px 12px rgba(22,163,74,0.3)">Start My Wrap-Up — $199 →</a>';
|
||||
h += '<span style="font-size:13px;color:#15803d;font-weight:600">Flat $199. We file everything for you.</span>';
|
||||
h += '</div>';
|
||||
// Entity dissolution add-on + liability caveat
|
||||
h += '<div style="margin-top:16px;padding-top:14px;border-top:1px solid #dcfce7">';
|
||||
h += '<p style="font-size:13px;color:#374151;margin:0;line-height:1.6"><strong>Also closing the business entity?</strong> Add <strong>LLC/Corp dissolution + final report</strong> at checkout. <span style="color:#b91c1c">Don’t dissolve if you have any outstanding lawsuits, liens, or judgments — settle those first; dissolving with open liabilities can put your personal assets at risk.</span></p>';
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
// Sell-your-trucks box (green)
|
||||
// Sell-your-trucks box (green) — quick cash / marketplace / both, one shared form
|
||||
var optStyle = "flex:1;min-width:180px;padding:14px;border-radius:10px;border:2px solid #86efac;background:#fff;color:#166534;font-weight:700;font-size:14px;cursor:pointer;text-align:left;line-height:1.4";
|
||||
var subStyle = "font-weight:400;font-size:12px;color:#15803d";
|
||||
var inStyle = "width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box";
|
||||
h += '<div style="background:#f0fdf4;border:2px solid #86efac;border-radius:12px;padding:24px;margin-top:8px">';
|
||||
h += '<h3 style="font-size:17px;font-weight:700;color:#166534;margin:0 0 4px">Looking to sell your trucks?</h3>';
|
||||
h += '<p style="font-size:14px;color:#374151;margin:0 0 14px">Two ways to go — pick what fits your timeline:</p>';
|
||||
h += '<p style="font-size:14px;color:#374151;margin:0 0 14px">Pick what fits your timeline — or do both and take the better deal:</p>';
|
||||
h += '<div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:4px">';
|
||||
h += '<button type="button" class="sell-opt" data-opt="quickcash" style="flex:1;min-width:200px;padding:14px;border-radius:10px;border:2px solid #16a34a;background:#fff;color:#166534;font-weight:700;font-size:14px;cursor:pointer;text-align:left;line-height:1.4">💰 Quick cash now<br><span style="font-weight:400;font-size:12px;color:#15803d">Instant offer, pickup in 48–72 hrs</span></button>';
|
||||
h += '<button type="button" class="sell-opt" data-opt="marketplace" style="flex:1;min-width:200px;padding:14px;border-radius:10px;border:2px solid #86efac;background:#fff;color:#166534;font-weight:700;font-size:14px;cursor:pointer;text-align:left;line-height:1.4">🏷️ List it & wait for top dollar<br><span style="font-weight:400;font-size:12px;color:#15803d">We’ll send you the best marketplaces</span></button>';
|
||||
h += '<button type="button" class="sell-opt" data-opt="quickcash" style="' + optStyle + '">💰 Quick cash now<br><span style="' + subStyle + '">Instant offer, pickup in 48–72 hrs</span></button>';
|
||||
h += '<button type="button" class="sell-opt" data-opt="marketplace" style="' + optStyle + '">🏷️ List & wait for top dollar<br><span style="' + subStyle + '">We’ll send the best marketplaces</span></button>';
|
||||
h += '<button type="button" class="sell-opt" data-opt="both" style="' + optStyle + '">🤝 Try both<br><span style="' + subStyle + '">A cash offer AND the listing guide</span></button>';
|
||||
h += '</div>';
|
||||
// Quick-cash form (hidden until chosen)
|
||||
h += '<div id="sell-quickcash" style="display:none;margin-top:14px;padding-top:14px;border-top:1px solid #dcfce7">';
|
||||
h += '<p style="font-size:13px;color:#374151;margin:0 0 10px">We’ll connect you with a vetted truck-buying partner for a no-obligation cash offer. Tell us what you’re selling:</p>';
|
||||
h += '<input type="text" id="qc-name" placeholder="Your name" value="' + (data.legal_name || '') + '" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box">';
|
||||
h += '<input type="tel" id="qc-phone" placeholder="Phone number" value="' + (data.telephone || '') + '" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box">';
|
||||
h += '<input type="email" id="qc-email" placeholder="Email address" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:8px;box-sizing:border-box">';
|
||||
h += '<textarea id="qc-truck" rows="2" placeholder="Year / make / model / mileage / condition" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:10px;box-sizing:border-box;resize:vertical"></textarea>';
|
||||
h += '<button type="button" id="qc-submit" style="padding:11px 28px;background:#16a34a;color:#fff;font-weight:700;border-radius:8px;font-size:14px;border:none;cursor:pointer">Get My Cash Offer →</button>';
|
||||
h += '<p id="qc-status" class="text-xs hidden" style="margin-top:8px"></p>';
|
||||
h += '</div>';
|
||||
// Marketplace form (hidden until chosen)
|
||||
h += '<div id="sell-marketplace" style="display:none;margin-top:14px;padding-top:14px;border-top:1px solid #dcfce7">';
|
||||
h += '<p style="font-size:13px;color:#374151;margin:0 0 10px">Smart move — a private/marketplace sale usually nets more than a quick buyout. Drop your email and we’ll send you our guide to the top truck marketplaces and how to list for the best price.</p>';
|
||||
h += '<input type="email" id="mp-email" placeholder="Email address" style="width:100%;padding:9px 12px;font-size:13px;border:1px solid #bbf7d0;border-radius:8px;outline:none;margin-bottom:10px;box-sizing:border-box">';
|
||||
h += '<button type="button" id="mp-submit" style="padding:11px 28px;background:#16a34a;color:#fff;font-weight:700;border-radius:8px;font-size:14px;border:none;cursor:pointer">Email Me the Marketplace Guide →</button>';
|
||||
h += '<p id="mp-status" class="text-xs hidden" style="margin-top:8px"></p>';
|
||||
h += '<div id="sell-form" style="display:none;margin-top:14px;padding-top:14px;border-top:1px solid #dcfce7">';
|
||||
h += '<p id="sell-intro" style="font-size:13px;color:#374151;margin:0 0 10px"></p>';
|
||||
h += '<input type="text" id="sell-name" placeholder="Your first & last name" style="' + inStyle + '">';
|
||||
h += '<input type="tel" id="sell-phone" placeholder="Phone number" value="' + (data.telephone || '') + '" style="' + inStyle + '">';
|
||||
h += '<input type="email" id="sell-email" placeholder="Email address" style="' + inStyle + '">';
|
||||
h += '<textarea id="sell-truck" rows="2" placeholder="Year / make / model / mileage / condition" style="' + inStyle + 'resize:vertical;margin-bottom:10px"></textarea>';
|
||||
h += '<button type="button" id="sell-submit" style="padding:11px 28px;background:#16a34a;color:#fff;font-weight:700;border-radius:8px;font-size:14px;border:none;cursor:pointer">Submit →</button>';
|
||||
h += '<p id="sell-status" class="text-xs hidden" style="margin-top:8px"></p>';
|
||||
h += '</div>';
|
||||
h += '</div>';
|
||||
|
||||
|
|
@ -386,67 +381,64 @@ Send reset link
|
|||
var loc = (data.phy_city || "") + ", " + (data.phy_state || "");
|
||||
var fleet = data.fleet ? (data.fleet.power_units + " trucks, " + data.fleet.drivers + " drivers") : "unknown";
|
||||
|
||||
// "Handle my shutdown" lead
|
||||
var coBtn = document.getElementById("co-submit");
|
||||
if (coBtn) coBtn.addEventListener("click", function() {
|
||||
var name = document.getElementById("co-name").value.trim();
|
||||
var email = document.getElementById("co-email").value.trim();
|
||||
var phone = document.getElementById("co-phone").value.trim();
|
||||
pwSubmitLead({
|
||||
category: "business_closeout", requireEmail: true, email: email, name: name,
|
||||
btn: coBtn, statusEl: document.getElementById("co-status"),
|
||||
okMsg: "Got it! We'll reach out within 1 business day to start your wind-down.",
|
||||
subject: "Business Close-Out — " + data.legal_name + " (DOT " + data.dot_number + ")",
|
||||
message: ["Business close-out / wind-down request from DOT Compliance Checker.", "",
|
||||
"Carrier: " + data.legal_name, "DOT#: " + data.dot_number, "Location: " + loc, "Fleet: " + fleet,
|
||||
"", "Contact: " + name, "Email: " + email, "Phone: " + (phone || data.telephone || "not provided")].join("\n")
|
||||
});
|
||||
});
|
||||
var MODE = {
|
||||
quickcash: {
|
||||
intro: "We’ll connect you with a vetted truck-buying partner for a no-obligation cash offer. Tell us what you’re selling:",
|
||||
truck: true, btn: "Get My Cash Offer →", category: "truck_sale_quickcash",
|
||||
ok: "Got it — a truck buyer will reach out with a cash offer.", subj: "Truck Sale (Quick Cash)",
|
||||
},
|
||||
marketplace: {
|
||||
intro: "Smart move — a private/marketplace sale usually nets more than a quick buyout. We’ll email you our guide to the best truck marketplaces and how to list for top dollar.",
|
||||
truck: false, btn: "Email Me the Marketplace Guide →", category: "truck_sale_marketplace",
|
||||
ok: "Done! Watch your inbox for our truck-marketplace guide.", subj: "Truck Sale (Marketplace guide)",
|
||||
},
|
||||
both: {
|
||||
intro: "Best of both — we’ll line up a cash offer AND send you the marketplace guide so you can compare and take the better deal. Tell us what you’re selling:",
|
||||
truck: true, btn: "Get a Cash Offer + the Guide →", category: "truck_sale_both",
|
||||
ok: "Done! We’ll line up a cash offer and send the marketplace guide so you can compare.", subj: "Truck Sale (Both — cash offer + marketplace)",
|
||||
},
|
||||
};
|
||||
|
||||
// Sell-trucks option reveal
|
||||
var current = null;
|
||||
var form = document.getElementById("sell-form");
|
||||
document.querySelectorAll(".sell-opt").forEach(function(b) {
|
||||
b.addEventListener("click", function() {
|
||||
var qc = document.getElementById("sell-quickcash");
|
||||
var mp = document.getElementById("sell-marketplace");
|
||||
qc.style.display = b.dataset.opt === "quickcash" ? "block" : "none";
|
||||
mp.style.display = b.dataset.opt === "marketplace" ? "block" : "none";
|
||||
current = b.dataset.opt;
|
||||
var m = MODE[current];
|
||||
if (form) form.style.display = "block";
|
||||
document.getElementById("sell-intro").innerHTML = m.intro;
|
||||
document.getElementById("sell-truck").style.display = m.truck ? "block" : "none";
|
||||
document.getElementById("sell-submit").innerHTML = m.btn;
|
||||
document.getElementById("sell-status").classList.add("hidden");
|
||||
document.querySelectorAll(".sell-opt").forEach(function(x) {
|
||||
x.style.background = x === b ? "#dcfce7" : "#fff";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Quick-cash → truck-buyer referral lead
|
||||
var qcBtn = document.getElementById("qc-submit");
|
||||
if (qcBtn) qcBtn.addEventListener("click", function() {
|
||||
var name = document.getElementById("qc-name").value.trim();
|
||||
var phone = document.getElementById("qc-phone").value.trim();
|
||||
var email = document.getElementById("qc-email").value.trim();
|
||||
var truck = document.getElementById("qc-truck").value.trim();
|
||||
var sBtn = document.getElementById("sell-submit");
|
||||
if (sBtn) sBtn.addEventListener("click", function() {
|
||||
if (!current) return;
|
||||
var m = MODE[current];
|
||||
var name = document.getElementById("sell-name").value.trim();
|
||||
var phone = document.getElementById("sell-phone").value.trim();
|
||||
var email = document.getElementById("sell-email").value.trim();
|
||||
var truck = document.getElementById("sell-truck").value.trim();
|
||||
var statusEl = document.getElementById("sell-status");
|
||||
if (!name) {
|
||||
statusEl.textContent = "Please enter your first & last name.";
|
||||
statusEl.className = "text-xs text-red-600"; statusEl.classList.remove("hidden");
|
||||
return;
|
||||
}
|
||||
pwSubmitLead({
|
||||
category: "truck_sale_quickcash", requireEmail: false, email: email, name: name,
|
||||
btn: qcBtn, statusEl: document.getElementById("qc-status"),
|
||||
okMsg: "Got it — we'll connect you with a truck buyer who'll reach out with a cash offer.",
|
||||
subject: "Truck Sale (Quick Cash) — " + data.legal_name + " (DOT " + data.dot_number + ")",
|
||||
message: ["Quick-cash truck sale lead from DOT Compliance Checker — route to truck-buying partner.", "",
|
||||
category: m.category, requireEmail: true, email: email, name: name,
|
||||
btn: sBtn, statusEl: statusEl, okMsg: m.ok,
|
||||
subject: m.subj + " — " + data.legal_name + " (DOT " + data.dot_number + ")",
|
||||
message: [m.subj + " lead from DOT Compliance Checker.", "",
|
||||
"Carrier: " + data.legal_name, "DOT#: " + data.dot_number, "Location: " + loc, "Fleet: " + fleet,
|
||||
"Vehicle(s): " + (truck || "not specified"), "",
|
||||
"Contact: " + name, "Email: " + email, "Phone: " + (phone || data.telephone || "not provided")].join("\n")
|
||||
});
|
||||
});
|
||||
|
||||
// Marketplace → guide follow-up lead
|
||||
var mpBtn = document.getElementById("mp-submit");
|
||||
if (mpBtn) mpBtn.addEventListener("click", function() {
|
||||
var email = document.getElementById("mp-email").value.trim();
|
||||
pwSubmitLead({
|
||||
category: "truck_sale_marketplace", requireEmail: true, email: email, name: data.legal_name,
|
||||
btn: mpBtn, statusEl: document.getElementById("mp-status"),
|
||||
okMsg: "Done! Watch your inbox for our truck-marketplace guide.",
|
||||
subject: "Truck Sale (Marketplace guide) — " + data.legal_name + " (DOT " + data.dot_number + ")",
|
||||
message: ["Marketplace truck-sale lead from DOT Compliance Checker — send marketplace guide follow-up.", "",
|
||||
"Carrier: " + data.legal_name, "DOT#: " + data.dot_number, "Location: " + loc, "Fleet: " + fleet,
|
||||
"", "Email: " + email].join("\n")
|
||||
(m.truck ? "Vehicle(s): " + (truck || "not specified") : null), "",
|
||||
"Contact: " + name, "Email: " + email, "Phone: " + (phone || data.telephone || "not provided")]
|
||||
.filter(function(x) { return x !== null; }).join("\n"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue