<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManagerInterface;
use App\Repository\ProduitRepository;
use App\Repository\VenteRepository;
use App\Repository\DepenseRepository;
class DashboardController extends AbstractController
{
/**
* @Route("/", name="app_dashboard")
*/
public function index(
VenteRepository $venteRepo,
ProduitRepository $produitRepo,
DepenseRepository $depenseRepo
): Response {
// --- KPIs VENTES / STOCK ---
$kpis = [
'ventesJour' => $venteRepo->sumToday(),
'ventesMois' => $venteRepo->sumThisMonth(),
'margeJour' => $venteRepo->margeToday(),
'produitsCritiques' => $produitRepo->countCritiques(),
'valeurStock' => $produitRepo->valeurStock(),
];
// Rotation sur 30 jours
$fromRot = new \DateTime('-30 days');
$toRot = new \DateTime();
$qtySold30 = $venteRepo->sumQuantitiesSoldBetween($fromRot, $toRot);
$stockFinal = $produitRepo->sumStock();
$stockMoyenApprox = $stockFinal + ($qtySold30 / 2.0);
$rotation = ($stockMoyenApprox > 0) ? $qtySold30 / $stockMoyenApprox : 0;
$kpis['rotationStock30j'] = $rotation;
// --- KPIs DÉPENSES ---
$kpis['depensesJour'] = $depenseRepo->sumToday();
$kpis['depensesMois'] = $depenseRepo->sumThisMonth();
// Résultats (très simple : ventes - dépenses)
$kpis['resultatJour'] = $kpis['ventesJour'] - $kpis['depensesJour'];
$kpis['resultatMois'] = $kpis['ventesMois'] - $kpis['depensesMois'];
// --- Graphiques ventes ---
$graphDailySales = $venteRepo->dailySalesLast30Days();
$graphDailyMargins = $venteRepo->dailyMarginsLast30Days();
$monthlySales = $venteRepo->monthlySalesLast12Months();
$forecastMonthly = $this->forecastNextMonths($monthlySales, 3);
// --- Graphiques dépenses ---
$graphDailyExpenses = $depenseRepo->dailyExpensesLast30Days();
$monthlyExpenses = $depenseRepo->monthlyExpensesLast12Months();
$expenseByType = $depenseRepo->sumByType(null, null);
// --- Combinaison ventes / dépenses mensuelles ---
$combinedMonthly = $this->mergeMonthlySalesAndExpenses($monthlySales, $monthlyExpenses);
// --- Tops produits ---
$topQty = $venteRepo->topProductsByQuantity(10);
$topMargin = $venteRepo->topProductsByMargin(10);
// --- Performance par catégorie (30 jours) ---
$perfCategories = $venteRepo->performanceByCategory($fromRot, $toRot);
return $this->render('dashboard/index.html.twig', [
'kpis' => $kpis,
'graphDailySales' => $graphDailySales,
'graphDailyMargins'=> $graphDailyMargins,
'graphDailyExpenses' => $graphDailyExpenses,
'monthlySales' => $monthlySales,
'monthlyExpenses' => $monthlyExpenses,
'combinedMonthly' => $combinedMonthly,
'forecastMonthly' => $forecastMonthly,
'topQty' => $topQty,
'topMargin' => $topMargin,
'perfCategories' => $perfCategories,
'expenseByType' => $expenseByType,
]);
}
/**
* Prévision simple : moyenne des 3 derniers mois pour les N prochains.
*
* @param array $monthlySales tableau issu de monthlySalesLast12Months()
* @param int $nb nombre de mois à prévoir
*/
private function forecastNextMonths(array $monthlySales, int $nb): array
{
if (empty($monthlySales)) {
return [];
}
// On prend les 3 derniers mois (ou moins si pas assez)
$last = array_slice($monthlySales, -3);
$sum = 0;
$count = 0;
foreach ($last as $row) {
if (isset($row['total'])) {
$sum += (float) $row['total'];
$count++;
}
}
if ($count === 0) {
return [];
}
$avg = $sum / $count;
// Dernier mois connu
$lastMoisRow = end($monthlySales);
$lastKey = isset($lastMoisRow['mois']) ? $lastMoisRow['mois'] : null;
if ($lastKey instanceof \DateTimeInterface) {
$dt = clone $lastKey;
} elseif (is_string($lastKey)) {
$parsed = \DateTime::createFromFormat('Y-m', $lastKey);
$dt = $parsed ?: new \DateTime();
} else {
$dt = new \DateTime();
}
$forecasts = [];
for ($i = 1; $i <= $nb; $i++) {
$future = (clone $dt)->modify('+' . $i . ' month');
$forecasts[] = [
'mois' => $future->format('Y-m'),
'total' => $avg,
];
}
return $forecasts;
}
/**
* Fusionne les séries mensuelles ventes / dépenses sur une même base "YYYY-MM"
*/
private function mergeMonthlySalesAndExpenses(array $sales, array $expenses): array
{
$map = [];
// Ventes
foreach ($sales as $row) {
$rawMonth = isset($row['mois']) ? $row['mois'] : null;
if ($rawMonth instanceof \DateTimeInterface) {
$key = $rawMonth->format('Y-m');
} else {
$key = (string) $rawMonth;
}
if (!isset($map[$key])) {
$map[$key] = ['mois' => $key, 'ventes' => 0.0, 'depenses' => 0.0];
}
$map[$key]['ventes'] = isset($row['total']) ? (float) $row['total'] : 0.0;
}
// Dépenses
foreach ($expenses as $row) {
$rawMonth = isset($row['mois']) ? $row['mois'] : null;
if ($rawMonth instanceof \DateTimeInterface) {
$key = $rawMonth->format('Y-m');
} else {
$key = (string) $rawMonth;
}
if (!isset($map[$key])) {
$map[$key] = ['mois' => $key, 'ventes' => 0.0, 'depenses' => 0.0];
}
$map[$key]['depenses'] = isset($row['total']) ? (float) $row['total'] : 0.0;
}
ksort($map);
return array_values($map);
}
}