From e25399fd0555defee45d544ec4f3dd025dde5d34 Mon Sep 17 00:00:00 2001 From: Torped Date: Thu, 3 Jul 2025 12:18:28 +0200 Subject: [PATCH] Initial commit --- .env | 12 ++++ ticket.py | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 .env create mode 100644 ticket.py diff --git a/.env b/.env new file mode 100644 index 0000000..9a9bc4e --- /dev/null +++ b/.env @@ -0,0 +1,12 @@ +TWENTY_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJmY2UyYjc4OS1iY2Y4LTQzMjAtYjEyZS0yMjUyZDZkNzhlZjUiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiZmNlMmI3ODktYmNmOC00MzIwLWIxMmUtMjI1MmQ2ZDc4ZWY1IiwiaWF0IjoxNzUwODU4OTI4LCJleHAiOjQ5MDQ0NTg5MjcsImp0aSI6ImNiOTcxMjEyLWExYjAtNGU5NS1hYjI5LWU3YjdiN2E4YWUwMyJ9.mujCJqNnnk0xcQ0VP8m9uLzzXDtjH9AGi0RF2I8VXHA +TWENTY_API=https://crm.toothfairyai.com/rest +ZAMMAD_URL=https://zammad.toothfairyai.com +ZAMMAD_TOKEN=UFcbbba8YICcgk6KTgyvGXblpMhfDIhuXMxouj6sDHEhLF41fty5YcOcmkR8zJmE +ZAMMAD_GROUP=Users +SMTP_SERVER= +SMTP_PORT= +SMTP_USERNAME= +SMTP_PASSWORD= +CUSTOMER_REPLY_SUBJECT="Thanks for contacting ToothFairyAI" +SALES_EMAIL=sales@yourcompany.com +SUPPORT_EMAIL=support@yourcompany.com diff --git a/ticket.py b/ticket.py new file mode 100644 index 0000000..db474e6 --- /dev/null +++ b/ticket.py @@ -0,0 +1,185 @@ +from dotenv import load_dotenv +import os, requests +import smtplib +from email.mime.text import MIMEText + +load_dotenv() + +# — DEBUG: confirm env-vars are loading correctly — +print("→ ZAMMAD_TOKEN:", repr(os.getenv("ZAMMAD_TOKEN"))) +print("→ ZAMMAD_URL: ", repr(os.getenv("ZAMMAD_URL"))) +print("→ TWENTY_API_KEY:", repr(os.getenv("TWENTY_API_KEY"))) + +me = requests.get( + f"{os.getenv('ZAMMAD_URL')}/api/v1/users/me", + headers={"Authorization": f"Token token={os.getenv('ZAMMAD_TOKEN')}"} +) +print("→ GET /users/me:", me.status_code, me.text) + + +def is_business_opportunity(text): + keywords = ["partner", "quote", "enterprise", "demo", "pricing", "ai", "onboarding"] + return any(word in text.lower() for word in keywords) + + +def push_to_twenty(submission): + url = f"{os.getenv('TWENTY_API')}/people" + headers = { + "Authorization": f"Bearer {os.getenv('TWENTY_API_KEY')}", + "Content-Type": "application/json" + } + payload = { + "name": { + "firstName": submission["first_name"], + "lastName": submission["last_name"] + }, + "position": "first", + "emails": { + "primaryEmail": submission["email"], + "additionalEmails": [] + } + } + + res = requests.post(url, headers=headers, json=payload) + if res.status_code not in (200, 201): + print("→ TwentyCRM error:", res.status_code, res.text) + res.raise_for_status() + return res.json()["data"]["createPerson"]["id"] + + +def create_zammad_ticket(submission, is_lead): + """ + Create a new ticket in Zammad (always in 'Users' group). + Title = "Sales: {Name}" if lead, else "Other: {Name}". + If is_lead, article is an email to Gabriele & Scott; otherwise a note. + """ + ZAMMAD_URL = os.getenv('ZAMMAD_URL') + ZAMMAD_TOKEN = os.getenv('ZAMMAD_TOKEN') + ZAMMAD_GROUP = os.getenv('ZAMMAD_GROUP') # must be "Users" + + url = f"{ZAMMAD_URL}/api/v1/tickets" + headers = { + "Authorization": f"Token token={ZAMMAD_TOKEN}", + "Content-Type": "application/json" + } + + name = f"{submission['first_name']} {submission['last_name']}" + ticket_title = f"{'Sales' if is_lead else 'Other'}: {name}" + customer = submission["email"] + + if is_lead: + # Email‐style article + to_addrs = "daniel.grozdanovic@icloud.com" #gabriele.sanguigno@toothfairyai.com, scott.aquilina@toothfairyai.com + article_subject = ticket_title + article_body = ( + f"Name: {name}\n" + f"Email: {customer}\n\n" + f"Message:\n{submission['message']}" + ) + article = { + "to": to_addrs, + "subject": article_subject, + "body": article_body, + "note": submission["message"], + "type": "email", + "internal": False + } + else: + # Internal note + article = { + "subject": ticket_title, + "body": submission["message"], + "note": submission["message"], + "type": "note", + "internal": False + } + + payload = { + "title": ticket_title, + "customer": customer, + "group": ZAMMAD_GROUP, + "article": article + } + + res = requests.post(url, headers=headers, json=payload) + if res.status_code not in (200, 201): + print("→ Zammad create-ticket ERROR:", res.status_code, res.text) + print("→ Payload was:", payload) + res.raise_for_status() + return res.json() + + +def tag_zammad_ticket(ticket_id, tag): + url = f"{os.getenv('ZAMMAD_URL')}/api/v1/tickets/{ticket_id}" + headers = { + "Authorization": f"Token token={os.getenv('ZAMMAD_TOKEN')}", + "Content-Type": "application/json" + } + res = requests.put(url, headers=headers, json={"tags":[tag]}) + if res.status_code not in (200, 201): + print("→ Zammad tag-ticket ERROR:", res.status_code, res.text) + res.raise_for_status() + return res.json() + + +def send_email(to, subject, body): + msg = MIMEText(body) + msg["From"] = os.getenv("SMTP_USERNAME") + msg["To"] = to + msg["Subject"] = subject + with smtplib.SMTP(os.getenv("SMTP_SERVER"), int(os.getenv("SMTP_PORT"))) as server: + server.starttls() + server.login(os.getenv("SMTP_USERNAME"), os.getenv("SMTP_PASSWORD")) + server.send_message(msg) + + +def process_submission(submission): + is_lead = is_business_opportunity(submission["message"]) + crm_id = push_to_twenty(submission) + tag = "sales" if is_lead else "other" + + # Capture the full name here so it's available for internal notifications + name = f"{submission['first_name']} {submission['last_name']}" + + # 1) Create the ticket with the correct title & article + ticket = create_zammad_ticket(submission, is_lead) + + # 2) Tag the ticket + tag_zammad_ticket(ticket["id"], tag) + + # 3) Customer confirmation + send_email( + to=submission["email"], + subject=os.getenv("CUSTOMER_REPLY_SUBJECT"), + body=( + f"Hi {submission['first_name']},\n\n" + f"Your ticket “{ticket['title']}” (ID #{ticket['id']}) is in our system—" + "we'll be in touch soon.\n\n" + "Cheers,\nThe ToothFairyAI Team" + ) + ) + + # 4) Internal notification + internal_to = os.getenv("SALES_EMAIL") if is_lead else os.getenv("SUPPORT_EMAIL") + internal_subj = "🚀 New Business Lead" if is_lead else "ℹ️ New Inquiry" + send_email( + to=internal_to, + subject=internal_subj, + body=( + f"CRM ID: {crm_id}\n" + f"Zammad Ticket: #{ticket['id']} (Title: {ticket['title']}, Tags: {tag})\n" + f"Name: {name}\n" + f"Email: {submission['email']}\n" + f"Message: {submission['message']}" + ) + ) + + +if __name__ == "__main__": + sample = { + "first_name": "Joe", + "last_name": "Smith", + "email": "support@toothfairyai.com", + "message": "Interested in a product demo" + } + process_submission(sample)