diff --git a/backend/app/api/v1/certificates.py b/backend/app/api/v1/certificates.py
index a828afd..0a9afcc 100644
--- a/backend/app/api/v1/certificates.py
+++ b/backend/app/api/v1/certificates.py
@@ -20,6 +20,7 @@
DonationCertificateUpdate,
)
from app.certificates.generator import generate_certificate_pdf
+from app.certificates.svg_generator import generate_html_certificate
router = APIRouter(prefix="/certificates", tags=["certificates"])
@@ -90,24 +91,22 @@ async def get_public_certificate_page(
donor = (await db.execute(select(User).where(User.id == donation.donor_id))).scalar_one_or_none()
donor_name = cert.donor_name or (donor.stellar_public_key if donor else None) or "Anonymous Donor"
tx_hash = cert.stellar_tx_hash or donation.stellar_tx_hash or "N/A"
- html = f"""
-
-
-
LINGAP Certificate {cert.id}
-
-
-
LINGAP On-Chain Donation Proof
-
Public Impact Certificate
-
User Name: {donor_name}
-
Campaign Name: {campaign_name}
-
Milestone: {cert.milestone_description}
-
Donation Amount: {float(cert.amount):,.2f} XLM
-
Transaction Hash: {tx_hash}
-
Verification: {"Verified" if cert.verified else "Pending"}
-
-
-
- """
+ html = generate_html_certificate(
+ donor_name=donor_name,
+ amount=float(cert.amount),
+ beneficiary_name=campaign_name,
+ milestone_description=cert.milestone_description or "Campaign milestone completed",
+ lives_touched=int(cert.lives_touched or 0),
+ total_donated=float(cert.total_donated or cert.amount),
+ donation_date=donation.created_at,
+ stellar_tx_hash=tx_hash,
+ merkle_proof=cert.merkle_proof,
+ onchain_hash=cert.onchain_hash,
+ certificate_id=str(cert.id),
+ block_number=None,
+ network="Stellar Mainnet" if cert.verified else "Pending Verification",
+ certifying_officer="LINGAP Foundation",
+ )
return HTMLResponse(content=html)
@@ -264,6 +263,7 @@ async def list_certificates(
"donation_id": str(cert.donation_id),
"donor_name": cert.donor_name,
"amount": float(cert.amount),
+ "asset": donation.asset,
"beneficiary_name": cert.beneficiary_name,
"campaign_name": campaign_name,
"milestone_description": cert.milestone_description,
diff --git a/backend/app/certificates/svg_generator.py b/backend/app/certificates/svg_generator.py
index 4178365..2a2e46b 100644
--- a/backend/app/certificates/svg_generator.py
+++ b/backend/app/certificates/svg_generator.py
@@ -1,4 +1,4 @@
-"""Enhanced HTML certificate generation for LINGAP with PNG fallback wrapper."""
+"""Enhanced HTML certificate generation for LINGAP with PNG fallback wrapper."""
from datetime import datetime
import hashlib
@@ -19,46 +19,24 @@ def generate_html_certificate(
network: str = "Stellar Mainnet",
certifying_officer: str = "LINGAP Foundation",
) -> str:
- """Generate a polished HTML certificate for a LINGAP donation.
-
- Args:
- donor_name: Full name of the donor
- amount: This donation amount in PHP
- beneficiary_name: Name of the campaign beneficiary
- milestone_description: Milestone reached (e.g. "Chemo Cycle 3 of 6 Completed")
- lives_touched: Number of lives impacted
- total_donated: Cumulative amount donated by this donor
- donation_date: Date of the donation
- stellar_tx_hash: Full Stellar blockchain transaction hash
- merkle_proof: Optional Merkle proof string
- onchain_hash: Optional on-chain hash reference
- certificate_id: Optional certificate ID (auto-generated if not provided)
- block_number: Optional Stellar ledger block number
- network: Blockchain network name (default: "Stellar Mainnet")
- certifying_officer: Name for the signature block
-
- Returns:
- Full standalone HTML document as a string
- """
+ """Generate a polished HTML certificate for a LINGAP donation."""
date_str = donation_date.strftime("%B %d, %Y")
tx_preview = stellar_tx_hash[:20] + "..."
merkle_preview = (merkle_proof[:20] + "...") if merkle_proof else "N/A"
onchain_preview = (onchain_hash[:20] + "...") if onchain_hash else "N/A"
- # Auto-generate certificate ID from tx hash if not provided
if not certificate_id:
short = hashlib.sha256(stellar_tx_hash.encode()).hexdigest()[:6].upper()
year = donation_date.year
certificate_id = f"LNG-{year}-{short}"
- block_display = f" · Block {block_number}" if block_number else ""
+ block_display = f" · Block {block_number}" if block_number else ""
- # Build the 4 verification statement lines
verification_statements = [
"Blockchain transaction verified on Stellar Mainnet",
"Beneficiary campaign identity independently confirmed",
"Funds disbursed directly to verified medical providers",
- "Immutable record — publicly accessible at any time",
+ "Immutable record - publicly accessible at any time",
]
statements_html = "\n".join(
f"""
@@ -79,86 +57,132 @@ def generate_html_certificate(
-
-
+
+
- LINGAP Certificate — {certificate_id}
+ LINGAP Certificate - {certificate_id}
+
+
+
+
-
-
+
-
This certifies that
{donor_name}
has made a verified, blockchain-recorded donation in support of a humanitarian cause
-
Verified Donation
₱{amount:,.2f}
-
-
Benefiting the campaign of
+
in benefit of the campaign of
{beneficiary_name}
@@ -581,13 +671,12 @@ def generate_html_certificate(
-