![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/private_html/ |
<?php
// Suppress error display but log them
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
session_start();
require_once 'config/database.php';
require_once 'includes/translations.php';
$event_id = isset($_GET['event_id']) ? (int)$_GET['event_id'] : 0;
$is_ajax = isset($_GET['ajax']) && $_GET['ajax'] === '1';
// Start output buffering for AJAX requests
if ($is_ajax) {
ob_start();
}
if (!isset($_SESSION['user_id'])) {
if ($is_ajax) {
if (ob_get_level()) {
ob_clean();
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
} else {
header('Location: /auth/login.php');
}
exit;
}
if ($event_id <= 0) {
if ($is_ajax) {
ob_clean();
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Invalid event ID']);
} else {
ob_end_clean();
header('Location: /events.php');
}
exit;
}
$pdo = getDBConnection();
$user_id = $_SESSION['user_id'];
// Get event details and verify creator
$stmt = $pdo->prepare("
SELECT
e.*,
u.name as creator_name
FROM events e
JOIN users u ON e.creator_id = u.id
WHERE e.id = ?
");
$stmt->execute([$event_id]);
$event = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$event) {
if ($is_ajax) {
ob_clean();
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Event not found']);
} else {
ob_end_clean();
header('Location: /events.php');
}
exit;
}
// Verify user is the creator
if ($event['creator_id'] != $user_id) {
if ($is_ajax) {
ob_clean();
header('Content-Type: application/json');
echo json_encode(['success' => false, 'message' => 'Access denied']);
} else {
ob_end_clean();
header('Location: /events.php?event=' . $event_id . '&access=denied');
}
exit;
}
// Get user's plan for pricing tier
try {
$user_stmt = $pdo->prepare("SELECT plan FROM users WHERE id = ?");
$user_stmt->execute([$user_id]);
$user = $user_stmt->fetch(PDO::FETCH_ASSOC);
$user_plan = strtolower($user['plan'] ?? 'free');
} catch (Exception $e) {
if ($is_ajax) {
if (ob_get_level()) {
ob_clean();
}
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
exit;
}
throw $e;
}
// Load pricing configuration
try {
require_once __DIR__ . '/config/event_pricing.php';
$pricing_tier = getEventPricingTier($user_plan);
} catch (Exception $e) {
if ($is_ajax) {
if (ob_get_level()) {
ob_clean();
}
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Configuration error: ' . $e->getMessage()]);
exit;
}
throw $e;
}
// Get all ticket sales for this event
try {
$sales_stmt = $pdo->prepare("
SELECT
ets.*,
et.ticket_code,
et.status as ticket_status,
et.purchase_date,
et.price_paid,
u.name as buyer_name,
u.email as buyer_email
FROM event_ticket_sales ets
JOIN event_tickets et ON ets.ticket_id = et.id
LEFT JOIN users u ON ets.buyer_id = u.id
WHERE ets.event_id = ? AND ets.event_creator_id = ?
ORDER BY ets.created_at DESC
");
$sales_stmt->execute([$event_id, $user_id]);
$all_sales = $sales_stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
// If table doesn't exist, return empty array
if (strpos($e->getMessage(), "doesn't exist") !== false || strpos($e->getMessage(), "Unknown table") !== false) {
$all_sales = [];
} else {
if ($is_ajax) {
if (ob_get_level()) {
ob_clean();
}
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
exit;
}
throw $e;
}
} catch (Exception $e) {
if ($is_ajax) {
if (ob_get_level()) {
ob_clean();
}
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error: ' . $e->getMessage()]);
exit;
}
throw $e;
}
// Calculate totals using new pricing model
$total_tickets_sold = count($all_sales);
$total_revenue = 0;
$total_service_fees = 0;
$total_payment_processing_fees = 0;
$total_platform_fees = 0;
$total_creator_earnings = 0;
$is_free_event = ($event['ticket_price'] == 0 || $event['is_free'] == 1);
foreach ($all_sales as $sale) {
$amount = (float)$sale['amount'];
$total_revenue += $amount;
// Calculate fees using new pricing model
$fees = calculateEventTicketFees($amount, $user_plan, $is_free_event, false);
$service_fee = $fees['service_fee'];
$payment_processing_fee = $fees['payment_processing_fee'];
$total_fee = $fees['total_fees'];
$creator_earning = $fees['organizer_receives'];
$total_service_fees += $service_fee;
$total_payment_processing_fees += $payment_processing_fee;
$total_platform_fees += $total_fee;
$total_creator_earnings += $creator_earning;
}
// Get free tickets count
try {
$free_tickets_stmt = $pdo->prepare("
SELECT COUNT(*) as free_count
FROM event_tickets
WHERE event_id = ? AND (price_paid = 0 OR price_paid IS NULL)
");
$free_tickets_stmt->execute([$event_id]);
$free_tickets = $free_tickets_stmt->fetch(PDO::FETCH_ASSOC)['free_count'] ?? 0;
} catch (Exception $e) {
// If error, default to 0
$free_tickets = 0;
}
?>
<div class="event-modal-overlay" id="salesEarningsModalOverlay" style="display: flex; visibility: visible; opacity: 1; z-index: 99999;">
<div class="event-modal-container" style="max-width: 1200px; width: 95%; max-height: 90vh; overflow-y: auto; position: relative;">
<button class="sales-earnings-modal-close" onclick="if(window.closeSalesEarningsModal){window.closeSalesEarningsModal();}else{const o=document.getElementById('salesEarningsModalOverlay');if(o){o.remove();document.body.style.overflow='';}}return false;">
<i class="fas fa-times"></i>
</button>
<div class="event-modal-content" style="background: transparent; border-radius: 0; padding: 0;">
<!-- Console Hero -->
<section class="console-hero" style="margin-bottom: 2rem;">
<div style="margin-bottom: 1rem;">
<?php
try {
$start_date = new DateTime($event['start_date']);
$formatted_date = $start_date->format('M j, Y g:i A');
} catch (Exception $e) {
$formatted_date = date('M j, Y g:i A', strtotime($event['start_date']));
}
?>
<p style="margin: 0 0 0.5rem; color: #cbd5f5; font-size: 0.9rem;"><?= t('events.types.' . ($event['event_type'] ?? 'other')) ?> ยท <?= $formatted_date ?></p>
<h1 style="margin: 0 0 0.5rem; font-size: 2.2rem; color: #fff;">
<i class="fas fa-chart-line" style="color: #667eea; margin-right: 0.5rem;"></i> <?= t('events.sales_earnings.title') ?>
</h1>
<p style="margin: 0; color: #cbd5f5;"><?= htmlspecialchars($event['title']) ?></p>
</div>
<div class="console-metrics" style="margin-top: 2rem;">
<div class="metric-card">
<h4><?= t('events.sales_earnings.tickets_sold') ?></h4>
<strong><?= number_format($total_tickets_sold) ?></strong>
<?php if ($free_tickets > 0): ?>
<div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.3rem;">
<?= $free_tickets ?> <?= t('events.sales_earnings.free_tickets') ?>
</div>
<?php endif; ?>
</div>
<div class="metric-card">
<h4><?= t('events.sales_earnings.total_revenue') ?></h4>
<strong>$<?= number_format($total_revenue, 2) ?></strong>
</div>
<div class="metric-card">
<h4><?= t('events.sales_earnings.platform_fees') ?></h4>
<strong style="color: #fc8181;">$<?= number_format($total_platform_fees, 2) ?></strong>
<div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.3rem;">
<?= $pricing_tier['service_fee_percentage'] ?>% + $<?= number_format($pricing_tier['fixed_fee_per_ticket'], 2) ?>
</div>
<div style="font-size: 0.7rem; color: #718096; margin-top: 0.2rem;">
<?= $pricing_tier['name'] ?>
</div>
</div>
<div class="metric-card">
<h4><?= t('events.sales_earnings.your_earnings') ?></h4>
<strong style="color: #68d391;">$<?= number_format($total_creator_earnings, 2) ?></strong>
<div style="font-size: 0.75rem; color: #9ca3af; margin-top: 0.3rem;">
<?= $total_revenue > 0 ? number_format(($total_creator_earnings / $total_revenue) * 100, 1) : 0 ?>% <?= t('events.sales_earnings.of_revenue') ?>
</div>
</div>
</div>
</section>
<!-- Modal Body -->
<div style="padding: 0 1.5rem 2rem;">
<!-- Earnings Breakdown -->
<div style="background: #f7fafc; border-radius: 16px; padding: 1.5rem; margin-bottom: 2rem;">
<h3 style="font-size: 1.3rem; font-weight: 700; margin-bottom: 1rem; color: #1a202c;">
<?= t('events.sales_earnings.breakdown') ?>
</h3>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; border-bottom: 1px solid #e2e8f0;">
<span style="color: #4a5568;"><?= t('events.sales_earnings.total_sales') ?></span>
<span style="font-weight: 600; color: #1a202c;">$<?= number_format($total_revenue, 2) ?></span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; border-bottom: 1px solid #e2e8f0;">
<span style="color: #4a5568;"><?= t('events.sales_earnings.service_fee') ?> (<?= $pricing_tier['service_fee_percentage'] ?>% + $<?= number_format($pricing_tier['fixed_fee_per_ticket'], 2) ?>)</span>
<span style="font-weight: 600; color: #f56565;">-$<?= number_format($total_service_fees, 2) ?></span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; border-bottom: 1px solid #e2e8f0;">
<span style="color: #4a5568;"><?= t('events.sales_earnings.payment_processing') ?> (<?= $pricing_tier['payment_processing_percentage'] ?>%)</span>
<span style="font-weight: 600; color: #f56565;">-$<?= number_format($total_payment_processing_fees, 2) ?></span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; border-bottom: 1px solid #e2e8f0;">
<span style="color: #4a5568; font-weight: 600;"><?= t('events.sales_earnings.total_fees') ?></span>
<span style="font-weight: 700; color: #f56565;">-$<?= number_format($total_platform_fees, 2) ?></span>
</div>
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 0; font-weight: 700; font-size: 1.1rem; border-top: 2px solid #667eea; margin-top: 0.5rem; padding-top: 1rem;">
<span style="color: #1a202c;"><?= t('events.sales_earnings.net_earnings') ?></span>
<span style="color: #48bb78; font-size: 1.3rem;">$<?= number_format($total_creator_earnings, 2) ?></span>
</div>
</div>
<!-- Sales Table -->
<section class="panel" style="margin-top: 2rem;">
<div class="panel-header">
<h2><i class="fas fa-receipt"></i> <?= t('events.sales_earnings.sales_details') ?></h2>
</div>
<?php if (empty($all_sales)): ?>
<div class="empty-notice">
<i class="fas fa-receipt"></i>
<p><?= t('events.sales_earnings.no_sales') ?></p>
<p style="font-size: 0.9rem; margin-top: 0.5rem;"><?= t('events.sales_earnings.no_sales_message') ?></p>
</div>
<?php else: ?>
<div class="table-wrapper" style="overflow-x: auto;">
<table class="console-table">
<thead>
<tr>
<th><?= t('events.sales_earnings.date') ?></th>
<th><?= t('events.sales_earnings.ticket_code') ?></th>
<th><?= t('events.sales_earnings.buyer') ?></th>
<th><?= t('events.sales_earnings.amount') ?></th>
<th><?= t('events.sales_earnings.total_fees') ?></th>
<th><?= t('events.sales_earnings.earning') ?></th>
<th><?= t('events.sales_earnings.status') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($all_sales as $sale):
$amount = (float)$sale['amount'];
$fees = calculateEventTicketFees($amount, $user_plan, $is_free_event, false);
$total_fee = $fees['total_fees'];
$creator_earning = $fees['organizer_receives'];
$purchase_date = $sale['purchase_date'] ?? $sale['created_at'];
$status = $sale['ticket_status'] ?? 'confirmed';
?>
<tr>
<td><?= date('M j, Y g:i A', strtotime($purchase_date)) ?></td>
<td>
<span style="font-family: 'Courier New', monospace; font-size: 0.9rem; color: #667eea; font-weight: 600;">
<?= htmlspecialchars($sale['ticket_code']) ?>
</span>
</td>
<td>
<?php if ($sale['buyer_name']): ?>
<?= htmlspecialchars($sale['buyer_name']) ?>
<?php else: ?>
<span style="color: #a0aec0;"><?= t('events.sales_earnings.anonymous') ?></span>
<?php endif; ?>
</td>
<td style="font-weight: 600; color: #fff;">$<?= number_format($amount, 2) ?></td>
<td style="color: #fc8181;">-$<?= number_format($total_fee, 2) ?></td>
<td style="color: #68d391; font-weight: 600;">$<?= number_format($creator_earning, 2) ?></td>
<td>
<span class="status-chip <?= htmlspecialchars($status) ?>">
<?= ucfirst($status) ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
</div>
</div>
</div>
</div>
<script data-event-modal-script="1">
// Close modal function
function closeSalesEarningsModal() {
const overlay = document.getElementById('salesEarningsModalOverlay');
if (overlay) {
overlay.style.display = 'none';
overlay.remove();
document.body.style.overflow = '';
}
}
// Make function available globally
window.closeSalesEarningsModal = closeSalesEarningsModal;
// Setup modal event handlers (runs after modal is inserted)
setTimeout(function() {
const overlay = document.getElementById('salesEarningsModalOverlay');
const container = overlay ? overlay.querySelector('.event-modal-container') : null;
const closeBtn = overlay ? overlay.querySelector('.sales-earnings-modal-close') : null;
if (overlay) {
// Close button handler
if (closeBtn) {
closeBtn.onclick = function(e) {
e.preventDefault();
e.stopPropagation();
closeSalesEarningsModal();
};
}
// Close on overlay click
overlay.onclick = function(e) {
if (e.target === overlay) {
closeSalesEarningsModal();
}
};
// Prevent container clicks from closing
if (container) {
container.onclick = function(e) {
e.stopPropagation();
};
}
}
}, 100);
// Close on Escape key (only for this modal)
const escapeHandler = function(e) {
if (e.key === 'Escape') {
const overlay = document.getElementById('salesEarningsModalOverlay');
if (overlay && overlay.style.display !== 'none') {
closeSalesEarningsModal();
document.removeEventListener('keydown', escapeHandler);
}
}
};
document.addEventListener('keydown', escapeHandler);
</script>
<style>
.event-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(10px);
display: flex;
align-items: center;
justify-content: center;
z-index: 99999;
padding: 1rem;
}
.event-modal-container {
position: relative;
background: transparent;
border-radius: 0;
max-width: 1200px;
width: 95%;
max-height: 90vh;
overflow-y: auto;
}
.event-modal-content {
position: relative;
}
.sales-earnings-modal-close {
position: absolute;
top: 1.5rem;
right: 1.5rem;
width: 50px;
height: 50px;
background: rgba(239, 68, 68, 0.9);
border: 2px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
color: white;
font-size: 1.5rem;
cursor: pointer;
z-index: 10001;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(239, 68, 68, 0.4);
pointer-events: auto;
-webkit-tap-highlight-color: transparent;
}
.sales-earnings-modal-close:hover {
background: rgba(220, 38, 38, 1);
transform: scale(1.1);
box-shadow: 0 6px 20px rgba(239, 68, 68, 0.6);
}
.sales-earnings-modal-close:active {
transform: scale(0.95);
}
.console-hero {
background: linear-gradient(135deg, rgba(102, 126, 234, 0.15), rgba(118, 75, 162, 0.15));
border: 1px solid rgba(102, 126, 234, 0.35);
border-radius: 24px;
padding: 2.5rem;
margin-bottom: 2rem;
color: #f7fafc;
box-shadow: 0 20px 45px rgba(15, 23, 42, 0.35);
}
.console-hero h1 {
margin: 0 0 0.5rem;
font-size: 2.2rem;
color: #fff;
}
.console-hero p {
margin: 0;
color: #cbd5f5;
}
.console-metrics {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.metric-card {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16px;
padding: 1.3rem;
}
.metric-card h4 {
margin: 0;
color: #9ca3af;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.1em;
}
.metric-card strong {
display: block;
margin-top: 0.4rem;
font-size: 1.6rem;
color: #fff;
}
.panel {
background: rgba(15, 23, 42, 0.85);
border: 1px solid rgba(148, 163, 184, 0.2);
border-radius: 20px;
padding: 2rem;
margin-top: 2rem;
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.45);
color: #f8fafc;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
flex-wrap: wrap;
gap: 1rem;
}
.panel-header h2 {
margin: 0;
font-size: 1.4rem;
display: flex;
align-items: center;
gap: 0.6rem;
color: #fff;
}
.panel-header h2 i {
color: #667eea;
}
.console-table {
width: 100%;
border-collapse: collapse;
color: #e2e8f0;
}
.console-table th,
.console-table td {
padding: 0.9rem 0.7rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
text-align: left;
font-size: 0.92rem;
}
.console-table th {
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.75rem;
color: #a0aec0;
}
.status-chip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.2rem 0.8rem;
border-radius: 999px;
font-size: 0.8rem;
border: 1px solid transparent;
}
.status-chip.confirmed {
background: rgba(72, 187, 120, 0.2);
color: #68d391;
border-color: rgba(72, 187, 120, 0.3);
}
.status-chip.used {
background: rgba(236, 201, 75, 0.15);
color: #f6ad55;
border-color: rgba(236, 201, 75, 0.3);
}
.status-chip.pending {
background: rgba(237, 137, 54, 0.15);
color: #fbd38d;
border-color: rgba(237, 137, 54, 0.3);
}
.empty-notice {
text-align: center;
padding: 2rem 1rem;
color: #a0aec0;
}
.empty-notice i {
font-size: 2rem;
margin-bottom: 0.5rem;
color: #718096;
}
.table-wrapper {
overflow-x: auto;
}
@media (max-width: 768px) {
.event-modal-container {
width: 100%;
max-height: 100vh;
}
.event-modal-overlay {
padding: 0;
}
.console-hero {
padding: 1.5rem;
}
.console-hero h1 {
font-size: 1.5rem;
}
.console-metrics {
grid-template-columns: 1fr;
gap: 1rem;
}
.panel {
padding: 1rem;
margin-top: 1.5rem;
}
.panel-header {
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
}
.panel-header h2 {
font-size: 1.2rem;
}
.console-table {
font-size: 0.85rem;
}
.console-table th,
.console-table td {
padding: 0.75rem 0.5rem;
}
}
</style>
<?php
if ($is_ajax) {
// Get the buffered HTML
$html = ob_get_clean();
// Clear any remaining output
if (ob_get_level()) {
ob_clean();
}
// Send JSON response
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['success' => true, 'html' => $html], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
}
?>