src/Controller/DashController.php line 45

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\EventLog;
  4. use App\Entity\Invoice;
  5. use App\Entity\InvoiceItem;
  6. use App\Entity\Organization;
  7. use App\Entity\Parameter;
  8. use App\Entity\Product;
  9. use App\Entity\Purchase;
  10. use App\Entity\PurchaseItem;
  11. use App\Entity\Salesman;
  12. use App\Entity\StatusType;
  13. use App\Entity\Preinvoice;
  14. use App\Entity\User;
  15. use App\Repository\ParameterRepository;
  16. use DateInterval;
  17. use DateTime;
  18. use Doctrine\ORM\EntityManagerInterface;
  19. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  20. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  21. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  22. use Symfony\Component\HttpFoundation\JsonResponse;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\HttpFoundation\Response;
  25. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  26. use Symfony\Component\HttpFoundation\StreamedResponse;
  27. use Symfony\Component\Routing\Annotation\Route;
  28. class DashController extends AbstractController
  29. {
  30.     private $entityManager;
  31.     public function __constructEntityManagerInterface $entityManager   )
  32.     {
  33.         $this->entityManager $entityManager;
  34.     }
  35.     /**
  36.      * @Route("/", name="app_dash")
  37.      */
  38.     public function index(Request $request): Response
  39.     {
  40.         $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
  41.         $user   $this->getUser();
  42.         if( $user->isActive() == 0){
  43.             $this->addFlash(
  44.                 'error',
  45.                 'Su cuenta fue desactivada'
  46.             );
  47.             return $this->redirectToRoute('app_login');
  48.         }
  49.         if ($user->getIsSalesman()){
  50.             return $this->redirectToRoute('app_commissions');
  51.         }
  52.      
  53.         return $this->redirectToRoute('app_start');
  54.     }
  55.     /**
  56.      * @Route("/start", name="app_start")
  57.      */
  58.     public function start(Request $request): Response
  59.     {
  60.         $entityManager $this->entityManager;
  61.         $countOrganization $entityManager->getRepository(Organization::class)->findBy(['activeInd'=>1]);
  62.         $today = new DateTime();
  63.         $countPurchase $entityManager->getRepository(Purchase::class)->findBy(['payInd'=>1,'activeInd'=>1]);
  64.         $countPendingPurchase $entityManager->getRepository(Purchase::class)->findBy(['payInd'=>0,'activeInd'=>1]);
  65.         // Obtener el conteo de facturas pagadas con el statusType 4
  66.         $countPaidInvoices $entityManager->getRepository(Invoice::class)->countPaidInvoices(4);
  67.         // Obtener el conteo de facturas pagadas con el statusType 2
  68.         $countPendingInvoices $entityManager->getRepository(Invoice::class)->countPaidInvoices(2);
  69.         return $this->render('start.html.twig', [
  70.             'countPaidInvoicesPurchase' => count($countPurchase)+$countPaidInvoices,
  71.             'countPendingInvoicesPurchase'=>count($countPendingPurchase) +$countPendingInvoices,
  72.             'purchaseCount'=> count($countPurchase) + count($countPendingPurchase),
  73.             'invoiceCount'=>$countPaidInvoices $countPendingInvoices,
  74.             'countOrganization'=>count($countOrganization),
  75.             'mountAnio' => $today->format('m-Y'),
  76.             'anio' => $today->format('Y')
  77.         ]);
  78.     }
  79.     /**
  80.      * @Route("/purchases", name="app_purchases")
  81.      */
  82.     public function purchases(Request $request): Response
  83.     {
  84.         $user   $this->getUser();
  85.         return $this->render('purchases.html.twig');
  86.     }
  87.     /**
  88.      * @Route("/sales", name="app_sales")
  89.      */
  90.     public function sales(Request $request): Response
  91.     {
  92.         $user   $this->getUser();
  93.         return $this->render('sales.html.twig');
  94.     }
  95.      /**
  96.      * @Route("/orders", name="app_orders")
  97.      */
  98.     public function orders(Request $request): Response
  99.     {
  100.         // $preinvoice = $this->getDoctrine()
  101.         // ->getRepository(Preinvoice::class)
  102.         // ->findAll();
  103.         $user   $this->getUser();
  104.         return $this->render('ordenes.html.twig');
  105.     }
  106.     /**
  107.      * @Route("/commissions", name="app_commissions")
  108.      */
  109.     public function commissions(Request $request): Response
  110.     {
  111.         $user   $this->getUser();
  112.         return $this->render('commissions.html.twig');
  113.     }
  114.     /**
  115.      * @Route("/reporting", name="app_reporting")
  116.      */
  117.     public function reporting(Request $request): Response
  118.     {
  119.         $entityManager $this->getDoctrine()->getManager();
  120.         $salesmen $entityManager->getRepository(Salesman::class)->findBy(['activeInd' => 1]);
  121.         $products $entityManager->getRepository(Product::class)->findBy(['activeInd' => 1]);
  122.         $providers $entityManager->getRepository(Organization::class)->findBy(['activeInd' => 1'organizationType' => 1]);
  123.         $clients $entityManager->getRepository(Organization::class)->findBy(['activeInd' => 1'organizationType' => 2]);
  124.         $statusTypes $entityManager->getRepository(StatusType::class)->findAll();
  125.         return $this->render('reporting.html.twig', [
  126.             'salesmen' => $salesmen,
  127.             'products' => $products,
  128.             'providers' => $providers,
  129.             'clients' => $clients,
  130.             'statusTypes'=>$statusTypes
  131.         ]);
  132.     }
  133.     /**
  134.      * @Route("/reporting/data", name="app_reporting_data", methods={"POST"})
  135.      */
  136.     public function getReportingData(Request $request): JsonResponse
  137.     {
  138.         $entityManager $this->getDoctrine()->getManager();
  139.         $filters json_decode($request->getContent(), true);
  140.         $invoices $entityManager->getRepository(Invoice::class)->findByFilters($filters);
  141.         $purchases $entityManager->getRepository(Purchase::class)->findByFilters($filters);
  142.         $data $this->calculateData($invoices$purchases$entityManager);
  143.         return new JsonResponse($data);
  144.     }
  145.     private function calculateData($invoices$purchases$entityManager)
  146.     {
  147.         $salesTotal 0;
  148.         $purchasesTotal 0;
  149.         $commissionsTotal 0;
  150.         $invoiceItemRepository $entityManager->getRepository(InvoiceItem::class);
  151.         $numSalesInvoices count($invoices);
  152.         $numPurchaseInvoices count($purchases);
  153.         $numCommissionInvoices 0;
  154.         $monthlySales = [];
  155.         $monthlyPurchases = [];
  156.         $monthlyCommissions = [];
  157.         $numSalesInvoicesPerMonth = [];
  158.         $numPurchaseInvoicesPerMonth = [];
  159.         $numCommissionInvoicesPerMonth = [];
  160.         $months = [];
  161.         $dailySales = [];
  162.         $dailyPurchases = [];
  163.         $dailyCommissions = [];
  164.         $numSalesInvoicesPerDay = [];
  165.         $numPurchaseInvoicesPerDay = [];
  166.         $numCommissionInvoicesPerDay = [];
  167.         $days = [];
  168.         foreach ($invoices as $invoice) {
  169.             $salesTotal += $invoice->getInvoiceAmount();
  170.             $month $invoice->getInvoiceDate()->format('m-Y');
  171.             $day $invoice->getInvoiceDate()->format('d-m-Y');
  172.             if (!in_array($month$months)) {
  173.                 $months[] = $month;
  174.                 $monthlySales[$month] = 0;
  175.                 $monthlyPurchases[$month] = 0;
  176.                 $monthlyCommissions[$month] = 0;
  177.                 $numSalesInvoicesPerMonth[$month] = 0;
  178.                 $numPurchaseInvoicesPerMonth[$month] = 0;
  179.                 $numCommissionInvoicesPerMonth[$month] = 0;
  180.             }
  181.             if (!in_array($day$days)) {
  182.                 $days[] = $day;
  183.                 $dailySales[$day] = 0;
  184.                 $dailyPurchases[$day] = 0;
  185.                 $dailyCommissions[$day] = 0;
  186.                 $numSalesInvoicesPerDay[$day] = 0;
  187.                 $numPurchaseInvoicesPerDay[$day] = 0;
  188.                 $numCommissionInvoicesPerDay[$day] = 0;
  189.             }
  190.             $monthlySales[$month] += $invoice->getInvoiceAmount();
  191.             $numSalesInvoicesPerMonth[$month]++;
  192.             $dailySales[$day] += $invoice->getInvoiceAmount();
  193.             $numSalesInvoicesPerDay[$day]++;
  194.             $invoiceItems $invoiceItemRepository->findBy(['invoice' => $invoice->getId()]);
  195.             $hasCommission false;
  196.             foreach ($invoiceItems as $item) {
  197.                 $commission $item->getCommissionAmount();
  198.                 if ($commission !== null && $commission 0) {
  199.                     $hasCommission true;
  200.                     $commissionsTotal += $commission;
  201.                     $monthlyCommissions[$month] += $commission;
  202.                     $dailyCommissions[$day] += $commission;
  203.                 }
  204.             }
  205.             if ($hasCommission) {
  206.                 $numCommissionInvoices++;
  207.                 $numCommissionInvoicesPerMonth[$month]++;
  208.                 $numCommissionInvoicesPerDay[$day]++;
  209.             }
  210.         }
  211.         foreach ($purchases as $purchase) {
  212.             $purchasesTotal += $purchase->getPurchaseAmount();
  213.             $month $purchase->getPurchaseDate()->format('m-Y');
  214.             $day $purchase->getPurchaseDate()->format('d-m-Y');
  215.             if (!isset($monthlyPurchases[$month])) {
  216.                 if (!in_array($month$months)) {
  217.                     $months[] = $month;
  218.                 }
  219.                 $monthlySales[$month] = 0;
  220.                 $monthlyPurchases[$month] = 0;
  221.                 $monthlyCommissions[$month] = 0;
  222.                 $numSalesInvoicesPerMonth[$month] = 0;
  223.                 $numPurchaseInvoicesPerMonth[$month] = 0;
  224.                 $numCommissionInvoicesPerMonth[$month] = 0;
  225.             }
  226.             if (!isset($dailyPurchases[$day])) {
  227.                 if (!in_array($day$days)) {
  228.                     $days[] = $day;
  229.                 }
  230.                 $dailySales[$day] = 0;
  231.                 $dailyPurchases[$day] = 0;
  232.                 $dailyCommissions[$day] = 0;
  233.                 $numSalesInvoicesPerDay[$day] = 0;
  234.                 $numPurchaseInvoicesPerDay[$day] = 0;
  235.                 $numCommissionInvoicesPerDay[$day] = 0;
  236.             }
  237.             $monthlyPurchases[$month] += $purchase->getPurchaseAmount();
  238.             $numPurchaseInvoicesPerMonth[$month]++;
  239.             $dailyPurchases[$day] += $purchase->getPurchaseAmount();
  240.             $numPurchaseInvoicesPerDay[$day]++;
  241.         }
  242.         sort($months);
  243.         sort($days);
  244.         return [
  245.             'sales' => $salesTotal,
  246.             'purchases' => $purchasesTotal,
  247.             'commissions' => $commissionsTotal,
  248.             'numSalesInvoices' => $numSalesInvoices,
  249.             'numPurchaseInvoices' => $numPurchaseInvoices,
  250.             'numCommissionInvoices' => $numCommissionInvoices,
  251.             'months' => $months,
  252.             'monthlySales' => array_values($monthlySales),
  253.             'monthlyPurchases' => array_values($monthlyPurchases),
  254.             'monthlyCommissions' => array_values($monthlyCommissions),
  255.             'numSalesInvoicesPerMonth' => $numSalesInvoicesPerMonth,
  256.             'numPurchaseInvoicesPerMonth' => $numPurchaseInvoicesPerMonth,
  257.             'numCommissionInvoicesPerMonth' => $numCommissionInvoicesPerMonth,
  258.             'days' => $days,
  259.             'dailySales' => array_values($dailySales),
  260.             'dailyPurchases' => array_values($dailyPurchases),
  261.             'dailyCommissions' => array_values($dailyCommissions),
  262.             'numSalesInvoicesPerDay' => $numSalesInvoicesPerDay,
  263.             'numPurchaseInvoicesPerDay' => $numPurchaseInvoicesPerDay,
  264.             'numCommissionInvoicesPerDay' => $numCommissionInvoicesPerDay
  265.         ];
  266.     }
  267.     /**
  268.      * @Route("/api/dollar/check-update", name="check_dollar_update", methods={"GET"})
  269.      */
  270.     public function checkAndUpdateDollarPrice(ParameterRepository $repository): JsonResponse
  271.     {
  272.         $parameter $repository->findOneBy(['parameterTxtVal'=>'Dolar']);
  273.         $today = new \DateTime();
  274.         if (!$parameter || !$parameter->getLastUpdated() || $parameter->getLastUpdated()->format('Y-m-d') != $today->format('Y-m-d')) {
  275.             // Llamar a la API externa y actualizar la base de datos
  276.             $apiUrl 'https://mindicador.cl/api';
  277.             $data json_decode(file_get_contents($apiUrl), true);
  278.             $newDollarPrice $data['dolar']['valor'];
  279.             $newDollarPriceFormatted number_format($newDollarPrice2'.''');
  280.             if ($parameter) {
  281.                 $parameter->setParameterNumVal($newDollarPriceFormatted);
  282.                 $parameter->setLastUpdated($today);
  283.             } else {
  284.                 // Crear nueva instancia si no existe
  285.                 $parameter = new Parameter();
  286.                 $parameter->setParameterTxtVal('Dolar');
  287.                 $parameter->setParameterNumVal($newDollarPriceFormatted);
  288.                 $parameter->setLastUpdated($today);
  289.                 $repository->add($parametertrue);
  290.             }
  291.             $this->getDoctrine()->getManager()->flush();
  292.             return new JsonResponse(['status' => 'updated''dollarPrice' => $newDollarPriceFormatted]);
  293.         }
  294.         return new JsonResponse(['status' => 'no update needed''dollarPrice' => $parameter->getParameterNumVal()]);
  295.     }
  296.     /**
  297.      * @Route("/api/iva/check-update", name="check_iva_update", methods={"GET"})
  298.      */
  299.     public function checkAndUpdateIva(ParameterRepository $repository): JsonResponse
  300.     {
  301.         $parameter $repository->findOneBy(['parameterTxtVal'=>'IVA']);
  302.         return new JsonResponse(['status' => 'no update needed''iva' => $parameter->getParameterNumVal()]);
  303.     }
  304.     /**
  305.      * @Route("/get-items-timeline", name="get_items_timeline", methods={"GET"})
  306.      */
  307.     public function getItemsTimeline(): JsonResponse
  308.     {
  309.         $em $this->entityManager;
  310.         $eventLog $em->getRepository(EventLog::class)->eventLogToday();
  311.         $itemsTimeline= [];
  312.         foreach($eventLog as $item){
  313.             $itemsTimeline[] = [
  314.                 'time' => $item->getCreatedAt()->format('H:i'),
  315.                 'badgeClass' => $item->getTypeEventLog()->getCssColor(),
  316.                 'content' => $item->getDescription()
  317.             ];
  318.         }
  319.         // Función de comparación para ordenar por la hora en orden descendente
  320.         usort($itemsTimeline, function($a$b) {
  321.             return strtotime($b['time']) - strtotime($a['time']);
  322.         });
  323.         return $this->json($itemsTimeline);
  324.     }
  325.     /**
  326.      * @Route("/ajax/get-data", name="ajax_get_data")
  327.      */
  328.     public function getData(): JsonResponse
  329.     {
  330.         $em $this->entityManager;
  331.         $salesmen $em->getRepository(Salesman::class)->findBy(['activeInd' => 1]);
  332.         // Obtener la meta global desde la tabla Parameter
  333.         $parameter $em->getRepository(Parameter::class)->findOneBy(['parameterTxtVal' => 'Meta Vendedores']);
  334.         $globalTarget $parameter->getParameterNumVal();
  335.         $progressData = [];
  336.         foreach ($salesmen as $salesman) {
  337.             // Obtener el último día del mes actual
  338.             $lastDayOfMonth = new DateTime('last day of this month');
  339.             $targetDate $lastDayOfMonth;
  340.             // Fecha actual
  341.             $today = new DateTime();
  342.             // Obtener la cantidad de ventas del vendedor para el mes actual
  343.             $startDate = new DateTime('first day of this month');
  344.             //$countSales = $em->getRepository(Invoice::class)->count(['salesman' => $salesman]);
  345.             $countSales $em->getRepository(Invoice::class)->getTotalInvoiceAmountForCurrentMonth($salesman->getId());
  346.             // Calcular la diferencia en días entre la fecha actual y la fecha meta
  347.             $interval $today->diff($targetDate);
  348.             $daysLeft $interval->days;
  349.             // Calcular el porcentaje completado del mes actual
  350.             $totalDaysInMonth = (int)$startDate->format('t'); // Total de días en el mes actual
  351.             $percentage = (($totalDaysInMonth $daysLeft) / $totalDaysInMonth) * 100;
  352.             // Calcular el porcentaje de ventas alcanzado en relación con la meta global
  353.             $salesPercentage = ($countSales $globalTarget) * 100;
  354.             // Crear la barra de progreso
  355.             $progressData[] = [
  356.                 'name' => $salesman->getSalesmanName(),
  357.                 'percentage' => $percentage,
  358.                 'daysLeft' => $daysLeft,
  359.                 'salesCount' => $countSales,
  360.                 'salesPercentage' => $salesPercentage// Porcentaje de ventas alcanzado
  361.                 'globalTarget' => $globalTarget// Meta global
  362.                 'status' => 'orange'// Aquí podrías calcular el color según el porcentaje
  363.             ];
  364.         }
  365.         return new JsonResponse($progressData);
  366.     }
  367.     /**
  368.      * @Route("/certificationsChart", name="certifications_chart", methods={"GET"})
  369.      */
  370.     public function certificationsChart(): JsonResponse
  371.     {
  372.         setlocale(LC_TIME'es_ES.UTF-8''Spanish_Spain.1252');
  373.         $months = [];
  374.         $today = new \DateTime(); // Fecha actual
  375.         for ($i 5$i >= 0$i--) {
  376.             $date = clone $today// Clonamos la fecha de hoy para no modificarla
  377.             $date->modify("-$i months"); // Restamos meses
  378.             $months[] = $date;
  379.         }
  380.         $salesData = [];
  381.         $purchaseData = [];
  382.         $salesAmountData = [];
  383.         $purchaseAmountData = [];
  384.         foreach ($months as $month) {
  385.             $startDate $month->format('Y-m-01');
  386.             $endDate $month->format('Y-m-t');
  387.             // Obtener ventas del mes
  388.             $sales $this->entityManager->getRepository(Invoice::class)
  389.                 ->countInvoicesByMonth($startDate$endDate);
  390.             // Obtener compras del mes
  391.             $purchases $this->entityManager->getRepository(Purchase::class)->countPurchasesByMonth($startDate$endDate);
  392.             $salesData[] = (int)$sales['invoiceCount'];
  393.             $purchaseData[] = (int)$purchases['purchaseCount'];
  394.             $salesAmountData[] = (float)$sales['totalAmount'];
  395.             $purchaseAmountData[] = (float)$purchases['totalAmount'];
  396.         }
  397.         $spanishMonths array_map(function($month) {
  398.             return ucwords(strftime('%B'$month->getTimestamp())); // '%B' devuelve el nombre completo del mes
  399.         }, $months);
  400.         $data = [
  401.             'categories' => $spanishMonths,
  402.             'series' => [
  403.                 ['name' => 'Compras''data' => $purchaseData],
  404.                 ['name' => 'Ventas''data' => $salesData],
  405.             ],
  406.             'amounts' => [
  407.                 'sales' => $salesAmountData,
  408.                 'purchases' => $purchaseAmountData,
  409.             ]
  410.         ];
  411.         return new JsonResponse($data);
  412.     }
  413.     /**
  414.      * @Route("/reporting/export/excel", name="app_reporting_export_excel", methods={"POST"})
  415.      */
  416.     public function exportToExcel(Request $requestEntityManagerInterface $entityManager)
  417.     {
  418.         // Obtén los filtros desde la solicitud
  419.         $filters json_decode($request->getContent(), true);
  420.         // Obtén los datos de ventas y compras
  421.         $invoices $entityManager->getRepository(Invoice::class)->findByFilters($filters);
  422.         $purchases $entityManager->getRepository(Purchase::class)->findByFilters($filters);
  423.         // Crea un nuevo archivo Excel
  424.         $spreadsheet = new Spreadsheet();
  425.         // Crear la hoja para Ventas
  426.         $sheetVentas $spreadsheet->setActiveSheetIndex(0);
  427.         $sheetVentas->setTitle('Ventas');
  428.         $this->populateSheetWithData($sheetVentas$invoices'Ventas'false$entityManager);
  429.         // Crear la hoja para Compras
  430.         $sheetCompras $spreadsheet->createSheet();
  431.         $sheetCompras->setTitle('Compras');
  432.         $this->populateSheetWithData($sheetCompras$purchases'Compras'false$entityManager);
  433.         // Crear la hoja para Comisiones
  434.         $sheetComisiones $spreadsheet->createSheet();
  435.         $sheetComisiones->setTitle('Comisiones');
  436.         $this->populateSheetWithData($sheetComisiones$invoices'Comisiones'true$entityManager);
  437.         // Configura el archivo de salida
  438.         $writer = new Xlsx($spreadsheet);
  439.         $filename 'Reporte_' date('Y-m-d') . '.xlsx';
  440.         // Genera la respuesta para descargar el archivo
  441.         $response = new Response();
  442.         $response->headers->set('Content-Type''application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  443.         $response->headers->set('Content-Disposition''attachment;filename="' $filename '"');
  444.         $response->headers->set('Cache-Control''max-age=0');
  445.         ob_start();
  446.         $writer->save('php://output');
  447.         $excelOutput ob_get_clean();
  448.         $response->setContent($excelOutput);
  449.         return $response;
  450.     }
  451.     /**
  452.      * Popula una hoja de Excel con los datos proporcionados.
  453.      *
  454.      * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet
  455.      * @param array $data
  456.      * @param string $type
  457.      * @param bool $isCommission
  458.      * @param EntityManagerInterface $entityManager
  459.      */
  460.     private function populateSheetWithData($sheet$data$type$isCommissionEntityManagerInterface $entityManager)
  461.     {
  462.         // Configurar encabezados de la hoja
  463.         $sheet->setCellValue('A1''N factura');
  464.         $sheet->setCellValue('B1''Fecha');
  465.         $sheet->setCellValue('C1''Monto Total');
  466.         $sheet->setCellValue('D1''Producto');
  467.         $sheet->setCellValue('E1''Cantidad');
  468.         $sheet->setCellValue('F1''Precio');
  469.         if ($type === 'Ventas' || $type === 'Comisiones') {
  470.             $sheet->setCellValue('G1''Utilidad Neta');
  471.             $sheet->setCellValue('H1''Margen Bruto (%)');
  472.             $sheet->setCellValue('I1''Comisión');
  473.             $sheet->setCellValue('J1''Vendedor');
  474.         }
  475.         $row 2;
  476.         // Procesar los datos
  477.         foreach ($data as $item) {
  478.             if ($type === 'Ventas' || $type === 'Comisiones') {
  479.                 $sheet->setCellValue('A' $row$item->getInvoiceHostnum());
  480.                 $sheet->setCellValue('B' $row$item->getInvoiceDate()->format('d-m-Y'));
  481.                 $sheet->setCellValue('C' $row$item->getInvoiceAmount());
  482.                 $invoiceItems $entityManager->getRepository(InvoiceItem::class)->findBy(['invoice' => $item->getId()]);
  483.                 foreach ($invoiceItems as $invoiceItem) {
  484.                     $sheet->setCellValue('D' $row$invoiceItem->getProduct()->getProductName());
  485.                     $sheet->setCellValue('E' $row$invoiceItem->getQuantityProduct());
  486.                     $sheet->setCellValue('F' $row$invoiceItem->getTotalAmount());
  487.                     $sheet->setCellValue('G' $row$invoiceItem->getNetUtility());
  488.                     $sheet->setCellValue('H' $row$invoiceItem->getGrossMarginPct() . '%');
  489.                     $sheet->setCellValue('I' $row$invoiceItem->getCommissionAmount());
  490.                     // Agregar vendedor si es ventas o comisiones
  491.                     if ($item->getSalesman()) {
  492.                         $sheet->setCellValue('J' $row$item->getSalesman()->getSalesmanName());
  493.                     } else {
  494.                         $sheet->setCellValue('J' $row'Sin vendedor');
  495.                     }
  496.                     $row++;
  497.                 }
  498.             } elseif ($type === 'Compras') {
  499.                 $sheet->setCellValue('A' $row$item->getInvoicePurchaseNum());
  500.                 $sheet->setCellValue('B' $row$item->getPurchaseDate()->format('d-m-Y'));
  501.                 $sheet->setCellValue('C' $row$item->getPurchaseAmount());
  502.                 $purchaseItems $entityManager->getRepository(PurchaseItem::class)->findBy(['purchase' => $item->getId()]);
  503.                 foreach ($purchaseItems as $purchaseItem) {
  504.                     $sheet->setCellValue('D' $row$purchaseItem->getProduct()->getProductName());
  505.                     $sheet->setCellValue('E' $row$purchaseItem->getQuantityProduct());
  506.                     $sheet->setCellValue('F' $row$purchaseItem->getTotalAmount());
  507.                     $row++;
  508.                 }
  509.             }
  510.         }
  511.         // Estilo de las celdas (alineación a la derecha y bordes)
  512.         $sheet->getStyle('A1:J' . ($row 1))->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT);
  513.         // Aplicar bordes
  514.         $styleArray = [
  515.             'borders' => [
  516.                 'allBorders' => [
  517.                     'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
  518.                     'color' => ['argb' => '000000'],
  519.                 ],
  520.             ],
  521.         ];
  522.         $sheet->getStyle('A1:J' . ($row 1))->applyFromArray($styleArray);
  523.         // Aplicar formato de tabla
  524.         $sheet->setAutoFilter('A1:J1');
  525.     }
  526. }