175 lines
7.4 KiB
Python
175 lines
7.4 KiB
Python
"""Setup email notifications in ERPNext for DiDi.
|
|
|
|
Required env vars:
|
|
SENDGRID_API_KEY — SendGrid SMTP credential (starts with `SG.`)
|
|
ERPNEXT_ADMIN_PASSWORD — ERPNext Administrator password (default: admin, dev only)
|
|
ERPNEXT_URL — ERPNext base URL (default: http://localhost:8080)
|
|
"""
|
|
import sys, io, os, requests
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
|
|
|
|
SENDGRID_API_KEY = os.environ.get("SENDGRID_API_KEY")
|
|
if not SENDGRID_API_KEY:
|
|
print("ERROR: SENDGRID_API_KEY env var not set. Export it before running:")
|
|
print(" export SENDGRID_API_KEY='SG.your-real-key-here'")
|
|
exit(1)
|
|
|
|
URL = os.environ.get("ERPNEXT_URL", "http://localhost:8080")
|
|
ADMIN_PWD = os.environ.get("ERPNEXT_ADMIN_PASSWORD", "admin")
|
|
|
|
s = requests.Session()
|
|
r = s.post(f"{URL}/api/method/login", data={"usr": "Administrator", "pwd": ADMIN_PWD})
|
|
if r.status_code != 200:
|
|
print(f"Login failed: {r.status_code} — check ERPNEXT_ADMIN_PASSWORD")
|
|
exit(1)
|
|
print("Logged in")
|
|
|
|
def exists(doctype, name):
|
|
r = s.get(f"{URL}/api/resource/{requests.utils.quote(doctype)}/{requests.utils.quote(name)}")
|
|
return r.status_code == 200
|
|
|
|
# ── 1. Email Account (SendGrid) ──
|
|
print("\n1. Email Account...")
|
|
if exists("Email Account", "DiDi Outgoing"):
|
|
print(" Already exists")
|
|
else:
|
|
r = s.post(f"{URL}/api/resource/Email%20Account", json={
|
|
"email_account_name": "DiDi Outgoing",
|
|
"email_id": "office@clossers.com",
|
|
"smtp_server": "smtp.sendgrid.net",
|
|
"smtp_port": 587,
|
|
"use_tls": 1,
|
|
"use_ssl": 0,
|
|
"login_id_for_outgoing": 1,
|
|
"login_id": "apikey",
|
|
"password": SENDGRID_API_KEY,
|
|
"default_outgoing": 1,
|
|
"enable_outgoing": 1,
|
|
"enable_incoming": 0,
|
|
"send_notifications": 1,
|
|
"always_use_account_email_id_as_sender": 1,
|
|
"always_use_account_name_as_sender_name": 1,
|
|
"append_to": "",
|
|
})
|
|
print(f" Created: {r.status_code}")
|
|
|
|
# ── 2. Notification: Factura Emisa ──
|
|
print("\n2. Notification: Factura Emisa...")
|
|
if exists("Notification", "DiDi - Factura Emisa"):
|
|
print(" Already exists")
|
|
else:
|
|
r = s.post(f"{URL}/api/resource/Notification", json={
|
|
"name": "DiDi - Factura Emisa",
|
|
"subject": "Factura {{ doc.name }} - {{ doc.grand_total }} {{ doc.currency }}",
|
|
"document_type": "Sales Invoice",
|
|
"event": "Submit",
|
|
"channel": "Email",
|
|
"attach_print": 1,
|
|
"print_format": "DiDi Invoice",
|
|
"condition": "doc.docstatus == 1",
|
|
"recipients": [
|
|
{
|
|
"receiver_by_document_field": "contact_email",
|
|
}
|
|
],
|
|
"message": """<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<div style="background-color: #0d9488; padding: 20px; text-align: center;">
|
|
<h1 style="color: white; margin: 0;">DiDi - Factura Emisa</h1>
|
|
</div>
|
|
<div style="padding: 30px; background: #f9fafb;">
|
|
<p>Stimate client,</p>
|
|
<p>Va informam ca a fost emisa factura <strong>{{ doc.name }}</strong>.</p>
|
|
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
|
|
<tr style="background: #e5e7eb;"><td style="padding: 8px; font-weight: bold;">Nr. Factura</td><td style="padding: 8px;">{{ doc.name }}</td></tr>
|
|
<tr><td style="padding: 8px; font-weight: bold;">Data</td><td style="padding: 8px;">{{ doc.posting_date }}</td></tr>
|
|
<tr style="background: #e5e7eb;"><td style="padding: 8px; font-weight: bold;">Total</td><td style="padding: 8px;">{{ doc.grand_total }} {{ doc.currency }}</td></tr>
|
|
<tr><td style="padding: 8px; font-weight: bold;">Status</td><td style="padding: 8px;">{{ doc.status }}</td></tr>
|
|
</table>
|
|
<p>Factura in format PDF este atasata la acest email.</p>
|
|
<p>Va multumim,<br><strong>Echipa DiDi / Clossers</strong></p>
|
|
</div>
|
|
<div style="padding: 15px; text-align: center; font-size: 12px; color: #9ca3af;">
|
|
TOP CLOSSERS SRL | CUI: 36193026 | office@clossers.com
|
|
</div>
|
|
</div>""",
|
|
"enabled": 1,
|
|
})
|
|
print(f" Created: {r.status_code}")
|
|
|
|
# ── 3. Notification: Plata Confirmata ──
|
|
print("\n3. Notification: Plata Confirmata...")
|
|
if exists("Notification", "DiDi - Plata Confirmata"):
|
|
print(" Already exists")
|
|
else:
|
|
r = s.post(f"{URL}/api/resource/Notification", json={
|
|
"name": "DiDi - Plata Confirmata",
|
|
"subject": "Plata confirmata - {{ doc.amount }} {{ doc.currency }}",
|
|
"document_type": "Payment Log",
|
|
"event": "New",
|
|
"channel": "Email",
|
|
"condition": "doc.status == 'Succeeded'",
|
|
"recipients": [
|
|
{
|
|
"receiver_by_document_field": "customer",
|
|
}
|
|
],
|
|
"message": """<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<div style="background-color: #0d9488; padding: 20px; text-align: center;">
|
|
<h1 style="color: white; margin: 0;">Plata Confirmata</h1>
|
|
</div>
|
|
<div style="padding: 30px; background: #f9fafb;">
|
|
<p>Stimate client,</p>
|
|
<p>Va confirmam ca plata dumneavoastra a fost procesata cu succes.</p>
|
|
<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
|
|
<tr style="background: #e5e7eb;"><td style="padding: 8px; font-weight: bold;">Suma</td><td style="padding: 8px;">{{ doc.amount }} {{ doc.currency }}</td></tr>
|
|
<tr><td style="padding: 8px; font-weight: bold;">Status</td><td style="padding: 8px;">{{ doc.status }}</td></tr>
|
|
<tr style="background: #e5e7eb;"><td style="padding: 8px; font-weight: bold;">Data</td><td style="padding: 8px;">{{ doc.creation }}</td></tr>
|
|
</table>
|
|
<p>Factura fiscala va fi disponibila in dashboard-ul dumneavoastra.</p>
|
|
<p>Va multumim,<br><strong>Echipa DiDi / Clossers</strong></p>
|
|
</div>
|
|
<div style="padding: 15px; text-align: center; font-size: 12px; color: #9ca3af;">
|
|
TOP CLOSSERS SRL | CUI: 36193026 | office@clossers.com
|
|
</div>
|
|
</div>""",
|
|
"enabled": 1,
|
|
})
|
|
print(f" Created: {r.status_code}")
|
|
|
|
# ── 4. Notification: Expirare Abonament (7 zile inainte) ──
|
|
print("\n4. Notification: Expirare Abonament...")
|
|
if exists("Notification", "DiDi - Expirare Abonament Notificare"):
|
|
print(" Already exists")
|
|
else:
|
|
r = s.post(f"{URL}/api/resource/Notification", json={
|
|
"name": "DiDi - Expirare Abonament Notificare",
|
|
"subject": "Abonamentul dumneavoastra expira in curand",
|
|
"document_type": "Subscription",
|
|
"event": "Days Before",
|
|
"days_in_advance": 7,
|
|
"date_changed": "current_invoice_end",
|
|
"channel": "Email",
|
|
"condition": "doc.status == 'Active'",
|
|
"recipients": [
|
|
{
|
|
"receiver_by_document_field": "party",
|
|
}
|
|
],
|
|
"message": """<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<div style="background-color: #f59e0b; padding: 20px; text-align: center;">
|
|
<h1 style="color: white; margin: 0;">Abonament - Expirare Apropiata</h1>
|
|
</div>
|
|
<div style="padding: 30px; background: #f9fafb;">
|
|
<p>Stimate client,</p>
|
|
<p>Va informam ca abonamentul dumneavoastra expira pe <strong>{{ doc.current_invoice_end }}</strong>.</p>
|
|
<p>Pentru a continua sa beneficiati de serviciile DiDi, va rugam sa reinnoti abonamentul din dashboard.</p>
|
|
<p>Va multumim,<br><strong>Echipa DiDi / Clossers</strong></p>
|
|
</div>
|
|
</div>""",
|
|
"enabled": 1,
|
|
})
|
|
print(f" Created: {r.status_code}")
|
|
|
|
print("\nDone! Email infrastructure ready.")
|
|
print("Email Account 'DiDi Outgoing' configured with key from SENDGRID_API_KEY env var.")
|
|
print("To rotate the key, run this script again with a new SENDGRID_API_KEY value.")
|