"""Post-completion email flow. Sends two emails after an order is marked completed: 1. Immediately: "Your filing is complete!" with documents 2. 24 hours later: Exit survey + referral program + review ask Run via cron every 15 minutes: python -m scripts.workers.completion_emails """ import json import logging import os import smtplib import sys import urllib.request from datetime import datetime, timedelta, timezone from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from scripts._email_plaintext import html_to_text import psycopg2 LOG = logging.getLogger("workers.completion_emails") DB_URL = os.getenv("DATABASE_URL", "") SMTP_FROM = "noreply@performancewest.net" SITE_URL = os.getenv("SITE_URL", "https://performancewest.net") API_URL = os.getenv("API_URL", "https://api.performancewest.net") GOOGLE_REVIEW_URL = os.getenv("GOOGLE_REVIEW_URL", "") TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN", "") TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID", "") def send_email(to: str, subject: str, html: str): """Send an HTML email via local Postfix.""" msg = MIMEMultipart("alternative") msg["From"] = f"Performance West <{SMTP_FROM}>" msg["To"] = to msg["Subject"] = subject msg.attach(MIMEText(html_to_text(html), "plain")) msg.attach(MIMEText(html, "html")) import os as _smtp_os with smtplib.SMTP(_smtp_os.getenv("SMTP_HOST", "co.carrierone.com"), int(_smtp_os.getenv("SMTP_PORT", "587")), timeout=30) as s: s.starttls() _u, _p = _smtp_os.getenv("SMTP_USER", ""), _smtp_os.getenv("SMTP_PASS", "") if _u and _p: s.login(_u, _p) s.sendmail(SMTP_FROM, [to], msg.as_string()) def get_or_create_referral_code(conn, email: str, name: str) -> str: """Get or create a referral code for a customer.""" cur = conn.cursor() cur.execute("SELECT code FROM referral_codes WHERE customer_email = %s", (email,)) row = cur.fetchone() if row: return row[0] clean = "".join(c for c in name.upper() if c.isalpha())[:12] code = f"REF-{clean or 'CUSTOMER'}" # Ensure unique cur.execute("SELECT 1 FROM referral_codes WHERE code = %s", (code,)) if cur.fetchone(): import random code = f"{code}{random.randint(10, 99)}" try: cur.execute( "INSERT INTO referral_codes (code, customer_email, customer_name) VALUES (%s, %s, %s) ON CONFLICT DO NOTHING", (code, email, name), ) conn.commit() except Exception: conn.rollback() return code def completion_email_html(order_number: str, service_name: str, customer_name: str) -> str: """Generate the completion email HTML.""" first = customer_name.split()[0] if customer_name else "there" return f"""
Performance West

Your {service_name} Is Complete!

Hi {first},

Great news — your {service_name} has been completed and filed successfully. Order reference: {order_number}.

You can view your documents and track all your filings in your client portal:

View in Portal →

If you have any questions about your filing, reply to this email or call us at (888) 411-0383.

— The Performance West Team

Performance West Inc. · (888) 411-0383 · performancewest.net
""" def followup_email_html( order_number: str, service_name: str, customer_name: str, referral_code: str, ) -> str: """Generate the 24h follow-up email with survey + referral.""" first = customer_name.split()[0] if customer_name else "there" survey_url = f"{SITE_URL}/survey?order={order_number}" return f"""
Performance West

How did we do, {first}?

Your {service_name} was completed yesterday. We'd love your feedback — it takes 30 seconds.

Rate your experience:

Click a star to rate

Know another trucker?

Share your referral code and earn $25 credit for each order they place.

Your referral code:

{referral_code}

They can enter this code at checkout. You earn $25 credit per order — no limit.

Thank you for choosing Performance West. We're here whenever you need us.

— The Performance West Team

Performance West Inc. · (888) 411-0383 · performancewest.net
""" def process_completions(): """Find completed orders and send emails.""" conn = psycopg2.connect(DB_URL) cur = conn.cursor() now = datetime.now(timezone.utc) # 1. Send completion emails (order completed, email not sent yet) cur.execute(""" SELECT order_number, customer_email, customer_name, service_name, updated_at FROM compliance_orders WHERE payment_status = 'paid' AND completion_email_sent_at IS NULL AND updated_at < NOW() - interval '5 minutes' AND ( intake_data->>'status' = 'completed' OR intake_data->>'status' = 'delivered' OR intake_data->>'status' = 'filed' ) ORDER BY updated_at LIMIT 20 """) completions = cur.fetchall() for row in completions: order_number, email, name, service_name, updated_at = row if not email: continue try: html = completion_email_html(order_number, service_name or "compliance filing", name or "") send_email(email, f"✅ Your {service_name or 'filing'} is complete — {order_number}", html) cur.execute( "UPDATE compliance_orders SET completion_email_sent_at = NOW() WHERE order_number = %s", (order_number,), ) conn.commit() LOG.info("[completion] Sent completion email for %s to %s", order_number, email) except Exception as exc: LOG.error("[completion] Failed for %s: %s", order_number, exc) conn.rollback() # 2. Send 24h follow-up emails (completion email sent 24h+ ago, follow-up not sent) cur.execute(""" SELECT order_number, customer_email, customer_name, service_name FROM compliance_orders WHERE payment_status = 'paid' AND completion_email_sent_at IS NOT NULL AND completion_email_sent_at < NOW() - interval '24 hours' AND followup_email_sent_at IS NULL ORDER BY completion_email_sent_at LIMIT 20 """) followups = cur.fetchall() for row in followups: order_number, email, name, service_name = row if not email: continue try: referral_code = get_or_create_referral_code(conn, email, name or "") html = followup_email_html(order_number, service_name or "compliance filing", name or "", referral_code) send_email(email, f"How was your experience? + Earn $25 referrals", html) cur.execute( "UPDATE compliance_orders SET followup_email_sent_at = NOW(), referral_code = %s WHERE order_number = %s", (referral_code, order_number), ) conn.commit() LOG.info("[followup] Sent follow-up email for %s to %s (ref: %s)", order_number, email, referral_code) except Exception as exc: LOG.error("[followup] Failed for %s: %s", order_number, exc) conn.rollback() conn.close() total = len(completions) + len(followups) if total: LOG.info("[completion_emails] Processed %d completion + %d follow-up emails", len(completions), len(followups)) def main(): logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s %(message)s", ) process_completions() if __name__ == "__main__": main()