From b79fc2ac9f14d4f8f5e04d73bbd95d1f222b5ae3 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Wed, 26 Feb 2025 17:14:37 +0100 Subject: [PATCH] =?UTF-8?q?mass=20import=20ok,=20liens=20entre=20s=C3=A9ri?= =?UTF-8?q?e=20et=20festival=20CRUD=20ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/js/parts/globalActions.js | 32 +++--- src/Controller/DefaultController.php | 126 +++++++++++++-------- src/Controller/FestivalController.php | 1 + src/Controller/SerieFestivalController.php | 25 +++- src/Form/SerieFestivalType.php | 15 ++- templates/logged/history.html.twig | 17 +-- templates/logged/mass-register.html.twig | 11 +- templates/serie_festival/index.html.twig | 4 +- 8 files changed, 152 insertions(+), 79 deletions(-) diff --git a/assets/js/parts/globalActions.js b/assets/js/parts/globalActions.js index d778d4b6..133727ab 100644 --- a/assets/js/parts/globalActions.js +++ b/assets/js/parts/globalActions.js @@ -21,7 +21,7 @@ catégorie: dessin à la demande // use example in mass import $('#use_example').on('click', function () { $('#produits').val(massimportExample); - // $('#filling_zone input').click(); + $('#filling_zone input').click(); }); // intro js $('#introjs_start').on('click', function () { @@ -33,49 +33,49 @@ catégorie: dessin à la demande { element: document.querySelector('#caisse-now'), position: 'right', - intro : "Ceci est l'écran principal de la CaisseBliss, votre tableau de bord liste les produits que vous souhaitez vendre actuellement. Utilisez les flèches du clavier pour continuer la visite guidée." + intro: "Ceci est l'écran principal de la CaisseBliss, votre tableau de bord liste les produits que vous souhaitez vendre actuellement. Utilisez les flèches du clavier pour continuer la visite guidée." }, { element: document.querySelector('#main_options'), position: 'bottom', - intro : "Les options d'affichage des boutons de produit permettent de visualiser ou non les stocks restants de vos produits, le nombre de produit vendus sur le festival en cours, et d'activer ou non le bouton de caddie de vente express à utiliser pour les clients qui n'achètent qu'un seul produit à la fois." + intro: "Les options d'affichage des boutons de produit permettent de visualiser ou non les stocks restants de vos produits, le nombre de produit vendus sur le festival en cours, et d'activer ou non le bouton de caddie de vente express à utiliser pour les clients qui n'achètent qu'un seul produit à la fois." }, { element: document.querySelector('#client-now'), position: 'bottom', - intro : "L'espace commentaire lié à la vente en cours vous permet de prendre une note que vous retrouverez plus tard dans votre historique de vente. Il peut servir à savoir à qui vous faites une dédicace dans un livre par exemple." - },{ + intro: "L'espace commentaire lié à la vente en cours vous permet de prendre une note que vous retrouverez plus tard dans votre historique de vente. Il peut servir à savoir à qui vous faites une dédicace dans un livre par exemple." + }, { element: document.querySelector('#listing-products'), - intro : "La liste des produits les range par colonne de catégorie. Vous n'avez qu'a appuyer sur un produit pour l'ajouter à la liste de vente en cours. Et vous pouvez scroller horizontalement vos colonnes" - },{ + intro: "La liste des produits les range par colonne de catégorie. Vous n'avez qu'a appuyer sur un produit pour l'ajouter à la liste de vente en cours. Et vous pouvez scroller horizontalement vos colonnes" + }, { element: document.querySelector('#sellings'), - intro : "La liste de vente permet de modifier le prix des produits si vous faites des remises spéciales pour un client particulier, et vous calcule le rendu de monnaie si le client ne paie pas l'appoint." - },{ + intro: "La liste de vente permet de modifier le prix des produits si vous faites des remises spéciales pour un client particulier, et vous calcule le rendu de monnaie si le client ne paie pas l'appoint." + }, { element: document.querySelector('#choice-categories'), - intro : "Les options de catégories permettent d'afficher ou masquer certaines catégories si vous ne vendez pas tous vos produits à chaque festival." + intro: "Les options de catégories permettent d'afficher ou masquer certaines catégories si vous ne vendez pas tous vos produits à chaque festival." }, { element: document.querySelector('#menu-dashboard'), - intro : "Le menu latéral vous permet de gérer vos produits, stocks, catégories. Conforme au RGPD par design de logiciel libre, Caisse Bliss vous permet d'exporter vos données et respecte votre vie privée" + intro: "Le menu latéral vous permet de gérer vos produits, stocks, catégories. Conforme au RGPD par design de logiciel libre, Caisse Bliss vous permet d'exporter vos données et respecte votre vie privée" }, { element: document.querySelector('#menu_festivals'), position: 'right', - intro : "Les festivals vous permettent de séparer vos ventes lors de différents évènements et d'obtenir des statistiques détaillées afin de vous permettre de connaître la rentabilité de chaque évènement" + intro: "Les festivals vous permettent de séparer vos ventes lors de différents évènements et d'obtenir des statistiques détaillées afin de vous permettre de connaître la rentabilité de chaque évènement" }, { element: document.querySelector('#menu_series'), position: 'right', - intro : "Les séries de festivals permettent de relier des évènements similaires d'une édition à une autre. Par exemple Festival Harajuku 2018 et 2019, Japan Expo de toutes les années. Et ce afin de pouvoir voir des statistiques groupées dans la partie Historique." + intro: "Les séries de festivals permettent de relier des évènements similaires d'une édition à une autre. Par exemple Festival Harajuku 2018 et 2019, Japan Expo de toutes les années. Et ce afin de pouvoir voir des statistiques groupées dans la partie Historique." }, { element: document.querySelector('#menu_previsionnel'), position: 'right', - intro : "La page de prévisionnel n'est pas reliée à vos ventes de produits mais permet de voir si votre commerce est viable en fonction de ce que vous gagnez et dépensez habituellement. Toujours utile." + intro: "La page de prévisionnel n'est pas reliée à vos ventes de produits mais permet de voir si votre commerce est viable en fonction de ce que vous gagnez et dépensez habituellement. Toujours utile." }, { element: document.querySelector('.user-info-link'), position: 'right', - intro : "Vous pouvez modifier vos informations de compte utilisateur (email, pseudo, mot de passe...) en cliquant sur votre pseudo" + intro: "Vous pouvez modifier vos informations de compte utilisateur (email, pseudo, mot de passe...) en cliquant sur votre pseudo" }, ] }); @@ -86,7 +86,7 @@ catégorie: dessin à la demande }) // demo login - $('#demo_login_btn').on('click', function (){ + $('#demo_login_btn').on('click', function () { $('#username').val('demo'); $('#password').val('demo'); $('#_submit').click(); diff --git a/src/Controller/DefaultController.php b/src/Controller/DefaultController.php index dbbb849e..34e77c50 100644 --- a/src/Controller/DefaultController.php +++ b/src/Controller/DefaultController.php @@ -85,31 +85,15 @@ final class DefaultController extends AbstractController 'value' => 20, ], ], - 'activeFestival' => [ - 'fondDeCaisseAvant' => 10, - 'chiffreAffaire' => 10, - 'clientsCount' => 10, - 'name' => 'demo festival mock dans default controller', - ], + 'activeFestival' => $user->getActiveFestival(), 'allSellings' => 12, 'recentSellings' => [], 'recentSells' => $user->getSellings(), -// [ -// [ -// 'id' => '1234', -// 'date' => date_create('now'), -// 'comment' => 'blah', -// 'amount' => 52, -// 'productsSold' => [ -// 'name' => 'un truc de démo aussi làààà' -// ], -// ], -// ], 'activeSelling' => [], -// 'sellingComment' => [], + 'sellingComment' => [], 'statisticsFestivals' => 'todo', - 'recentSells' => '' + 'recentSells' => $user->getSellings(), ]); } @@ -144,6 +128,7 @@ final class DefaultController extends AbstractController { // TODO prendre en compte l'ajout de nouveaux produits si on a une valeur dans le POST // $request = Request::createFromGlobals(); + $data = json_decode($request->getContent(), true); $loggedUser = $this->getUser(); @@ -156,64 +141,111 @@ final class DefaultController extends AbstractController // super bannière A2;10€ // Sébastien Chabal sexy;10€ + $detected = ""; // Vérifiez si une requête POST a été faite if ($request->isMethod('POST')) { + $data = $request->getContent(); - return new Response(var_dump($data)); + var_dump($data); + // Remplacer temporairement les retours à la ligne par un marqueur + $data = str_replace(["\r\n", "\r", "\n"], "RETOUR_A_LA_LIGNE", $data); + + // Décoder les caractères URL + $data = urldecode($data); + + // Restaurer les vrais retours à la ligne + $data = str_replace("RETOUR_A_LA_LIGNE", "\n", $data); + // Décode les caractères URL encodés + $data = urldecode($data); + + var_dump($data); + // die(); + // Extrait la partie après "produits=" + if (strpos($data, 'produits=') === 0) { + $data = substr($data, 9); + } + + // Normalise les retours à la ligne + $data = str_replace(["\r\n", "\r"], "\n", $data); + var_dump($data); - - - - - - - - $lines = explode("\n", $data); // Séparez les lignes - + // $detected += "data: ".$data."\n -------------- \n"; + $lines = explode("\n", $data); + $currentCategory = null; + $categoriesCount = 0; + $productsCount = 0; + foreach ($lines as $line) { $line = trim($line); if (empty($line)) { - continue; // Ignorez les lignes vides - } - - // Vérifiez si la ligne commence par un nom de catégorie - if (preg_match('/^(.*):$/', $line, $matches)) { - $currentCategory = new GroupOfProducts(); - $currentCategory->setName(trim($matches[1])); - $currentCategory->setOwner($loggedUser); - $entityManager->persist($currentCategory); continue; } - // Vérifiez si la ligne contient un produit - if ($currentCategory && preg_match('/^(.*); ([0-9]+(?:\.[0-9]+)?)$/', $line, $matches)) { + // Modifié pour matcher "catégorie: dessin à la demande" + if (preg_match('/^catégorie:(.*)$/', $line, $matches)) { + $detected .= "\n category ".trim($matches[1]); + $currentCategory = new GroupOfProducts(); + $currentCategory->setName(trim($matches[1])); + $currentCategory->setUser($loggedUser); + $loggedUser->addGroupOfProduct($currentCategory); + $entityManager->persist($currentCategory); + $categoriesCount++; + continue; + } + + // Modifié pour matcher "nom_produit;XXX€" + if ($currentCategory && preg_match('/(.*?);.*(\d+)€\s*$/', $line, $matches)) { $productName = trim($matches[1]); $productPrice = (float)trim($matches[2]); - // Créez un nouvel objet Product $product = new Product(); $product->setUser($loggedUser); + $loggedUser->addProduct($product); $product->setName($productName); + $detected .= "\n product ".$productName; $product->setPrice($productPrice); + $product->setStock(1); + $product->setImage('default.jpg'); - // Ajoutez le produit à la catégorie $currentCategory->addProduct($product); $entityManager->persist($product); + $productsCount++; } } - // Enregistrez tous les changements dans la base de données + $entityManager->persist($loggedUser); + $entityManager->flush(); + $this->addFlash( + 'success', + sprintf( + 'Import réussi ! %d catégorie(s) et %d produit(s) ont été créés.', + $categoriesCount, + $productsCount + ) + ); -// return $this->redirectToRoute('app_product_index'); - return new Response('Produits importés avec succès.', Response::HTTP_CREATED); + if ($categoriesCount === 0 && $productsCount === 0) { + $this->addFlash( + 'warning', + 'Aucune donnée n\'a été importée. Vérifiez le format de vos données.' + ); + } + $this->addFlash( + 'success', + 'détecté: '.$detected + ); + + return $this->redirectToRoute('app_product_index'); } + + return new Response('Méthode non autorisée', Response::HTTP_METHOD_NOT_ALLOWED); } @@ -279,7 +311,7 @@ final class DefaultController extends AbstractController ->setPaidByCustomer($dataOfNewSelling['paidByClient']) ->setCustomerInfo($dataOfNewSelling['sellingComment']) ->setDate(new \DateTime()) - ->setOwner($loggedUser); + ->setUser($loggedUser); $currentFestival->updateChiffreAffaire(); @@ -287,7 +319,7 @@ final class DefaultController extends AbstractController $entityManager->persist($newSelling); $entityManager->persist($currentFestival); - $newSelling->setOwner($loggedUser); + $newSelling->setUser($loggedUser); $entityManager->persist($loggedUser); $entityManager->flush(); diff --git a/src/Controller/FestivalController.php b/src/Controller/FestivalController.php index ae791101..8d115bc2 100644 --- a/src/Controller/FestivalController.php +++ b/src/Controller/FestivalController.php @@ -68,6 +68,7 @@ final class FestivalController extends AbstractController if ($form->isSubmitted() && $form->isValid()) { $entityManager->flush(); + $this->addFlash('success', 'Le festival a été modifié avec succès.'); return $this->redirectToRoute('app_festival_index', [], Response::HTTP_SEE_OTHER); } diff --git a/src/Controller/SerieFestivalController.php b/src/Controller/SerieFestivalController.php index a85cb25a..f70eb3af 100644 --- a/src/Controller/SerieFestivalController.php +++ b/src/Controller/SerieFestivalController.php @@ -25,14 +25,20 @@ final class SerieFestivalController extends AbstractController #[Route('/new', name: 'app_serie_festival_new', methods: ['GET', 'POST'])] public function new(Request $request, EntityManagerInterface $entityManager): Response { + $userFound = $this->getUser(); $serieFestival = new SerieFestival(); + $serieFestival->setUser($userFound); + $serieFestival->setDateCreation(new \DateTime()); + $userFound->addSeriesFestival($serieFestival); + $form = $this->createForm(SerieFestivalType::class, $serieFestival); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager->persist($serieFestival); + $entityManager->persist($userFound); $entityManager->flush(); - + $this->addFlash('success', 'La série de festivals "'.$serieFestival->getName().'" a été créée avec succès.'); return $this->redirectToRoute('app_serie_festival_index', [], Response::HTTP_SEE_OTHER); } @@ -45,6 +51,10 @@ final class SerieFestivalController extends AbstractController #[Route('/{id}', name: 'app_serie_festival_show', methods: ['GET'])] public function show(SerieFestival $serieFestival): Response { + $userFound = $this->getUser(); + if (!$userFound || $serieFestival->getUser() !== $userFound) { + throw $this->createAccessDeniedException('Vous n\'êtes pas autorisé à consulter cette série de festivals.'); + } return $this->render('serie_festival/show.html.twig', [ 'serie_festival' => $serieFestival, @@ -54,12 +64,17 @@ final class SerieFestivalController extends AbstractController #[Route('/{id}/edit', name: 'app_serie_festival_edit', methods: ['GET', 'POST'])] public function edit(Request $request, SerieFestival $serieFestival, EntityManagerInterface $entityManager): Response { + $userFound = $this->getUser(); + // if (!$userFound || $serieFestival->getUser() !== $userFound) { + // throw $this->createAccessDeniedException('Vous n\'êtes pas autorisé à modifier cette série de festivals.'); + // } + $form = $this->createForm(SerieFestivalType::class, $serieFestival); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $entityManager->flush(); - + $this->addFlash('success', 'La série de festivals a été modifiée avec succès.'); return $this->redirectToRoute('app_serie_festival_index', [], Response::HTTP_SEE_OTHER); } @@ -72,9 +87,15 @@ final class SerieFestivalController extends AbstractController #[Route('/{id}', name: 'app_serie_festival_delete', methods: ['POST'])] public function delete(Request $request, SerieFestival $serieFestival, EntityManagerInterface $entityManager): Response { + $userFound = $this->getUser(); + if (!$userFound || $serieFestival->getUser() !== $userFound) { + throw $this->createAccessDeniedException('Vous n\'êtes pas autorisé à supprimer cette série de festivals.'); + } + if ($this->isCsrfTokenValid('delete'.$serieFestival->getId(), $request->getPayload()->getString('_token'))) { $entityManager->remove($serieFestival); $entityManager->flush(); + $this->addFlash('success', 'La série de festivals a été supprimée avec succès.'); } return $this->redirectToRoute('app_serie_festival_index', [], Response::HTTP_SEE_OTHER); diff --git a/src/Form/SerieFestivalType.php b/src/Form/SerieFestivalType.php index 80e11530..99e6b453 100644 --- a/src/Form/SerieFestivalType.php +++ b/src/Form/SerieFestivalType.php @@ -4,6 +4,7 @@ namespace App\Form; use App\Entity\SerieFestival; use App\Entity\User; +use App\Entity\Festival; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -18,10 +19,18 @@ class SerieFestivalType extends AbstractType ->add('dateCreation', null, [ 'widget' => 'single_text', ]) - ->add('user', EntityType::class, [ - 'class' => User::class, - 'choice_label' => 'id', + ->add('festivals', EntityType::class, [ + 'class' => Festival::class, + 'choice_label' => function($festival) { + return $festival->getName() . ' : ' . $festival->getDateStart()->format('Y-m-d') . ' - ' . $festival->getDateEnd()->format('Y-m-d'); + }, + 'multiple' => true, + 'expanded' => true ]) + // ->add('user', EntityType::class, [ + // 'class' => User::class, + // 'choice_label' => 'id', + // ]) ; } diff --git a/templates/logged/history.html.twig b/templates/logged/history.html.twig index 5d7dfe44..d3310a9e 100755 --- a/templates/logged/history.html.twig +++ b/templates/logged/history.html.twig @@ -110,26 +110,29 @@ {{ vente.id }} {{ vente.date |date('Y-m-d H:i:s') }} - {{ vente.comment }} + + {# {{ vente.comment }} #} + + - {% if vente.productsSold |length >1 %} + {% if vente.products |length >1 %} - {{ vente.productsSold |length }} + {{ vente.products |length }} produits {% else %} - {% if vente.productsSold and vente.productsSold.0 is defined %} + {% if vente.products and vente.products.0 is defined %} - {{ vente.productsSold.0.name }} + {{ vente.products.0.name }} {% endif %} {% endif %} - {{ vente.amount }} + {{ vente.sum }} - diff --git a/templates/logged/mass-register.html.twig b/templates/logged/mass-register.html.twig index 9b261bd6..3209bd94 100755 --- a/templates/logged/mass-register.html.twig +++ b/templates/logged/mass-register.html.twig @@ -1,5 +1,5 @@
-
+
@@ -35,9 +35,14 @@ catégorie: dessin à la demande nom de catégorie existe déjà, le produit sera associé avec celle-ci.
diff --git a/templates/serie_festival/index.html.twig b/templates/serie_festival/index.html.twig index 5364d8b2..e9723a21 100644 --- a/templates/serie_festival/index.html.twig +++ b/templates/serie_festival/index.html.twig @@ -11,6 +11,7 @@ Id Name DateCreation + Nombre de festivals actions @@ -20,6 +21,7 @@ {{ serie_festival.id }} {{ serie_festival.name }} {{ serie_festival.dateCreation ? serie_festival.dateCreation|date('Y-m-d') : '' }} + {{ serie_festival.festivals|length }} show edit @@ -27,7 +29,7 @@ {% else %} - no records found + Aucun enregistrement trouvé {% endfor %}