Add export functionality to all reports pages

parent 849b646a
...@@ -2265,6 +2265,564 @@ def sync_logs(): ...@@ -2265,6 +2265,564 @@ def sync_logs():
flash('Error loading sync logs', 'error') flash('Error loading sync logs', 'error')
return render_template('main/sync_logs.html', logs=[], pagination=None, client_ids=[]) return render_template('main/sync_logs.html', logs=[], pagination=None, client_ids=[])
def export_bet_detail(client_id, match_id, bet_uuid, export_format):
"""Export bet detail to CSV, XLSX, or PDF"""
try:
from app.models import Bet, BetDetail, APIToken, ClientActivity
# Check if user has access to this client
if current_user.is_admin:
bet_query = Bet.query.filter_by(client_id=client_id, match_id=match_id, uuid=bet_uuid)
else:
user_token_ids = [t.id for t in APIToken.query.filter_by(user_id=current_user.id).all()]
if user_token_ids:
client_ids = [c.rustdesk_id for c in ClientActivity.query.filter(
ClientActivity.api_token_id.in_(user_token_ids)
).all()]
if client_id not in client_ids:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
bet_query = Bet.query.filter_by(client_id=client_id, match_id=match_id, uuid=bet_uuid)
else:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
# Get bet and bet details
bet = bet_query.first()
if not bet:
flash('Bet not found', 'error')
return redirect(url_for('main.match_report_detail', client_id=client_id, match_id=match_id))
bet_details = BetDetail.query.filter_by(bet_id=bet.id).all()
# Prepare data for export
export_data = []
# Add bet summary
export_data.append({
'Type': 'Bet Summary',
'Bet UUID': bet.uuid,
'Match ID': match_id,
'Match Number': bet.match_number,
'Bet DateTime': bet.bet_datetime.strftime('%Y-%m-%d %H:%M:%S') if bet.bet_datetime else '',
'Total Amount': float(bet.total_amount) if bet.total_amount else 0.0,
'Bet Count': bet.bet_count,
'Paid': bet.paid,
'Paid Out': bet.paid_out
})
# Add bet details
for detail in bet_details:
export_data.append({
'Type': 'Bet Detail',
'Bet UUID': bet.uuid,
'Match ID': match_id,
'Match Number': bet.match_number,
'Bet DateTime': bet.bet_datetime.strftime('%Y-%m-%d %H:%M:%S') if bet.bet_datetime else '',
'Total Amount': '',
'Bet Count': '',
'Paid': '',
'Paid Out': '',
'Outcome': detail.outcome,
'Amount': float(detail.amount) if detail.amount else 0.0,
'Win Amount': float(detail.win_amount) if detail.win_amount else 0.0,
'Result': detail.result
})
# Create DataFrame
df = pd.DataFrame(export_data)
# Export based on format
if export_format == 'csv':
output = StringIO()
df.to_csv(output, index=False)
output.seek(0)
return Response(
output.getvalue(),
mimetype='text/csv',
headers={'Content-Disposition': 'attachment; filename=bet_detail_export.csv'}
)
elif export_format == 'xlsx':
output = BytesIO()
with pd.ExcelWriter(output, engine='openpyxl') as writer:
df.to_excel(writer, index=False, sheet_name='Bet Detail')
output.seek(0)
return Response(
output.getvalue(),
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers={'Content-Disposition': 'attachment; filename=bet_detail_export.xlsx'}
)
elif export_format == 'pdf':
from weasyprint import HTML
# Create HTML table with styling
html_table = df.to_html(index=False, classes='table table-striped table-bordered')
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
h1 {{ color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }}
table {{ border-collapse: collapse; width: 100%; margin-bottom: 20px; }}
th {{ background-color: #007bff; color: white; padding: 10px; text-align: left; font-weight: bold; }}
td {{ padding: 8px; border: 1px solid #ddd; }}
tr:nth-child(even) {{ background-color: #f9f9f9; }}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
</style>
</head>
<body>
<h1>Bet Detail Export</h1>
<p>Generated on: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Client ID: {client_id}</p>
<p>Match ID: {match_id}</p>
<p>Bet UUID: {bet_uuid}</p>
<p>Total Bet Details: {len(bet_details)}</p>
{html_table}
</body>
</html>
"""
# Generate PDF
pdf_bytes = HTML(string=html_content).write_pdf()
return Response(
pdf_bytes,
mimetype='application/pdf',
headers={'Content-Disposition': 'attachment; filename=bet_detail_export.pdf'}
)
else:
flash('Invalid export format', 'error')
return redirect(url_for('main.bet_detail', client_id=client_id, match_id=match_id, bet_uuid=bet_uuid))
except Exception as e:
logger.error(f"Export bet detail error: {str(e)}")
flash('Error exporting bet detail', 'error')
return redirect(url_for('main.bet_detail', client_id=client_id, match_id=match_id, bet_uuid=bet_uuid))
def export_match_report(client_id, match_id, export_format):
"""Export match report to CSV, XLSX, or PDF"""
try:
from app.models import MatchReport, Bet, BetDetail, APIToken, ClientActivity
from datetime import timedelta
# Get filter parameters
date_range_filter = request.args.get('date_range', 'today').strip()
start_date_filter = request.args.get('start_date', '').strip()
end_date_filter = request.args.get('end_date', '').strip()
start_time_filter = request.args.get('start_time', '').strip()
end_time_filter = request.args.get('end_time', '').strip()
timezone_filter = request.args.get('timezone', 'auto').strip()
# Calculate date range
now = datetime.utcnow()
start_date = None
end_date = None
if date_range_filter == 'today':
start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'yesterday':
yesterday = now - timedelta(days=1)
start_date = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = yesterday.replace(hour=23, minute=59, second=59, microsecond=999999)
elif date_range_filter == 'this_week':
start_date = now - timedelta(days=now.weekday())
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'last_week':
last_week_end = now - timedelta(days=now.weekday() + 1)
last_week_start = last_week_end - timedelta(days=6)
start_date = last_week_start.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = last_week_end.replace(hour=23, minute=59, second=59, microsecond=999999)
elif date_range_filter == 'this_month':
start_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'all':
start_date = None
end_date = None
elif date_range_filter == 'custom':
if start_date_filter:
try:
start_date = datetime.strptime(start_date_filter, '%Y-%m-%d')
if start_time_filter:
hour, minute = map(int, start_time_filter.split(':'))
start_date = start_date.replace(hour=hour, minute=minute, second=0, microsecond=0)
else:
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
except ValueError:
pass
if end_date_filter:
try:
end_date = datetime.strptime(end_date_filter, '%Y-%m-%d')
if end_time_filter:
hour, minute = map(int, end_time_filter.split(':'))
end_date = end_date.replace(hour=hour, minute=minute, second=59, microsecond=999999)
else:
end_date = end_date.replace(hour=23, minute=59, second=59, microsecond=999999)
except ValueError:
pass
# Check if user has access to this client
if current_user.is_admin:
match_report_query = MatchReport.query.filter_by(client_id=client_id, match_id=match_id)
bets_query = Bet.query.filter_by(client_id=client_id, match_id=match_id)
else:
user_token_ids = [t.id for t in APIToken.query.filter_by(user_id=current_user.id).all()]
if user_token_ids:
client_ids = [c.rustdesk_id for c in ClientActivity.query.filter(
ClientActivity.api_token_id.in_(user_token_ids)
).all()]
if client_id not in client_ids:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
match_report_query = MatchReport.query.filter_by(client_id=client_id, match_id=match_id)
bets_query = Bet.query.filter_by(client_id=client_id, match_id=match_id)
else:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
# Get match report (don't apply date filters - we want specific match)
match_report = match_report_query.first()
if not match_report:
flash('Match report not found', 'error')
return redirect(url_for('main.client_report_detail', client_id=client_id))
# Apply date filters to bets
if start_date:
bets_query = bets_query.filter(Bet.bet_datetime >= start_date)
if end_date:
bets_query = bets_query.filter(Bet.bet_datetime <= end_date)
# Get bets and bet details
bets = bets_query.all()
# Prepare data for export
export_data = []
# Add match summary
export_data.append({
'Type': 'Match Summary',
'Match ID': match_report.match_id,
'Match Number': match_report.match_number,
'Fixture ID': match_report.fixture_id,
'Match DateTime': match_report.match_datetime.strftime('%Y-%m-%d %H:%M:%S') if match_report.match_datetime else '',
'Total Bets': match_report.total_bets,
'Winning Bets': match_report.winning_bets,
'Losing Bets': match_report.losing_bets,
'Pending Bets': match_report.pending_bets,
'Total Payin': float(match_report.total_payin) if match_report.total_payin else 0.0,
'Total Payout': float(match_report.total_payout) if match_report.total_payout else 0.0,
'Balance': float(match_report.balance) if match_report.balance else 0.0,
'Actual Result': match_report.actual_result,
'Extraction Result': match_report.extraction_result,
'CAP Applied': match_report.cap_applied,
'CAP Percentage': match_report.cap_percentage,
'CAP Balance': float(match_report.cap_compensation_balance) if match_report.cap_compensation_balance else 0.0,
'Accumulated Shortfall': float(match_report.accumulated_shortfall) if match_report.accumulated_shortfall else 0.0
})
# Add bets
for bet in bets:
bet_details = BetDetail.query.filter_by(bet_id=bet.id).all()
for detail in bet_details:
export_data.append({
'Type': 'Bet Detail',
'Match ID': match_report.match_id,
'Match Number': match_report.match_number,
'Fixture ID': match_report.fixture_id,
'Match DateTime': match_report.match_datetime.strftime('%Y-%m-%d %H:%M:%S') if match_report.match_datetime else '',
'Total Bets': '',
'Winning Bets': '',
'Losing Bets': '',
'Pending Bets': '',
'Total Payin': '',
'Total Payout': '',
'Balance': '',
'Actual Result': '',
'Extraction Result': '',
'CAP Applied': '',
'CAP Percentage': '',
'CAP Balance': '',
'Accumulated Shortfall': '',
'Bet UUID': bet.uuid,
'Bet DateTime': bet.bet_datetime.strftime('%Y-%m-%d %H:%M:%S') if bet.bet_datetime else '',
'Total Amount': float(bet.total_amount) if bet.total_amount else 0.0,
'Bet Count': bet.bet_count,
'Paid': bet.paid,
'Paid Out': bet.paid_out,
'Outcome': detail.outcome,
'Amount': float(detail.amount) if detail.amount else 0.0,
'Win Amount': float(detail.win_amount) if detail.win_amount else 0.0,
'Result': detail.result
})
# Create DataFrame
df = pd.DataFrame(export_data)
# Export based on format
if export_format == 'csv':
output = StringIO()
df.to_csv(output, index=False)
output.seek(0)
return Response(
output.getvalue(),
mimetype='text/csv',
headers={'Content-Disposition': 'attachment; filename=match_report_export.csv'}
)
elif export_format == 'xlsx':
output = BytesIO()
with pd.ExcelWriter(output, engine='openpyxl') as writer:
df.to_excel(writer, index=False, sheet_name='Match Report')
output.seek(0)
return Response(
output.getvalue(),
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers={'Content-Disposition': 'attachment; filename=match_report_export.xlsx'}
)
elif export_format == 'pdf':
from weasyprint import HTML
# Create HTML table with styling
html_table = df.to_html(index=False, classes='table table-striped table-bordered')
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
h1 {{ color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }}
table {{ border-collapse: collapse; width: 100%; margin-bottom: 20px; }}
th {{ background-color: #007bff; color: white; padding: 10px; text-align: left; font-weight: bold; }}
td {{ padding: 8px; border: 1px solid #ddd; }}
tr:nth-child(even) {{ background-color: #f9f9f9; }}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
</style>
</head>
<body>
<h1>Match Report Export</h1>
<p>Generated on: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Client ID: {client_id}</p>
<p>Match ID: {match_id}</p>
<p>Total Bets: {len(bets)}</p>
{html_table}
</body>
</html>
"""
# Generate PDF
pdf_bytes = HTML(string=html_content).write_pdf()
return Response(
pdf_bytes,
mimetype='application/pdf',
headers={'Content-Disposition': 'attachment; filename=match_report_export.pdf'}
)
else:
flash('Invalid export format', 'error')
return redirect(url_for('main.match_report_detail', client_id=client_id, match_id=match_id))
except Exception as e:
logger.error(f"Export match report error: {str(e)}")
flash('Error exporting match report', 'error')
return redirect(url_for('main.match_report_detail', client_id=client_id, match_id=match_id))
def export_client_report(client_id, export_format):
"""Export client report to CSV, XLSX, or PDF"""
try:
from app.models import ReportSync, Bet, ExtractionStats, APIToken, ClientActivity, MatchReport
from datetime import timedelta
# Get filter parameters
date_range_filter = request.args.get('date_range', 'today').strip()
start_date_filter = request.args.get('start_date', '').strip()
end_date_filter = request.args.get('end_date', '').strip()
start_time_filter = request.args.get('start_time', '').strip()
end_time_filter = request.args.get('end_time', '').strip()
timezone_filter = request.args.get('timezone', 'auto').strip()
# Calculate date range
now = datetime.utcnow()
start_date = None
end_date = None
if date_range_filter == 'today':
start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'yesterday':
yesterday = now - timedelta(days=1)
start_date = yesterday.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = yesterday.replace(hour=23, minute=59, second=59, microsecond=999999)
elif date_range_filter == 'this_week':
start_date = now - timedelta(days=now.weekday())
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'last_week':
last_week_end = now - timedelta(days=now.weekday() + 1)
last_week_start = last_week_end - timedelta(days=6)
start_date = last_week_start.replace(hour=0, minute=0, second=0, microsecond=0)
end_date = last_week_end.replace(hour=23, minute=59, second=59, microsecond=999999)
elif date_range_filter == 'this_month':
start_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
end_date = now
elif date_range_filter == 'all':
start_date = None
end_date = None
elif date_range_filter == 'custom':
if start_date_filter:
try:
start_date = datetime.strptime(start_date_filter, '%Y-%m-%d')
if start_time_filter:
hour, minute = map(int, start_time_filter.split(':'))
start_date = start_date.replace(hour=hour, minute=minute, second=0, microsecond=0)
else:
start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0)
except ValueError:
pass
if end_date_filter:
try:
end_date = datetime.strptime(end_date_filter, '%Y-%m-%d')
if end_time_filter:
hour, minute = map(int, end_time_filter.split(':'))
end_date = end_date.replace(hour=hour, minute=minute, second=59, microsecond=999999)
else:
end_date = end_date.replace(hour=23, minute=59, second=59, microsecond=999999)
except ValueError:
pass
# Check if user has access to this client
if current_user.is_admin:
query = MatchReport.query.filter_by(client_id=client_id)
else:
user_token_ids = [t.id for t in APIToken.query.filter_by(user_id=current_user.id).all()]
if user_token_ids:
client_ids = [c.rustdesk_id for c in ClientActivity.query.filter(
ClientActivity.api_token_id.in_(user_token_ids)
).all()]
if client_id not in client_ids:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
query = MatchReport.query.filter_by(client_id=client_id)
else:
flash('Access denied to this client', 'error')
return redirect(url_for('main.reports'))
# Apply date filters
if start_date:
query = query.filter(MatchReport.match_datetime >= start_date)
if end_date:
query = query.filter(MatchReport.match_datetime <= end_date)
# Get all matching match reports for this client
match_reports = query.all()
if not match_reports:
flash('No reports to export', 'warning')
return redirect(url_for('main.client_report_detail', client_id=client_id))
# Prepare data for export
export_data = []
for report in match_reports:
export_data.append({
'Match ID': report.match_id,
'Match Number': report.match_number,
'Fixture ID': report.fixture_id,
'Match DateTime': report.match_datetime.strftime('%Y-%m-%d %H:%M:%S') if report.match_datetime else '',
'Total Bets': report.total_bets,
'Winning Bets': report.winning_bets,
'Losing Bets': report.losing_bets,
'Pending Bets': report.pending_bets,
'Total Payin': float(report.total_payin) if report.total_payin else 0.0,
'Total Payout': float(report.total_payout) if report.total_payout else 0.0,
'Balance': float(report.balance) if report.balance else 0.0,
'Actual Result': report.actual_result,
'Extraction Result': report.extraction_result,
'CAP Applied': report.cap_applied,
'CAP Percentage': report.cap_percentage,
'CAP Balance': float(report.cap_compensation_balance) if report.cap_compensation_balance else 0.0,
'Accumulated Shortfall': float(report.accumulated_shortfall) if report.accumulated_shortfall else 0.0
})
# Create DataFrame
df = pd.DataFrame(export_data)
# Export based on format
if export_format == 'csv':
output = StringIO()
df.to_csv(output, index=False)
output.seek(0)
return Response(
output.getvalue(),
mimetype='text/csv',
headers={'Content-Disposition': 'attachment; filename=client_report_export.csv'}
)
elif export_format == 'xlsx':
output = BytesIO()
with pd.ExcelWriter(output, engine='openpyxl') as writer:
df.to_excel(writer, index=False, sheet_name='Client Report')
output.seek(0)
return Response(
output.getvalue(),
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers={'Content-Disposition': 'attachment; filename=client_report_export.xlsx'}
)
elif export_format == 'pdf':
from weasyprint import HTML
# Create HTML table with styling
html_table = df.to_html(index=False, classes='table table-striped table-bordered')
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
h1 {{ color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }}
table {{ border-collapse: collapse; width: 100%; margin-bottom: 20px; }}
th {{ background-color: #007bff; color: white; padding: 10px; text-align: left; font-weight: bold; }}
td {{ padding: 8px; border: 1px solid #ddd; }}
tr:nth-child(even) {{ background-color: #f9f9f9; }}
.text-right {{ text-align: right; }}
.text-center {{ text-align: center; }}
</style>
</head>
<body>
<h1>Client Report Export</h1>
<p>Generated on: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Client ID: {client_id}</p>
<p>Total Matches: {len(export_data)}</p>
{html_table}
</body>
</html>
"""
# Generate PDF
pdf_bytes = HTML(string=html_content).write_pdf()
return Response(
pdf_bytes,
mimetype='application/pdf',
headers={'Content-Disposition': 'attachment; filename=client_report_export.pdf'}
)
else:
flash('Invalid export format', 'error')
return redirect(url_for('main.client_report_detail', client_id=client_id))
except Exception as e:
logger.error(f"Export client report error: {str(e)}")
flash('Error exporting client report', 'error')
return redirect(url_for('main.client_report_detail', client_id=client_id))
def export_sync_logs(export_format): def export_sync_logs(export_format):
"""Export sync logs to CSV, XLSX, or PDF""" """Export sync logs to CSV, XLSX, or PDF"""
try: try:
...@@ -2524,6 +3082,11 @@ def client_report_detail(client_id): ...@@ -2524,6 +3082,11 @@ def client_report_detail(client_id):
from app.models import ReportSync, Bet, ExtractionStats, APIToken, ClientActivity, MatchReport from app.models import ReportSync, Bet, ExtractionStats, APIToken, ClientActivity, MatchReport
from datetime import timedelta from datetime import timedelta
# Check for export request
export_format = request.args.get('export')
if export_format:
return export_client_report(client_id, export_format)
# Get filter parameters # Get filter parameters
date_range_filter = request.args.get('date_range', 'today').strip() date_range_filter = request.args.get('date_range', 'today').strip()
start_date_filter = request.args.get('start_date', '').strip() start_date_filter = request.args.get('start_date', '').strip()
...@@ -2689,6 +3252,11 @@ def match_report_detail(client_id, match_id): ...@@ -2689,6 +3252,11 @@ def match_report_detail(client_id, match_id):
from app.models import MatchReport, Bet, BetDetail, APIToken, ClientActivity from app.models import MatchReport, Bet, BetDetail, APIToken, ClientActivity
from datetime import timedelta from datetime import timedelta
# Check for export request
export_format = request.args.get('export')
if export_format:
return export_match_report(client_id, match_id, export_format)
# Get filter parameters # Get filter parameters
date_range_filter = request.args.get('date_range', 'today').strip() date_range_filter = request.args.get('date_range', 'today').strip()
start_date_filter = request.args.get('start_date', '').strip() start_date_filter = request.args.get('start_date', '').strip()
...@@ -2822,6 +3390,11 @@ def bet_detail(client_id, match_id, bet_uuid): ...@@ -2822,6 +3390,11 @@ def bet_detail(client_id, match_id, bet_uuid):
try: try:
from app.models import Bet, BetDetail, APIToken, ClientActivity from app.models import Bet, BetDetail, APIToken, ClientActivity
# Check for export request
export_format = request.args.get('export')
if export_format:
return export_bet_detail(client_id, match_id, bet_uuid, export_format)
# Get filter parameters # Get filter parameters
date_range_filter = request.args.get('date_range', 'today').strip() date_range_filter = request.args.get('date_range', 'today').strip()
start_date_filter = request.args.get('start_date', '').strip() start_date_filter = request.args.get('start_date', '').strip()
......
...@@ -129,9 +129,21 @@ ...@@ -129,9 +129,21 @@
</ol> </ol>
</nav> </nav>
</div> </div>
<a href="{{ url_for('main.match_report_detail', client_id=client_id, match_id=match_id, **filters) }}" class="btn btn-secondary"> <div class="d-flex gap-2">
<i class="fas fa-arrow-left"></i> Back to Match <div class="btn-group">
</a> <button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ url_for('main.bet_detail', client_id=client_id, match_id=match_id, bet_uuid=bet_uuid, export='csv', **filters) }}">Export as CSV</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.bet_detail', client_id=client_id, match_id=match_id, bet_uuid=bet_uuid, export='xlsx', **filters) }}">Export as Excel</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.bet_detail', client_id=client_id, match_id=match_id, bet_uuid=bet_uuid, export='pdf', **filters) }}">Export as PDF</a></li>
</ul>
</div>
<a href="{{ url_for('main.match_report_detail', client_id=client_id, match_id=match_id, **filters) }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Back to Match
</a>
</div>
</div> </div>
<!-- Bet Summary Cards --> <!-- Bet Summary Cards -->
......
...@@ -186,9 +186,21 @@ ...@@ -186,9 +186,21 @@
</ol> </ol>
</nav> </nav>
</div> </div>
<a href="{{ url_for('main.reports', **filters) }}" class="btn btn-secondary"> <div class="d-flex gap-2">
<i class="fas fa-arrow-left"></i> Back to Reports <div class="btn-group">
</a> <button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ url_for('main.client_report_detail', client_id=client_id, export='csv', **filters) }}">Export as CSV</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.client_report_detail', client_id=client_id, export='xlsx', **filters) }}">Export as Excel</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.client_report_detail', client_id=client_id, export='pdf', **filters) }}">Export as PDF</a></li>
</ul>
</div>
<a href="{{ url_for('main.reports', **filters) }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Back to Reports
</a>
</div>
</div> </div>
<!-- Summary Cards - First Row (3 cards) --> <!-- Summary Cards - First Row (3 cards) -->
......
...@@ -187,9 +187,21 @@ ...@@ -187,9 +187,21 @@
</ol> </ol>
</nav> </nav>
</div> </div>
<a href="{{ url_for('main.client_report_detail', client_id=client_id, **filters) }}" class="btn btn-secondary"> <div class="d-flex gap-2">
<i class="fas fa-arrow-left"></i> Back to Client <div class="btn-group">
</a> <button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown">
<i class="fas fa-download"></i> Export
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{{ url_for('main.match_report_detail', client_id=client_id, match_id=match_id, export='csv', **filters) }}">Export as CSV</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.match_report_detail', client_id=client_id, match_id=match_id, export='xlsx', **filters) }}">Export as Excel</a></li>
<li><a class="dropdown-item" href="{{ url_for('main.match_report_detail', client_id=client_id, match_id=match_id, export='pdf', **filters) }}">Export as PDF</a></li>
</ul>
</div>
<a href="{{ url_for('main.client_report_detail', client_id=client_id, **filters) }}" class="btn btn-secondary">
<i class="fas fa-arrow-left"></i> Back to Client
</a>
</div>
</div> </div>
<!-- Match Summary Cards --> <!-- Match Summary Cards -->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment