332 lines
15 KiB
PHP
332 lines
15 KiB
PHP
<?php
|
|
include('include/headscript.php');
|
|
if (!isset($iduserlogin)) die("Errore: utente non loggato.");
|
|
|
|
$dbHandler = DBHandlerSelect::getInstance();
|
|
$pdo = $dbHandler->getConnection();
|
|
|
|
$stmt = $pdo->prepare("SELECT id, name FROM schools WHERE owner_id = ?");
|
|
$stmt->execute([$iduserlogin]);
|
|
$school = $stmt->fetch();
|
|
if (!$school) die("Scuola non trovata.");
|
|
$school_id = $school['id'];
|
|
|
|
// === FILTRI ===
|
|
$year = $_GET['year'] ?? date('Y');
|
|
$month = $_GET['month'] ?? null;
|
|
$start_date = $month ? "$year-$month-01" : "$year-01-01";
|
|
$end_date = $month ? date('Y-m-t', strtotime($start_date)) : "$year-12-31";
|
|
|
|
$where_date = "AND o.created_at BETWEEN ? AND ?";
|
|
$params = [$school_id, $start_date . ' 00:00:00', $end_date . ' 23:59:59'];
|
|
|
|
// === STATISTICHE FILTRATE ===
|
|
$stmt = $pdo->prepare("
|
|
SELECT
|
|
COUNT(*) as total_orders,
|
|
SUM(price) as total_revenue,
|
|
SUM(CASE WHEN payment_method = 'stripe' THEN price ELSE 0 END) as stripe_revenue,
|
|
SUM(CASE WHEN payment_method = 'paypal' THEN price ELSE 0 END) as paypal_revenue,
|
|
SUM(CASE WHEN payment_method = 'manual' THEN price ELSE 0 END) as manual_revenue
|
|
FROM orders o
|
|
WHERE o.school_id = ? AND o.status = 'completed' $where_date
|
|
");
|
|
$stmt->execute($params);
|
|
$stats = $stmt->fetch();
|
|
|
|
// === RICAVI MENSILI (per grafico) ===
|
|
$monthly = [];
|
|
$start = new DateTime($month ? $start_date : "$year-01-01");
|
|
$end = new DateTime($end_date);
|
|
$interval = new DateInterval('P1M');
|
|
$period = new DatePeriod($start, $interval, $end->modify('+1 month'));
|
|
|
|
foreach ($period as $dt) {
|
|
$m = $dt->format('Y-m');
|
|
$label = $dt->format('M Y');
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT COALESCE(SUM(price), 0) as revenue
|
|
FROM orders
|
|
WHERE school_id = ? AND status = 'completed'
|
|
AND DATE_FORMAT(created_at, '%Y-%m') = ?
|
|
");
|
|
$stmt->execute([$school_id, $m]);
|
|
$monthly[] = ['label' => $label, 'revenue' => (float)$stmt->fetchColumn()];
|
|
}
|
|
|
|
// === DISTRIBUZIONE METODI PAGAMENTO (per torta) ===
|
|
$payment_data = [
|
|
'Stripe' => $stats['stripe_revenue'] ?? 0,
|
|
'PayPal' => $stats['paypal_revenue'] ?? 0,
|
|
'Manuale' => $stats['manual_revenue'] ?? 0
|
|
];
|
|
|
|
// === TOP 5 PRODOTTI ===
|
|
$stmt = $pdo->prepare("
|
|
SELECT p.name, pv.name as variation, COUNT(*) as vendite, SUM(o.price) as incasso
|
|
FROM orders o
|
|
JOIN products p ON o.product_id = p.id
|
|
LEFT JOIN product_variations pv ON o.variation_id = pv.id
|
|
WHERE o.school_id = ? AND o.status = 'completed' $where_date
|
|
GROUP BY o.product_id, o.variation_id
|
|
ORDER BY incasso DESC LIMIT 5
|
|
");
|
|
$stmt->execute($params);
|
|
$top_products = $stmt->fetchAll();
|
|
|
|
// === ULTIMI ORDINI ===
|
|
$stmt = $pdo->prepare("
|
|
SELECT o.*, u.first_name, u.last_name, u.email, p.name as product_name, pv.name as variation_name
|
|
FROM orders o
|
|
JOIN auth_users u ON o.user_id = u.id
|
|
JOIN products p ON o.product_id = p.id
|
|
LEFT JOIN product_variations pv ON o.variation_id = pv.id
|
|
WHERE o.school_id = ? $where_date
|
|
ORDER BY o.created_at DESC
|
|
");
|
|
$stmt->execute($params);
|
|
$recent_orders = $stmt->fetchAll();
|
|
?>
|
|
|
|
<!doctype html>
|
|
<html lang="it">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Finanze - <?php echo htmlspecialchars($school['name']); ?></title>
|
|
<?php include('cssinclude.php'); ?>
|
|
<?php include('siteinfo.php'); ?>
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap5.min.css">
|
|
</head>
|
|
|
|
<body>
|
|
<div class="wrapper">
|
|
<?php include('include/navbar.php'); ?>
|
|
<?php include('include/topbar.php'); ?>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="page-content">
|
|
<div class="container-fluid px-4">
|
|
|
|
<!-- FILTRO -->
|
|
<div class="card radius-15 shadow mb-4">
|
|
<div class="card-body">
|
|
<form method="GET" class="row g-3 align-items-end">
|
|
<div class="col-md-3">
|
|
<label>Anno</label>
|
|
<select name="year" class="form-select" onchange="this.form.submit()">
|
|
<?php for ($y = date('Y'); $y >= date('Y') - 5; $y--): ?>
|
|
<option value="<?php echo $y; ?>" <?php echo $y == $year ? 'selected' : ''; ?>><?php echo $y; ?></option>
|
|
<?php endfor; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label>Mese (opzionale)</label>
|
|
<select name="month" class="form-select" onchange="this.form.submit()">
|
|
<option value="">Tutti i mesi</option>
|
|
<?php for ($m = 1; $m <= 12; $m++):
|
|
$mm = str_pad($m, 2, '0', STR_PAD_LEFT);
|
|
$name = date('F', mktime(0, 0, 0, $m, 1));
|
|
?>
|
|
<option value="<?php echo $mm; ?>" <?php echo $mm == $month ? 'selected' : ''; ?>>
|
|
<?php echo ucfirst($name); ?>
|
|
</option>
|
|
<?php endfor; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button type="button" class="btn btn-outline-secondary" onclick="window.location='finances.php'">Reset</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TOTALE FILTRATO -->
|
|
<div class="text-center mb-5">
|
|
<h2 class="text-primary">Finanze <?php echo $month ? date('F Y', strtotime("$year-$month-01")) : "Anno $year"; ?></h2>
|
|
<h1 class="display-3 fw-bold text-success">
|
|
€<?php echo number_format($stats['total_revenue'] ?? 0, 2); ?>
|
|
</h1>
|
|
</div>
|
|
|
|
<div class="row g-4 mb-5">
|
|
<div class="col-lg-4">
|
|
<div class="card h-100 shadow-sm border-0">
|
|
<div class="card-body text-center">
|
|
<h5 class="text-primary">Ordini</h5>
|
|
<h3 class="fw-bold"><?php echo $stats['total_orders'] ?? 0; ?></h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-8">
|
|
<div class="card h-100 shadow-sm border-0">
|
|
<div class="card-header bg-primary text-white">
|
|
<h5 class="mb-0">Distribuzione Pagamenti</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="paymentChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-8">
|
|
<div class="card shadow">
|
|
<div class="card-header bg-primary text-white">
|
|
<h5 class="mb-0">Andamento Ricavi</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="revenueChart" height="120"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<div class="card shadow h-100">
|
|
<div class="card-header bg-success text-white">
|
|
<h5 class="mb-0">Top 5 Prodotti</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<table class="table table-sm">
|
|
<tbody>
|
|
<?php foreach ($top_products as $tp): ?>
|
|
<tr>
|
|
<td>
|
|
<strong><?php echo htmlspecialchars($tp['name']); ?></strong>
|
|
<?php if ($tp['variation']): ?><br><small><?php echo htmlspecialchars($tp['variation']); ?></small><?php endif; ?>
|
|
</td>
|
|
<td class="text-end text-success fw-bold">
|
|
€<?php echo number_format($tp['incasso'], 2); ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php if (empty($top_products)): ?>
|
|
<tr>
|
|
<td class="text-center text-muted">Nessun dato</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- TABELLA ORDINI -->
|
|
<div class="card shadow mt-5">
|
|
<div class="card-header bg-dark text-white">
|
|
<h5 class="mb-0">Tutti gli ordini del periodo</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<table id="ordersTable" class="table table-striped table-hover mb-0">
|
|
<thead class="table-dark">
|
|
<tr>
|
|
<th>Data</th>
|
|
<th>Ordine</th>
|
|
<th>Cliente</th>
|
|
<th>Prodotto</th>
|
|
<th class="text-end">Importo</th>
|
|
<th>Metodo</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($recent_orders as $o): ?>
|
|
<tr>
|
|
<td><?php echo date('d/m/Y H:i', strtotime($o['created_at'])); ?></td>
|
|
<td>#<?php echo $o['order_number']; ?></td>
|
|
<td><?php echo htmlspecialchars($o['first_name'] . ' ' . $o['last_name']); ?></td>
|
|
<td><?php echo htmlspecialchars($o['product_name'] . ($o['variation_name'] ? ' - ' . $o['variation_name'] : '')); ?></td>
|
|
<td class="text-end text-success fw-bold">€<?php echo number_format($o['price'], 2); ?></td>
|
|
<td>
|
|
<span class="badge bg-<?php echo $o['payment_method'] == 'stripe' ? 'primary' : ($o['payment_method'] == 'paypal' ? 'info' : 'secondary'); ?>">
|
|
<?php echo strtoupper($o['payment_method']); ?>
|
|
</span>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include('include/footer.php'); ?>
|
|
</div>
|
|
|
|
<?php include('jsinclude.php'); ?>
|
|
|
|
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
|
|
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap5.min.js"></script>
|
|
|
|
<script>
|
|
// Grafico a barre ricavi
|
|
new Chart(document.getElementById('revenueChart'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: [<?php echo "'" . implode("','", array_column($monthly, 'label')) . "'"; ?>],
|
|
datasets: [{
|
|
label: 'Ricavi',
|
|
data: [<?php echo implode(',', array_column($monthly, 'revenue')); ?>],
|
|
backgroundColor: 'rgba(0, 123, 255, 0.7)',
|
|
borderRadius: 6
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: {
|
|
display: false
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
ticks: {
|
|
callback: v => '€' + v
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Grafico a torta pagamenti
|
|
new Chart(document.getElementById('paymentChart'), {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Stripe', 'PayPal', 'Manuale'],
|
|
datasets: [{
|
|
data: [<?php echo ($stats['stripe_revenue'] ?? 0) . ',' . ($stats['paypal_revenue'] ?? 0) . ',' . ($stats['manual_revenue'] ?? 0); ?>],
|
|
backgroundColor: ['#0d6efd', '#0dcaf0', '#ffc107']
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom'
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// DataTable
|
|
$('#ordersTable').DataTable({
|
|
language: {
|
|
url: "//cdn.datatables.net/plug-ins/1.10.25/i18n/Italian.json"
|
|
},
|
|
pageLength: 25,
|
|
order: [
|
|
[0, 'desc']
|
|
],
|
|
responsive: true
|
|
});
|
|
</script>
|
|
</body>
|
|
|
|
</html>
|