fix: Various fixes. Mail, UI, Flash etc
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import logging
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime, timezone
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from shared.firebase import get_db
|
||||
from shared.exceptions import NotFoundError
|
||||
from utils.serial_number import generate_serial
|
||||
from utils.nvs_generator import generate as generate_nvs_binary
|
||||
from manufacturing.models import BatchCreate, BatchResponse, DeviceInventoryItem, DeviceStatusUpdate, DeviceAssign, ManufacturingStats, RecentActivityItem
|
||||
from manufacturing.models import BatchCreate, BatchResponse, DeviceInventoryItem, DeviceStatusUpdate, DeviceAssign, ManufacturingStats, RecentActivityItem, BOARD_TYPE_LABELS
|
||||
|
||||
COLLECTION = "devices"
|
||||
_BATCH_ID_CHARS = string.ascii_uppercase + string.digits
|
||||
@@ -162,6 +165,7 @@ def assign_device(sn: str, data: DeviceAssign) -> DeviceInventoryItem:
|
||||
if not docs:
|
||||
raise NotFoundError("Device")
|
||||
|
||||
doc_data = docs[0].to_dict() or {}
|
||||
doc_ref = docs[0].reference
|
||||
doc_ref.update({
|
||||
"owner": data.customer_email,
|
||||
@@ -169,11 +173,18 @@ def assign_device(sn: str, data: DeviceAssign) -> DeviceInventoryItem:
|
||||
"mfg_status": "sold",
|
||||
})
|
||||
|
||||
send_device_assignment_invite(
|
||||
customer_email=data.customer_email,
|
||||
serial_number=sn,
|
||||
customer_name=data.customer_name,
|
||||
)
|
||||
hw_type = doc_data.get("hw_type", "")
|
||||
device_name = BOARD_TYPE_LABELS.get(hw_type, hw_type or "Device")
|
||||
|
||||
try:
|
||||
send_device_assignment_invite(
|
||||
customer_email=data.customer_email,
|
||||
serial_number=sn,
|
||||
device_name=device_name,
|
||||
customer_name=data.customer_name,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error("Assignment succeeded but email failed for %s → %s: %s", sn, data.customer_email, exc)
|
||||
|
||||
return _doc_to_inventory_item(doc_ref.get())
|
||||
|
||||
|
||||
@@ -5,15 +5,11 @@ from config import settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_client() -> resend.Resend:
|
||||
return resend.Resend(api_key=settings.resend_api_key)
|
||||
|
||||
|
||||
def send_email(to: str, subject: str, html: str) -> None:
|
||||
"""Send a transactional email via Resend. Logs errors but does not raise."""
|
||||
try:
|
||||
client = _get_client()
|
||||
client.emails.send({
|
||||
resend.api_key = settings.resend_api_key
|
||||
resend.Emails.send({
|
||||
"from": settings.email_from,
|
||||
"to": to,
|
||||
"subject": subject,
|
||||
@@ -28,29 +24,99 @@ def send_email(to: str, subject: str, html: str) -> None:
|
||||
def send_device_assignment_invite(
|
||||
customer_email: str,
|
||||
serial_number: str,
|
||||
device_name: str,
|
||||
customer_name: str | None = None,
|
||||
) -> None:
|
||||
"""Notify a customer that a Vesper device has been assigned to them."""
|
||||
greeting = f"Hi {customer_name}," if customer_name else "Hello,"
|
||||
"""Notify a customer that a Bell Systems device has been assigned and shipped to them."""
|
||||
greeting = f"Dear {customer_name}," if customer_name else "Dear Customer,"
|
||||
html = f"""
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2 style="color: #111827;">Your Vesper device is ready</h2>
|
||||
<p>{greeting}</p>
|
||||
<p>A Vesper bell automation device has been registered and assigned to you.</p>
|
||||
<p>
|
||||
<strong>Serial Number:</strong>
|
||||
<code style="background: #f3f4f6; padding: 2px 6px; border-radius: 4px; font-size: 14px;">{serial_number}</code>
|
||||
</p>
|
||||
<p>Open the Vesper app and enter this serial number to get started.</p>
|
||||
<hr style="border: none; border-top: 1px solid #e5e7eb; margin: 24px 0;" />
|
||||
<p style="color: #6b7280; font-size: 12px;">
|
||||
If you did not expect this email, please contact your system administrator.
|
||||
</p>
|
||||
</div>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
|
||||
<body style="margin:0; padding:0; background-color:#f4f4f7; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7; padding: 40px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<table width="600" cellpadding="0" cellspacing="0" style="background-color:#ffffff; border-radius:8px; overflow:hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.08); max-width:600px; width:100%;">
|
||||
|
||||
<!-- Header -->
|
||||
<tr>
|
||||
<td style="background-color:#0f172a; padding: 32px 40px; text-align:center;">
|
||||
<h1 style="color:#ffffff; margin:0; font-size:22px; font-weight:700; letter-spacing:1px;">BELLSYSTEMS</h1>
|
||||
<p style="color:#94a3b8; margin:6px 0 0; font-size:13px; letter-spacing:2px; text-transform:uppercase;">Device Shipment Confirmation</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Body -->
|
||||
<tr>
|
||||
<td style="padding: 40px 40px 32px;">
|
||||
<p style="margin:0 0 20px; font-size:16px; color:#1e293b;">{greeting}</p>
|
||||
|
||||
<p style="margin:0 0 16px; font-size:15px; color:#334155; line-height:1.7;">
|
||||
Your <strong>Bell Systems {device_name}</strong> device has been successfully manufactured and shipped.
|
||||
We are delighted to have it on its way to you!
|
||||
</p>
|
||||
|
||||
<p style="margin:0 0 24px; font-size:15px; color:#334155; line-height:1.7;">
|
||||
To get started, download our controller application from the Google Play Store and follow the in-app setup instructions.
|
||||
</p>
|
||||
|
||||
<!-- CTA Button -->
|
||||
<table cellpadding="0" cellspacing="0" width="100%" style="margin: 28px 0;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://play.google.com/store/apps/details?id=com.bellsystems.vesper"
|
||||
style="display:inline-block; background-color:#0f172a; color:#ffffff; text-decoration:none;
|
||||
padding:14px 32px; border-radius:6px; font-size:15px; font-weight:600; letter-spacing:0.5px;">
|
||||
Download on Google Play
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Device info card -->
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px; margin-bottom:28px;">
|
||||
<tr>
|
||||
<td style="padding:16px 20px; border-bottom:1px solid #e2e8f0;">
|
||||
<span style="font-size:12px; color:#64748b; text-transform:uppercase; letter-spacing:1px; font-weight:600;">Device</span><br>
|
||||
<span style="font-size:15px; color:#0f172a; font-weight:600;">Bell Systems {device_name}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:16px 20px;">
|
||||
<span style="font-size:12px; color:#64748b; text-transform:uppercase; letter-spacing:1px; font-weight:600;">Serial Number</span><br>
|
||||
<code style="font-size:14px; color:#0f172a; background:#e2e8f0; padding:3px 8px; border-radius:4px; font-family:monospace;">{serial_number}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p style="margin:0; font-size:15px; color:#334155; line-height:1.7;">
|
||||
Thank you very much. We greatly appreciate your choice in our products.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr>
|
||||
<td style="background-color:#f8fafc; border-top:1px solid #e2e8f0; padding:24px 40px; text-align:center;">
|
||||
<p style="margin:0 0 4px; font-size:14px; color:#0f172a; font-weight:700;">BellSystems.gr</p>
|
||||
<p style="margin:0; font-size:12px; color:#94a3b8;">
|
||||
If you did not expect this email, please contact us at
|
||||
<a href="mailto:support@bellsystems.gr" style="color:#64748b;">support@bellsystems.gr</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
send_email(
|
||||
to=customer_email,
|
||||
subject=f"Your Vesper device is ready — {serial_number}",
|
||||
subject=f"Your Bell Systems {device_name} is on its way! 🎉",
|
||||
html=html,
|
||||
)
|
||||
|
||||
|
||||
@@ -16,4 +16,5 @@ def generate_serial(board_type: str, board_version: str) -> str:
|
||||
month = MONTH_CODES[now.month - 1]
|
||||
day = now.strftime("%d")
|
||||
suffix = "".join(random.choices(SAFE_CHARS, k=5))
|
||||
return f"PV-{year}{month}{day}-{board_type.upper()}{board_version}R-{suffix}"
|
||||
version_clean = board_version.replace(".", "")
|
||||
return f"PV-{year}{month}{day}-{board_type.upper()}{version_clean}R-{suffix}"
|
||||
|
||||
Reference in New Issue
Block a user