src/Controller/HomeController.php line 19

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Repository\CarRepository;
  4. use Doctrine\Persistence\ManagerRegistry;
  5. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\Routing\Annotation\Route;
  8. use App\Repository\CarSaleRepository;
  9. use Symfony\Component\HttpFoundation\JsonResponse;
  10. use Symfony\Component\HttpFoundation\Request;
  11. class HomeController extends AbstractController
  12. {
  13.     /**
  14.      * @Route("/", name="homepage")
  15.      */
  16.     public function index(ManagerRegistry $doctrineCarSaleRepository $carSaleRepositoryCarRepository $carRepository): Response
  17.     {
  18.         //dump( $this->getStatistics($doctrine, 7) ) ; exit();
  19.         /*
  20.         $currentDate = new \DateTime();
  21.         $query = "
  22.             SELECT c.name, c.status, cs.car_sale_id, cs.is_done_date, cs.signaled_date, cs.price, cs.currency, cs.is_done
  23.             FROM car_sale cs
  24.             LEFT JOIN car c ON c.id = cs.car_sale_id
  25.             WHERE c.status IN ('sold', 'signaled')
  26.                 AND MONTH(is_done_date) = MONTH(:date) 
  27.                 AND YEAR(is_done_date) = YEAR(:date)
  28.         ";
  29.         $conn = $doctrine->getConnection();
  30.         $params = [ 'date' => $currentDate->format('Y:m:d') ];
  31.         $result = $conn->executeQuery($query, $params);
  32.         $dataCurrentMonth  = $result->fetchAll();
  33.         $aStatisticsCurrentMonth = [
  34.             'delivered' => 0,
  35.             'signaled' => 0,
  36.             'deliveredPrice' => 0,
  37.             'signaledPrice' => 0
  38.         ];
  39.         foreach ($dataCurrentMonth as $item) {
  40.             $isDone = $item['is_done'];
  41.             $currency = $item['currency'];
  42.             $price  = $item['price'];
  43.             $signaledDate = new \DateTime($item['signaled_date']);
  44.             if ($isDone) {
  45.                 $aStatisticsCurrentMonth['delivered'] ++;
  46.                 $aStatisticsCurrentMonth['deliveredPrice'] = $aStatisticsCurrentMonth['deliveredPrice'] + $price;
  47.                 //$nDelivered ++;
  48.                 //$nDeliveredPrice = $nDeliveredPrice + $price;
  49.             }
  50.             if (!$isDone && $signaledDate != null && $signaledDate->format('Y-m') === $currentDate->format('Y-m')) {
  51.                 $aStatisticsCurrentMonth['signaled'] ++;
  52.                 $aStatisticsCurrentMonth['signaledPrice'] = $aStatisticsCurrentMonth['signaledPrice'] + $price;
  53.                 //$nSignaled ++;
  54.                 //$nSignaledPrice = $nSignaledPrice + $price;
  55.             }
  56.         }
  57.         *
  58.         dump($aStatisticsCurrentMonth);
  59.         exit();
  60.         $data = $carSaleRepository->createQueryBuilder('cs')
  61.             ->leftJoin('cs.carSale', 'c')
  62.             ->leftJoin('cs.carPayment', 'cscp')
  63.             ->leftJoin('cs.bankCheckId', 'csb')
  64.             ->leftJoin('cscp.car', 'cp')
  65.             ->leftJoin('cs.user', 'u')
  66.             ->leftJoin('cs.client', 'cl')
  67.             ->addSelect('c')
  68.             ->addSelect('cscp')
  69.             ->addSelect('csb')
  70.             ->addSelect('cp')
  71.             ->addSelect('u')
  72.             ->addSelect('cl')
  73.             ->where('cs.id > :id')
  74.             ->setParameter('id', '0');
  75.         $data = $data->leftJoin('App:Agency', 'ag', 'WITH', 'cs.id = ag.saleId')
  76.             ->addSelect('ag.enabledNotification, ag.status');
  77.         $dataCurrent = clone $data->having('MONTH(cs.isDoneDate) = MONTH(CURRENT_DATE())')
  78.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(CURRENT_DATE())')
  79.             ->orHaving('cs.isDone = 0');
  80.         /*$monthPrev = new \DateTime();
  81.         $monthPrev->modify('-1 month');
  82.         $monthPrev = $monthPrev->format('Y-m-d');
  83.         exit($monthPrev);
  84.         * /
  85.         $monthPrev = (new \DateTime('first day of this month'))->modify('-1 months')->setTime(0, 0);
  86.         $dataPrev1 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  87.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  88.             ->orHaving('cs.isDone = 0')
  89.             ->setParameter('monthPrev', $monthPrev);
  90.         $monthPrev = (new \DateTime('first day of this month'))->modify('-2 months')->setTime(0, 0);
  91.         $dataPrev2 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  92.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  93.             ->orHaving('cs.isDone = 0')
  94.             ->setParameter('monthPrev', $monthPrev);
  95.         $monthPrev = (new \DateTime('first day of this month'))->modify('-3 months')->setTime(0, 0);
  96.         $dataPrev3 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  97.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  98.             ->orHaving('cs.isDone = 0')
  99.             ->setParameter('monthPrev', $monthPrev);
  100.         $monthPrev = (new \DateTime('first day of this month'))->modify('-4 months')->setTime(0, 0);
  101.         $dataPrev4 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  102.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  103.             ->orHaving('cs.isDone = 0')
  104.             ->setParameter('monthPrev', $monthPrev);
  105.         $monthPrev = (new \DateTime('first day of this month'))->modify('-5 months')->setTime(0, 0);
  106.         $dataPrev5 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  107.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  108.             ->orHaving('cs.isDone = 0')
  109.             ->setParameter('monthPrev', $monthPrev);
  110.         $monthPrev = (new \DateTime('first day of this month'))->modify('-6 months')->setTime(0, 0);
  111.         $dataPrev6 = clone $data->having('MONTH(cs.isDoneDate) = MONTH(:monthPrev)')
  112.             ->andHaving('YEAR(cs.isDoneDate) = YEAR(:monthPrev)')
  113.             ->orHaving('cs.isDone = 0')
  114.             ->setParameter('monthPrev', $monthPrev);
  115.         $total = $dataCurrent->getQuery()
  116.             ->getArrayResult();
  117.         $totalPrev1 = $dataPrev1->getQuery()
  118.             ->getArrayResult();
  119.         $totalPrev2 = $dataPrev2->getQuery()
  120.             ->getArrayResult();
  121.         $totalPrev3 = $dataPrev3->getQuery()
  122.             ->getArrayResult();
  123.         $totalPrev4 = $dataPrev4->getQuery()
  124.             ->getArrayResult();
  125.         $totalPrev5 = $dataPrev5->getQuery()
  126.             ->getArrayResult();
  127.         $totalPrev6 = $dataPrev6->getQuery()
  128.             ->getArrayResult();
  129.         /*dump($total);
  130.         dump($totalPrev);
  131.         exit();* /
  132.         $currentDate = new \DateTime();
  133.         $nDelivered = 0;
  134.         $nSignaled  = 0;
  135.         $nDeliveredPrice = 0;
  136.         $nSignaledPrice  = 0;
  137.         foreach ($total as $item) {
  138.             $isDone = $item[0]['isDone'];
  139.             $price  = $item[0]['price'];
  140.             $signaledDate = $item[0]['signaledDate'];
  141.             if ($isDone) {
  142.                 $nDelivered ++;
  143.                 $nDeliveredPrice = $nDeliveredPrice + $price;
  144.             }
  145.             if (!$isDone && $signaledDate != null && $signaledDate->format('Y-m') === $currentDate->format('Y-m')) {
  146.                 //dump($signaledDate, $signaledDate->format('Y-m'));
  147.                 //echo ($item[0]['id']).'<br>';
  148.                 $nSignaled ++;
  149.                 $nSignaledPrice = $nSignaledPrice + $price;
  150.             }
  151.         }
  152.         $totalPrice = $nDeliveredPrice + $nSignaledPrice;
  153.         /*
  154.         $nDeliveredPrev = 0;
  155.         $nSignaledPrev  = 0;
  156.         $nDeliveredPricePrev = 0;
  157.         $nSignaledPricePrev  = 0;
  158.         foreach ($totalPrev as $item) {
  159.             $isDone = $item[0]['isDone'];
  160.             $price  = $item[0]['price'];
  161.             $signaledDate = $item[0]['signaledDate'];
  162.             if ($isDone) {
  163.                 $nDeliveredPrev ++;
  164.                 $nDeliveredPricePrev = $nDeliveredPricePrev + $price;
  165.             }
  166.             if (!$isDone && $signaledDate != null && $signaledDate->format('Y-m') === $currentDate->format('Y-m')) {
  167.                 //echo ($item[0]['id']).'<br>';
  168.                 $nSignaledPrev ++;
  169.                 $nSignaledPricePrev = $nSignaledPricePrev + $price;
  170.             }
  171.         }
  172.         $totalPricePrev = $nDeliveredPricePrev + $nSignaledPricePrev;
  173.         //exit();
  174.         $nDeliveredVar = $this->getVariation($nDelivered,$nDeliveredPrev);
  175.         $nSignaledVar  = $this->getVariation($nSignaled, $nSignaledPrev);
  176.         $nDeliveredPriceVar = $this->getVariation($nDeliveredPrice, $nDeliveredPricePrev);
  177.         $nSignaledPriceVar  = $this->getVariation($nSignaledPrice, $nSignaledPricePrev);
  178.         $totalPriceVar = $this->getVariation($totalPrice, $totalPricePrev);
  179.         * /
  180.         $statisticsPrev1 = $this->getStatistics($totalPrev1, $nDelivered, $nSignaled, $nDeliveredPrice, $nSignaledPrice);
  181.         //dump($statisticsPrev1); exit();
  182.         $statisticsPrev2 = $this->getStatistics($totalPrev2, $statisticsPrev1['nDelivered'], $statisticsPrev1['nSignaled'], $statisticsPrev1['nDeliveredPrice'], $statisticsPrev1['nSignaledPrice']);
  183.         $statisticsPrev3 = $this->getStatistics($totalPrev3, $statisticsPrev2['nDelivered'], $statisticsPrev2['nSignaled'], $statisticsPrev2['nDeliveredPrice'], $statisticsPrev2['nSignaledPrice']);
  184.         $statisticsPrev4 = $this->getStatistics($totalPrev4, $statisticsPrev3['nDelivered'], $statisticsPrev3['nSignaled'], $statisticsPrev3['nDeliveredPrice'], $statisticsPrev3['nSignaledPrice']);
  185.         $statisticsPrev5 = $this->getStatistics($totalPrev5, $statisticsPrev4['nDelivered'], $statisticsPrev4['nSignaled'], $statisticsPrev4['nDeliveredPrice'], $statisticsPrev4['nSignaledPrice']);
  186.         $statisticsPrev6 = $this->getStatistics($totalPrev6, $statisticsPrev5['nDelivered'], $statisticsPrev5['nSignaled'], $statisticsPrev5['nDeliveredPrice'], $statisticsPrev5['nSignaledPrice']);
  187.         dump($statisticsPrev1);
  188.         dump($statisticsPrev2);
  189.         dump($statisticsPrev3);
  190.         dump($statisticsPrev4);
  191.         dump($statisticsPrev5);
  192.         dump($statisticsPrev6); exit(); //*/
  193.         /*---- [BEGIN] ----*/
  194.         $availableVehicles $carRepository->createQueryBuilder('c')
  195.             //->select('COUNT(c.id)') // ← campo a sumar
  196.             ->select('c'// ← campo a sumar
  197.             ->where('c.id > :id')
  198.             ->setParameter('id''0')
  199.             ->andWhere('c.status like :status')
  200.             ->setParameter(':status'"%entered%")
  201.             ->andWhere('c.status != \'sold\'')
  202.             ->getQuery()
  203.             //->getSingleScalarResult();
  204.             ->getArrayResult();
  205.         $availableVehiclesPrice = [];
  206.         foreach ($availableVehicles as $item) {
  207.             $currency $item['priceCurrencySale'];
  208.             $price is_numeric($item['priceSale']) ? (int)$item['priceSale'] : 0;
  209.             if (!empty($price)) {
  210.                 if (isset($availableVehiclesPrice[$currency])) {
  211.                     $availableVehiclesPrice[$currency] = (int)$availableVehiclesPrice[$currency] + $price;
  212.                 } else {
  213.                     $availableVehiclesPrice[$currency] = $price;
  214.                 }
  215.             }
  216.         }
  217.         /*---- [END] ----*/
  218.         return $this->render('home/index.html.twig', [
  219.             'controller_name' => 'HomeController',
  220.             /*'delivered' => $nDelivered,
  221.             'signaled' => $nSignaled,
  222.             'deliveredPrice' => $nDeliveredPrice,
  223.             'signaledPrice' => $nSignaledPrice,
  224.             'totalPrice' => $totalPrice,
  225.             'deliveredPrev' => $nDeliveredPrev,
  226.             'signaledPrev' => $nSignaledPrev,
  227.             'deliveredPricePrev' => $nDeliveredPricePrev,
  228.             'signaledPricePrev' => $nSignaledPricePrev,
  229.             'totalPricePrev' => $totalPricePrev,
  230.             'deliveredVar' => $nDeliveredVar,
  231.             'signaledVar' => $nSignaledVar,
  232.             'deliveredPriceVar' => $nDeliveredPriceVar,
  233.             'signaledPriceVar' => $nSignaledPriceVar,
  234.             'totalPriceVar' => $totalPriceVar,
  235.             */
  236.             'availableVehicles' => count($availableVehicles),
  237.             'availableVehiclesPrice' => $availableVehiclesPrice,
  238.             'currentMenu' => 'homepage',
  239.         ]);
  240.     }
  241.     /**
  242.      * @Route("/getToDeliver", name="get_to_deliver", methods={"GET", "POST"})
  243.      */
  244.     public function getToDeliver(CarSaleRepository $carSaleRepository): jsonResponse
  245.     {
  246.         /*
  247.         $data = $carSaleRepository->createQueryBuilder('cs')
  248.             ->leftJoin('cs.carSale', 'c')
  249.             ->leftJoin('cs.carSaleId', 'c')
  250.             ->addSelect('c')
  251.             ->where('cs.id > :id')
  252.             ->setParameter('id', '0')
  253.             ->andWhere('MONTH(cs.isDoneDate) = MONTH(CURRENT_DATE())')
  254.             ->andWhere('YEAR(cs.isDoneDate) = YEAR(CURRENT_DATE())')
  255.             ->andWhere('cs.isDone = 0')
  256.             ->getQuery()
  257.             ->getArrayResult();
  258.         */
  259.         /*
  260.         $data = $carSaleRepository->createQueryBuilder('cs')
  261.             ->leftJoin('cs.carSale', 'c')
  262.             ->leftJoin('cs.carPayment', 'cscp')
  263.             ->leftJoin('cs.bankCheckId', 'csb')
  264.             ->leftJoin('cscp.car', 'cp')
  265.             ->leftJoin('cs.user', 'u')
  266.             ->leftJoin('cs.client', 'cl')
  267.             ->addSelect('c')
  268.             ->addSelect('cscp')
  269.             ->addSelect('csb')
  270.             ->addSelect('cp')
  271.             ->addSelect('u')
  272.             ->addSelect('cl')
  273.             ->where('cs.id > :id')
  274.             ->setParameter('id', '0');
  275.         */
  276.         $data $carSaleRepository->createQueryBuilder('cs')
  277.             ->leftJoin('cs.carSale''c')
  278.             ->addSelect('c')
  279.             ->where('cs.id > :id')
  280.             ->setParameter('id''0')
  281.             ->andWhere('MONTH(cs.isDoneDate) = MONTH(CURRENT_DATE())')
  282.             ->andWhere('YEAR(cs.isDoneDate) = YEAR(CURRENT_DATE())')
  283.             ->andWhere('cs.isDone = 0')
  284.             ->getQuery()
  285.             ->getArrayResult();
  286.         //dump($data); exit();
  287.         $aColors = ['#FF5733''#33C1FF''#75FF33''#FF33D4'];
  288.         $colorIndex 0;
  289.         $totalColors count($aColors);
  290.         $aRecords = [];
  291.         foreach ($data as $item) {
  292.             $aRecords[] = [
  293.                 'title' => $item['carSale']['patent'],
  294.                 'start' => $item['isDoneDate']->format('Y-m-d'),
  295.                 'color' => $aColors[$colorIndex],
  296.                 'description' => $item['carSale']['name']
  297.             ];
  298.             $colorIndex = ($colorIndex 1) % $totalColors;
  299.         }
  300.         //dump($aRecords); exit();
  301.         /*$data = [
  302.             [
  303.                 'title' => 'Etiqueta A1',
  304.                 'start' => '2025-05-05',
  305.                 'color' => '#28a745' // verde
  306.             ]
  307.         ];*/
  308.         return new JsonResponse($aRecordsJsonResponse::HTTP_OK);
  309.     }
  310.     public function getVariation($current$prev)
  311.     {
  312.         if ($prev == 0) {
  313.             return $current == INF// o "N/A"
  314.         }
  315.         $variation = (($current $prev) / $prev) * 100;
  316.         return round($variation2);
  317.     }
  318.     public function convertMonth($month)
  319.     {
  320.         $monthLabels = [
  321.             '01' => 'Enero',
  322.             '02' => 'Febrero',
  323.             '03' => 'Marzo',
  324.             '04' => 'Abril',
  325.             '05' => 'Mayo',
  326.             '06' => 'Junio',
  327.             '07' => 'Julio',
  328.             '08' => 'Agosto',
  329.             '09' => 'Septiembre',
  330.             '10' => 'Octubre',
  331.             '11' => 'Noviembre',
  332.             '12' => 'Diciembre',
  333.         ];
  334.         return $monthLabels[$month];
  335.     }
  336.     public function getStatisticsOld($totalPrev$nDelivered$nSignaled$nDeliveredPrice$nSignaledPrice)
  337.     {
  338.         $currentDate = new \DateTime();
  339.         $nDeliveredPrev 0;
  340.         $nSignaledPrev  0;
  341.         $nDeliveredPricePrev 0;
  342.         $nSignaledPricePrev  0;
  343.         foreach ($totalPrev as $item) {
  344.             $isDone $item[0]['isDone'];
  345.             $price  $item[0]['price'];
  346.             $signaledDate $item[0]['signaledDate'];
  347.             if ($isDone) {
  348.                 $nDeliveredPrev ++;
  349.                 $nDeliveredPricePrev $nDeliveredPricePrev $price;
  350.             }
  351.             if (!$isDone && $signaledDate != null && $signaledDate->format('Y-m') === $currentDate->format('Y-m')) {
  352.                 //echo ($item[0]['id']).'<br>';
  353.                 $nSignaledPrev ++;
  354.                 $nSignaledPricePrev $nSignaledPricePrev $price;
  355.             }
  356.         }
  357.         return [
  358.             'nDelivered' => $nDeliveredPrev,
  359.             'nSignaled'  => $nSignaledPrev,
  360.             'nDeliveredPrice' => $nDeliveredPricePrev,
  361.             'nSignaledPrice'  => $nSignaledPricePrev,
  362.             'nDeliveredVar' => $this->getVariation($nDelivered,$nDeliveredPrev),
  363.             'nSignaledVar'  => $this->getVariation($nSignaled$nSignaledPrev),
  364.             'nDeliveredPriceVar' => $this->getVariation($nDeliveredPrice$nDeliveredPricePrev),
  365.             'nSignaledPriceVar'  => $this->getVariation($nSignaledPrice$nSignaledPricePrev),
  366.             'totalPriceVar' => $this->getVariation($nDeliveredPrice $nSignaledPrice$nDeliveredPricePrev $nSignaledPricePrev)
  367.         ];
  368.     }
  369.     /*
  370.      * Si no se específica $numberMonths toma por defecto el valor "1" (mes actual)
  371.      * Si el valor de $numberMonths es mayor a 1 se busca el mes actual y los meses anteriores especificados
  372.      */
  373.     public function getSalesStatistics($doctrine$numberMonths 1)
  374.     {
  375.         $numberMonths $numberMonths 1;
  376.         $currentDate = (new \DateTime('last day of this month'))->setTime(00);
  377.         $prevDate = (new \DateTime('first day of this month'))->modify('-'.$numberMonths.' months')->setTime(00);
  378.         $query "
  379.             SELECT c.name, c.status, cs.car_sale_id, cs.is_done_date, cs.signaled_date, cs.price, cs.currency, cs.is_done 
  380.             FROM car_sale cs
  381.             LEFT JOIN car c ON c.id = cs.car_sale_id
  382.             WHERE c.status IN ('sold', 'signaled')
  383.                 AND is_done_date >= :prevDate AND is_done_date <= :currentDate                    
  384.         "//exit($query);
  385.         $conn $doctrine->getConnection();
  386.         $params = [ 'currentDate' => $currentDate->format('Y-m-d'), 'prevDate' => $prevDate->format('Y-m-d') ];
  387.         $result $conn->executeQuery($query$params);
  388.         $dataCurrentMonth  $result->fetchAll();
  389.         $aStatisticsByMonth = [];
  390.         $aStatisticsRef = [
  391.             'delivered' => 0,
  392.             'signaled' => 0,
  393.             'deliveredPrice' => [],
  394.             'signaledPrice' => []
  395.         ];
  396.         foreach ($dataCurrentMonth as $item) {
  397.             $month = (new \DateTime($item['is_done_date']))->format('Y-m');
  398.             $isDone $item['is_done'];
  399.             $currency $item['currency'];
  400.             $price is_numeric($item['price']) ? (int)$item['price'] : 0;
  401.             $signaledDate = new \DateTime($item['signaled_date']);
  402.             if (!array_key_exists($month$aStatisticsByMonth)) {
  403.                 $aStatisticsByMonth[$month] = $aStatisticsRef;
  404.             }
  405.             if ($isDone) {
  406.                 $aStatisticsByMonth[$month]['delivered'] ++;
  407.                 if (!empty($price)) {
  408.                     if (isset($aStatisticsByMonth[$month]['deliveredPrice'][$currency])) {
  409.                         $aStatisticsByMonth[$month]['deliveredPrice'][$currency] = (int) $aStatisticsByMonth[$month]['deliveredPrice'][$currency] + $price;
  410.                     } else {
  411.                         $aStatisticsByMonth[$month]['deliveredPrice'][$currency] = $price;
  412.                     }
  413.                 }
  414.             }
  415.             if (!$isDone && $signaledDate != null && $signaledDate->format('Y-m') === $currentDate->format('Y-m')) {
  416.                 $aStatisticsByMonth[$month]['signaled'] ++;
  417.                 if (!empty($price)) {
  418.                     if (isset($aStatisticsByMonth[$month]['signaledPrice'][$currency])) {
  419.                         $aStatisticsByMonth[$month]['signaledPrice'][$currency] = (int) $aStatisticsByMonth[$month]['signaledPrice'][$currency] + $price;
  420.                     } else {
  421.                         $aStatisticsByMonth[$month]['signaledPrice'][$currency] = $price;
  422.                     }
  423.                 }
  424.             }
  425.         }
  426.         $this->formatPriceFields($aStatisticsByMonth, ['deliveredPrice''signaledPrice']);
  427.         ksort($aStatisticsByMonth);
  428.         $this->addDeliveredChange($aStatisticsByMonth);
  429.         krsort($aStatisticsByMonth);
  430.         return $aStatisticsByMonth;
  431.     }
  432.     function formatPriceFields(array &$data, array $priceFieldsint $decimals 0string $decPoint ','string $thousandsSep '.') {
  433.         foreach ($data as &$item) {
  434.             $totals = [];
  435.             foreach ($priceFields as $field) {
  436.                 if (isset($item[$field]) && is_array($item[$field])) {
  437.                     foreach ($item[$field] as $currency => $amount) {
  438.                         if (is_numeric($amount)) {
  439.                             if (!isset($totals[$currency])) {
  440.                                 $totals[$currency] = 0;
  441.                             }
  442.                             $totals[$currency] += $amount;
  443.                             $item[$field][$currency] = number_format($amount$decimals$decPoint$thousandsSep);
  444.                         }
  445.                     }
  446.                 }
  447.             }
  448.             // Formatear y asignar totalPrice
  449.             foreach ($totals as $currency => $sum) {
  450.                 $totals[$currency] = number_format($sum$decimals$decPoint$thousandsSep);
  451.             }
  452.             $item['totalPrice'] = $totals;
  453.         }
  454.         unset($item); // importante para evitar referencias colgantes
  455.     }
  456.     function addDeliveredChange(array &$data) {
  457.         // Ordenar por clave (suponiendo formato YYYY-MM)
  458.         //ksort($data);
  459.         $prevDelivered null;
  460.         foreach ($data as $month => &$monthData) {
  461.             if ($prevDelivered !== null && is_numeric($prevDelivered) && $prevDelivered 0) {
  462.                 $change = (($monthData['delivered'] - $prevDelivered) / $prevDelivered) * 100;
  463.                 $monthData['deliveredChange'] = round($change2); // Ej: +21.43%
  464.             } else {
  465.                 $monthData['deliveredChange'] = null;
  466.             }
  467.             $prevDelivered $monthData['delivered'];
  468.         }
  469.         unset($monthData); // liberar referencia
  470.     }
  471.     /**
  472.      * @Route("/salesStatistics", name="sales_statistics", methods={"GET", "POST"})
  473.      */
  474.     public function salesStatistics(ManagerRegistry $doctrineRequest $request): jsonResponse
  475.     {
  476.         return $this->json$this->getSalesStatistics($doctrine$request->get('m')) );
  477.     }
  478. }