src/Controller/DashboardController.php line 17

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\HttpFoundation\Response;
  5. use Symfony\Component\Routing\Annotation\Route;
  6. use Doctrine\ORM\EntityManagerInterface;
  7. use App\Repository\ProduitRepository;
  8. use App\Repository\VenteRepository;
  9. use App\Repository\DepenseRepository;
  10. class DashboardController extends AbstractController
  11. {
  12.     /**
  13.      * @Route("/", name="app_dashboard")
  14.      */
  15.     public function index(
  16.         VenteRepository $venteRepo,
  17.         ProduitRepository $produitRepo,
  18.         DepenseRepository $depenseRepo
  19.     ): Response {
  20.         // --- KPIs VENTES / STOCK ---
  21.         $kpis = [
  22.             'ventesJour'        => $venteRepo->sumToday(),
  23.             'ventesMois'        => $venteRepo->sumThisMonth(),
  24.             'margeJour'         => $venteRepo->margeToday(),
  25.             'produitsCritiques' => $produitRepo->countCritiques(),
  26.             'valeurStock'       => $produitRepo->valeurStock(),
  27.         ];
  28.         // Rotation sur 30 jours
  29.         $fromRot = new \DateTime('-30 days');
  30.         $toRot   = new \DateTime();
  31.         $qtySold30 $venteRepo->sumQuantitiesSoldBetween($fromRot$toRot);
  32.         $stockFinal $produitRepo->sumStock();
  33.         $stockMoyenApprox $stockFinal + ($qtySold30 2.0);
  34.         $rotation = ($stockMoyenApprox 0) ? $qtySold30 $stockMoyenApprox 0;
  35.         $kpis['rotationStock30j'] = $rotation;
  36.         // --- KPIs DÉPENSES ---
  37.         $kpis['depensesJour'] = $depenseRepo->sumToday();
  38.         $kpis['depensesMois'] = $depenseRepo->sumThisMonth();
  39.         // Résultats (très simple : ventes - dépenses)
  40.         $kpis['resultatJour'] = $kpis['ventesJour'] - $kpis['depensesJour'];
  41.         $kpis['resultatMois'] = $kpis['ventesMois'] - $kpis['depensesMois'];
  42.         // --- Graphiques ventes ---
  43.         $graphDailySales    $venteRepo->dailySalesLast30Days();
  44.         $graphDailyMargins  $venteRepo->dailyMarginsLast30Days();
  45.         $monthlySales       $venteRepo->monthlySalesLast12Months();
  46.         $forecastMonthly    $this->forecastNextMonths($monthlySales3);
  47.         // --- Graphiques dépenses ---
  48.         $graphDailyExpenses $depenseRepo->dailyExpensesLast30Days();
  49.         $monthlyExpenses    $depenseRepo->monthlyExpensesLast12Months();
  50.         $expenseByType      $depenseRepo->sumByType(nullnull);
  51.         // --- Combinaison ventes / dépenses mensuelles ---
  52.         $combinedMonthly $this->mergeMonthlySalesAndExpenses($monthlySales$monthlyExpenses);
  53.         // --- Tops produits ---
  54.         $topQty    $venteRepo->topProductsByQuantity(10);
  55.         $topMargin $venteRepo->topProductsByMargin(10);
  56.         // --- Performance par catégorie (30 jours) ---
  57.         $perfCategories $venteRepo->performanceByCategory($fromRot$toRot);
  58.         return $this->render('dashboard/index.html.twig', [
  59.             'kpis'             => $kpis,
  60.             'graphDailySales'  => $graphDailySales,
  61.             'graphDailyMargins'=> $graphDailyMargins,
  62.             'graphDailyExpenses' => $graphDailyExpenses,
  63.             'monthlySales'     => $monthlySales,
  64.             'monthlyExpenses'  => $monthlyExpenses,
  65.             'combinedMonthly'  => $combinedMonthly,
  66.             'forecastMonthly'  => $forecastMonthly,
  67.             'topQty'           => $topQty,
  68.             'topMargin'        => $topMargin,
  69.             'perfCategories'   => $perfCategories,
  70.             'expenseByType'    => $expenseByType,
  71.         ]);
  72.     }
  73.     /**
  74.      * Prévision simple : moyenne des 3 derniers mois pour les N prochains.
  75.      *
  76.      * @param array $monthlySales  tableau issu de monthlySalesLast12Months()
  77.      * @param int   $nb            nombre de mois à prévoir
  78.      */
  79.     private function forecastNextMonths(array $monthlySalesint $nb): array
  80.     {
  81.         if (empty($monthlySales)) {
  82.             return [];
  83.         }
  84.         // On prend les 3 derniers mois (ou moins si pas assez)
  85.         $last array_slice($monthlySales, -3);
  86.         $sum 0;
  87.         $count 0;
  88.         foreach ($last as $row) {
  89.             if (isset($row['total'])) {
  90.                 $sum += (float) $row['total'];
  91.                 $count++;
  92.             }
  93.         }
  94.         if ($count === 0) {
  95.             return [];
  96.         }
  97.         $avg $sum $count;
  98.         // Dernier mois connu
  99.         $lastMoisRow end($monthlySales);
  100.         $lastKey = isset($lastMoisRow['mois']) ? $lastMoisRow['mois'] : null;
  101.         if ($lastKey instanceof \DateTimeInterface) {
  102.             $dt = clone $lastKey;
  103.         } elseif (is_string($lastKey)) {
  104.             $parsed = \DateTime::createFromFormat('Y-m'$lastKey);
  105.             $dt $parsed ?: new \DateTime();
  106.         } else {
  107.             $dt = new \DateTime();
  108.         }
  109.         $forecasts = [];
  110.         for ($i 1$i <= $nb$i++) {
  111.             $future = (clone $dt)->modify('+' $i ' month');
  112.             $forecasts[] = [
  113.                 'mois'  => $future->format('Y-m'),
  114.                 'total' => $avg,
  115.             ];
  116.         }
  117.         return $forecasts;
  118.     }
  119.     /**
  120.      * Fusionne les séries mensuelles ventes / dépenses sur une même base "YYYY-MM"
  121.      */
  122.     private function mergeMonthlySalesAndExpenses(array $sales, array $expenses): array
  123.     {
  124.         $map = [];
  125.         // Ventes
  126.         foreach ($sales as $row) {
  127.             $rawMonth = isset($row['mois']) ? $row['mois'] : null;
  128.             if ($rawMonth instanceof \DateTimeInterface) {
  129.                 $key $rawMonth->format('Y-m');
  130.             } else {
  131.                 $key = (string) $rawMonth;
  132.             }
  133.             if (!isset($map[$key])) {
  134.                 $map[$key] = ['mois' => $key'ventes' => 0.0'depenses' => 0.0];
  135.             }
  136.             $map[$key]['ventes'] = isset($row['total']) ? (float) $row['total'] : 0.0;
  137.         }
  138.         // Dépenses
  139.         foreach ($expenses as $row) {
  140.             $rawMonth = isset($row['mois']) ? $row['mois'] : null;
  141.             if ($rawMonth instanceof \DateTimeInterface) {
  142.                 $key $rawMonth->format('Y-m');
  143.             } else {
  144.                 $key = (string) $rawMonth;
  145.             }
  146.             if (!isset($map[$key])) {
  147.                 $map[$key] = ['mois' => $key'ventes' => 0.0'depenses' => 0.0];
  148.             }
  149.             $map[$key]['depenses'] = isset($row['total']) ? (float) $row['total'] : 0.0;
  150.         }
  151.         ksort($map);
  152.         return array_values($map);
  153.     }
  154. }