src/Controller/CartController.php line 2202
<?phpnamespace App\Controller;use App\Entity\ActionShock;use App\Entity\AdditionalCompanyInformation;use App\Entity\Billings;use App\Entity\BrandDiscount;use App\Entity\Cart;use App\Entity\CartFinished;use App\Entity\ConfigSite;use App\Entity\CustomerControl;use App\Entity\DeliveryAddress;use App\Entity\Joker;use App\Entity\LotNumber;use App\Entity\Products;use App\Entity\Rebate;use App\Entity\SpecialCustomer;use App\Entity\SpecialDiscount;use App\Entity\User;use App\Service\JwtMercator;use Symfony\Component\Mime\Email;use Symfony\Component\Mailer\MailerInterface;use Doctrine\ORM\EntityManagerInterface;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\JsonResponse;use Symfony\Component\HttpFoundation\RedirectResponse;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Routing\Annotation\Route;use Symfony\Contracts\HttpClient\HttpClientInterface;use TCPDF;class CartController extends AbstractController{private EntityManagerInterface $manager;private $client;private $jwtMercator;public function __construct(EntityManagerInterface $manager, HttpClientInterface $client, JwtMercator $jwtMercator){$this->manager = $manager;$this->client = $client;$this->jwtMercator = $jwtMercator;}#[Route('/addtocart', name: 'addtocart', methods: ['GET', 'POST'])]public function index(Request $request): Response{$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();} else {$user = $checkControl->getCustomer();}$information = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(['user' => $user]);$exist_cart = $this->manager->getRepository(Cart::class)->findOneBy(array('user' => $user, 'finish' => false), array('commandNumber' => 'DESC'));if ($exist_cart) {$exist_product = $this->manager->getRepository(Cart::class)->findOneBy(array('user' => $user, 'finish' => false, 'products' => $this->manager->getRepository(Products::class)->find($request->get('id_product'))));if ($exist_product) {$availableStock = $this->manager->getRepository(LotNumber::class)->getProductAvailableStock($exist_product->getProducts()->getId(), $this->getMercatorFolder($information->getCompanyCountry()));$newQuantity = $exist_product->getQuantity() + $request->get('quantity');if ($newQuantity > $availableStock) {$newQuantity = $availableStock;}$exist_product->setQuantity($newQuantity);$this->manager->flush();} else {$cart = new Cart();$cart->setFinish(0);$cart->setCommandNumber($exist_cart->getCommandNumber());$cart->setProducts($this->manager->getRepository(Products::class)->find($request->get('id_product')));$cart->setUser($user);$cart->setQuantity($request->get('quantity'));$this->manager->persist($cart);$this->manager->flush();}} else {$exist_cart_before = $this->manager->getRepository(Cart::class)->findOneBy(array('user' => $user, 'finish' => true), array('commandNumber' => 'DESC'));$cart = new Cart();$cart->setFinish(0);if ($exist_cart_before) {$cart->setCommandNumber($exist_cart_before->getCommandNumber() + 1);} else {$cart->setCommandNumber(1);}$cart->setProducts($this->manager->getRepository(Products::class)->find($request->get('id_product')));$cart->setUser($user);$cart->setQuantity($request->get('quantity'));$this->manager->persist($cart);$this->manager->flush();}// Récupérer les informations pour la réponse JSON$cartCounts = $this->calculateCountItemInCart();// Calculer le pourcentage de remise en cours$specialCustomer = $this->manager->getRepository(SpecialCustomer::class)->findOneBy(array('user' => $user));$pourcentSpecialCustomer = null;if ($specialCustomer) {$pourcentSpecialCustomer = $specialCustomer;}$rebatePercent = $this->calculateRebate($pourcentSpecialCustomer);// Récupérer les informations sur les produits gratuits$carts = $this->retrieveCart();$freeProductInfo = $this->checkFreeProduct($carts);// Récupérer les informations de remises$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();$rebateInfo = [];foreach ($rebates as $rebate) {$rebateInfo[] = ['min' => $rebate->getMin(),'percent' => $rebate->getPourcentRebate()];}// Créer la réponse JSON avec toutes les informations nécessairesreturn new JsonResponse(['success' => true,'cartCount' => $cartCounts['total'],'cartCountEligible' => $cartCounts['eligible'],'rebateInfo' => ['currentPercent' => $rebatePercent,'availableRebates' => $rebateInfo],'freeProductInfo' => $freeProductInfo,'message' => 'Produit ajouté au panier']);}#[Route('/addtocartfromcart', name: 'addtocartfromcart')]public function addToCartFromCart(Request $request): JsonResponse{$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();} else {$user = $checkControl->getCustomer();}$information = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(['user' => $user]);$exist_cart = $this->manager->getRepository(Cart::class)->findOneBy(array('user' => $user, 'finish' => false), array('commandNumber' => 'DESC'));if ($exist_cart) {$exist_product = $this->manager->getRepository(Cart::class)->find($request->get('id_product'));if (!$exist_product) {return new JsonResponse('Cart item not found');}if ($request->get('move') == "quantity-increase") {$availableStock = $this->manager->getRepository(LotNumber::class)->getProductAvailableStock($exist_product->getProducts()->getId(), $this->getMercatorFolder($information->getCompanyCountry()));$newQuantity = $exist_product->getQuantity() + 1;if ($newQuantity > $availableStock) {$newQuantity = $availableStock;}$exist_product->setQuantity($newQuantity);} elseif ($request->get('move') == "quantity-decrease") {$exist_product->setQuantity($exist_product->getQuantity() - 1);}if ($exist_product->getQuantity() == 0) {$this->manager->remove($exist_product);}$this->manager->flush();}// Récupérer les informations pour la réponse JSON$cartCounts = $this->calculateCountItemInCart();// Calculer le pourcentage de remise en cours$specialCustomer = $this->manager->getRepository(SpecialCustomer::class)->findOneBy(array('user' => $user));$pourcentSpecialCustomer = null;if ($specialCustomer) {$pourcentSpecialCustomer = $specialCustomer;}$rebatePercent = $this->calculateRebate($pourcentSpecialCustomer);// Récupérer les informations de remises$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();$rebateInfo = [];foreach ($rebates as $rebate) {$rebateInfo[] = ['min' => $rebate->getMin(),'percent' => $rebate->getPourcentRebate()];}return new JsonResponse(['success' => true,'cartCount' => $cartCounts['total'],'cartCountEligible' => $cartCounts['eligible'],'rebateInfo' => ['currentPercent' => $rebatePercent,'availableRebates' => $rebateInfo]]);}#[Route('/cart', name: 'cartView')]public function cartView(JwtMercator $jwtMercator, Request $request): Response{if (!$this->getUser()) {return $this->redirectToRoute('app_login');}$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $this->getUser()));} else {$user = $checkControl->getCustomer();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $checkControl->getCustomer()));}$costDelivery = $this->manager->getRepository(ConfigSite::class)->findAll();$costDelivery = $costDelivery[0];$informations = $this->manager->getRepository(User::class)->getAllInformationsForAccount($user);if ($additionalInformations != null && $additionalInformations->getGeneralCondition()) {$cart = $this->retrieveCart();} else {$this->addFlash('danger', 'Veuillez remplir votre pays & accepter les conditions générales de ventes!');return $this->redirectToRoute('profile');}// $this->applyDiscountOnNewRefItems($cart);$faReference = ['NMJ007', 'NMJ008', 'NMJ011', 'NMJ084', 'NMJ013', 'NMJ056', 'NMJ040'];$countFaInCart = 0;foreach ($cart['carts'] as $item) {if (isset($item['reference'])) {if (in_array($item['reference'], $faReference)) {$countFaInCart += $item[0]['quantity'];}}}$numberOfFaRef = null;if ($countFaInCart >= 2) {$numberOfFaRef = floor($countFaInCart / 2);}$flyersProduct = $this->manager->getRepository(Products::class)->findOneBy(array('reference' => 'NMZZ21'));$deliveryAdress = $this->manager->getRepository(DeliveryAddress::class)->findOneBy(array('user' => $user));// if ($additionalInformations->getCompanyAddress() != null && $additionalInformations->getCompanyPostal() != null && $additionalInformations->getCompanyCountry() &&// $additionalInformations->getTownAddressCompany() != null)if (!$deliveryAdress) {$this->addFlash('danger', 'Veuillez ajouter une adresse de livraison! "Bouton bleu gestion des adresses"');return $this->redirectToRoute('profile');}$address = $this->manager->getRepository(DeliveryAddress::class)->findBy(array('user' => $user));$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();$specificRebates = $this->manager->getRepository(Rebate::class)->getActiveSpecificRebates();$brandDiscounts = $this->manager->getRepository(BrandDiscount::class)->findBy(['active' => true]);// Gestion de la préférence flyers via sessionif (!$request->getSession()->has('wantFlyers')) {$request->getSession()->set('wantFlyers', true);}$wantFlyers = $request->getSession()->get('wantFlyers');// Si l'utilisateur ne veut pas de flyers, on n'ajoute pas de flyersif (!$wantFlyers) {$numberOfFaRef = null;}return $this->render('cart/index.html.twig', ['shockActionTypes' => ActionShock::TYPES,'informations' => $informations,'carts' => $cart['carts'],'rebate' => $cart['rebate'],'grandTotalPrice' => $cart['grandTotalPrice'],'freeProduct' => $cart['freeProduct'],'freeTransport' => $cart['freeTransport'],'joker' => $cart['joker'],'user' => $this->getUser(),'address' => $address,'jokerNumber' => $this->checkJokerNumber(),'missingItems' => $cart['missingItems'],'costDelivery' => $costDelivery->getCostDelivery(),'phFlyers' => (int)$numberOfFaRef,'countFaInCart' => $countFaInCart,'flyersProduct' => $flyersProduct,'wantFlyers' => $wantFlyers,'rebates' => array_reverse($rebates),'specificRebates' => array_reverse($specificRebates),// TODO update twig template'brandDiscounts' => $brandDiscounts]);}private function applyDiscountOnNewRefItems(&$cart){// Parcourez chaque élément du panier directement.foreach ($cart as $key => &$item) {// Vérifiez si l'élément est un tableau et a une propriété 'newRef' à true.if (is_array($item) && isset($item['newRef']) && $item['newRef']) {// Vérifiez si 'PriceRebateInclude' existe et appliquez la réduction de 2%.if (isset($item['PriceRebateInclude'])) {// Calcul de la réduction de 2%.$discountAmount = $item['PriceRebateInclude'] * 0.02;// Calculez le nouveau prix après réduction et stockez-le dans 'PriceRebateIncludeWith2pourcent'.$item['PriceRebateIncludeWith2pourcent'] = $item['PriceRebateInclude'] - $discountAmount;}}}unset($item); // Détruisez la référence sur le dernier élément pour éviter les problèmes potentiels.// Pas besoin de retourner $cart car il est modifié par référence.}#[Route('/cart/send', name: 'cartSend')]public function sendCart(Request $request, MailerInterface $mailer, JwtMercator $jwtMercator): RedirectResponse|JsonResponse{$orderRecipientEmails = $this->getParameter('app.order.emails');if (!is_array($orderRecipientEmails)) {$orderRecipientEmails = explode(',', $orderRecipientEmails);}$orderRecipientEmails = array_values(array_filter(array_map('trim', $orderRecipientEmails)));$lotNumbersFromRequest = $request->request->all('lotNumbers');if (!is_array($lotNumbersFromRequest)) {$lotNumbersFromRequest = $lotNumbersFromRequest !== null && $lotNumbersFromRequest !== '' ? [(string) $lotNumbersFromRequest] : [];}$lotNumbersFromRequest = array_values(array_filter(array_map(static fn ($lot) => trim(strip_tags((string) $lot)),$lotNumbersFromRequest)));$defaultRebatePercent = floatval($request->request->get('rebatePourcent'));$costDelivery = $this->manager->getRepository(ConfigSite::class)->findAll();$costDelivery = $costDelivery[0];if ($request->request->get('idUser') === null) {return $this->redirectToRoute('app_login');}$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if ($checkControl != null) {$user = $checkControl->getCustomer();} else {$user = $this->manager->getRepository(User::class)->find($request->request->get('idUser'));}$commandId = (int) $request->request->get('idCommande');$existingOrder = $this->manager->getRepository(CartFinished::class)->findOneBy(['user' => $user,'commandId' => $commandId,]);if ($existingOrder !== null) {return new JsonResponse('ok', headers: ['Content-Type' => 'application/json;charset=UTF-8']);}$additionalInformation = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $user));$country = $additionalInformation->getCompanyCountry();$saleField = $country === 'Belgique' ? 'p.saleBe' : 'p.saleFr';$folderMercatorValue = $this->getMercatorFolder($country);$countryShip = $this->getCountryCode($country);$pourcentSpecialCustomer = null;if ($user->getSpecialCustomer()) {$checkUserSpecialEntity = $this->manager->getRepository(SpecialCustomer::class)->findOneBy(array('user' => $user, 'active' => true));if ($checkUserSpecialEntity == null) {$pourcentSpecialCustomer = $this->manager->getRepository(ConfigSite::class)->findAll();$pourcentSpecialCustomer = $pourcentSpecialCustomer[0];} else {$pourcentSpecialCustomer = $checkUserSpecialEntity->getPourcentRebate();}}$articles = $this->manager->getRepository(Cart::class)->getCurrentCart($user, $commandId);$articles = array_values(array_filter($articles, static fn ($item) => !$item->getFinish()));if (empty($articles)) {return new JsonResponse(['error' => 'empty_cart'], JsonResponse::HTTP_BAD_REQUEST);}$jwtToken = $this->jwtMercator->getToken();// Récupérer l'historique local des commandes pour détecter les nouvelles références// L'API Mercator /OrderHistory retourne des IDs incompatibles avec idProductOnMercator$finishedCartItems = $this->manager->getRepository(Cart::class)->findBy(['user' => $user,'finish' => true]);$localHistoryProductIds = [];foreach ($finishedCartItems as $cartItem) {$productItem = $cartItem->getProducts();if ($productItem) {$localHistoryProductIds[] = $productItem->getIdProductOnMercator();}}$localHistoryProductIds = array_unique($localHistoryProductIds);$addressDelivery = $this->manager->getRepository(DeliveryAddress::class)->find($request->request->get('deliveryAddress'));$cart = $this->manager->getRepository(Cart::class)->getAllCart($user);$freeProducts = $this->checkFreeProduct($cart);// Calculer le total de produits dans le panier pour la règle des 2% nouvelles références$totalCartQuantity = 0;foreach ($articles as $article) {$totalCartQuantity += $article->getQuantity();}$specificRebates = $this->manager->getRepository(Rebate::class)->getActiveSpecificRebates();if ($additionalInformation->getCompanyCountry() == 'Belgique') {$tvaLow = 6;$tvaHigh = 21;} elseif ($additionalInformation->getCompanyCountry() == 'France') {$tvaLow = 5.5;$tvaHigh = 20;} elseif ($additionalInformation->getCompanyCountry() == 'Luxembourg') {$tvaLow = 3;$tvaHigh = 17;} else {$tvaLow = 6;$tvaHigh = 21;}// Tableau associatif pour faire correspondre les noms des jours en anglais avec leur équivalent en français$daysMapping = ['monday' => 'Lu','tuesday' => 'Ma','wednesday' => 'Me','thursday' => 'Je','friday' => 'Ve','saturday' => 'Sa','sunday' => 'Di',];// Obtenir les jours en français avec les deux premières lettres où la valeur est true$daysTrue = [];foreach ($daysMapping as $dayEnglish => $dayFrench) {if ($addressDelivery->{'get' . ucfirst($dayEnglish)}() === true) {$morningStart = $addressDelivery->{'getMorning' . ucfirst($dayEnglish)}();$morningEnd = $addressDelivery->{'getMorning' . ucfirst($dayEnglish) . 'End'}();$afternoonStart = $addressDelivery->{'getAfternoon' . ucfirst($dayEnglish)}();$afternoonEnd = $addressDelivery->{'getAfternoon' . ucfirst($dayEnglish) . 'End'}();$daysTrue[$dayFrench] = ['morning' => ['start' => $morningStart instanceof \DateTimeInterface ? $morningStart->format('H:i') : '','end' => $morningEnd instanceof \DateTimeInterface ? $morningEnd->format('H:i') : '',],'afternoon' => ['start' => $afternoonStart instanceof \DateTimeInterface ? $afternoonStart->format('H:i') : '','end' => $afternoonEnd instanceof \DateTimeInterface ? $afternoonEnd->format('H:i') : '',],];}}if ($additionalInformation->getCompanyName() === null || $additionalInformation->getTva() === null || $addressDelivery->getAddress() === null) {$this->addFlash('danger', 'Veuillez complèter votre profil pour continuer.');return new JsonResponse('profile', headers: ['Content-Type' => 'application/json;charset=UTF-8']);}$cartFinished = new CartFinished();if (!$checkControl) {$cartFinished->setUser($user);} else {$cartFinished->setUser($checkControl->getCustomer());}$cartFinished->setCommandId($commandId);$cartFinished->setTotalPriceWithNoReduction(floatval($request->request->get('total-price-tvac-no-reduct')));$deliveryAddressDb = $this->manager->getRepository(DeliveryAddress::class)->find($request->request->get('deliveryAddress'));$cartFinished->setDeliveryAddress($deliveryAddressDb);if ($request->request->get('addressCheck') == "true") {$cartFinished->setDeliveryBillingAddress($deliveryAddressDb);$addressBilling = $deliveryAddressDb;} else {$addressBilling = $this->manager->getRepository(DeliveryAddress::class)->find($request->request->get('deliveryBilling'));$cartFinished->setDeliveryBillingAddress($addressBilling);}if ($request->request->get('totalPriceProductLowVatHtva') != 0) {$cartFinished->setTotalPriceProductLowVatHtva($request->request->get('totalPriceProductLowVatHtva'));$cartFinished->setTotalPriceProductLowVatTvac($request->request->get('totalPriceProductLowVatTvac'));} else {$cartFinished->setTotalPriceProductLowVatHtva(0);$cartFinished->setTotalPriceProductLowVatTvac(0);}if ($request->request->get('totalPriceProductHighVatHtva') != 0) {$cartFinished->setTotalPriceProductHighVatHtva($request->request->get('totalPriceProductHighVatHtva'));$cartFinished->setTotalPriceProductHighVatTvac($request->request->get('totalPriceProductHighVatTvac'));} else {$cartFinished->setTotalPriceProductHighVatHtva(0);$cartFinished->setTotalPriceProductHighVatTvac(0);}$cartFinished->setTotalPriceAllProductHtva($request->request->get('totalPriceAllProductHtva'));$cartFinished->setTotalPriceTvacWithRebate($request->request->get('totalPriceTvacWithRebate'));$cartFinished->setTotalRebate(floatval($request->request->get('totalRemise')));$cartFinished->setPourcentRebate($defaultRebatePercent);$cartFinished->setTotalPaid(floatval($request->request->get('totalPriceWithVat')));$dateFormatted = date('d-m-Y'); // Récupère la date du jour formatée "d-m-Y"$dateObject = \DateTime::createFromFormat('d-m-Y', $dateFormatted);$cartFinished->setCommandDate($dateObject);if ($request->request->get('joker') == "true") {$joker = $this->manager->getRepository(Joker::class)->findOneBy(array('user' => $user));if ($joker !== null && $joker->getNumberJoker() > 0) {$joker->setNumberJoker($joker->getNumberJoker() - 1);$cartFinished->setUsedJoker(1);$jokerFact = 'Oui';} else {$cartFinished->setUsedJoker(0);$jokerFact = 'Non';}} else {$cartFinished->setUsedJoker(0);$jokerFact = 'Non';}$jokerUsedForDelivery = ($jokerFact === 'Oui');$duplicateOrder = $this->manager->getRepository(CartFinished::class)->findOneBy(['user' => $user,'commandId' => $commandId,]);if ($duplicateOrder !== null) {return new JsonResponse('ok', headers: ['Content-Type' => 'application/json;charset=UTF-8']);}$this->manager->persist($cartFinished);foreach ($articles as $item) {$item->setFinish(true);}$this->manager->flush();$imagePath = $this->getParameter('kernel.project_dir') . '/public/uploads/img/media/logo-naturamedicatrix-pro-v2.png';// Création du PDF$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);$pdf->SetTitle('Facture');$pdf->SetPrintHeader(false);$pdf->setPrintFooter(false);$pdf->SetMargins(10, 10, 10);$pdf->AddPage();// Ajout de l'image centrée en haut$pdf->Image($imagePath, 80, 0, 50, 0, 'PNG', '', 'C');// Ajout des adresses de livraison et de facturation$pdf->SetFont('helvetica', 'B', 12);$pdf->Ln(5); // Espace après l'image$companyName = $addressDelivery->getCompanyName();// Adresse de livraison$pdf->SetFont('helvetica', 'B', 12);$pdf->Cell(130, 10, 'Adresse de livraison', 0, 0, 'L');$pdf->Cell(80, 10, 'Adresse de facturation', 0, 0, 'L');$pdf->Ln(5);$pdf->SetFont('helvetica', '', 12);$deliveryAddress = $addressDelivery->getFirstName() . ' ' . $addressDelivery->getName();$billingAddress = $addressBilling->getFirstName() . ' ' . $addressBilling->getName();$pdf->Cell(130, 10, $companyName, 0, 0, 'L');$pdf->Cell(80, 10, $companyName, 0, 0, 'L');$pdf->Ln(5);$pdf->Cell(130, 10, $deliveryAddress, 0, 0, 'L');$pdf->Cell(80, 10, $billingAddress, 0, 0, 'L');$pdf->Ln(5);$pdf->SetFont('helvetica', '', 12);$pdf->Cell(130, 10, $addressDelivery->getAddress(), 0, 0, 'L');$pdf->Cell(80, 10, $addressBilling->getAddress(), 0, 0, 'L');$pdf->Ln(5);$pdf->SetFont('helvetica', '', 12);$pdf->Cell(130, 10, $addressDelivery->getTown() . ' ' . $addressDelivery->getPostal() . ' ' . $addressDelivery->getCountry(), 0, 0, 'L');$pdf->Cell(80, 10, $addressBilling->getTown() . ' ' . $addressDelivery->getPostal() . ' ' . $addressBilling->getCountry(), 0, 0, 'L');$pdf->Ln(5);// $pdf->SetFont('helvetica', '', 12);// $pdf->Cell(130, 10, "", 0, 0, 'L');// $pdf->Cell(80, 10, 'TVA : ' . $additionalInformation->getTva(), 0, 0, 'L');$pdf->Ln(5);if ($daysTrue != null) {$pdf->SetFont('helvetica', '', 12);$pdf->Cell(130, 5, "Préférences jours et heures de livraison :", 0, 0, 'L');// $pdf->Cell(80, 10, 'Jour livraison : ' . implode(', ', $daysTrue), 0, 0, 'L');// $pdf->Cell(80, 10, 'Jour livraison : ', 0, 0, 'L');$pdf->Ln(5);foreach ($daysTrue as $day => $hours) {$morningHours = $hours['morning']['start'] . ' - ' . $hours['morning']['end'];$afternoonHours = $hours['afternoon']['start'] . ' - ' . $hours['afternoon']['end'];$pdf->Cell(0, 5, $day . ': Matin ' . $morningHours . ', Après-midi ' . $afternoonHours, 0, 1, 'L');}$pdf->Ln(3);}// Ajout du nom du client et numéro de commande$pdf->SetFont('helvetica', '', 12);// $pdf->Ln(10); // Espace après les adresses$pdf->Cell(140, 5, 'Client: ' . $additionalInformation->getCompanyName(), 0, 0, 'L');$pdf->Cell(50, 5, 'Date commande: ' . $cartFinished->getCommandDate()->format('d/m/Y'), 0, 0, 'L');$pdf->Ln(5);// $pdf->Cell(0, 10, 'Date commande: ' . $cartFinished->getCommandDate()->format('d/m/Y'), 0, 1, 'L');if ($defaultRebatePercent != 0) {$pdf->Cell(0, 5, 'Votre commande avec votre remise de: ' . $defaultRebatePercent . "%", 0, 1, 'L');}$pdf->Cell(70, 5, 'Joker utilisé ? : ' . $jokerFact, 0, 0, 'L');if ($request->get('messageNewRef') != "") {$pdf->Ln(5);$pdf->MultiCell(0, 5, 'Nouvelle référence ? : ' . $request->get('messageNewRef'), 0, 'L');// $pdf->Cell(70, 5, 'Nouvelle référence ? : ' . $request->get('messageNewRef'), 0, 0, 'L');}// Ajout du tableau des articles$pdf->SetFont('helvetica', '', 7);$pdf->Ln(10); // Espace après le titre$pdf->Cell(50, 5, 'Article', 1, 0, 'C');$pdf->Cell(30, 5, 'n° lot', 1, 0, 'C');$pdf->Cell(30, 5, 'Prix professionnel remisé', 1, 0, 'C');$pdf->Cell(20, 5, 'Quantité', 1, 0, 'C');$pdf->Cell(30, 5, 'Remise augmentée', 1, 0, 'C');$pdf->Cell(30, 5, 'Sous-total(HTVA)', 1, 0, 'C');$pdf->SetFont('helvetica', '', 10);$pdf->Ln(5);$productInfo = [];$faReference = ['NMJ007', 'NMJ008', 'NMJ011', 'NMJ084', 'NMJ013', 'NMJ056', 'NMJ040'];$countFaInCart = 0;foreach ($articles as $item) {if ($item->getProducts()->getReference() != null) {if (in_array($item->getProducts()->getReference(), $faReference) && $item->getQuantity() > 1) {$countFaInCart += $item->getQuantity();}}}$numberOfFaRef = null;if ($countFaInCart >= 2) {$numberOfFaRef = floor($countFaInCart / 2);}$flyersProduct = $this->manager->getRepository(Products::class)->findOneBy(array('reference' => 'NMZZ21'));$excludedProducts = $this->manager->getRepository(Rebate::class)->getExcludedProducts();$lotsOrderedQuantity = [];foreach ($articles as $article) {$shockActions = $article->getProducts()->getActionShockCalendar();$shockAction = null;if (count($shockActions) > 0) {$shockAction = $shockActions[0];}$shockActionPercent = $shockAction ? $shockAction->getDiscountPercent() : 0;$shockActionType = $shockAction ? $shockAction->getType() : null;$rebatePercent = $defaultRebatePercent;// Vérifier d'abord si le produit a une promotion spéciale$checkSpecialDiscount = $this->manager->getRepository(SpecialDiscount::class)->findOneBy(array('product' => $article->getProducts()));// Si le produit est dans la liste des exclus mais qu'il a une promotion spéciale// et que sa quantité est inférieure à 12, on le laisse bénéficier de la remise globaleif (in_array($article->getProducts()->getReference(), $excludedProducts) &&!($checkSpecialDiscount != null && $article->getQuantity() < 12)) {$rebatePercent = 0;}foreach ($specificRebates as $rebate) {if (in_array($article->getProducts()->getReference(), $rebate->getSpecificProducts()) && $article->getQuantity() >= $rebate->getMin()) {$rebatePercent = $rebate->getPourcentRebate();break;}}$productIdMercator = $article->getProducts()->getIdProductOnMercator();// Déterminez si c'est une newRef (basé sur l'historique local)$isNewRef = !in_array($productIdMercator, $localHistoryProductIds);$productName = $article->getProducts()->getName();$quantity = $article->getQuantity();$productInfo[$productName]['noLot'] = null;$lotss = [];foreach ($lotNumbersFromRequest as $lot) {$checkArticle = $this->manager->getRepository(LotNumber::class)->findBy(array('lotNumber' => $lot, 'folderMercator' => $folderMercatorValue));$lotss[] = $checkArticle;}foreach ($lotss as $lots) {foreach ($lots as $lot) {if ($lot->getProducts()->getName() == $article->getProducts()->getName()) {$productInfo[$productName]['noLot'] = $lot->getLotNumber();if (!in_array($lot->getDepot(), LotNumber::EXCLUDED_DEPOTS)) {$lotsOrderedQuantity[] = ['product' => $article->getProducts(),'lot_number' => $lot->getLotNumber(),'ordered_quantity' => $article->getQuantity(),'depot' => $lot->getDepot(),'folderMercator' => $folderMercatorValue,];}}}}if (empty($productInfo[$productName]['noLot'])) {$dlus = $this->manager->getRepository(LotNumber::class)->findBy(['products' => $article->getProducts(),'folderMercator' => $folderMercatorValue,]);$maxDlu = null;foreach ($dlus as $dlu) {$dluDate = $dlu->getDlu();if ($maxDlu === null || ($dluDate !== null && $dluDate > $maxDlu)) {$maxDlu = $dluDate;$productInfo[$productName]['noLot'] = $dlu->getLotNumber();}}}if ($checkSpecialDiscount != null && $article->getQuantity() > 11) {$productPrice = $article->getProducts()->getPublicPrice();} else {$productPrice = $article->getProducts()->getPrice();$checkSpecialDiscount = null;}$productBrandName = $article->getProducts()->getBrand();$pourcentNatura = null; // Initialisation par défautif (strcasecmp($productBrandName, 'NaturaMedicatrix') === 0) {// Pour les nouvelles références, appliquer la remise NaturaMedicatrix même si rebatePercent = 0$effectiveRebateForNatura = $rebatePercent;if ($isNewRef && $quantity >= 2 && $rebatePercent == 0) {$effectiveRebateForNatura = 13;}if ($effectiveRebateForNatura >= 19) {$pourcentNatura = $this->manager->getRepository(BrandDiscount::class)->findOneBy(array('brandName' => 'NaturaMedicatrix'));$pourcentNatura = $pourcentNatura->getRebateHeigh();} elseif ($effectiveRebateForNatura >= 13) {$pourcentNatura = $this->manager->getRepository(BrandDiscount::class)->findOneBy(array('brandName' => 'NaturaMedicatrix'));$pourcentNatura = $pourcentNatura->getRebateLow();}}if ($request->get('messageNewRef') != "") {$article->setMessage($request->get('messageNewRef'));$this->manager->flush();}$actionShock = $article->getProducts()->getActionShock();$productInfo[$productName] = ['brand' => $productBrandName,'price' => $productPrice,'quantity' => $quantity,'noLot' => $productInfo[$productName]['noLot'] ?? '','reference' => $article->getProducts()->getReference(),'specialDiscount' => $checkSpecialDiscount,'rebatePercent' => $rebatePercent,'newRef' => $isNewRef,'actionShock' => $actionShock,'shockActionPercent' => $shockActionPercent,'shockActionType' => $shockActionType,];$priceTotal = $productPrice * $quantity;$minQuantity = $isNewRef ? 2 : 4;// Pour les nouvelles références avec qté >= 2, appliquer 13% même si defaultRebatePercent = 0$effectiveRebatePercent = $rebatePercent;if ($isNewRef && $quantity >= 2 && $rebatePercent == 0) {$effectiveRebatePercent = 13;}// Priorité 1 : NaturaMedicatrix (vérifier en premier)// DEBUG - Stocker les valeurs pour affichageif (strcasecmp($productInfo[$productName]['brand'], 'NaturaMedicatrix') === 0 && $isNewRef) {$productInfo[$productName]['debug'] = "effectiveRebate=$effectiveRebatePercent, qty=$quantity, minQty=$minQuantity, pourcentNatura=$pourcentNatura, specialDiscount=" . ($checkSpecialDiscount ? 'NOT NULL' : 'NULL') . ", actionShock=" . ($productInfo[$productName]['actionShock'] ? 'true' : 'false');}if ($effectiveRebatePercent != 0 && $effectiveRebatePercent != null && !$productInfo[$productName]['actionShock'] && $quantity >= $minQuantity && $checkSpecialDiscount == null && strcasecmp($productInfo[$productName]['brand'], 'NaturaMedicatrix') === 0) {$totalRebate = floatval(number_format(($priceTotal / 100) * ($pourcentNatura + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0)), 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($priceTotal - $totalRebate, 2, '.', ''));}// Priorité 2 : Autres marqueselseif ($effectiveRebatePercent != 0 && $effectiveRebatePercent != null && !$productInfo[$productName]['actionShock'] && $quantity >= $minQuantity && $checkSpecialDiscount == null && $pourcentNatura == null) {$totalRebate = floatval(number_format(($priceTotal / 100) * ($effectiveRebatePercent + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0)), 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($priceTotal - $totalRebate, 2, '.', ''));}// Priorité 3 : Action chocelseif ($effectiveRebatePercent != 0 && $effectiveRebatePercent != null && $productInfo[$productName]['actionShock'] && $quantity >= $minQuantity) {$totalRebate = floatval(number_format(($priceTotal / 100) * ($shockActionPercent + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0)), 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($priceTotal - $totalRebate, 2, '.', ''));} elseif ($productInfo[$productName]['actionShock'] && $quantity >= $minQuantity) {$totalRebate = floatval(number_format(($priceTotal / 100) * ($shockActionPercent + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0)), 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($priceTotal - $totalRebate, 2, '.', ''));} elseif (!$productInfo[$productName]['actionShock'] && $quantity > 11 && $checkSpecialDiscount != null) {$totalRebate = floatval(number_format(($priceTotal / 100) * ($checkSpecialDiscount->getPourcentRebate() + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0)), 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($priceTotal - $totalRebate, 2, '.', ''));} elseif ($quantity > 1 && $isNewRef && $totalCartQuantity >= 12) {$productInfo[$productName]['priceTotal'] = $productPrice * $quantity;$rebateNewRef = floatval(number_format(($productInfo[$productName]['priceTotal'] / 100) * 2, 2, '.', ''));$productInfo[$productName]['priceTotal'] = floatval(number_format($productInfo[$productName]['priceTotal'] - $rebateNewRef, 2, '.', ''));} else {$productInfo[$productName]['priceTotal'] = $productPrice * $quantity;}// Vérifier s'il y a des produits gratuits correspondant au produit actuelforeach ($freeProducts as $freeProduct) {if ($freeProduct['name'] === $productName) {$productInfo[$productName]['free'] = $freeProduct['free'];}}}foreach ($lotsOrderedQuantity as $ordered) {$lotNumber = $this->manager->getRepository(LotNumber::class)->findOneBy(['products' => $ordered['product'],'lotNumber' => $ordered['lot_number'],'depot' => $ordered['depot'],'folderMercator' => $ordered['folderMercator'],]);if (!$lotNumber) {continue;}$lotNumber->setStock($lotNumber->getStock() - $ordered['ordered_quantity']);$this->manager->persist($lotNumber);}$this->manager->flush();// Calcul du nombre de flyers (Formule Alcalisante)$numberOfFaRef = null;$countFaInCart = 0;$flyersProduct = $this->manager->getRepository(Products::class)->findOneBy(['reference' => 'NMZZ21']);// Tableau des références de produits Formule Alcalisante$faReference = ['NMJ007', 'NMJ008', 'NMJ011', 'NMJ084', 'NMJ013', 'NMJ056', 'NMJ040'];// Compte le nombre de Formule Alcalisanteforeach ($articles as $item) {if (in_array($item->getProducts()->getReference(), $faReference)) {$countFaInCart += $item->getQuantity();}}// Calcul du nombre de flyers gratuits (1 par 2 FA)if ($countFaInCart >= 2) {$numberOfFaRef = floor($countFaInCart / 2);}// Respect de la préférence utilisateurif (!$request->getSession()->has('wantFlyers') || !$request->getSession()->get('wantFlyers')) {$numberOfFaRef = null;}$shockActionTypes = ActionShock::TYPES;// Fonction helper pour calculer la hauteur nécessaire pour un texte multicell$getMultiCellHeight = function($pdf, $w, $txt) {$cw = $pdf->GetStringWidth($txt);if ($cw == 0) {return 0;}$ratio = $w / $cw;$lines = ceil(1 / $ratio);return $lines * 5; // 5 est la hauteur de base d'une ligne};// Affiche les informations dans le PDFforeach ($productInfo as $productName => $info) {$productRebatePercent = $info['rebatePercent'];if ($info['actionShock']) {$shockActionName = $shockActionTypes[$info['shockActionType']->value];}$freeQuantity = isset($info['free']) ? (int) $info['free'] : 0;if ($info['actionShock']) {$pdf->SetFont('helvetica', '', 7);$productText = $productName . ' (' . $info['reference'] . ') - ' . $shockActionName;// Commence une nouvelle ligne$pdf->Ln(0);$x = $pdf->GetX();$y = $pdf->GetY();// Calcule la hauteur nécessaire pour le texte$height = max(5, $getMultiCellHeight($pdf, 50, $productText));// Cellule pour le nom du produit avec référence$pdf->MultiCell(50, $height, $productText, 1, 'C');// Repositionne pour les cellules suivantes$pdf->SetXY($x + 50, $y);} elseif (!$info['actionShock'] && $info['specialDiscount'] != null && $info['quantity'] > 11) {$pdf->SetFont('helvetica', '', 7);$productText = $productName . ' (' . $info['reference'] . ') - ' . 'PROMO « SPECIALE »';// Commence une nouvelle ligne$pdf->Ln(0);$x = $pdf->GetX();$y = $pdf->GetY();// Calcule la hauteur nécessaire pour le texte$height = max(5, $getMultiCellHeight($pdf, 50, $productText));// Cellule pour le nom du produit avec référence$pdf->MultiCell(50, $height, $productText, 1, 'C');// Repositionne pour les cellules suivantes$pdf->SetXY($x + 50, $y);} else {$pdf->SetFont('helvetica', '', 7);$productText = $productName . ' (' . $info['reference'] . ')';// Commence une nouvelle ligne$pdf->Ln(0);$x = $pdf->GetX();$y = $pdf->GetY();// Calcule la hauteur nécessaire pour le texte$height = max(5, $getMultiCellHeight($pdf, 50, $productText));// Cellule pour le nom du produit avec référence$pdf->MultiCell(50, $height, $productText, 1, 'C');// Repositionne pour les cellules suivantes$pdf->SetXY($x + 50, $y);}// Utilise la même hauteur pour les cellules suivantes$pdf->Cell(30, $height, "lot : " . $info['noLot'], 1, 0, 'C');$pdf->Cell(30, $height, $info['price'] . "€", 1, 0, 'C');$pdf->Cell(20, $height, $info['quantity'], 1, 0, 'C');$minQuantityPdf = $info['newRef'] ? 2 : 4;if ($info['specialDiscount'] != null && $info['quantity'] > 11) {$pdf->Cell(30, $height, $info['specialDiscount']->getPourcentRebate() . '%', 1, 0, 'C');} elseif ($info['actionShock'] != null && $info['shockActionPercent']) {$pdf->Cell(30, $height, ($info['shockActionPercent'] + (($info['newRef'] && $totalCartQuantity >= 12) ? 2 : 0)) . '%', 1, 0, 'C');} elseif (strcasecmp($info['brand'], 'NaturaMedicatrix') === 0 && $info['quantity'] >= $minQuantityPdf && $productRebatePercent != 0) {$rebateNatura = $this->manager->getRepository(BrandDiscount::class)->findOneBy(array('active' => true, 'brandName' => 'NaturaMedicatrix'));if ($rebateNatura && $productRebatePercent == 13) {if ($info['newRef'] && $totalCartQuantity >= 12) {$pdf->Cell(30, $height, $rebateNatura->getRebateLow() + 2 . '%', 1, 0, 'C');} else {$pdf->Cell(30, $height, $rebateNatura->getRebateLow() . '%', 1, 0, 'C');}} elseif ($rebateNatura && $productRebatePercent == 19) {if ($info['newRef'] && $totalCartQuantity >= 12) {$pdf->Cell(30, $height, $rebateNatura->getRebateHeigh() + 2 . '%', 1, 0, 'C');} else {$pdf->Cell(30, $height, $rebateNatura->getRebateHeigh() . '%', 1, 0, 'C');}} else {$pdf->Cell(30, $height, '0' . '%', 1, 0, 'C');}} elseif ($productRebatePercent != 0 && $info['quantity'] >= $minQuantityPdf) {if ($info['newRef'] && $totalCartQuantity >= 12) {$pdf->Cell(30, $height, $productRebatePercent + 2 . '%', 1, 0, 'C');} else {$pdf->Cell(30, $height, $productRebatePercent . '%', 1, 0, 'C');}} elseif ($info['newRef'] && $info['quantity'] > 1 && $totalCartQuantity >= 12) {$pdf->Cell(30, $height, '2%', 1, 0, 'C');} else {$pdf->Cell(30, $height, '0', 1, 0, 'C');}// Calculer le pourcentage total pour l'affichage$totalDiscountPercent = 0;if ($info['specialDiscount'] != null && $info['quantity'] > 11) {$totalDiscountPercent = $info['specialDiscount']->getPourcentRebate();} elseif ($info['actionShock'] != null && $info['shockActionPercent']) {$totalDiscountPercent = $info['shockActionPercent'] + (($info['newRef'] && $totalCartQuantity >= 12) ? 2 : 0);} elseif (strcasecmp($info['brand'], 'NaturaMedicatrix') === 0 && $info['quantity'] >= $minQuantityPdf && $productRebatePercent != 0) {$rebateNatura = $this->manager->getRepository(BrandDiscount::class)->findOneBy(array('active' => true, 'brandName' => 'NaturaMedicatrix'));if ($rebateNatura && $productRebatePercent == 13) {$totalDiscountPercent = $rebateNatura->getRebateLow() + (($info['newRef'] && $totalCartQuantity >= 12) ? 2 : 0);} elseif ($rebateNatura && $productRebatePercent == 19) {$totalDiscountPercent = $rebateNatura->getRebateHeigh() + (($info['newRef'] && $totalCartQuantity >= 12) ? 2 : 0);}} elseif ($productRebatePercent != 0 && $info['quantity'] >= $minQuantityPdf) {$totalDiscountPercent = $productRebatePercent + (($info['newRef'] && $totalCartQuantity >= 12) ? 2 : 0);} elseif ($info['newRef'] && $info['quantity'] > 1 && $totalCartQuantity >= 12) {$totalDiscountPercent = 2;}if ($totalDiscountPercent > 0) {$pdf->Cell(30, $height, $info['priceTotal'] . "€ (-" . $totalDiscountPercent . "% inclus)", 1, 0, 'C');$pdf->Ln($height);} else {$pdf->Cell(30, $height, $info['priceTotal'] . "€", 1, 0, 'C');$pdf->Ln($height);}if ($freeQuantity > 0) {$pdf->SetFont('helvetica', '', 7);$productTextFree = $productName . ' (' . $info['reference'] . ') - OFFERT';$xFree = $pdf->GetX();$yFree = $pdf->GetY();$heightFree = max(5, $getMultiCellHeight($pdf, 50, $productTextFree));$pdf->MultiCell(50, $heightFree, $productTextFree, 1, 'C');$pdf->SetXY($xFree + 50, $yFree);$pdf->Cell(30, $heightFree, "lot : " . $info['noLot'], 1, 0, 'C');$pdf->Cell(30, $heightFree, "0€", 1, 0, 'C');$pdf->Cell(20, $heightFree, $freeQuantity, 1, 0, 'C');$pdf->Cell(30, $heightFree, "0", 1, 0, 'C');$pdf->Cell(30, $heightFree, "0€", 1, 0, 'C');$pdf->Ln($heightFree);}}if ((int)$numberOfFaRef > 0 && $flyersProduct !== null) {$pdf->SetFont('helvetica', '', 7);$pdf->Cell(50, 5, $flyersProduct->getName(), 1, 0, 'C');$pdf->Cell(30, 5, "ref : " . $flyersProduct->getReference(), 1, 0, 'C');$pdf->Cell(30, 5, "0 €", 1, 0, 'C');$pdf->Cell(20, 5, (int)$numberOfFaRef, 1, 0, 'C');}$pdf->Ln(5);$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Produits HTVA ' . $tvaLow . '%: ' . floatval(number_format($request->request->get('totalPriceProductLowVatHtva'), 2, '.', '')) . "€", 1, 0, 'L');$pdf->Ln(5);$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Produits HTVA ' . $tvaHigh . '%: ' . floatval(number_format($request->request->get('totalPriceProductHighVatHtva'), 2, '.', '')) . "€", 1, 0, 'L');$pdf->Ln(5);$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Total (HTVA): ' . floatval(number_format($request->request->get('totalPriceAllProductHtva'), 2, '.', '')) . "€", 1, 0, 'L');$pdf->Ln(5);$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'TVA ' . $tvaLow . '%: ' . floatval(number_format($request->request->get('totalPriceProductLowVatTvac'), 2, '.', '')) . "€", 1, 0, 'L');$pdf->Ln(5);$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'TVA ' . $tvaHigh . '%: ' . floatval(number_format($request->request->get('totalPriceProductHighVatTvac'), 2, '.', '')) . "€", 1, 0, 'L');$pdf->Ln(5);if ($jokerUsedForDelivery) {$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Frais livraison : GRATUIT (Joker)', 1, 0, 'L');$pdf->Ln(5);$pdf->SetFont('helvetica', 'B', 12);$pdf->Cell(140, 5, 'Total TTC', 1, 0, 'C');$pdf->Cell(50, 5, floatval(number_format($request->request->get('totalPriceTvacWithRebate'), 2, '.', '')) . "€", 1, 1, 'C');} elseif (floatval($request->request->get('totalPriceTvacWithRebate')) < floatval($costDelivery->getFrancoDelivery())) {$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Frais livraison : ' . $costDelivery->getCostDelivery() . '€', 1, 0, 'L');$pdf->Ln(5);// Ajout du total$totalCost = $request->request->get('totalPriceTvacWithRebate') + $costDelivery->getCostDelivery();$pdf->SetFont('helvetica', 'B', 12);$pdf->Cell(140, 5, 'Total TTC', 1, 0, 'C');$pdf->Cell(50, 5, $totalCost . "€", 1, 1, 'C');} else {$pdf->Cell(140, 5, "", 0, 0, 'C');$pdf->Cell(50, 5, 'Frais livraison : GRATUIT (Franco 300€)', 1, 0, 'L');$pdf->Ln(5);// Ajout du total$pdf->SetFont('helvetica', 'B', 12);$pdf->Cell(140, 5, 'Total TTC', 1, 0, 'C');$pdf->Cell(50, 5, floatval(number_format($request->request->get('totalPriceTvacWithRebate'), 2, '.', '')) . "€", 1, 1, 'C');}// Juste avant de sauvegarder ou de sortir le PDF, ajoutez votre pied de page$pdf->SetY(-55); // Positionner le curseur 60 mm du bas de la page$pdf->SetFont('helvetica', '', 10);$pdf->SetFont('helvetica', 'B', 10); // Gras pour NATURAMedicatrix$pdf->Cell(0, 5, "NATURAMedicatrix srl", 0, 1, 'C');$pdf->SetFont('helvetica', '', 10); // Normal pour le reste de l'adresse$pdf->Cell(0, 5, "22, route de Fagnes, B-4190 Ferrières, Belgique", 0, 1, 'C');$pdf->Cell(0, 5, "TVA BE 0543.862.766", 0, 1, 'C');$pdf->Ln(4); // Un peu d'espace avant la prochaine section$pdf->SetFont('helvetica', 'B', 10); // Gras pour NATURAMedicatrix$pdf->Cell(0, 5, "NATURAMedicatrix sàrl", 0, 1, 'C');$pdf->SetFont('helvetica', '', 10); // Normal pour le reste de l'adresse$pdf->Cell(0, 5, "8 Hannert dem Duarref, L-9772 Troine (Wincrange), Luxembourg -", 0, 1, 'C');$pdf->Cell(0, 5, "TVA: LU26788281 - MATRICULE:20142414296", 0, 1, 'C');// Nom du fichier PDF$pdfFilename = trim($additionalInformation->getCompanyName()) . '_' . trim($user->getId()) . '_' . trim(str_replace(' ', '', $request->request->get('idCommande'))) . '.pdf';// Enregistrement du PDF dans le dossier public/factures/$pdfPath = $this->getParameter('factures_directory') . $pdfFilename;$facturesDirectory = $this->getParameter('factures_directory');if (!is_dir($facturesDirectory)) {mkdir($facturesDirectory, 0755, true);}$pdf->Output($pdfPath, 'F');$this->createNewBilling($pdfFilename, $user, $request->request->get('totalPriceTvacWithRebate'), $cartFinished->getCommandDate()->format('d/m/Y'));// E-mail du client$clientEmail = $user->getEmail();$email = (new Email())->from('info@b2bnaturamedicatrix.com')->to($clientEmail)->subject('Bon de commande B2B')->text('Veuillez trouver ci-joint le bon de commande en pdf.')->attachFromPath($pdfPath, $pdfFilename, 'application/pdf');foreach ($orderRecipientEmails as $recipient) {$email->addCc($recipient);}$mailer->send($email);// ========== ENVOI COMMANDE VERS API MERCATOR ==========$this->sendOrderToMercator($jwtToken,$additionalInformation,$folderMercatorValue,$countryShip,$addressDelivery,$articles,$productInfo,$defaultRebatePercent,$pourcentSpecialCustomer,$cartFinished,$lotNumbersFromRequest,$jokerUsedForDelivery,floatval($request->request->get('totalPriceTvacWithRebate')),floatval($costDelivery->getFrancoDelivery()),floatval($costDelivery->getCostDelivery()),$totalCartQuantity);$this->addFlash('success', 'Commande passée avec succès.');return new JsonResponse('ok', headers: ['Content-Type' => 'application/json;charset=UTF-8']);}/*** Envoie la commande vers l'API Mercator /Order*/private function sendOrderToMercator(string $jwtToken,AdditionalCompanyInformation $additionalInformation,string $folderMercatorValue,string $countryShip,DeliveryAddress $addressDelivery,array $articles,array $productInfo,float $defaultRebatePercent,$pourcentSpecialCustomer,CartFinished $cartFinished,array $lotNumbers,bool $jokerUsedForDelivery = false,float $totalPriceTvac = 0,float $francoDelivery = 300,float $costDelivery = 15,int $totalCartQuantity = 0): void {// Validation : le client doit avoir un ID Mercatorif (empty($additionalInformation->getIdClientMercator())) {error_log("Erreur envoi Mercator: Client sans ID Mercator - User ID: " . $additionalInformation->getUser()->getId());return;}try {// Construction de la requête$data = ['headers' => ['Authorization' => 'Bearer ' . $jwtToken,],'json' => ["customerId" => $additionalInformation->getIdClientMercator(),"reference" => "B2B-" . $cartFinished->getCommandId(),"mercator" => $folderMercatorValue,"shippingInfo" => ["firstName" => $addressDelivery->getFirstName() ?? "","lastName" => $addressDelivery->getName() ?? "","company" => $addressDelivery->getCompanyName() ?? "","address1" => $addressDelivery->getAddress() ?? "","address2" => "","postalCode" => $addressDelivery->getPostal() ?? "","city" => $addressDelivery->getTown() ?? "","phone" => $addressDelivery->getPhoneNumber() ?? "","mobile" => "","country" => $countryShip,"note" => "Commande B2B #" . $cartFinished->getCommandId()],"lines" => []]];// Récupération des lots pour ce dossier Mercator// On utilise $productInfo qui contient déjà le bon noLot par produit (résolu via matching par nom)$lotsMap = [];foreach ($articles as $articleForLot) {$productForLot = $articleForLot->getProducts();$productNameForLot = $productForLot->getName();if (isset($productInfo[$productNameForLot]['noLot']) && !empty($productInfo[$productNameForLot]['noLot'])) {$lot = $this->manager->getRepository(LotNumber::class)->findOneBy(['products' => $productForLot,'lotNumber' => $productInfo[$productNameForLot]['noLot'],'folderMercator' => $folderMercatorValue]);if ($lot !== null) {$lotsMap[$productNameForLot] = $lot;}}}$freeLinesAdded = [];// Construction des lignes de commandeforeach ($articles as $article) {$product = $article->getProducts();$productName = $product->getName();// Validation : le produit doit avoir un ID Mercatorif (empty($product->getIdProductOnMercator())) {error_log("Erreur envoi Mercator: Produit sans ID Mercator - " . $productName);continue;}// Récupération du lot pour ce produit$lotId = "";if (isset($lotsMap[$productName])) {$lot = $lotsMap[$productName];$candidateLotId = $lot->getIdLotMercator();// Valider que le lotId n'est pas un fallback (= ID produit Mercator)// Le fallback est assigné quand Mercator n'a pas de numéro de lot (iD_LOT null)if (!empty($candidateLotId) && $candidateLotId !== strval($product->getIdProductOnMercator())) {$lotId = $candidateLotId;}}// Validation : le lot doit exister et être un vrai numéro de lotif (empty($lotId)) {error_log("Erreur envoi Mercator: Lot non trouvé ou invalide pour produit - " . $productName);continue;}// Calcul du discount$discount = $this->calculateMercatorDiscount($productName,$productInfo,$defaultRebatePercent,$pourcentSpecialCustomer,$totalCartQuantity);// Détermination de la promotion spéciale$specialPromotion = false;if (isset($productInfo[$productName])) {$info = $productInfo[$productName];if (isset($info['specialDiscount']) && $info['specialDiscount'] !== null && $info['quantity'] > 11) {$specialPromotion = true;}}$line = ["productId" => strval($product->getIdProductOnMercator()),"quantity" => $article->getQuantity(),"discount" => intval($discount),"lotId" => $lotId,"specialPromotion" => $specialPromotion];$data['json']['lines'][] = $line;// Ajout d'une ligne OFFERT si applicable (remise 100%)// La quantité gratuite est calculée côté B2B (checkFreeProduct) et stockée dans $productInfo[$productName]['free']// On utilise l'ID produit Mercator comme clé pour éviter les doublons liés aux variations de nom$productMercatorId = strval($product->getIdProductOnMercator());if (!isset($freeLinesAdded[$productMercatorId])&& isset($productInfo[$productName]['free'])&& (int) $productInfo[$productName]['free'] > 0) {$freeLine = ["productId" => strval($product->getIdProductOnMercator()),"quantity" => (int) $productInfo[$productName]['free'],"discount" => 100,"lotId" => $lotId,"specialPromotion" => false];$data['json']['lines'][] = $freeLine;$freeLinesAdded[$productMercatorId] = true;}}// Ajout des frais de port (produit 55) si < franco et pas de joker utiliséif (!$jokerUsedForDelivery && $totalPriceTvac < $francoDelivery) {$shippingLine = ["productId" => "55","quantity" => 1,"discount" => 0,"lotId" => "","specialPromotion" => false];$data['json']['lines'][] = $shippingLine;}// Validation : au moins une ligne de commandeif (empty($data['json']['lines'])) {error_log("Erreur envoi Mercator: Aucune ligne de commande valide - Commande B2B #" . $cartFinished->getCommandId());return;}// Log avant envoierror_log("Envoi commande Mercator - Client: " . $additionalInformation->getIdClientMercator() ." - Dossier: " . $folderMercatorValue ." - Commande B2B #" . $cartFinished->getCommandId() ." - Nb lignes: " . count($data['json']['lines']));// Envoi de la requête$response = $this->client->request('POST', 'https://ns3190747.ip-51-89-219.eu/Order', $data);$responseContent = $response->getContent();$statusCode = $response->getStatusCode();// Extraction de l'ID Mercator depuis la réponse// Format attendu: "1CB2B 26000063" ou JSON {"id": "..."}$mercatorOrderId = 'N/A';$responseData = json_decode($responseContent, true);if (is_array($responseData) && isset($responseData['id'])) {// Format JSON$mercatorOrderId = $responseData['id'];} elseif (is_string($responseContent)) {// Format string "1CB2B 26000063"$responseContent = trim(str_replace('"', '', $responseContent));if (preg_match('/(\d+)$/', $responseContent, $matches)) {$mercatorOrderId = $matches[1];} else {$mercatorOrderId = $responseContent;}}// Log succèserror_log("Commande Mercator envoyée avec succès - Status: " . $statusCode ." - ID Mercator: " . $mercatorOrderId);} catch (\Exception $e) {// Log erreur détailléerror_log("Erreur envoi commande Mercator - Client: " . $additionalInformation->getIdClientMercator() ." - Commande B2B #" . $cartFinished->getCommandId() ." - Erreur: " . $e->getMessage());}}/*** Calcule le discount à envoyer à Mercator pour un produit*/private function calculateMercatorDiscount(string $productName,array $productInfo,float $defaultRebatePercent,$pourcentSpecialCustomer,int $totalCartQuantity = 0): float {$discount = 0;if (!isset($productInfo[$productName])) {return $discount;}$info = $productInfo[$productName];$isNewRef = $info['newRef'] ?? false;// Utiliser la remise spécifique au produit si disponible (gère les produits exclus)$productRebatePercent = $info['rebatePercent'] ?? $defaultRebatePercent;// Déterminer le seuil de quantité : 2 pour nouvelle réf, 4 pour les autres$minQuantity = $isNewRef ? 2 : 4;// Priorité 1 : Remise spéciale (quantité > 11)if (isset($info['specialDiscount']) && $info['specialDiscount'] !== null && $info['quantity'] > 11) {$discount = $info['specialDiscount']->getPourcentRebate();}// Priorité 2 : Action choc (quantité >= minQuantity)elseif (isset($info['actionShock']) && $info['actionShock'] !== null && $info['actionShock'] === true && $info['quantity'] >= $minQuantity) {$discount = $info['shockActionPercent'] ?? 25;}// Priorité 3 : Remise par quantité (si pas action choc et quantité >= minQuantity)elseif ($productRebatePercent != 0 && $info['brand'] != "NaturaMedicatrix" && !$pourcentSpecialCustomer && $info['quantity'] >= $minQuantity) {$discount = $productRebatePercent;}// Priorité 4 : Remise NaturaMedicatrix (quantité >= minQuantity ET remise de base existe)elseif ($info['brand'] == "NaturaMedicatrix" && !$pourcentSpecialCustomer && $info['quantity'] >= $minQuantity && $productRebatePercent != 0) {$brandDiscount = $this->manager->getRepository(BrandDiscount::class)->findOneBy(['brandName' => 'NaturaMedicatrix']);if ($brandDiscount) {if ($productRebatePercent == 13) {$discount = $brandDiscount->getRebateLow();} elseif ($productRebatePercent == 19) {$discount = $brandDiscount->getRebateHeigh();}}}// Priorité 5 : Client spécial (quantité >= minQuantity)elseif ($productRebatePercent != 0 && $pourcentSpecialCustomer && $info['quantity'] >= $minQuantity) {$discount = is_numeric($pourcentSpecialCustomer) ? $pourcentSpecialCustomer : 0;}// Ajouter la remise de 2% pour les nouvelles références (seulement si >= 12 produits dans le panier)if ($isNewRef && $totalCartQuantity >= 12 && $discount > 0) {$discount += 2;} elseif ($isNewRef && $totalCartQuantity >= 12 && $discount == 0) {$discount = 2;}return $discount;}private function createNewBilling(string $billings, User $user, $totalPaid, $dateOrder): void{$billing = new Billings();$billing->setUser($user);$billing->setBilling($billings);$billing->setTotalPaid($totalPaid);$commandDate = \DateTime::createFromFormat('d/m/Y', $dateOrder);if ($commandDate) {$billing->setCommandDate($commandDate);}// $billing->setCommandDate($dateOrder);$this->manager->persist($billing);$this->manager->flush();}/*** Retourne le code dossier Mercator selon le pays du client* Belgique => BE, France/Luxembourg => LU*/private function getMercatorFolder(string $country): string{return $country === 'Belgique' ? 'BE' : 'LU';}/*** Retourne le code ISO du pays pour l'adresse de livraison*/private function getCountryCode(string $country): string{return match($country) {'France' => 'FR','Belgique' => 'BE','Luxembourg' => 'LU',default => 'LU'};}private function checkJokerAvailable($numberItems): bool{$joker = $this->manager->getRepository(Joker::class)->findOneBy(array('user' => $this->getUser()));if ($joker) {if ($numberItems <= 4 && $joker->getNumberJoker() > 0) {return true;} else {return false;}} else {return false;}}private function checkJokerNumber(): int{$joker = $this->manager->getRepository(Joker::class)->findOneBy(array('user' => $this->getUser()));return $joker->getNumberJoker();}private function retrieveCart(): array{$productEligibleReduction = null;$freeProduct = null;$pourcentSpecialCustomer = null;$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $this->getUser()));} else {$user = $checkControl->getCustomer();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $checkControl->getCustomer()));}if ($user->getSpecialCustomer()) {$checkUserSpecialEntity = $this->manager->getRepository(SpecialCustomer::class)->findOneBy(array('user' => $user, 'active' => true));if ($checkUserSpecialEntity == null) {$pourcentSpecialCustomer = $this->manager->getRepository(ConfigSite::class)->findAll();$pourcentSpecialCustomer = $pourcentSpecialCustomer[0];} else {$pourcentSpecialCustomer = $checkUserSpecialEntity->getPourcentRebate();}}$cart = $this->manager->getRepository(Cart::class)->getAllCart($user);$country = $additionalInformations->getCompanyCountry();$folderMercatorValue = $this->getMercatorFolder($country);// Récupérer l'historique local des commandes pour détecter les nouvelles références// L'API Mercator /OrderHistory retourne des IDs incompatibles avec idProductOnMercator$finishedCartItems = $this->manager->getRepository(Cart::class)->findBy(['user' => $user,'finish' => true]);$localHistoryProductIds = [];foreach ($finishedCartItems as $cartItem) {$productItem = $cartItem->getProducts();if ($productItem) {$localHistoryProductIds[] = $productItem->getIdProductOnMercator();}}$localHistoryProductIds = array_unique($localHistoryProductIds);foreach ($cart as &$item) {$product = $this->manager->getRepository(Products::class)->find($item['productId']);$dlus = $this->manager->getRepository(LotNumber::class)->findBy(['products' => $product, 'folderMercator' => $folderMercatorValue]);// Déterminer si c'est une nouvelle référence (basé sur l'historique local)$productIdMercator = $product->getIdProductOnMercator();$item['newRef'] = !in_array($productIdMercator, $localHistoryProductIds);// Convertir la collection en un simple tableau associatif$dlusArray = [];foreach ($dlus as $dlu) {$dlusArray[] = ['dlu' => $dlu->getDlu(),'lotNumber' => $dlu->getLotNumber()// Ajoutez d'autres propriétés de LotNumber ici si nécessaire// 'property_name' => $dlu->getPropertyName(),];}// Trouver la date la plus lointaine (la plus grande) dans le tableau $dlusArray$maxDlu = null;foreach ($dlusArray as $dluItem) {if ($maxDlu === null || $dluItem['dlu'] > $maxDlu) {$maxDlu = $dluItem['dlu'];$maxLotNumber = $dluItem['lotNumber'];}}// Mettre à jour le tableau $item avec la date la plus lointaine$item['dlus'] = ['dlu' => $maxDlu,'lotNumber' => $maxLotNumber,];// enlever le commentaire pour avoir toutes les dlus// $item['dlus'] = $dlusArray;}unset($item); // Dissocier la référence après la boucle foreach$count = 0;$grandTotalPrice = 0;foreach ($cart as $item) {if (intval($item['totalQuantity']) > 3) {$productEligibleReduction[] = $item;$count += $item['totalQuantity'];$grandTotalPrice += intval($item['price']) * intval($item['totalQuantity']);} else {$count += $item['totalQuantity'];$grandTotalPrice += intval($item['price']) * intval($item['totalQuantity']);}}$joker = $this->checkJokerAvailable($count);// nous renvoi le % de remise (quantité de produits)$rebate = $this->calculateRebate($pourcentSpecialCustomer);$carts = $this->calculatePriceHtvaWithRebateEachProduct($cart, $rebate);$freeTransport = $this->calculateFreeTransport($carts['totalPriceTvacWithRebate']);if ($rebate == null) {$rebate = 0;} else {$freeProduct = $this->checkFreeProduct($cart);}$missingItems = $this->calculateMissingItemsForNextRebate();return ['carts' => $carts,'rebate' => $rebate,'grandTotalPrice' => $grandTotalPrice,'freeProduct' => $freeProduct,'freeTransport' => $freeTransport,'joker' => $joker,'missingItems' => $missingItems];}private function calculateMissingItemsForNextRebate(){$cartCounts = $this->calculateCountItemInCart();$eligibleCount = $cartCounts['eligible'];$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();// Trier les remises par ordre croissant de minimum$rebatesArray = [];foreach ($rebates as $rebate) {$rebatesArray[] = ['min' => $rebate->getMin(),'percent' => $rebate->getPourcentRebate()];}usort($rebatesArray, function($a, $b) {return $a['min'] - $b['min'];});// Trouver la prochaine remise à atteindre$nextRebateMin = null;foreach ($rebatesArray as $rebate) {if ($eligibleCount < $rebate['min']) {$nextRebateMin = $rebate['min'];break;}}// Si on a trouvé une prochaine remise, calculer combien d'articles manquentif ($nextRebateMin !== null) {return $nextRebateMin - $eligibleCount;}// Si on a déjà atteint la remise maximale, retourner un nombre >= 48return 48;}private function calculatePriceHtvaWithRebateEachProduct($cart, $rebatePercent){$carts = [];// dd($cart);// Calculer le total de produits dans le panier pour la règle des 2% nouvelles références$totalCartQuantity = 0;foreach ($cart as $item) {$totalCartQuantity += intval($item['totalQuantity'] ?? 0);}$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $this->getUser()));} else {$user = $checkControl->getCustomer();$additionalInformations = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $checkControl->getCustomer()));}$pourcentActionShock = $this->manager->getRepository(ConfigSite::class)->findAll();$pourcentActionShock = $pourcentActionShock[0];$pourcentSpecialCustomer = null;// Récupérer l'historique des produits commandés via l'API Mercator// L'API /OrderHistory retourne maintenant les paires {s_ID, ref} pour chaque produit$mercatorHistoryProductIds = $this->getMercatorOrderHistory($additionalInformations);// Parcourir chaque élément du panier et déterminer si c'est une nouvelle référenceforeach ($cart as $key => &$item) {if (is_array($item) && isset($item['productIdMercator'])) {$totalQuantity = intval($item['totalQuantity']);$mercatorId = intval($item['productIdMercator']);// Vérifier si le produit est dans l'historique Mercator$isInMercatorHistory = in_array($mercatorId, $mercatorHistoryProductIds);// Nouvelle référence si: pas dans l'historique ET quantité >= 2if (!$isInMercatorHistory && $totalQuantity >= 2) {$item['newRef'] = true;} else {$item['newRef'] = false;}}}unset($item);$excludedProducts = $this->manager->getRepository(Rebate::class)->getExcludedProducts();$specificRebates = $this->manager->getRepository(Rebate::class)->getActiveSpecificRebates();foreach ($cart as $item) {$isNewRef = isset($item['newRef']) && $item['newRef'] ?? false;$productRebatePercent = $rebatePercent;$shockActionDiscountPercent = 0;if ($item['shockActionDiscountPercent']) {$shockActionDiscountPercent = $item['shockActionDiscountPercent'] ?? 0;}// Vérifier d'abord si le produit a une promotion spéciale$checkProduct = $this->manager->getRepository(Products::class)->find($item['productId']);$checkSpecialDiscount = $this->manager->getRepository(SpecialDiscount::class)->findOneBy(array('product' => $checkProduct));// Si le produit est dans la liste des exclus mais qu'il a une promotion spéciale// et que sa quantité est inférieure à 12, on le laisse bénéficier de la remise globaleif (in_array($item['reference'], $excludedProducts) &&!($checkSpecialDiscount != null && $item['totalQuantity'] < 12)) {$productRebatePercent = 0;}foreach ($specificRebates as $rebate) {if (in_array($item['reference'], $rebate->getSpecificProducts()) && $item['totalQuantity'] >= $rebate->getMin()) {$productRebatePercent = $rebate->getPourcentRebate();break;}}$item['rebatePercent'] = $productRebatePercent;$checkProduct = $this->manager->getRepository(Products::class)->find($item['productId']);$checkSpecialDiscount = $this->manager->getRepository(SpecialDiscount::class)->findOneBy(array('product' => $checkProduct));if ($user->getSpecialCustomer()) {$checkUserSpecialEntity = $this->manager->getRepository(SpecialCustomer::class)->findOneBy(array('user' => $user, 'active' => true));if ($checkUserSpecialEntity == null) {$pourcentSpecialCustomer = $this->manager->getRepository(ConfigSite::class)->findAll();$pourcentSpecialCustomer = $pourcentSpecialCustomer[0];} else {$pourcentSpecialCustomer = $checkUserSpecialEntity->getPourcentRebate();}}// Produits sans promotion spéciale ni action chocif (isset($item['price']) && !$item['actionShock'] && !$checkSpecialDiscount && $pourcentSpecialCustomer == null) {$totalPriceProduct = $item['price'] * $item['totalQuantity'];$minQuantity = $isNewRef ? 2 : 4;if (strcasecmp($item['brand'], 'NaturaMedicatrix') === 0) {$brandRebate = $this->manager->getRepository(BrandDiscount::class)->findOneBy(array('brandName' => 'NaturaMedicatrix', 'active' => true));if ($brandRebate && $productRebatePercent > 0 && $item['totalQuantity'] >= $minQuantity) {// Total panier >= 12 ET quantité >= colissage : remise de base + 2% marque + 2% nouvelle réf si applicable$totalPriceProduct = $item['price'] * $item['totalQuantity'];$newRefBonus = ($isNewRef && $item['totalQuantity'] >= 2) ? 2 : 0;if ($productRebatePercent == 13) {// 13% → 15% (13% + 2% marque) + 2% si nouvelle réf = 17%$totalDiscount = $brandRebate->getRebateLow() + $newRefBonus;$totalRebate = ($totalPriceProduct / 100) * $totalDiscount;$item['rebatePercent'] = $totalDiscount;$item['newRefDiscount'] = $totalDiscount;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $totalDiscount), 2, '.', ''));} elseif ($productRebatePercent == 19) {// 19% → 21% (19% + 2% marque) + 2% si nouvelle réf = 23%$totalDiscount = $brandRebate->getRebateHeigh() + $newRefBonus;$totalRebate = ($totalPriceProduct / 100) * $totalDiscount;$item['rebatePercent'] = $totalDiscount;$item['newRefDiscount'] = $totalDiscount;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $totalDiscount), 2, '.', ''));}} elseif ($isNewRef && $item['totalQuantity'] >= 2 && $totalCartQuantity >= 12) {// Nouvelle réf NaturaMedicatrix sans remise de base : seulement 2% (si >= 12 produits dans le panier)$totalPriceProduct = $item['price'] * $item['totalQuantity'];$totalRebate = ($totalPriceProduct / 100) * 2;$item['rebatePercent'] = 2;$item['newRefDiscount'] = 2;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * 2), 2, '.', ''));} else {// Pas de remise (en dessous du colissage ou pas de remise de base ou < 12 produits)$totalPriceProduct = $item['price'] * $item['totalQuantity'];$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct, 2, '.', ''));$item['reductionUniteItem'] = $item['price'];$item['rebatePercent'] = 0;$item['newRefDiscount'] = 0;}} elseif ($productRebatePercent > 0 && $item['totalQuantity'] >= $minQuantity) {// Total panier >= 12 ET quantité >= colissage : remise de base + 2% nouvelle réf si applicable$newRefBonus = ($isNewRef && $item['totalQuantity'] >= 2 && $totalCartQuantity >= 12) ? 2 : 0;$totalDiscount = $productRebatePercent + $newRefBonus;$totalRebate = ($totalPriceProduct / 100) * $totalDiscount;$item['rebatePercent'] = $totalDiscount;$item['newRefDiscount'] = $totalDiscount;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $totalDiscount), 2, '.', ''));} elseif ($isNewRef && $item['totalQuantity'] >= 2 && $totalCartQuantity >= 12) {// Nouvelle réf sans remise de base : seulement 2% (si >= 12 produits dans le panier)$totalRebate = ($totalPriceProduct / 100) * 2;$item['rebatePercent'] = 2;$item['newRefDiscount'] = 2;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * 2), 2, '.', ''));} else {// Pas de remise (en dessous du colissage ou pas de remise de base ou < 12 produits)$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct, 2, '.', ''));$item['reductionUniteItem'] = $item['price'];$item['rebatePercent'] = 0;$item['newRefDiscount'] = 0;}} elseif (isset($item['price']) && $item['actionShock']) {$totalPriceProduct = $item['price'] * $item['totalQuantity'];$minQuantityShock = $isNewRef ? 2 : 4;$item['rebatePercent'] = 0;if ($item['totalQuantity'] >= $minQuantityShock) {$item['rebatePercent'] = $shockActionDiscountPercent + (($isNewRef && $totalCartQuantity >= 12) ? 2 : 0);}$item['newRefDiscount'] = $item['rebatePercent'];$totalRebate = ($totalPriceProduct / 100) * $item['rebatePercent'];$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $item['rebatePercent']), 2, '.', ''));} elseif (isset($item['price']) && !$item['actionShock'] && $checkSpecialDiscount != null) {// Produits avec promotion spécialeif ($item['totalQuantity'] > 11) {// Si la quantité est supérieure à 11, on applique la promotion spéciale (50%)$totalPriceProduct = $item['publicPrice'] * $item['totalQuantity'];$totalRebate = ($totalPriceProduct / 100) * $checkSpecialDiscount->getPourcentRebate();$item['rebatePercent'] = $checkSpecialDiscount->getPourcentRebate();$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['publicPrice']) - (($item['publicPrice'] / 100) * floatval(number_format($checkSpecialDiscount->getPourcentRebate(), 2, '.', ''))), 2, '.', ''));} elseif ($productRebatePercent > 0 && $item['totalQuantity'] >= ($isNewRef ? 2 : 4)) {// Total panier >= 12 ET quantité >= colissage : remise de base + 2% nouvelle réf si applicable$totalPriceProduct = $item['price'] * $item['totalQuantity'];$newRefBonus = ($isNewRef && $item['totalQuantity'] >= 2 && $totalCartQuantity >= 12) ? 2 : 0;$totalDiscount = $productRebatePercent + $newRefBonus;$totalRebate = ($totalPriceProduct / 100) * $totalDiscount;$item['rebatePercent'] = $totalDiscount;$item['newRefDiscount'] = $totalDiscount;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $totalDiscount), 2, '.', ''));} elseif ($isNewRef && $item['totalQuantity'] >= 2 && $totalCartQuantity >= 12) {// Nouvelle réf sans remise de base : seulement 2% (si >= 12 produits dans le panier)$totalPriceProduct = $item['price'] * $item['totalQuantity'];$totalRebate = ($totalPriceProduct / 100) * 2;$item['rebatePercent'] = 2;$item['newRefDiscount'] = 2;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * 2), 2, '.', ''));} else {// Pas de remise (en dessous du colissage ou pas de remise de base)$totalPriceProduct = $item['price'] * $item['totalQuantity'];$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct, 2, '.', ''));$item['reductionUniteItem'] = $item['price'];$item['rebatePercent'] = 0;$item['newRefDiscount'] = 0;}} elseif (isset($item['price']) && $pourcentSpecialCustomer != null) {$totalPriceProduct = $item['publicPrice'] * $item['totalQuantity'];if ($item['totalQuantity'] > 11 && $checkSpecialDiscount != null) {$totalRebate = ($totalPriceProduct / 100) * $checkSpecialDiscount->getPourcentRebate();$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['publicPrice']) - (($item['publicPrice'] / 100) * floatval(number_format($pourcentSpecialCustomer->getPourcentSpecialCustomer(), 2, '.', ''))), 2, '.', ''));} else {$totalPriceProduct = $item['price'] * $item['totalQuantity'];if ($item['totalQuantity'] > 3) {$totalRebate = ($totalPriceProduct / 100) * $productRebatePercent;$item['totalRebate'] = floatval(number_format($totalRebate, 2, '.', ''));$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct - $item['totalRebate'], 2, '.', ''));$item['reductionUniteItem'] = floatval(number_format(($item['price']) - (($item['price'] / 100) * $productRebatePercent), 2, '.', ''));} else {$item['PriceRebateInclude'] = floatval(number_format($totalPriceProduct, 2, '.', ''));$item['reductionUniteItem'] = $item['price'];}}}$carts[] = $item;}// $this->applyDiscountOnNewRefItems($carts);// dd($carts);$carts = $this->groupItemWithVat($carts, $user);return $carts;}private function groupItemWithVat($carts, $user){$tvaLow = 0;$tvaHigh = 0;$productsLowTva = 0;$productsHighTva = 0;$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();$additionalInformation = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $this->getUser()));} else {$user = $checkControl->getCustomer();$additionalInformation = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $checkControl->getCustomer()));}// $additionalInformation = $this->manager->getRepository(AdditionalCompanyInformation::class)->findOneBy(array('user' => $user));// Determine country-specific VAT rates and which product VAT field to use$vatField = null;if ($additionalInformation->getCompanyCountry() == 'Belgique') {$tvaLow = 6;$tvaHigh = 21;$vatField = 'tvaBe';} elseif ($additionalInformation->getCompanyCountry() == 'France') {$tvaLow = 5.5;$tvaHigh = 20;$vatField = 'tvaFr';} elseif ($additionalInformation->getCompanyCountry() == 'Luxembourg') {$tvaLow = 3;$tvaHigh = 17;$vatField = 'tvaLu';}foreach ($carts as $item) {// Ensure we have the computed HTVA with all discounts appliedif (!isset($item['PriceRebateInclude'])) {continue;}$productVat = isset($item[$vatField]) ? $item[$vatField] : null;if ($productVat == $tvaLow) {$productsLowTva += $item['PriceRebateInclude'];} else {$productsHighTva += $item['PriceRebateInclude'];}}$carts['TotalPriceProductLowVatHtva'] = $productsLowTva;$carts['TotalPriceProductHighVatHtva'] = $productsHighTva;$carts = $this->calculateTvaOnEachProduct($carts, $additionalInformation);return $carts;}private function calculateTvaOnEachProduct($carts, $additionalInformation){$tvaLow = 0;$tvaHigh = 0;if ($additionalInformation->getCompanyCountry() == 'Belgique') {$tvaLow = 6;$tvaHigh = 21;} elseif ($additionalInformation->getCompanyCountry() == 'France') {$tvaLow = 5.5;$tvaHigh = 20;} elseif ($additionalInformation->getCompanyCountry() == 'Luxembourg') {$tvaLow = 3;$tvaHigh = 17;}$carts['TotalPriceProductLowVatTvac'] = floatval(number_format(($carts['TotalPriceProductLowVatHtva'] / 100) * $tvaLow, 2, '.', ''));$carts['TotalPriceProductHighVatTvac'] = floatval(number_format(($carts['TotalPriceProductHighVatHtva'] / 100) * $tvaHigh, 2, '.', ''));$carts['totalPriceAllProductHtva'] = floatval(number_format($carts['TotalPriceProductLowVatHtva'] + $carts['TotalPriceProductHighVatHtva'], 2, '.', ''));$carts['totalPriceTvacWithRebate'] = floatval(number_format($carts['TotalPriceProductLowVatHtva'] + $carts['TotalPriceProductHighVatHtva'] + $carts['TotalPriceProductLowVatTvac'] + $carts['TotalPriceProductHighVatTvac'], 2, '.', ''));return $carts;}private function calculateCountItemInCart(){$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();} else {$user = $checkControl->getCustomer();}$carts = $this->manager->getRepository(Cart::class)->getUserPendingItems($user);$excludedProducts = $this->manager->getRepository(Rebate::class)->getExcludedProducts();$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();// Compter les articles éligibles (même logique que calculateRebate)$productCounts = [];$totalCount = 0;// Première passe : compter les produits avec promotion spécialeforeach ($carts as $item) {$productRef = $item->getProducts()->getReference();$quantity = $item->getQuantity();$checkSpecialDiscount = $this->manager->getRepository(SpecialDiscount::class)->findOneBy(array('product' => $item->getProducts()));if (!isset($productCounts[$productRef])) {$productCounts[$productRef] = ['quantity' => 0,'hasSpecialDiscount' => ($checkSpecialDiscount != null)];}$productCounts[$productRef]['quantity'] += $quantity;$totalCount += $quantity;}// Deuxième passe : calculer le total d'articles éligibles$eligibleCount = 0;foreach ($carts as $item) {$productRef = $item->getProducts()->getReference();if (in_array($productRef, $excludedProducts)) {// Si produit exclu avec promotion spéciale et quantité >=12 - NE PAS compterif ($productCounts[$productRef]['hasSpecialDiscount'] && $productCounts[$productRef]['quantity'] >= 12) {continue;}}$eligibleCount += $item->getQuantity();}// Retourner un tableau avec le total et les éligiblesreturn ['total' => $totalCount,'eligible' => $eligibleCount];}private function calculateRebate($pourcentSpecialCustomer): float|int{$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();} else {$user = $checkControl->getCustomer();}$rebates = $this->manager->getRepository(Rebate::class)->getActiveNormalRebates();$carts = $this->manager->getRepository(Cart::class)->getUserPendingItems($user);$excludedProducts = $this->manager->getRepository(Rebate::class)->getExcludedProducts();// Initialiser le compteur total d'articles$count = 0;$productCounts = [];// Première passe : compter les produits avec promotion spécialeforeach ($carts as $item) {$productRef = $item->getProducts()->getReference();$quantity = $item->getQuantity();// Vérifier si le produit a une promotion spéciale$checkSpecialDiscount = $this->manager->getRepository(SpecialDiscount::class)->findOneBy(array('product' => $item->getProducts()));if (!isset($productCounts[$productRef])) {$productCounts[$productRef] = ['quantity' => 0,'hasSpecialDiscount' => ($checkSpecialDiscount != null)];}$productCounts[$productRef]['quantity'] += $quantity;}// Deuxième passe : calculer le total d'articles pour la remise globaleforeach ($carts as $item) {$productRef = $item->getProducts()->getReference();// Si le produit est dans la liste des exclusionsif (in_array($productRef, $excludedProducts)) {// Cas 1: Si c'est un produit exclu sans promotion spéciale - COMPTER DANS LA REMISE 13% 19%// On ne fait rien de spécial, on laisse passer pour le comptage en bas// Cas 2: Si c'est un produit exclu avec promotion spéciale et quantité >=12 - NE PAS compter DANS LA REMISE 13% 19%if ($productCounts[$productRef]['hasSpecialDiscount'] && $productCounts[$productRef]['quantity'] >= 12) {continue;}// Cas 3: Si c'est un produit exclu avec promotion spéciale et quantité <12 - COMPTER DANS LA REMISE 13% 19%// Cette ligne ne fait rien car on va passer au comptage par défaut en dessous} else {// Produits non-exclus: Toujours compter (pas de condition spéciale)}// Pour tous les autres produits, ajouter leur quantité au compteur$count += $item->getQuantity();}$reduction = 0;if ($pourcentSpecialCustomer != null) {if ($count >= 12) {if (is_float($pourcentSpecialCustomer) || is_int($pourcentSpecialCustomer)) {$reduction = $pourcentSpecialCustomer;} else {$reduction = $pourcentSpecialCustomer->getPourcentSpecialCustomer() ?? 0;}}} else {foreach ($rebates as $rebate) {if ($count >= $rebate->getMin()) {$reduction = $rebate->getPourcentRebate() ?? 0;break;}}}return (float) $reduction;}private function checkFreeProduct($cart): array{$countFreeProduct = [];$index = 0;foreach ($cart as $item) {if (isset($item['totalQuantity']) && $item['totalQuantity'] >= 24) {$countFreeProduct[$index]['free'] = floor($item['totalQuantity'] / 24);$countFreeProduct[$index]['name'] = $item['name'];}$index++;}return $countFreeProduct;}#[Route('/cart/toggle-flyers', name: 'toggleFlyers')]public function toggleFlyers(Request $request): Response{// Inverser la valeur actuelle (true par défaut)$currentValue = $request->getSession()->get('wantFlyers', true);$request->getSession()->set('wantFlyers', !$currentValue);return $this->redirectToRoute('cartView');}private function calculateFreeTransport($totalPrice): bool{$franco = $this->manager->getRepository(ConfigSite::class)->findAll();if ($totalPrice >= $franco[0]->getFrancoDelivery()) {return true;} else {return false;}}#[Route('/cart/remove/product/{productID}', name: 'cartRemoveProduct')]public function removeProductFromCart($productID): RedirectResponse{$checkControl = $this->manager->getRepository(CustomerControl::class)->findOneBy(array('user' => $this->getUser(), 'finish' => false));if (!$checkControl) {$user = $this->getUser();} else {$user = $checkControl->getCustomer();}$product = $this->manager->getRepository(Products::class)->find($productID);$products = $this->manager->getRepository(Cart::class)->findBy(array('user' => $user, 'finish' => false, 'products' => $product));foreach ($products as $item) {$this->manager->remove($item);$this->manager->flush();}return $this->redirectToRoute('cartView');}/*** Récupère l'historique des produits commandés via l'API Mercator /OrderHistory* Retourne un tableau des s_ID des produits déjà commandés par le client*/private function getMercatorOrderHistory(?AdditionalCompanyInformation $additionalInformations): array{// Vérifier que le client a un ID Mercatorif (!$additionalInformations || !$additionalInformations->getIdClientMercator()) {return [];}try {// Récupérer le token JWT$jwtToken = $this->jwtMercator->getToken();// Appeler l'endpoint /OrderHistory avec le clientId$clientId = $additionalInformations->getIdClientMercator();$response = $this->client->request('GET', 'https://ns3190747.ip-51-89-219.eu/OrderHistory?clientId=' . $clientId, ['headers' => ['Authorization' => 'Bearer ' . $jwtToken,],]);if ($response->getStatusCode() === 200) {$orderHistory = json_decode($response->getContent(), true);if (empty($orderHistory)) {return [];}// Extraire tous les s_ID des produits commandés$productIds = [];foreach ($orderHistory as $item) {if (isset($item['s_ID'])) {$productIds[] = intval($item['s_ID']);}}return array_unique($productIds);}} catch (\Exception $e) {// En cas d'erreur API, retourner un tableau videreturn [];}return [];}}