Template
Extract always-on public/portal/UTM plus optional email_sms, directmail, blog, payments, social, and social_ai so new client sites can be bootstrapped from this seed. Refs #1 Refs #2 Co-authored-by: Cursor <cursoragent@cursor.com>
67 lines
2.3 KiB
Python
67 lines
2.3 KiB
Python
"""Lob postcard adapter (default)."""
|
|
|
|
from dataclasses import dataclass
|
|
|
|
import requests
|
|
from django.conf import settings
|
|
|
|
from directmail.providers.postcard import PostcardResult
|
|
|
|
|
|
@dataclass
|
|
class LobProvider:
|
|
name: str = "lob"
|
|
|
|
def send_postcard(self, message) -> PostcardResult:
|
|
api_key = settings.LOB_API_KEY
|
|
if not api_key:
|
|
raise RuntimeError("LOB_API_KEY is not configured")
|
|
|
|
contact = message.contact
|
|
address = contact.postal_address or {}
|
|
if not address.get("line1"):
|
|
raise ValueError("Contact postal_address.line1 required for postcard")
|
|
|
|
# Minimal Lob create-postcard payload; artwork URLs come from template JSON.
|
|
template = message.campaign.template
|
|
front = (template.postcard_front if template else {}) or {}
|
|
back = (template.postcard_back if template else {}) or {}
|
|
|
|
payload = {
|
|
"description": f"campaign-{message.campaign_id}",
|
|
"to": {
|
|
"name": contact.full_name or contact.email or "Resident",
|
|
"address_line1": address.get("line1", ""),
|
|
"address_line2": address.get("line2", ""),
|
|
"address_city": address.get("city", ""),
|
|
"address_state": address.get("state", ""),
|
|
"address_zip": address.get("zip", ""),
|
|
"address_country": address.get("country", "US"),
|
|
},
|
|
"front": front.get("html") or front.get("url") or "<html></html>",
|
|
"back": back.get("html") or back.get("url") or "<html></html>",
|
|
}
|
|
response = requests.post(
|
|
"https://api.lob.com/v1/postcards",
|
|
json=payload,
|
|
auth=(api_key, ""),
|
|
timeout=60,
|
|
headers={"Idempotency-Key": str(message.pk)},
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
return PostcardResult(provider_id=str(data.get("id") or message.pk))
|
|
|
|
def get_status(self, provider_id: str) -> str:
|
|
api_key = settings.LOB_API_KEY
|
|
if not api_key:
|
|
return "unknown"
|
|
response = requests.get(
|
|
f"https://api.lob.com/v1/postcards/{provider_id}",
|
|
auth=(api_key, ""),
|
|
timeout=30,
|
|
)
|
|
if not response.ok:
|
|
return "unknown"
|
|
return str(response.json().get("status") or "unknown")
|