How the platform auto-generates QR codes on purchase and sends invoice emails via EmailJS.
Every purchase order triggers two automatic actions: a QR code is generated on the backend and an invoice email is sent from the frontend. Neither action requires manual intervention.
The buyer submits the ticketing form. createAnonymousPurchase posts to POST /api/purchase_orders/anonymous/ and returns a purchase order object.
2
QR generated automatically
A Django post_save signal fires immediately after the PurchaseOrders row is created. It calls generate_qr_code(instance), which writes a .png file to media/qr_codes/ and stores the relative path back on the order.
3
Invoice email sent
Back in the browser, sendInvoiceEmail from emailInvoiceService.js sends the complete invoice — including a reference to the QR URL — through the EmailJS API.
The signal is defined in api/purchase_orders/signals.py and registered when the PurchaseOrdersConfig app is ready.
signals.py
from django.db.models.signals import post_savefrom django.dispatch import receiverfrom .models import PurchaseOrdersfrom api.utils import generate_qr_code@receiver(post_save, sender=PurchaseOrders)def create_qr_on_order(sender, instance, created, **kwargs): if created and not instance.qr_image: generate_qr_code(instance)
The guard not instance.qr_image prevents regeneration on subsequent saves (e.g. update_fields).
The verification field is an 8-character MD5 digest of "<id>-<email>-<purchase_date>-<total_tickets>". Staff can recompute this server-side with verify_qr_data to confirm a QR has not been tampered with.
verify_qr_data (also in api/utils.py) checks order_id, email, and recomputes the verification hash. It returns True only when all three match.
Create a template in your EmailJS dashboard with these variables:
Field
Description
{{nombre}}
Buyer’s name
{{correo}}
Buyer’s email
{{asunto}}
Subject line (includes confirmation code)
{{mensaje}}
Full formatted invoice body
{{order_id}}
Numeric order ID
{{confirmation_code}}
Alphanumeric confirmation code
{{qr_image_url}}
Public URL of the QR image
{{total_amount}}
Formatted total (e.g. ₡25,000)
Minimal template HTML:
EmailJS template (template_factura)
<h2>Purchase receipt — Fundación Corcovado</h2><p>Dear {{nombre}},</p><p>Thank you for your purchase. Here are your order details:</p><div style="background:#f5f5f5;padding:15px;border-radius:5px"> <p><strong>Confirmation code:</strong> {{confirmation_code}}</p> <p><strong>Email:</strong> {{correo}}</p> <p><strong>Total:</strong> {{total_amount}}</p></div><pre style="white-space:pre-wrap;background:#f9f9f9;padding:10px">{{mensaje}}</pre><p>Present your QR code on the day of your visit.</p><p>Questions? Contact us at [email protected]</p>
sendInvoiceEmail attempts the primary template first. If it fails (e.g. the template does not exist in the EmailJS dashboard), it retries automatically with fallbackTemplateId.
Error 412: Faltan campos requeridos en el template
400
Invalid data sent to EmailJS
Error 400: Datos inválidos para el envío
other
Generic EmailJS error
Error EmailJS: <error.text>
A failed email does not fail the purchase. The order is confirmed and the QR is generated regardless of email delivery. Notify the buyer via the UI if sendInvoiceEmail returns { success: false }.