<?php
namespace App\Controller;
use App\Entity\Pays;
use App\Entity\Zone;
use App\Entity\Annee;
use App\Entity\Frais;
use App\Entity\Tarif;
use App\Entity\Token;
use App\Entity\Assurance;
use App\Entity\TypeTarifs;
use App\Entity\Restriction;
use App\Entity\FournitureItem;
use App\Service\BandeauService;
use App\Entity\QuantiteBouteille;
use App\Entity\FournitureCategorie;
use Doctrine\ORM\EntityManagerInterface;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class OffreCompleteController extends AbstractController
{
private $zoneRepository;
private $paysRepository;
private $anneeRepository;
private $fraisRepository;
private $tarifRepository;
private $assuranceRepository;
private $typeTarifsRepository;
private $restrictionRepository;
private $fournitureItemRepository;
private $quantiteBouteilleRepository;
private $fournitureCategorieRepository;
private $bandeauService;
public function __construct(EntityManagerInterface $entityManager, BandeauService $bandeauService)
{
$this->zoneRepository = $entityManager->getRepository(Zone::class);
$this->paysRepository = $entityManager->getRepository(Pays::class);
$this->anneeRepository = $entityManager->getRepository(Annee::class);
$this->fraisRepository = $entityManager->getRepository(Frais::class);
$this->tarifRepository = $entityManager->getRepository(Tarif::class);
$this->assuranceRepository = $entityManager->getRepository(Assurance::class);
$this->typeTarifsRepository = $entityManager->getRepository(TypeTarifs::class);
$this->restrictionRepository = $entityManager->getRepository(Restriction::class);
$this->fournitureItemRepository = $entityManager->getRepository(FournitureItem::class);
$this->quantiteBouteilleRepository = $entityManager->getRepository(QuantiteBouteille::class);
$this->fournitureCategorieRepository = $entityManager->getRepository(FournitureCategorie::class);
$this->bandeauService = $bandeauService;
}
/**
* @Route("/offre", name="app_offre")
*/
public function index(Request $request): Response
{
$user = $this->getUser();
// // Vérifier si l'utilisateur est authentifié
// if (!$user) {
// return $this->redirectToRoute('login');
// }
//on regarde si le token est présent
// Vérifier le token dans l'URL
$tokenValue = $request->query->get('token');
if ($tokenValue) {
$entityManager = $this->getDoctrine()->getManager();
$tokenRepository = $entityManager->getRepository(Token::class);
$token = $tokenRepository->findOneBy(['string' => $tokenValue]);
$isvalid = $token->isValid();
if (!$token or !$isvalid) {
return $this->redirectToRoute('login');
}
if ($isvalid) {
//si la date d'expiration est vide, on la remplit (délai une semaine)
if ($token->getDateUse() == null) {
$token->setDateUse(new \DateTime('@' . strtotime('+1 week')));
$entityManager->persist($token);
$entityManager->flush();
}
}
} else {
if (!$user) {
return $this->redirectToRoute('login');
}
//pas de token, on vérifie que le comtpe est enadmin
if ($this->isGranted('ROLE_ADMIN')) {
return $this->redirectToRoute('app_admin_index');
}
}
// Récupérer l'année en cours et l'année prochaine
$currentYear = (int)date('Y');
$nextYear = $currentYear + 1;
// Vérifier si la date actuelle est supérieure au 10 novembre de l'année en cours
$currentDate = new \DateTime();
$november10 = new \DateTime("$currentYear-11-10");
$showOffreSuivante = $currentDate > $november10;
$nextYearBoolean = false;
// Permet de savoir si on est dans l'année suivante
$offre = $request->query->get('offre');
// Si l'utilisateur a choisi l'offre suivante et si c'est possible en terme de date alors on passe à true le nextYearBoolean
if ($offre === 'suivante' && $showOffreSuivante) {
$nextYearBoolean = true;
}
// Récupération des données
$zones = $this->zoneRepository->findZonesForCurrentYear($nextYearBoolean);
return $this->render('offre_complete/index.html.twig', [
'controller_name' => 'OffreController',
'user' => $user,
'zones' => $zones,
'currentYear' => $currentYear,
'nextYear' => $nextYear,
'showOffreSuivante' => $showOffreSuivante,
'nextYearBoolean' => $nextYearBoolean,
'bandeau' => $this->bandeauService->displayPopup()
]);
}
/**
* @Route("/get_tarifs_pays/{id}", name="get_country_info", methods={"GET"})
*/
public function getTarifsPays(Pays $pays, EntityManagerInterface $entityManager, request $request): Response
{
$user = $this->getUser();
//on regarde s'il un token est présent
$tokenValue = $request->query->get('token');
if ($tokenValue) {
$entityManager = $this->getDoctrine()->getManager();
$tokenRepository = $entityManager->getRepository(Token::class);
$token = $tokenRepository->findOneBy(['string' => $tokenValue]);
$isvalid = $token->isValid();
if (!$isvalid) {
return $this->redirectToRoute('login');
}
} else {
//si il n'y a pas de token
// Vérifier si l'utilisateur est authentifié
if (!$user) {
return $this->redirectToRoute('login');
}
}
// Si le pays n'est pas trouvé, retourner une réponse 404
if (!$pays) {
return new Response("Pays non trouvé", Response::HTTP_NOT_FOUND);
}
$zone = $pays->getZone();
$quantitesBouteilles = $zone->getQuantitesBouteilles();
$typesTarifs = $zone->getTypeTarifs();
$frais = $zone->getFrais();
$informations = $zone->getInformation();
$restrictions = $pays->getRestrictions();
$tarifsData = $this->tarifsDataConstruct($typesTarifs, $quantitesBouteilles);
// Rendre un template partiel avec les informations du pays
return $this->render('tarifs/_show_tarifs.html.twig', [
'pays' => $pays,
'typesTarifs' => $typesTarifs,
'quantitesBouteilles' => $quantitesBouteilles,
'tarifsData' => $tarifsData, // Matrice des tarifs organisée par type et quantité
'frais' => $frais,
'informations' => $informations,
'restrictions' => $restrictions,
'user' => $user
]);
}
/**
* @Route("/export-tarifs/{id}", name="export_tarifs")
*/
public function exportTarifs(Pays $pays): StreamedResponse
{
$user = $this->getUser();
// Vérifier si l'utilisateur est authentifié
if (!$user) {
return $this->redirectToRoute('login');
}
// Si le pays n'est pas trouvé, retourner une réponse 404
if (!$pays) {
return new Response("Pays non trouvé", Response::HTTP_NOT_FOUND);
}
// Récupérer les données nécessaires
$zone = $pays->getZone();
$quantitesBouteilles = $zone->getQuantitesBouteilles();
$typesTarifs = $zone->getTypeTarifs();
$tarifsData = $this->tarifsDataConstruct($typesTarifs, $quantitesBouteilles);
// Création du fichier Excel
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Style des en-têtes
$headerStyle = [
'font' => [
'bold' => true,
'color' => ['rgb' => 'FFFFFF'],
],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['rgb' => 'C20E1B'],
],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
// Style des cellules de données
$dataStyle = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
'borders' => [
'bottom' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb' => 'CCCCCC'],
],
],
];
// Style de bordure pour le tableau
$borderStyle = [
'borders' => [
'outline' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb' => 'C20E1B'],
],
],
];
// En-têtes du premier tableau
$sheet->setCellValue('A1', 'Nb de bouteilles');
$sheet->setCellValue('B1', 'Nb de cartons');
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$sheet->setCellValueByColumnAndRow($columnIndex, 1, $typeTarif->getTitre());
$columnIndex++;
}
// Appliquer le style aux en-têtes
$sheet->getStyle("A1:" . chr(64 + $columnIndex - 1) . "1")->applyFromArray($headerStyle);
// Fixer la largeur des colonnes à 210px
foreach (range('A', chr(64 + $columnIndex - 1)) as $columnID) {
$sheet->getColumnDimension($columnID)->setWidth(30); // Environ 210px
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
// Remplir les données du premier tableau (1 carton)
$rowIndex = 2;
foreach ($quantitesBouteilles as $quantiteBouteille) {
if ($quantiteBouteille->getNbCartons() == 1) {
$sheet->setCellValueByColumnAndRow(1, $rowIndex, $quantiteBouteille->getMinBouteille() . ' > ' . $quantiteBouteille->getMaxBouteille());
$sheet->setCellValueByColumnAndRow(2, $rowIndex, $quantiteBouteille->getNbCartons());
// Remplir les tarifs par type
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$tarif = $tarifsData[$typeTarif->getId()][$quantiteBouteille->getId()] ?? 'N/A';
$sheet->setCellValueByColumnAndRow($columnIndex, $rowIndex, is_numeric($tarif) ? number_format($tarif, 2, '.', ',') . ' €' : 'N/A');
$columnIndex++;
}
// Appliquer le style de données aux lignes de données
$sheet->getStyle("A$rowIndex:" . chr(64 + $columnIndex - 1) . "$rowIndex")->applyFromArray($dataStyle);
$rowIndex++;
}
}
// Ajouter une ligne vide entre les deux tableaux
$rowIndex++;
// Remplir les données du second tableau (plusieurs cartons)
foreach ($quantitesBouteilles as $quantiteBouteille) {
if ($quantiteBouteille->getNbCartons() > 1) {
$sheet->setCellValueByColumnAndRow(1, $rowIndex, $quantiteBouteille->getMinBouteille() . ' > ' . $quantiteBouteille->getMaxBouteille());
$sheet->setCellValueByColumnAndRow(2, $rowIndex, $quantiteBouteille->getNbCartons());
// Remplir les tarifs par type
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$tarif = $tarifsData[$typeTarif->getId()][$quantiteBouteille->getId()] ?? 'N/A';
$sheet->setCellValueByColumnAndRow($columnIndex, $rowIndex, is_numeric($tarif) ? number_format($tarif, 2, '.', ',') . ' €' : 'N/A');
$columnIndex++;
}
// Appliquer le style de données aux lignes de données
$sheet->getStyle("A$rowIndex:" . chr(64 + $columnIndex - 1) . "$rowIndex")->applyFromArray($dataStyle);
$rowIndex++;
}
}
// Appliquer la bordure autour du tableau
$sheet->getStyle("A1:" . chr(64 + $columnIndex - 1) . ($rowIndex - 1))->applyFromArray($borderStyle);
// Création de la réponse en streaming pour le téléchargement
$response = new StreamedResponse(function () use ($spreadsheet) {
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
});
// Obtenir la date et l'heure actuelles
$dateTime = (new \DateTime())->format('Y-m-d_H-i-s');
// Définir les en-têtes de téléchargement
$response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response->headers->set('Content-Disposition', ResponseHeaderBag::DISPOSITION_ATTACHMENT);
$response->headers->set('Content-Disposition', 'attachment;filename="tarifs_' . $pays->getNom() . '_' . $dateTime . '.xlsx"');
$response->headers->set('Cache-Control', 'max-age=0');
return $response;
}
/**
* @Route("/export-tarifs-global", name="export_tarifs_global")
*/
public function exportTarifsGlobal(): StreamedResponse
{
$user = $this->getUser();
// Vérifier si l'utilisateur est authentifié
if (!$user) {
return $this->redirectToRoute('login');
}
$zones = $this->zoneRepository->findZonesForCurrentYear(false);
// Création du fichier Excel
$spreadsheet = new Spreadsheet();
$indexFeuille = 0;
foreach ($zones as $keyZone => $zone) {
// Pour la première itération, récupération de la feuille active
// Pour les suivantes, création d'une nouvelle feuille.
if ($indexFeuille === 0) {
$sheet = $spreadsheet->getActiveSheet();
} else {
// Crée un nouvel onglet
$sheet = $spreadsheet->createSheet();
}
$titreFeuille = substr($zone->getNom(), 0, 31);
$sheet->setTitle($titreFeuille);
// Récupérer les données nécessaires
$quantitesBouteilles = $zone->getQuantitesBouteilles();
$typesTarifs = $zone->getTypeTarifs();
$tarifsData = $this->tarifsDataConstruct($typesTarifs, $quantitesBouteilles);
// Style des en-têtes
$headerStyle = [
'font' => [
'bold' => true,
'color' => ['rgb' => 'FFFFFF'],
],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['rgb' => 'C20E1B'],
],
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
];
// Style des cellules de données
$dataStyle = [
'alignment' => [
'horizontal' => Alignment::HORIZONTAL_CENTER,
'vertical' => Alignment::VERTICAL_CENTER,
],
'borders' => [
'bottom' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb' => 'CCCCCC'],
],
],
];
// Style de bordure pour le tableau
$borderStyle = [
'borders' => [
'outline' => [
'borderStyle' => Border::BORDER_THIN,
'color' => ['rgb' => 'C20E1B'],
],
],
];
// En-têtes du premier tableau
$sheet->setCellValue('A1', 'Nb de bouteilles');
$sheet->setCellValue('B1', 'Nb de cartons');
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$sheet->setCellValueByColumnAndRow($columnIndex, 1, $typeTarif->getTitre());
$columnIndex++;
}
// Appliquer le style aux en-têtes
$sheet->getStyle("A1:" . chr(64 + $columnIndex - 1) . "1")->applyFromArray($headerStyle);
// Fixer la largeur des colonnes à 210px
foreach (range('A', chr(64 + $columnIndex - 1)) as $columnID) {
$sheet->getColumnDimension($columnID)->setWidth(30); // Environ 210px
$sheet->getColumnDimension($columnID)->setAutoSize(true);
}
// Remplir les données du premier tableau (1 carton)
$rowIndex = 2;
foreach ($quantitesBouteilles as $quantiteBouteille) {
if ($quantiteBouteille->getNbCartons() == 1) {
$sheet->setCellValueByColumnAndRow(1, $rowIndex, $quantiteBouteille->getMinBouteille() . ' > ' . $quantiteBouteille->getMaxBouteille());
$sheet->setCellValueByColumnAndRow(2, $rowIndex, $quantiteBouteille->getNbCartons());
// Remplir les tarifs par type
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$tarif = $tarifsData[$typeTarif->getId()][$quantiteBouteille->getId()] ?? 'N/A';
$sheet->setCellValueByColumnAndRow($columnIndex, $rowIndex, is_numeric($tarif) ? number_format($tarif, 2, '.', ',') . ' €' : 'N/A');
$columnIndex++;
}
// Appliquer le style de données aux lignes de données
$sheet->getStyle("A$rowIndex:" . chr(64 + $columnIndex - 1) . "$rowIndex")->applyFromArray($dataStyle);
$rowIndex++;
}
}
// Ajouter une ligne vide entre les deux tableaux
$rowIndex++;
// Remplir les données du second tableau (plusieurs cartons)
foreach ($quantitesBouteilles as $quantiteBouteille) {
if ($quantiteBouteille->getNbCartons() > 1) {
$sheet->setCellValueByColumnAndRow(1, $rowIndex, $quantiteBouteille->getMinBouteille() . ' > ' . $quantiteBouteille->getMaxBouteille());
$sheet->setCellValueByColumnAndRow(2, $rowIndex, $quantiteBouteille->getNbCartons());
// Remplir les tarifs par type
$columnIndex = 3;
foreach ($typesTarifs as $typeTarif) {
$tarif = $tarifsData[$typeTarif->getId()][$quantiteBouteille->getId()] ?? 'N/A';
$sheet->setCellValueByColumnAndRow($columnIndex, $rowIndex, is_numeric($tarif) ? number_format($tarif, 2, '.', ',') . ' €' : 'N/A');
$columnIndex++;
}
// Appliquer le style de données aux lignes de données
$sheet->getStyle("A$rowIndex:" . chr(64 + $columnIndex - 1) . "$rowIndex")->applyFromArray($dataStyle);
$rowIndex++;
}
}
// Appliquer la bordure autour du tableau
$sheet->getStyle("A1:" . chr(64 + $columnIndex - 1) . ($rowIndex - 1))->applyFromArray($borderStyle);
$indexFeuille++;
}
// Création de la réponse en streaming pour le téléchargement
$response = new StreamedResponse(function () use ($spreadsheet) {
$writer = new Xlsx($spreadsheet);
$writer->save('php://output');
});
// Obtenir la date et l'heure actuelles
$dateTime = (new \DateTime())->format('Y-m-d_H-i-s');
// Définir les en-têtes de téléchargement
$response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response->headers->set('Content-Disposition', ResponseHeaderBag::DISPOSITION_ATTACHMENT);
$response->headers->set('Content-Disposition', 'attachment;filename="tarifs_global_' . $dateTime . '.xlsx"');
$response->headers->set('Cache-Control', 'max-age=0');
return $response;
}
private function tarifsDataConstruct($typesTarifs, $quantitesBouteilles)
{
$tarifsData = [];
foreach ($typesTarifs as $typeTarif) {
$tarifsData[$typeTarif->getId()] = [];
foreach ($quantitesBouteilles as $quantiteBouteille) {
$tarif = $this->tarifRepository->findOneBy([
'typeTarifs' => $typeTarif,
'quantiteBouteille' => $quantiteBouteille,
]);
// Stocker le tarif ou null s'il n'y a pas de tarif pour cette combinaison
$tarifsData[$typeTarif->getId()][$quantiteBouteille->getId()] = $tarif ? $tarif->getMontant() : null;
}
}
return $tarifsData;
}
}