Lý thuyết
Bài 14/17

Executive Reporting

Tạo báo cáo KPIs, dashboards, và insights cho leadership

Executive Reporting

Executive Dashboard and Reports

1. Introduction

Executive Reporting

Executive reports cần ngắn gọn, actionable, và focus vào business impact. Leadership không cần biết how - họ cần biết what, so what, và now what.

1.1 Executive vs Analyst Mindset

Text
1┌──────────────────────────────────────────────────────────┐
2│ Analyst vs Executive Focus │
3├──────────────────────────────────────────────────────────┤
4│ │
5│ ANALYST THINKS: EXECUTIVE THINKS: │
6│ ───────────────── ───────────────── │
7│ "How did I get this?" "What should I do?" │
8│ "Is the data accurate?" "What's the impact?" │
9│ "What methodology?" "How confident are we?" │
10│ "Show all the details" "Just the bottom line" │
11│ "Here's what I found" "Here's what it means" │
12│ │
13├──────────────────────────────────────────────────────────┤
14│ │
15│ EXECUTIVE REPORT MUST ANSWER: │
16│ 1. Are we on track? (Performance) │
17│ 2. What's changed? (Trends) │
18│ 3. What's at risk? (Issues) │
19│ 4. What should we do? (Actions) │
20│ │
21└──────────────────────────────────────────────────────────┘

2. KPI Framework

2.1 Choosing the Right KPIs

Text
1┌─────────────────────────────────────────────────────────┐
2│ KPI Selection Criteria │
3├─────────────────────────────────────────────────────────┤
4│ │
5│ ✅ GOOD KPIs are: │
6│ • Actionable - Can we influence it? │
7│ • Aligned - Tied to business strategy │
8│ • Accurate - Reliable data source │
9│ • Accessible - Easy to understand │
10│ • Auditable - Can be verified │
11│ │
12│ ❌ AVOID Vanity Metrics: │
13│ • Total page views (without context) │
14│ • Social media followers (if not converting) │
15│ • Raw user count (without engagement) │
16│ │
17├─────────────────────────────────────────────────────────┤
18│ │
19│ KPI HIERARCHY: │
20│ ┌──────────────────────────────────────────────────┐ │
21│ │ Level 1: North Star Metric │ │
22│ │ (e.g., Monthly Active Users) │ │
23│ └──────────────────────┬───────────────────────────┘ │
24│ │ │
25│ ┌──────────┬───────────┼───────────┬──────────┐ │
26│ v v v v v │
27│ Revenue Customers Engagement Efficiency Quality │
28│ ─────── ───────── ────────── ────────── ─────── │
29│ MRR CAC DAU/MAU OpEx NPS │
30│ ARPU LTV Session Margin CSAT │
31│ Growth Churn Features Time Defects │
32│ │
33└─────────────────────────────────────────────────────────┘

2.2 KPI Dashboard Structure

Python
1import pandas as pd
2import numpy as np
3
4# Sample KPI data
5kpis = {
6 'Revenue': {
7 'current': 2.5,
8 'target': 2.3,
9 'previous': 2.1,
10 'unit': 'M',
11 'higher_is_better': True
12 },
13 'Customer Count': {
14 'current': 12500,
15 'target': 13000,
16 'previous': 11800,
17 'unit': '',
18 'higher_is_better': True
19 },
20 'Churn Rate': {
21 'current': 5.2,
22 'target': 4.0,
23 'previous': 4.8,
24 'unit': '%',
25 'higher_is_better': False
26 },
27 'NPS': {
28 'current': 42,
29 'target': 50,
30 'previous': 38,
31 'unit': '',
32 'higher_is_better': True
33 },
34 'CAC': {
35 'current': 125,
36 'target': 100,
37 'previous': 145,
38 'unit': '$',
39 'higher_is_better': False
40 }
41}
42
43def calculate_kpi_status(kpi_data):
44 """Calculate status and variance for each KPI"""
45 results = []
46
47 for name, data in kpi_data.items():
48 current = data['current']
49 target = data['target']
50 previous = data['previous']
51 higher_better = data['higher_is_better']
52
53 # Calculate variances
54 vs_target = ((current - target) / target) * 100
55 vs_previous = ((current - previous) / previous) * 100
56
57 # Determine status
58 if higher_better:
59 on_track = current >= target
60 else:
61 on_track = current <= target
62
63 status = '✅' if on_track else '⚠️' if abs(vs_target) < 10 else '❌'
64
65 results.append({
66 'KPI': name,
67 'Current': f"{current}{data['unit']}",
68 'Target': f"{target}{data['unit']}",
69 'vs Target': f"{'+' if vs_target > 0 else ''}{vs_target:.1f}%",
70 'vs Previous': f"{'+' if vs_previous > 0 else ''}{vs_previous:.1f}%",
71 'Status': status
72 })
73
74 return pd.DataFrame(results)
75
76kpi_summary = calculate_kpi_status(kpis)
77print("Executive KPI Summary")
78print("=" * 70)
79print(kpi_summary.to_string(index=False))

3. Report Templates

3.1 Weekly Flash Report

Text
1┌──────────────────────────────────────────────────────────┐
2│ WEEKLY FLASH REPORT │
3│ Week of [DATE] │
4├──────────────────────────────────────────────────────────┤
5│ │
6│ 📊 KEY METRICS AT A GLANCE │
7│ ┌────────────────┬─────────┬─────────┬────────┐ │
8│ │ Metric │ Actual │ Target │ Status │ │
9│ ├────────────────┼─────────┼─────────┼────────┤ │
10│ │ Revenue │ $2.5M │ $2.3M │ ✅ │ │
11│ │ Orders │ 12,500 │ 11,000 │ ✅ │ │
12│ │ Conversion │ 3.2% │ 3.5% │ ⚠️ │ │
13│ │ CSAT │ 4.2 │ 4.5 │ ⚠️ │ │
14│ └────────────────┴─────────┴─────────┴────────┘ │
15│ │
16│ 🔴 KEY ISSUES (Need Attention) │
17│ 1. Mobile conversion down 15% - investigating UX issue │
18│ 2. Support tickets up 20% - staffing being addressed │
19│ │
20│ 🟢 WINS THIS WEEK │
21│ 1. Record revenue day on Thursday (+45% vs typical) │
22│ 2. New customer acquisition up 12% from campaign │
23│ │
24│ 📋 KEY ACTIONS FOR NEXT WEEK │
25│ 1. Deploy mobile checkout fix (Owner: Product) │
26│ 2. Review Q2 forecast (Owner: Finance) │
27│ │
28└──────────────────────────────────────────────────────────┘

3.2 Monthly Business Review

Python
1def generate_monthly_report(data, month, year):
2 """Generate monthly executive report"""
3
4 report = f"""
5
6 MONTHLY BUSINESS REVIEW
7 {month} {year}
8
9
10
11 EXECUTIVE SUMMARY
12
13
14Overall Status: ON TRACK
15
16Key Highlight: Revenue exceeded target by 12%, driven by
17successful product launch and seasonal demand.
18
19Main Concern: Customer acquisition cost increased 18%,
20requiring marketing efficiency review.
21
22
23 FINANCIAL PERFORMANCE
24
25
26 Actual Target Variance
27Revenue $2.8M $2.5M +12%
28Gross Margin 68% 65% +3pp
29Operating Cost $1.2M $1.1M +9%
30EBITDA $0.7M $0.6M +17%
31
32YTD Progress: $8.2M of $12M target (68% complete with 50% time elapsed)
33
34
35 CUSTOMER METRICS
36
37
38Total Customers: 15,200 (+8% MoM)
39New Customers: 2,400
40Churned: 650
41Net Addition: 1,750
42
43Customer Health:
44 Active (>3 logins/mo): 72%
45 At Risk (declining): 18%
46 Dormant (<1 login/mo): 10%
47
48
49 TOP 3 PRIORITIES FOR NEXT MONTH
50
51
521. Reduce CAC by 15%
53 Owner: Marketing
54 Actions: Review channel mix, optimize ad spend
55
562. Launch mobile app v2.0
57 Owner: Product
58 Actions: Complete testing, deploy to 10% users
59
603. Expand sales team
61 Owner: HR
62 Actions: Hire 3 SDRs, 2 AEs
63
64
65"""
66 return report
67
68print(generate_monthly_report(None, "March", 2024))

3.3 Quarterly Business Review (QBR)

Text
1QUARTERLY BUSINESS REVIEW STRUCTURE
2====================================
3
4SECTION 1: EXECUTIVE SUMMARY (1 page)
5├── Quarter performance vs targets
6├── Key achievements
7├── Critical issues
8└── Top 3 priorities for next quarter
9
10SECTION 2: FINANCIAL REVIEW (2-3 pages)
11├── Revenue analysis
12│ ├── By product/segment
13│ ├── By region
14│ └── Vs forecast
15├── Profitability
16│ ├── Gross margin trends
17│ └── Operating efficiency
18└── Cash position and forecast
19
20SECTION 3: CUSTOMER & MARKET (2-3 pages)
21├── Customer growth and retention
22├── Market share trends
23├── Competitive landscape
24└── NPS and satisfaction trends
25
26SECTION 4: OPERATIONAL EXCELLENCE (1-2 pages)
27├── Key operational metrics
28├── Process improvements
29└── Technology updates
30
31SECTION 5: PEOPLE & CULTURE (1 page)
32├── Headcount and hiring
33├── Engagement scores
34└── Key organizational changes
35
36SECTION 6: RISK & OPPORTUNITIES (1 page)
37├── Top 3 risks and mitigation
38└── Top 3 growth opportunities
39
40SECTION 7: NEXT QUARTER OUTLOOK (1-2 pages)
41├── Forecast and assumptions
42├── Key initiatives
43└── Resource requirements
44
45APPENDIX
46├── Detailed financial statements
47├── Complete KPI dashboard
48└── Supporting analysis

4. Data Visualization for Executives

4.1 Executive Dashboard Design

Python
1import matplotlib.pyplot as plt
2import matplotlib.patches as mpatches
3import numpy as np
4
5def create_executive_dashboard():
6 """Create a clean executive dashboard"""
7
8 fig = plt.figure(figsize=(16, 10))
9 fig.suptitle('Q1 2024 Executive Dashboard', fontsize=16, fontweight='bold', y=0.98)
10
11 # Layout: 3 rows
12 gs = fig.add_gridspec(3, 4, hspace=0.3, wspace=0.3)
13
14 # Row 1: Big Numbers (KPIs)
15 # Revenue
16 ax1 = fig.add_subplot(gs[0, 0])
17 ax1.text(0.5, 0.7, '$8.2M', fontsize=28, fontweight='bold', ha='center', va='center', color='green')
18 ax1.text(0.5, 0.3, 'Revenue\n+15% vs LY', fontsize=10, ha='center', va='center', color='gray')
19 ax1.set_xlim(0, 1)
20 ax1.set_ylim(0, 1)
21 ax1.axis('off')
22
23 # Customers
24 ax2 = fig.add_subplot(gs[0, 1])
25 ax2.text(0.5, 0.7, '15,200', fontsize=28, fontweight='bold', ha='center', va='center', color='steelblue')
26 ax2.text(0.5, 0.3, 'Customers\n+22% vs LY', fontsize=10, ha='center', va='center', color='gray')
27 ax2.axis('off')
28
29 # NPS
30 ax3 = fig.add_subplot(gs[0, 2])
31 ax3.text(0.5, 0.7, '48', fontsize=28, fontweight='bold', ha='center', va='center', color='orange')
32 ax3.text(0.5, 0.3, 'NPS Score\n-2 vs target', fontsize=10, ha='center', va='center', color='gray')
33 ax3.axis('off')
34
35 # Margin
36 ax4 = fig.add_subplot(gs[0, 3])
37 ax4.text(0.5, 0.7, '68%', fontsize=28, fontweight='bold', ha='center', va='center', color='green')
38 ax4.text(0.5, 0.3, 'Gross Margin\n+3pp vs LY', fontsize=10, ha='center', va='center', color='gray')
39 ax4.axis('off')
40
41 # Row 2: Trend and Breakdown
42 # Revenue trend
43 ax5 = fig.add_subplot(gs[1, :2])
44 months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
45 actual = [2.1, 2.3, 2.5, 2.6, 2.8, 3.0]
46 target = [2.0, 2.2, 2.4, 2.5, 2.7, 2.9]
47 ax5.fill_between(months, actual, alpha=0.3, color='green')
48 ax5.plot(months, actual, 'go-', linewidth=2, label='Actual')
49 ax5.plot(months, target, 'k--', label='Target')
50 ax5.set_ylabel('Revenue ($M)')
51 ax5.set_title('Revenue Trend', fontweight='bold')
52 ax5.legend(loc='upper left')
53 ax5.set_ylim(0, 3.5)
54
55 # Revenue breakdown
56 ax6 = fig.add_subplot(gs[1, 2:])
57 segments = ['Enterprise', 'Mid-Market', 'SMB', 'Consumer']
58 values = [3.5, 2.8, 1.5, 0.4]
59 colors = ['#2ecc71', '#3498db', '#9b59b6', '#e74c3c']
60 bars = ax6.barh(segments, values, color=colors)
61 ax6.set_xlabel('Revenue ($M)')
62 ax6.set_title('Revenue by Segment', fontweight='bold')
63 ax6.bar_label(bars, fmt='$%.1fM')
64
65 # Row 3: Issues and Actions
66 ax7 = fig.add_subplot(gs[2, :2])
67 ax7.axis('off')
68 issues_text = """
69 KEY ISSUES
70
711. CAC increased 18% - Marketing review in progress
722. Support backlog at 72hrs - Adding 2 headcount
733. Enterprise deal slipped to Q2 - Risk $500K
74 """
75 ax7.text(0.05, 0.95, issues_text, fontsize=10, fontfamily='monospace',
76 verticalalignment='top', transform=ax7.transAxes)
77
78 ax8 = fig.add_subplot(gs[2, 2:])
79 ax8.axis('off')
80 actions_text = """
81 KEY ACTIONS (Next 30 Days)
82
831. Launch loyalty program - Expected: +5% retention
842. Deploy mobile app v2 - Expected: +10% engagement
853. Close 3 enterprise deals - Expected: +$800K
86 """
87 ax8.text(0.05, 0.95, actions_text, fontsize=10, fontfamily='monospace',
88 verticalalignment='top', transform=ax8.transAxes)
89
90 plt.savefig('executive_dashboard.png', dpi=150, bbox_inches='tight', facecolor='white')
91 plt.show()
92
93create_executive_dashboard()

4.2 Traffic Light Indicators

Python
1def create_status_indicator(value, target, higher_is_better=True):
2 """Create traffic light status"""
3 if higher_is_better:
4 pct = (value - target) / target * 100
5 if pct >= 0:
6 return '🟢', 'On Track'
7 elif pct >= -10:
8 return '🟡', 'Monitor'
9 else:
10 return '🔴', 'At Risk'
11 else:
12 pct = (target - value) / target * 100
13 if pct >= 0:
14 return '🟢', 'On Track'
15 elif pct >= -10:
16 return '🟡', 'Monitor'
17 else:
18 return '🔴', 'At Risk'
19
20# Example usage
21metrics = [
22 ('Revenue', 2.5, 2.3, True),
23 ('Customers', 12500, 13000, True),
24 ('Churn Rate', 5.2, 4.0, False),
25 ('CAC', 125, 100, False),
26 ('NPS', 42, 50, True)
27]
28
29print("\nKPI Status Summary")
30print("=" * 50)
31for name, actual, target, higher_better in metrics:
32 light, status = create_status_indicator(actual, target, higher_better)
33 print(f"{light} {name:15s} | Actual: {actual:>8} | Target: {target:>8} | {status}")

4.3 Sparklines and Trends

Python
1def add_sparkline(ax, data, color='steelblue'):
2 """Add simple sparkline to axis"""
3 x = range(len(data))
4 ax.plot(x, data, color=color, linewidth=1.5)
5 ax.fill_between(x, data, alpha=0.2, color=color)
6 ax.scatter([len(data)-1], [data[-1]], color=color, s=30, zorder=5)
7 ax.axis('off')
8 ax.set_ylim(min(data) * 0.9, max(data) * 1.1)
9
10# Create sparkline dashboard
11fig, axes = plt.subplots(4, 1, figsize=(3, 6))
12
13metrics_data = {
14 'Revenue': [2.1, 2.2, 2.3, 2.5, 2.6, 2.8],
15 'Customers': [11.0, 11.5, 12.0, 12.5, 13.0, 13.8],
16 'NPS': [45, 44, 46, 48, 47, 48],
17 'Churn': [4.5, 4.8, 5.0, 5.2, 5.1, 5.0]
18}
19
20for ax, (name, data) in zip(axes, metrics_data.items()):
21 add_sparkline(ax, data)
22 ax.set_ylabel(name, rotation=0, ha='right', va='center', fontsize=9)
23 # Add current value
24 ax.text(1.05, 0.5, f'{data[-1]}', transform=ax.transAxes,
25 fontsize=10, fontweight='bold', va='center')
26
27plt.suptitle('6-Month Trends', fontsize=11, fontweight='bold')
28plt.tight_layout()
29plt.show()

5. Presenting to Executives

5.1 The 5-Minute Rule

Text
1EXECUTIVE PRESENTATION STRUCTURE
2================================
3
4MINUTE 1: THE HEADLINE
5└── Start with the conclusion
6 "Revenue is up 15%, we're on track for annual target,
7 but customer acquisition cost needs attention."
8
9MINUTE 2: THE EVIDENCE
10└── 3-5 key numbers that prove your headline
11 • Revenue: $8.2M (+15% YoY)
12 • Customers: 15,200 (+22%)
13 • CAC: $125 (+18% - above target)
14
15MINUTE 3: THE INSIGHT
16└── What's driving the numbers
17 "Growth is strong because of product launch.
18 CAC increase due to competitive pressure in paid channels."
19
20MINUTE 4: THE RECOMMENDATION
21└── What action you're proposing
22 "Reallocate $200K from paid to organic content.
23 Expected result: CAC back to $100 in Q2."
24
25MINUTE 5: THE ASK
26└── What you need from them
27 "I need approval for budget reallocation by Friday
28 and a decision on expanding the sales team."
29
30━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
31Then: Answer questions with backup slides
32━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

5.2 Handling Questions

Text
1COMMON EXECUTIVE QUESTIONS & HOW TO PREPARE
2
3Q: "What's driving this?"
4A: Have root cause analysis ready
5 "The increase is driven by: 60% pricing, 25% competition, 15% seasonality"
6
7Q: "How confident are you?"
8A: Be honest with uncertainty ranges
9 "We're 80% confident in this range. Best case: +20%, worst case: +5%"
10
11Q: "What are the risks?"
12A: Top 3 risks + mitigation
13 "Main risk is competitive response. Mitigation: loyalty program launch"
14
15Q: "What do you need from us?"
16A: Clear ask with options
17 "Option A: $200K budget (recommended). Option B: $100K with slower timeline"
18
19Q: "When will we see results?"
20A: Specific timeline with milestones
21 "Initial results in 4 weeks. Full impact visible by end of Q2"
22
23Q: "What happens if we do nothing?"
24A: Quantify the cost of inaction
25 "If we don't act, we'll lose $500K in Q2 based on current trajectory"

6. Automated Reporting

6.1 Report Generation Script

Python
1import pandas as pd
2import numpy as np
3from datetime import datetime
4from jinja2 import Template
5
6def generate_automated_report(data, period='Weekly'):
7 """Generate automated executive report"""
8
9 template = Template("""
10{{ header }}
11Report Generated: {{ timestamp }}
12Period: {{ period }}
13
14
15 EXECUTIVE SUMMARY
16
17
18Overall Status: {{ overall_status }}
19
20Revenue: ${{ revenue }}M ({{ revenue_vs_target }} vs target)
21Customers: {{ customers }} ({{ customer_vs_target }} vs target)
22Key Concern: {{ key_concern }}
23
24
25 KPI DASHBOARD
26
27
28{% for kpi in kpis %}
29{{ kpi.status }} {{ kpi.name }}: {{ kpi.value }} (Target: {{ kpi.target }})
30{% endfor %}
31
32
33 ACTION ITEMS
34
35
36{% for action in actions %}
37{{ loop.index }}. {{ action }}
38{% endfor %}
39
40
41 """)
42
43 # Calculate metrics
44 revenue = 2.5
45 revenue_target = 2.3
46 revenue_vs = '+8.7%' if revenue > revenue_target else '-8.7%'
47
48 customers = 15200
49 customer_target = 14000
50 customer_vs = '+8.6%' if customers > customer_target else '-8.6%'
51
52 kpis = [
53 {'name': 'Revenue', 'value': f'${revenue}M', 'target': f'${revenue_target}M', 'status': '✅'},
54 {'name': 'Customers', 'value': f'{customers:,}', 'target': f'{customer_target:,}', 'status': '✅'},
55 {'name': 'Churn Rate', 'value': '5.2%', 'target': '4.0%', 'status': '⚠️'},
56 {'name': 'NPS', 'value': '48', 'target': '50', 'status': '⚠️'},
57 {'name': 'CAC', 'value': '$125', 'target': '$100', 'status': '❌'}
58 ]
59
60 actions = [
61 'Review marketing spend allocation (Owner: CMO, Due: Friday)',
62 'Implement churn prevention campaign (Owner: CS, Due: Next Monday)',
63 'Schedule enterprise pipeline review (Owner: Sales, Due: Thursday)'
64 ]
65
66 report = template.render(
67 header='EXECUTIVE FLASH REPORT',
68 timestamp=datetime.now().strftime('%Y-%m-%d %H:%M'),
69 period=period,
70 overall_status='✅ ON TRACK',
71 revenue=revenue,
72 revenue_vs_target=revenue_vs,
73 customers=f'{customers:,}',
74 customer_vs_target=customer_vs,
75 key_concern='CAC above target - marketing efficiency review needed',
76 kpis=kpis,
77 actions=actions
78 )
79
80 return report
81
82# Generate report
83report = generate_automated_report(None)
84print(report)

6.2 Scheduling Reports

Python
1# Schedule configuration
2schedule_config = {
3 'daily_flash': {
4 'time': '07:00',
5 'recipients': ['ceo@company.com', 'cfo@company.com'],
6 'metrics': ['revenue', 'orders', 'active_users']
7 },
8 'weekly_summary': {
9 'day': 'Monday',
10 'time': '08:00',
11 'recipients': ['leadership@company.com'],
12 'metrics': 'all_kpis'
13 },
14 'monthly_review': {
15 'day': 1, # First of month
16 'time': '09:00',
17 'recipients': ['board@company.com'],
18 'metrics': 'full_report'
19 }
20}
21
22def schedule_report_job(config):
23 """Schedule automated report generation"""
24 # In production, use APScheduler, Airflow, or similar
25 print(f"Scheduled: {config}")
26 pass

7. Thực hành

Executive Report Project

Exercise: Build Executive Report

Python
1# Create a complete executive report:
2# 1. Define KPIs and targets
3# 2. Calculate performance metrics
4# 3. Generate visualizations
5# 4. Write executive summary
6# 5. Create actionable recommendations
7
8# YOUR CODE HERE
💡 Xem đáp án
Python
1import pandas as pd
2import numpy as np
3import matplotlib.pyplot as plt
4from datetime import datetime
5
6class ExecutiveReport:
7 def __init__(self, company_name, period):
8 self.company = company_name
9 self.period = period
10 self.kpis = {}
11 self.issues = []
12 self.wins = []
13 self.actions = []
14
15 def add_kpi(self, name, current, target, previous, unit='', higher_better=True):
16 """Add KPI to report"""
17 vs_target_pct = ((current - target) / target * 100) if target else 0
18 vs_previous_pct = ((current - previous) / previous * 100) if previous else 0
19
20 if higher_better:
21 on_track = current >= target
22 else:
23 on_track = current <= target
24
25 status = '✅' if on_track else '⚠️' if abs(vs_target_pct) < 15 else '❌'
26
27 self.kpis[name] = {
28 'current': current,
29 'target': target,
30 'previous': previous,
31 'unit': unit,
32 'vs_target': vs_target_pct,
33 'vs_previous': vs_previous_pct,
34 'status': status,
35 'on_track': on_track
36 }
37
38 def add_issue(self, issue, impact, owner, due_date):
39 self.issues.append({
40 'issue': issue,
41 'impact': impact,
42 'owner': owner,
43 'due': due_date
44 })
45
46 def add_win(self, win, impact):
47 self.wins.append({'win': win, 'impact': impact})
48
49 def add_action(self, action, owner, due_date, expected_impact):
50 self.actions.append({
51 'action': action,
52 'owner': owner,
53 'due': due_date,
54 'impact': expected_impact
55 })
56
57 def get_overall_status(self):
58 """Calculate overall business status"""
59 on_track_count = sum(1 for k in self.kpis.values() if k['on_track'])
60 total = len(self.kpis)
61 pct = on_track_count / total if total > 0 else 0
62
63 if pct >= 0.8:
64 return '✅ ON TRACK', 'green'
65 elif pct >= 0.6:
66 return '⚠️ NEEDS ATTENTION', 'orange'
67 else:
68 return '❌ AT RISK', 'red'
69
70 def generate_text_report(self):
71 """Generate text-based executive report"""
72 status, _ = self.get_overall_status()
73
74 report = f"""
75{'='*70}
76 EXECUTIVE SUMMARY REPORT
77 {self.company}
78 {self.period}
79{'='*70}
80
81Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}
82Overall Status: {status}
83
84{'─'*70}
85KEY PERFORMANCE INDICATORS
86{'─'*70}
87"""
88 # KPI Summary
89 for name, data in self.kpis.items():
90 unit = data['unit']
91 report += f"""
92{data['status']} {name}
93 Current: {data['current']}{unit} | Target: {data['target']}{unit}
94 vs Target: {'+' if data['vs_target'] > 0 else ''}{data['vs_target']:.1f}%
95 vs Previous: {'+' if data['vs_previous'] > 0 else ''}{data['vs_previous']:.1f}%
96"""
97
98 # Issues
99 if self.issues:
100 report += f"\n{'─'*70}\n🔴 KEY ISSUES\n{'─'*70}\n"
101 for i, issue in enumerate(self.issues, 1):
102 report += f"{i}. {issue['issue']}\n"
103 report += f" Impact: {issue['impact']} | Owner: {issue['owner']} | Due: {issue['due']}\n"
104
105 # Wins
106 if self.wins:
107 report += f"\n{'─'*70}\n🟢 KEY WINS\n{'─'*70}\n"
108 for i, win in enumerate(self.wins, 1):
109 report += f"{i}. {win['win']} (Impact: {win['impact']})\n"
110
111 # Actions
112 if self.actions:
113 report += f"\n{'─'*70}\n📋 ACTION ITEMS\n{'─'*70}\n"
114 for i, action in enumerate(self.actions, 1):
115 report += f"{i}. {action['action']}\n"
116 report += f" Owner: {action['owner']} | Due: {action['due']} | Expected: {action['impact']}\n"
117
118 report += f"\n{'='*70}\n"
119
120 return report
121
122 def create_dashboard(self):
123 """Create visual dashboard"""
124 fig = plt.figure(figsize=(16, 12))
125 fig.suptitle(f'{self.company} - {self.period} Executive Dashboard',
126 fontsize=14, fontweight='bold')
127
128 # KPI cards row
129 n_kpis = len(self.kpis)
130 for i, (name, data) in enumerate(self.kpis.items()):
131 ax = fig.add_subplot(3, n_kpis, i+1)
132
133 color = 'green' if data['on_track'] else 'red'
134 ax.text(0.5, 0.6, f"{data['current']}{data['unit']}",
135 fontsize=24, fontweight='bold', ha='center', va='center', color=color)
136 ax.text(0.5, 0.25, name, fontsize=10, ha='center', va='center')
137 ax.text(0.5, 0.1, f"Target: {data['target']}{data['unit']}",
138 fontsize=8, ha='center', va='center', color='gray')
139 ax.set_xlim(0, 1)
140 ax.set_ylim(0, 1)
141 ax.axis('off')
142
143 # Border color based on status
144 for spine in ax.spines.values():
145 spine.set_visible(True)
146 spine.set_color(color)
147 spine.set_linewidth(2)
148
149 # Trend chart
150 ax_trend = fig.add_subplot(3, 2, 3)
151 months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
152 revenue = [2.0, 2.2, 2.1, 2.4, 2.3, 2.5]
153 target = [2.1, 2.2, 2.3, 2.4, 2.5, 2.6]
154
155 ax_trend.plot(months, revenue, 'go-', linewidth=2, label='Actual')
156 ax_trend.plot(months, target, 'k--', label='Target')
157 ax_trend.fill_between(months, revenue, alpha=0.3, color='green')
158 ax_trend.set_ylabel('Revenue ($M)')
159 ax_trend.set_title('Revenue Trend')
160 ax_trend.legend()
161
162 # Bar comparison
163 ax_bar = fig.add_subplot(3, 2, 4)
164 kpi_names = list(self.kpis.keys())[:4]
165 vs_target = [self.kpis[k]['vs_target'] for k in kpi_names]
166 colors = ['green' if v >= 0 else 'red' for v in vs_target]
167
168 bars = ax_bar.barh(kpi_names, vs_target, color=colors)
169 ax_bar.axvline(0, color='black', linewidth=0.5)
170 ax_bar.set_xlabel('% vs Target')
171 ax_bar.set_title('KPI Performance vs Target')
172 ax_bar.bar_label(bars, fmt='%.1f%%')
173
174 # Issues and Actions
175 ax_text = fig.add_subplot(3, 1, 3)
176 ax_text.axis('off')
177
178 text = "🔴 TOP ISSUES:\n"
179 for issue in self.issues[:3]:
180 text += f" • {issue['issue']} (Owner: {issue['owner']})\n"
181
182 text += "\n🎯 KEY ACTIONS:\n"
183 for action in self.actions[:3]:
184 text += f" • {action['action']} (Due: {action['due']})\n"
185
186 ax_text.text(0.05, 0.95, text, fontsize=10, verticalalignment='top',
187 fontfamily='monospace', transform=ax_text.transAxes)
188
189 plt.tight_layout()
190 plt.savefig('executive_report_dashboard.png', dpi=150, bbox_inches='tight')
191 plt.show()
192
193
194# Create report
195report = ExecutiveReport('TechCo Inc', 'March 2024')
196
197# Add KPIs
198report.add_kpi('Revenue', 2.5, 2.3, 2.1, 'M', higher_better=True)
199report.add_kpi('Customers', 15200, 14000, 13500, '', higher_better=True)
200report.add_kpi('Churn Rate', 5.2, 4.0, 4.5, '%', higher_better=False)
201report.add_kpi('NPS', 48, 50, 45, '', higher_better=True)
202report.add_kpi('CAC', 125, 100, 135, '$', higher_better=False)
203
204# Add issues
205report.add_issue(
206 'Churn rate above target',
207 'Risk of $400K revenue loss',
208 'VP Customer Success',
209 'April 15'
210)
211report.add_issue(
212 'CAC trending up',
213 '18% above target, impacting unit economics',
214 'CMO',
215 'April 10'
216)
217
218# Add wins
219report.add_win('Revenue exceeded target by 9%', '+$200K incremental')
220report.add_win('Customer count growth accelerated', '+12% MoM')
221
222# Add actions
223report.add_action(
224 'Launch customer loyalty program',
225 'VP Customer Success',
226 'April 20',
227 'Reduce churn by 15%'
228)
229report.add_action(
230 'Optimize paid marketing channels',
231 'CMO',
232 'April 15',
233 'Reduce CAC by $20'
234)
235
236# Generate outputs
237print(report.generate_text_report())
238report.create_dashboard()
239
240print("✅ Executive report generated!")

8. Tổng kết

TopicKey Concepts
KPI FrameworkChoose actionable, aligned metrics
Report StructureExecutive summary first, details in appendix
VisualizationClean design, traffic lights, sparklines
Presenting5-minute rule, prepare for questions
AutomationTemplate-based generation, scheduling

Bài tiếp theo: Automated Reports