import sql from "./db"; import { COINS } from "./plans"; export async function generateReceipt(paymentId: number): Promise { const [payment] = await sql`SELECT * FROM payments WHERE id = ${paymentId}`; if (!payment) throw new Error("Payment not found"); // Already locked — return as-is if (payment.receipt_html) return payment.receipt_html; const coinInfo = COINS[payment.coin]; const txs = await sql` SELECT txid, amount, confirmed, detected_at FROM payment_txs WHERE payment_id = ${paymentId} ORDER BY detected_at ASC `; const paidDate = payment.paid_at ? new Date(payment.paid_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }) : "—"; const createdDate = new Date(payment.created_at).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }); const planLabel = payment.plan === "lifetime" ? "Lifetime" : `Pro × ${payment.months} month${payment.months > 1 ? "s" : ""}`; const txRows = txs.map((tx: any) => { const date = new Date(tx.detected_at).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); return ` ${tx.txid} ${tx.amount} ${coinInfo?.ticker || payment.coin.toUpperCase()} ${date} `; }).join(""); const html = ` PingQL Receipt #${payment.id}
Receipt #${payment.id} · Issued ${paidDate}
Plan
Product PingQL ${planLabel}
Invoice Date ${createdDate}
Payment Date ${paidDate}
Payment
Currency ${coinInfo?.label || payment.coin} (${coinInfo?.ticker || payment.coin.toUpperCase()})
Amount Paid ${payment.amount_received || payment.amount_crypto} ${coinInfo?.ticker || payment.coin.toUpperCase()}
Payment Address ${payment.address}
Total (USD) $${Number(payment.amount_usd).toFixed(2)}
${txs.length > 0 ? `
Transactions
${txRows}
Transaction IDAmountDate
` : ""} `; // Lock it await sql`UPDATE payments SET receipt_html = ${html} WHERE id = ${paymentId}`; return html; }