""" Quarterly Business Review (QBR) Generator. Composes a monthly/quarterly executive summary per customer pulling from: - EmailSendLog metrics (sent / replied / bounced) - GmailDraftRecord + LinkedInDraftRecord counts - LeadScoreRecord priority distribution - Customer health score - Suppression activity (proof of compliance) Output: structured dict ready for: - markdown export (for email to customer) - PowerPoint generation (PPTX skill — future) - dashboard rendering Pure-function — takes pre-fetched data, computes the brief. """ from __future__ import annotations from dataclasses import asdict, dataclass, field from datetime import datetime, timedelta, timezone from typing import Any @dataclass class QBRSection: title: str bullets: list[str] = field(default_factory=list) metrics: dict[str, Any] = field(default_factory=dict) @dataclass class QBRReport: customer_id: str customer_name: str period_start: str period_end: str period_days: int health_overall: float health_bucket: str # Executive summary headline_metric: str headline_delta: str # Sections sections: list[QBRSection] = field(default_factory=list) # Recommendations next_quarter_focus: list[str] = field(default_factory=list) upsell_opportunities: list[str] = field(default_factory=list) # Generated_at generated_at: str = "" def to_dict(self) -> dict[str, Any]: return { **{k: v for k, v in asdict(self).items() if k != "sections"}, "sections": [asdict(s) for s in self.sections], } def to_markdown(self) -> str: """Render as markdown for email send.""" lines = [ f"# QBR — {self.customer_name}", f"**Period:** {self.period_start} → {self.period_end} ({self.period_days} days)", f"**Health Score:** {self.health_overall}/100 ({self.health_bucket})", "", f"## 🎯 Headline", f"**{self.headline_metric}** — {self.headline_delta}", "", ] for section in self.sections: lines.append(f"## {section.title}") for b in section.bullets: lines.append(f"- {b}") if section.metrics: lines.append("") for k, v in section.metrics.items(): lines.append(f" - `{k}`: {v}") lines.append("") if self.next_quarter_focus: lines.append("## 🚀 Next Quarter Focus") for f in self.next_quarter_focus: lines.append(f"- {f}") lines.append("") if self.upsell_opportunities: lines.append("## 💎 Upsell Opportunities") for u in self.upsell_opportunities: lines.append(f"- {u}") lines.append("") lines.append(f"_Generated by Dealix at {self.generated_at}_") return "\n".join(lines) def generate_qbr( *, customer_id: str, customer_name: str, period_days: int = 30, # Outreach metrics emails_sent: int = 0, emails_replied: int = 0, emails_bounced: int = 0, drafts_created: int = 0, drafts_sent: int = 0, linkedin_drafts: int = 0, linkedin_sent: int = 0, # Pipeline metrics new_leads: int = 0, qualified_leads: int = 0, demos_booked: int = 0, deals_won: int = 0, pipeline_value_sar: float = 0, closed_revenue_sar: float = 0, # Compliance suppression_added: int = 0, opt_outs_received: int = 0, # Health health_overall: float = 70, health_bucket: str = "stable", # Top performers best_sector: str | None = None, best_message_angle: str | None = None, # Plan current_plan: str = "Growth", ) -> QBRReport: """Compose QBR from raw metrics.""" now = datetime.now(timezone.utc) period_start = (now - timedelta(days=period_days)).date().isoformat() period_end = now.date().isoformat() # Headline = highest-impact metric if deals_won > 0: headline_metric = f"Closed {deals_won} deals worth {closed_revenue_sar:,.0f} SAR" headline_delta = f"via Dealix-generated pipeline" elif demos_booked > 0: headline_metric = f"{demos_booked} demos booked from {emails_sent + linkedin_sent} outreaches" ratio = (demos_booked / max(1, emails_sent + linkedin_sent)) * 100 headline_delta = f"{ratio:.1f}% conversion to demo" elif emails_replied > 0: headline_metric = f"{emails_replied} replies on {emails_sent} sends" rate = (emails_replied / max(1, emails_sent)) * 100 headline_delta = f"{rate:.1f}% reply rate" else: headline_metric = f"{drafts_created} personalized drafts generated" headline_delta = "Pipeline being built — first conversions expected next period" sections: list[QBRSection] = [] # Section 1: Outreach activity reply_rate = (emails_replied / max(1, emails_sent)) * 100 bounce_rate = (emails_bounced / max(1, emails_sent)) * 100 sections.append(QBRSection( title="📨 Outreach Activity", bullets=[ f"{drafts_created} drafts generated, {drafts_sent} sent ({drafts_sent/max(1,drafts_created)*100:.0f}% approval rate)", f"{emails_sent} emails reached inboxes — {reply_rate:.1f}% reply rate", f"{linkedin_drafts} LinkedIn drafts; {linkedin_sent} sent manually", f"Bounce rate: {bounce_rate:.1f}% (target < 5%)", ], metrics={ "drafts_created": drafts_created, "drafts_sent": drafts_sent, "emails_sent": emails_sent, "emails_replied": emails_replied, "linkedin_drafts": linkedin_drafts, "linkedin_sent": linkedin_sent, "reply_rate_pct": round(reply_rate, 2), "bounce_rate_pct": round(bounce_rate, 2), }, )) # Section 2: Pipeline impact sections.append(QBRSection( title="📈 Pipeline Impact", bullets=[ f"{new_leads} new leads ingested", f"{qualified_leads} qualified by Dealix scoring", f"{demos_booked} demos booked", f"{deals_won} deals closed — {closed_revenue_sar:,.0f} SAR revenue", f"Open pipeline: {pipeline_value_sar:,.0f} SAR", ], metrics={ "new_leads": new_leads, "qualified": qualified_leads, "demos": demos_booked, "deals_won": deals_won, "pipeline_sar": pipeline_value_sar, "closed_sar": closed_revenue_sar, }, )) # Section 3: Compliance sections.append(QBRSection( title="🛡️ Compliance Health", bullets=[ f"{suppression_added} new suppression entries added", f"{opt_outs_received} opt-outs honored automatically (RFC 8058 + STOP)", f"All sends passed 11-gate compliance check", f"Audit log: 100% complete", ], metrics={ "suppression_added": suppression_added, "opt_outs": opt_outs_received, }, )) # Section 4: Top performers top_bullets = [] if best_sector: top_bullets.append(f"Best sector: **{best_sector}**") if best_message_angle: top_bullets.append(f"Best message angle: **{best_message_angle}**") if top_bullets: sections.append(QBRSection( title="🏆 What Worked", bullets=top_bullets, )) # Recommendations next_focus: list[str] = [] if reply_rate < 3 and emails_sent >= 50: next_focus.append("Iterate subject lines — current reply rate below 3%") if bounce_rate > 8: next_focus.append("Audit data sources — bounce rate >8% threatens Gmail reputation") if demos_booked == 0 and emails_replied >= 5: next_focus.append("Review reply-to-demo conversion — leads engaging but not converting") if drafts_created < period_days: next_focus.append("Increase daily run cadence — currently below 1 draft/day") if not next_focus: next_focus.append("Maintain current cadence + run /score-tuner monthly") upsell: list[str] = [] if current_plan == "Starter" and emails_sent >= 400: upsell.append("Approaching Starter cap — Growth tier 2,500 lead/mo at 2,999 SAR") if current_plan in {"Starter", "Growth"} and deals_won >= 3: upsell.append("Strong outcomes — Scale tier unlocks API + dedicated AM at 7,999 SAR") if best_sector and demos_booked >= 5: upsell.append(f"Best-sector ({best_sector}) showing strong ROI — consider expanding to adjacent sectors") if health_bucket == "healthy" and deals_won >= 1: upsell.append("Strong NPS candidate → request testimonial + 10% referral kickback") return QBRReport( customer_id=customer_id, customer_name=customer_name, period_start=period_start, period_end=period_end, period_days=period_days, health_overall=health_overall, health_bucket=health_bucket, headline_metric=headline_metric, headline_delta=headline_delta, sections=sections, next_quarter_focus=next_focus, upsell_opportunities=upsell, generated_at=now.isoformat(), )