Permanent price cuts: - MCS-150 Biennial Update: $69 -> $39 - UCR Annual Registration: $69 -> $39 (+ gov fee unchanged) - MC Operating Authority: $349 -> $199 (+ $300 FMCSA fee unchanged) - State compliance programs (IRP, IFTA, weight-distance/HUT/HUF/KYU, intrastate, OSOW, state DOT, state emissions): -> $109 - California MCP + CARB: $349 -> $229 Updated source of truth (compliance-orders.ts, intake_manifest SERVICE_META), stale dot-lookup recommendation prices, all static trucking landing/marketing pages (services/trucking/*, order/dot-compliance, pricing), and the email campaign scripts (setup_trucking_campaigns, create_state_campaigns). FE/BE price cross-check: all 16 changed slugs consistent. tsc clean, fulfillment consistency 24/24, site build OK.
207 lines
15 KiB
Python
207 lines
15 KiB
Python
#!/usr/bin/env python3
|
|
"""Create state-targeted email campaigns in Listmonk for trucking compliance."""
|
|
import json
|
|
import urllib.request
|
|
import base64
|
|
import sys
|
|
|
|
AUTH = base64.b64encode(b"api:6X1rKPea61N4rZ1S65Hx5zvqzbCj30F6nvEe9oVGH_Y").decode()
|
|
API = "http://localhost:9100/api"
|
|
|
|
def api_call(path, data=None, method=None):
|
|
headers = {"Content-Type": "application/json", "Authorization": "Basic " + AUTH}
|
|
req = urllib.request.Request(API + path, headers=headers)
|
|
if data:
|
|
req.data = json.dumps(data).encode()
|
|
if method:
|
|
req.method = method
|
|
return json.loads(urllib.request.urlopen(req).read())
|
|
|
|
def find_list(name_contains):
|
|
lists = api_call("/lists").get("data", {}).get("results", [])
|
|
for l in lists:
|
|
if name_contains.lower() in l["name"].lower():
|
|
return l
|
|
return None
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# Campaign templates by state
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
CAMPAIGNS = {
|
|
"california": {
|
|
"list_search": "California",
|
|
"name": "CA Motor Carrier Permit + CARB Compliance Alert",
|
|
"subject": "California Motor Carrier Permit — is your MCP current, {{ .Subscriber.Attribs.company }}?",
|
|
"state_section": """
|
|
<h3 style="font-size:15px;font-weight:700;color:#1e3a5f;margin:24px 0 12px;font-family:Inter,sans-serif;">California-Specific Requirements</h3>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;">
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>Motor Carrier Permit (MCP)</strong> — required for all for-hire carriers and CMVs over 10,001 lbs. Annual renewal through CA DMV. Operating without an MCP is a misdemeanor.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>CA Number (CHP)</strong> — issued by California Highway Patrol. Required before you can get an MCP. Must also have a USDOT number.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>CARB Truck & Bus Rule</strong> — all diesel vehicles over 14,000 lbs must have a 2010 or newer engine. Non-compliant vehicles face $1,000/day fines.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;font-family:Inter,sans-serif;"><strong>State Insurance</strong> — California requires $750K+ liability for most carriers, up to $5M depending on cargo. Form E/H filing required with CHP.</td></tr>
|
|
</table>""",
|
|
"services_section": """
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:13px;color:#374151;font-family:Inter,sans-serif;">
|
|
<tr><td style="padding:6px 0;"><strong>California MCP + CARB Compliance</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$229</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>IRP Registration Assistance</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>IFTA Application + Decals</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>State Compliance Bundle</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$599</td></tr>
|
|
</table>""",
|
|
"cta_url": "https://performancewest.net/services/trucking/california/",
|
|
"cta_text": "View California Compliance Services",
|
|
},
|
|
"oregon": {
|
|
"list_search": "Oregon",
|
|
"name": "Oregon Weight-Mile Tax Compliance Alert",
|
|
"subject": "Oregon Weight-Mile Tax — are you registered, {{ .Subscriber.Attribs.company }}?",
|
|
"state_section": """
|
|
<h3 style="font-size:15px;font-weight:700;color:#1e3a5f;margin:24px 0 12px;font-family:Inter,sans-serif;">Oregon-Specific Requirements</h3>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;">
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>Weight-Mile Tax</strong> — Oregon has NO diesel fuel tax for trucks. Instead, all vehicles over 26,001 lbs pay a weight-mile tax based on miles driven and weight class. Filed via Oregon Trucking Online.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>IRP Registration</strong> — interstate carriers must register through ODOT for apportioned plates.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;font-family:Inter,sans-serif;"><strong>ODOT Certificate of Authority</strong> — for-hire intrastate carriers must register with Oregon DOT.</td></tr>
|
|
</table>""",
|
|
"services_section": """
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:13px;color:#374151;font-family:Inter,sans-serif;">
|
|
<tr><td style="padding:6px 0;"><strong>Oregon Weight-Mile Tax Setup</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>IRP Registration Assistance</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>IFTA Application + Decals</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>State Compliance Bundle</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$599</td></tr>
|
|
</table>""",
|
|
"cta_url": "https://performancewest.net/services/trucking/oregon/",
|
|
"cta_text": "View Oregon Compliance Services",
|
|
},
|
|
"new-york": {
|
|
"list_search": "New York",
|
|
"name": "NY Highway Use Tax Compliance Alert",
|
|
"subject": "New York Highway Use Tax — is your HUT current, {{ .Subscriber.Attribs.company }}?",
|
|
"state_section": """
|
|
<h3 style="font-size:15px;font-weight:700;color:#1e3a5f;margin:24px 0 12px;font-family:Inter,sans-serif;">New York-Specific Requirements</h3>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;">
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>Highway Use Tax (HUT)</strong> — New York requires all vehicles over 18,000 lbs to pay the Highway Use Tax. Quarterly filing via NY Department of Tax and Finance. Lowest weight threshold in the US.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;border-bottom:1px solid #fee2e2;font-family:Inter,sans-serif;"><strong>State Insurance</strong> — $750K liability required for most carriers. $1.5M minimum for NYC operations.</td></tr>
|
|
<tr><td style="padding:10px 14px;font-size:13px;color:#991b1b;font-family:Inter,sans-serif;"><strong>Intrastate Authority</strong> — for-hire intrastate carriers need NY DOT Certificate of Authority.</td></tr>
|
|
</table>""",
|
|
"services_section": """
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="font-size:13px;color:#374151;font-family:Inter,sans-serif;">
|
|
<tr><td style="padding:6px 0;"><strong>NY Highway Use Tax Registration</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>IRP Registration Assistance</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>Intrastate Operating Authority</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$109</td></tr>
|
|
<tr><td style="padding:6px 0;"><strong>State Compliance Bundle</strong></td><td style="padding:6px 0;text-align:right;font-weight:700;color:#f97316;">$599</td></tr>
|
|
</table>""",
|
|
"cta_url": "https://performancewest.net/services/trucking/new-york/",
|
|
"cta_text": "View New York Compliance Services",
|
|
},
|
|
}
|
|
|
|
def build_email(cfg):
|
|
"""Build the full email HTML using the general template + state-specific sections."""
|
|
return r"""<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>@media only screen and (max-width:600px){.pw-wrap{width:100%!important;border-radius:0!important;}.pw-pad{padding:24px 16px!important;}}body,table,td,p,a{-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}table{border-collapse:collapse!important;}img{border:0;outline:none;text-decoration:none;}</style></head><body style="margin:0;padding:0;background:#eef0f3;">
|
|
<center>
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:#eef0f3;"><tr><td style="padding:24px 10px;">
|
|
<table role="presentation" class="pw-wrap" width="620" cellpadding="0" cellspacing="0" style="margin:0 auto;border-radius:10px;overflow:hidden;background:#fff;">
|
|
|
|
<tr><td style="background:#1a2744;padding:24px 28px;">
|
|
<img src="https://performancewest.net/images/logo.png" alt="Performance West" style="height:44px;margin-bottom:10px;display:block" />
|
|
<h1 style="color:#fff;margin:0;font-size:22px;font-weight:700;font-family:Inter,system-ui,sans-serif;">State Compliance Alert</h1>
|
|
<p style="color:#94a3b8;margin:6px 0 0;font-size:13px;font-family:Inter,sans-serif;">Compliance report for {{ .Subscriber.Attribs.company }}</p>
|
|
</td></tr>
|
|
|
|
<tr><td style="background:#f97316;height:4px;font-size:0;"> </td></tr>
|
|
|
|
<tr><td class="pw-pad" style="padding:28px;font-family:Inter,system-ui,sans-serif;color:#1f2937;">
|
|
|
|
<p style="font-size:15px;margin:0 0 18px;line-height:1.5;">Hi {{ .Subscriber.Name }},</p>
|
|
|
|
<p style="font-size:14px;line-height:1.7;margin:0 0 18px;">We reviewed compliance records for <strong>{{ .Subscriber.Attribs.company }}</strong> (DOT# {{ .Subscriber.Attribs.dot_number }}) and identified state-level requirements that may need your attention.</p>
|
|
|
|
""" + cfg["state_section"] + """
|
|
|
|
<h3 style="font-size:15px;font-weight:700;color:#1e3a5f;margin:24px 0 12px;font-family:Inter,sans-serif;">Check Your Full Compliance Status</h3>
|
|
|
|
<p style="font-size:14px;line-height:1.7;margin:0 0 18px;">Run our free DOT compliance check to see your complete filing status — federal and state requirements, all in one report.</p>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;"><tr><td style="text-align:center;padding:8px 0;">
|
|
<a href="https://performancewest.net/tools/dot-compliance-check?dot={{ .Subscriber.Attribs.dot_number }}" style="display:inline-block;padding:16px 48px;background:#f97316;color:#fff;font-weight:700;border-radius:8px;text-decoration:none;font-size:16px;font-family:Inter,sans-serif;box-shadow:0 4px 12px rgba(249,115,22,0.4);">Check My DOT Compliance →</a>
|
|
<p style="font-size:11px;color:#6b7280;margin:10px 0 0;font-family:Inter,sans-serif;">Free, no account required. Your DOT# is pre-filled.</p>
|
|
</td></tr></table>
|
|
|
|
<h3 style="font-size:15px;font-weight:700;color:#1e3a5f;margin:24px 0 12px;font-family:Inter,sans-serif;">How We Can Help</h3>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;"><tr><td style="background:#f0f4f8;border-radius:10px;padding:18px;">
|
|
""" + cfg["services_section"] + """
|
|
<p style="font-size:12px;color:#64748b;margin:10px 0 0;font-family:Inter,sans-serif;">We handle the paperwork. You focus on driving.</p>
|
|
</td></tr></table>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:0 0 22px;"><tr><td style="text-align:center;padding:8px 0;">
|
|
<a href=""" + '"' + cfg["cta_url"] + '"' + """ style="display:inline-block;padding:14px 36px;background:#1a2744;color:#fff;font-weight:700;border-radius:8px;text-decoration:none;font-size:15px;font-family:Inter,sans-serif;">""" + cfg["cta_text"] + """ →</a>
|
|
</td></tr></table>
|
|
|
|
<p style="font-size:14px;line-height:1.7;margin:0 0 4px;">Questions? We are happy to help.</p>
|
|
|
|
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin:12px 0 0;"><tr><td style="background:#eff6ff;border:1px solid #bfdbfe;border-radius:10px;padding:14px;text-align:center;">
|
|
<p style="font-size:14px;color:#1e3a5f;margin:0 0 6px;font-weight:600;font-family:Inter,sans-serif;">Reply to this email or reach us at:</p>
|
|
<p style="font-size:20px;color:#1e3a5f;margin:0;font-weight:800;font-family:Inter,sans-serif;"><a href="mailto:info@performancewest.net" style="color:#1e3a5f;text-decoration:none;">info@performancewest.net</a></p>
|
|
<p style="font-size:12px;color:#6b7280;margin:6px 0 0;font-family:Inter,sans-serif;">or call (888) 411-0383</p>
|
|
</td></tr></table>
|
|
|
|
<p style="font-size:14px;line-height:1.7;margin:18px 0 0;">Best,</p>
|
|
<p style="font-size:14px;line-height:1.5;margin:4px 0 0;"><strong>Justin Hannah</strong><br>Performance West Inc.<br><span style="font-size:12px;color:#64748b;">DOT Compliance Services</span></p>
|
|
|
|
</td></tr>
|
|
|
|
<tr><td style="padding:16px 28px;background:#f8fafc;border-top:1px solid #e5e7eb;font-size:11px;color:#9ca3af;text-align:center;font-family:Inter,sans-serif;">
|
|
<p style="margin:0;">Performance West Inc. · 525 Randall Ave Ste 100-1195, Cheyenne, WY 82001 · <a href="https://performancewest.net" style="color:#6b7280;">performancewest.net</a></p>
|
|
<p style="margin:6px 0 0;"><a href="{{ UnsubscribeURL }}" style="color:#6b7280;">Unsubscribe</a></p>
|
|
</td></tr>
|
|
|
|
</table>
|
|
</td></tr></table>
|
|
</center>
|
|
</body></html>"""
|
|
|
|
def main():
|
|
state = sys.argv[1] if len(sys.argv) > 1 else "california"
|
|
if state not in CAMPAIGNS:
|
|
print(f"Unknown state: {state}. Available: {', '.join(CAMPAIGNS.keys())}")
|
|
sys.exit(1)
|
|
|
|
cfg = CAMPAIGNS[state]
|
|
|
|
# Find the Listmonk list
|
|
lst = find_list(cfg["list_search"])
|
|
if not lst:
|
|
print(f"No Listmonk list found containing '{cfg['list_search']}'")
|
|
print("Run the flagger with --state-lists first")
|
|
sys.exit(1)
|
|
|
|
list_id = lst["id"]
|
|
print(f"Found list: {lst['name']} (ID {list_id}, {lst.get('subscriber_count', '?')} subscribers)")
|
|
|
|
# Build the email
|
|
body = build_email(cfg)
|
|
|
|
# Create campaign as draft
|
|
campaign_data = {
|
|
"name": cfg["name"],
|
|
"subject": cfg["subject"],
|
|
"from_email": "Performance West <noreply@performancewest.net>",
|
|
"content_type": "html",
|
|
"body": body,
|
|
"lists": [list_id],
|
|
"template_id": 1,
|
|
"headers": [{"Reply-To": "info@performancewest.net"}],
|
|
"tags": ["state-compliance", state, "dot-compliance"],
|
|
}
|
|
|
|
resp = api_call("/campaigns", campaign_data)
|
|
cid = resp.get("data", {}).get("id")
|
|
print(f"Campaign {cid} created (draft) — '{cfg['name']}'")
|
|
print(f"Review at: http://localhost:9100/campaigns/{cid}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|