src/Controller/Front/TradeInController.php line 111

  1. <?php
  2. namespace App\Controller\Front;
  3. use App\Entity\Bank;
  4. use App\Entity\BankAccount;
  5. use App\Entity\EntityChangeLog;
  6. use App\Entity\LoyaltyOffer;
  7. use App\Entity\Offer;
  8. use App\Entity\Product;
  9. use App\Entity\ProductTradeIn;
  10. use App\Entity\Status;
  11. use App\Entity\TradeIn;
  12. use App\Entity\User;
  13. use App\Enum\OdooCountryEnum;
  14. use App\Enum\OdooEntityEnum;
  15. use App\Form\CustomerAddressType;
  16. use App\Form\PaymentType;
  17. use App\Form\ProductTradeInType;
  18. use App\Form\ShippingType;
  19. use App\Form\StepOneType;
  20. use App\Repository\AdminNotificationRepository;
  21. use App\Repository\LoyaltyOfferRepository;
  22. use App\Repository\OfferRepository;
  23. use App\Repository\ProductRepository;
  24. use App\Repository\StatusRepository;
  25. use App\Repository\TradeInFileRepository;
  26. use App\Repository\TradeInRepository;
  27. use App\Repository\UserRepository;
  28. use App\Service\ChronopostTools;
  29. use App\Service\NotificationSender;
  30. use App\Service\OdooApi;
  31. use App\Service\PrestashopApi;
  32. use App\Service\TradeInService;
  33. use App\Tools\Tools;
  34. use Doctrine\ORM\EntityManagerInterface;
  35. use Psr\Log\LoggerInterface;
  36. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  37. use Symfony\Component\HttpFoundation\Request;
  38. use Symfony\Component\HttpFoundation\RequestStack;
  39. use Symfony\Component\Mailer\MailerInterface;
  40. use Symfony\Component\Routing\Annotation\Route;
  41. use Symfony\Component\Form\FormError;
  42. use App\Service\LoyaltyService;
  43. /**
  44.  * Class TradeInController
  45.  * @package App\Controller\Front
  46.  */
  47. class TradeInController extends AbstractController
  48. {
  49.     private RequestStack $requestStack;
  50.     private PrestashopApi $prestashopApi;
  51.     private \Symfony\Component\HttpFoundation\Session\SessionInterface $session;
  52.     private $mailer;
  53.     private EntityManagerInterface $em;
  54.     private NotificationSender $notificationSender;
  55.     private AdminNotificationRepository $adminNotificationRepository;
  56.     private TradeInService $tradeInService;
  57.     protected ChronopostTools $chronopost;
  58.     private LoggerInterface $logger;
  59.     private LoyaltyService $loyaltyService;
  60.     /**
  61.      * TradeInController constructor.
  62.      * @param RequestStack $requestStack
  63.      * @param PrestashopApi $prestashopApi
  64.      */
  65.     public function __construct(
  66.         RequestStack                $requestStack,
  67.         PrestashopApi               $prestashopApi,
  68.         MailerInterface             $mailer,
  69.         EntityManagerInterface      $em,
  70.         NotificationSender          $notificationSender,
  71.         AdminNotificationRepository $adminNotificationRepository,
  72.         ChronopostTools             $chronopostService,
  73.         TradeInService              $tradeInService,
  74.         LoggerInterface             $logger,
  75.         LoyaltyService              $loyaltyService
  76.     )
  77.     {
  78.         $this->requestStack $requestStack;
  79.         $this->chronopost $chronopostService;
  80.         $this->prestashopApi $prestashopApi;
  81.         $this->session $this->requestStack->getSession();
  82.         $this->mailer $mailer;
  83.         $this->em $em;
  84.         $this->notificationSender $notificationSender;
  85.         $this->adminNotificationRepository $adminNotificationRepository;
  86.         $this->tradeInService $tradeInService;
  87.         $this->logger $logger;
  88.         $this->loyaltyService $loyaltyService;
  89.     }
  90.     /**
  91.      * @Route("/reset-reprise", name="tradeIn.reset")
  92.      */
  93.     public function resetTradeIn()
  94.     {
  95.         $session $this->requestStack->getSession();
  96.         if ($session->get("trade_in_id")) {
  97.             $session->remove("trade_in_id");
  98.         }
  99.         return $this->redirectToRoute("tradeIn.start");
  100.     }
  101.     /**
  102.      * @Route("/reprise", name="tradeIn.start")
  103.      */
  104.     public function tradeIn(
  105.         Request                $request,
  106.         UserRepository         $userRepository,
  107.         ProductRepository      $productRepository,
  108.         TradeInRepository      $tradeInRepository,
  109.         OfferRepository        $offerRepository,
  110.         EntityManagerInterface $em,
  111.         StatusRepository       $statusRepository,
  112.         OdooApi                $odooApi,
  113.         LoyaltyOfferRepository $loyaltyOfferRepository,
  114.     )
  115.     {
  116.         $formStepOne $this->createForm(StepOneType::class);
  117.         $formStepOne->handleRequest($request);
  118.         $session $this->requestStack->getSession();
  119.         if ($formStepOne->isSubmitted() && $formStepOne->isValid()) {
  120.             if ($formStepOne->get("productTradeIn")->get("shutterCount")->getData() === 3) {
  121.                 if ($formStepOne->get("productTradeIn")->get("numberShutterCount")->getData() > 125000) {
  122.                     $this->addFlash("notice""Désolé, nous ne pouvons pas reprendre votre boîtier car il a dépassé le nombre de déclenchements précis.");
  123.                     return $this->redirectToRoute("tradeIn.start");
  124.                 }
  125.             }
  126.             $formStepOneUser $formStepOne->get("user");
  127.             if ($session->get("trade_in_id")) {
  128.                 $session->remove("trade_in_id");
  129.             }
  130.             try {
  131.                 $userPresta $this->prestashopApi->findUserByEmailPassword(
  132.                     $formStepOneUser->get("email")->getData(),
  133.                     $formStepOneUser->get("plainPassword")->getData()
  134.                 );
  135.                 if ($userPresta['accountExist'] === true && $userPresta['validPassword'] === false) {
  136.                     $formStepOneUser->get('plainPassword')
  137.                         ->addError(new FormError('Mot de passe incorrect.'));
  138.                     return $this->render('trade_in/start.html.twig', [
  139.                         'formStepOne' => $formStepOne->createView(),
  140.                     ]);
  141.                 }
  142.             } catch (\Exception $e) {
  143.                 $this->logger->error('Prestashop API error: ' $e->getMessage());
  144.                 $this->addFlash(
  145.                     'notice',
  146.                     'Une erreur est survenue lors de la connexion à votre compte PrestaShop. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.'
  147.                 );
  148.                 return $this->redirectToRoute("tradeIn.start");
  149.             }
  150.             $user $userRepository->findOneBy([
  151.                 "email" => $formStepOne->get("user")->get("email")->getData(),
  152.             ]);
  153.             if (!$user) {
  154.                 $user = new User();
  155.                 $user->setEmail($formStepOneUser->get("email")->getData());
  156.                 if (!empty($userPresta["firstname"])) {
  157.                     $user->setFirstname($userPresta["firstname"]);
  158.                     $user->setLastname($userPresta["lastname"]);
  159.                 } else {
  160.                     $user->setFirstname($formStepOneUser->get("firstname")->getData());
  161.                     $user->setLastname($formStepOneUser->get("lastname")->getData());
  162.                 }
  163.                 $user->setRoles(["ROLE_CUSTOMER"]);
  164.                 if ($userPresta["accountExist"] == true && $userPresta["validPassword"] == true) {
  165.                     $user->setPsId($userPresta["psId"]);
  166.                 } elseif ($userPresta["accountExist"] == false) {
  167.                     try {
  168.                         $prestashopUser $this->createPrestashopAccount(
  169.                             $formStepOneUser->get("email")->getData(),
  170.                             $formStepOneUser->get("plainPassword")->getData(),
  171.                             $formStepOneUser->get("firstname")->getData(),
  172.                             $formStepOneUser->get("lastname")->getData(),
  173.                             $formStepOneUser->get("phone")->getData(),
  174.                             $formStepOneUser->get("country")->getData(),
  175.                             $formStepOneUser->get("postcode")->getData(),
  176.                             $formStepOneUser->get("streetAddress")->getData(),
  177.                             $formStepOneUser->get("city")->getData()
  178.                         );
  179.                     } catch (\Exception $e) {
  180.                         $this->logger->error('Prestashop API error: ' $e->getMessage());
  181.                         $this->addFlash(
  182.                             'notice',
  183.                             'Une erreur est survenue lors de la création de votre compte PrestaShop. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.'
  184.                         );
  185.                         return $this->redirectToRoute("tradeIn.start");
  186.                     }
  187.                     if (isset($prestashopUser)) {
  188.                         $user->setPsId($prestashopUser);
  189.                         $user->setActive(true);
  190.                     } else {
  191.                         $this->addFlash("notice""Erreur lors de la création de votre compte");
  192.                         return $this->redirectToRoute("tradeIn.start");
  193.                     }
  194.                 } else {
  195.                     $this->addFlash("notice""Erreur avec le mot de passe indiqué");
  196.                     return $this->redirectToRoute("tradeIn.start");
  197.                 }
  198.                 $em->persist($user);
  199.                 $em->flush();
  200.             }
  201.             $statusInProgress $statusRepository->findOneBy([
  202.                 "slug" => Status::trade_in_progress,
  203.             ]);
  204.             $tradeIn = new TradeIn();
  205.             $tradeIn->setTStatus($statusInProgress);
  206.             $tradeIn->setUser($user);
  207.             $tradeIn->setTradeCode(Tools::generateTradeCode());
  208.             $tradeIn->setIsInStore(false);
  209.             $offerAvailable $offerRepository->findOneByOvercost();
  210.             if ($offerAvailable) {
  211.                 $tradeIn->setOffer($offerAvailable);
  212.             }
  213.             if ($creatorCode $session->get("creator")) {
  214.                 $tradeIn->setCreatorCode($creatorCode);
  215.             }
  216.             $userLoyaltyTierName $this->loyaltyService->getUserTier($user->getEmail());
  217.             if ($userLoyaltyTierName) {
  218.                 $loyaltyOffer $loyaltyOfferRepository->findOneBy([
  219.                     'tierName' => $userLoyaltyTierName,
  220.                     'active' => true,
  221.                 ]);
  222.                 if ($loyaltyOffer) {
  223.                     $tradeIn->addLoyaltyOffer($loyaltyOffer);
  224.                 }
  225.             }
  226.             $em->persist($tradeIn);
  227.             $em->flush();
  228.             $adminNotificationType $this->adminNotificationRepository->findOneBy([
  229.                 "type" => $tradeIn->getTStatus()->getSlug(),
  230.             ]);
  231.             $formStepOneProduct $formStepOne->get("productTradeIn");
  232.             $product $productRepository->find(
  233.                 $formStepOneProduct->get("product")->getData()
  234.             );
  235.             $productTradeIn = new ProductTradeIn();
  236.             $productTradeIn->setProduct($product);
  237.             $productTradeIn->setPackaging($formStepOneProduct->get("packaging")->getData());
  238.             $productTradeIn->setShutterCount($formStepOneProduct->get("shutterCount")->getData());
  239.             $productTradeIn->setAccessories($formStepOneProduct->get("accessories")->getData());
  240.             $productTradeIn->setProductQuality($formStepOneProduct->get("productQuality")->getData());
  241.             $productTradeIn->setStatus(0); // NOT USE
  242.             $productTradeIn->setTradeIn($tradeIn);
  243.             $productTradeIn->setPrice(
  244.                 $this->tradeInService->calculationProductPrice($productTradeIn$product)
  245.             );
  246.             $em->persist($productTradeIn);
  247.             $em->flush();
  248.             $tradeIn->setCalculatedAmount($productTradeIn->getPrice());
  249.             $em->persist($tradeIn);
  250.             $em->flush();
  251.             $session->set("trade_in_id"$tradeIn->getId());
  252.             // =========================
  253.             // ODOO CONTACT RESOLUTION (Prestashop -> Odoo) with integration_id=1
  254.             // =========================
  255.             try {
  256.                 $psId = (int)$user->getPsId();
  257.                 if (!$psId) {
  258.                     return $this->redirectToRoute('reprise.missing.address');
  259.                 }
  260.                 // --------------------------------------------------
  261.                 // 1) integration_id fixed
  262.                 // --------------------------------------------------
  263.                 $integrationId 1;
  264.                 // --------------------------------------------------
  265.                 // 2) Build address (form > Prestashop fallback)
  266.                 // --------------------------------------------------
  267.                 $countryId $formStepOneUser->get('country')->getData();
  268.                 $odooCountryId $countryId
  269.                     OdooCountryEnum::getOdooIdFromPrestashopId($countryId)
  270.                     : null;
  271.                 $address = [
  272.                     'street' => (string)($formStepOneUser->get('streetAddress')->getData() ?? ''),
  273.                     'street2' => '',
  274.                     'zip' => (string)($formStepOneUser->get('postcode')->getData() ?? ''),
  275.                     'city' => (string)($formStepOneUser->get('city')->getData() ?? ''),
  276.                     'country_id' => $odooCountryId,
  277.                     'phone' => (string)($formStepOneUser->get('phone')->getData() ?? ''),
  278.                 ];
  279.                 $hasAddress = static function (array $a): bool {
  280.                     foreach (['street''zip''city''country_id''phone'] as $k) {
  281.                         if (!empty($a[$k])) return true;
  282.                     }
  283.                     return false;
  284.                 };
  285.                 if (!$hasAddress($address)) {
  286.                     $psAddress $this->prestashopApi->findAddressCustomer($psId);
  287.                     if (!$psAddress) {
  288.                         return $this->redirectToRoute('reprise.missing.address');
  289.                     }
  290.                     $address = [
  291.                         'street' => (string)($psAddress['address1'] ?? ''),
  292.                         'street2' => (string)($psAddress['address2'] ?? ''),
  293.                         'zip' => (string)($psAddress['postcode'] ?? ''),
  294.                         'city' => (string)($psAddress['city'] ?? ''),
  295.                         'country_id' => !empty($psAddress['id_country'])
  296.                             ? OdooCountryEnum::getOdooIdFromPrestashopId($psAddress['id_country'])
  297.                             : null,
  298.                         'phone' => (string)($psAddress['phone'] ?? ''),
  299.                     ];
  300.                     if (!$hasAddress($address)) {
  301.                         return $this->redirectToRoute('reprise.missing.address');
  302.                     }
  303.                 }
  304.                 $fullName trim(($user->getFirstname() ?? '') . ' ' . ($user->getLastname() ?? ''));
  305.                 // --------------------------------------------------
  306.                 // 3) Find or create res.partner
  307.                 // --------------------------------------------------
  308.                 $partnerId null;
  309.                 $partners $odooApi->select(
  310.                     OdooEntityEnum::CUSTOMER,
  311.                     ['id''email'],
  312.                     ['email' => $user->getEmail()]
  313.                 );
  314.                 if (!empty($partners) && !empty($partners[0]['id'])) {
  315.                     $partnerId = (int)$partners[0]['id'];
  316.                 } else {
  317.                     $createdPartner $odooApi->create(OdooEntityEnum::CUSTOMER, [
  318.                         'type' => 'contact',
  319.                         'name' => $fullName,
  320.                         'email' => $user->getEmail(),
  321.                         'street' => $address['street'],
  322.                         'street2' => $address['street2'],
  323.                         'zip' => $address['zip'],
  324.                         'city' => $address['city'],
  325.                         'country_id' => $address['country_id'],
  326.                         'phone' => $address['phone'],
  327.                     ]);
  328.                     $partnerId is_array($createdPartner)
  329.                         ? (int)($createdPartner['id'] ?? $createdPartner[0] ?? 0)
  330.                         : (int)$createdPartner;
  331.                     if (!$partnerId) {
  332.                         throw new \RuntimeException('Failed to create res.partner');
  333.                     }
  334.                 }
  335.                 // --------------------------------------------------
  336.                 // 4) integration.res.partner.external (integration_id mandatory)
  337.                 // --------------------------------------------------
  338.                 $external $odooApi->select(
  339.                     OdooEntityEnum::INTEGRATION_EXTERNAL,
  340.                     ['id'],
  341.                     [
  342.                         'code' => (string)$psId,
  343.                         'integration_id' => $integrationId,
  344.                     ]
  345.                 );
  346.                 $externalId null;
  347.                 if (!empty($external) && !empty($external[0]['id'])) {
  348.                     $externalId = (int)$external[0]['id'];
  349.                 } else {
  350.                     $createdExternal $odooApi->create(
  351.                         OdooEntityEnum::INTEGRATION_EXTERNAL,
  352.                         [
  353.                             'code' => (string)$psId,
  354.                             'integration_id' => $integrationId,
  355.                         ]
  356.                     );
  357.                     $externalId is_array($createdExternal)
  358.                         ? (int)($createdExternal['id'] ?? $createdExternal[0] ?? 0)
  359.                         : (int)$createdExternal;
  360.                     if (!$externalId) {
  361.                         throw new \RuntimeException('Failed to create integration external');
  362.                     }
  363.                 }
  364.                 // --------------------------------------------------
  365.                 // 5) integration.res.partner.mapping (integration_id mandatory too!)
  366.                 // --------------------------------------------------
  367.                 $mapping $odooApi->select(
  368.                     OdooEntityEnum::INTEGRATION_MAPPING,
  369.                     ['id'],
  370.                     [
  371.                         'external_partner_id' => $externalId,
  372.                         'partner_id' => $partnerId,
  373.                         'integration_id' => $integrationId,
  374.                     ]
  375.                 );
  376.                 if (empty($mapping)) {
  377.                     $odooApi->create(
  378.                         OdooEntityEnum::INTEGRATION_MAPPING,
  379.                         [
  380.                             'external_partner_id' => $externalId,
  381.                             'partner_id' => $partnerId,
  382.                             'integration_id' => $integrationId,
  383.                         ]
  384.                     );
  385.                 }
  386.                 // --------------------------------------------------
  387.                 // 6) Final sync partner
  388.                 // --------------------------------------------------
  389.                 $odooApi->update(OdooEntityEnum::CUSTOMER$partnerId, [
  390.                     'type' => 'contact',
  391.                     'name' => $fullName,
  392.                     'email' => $user->getEmail(),
  393.                     'street' => $address['street'],
  394.                     'street2' => $address['street2'],
  395.                     'zip' => $address['zip'],
  396.                     'city' => $address['city'],
  397.                     'country_id' => $address['country_id'],
  398.                     'phone' => $address['phone'],
  399.                 ]);
  400.                 $tradeIn->setOdooUserId($partnerId);
  401.                 $em->persist($tradeIn);
  402.                 $em->flush();
  403.             } catch (\Exception $e) {
  404.                 $this->addFlash(
  405.                     'warning',
  406.                     'An error occurred while processing your account. ' $e->getMessage()
  407.                 );
  408.                 return $this->redirectToRoute('tradeIn.start');
  409.             }
  410.             // Send admin notification if available
  411.             if ($adminNotificationType) {
  412.                 $this->notificationSender->sendAdminEmail(
  413.                     $tradeIn->getTStatus()->getLabel() . " - Reprise #" $tradeIn->getTradeCode() . " a évolué | BACK ipln",
  414.                     "emails/admin_tradeInUpdated.html.twig",
  415.                     [
  416.                         "firstname" => $tradeIn->getUser()->getFirstname(),
  417.                         "tradeCode" => $tradeIn->getTradeCode(),
  418.                         "products" => $tradeIn->getProductTradeIn(),
  419.                         "total" => $tradeIn->getCalculatedAmount(),
  420.                         "paymentType" => "Non défini",
  421.                         "tradeInPath" => $request->getUriForPath(
  422.                             $this->generateUrl("admin.tradein.editable", [
  423.                                 "id" => $tradeIn->getId(),
  424.                             ])
  425.                         ),
  426.                         "tradeInStatus" => $tradeIn->getTStatus()->getLabel(),
  427.                     ],
  428.                     $adminNotificationType,
  429.                     $tradeIn
  430.                 );
  431.             }
  432.             return $this->redirectToRoute("tradeIn.addProduct");
  433.         }
  434.         $tradeInProgress false;
  435.         if ($session->get("trade_in_id") && $tradeInRepository->find($session->get("trade_in_id"))) {
  436.             $tradeInProgress true;
  437.         }
  438.         return $this->render("front/trade_in/begin.html.twig", [
  439.             "formStepOne" => $formStepOne->createView(),
  440.             "tradeInProgress" => $tradeInProgress
  441.         ]);
  442.     }
  443.     /**
  444.      * @Route("/ajout-produit", name="tradeIn.addProduct")
  445.      */
  446.     public function addProduct(
  447.         Request                $request,
  448.         TradeInRepository      $tradeInRepository,
  449.         ProductRepository      $productRepository,
  450.         OfferRepository        $offerRepository,
  451.         EntityManagerInterface $em
  452.     )
  453.     {
  454.         if (!$this->session->get("trade_in_id")) {
  455.             $this->addFlash("notice""Vous n'avez pas encore créé de reprise");
  456.             return $this->redirectToRoute("tradeIn.start");
  457.         }
  458.         $tradeIn $tradeInRepository->find($this->session->get("trade_in_id"));
  459.         if (empty($tradeIn)) {
  460.             $this->addFlash(
  461.                 "notice",
  462.                 "Reprise introuvable, veuillez démarrer une nouvelle reprise."
  463.             );
  464.             return $this->redirectToRoute("tradeIn.start");
  465.         }
  466.         $formStepTwo $this->createForm(ProductTradeInType::class);
  467.         $formStepTwo->handleRequest($request);
  468.         if ($formStepTwo->isSubmitted() && $formStepTwo->isValid()) {
  469.             if ($formStepTwo->get("shutterCount")->getData() === 3) {
  470.                 if ($formStepTwo->get("numberShutterCount")->getData() > 125000) {
  471.                     $this->addFlash("notice""Désolé, nous ne pouvons pas reprendre votre boîtier car il a dépassé le nombre de déclenchements précis.");
  472.                     return $this->redirectToRoute("tradeIn.addProduct");
  473.                 }
  474.             }
  475.             $product $productRepository->find(
  476.                 $formStepTwo->get("product")->getData()
  477.             );
  478.             $productTradeIn = new ProductTradeIn();
  479.             $productTradeIn->setProduct($product);
  480.             $productTradeIn->setPackaging(
  481.                 $formStepTwo->get("packaging")->getData()
  482.             );
  483.             $productTradeIn->setShutterCount(
  484.                 $formStepTwo->get("shutterCount")->getData()
  485.             );
  486.             $productTradeIn->setAccessories(
  487.                 $formStepTwo->get("accessories")->getData()
  488.             );
  489.             $productTradeIn->setProductQuality(
  490.                 $formStepTwo->get("productQuality")->getData()
  491.             );
  492.             $productTradeIn->setStatus(0); //NOT USE
  493.             $productTradeIn->setTradeIn($tradeIn);
  494.             $productTradeIn->setPrice(
  495.                 $this->tradeInService->calculationProductPrice($productTradeIn$product)
  496.             );
  497.             $em->persist($productTradeIn);
  498.             $offerAvailable $offerRepository->findOneByOvercost();
  499.             if ($offerAvailable) {
  500.                 $tradeIn->setOffer($offerAvailable);
  501.             }
  502.             $tradeIn->setCalculatedAmount(
  503.                 $tradeIn->getCalculatedAmount() + $productTradeIn->getPrice()
  504.             );
  505.             $em->persist($tradeIn);
  506.             $em->flush();
  507.             return $this->redirectToRoute("tradeIn.addProduct");
  508.         }
  509.         $offersData $this->getBestLoyaltyOrOfferTotal($tradeIn);
  510.         return $this->render("front/trade_in/add_product.html.twig", [
  511.             "tradeIn" => $tradeIn,
  512.             "formStepTwo" => $formStepTwo->createView(),
  513.             "loyaltyOffer" => $offersData["loyaltyOffer"],
  514.             "showLoyaltyOffer" => $offersData["showLoyaltyOffer"],
  515.             "totalOffer" => $offersData["totalOffer"],
  516.             "totalLoyalty" => $offersData["totalLoyalty"],
  517.         ]);
  518.     }
  519.     private function calculateOfferTotal(TradeIn $tradeInOffer $offer)
  520.     {
  521.         if ($offer->getAmountType() === "percentage") {
  522.             return (int)round($tradeIn->getCalculatedAmount()
  523.                 + ($tradeIn->getCalculatedAmount() * $offer->getAmount() / 100));
  524.         }
  525.         if ($offer->getAmountType() === "euro") {
  526.             return (int)round($tradeIn->getCalculatedAmount() + $offer->getAmount());
  527.         }
  528.     }
  529.     private function getBestLoyaltyOrOfferTotal(TradeIn $tradeIn)
  530.     {
  531.         $tradeInLoyaltyOffer $tradeIn->getLoyaltyOffer();
  532.         $loyaltyOfferValues $tradeInLoyaltyOffer->getValues();
  533.         $showLoyaltyOffer false;
  534.         $loyaltyOffer null;
  535.         $totalOffer 0;
  536.         $totalLoyalty 0;
  537.         $offer $tradeIn->getOffer();
  538.         $hasLoyalty = !empty($loyaltyOfferValues);
  539.         if ($hasLoyalty) {
  540.             $loyaltyOffer $loyaltyOfferValues[0];
  541.             $totalLoyalty = (int)round($tradeIn->getCalculatedAmount()
  542.                 + ($tradeIn->getCalculatedAmount() * $loyaltyOffer->getPercentage() / 100));
  543.         }
  544.         if ($offer) {
  545.             $totalOffer $this->calculateOfferTotal($tradeIn$offer);
  546.         }
  547.         if ($hasLoyalty && $offer) {
  548.             $showLoyaltyOffer $totalLoyalty >= $totalOffer;
  549.         } elseif ($hasLoyalty) {
  550.             $showLoyaltyOffer true;
  551.         }
  552.         return [
  553.             "loyaltyOffer" => $loyaltyOffer,
  554.             "showLoyaltyOffer" => $showLoyaltyOffer,
  555.             "totalOffer" => $totalOffer,
  556.             "totalLoyalty" => $totalLoyalty,
  557.         ];
  558.     }
  559.     /**
  560.      * @Route("/ajout-fichiers", name="tradeIn.addFiles")
  561.      */
  562.     public function addFiles(
  563.         Request           $request,
  564.         TradeInRepository $tradeInRepository
  565.     )
  566.     {
  567.         if (!$this->session->get("trade_in_id")) {
  568.             $this->addFlash("notice""Vous n'avez pas encore créé de reprise");
  569.             return $this->redirectToRoute("tradeIn.start");
  570.         }
  571.         $tradeIn $tradeInRepository->find($this->session->get("trade_in_id"));
  572.         if (empty($tradeIn)) {
  573.             $this->addFlash(
  574.                 "notice",
  575.                 "Reprise introuvable, veuillez démarrer une nouvelle reprise."
  576.             );
  577.             return $this->redirectToRoute("tradeIn.start");
  578.         }
  579.         $offersData $this->getBestLoyaltyOrOfferTotal($tradeIn);
  580.         return $this->render("front/trade_in/add_files.html.twig", [
  581.             "tradeIn" => $tradeIn,
  582.             "loyaltyOffer" => $offersData["loyaltyOffer"],
  583.             "showLoyaltyOffer" => $offersData["showLoyaltyOffer"],
  584.             "totalOffer" => $offersData["totalOffer"],
  585.             "totalLoyalty" => $offersData["totalLoyalty"],
  586.         ]);
  587.     }
  588.     /**
  589.      * @Route("/choix-de-transport", name="tradeIn.shipping_method")
  590.      */
  591.     public function shippingMethod(
  592.         Request                $request,
  593.         TradeInRepository      $tradeInRepository,
  594.         ShippingType           $shippingType,
  595.         StatusRepository       $statusRepository,
  596.         EntityManagerInterface $em
  597.     )
  598.     {
  599.         if (!$this->session->get("trade_in_id")) {
  600.             $this->addFlash("notice""Vous n'avez pas encore créé de reprise");
  601.             return $this->redirectToRoute("tradeIn.start");
  602.         }
  603.         $tradeIn $tradeInRepository->find($this->session->get("trade_in_id"));
  604.         if (empty($tradeIn)) {
  605.             $this->addFlash(
  606.                 "notice",
  607.                 "Reprise introuvable, veuillez démarrer une nouvelle reprise."
  608.             );
  609.             return $this->redirectToRoute("tradeIn.start");
  610.         }
  611.         $shippingTypeForm $this->createForm(ShippingType::class, $tradeIn);
  612.         $shippingTypeForm->handleRequest($request);
  613.         if ($shippingTypeForm->isSubmitted() && $shippingTypeForm->isValid()) {
  614.             $shippingType $shippingTypeForm->get("shippingType")->getData();
  615.             if ($shippingType === "ship_chronopost") {
  616.                 $tradeIn->setDepositCity(null);
  617.             } elseif ($shippingType === "ship_lyon") {
  618.                 $tradeIn->setDepositCity(TradeIn::CONST_LYON);
  619.             } elseif ($shippingType === "ship_paris") {
  620.                 $tradeIn->setDepositCity(TradeIn::CONST_PARIS);
  621.             }
  622.             $em->persist($tradeIn);
  623.             $em->flush();
  624.             return $this->redirectToRoute("tradeIn.payment_method");
  625.         }
  626.         return $this->render("front/trade_in/shipping_method.html.twig", [
  627.             "tradeIn" => $tradeIn,
  628.             "shippingTypeForm" => $shippingTypeForm->createView()
  629.         ]);
  630.     }
  631.     /**
  632.      * @Route("/type-de-paiement", name="tradeIn.payment_method")
  633.      */
  634.     public function tradeInPayment(
  635.         Request                $request,
  636.         TradeInRepository      $tradeInRepository,
  637.         TradeInFileRepository  $tradeInFileRepository,
  638.         EntityManagerInterface $em,
  639.         StatusRepository       $statusRepository
  640.     )
  641.     {
  642.         if (!$this->session->get("trade_in_id")) {
  643.             $this->addFlash("notice""Vous n'avez pas encore créé de reprise");
  644.             return $this->redirectToRoute("tradeIn.start");
  645.         }
  646.         $tradeIn $tradeInRepository->find($this->session->get("trade_in_id"));
  647.         if (empty($tradeIn)) {
  648.             $this->addFlash(
  649.                 "notice",
  650.                 "Reprise introuvable, veuillez démarrer une nouvelle reprise."
  651.             );
  652.             return $this->redirectToRoute("tradeIn.start");
  653.         }
  654.         $productTradeIn $tradeIn->getProductTradeIn();
  655.         $tradeInFile $tradeInFileRepository->findBy([
  656.             "ProductTradeIn" => $productTradeIn[0],
  657.         ]);
  658.         if (empty($tradeInFile)) {
  659.             $this->addFlash(
  660.                 "notice",
  661.                 "Aucune photos trouvé, merci d'ajouter les photos de votre produit"
  662.             );
  663.             return $this->redirectToRoute("tradeIn.addFiles");
  664.         }
  665.         $userPsId $tradeIn->getUser()->getPsId();
  666.         if ($userPsId == null) {
  667.             $psUser $this->prestashopApi->findUserByEmail($tradeIn->getUser()->getEmail());
  668.             if ($psUser['accountExist']) {
  669.                 $userPsId $psUser['psId'];
  670.                 $tradeIn->getUser()->setPsId($userPsId);
  671.                 $em->persist($tradeIn->getUser());
  672.                 $em->flush();
  673.             }
  674.         }
  675.         //Redirect if missing address of customer
  676.         try {
  677.             $addresses $this->prestashopApi->findAddressCustomer($tradeIn->getUser()->getPsId());
  678.         } catch (\Throwable $e) {
  679.             $this->logger->error('Prestashop API error: ' $e->getMessage());
  680.             $this->addFlash('notice''Une erreur est survenue lors de la récupération de vos adresses. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.');
  681.             return $this->redirectToRoute('tradeIn.addFiles');
  682.         }
  683.         if (empty($addresses)) {
  684.             return $this->redirectToRoute('reprise.missing.address');
  685.         }
  686.         $productsTradeIn $tradeIn->getProductTradeIn();
  687.         $totalPriceCash 0;
  688.         $totalPriceCoupon 0;
  689.         foreach ($productsTradeIn as $productTradeIn) {
  690.             $totalPriceCash += $this->tradeInService->calculationProductPrice(
  691.                 $productTradeIn,
  692.                 $productTradeIn->getProduct(),
  693.                 35
  694.             );
  695.         }
  696.         foreach ($productsTradeIn as $productTradeIn) {
  697.             $totalPriceCoupon += $this->tradeInService->calculationProductPrice(
  698.                 $productTradeIn,
  699.                 $productTradeIn->getProduct(),
  700.                 25
  701.             );
  702.         }
  703.         $offersData $this->getBestLoyaltyOrOfferTotal($tradeIn);
  704.         if ($offersData["showLoyaltyOffer"] && $offersData['loyaltyOffer']) {
  705.             $totalPriceCoupon = (int)round($totalPriceCoupon + ($totalPriceCoupon $offersData['loyaltyOffer']->getPercentage() / 100));
  706.             $totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash $offersData['loyaltyOffer']->getPercentage() / 100));
  707.         } elseif (($offer $tradeIn->getOffer())) {
  708.             if ($offer->getAmountType() === 'percentage') {
  709.                 $totalPriceCoupon = (int)round($totalPriceCoupon + ($totalPriceCoupon $offer->getAmount() / 100));
  710.                 if ($offer->getAmountRibPayment()) {
  711.                     $totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash $offer->getAmountRibPayment() / 100));
  712.                 } else {
  713.                     $totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash $offer->getAmount() / 100));
  714.                 }
  715.             } elseif ($offer->getAmountType() === 'euro') {
  716.                 $totalPriceCoupon = (int)round($totalPriceCoupon $offer->getAmount());
  717.                 if ($offer->getAmountRibPayment()) {
  718.                     $totalPriceCash = (int)round($totalPriceCash $offer->getAmountRibPayment());
  719.                 } else {
  720.                     $totalPriceCash = (int)round($totalPriceCash $offer->getAmount());
  721.                 }
  722.             }
  723.         }
  724.         $formPayment $this->createForm(PaymentType::class, $tradeIn);
  725.         $formPayment->handleRequest($request);
  726.         if ($formPayment->isSubmitted() && $formPayment->isValid()) {
  727.             if (
  728.                 $tradeIn->getTStatus()->getSlug() == Status::trade_in_progress
  729.             ) {
  730.                 if (!empty($formPayment->get("rib")->getData())) {
  731.                     $tradeIn->setPaymentType(TradeIn::PAYMENT_TYPE_RIB);
  732.                     $priceMargin 35;
  733.                     $user $tradeIn->getUser();
  734.                     $bankName $formPayment->get("bankName")->getData();
  735.                     if ($bankName === 'Autre') {
  736.                         $bankName $formPayment->get("bankNameOther")->getData();
  737.                     }
  738.                     $bankBic $formPayment->get("bankBic")->getData();
  739.                     $bank $em->getRepository(Bank::class)->findOneBy([
  740.                         'name' => $bankName,
  741.                         'bic' => $bankBic,
  742.                     ]);
  743.                     if (!$bank) {
  744.                         $bank = new Bank();
  745.                         $bank->setName($bankName);
  746.                         $bank->setBic($bankBic);
  747.                         $bank->setIsUploaded(false);
  748.                         $em->persist($bank);
  749.                     }
  750.                     $bankAccount = new BankAccount();
  751.                     $bankAccount->setUser($user);
  752.                     $bankAccount->setBank($bank);
  753.                     $bankAccount->setRib($formPayment->get("rib")->getData());
  754.                     $bankAccount->setOwner($formPayment->get("ribOwner")->getData());
  755.                     $bankAccount->setIsUploaded(false);
  756.                     $em->persist($bankAccount);
  757.                     $em->flush();
  758.                     $tradeIn->setBankAccount($bankAccount);
  759.                     $em->persist($tradeIn);
  760.                     $em->flush();
  761.                 } elseif (
  762.                     $formPayment->get("paymentType")->getData() ==
  763.                     TradeIn::PAYMENT_TYPE_COUPON
  764.                 ) {
  765.                     $tradeIn->setPaymentType(TradeIn::PAYMENT_TYPE_COUPON);
  766.                     $priceMargin 25;
  767.                 } else {
  768.                     return $this->redirectToRoute("tradeIn.start");
  769.                 }
  770.                 $totalPrice 0;
  771.                 foreach ($productsTradeIn as $productTradeIn) {
  772.                     $productPrice $this->tradeInService->calculationProductPrice(
  773.                         $productTradeIn,
  774.                         $productTradeIn->getProduct(),
  775.                         $priceMargin
  776.                     );
  777.                     if ($offersData["showLoyaltyOffer"]) {
  778.                         $productPrice =
  779.                             $productPrice +
  780.                             ($productPrice *
  781.                                 $offersData["loyaltyOffer"]->getPercentage() / 100);
  782.                         $productTradeIn->setPrice((int)round($productPrice));
  783.                         $totalPrice += $productTradeIn->getPrice();
  784.                     } else {
  785.                         if (
  786.                             $tradeIn->getOffer() &&
  787.                             $tradeIn->getOffer()->getAmountType() === "percentage"
  788.                         ) {
  789.                             // Add check on tradeIn method selected to select the right amount offer
  790.                             if (
  791.                                 $tradeIn->getOffer()->getAmountRibPayment() != null &&
  792.                                 $tradeIn->getPaymentType() === TradeIn::PAYMENT_TYPE_RIB
  793.                             ) {
  794.                                 $amountToAdd $tradeIn->getOffer()->getAmountRibPayment();
  795.                             } else {
  796.                                 $amountToAdd $tradeIn->getOffer()->getAmount();
  797.                             }
  798.                             $productPrice =
  799.                                 $productPrice +
  800.                                 ($productPrice *
  801.                                     $amountToAdd) /
  802.                                 100;
  803.                         }
  804.                         $productTradeIn->setPrice((int)round($productPrice));
  805.                         $totalPrice += $productTradeIn->getPrice();
  806.                     }
  807.                 }
  808.                 if (
  809.                     !$offersData["showLoyaltyOffer"] &&
  810.                     $tradeIn->getOffer() &&
  811.                     $tradeIn->getOffer()->getAmountType() === "euro"
  812.                 ) {
  813.                     $totalPrice =
  814.                         $totalPrice $tradeIn->getOffer()->getAmount();
  815.                 }
  816.                 $status $statusRepository->findOneBy([
  817.                     "slug" => Status::tradein_todo,
  818.                 ]);
  819.                 $tradeIn->setCalculatedAmount($totalPrice);
  820.                 $tradeIn->setTStatus($status);
  821.                 $em->persist($tradeIn);
  822.                 $em->flush();
  823.                 $session $this->requestStack->getSession();
  824.                 $this->notificationSender->sendCustomerEmail(
  825.                     "Reprise #" .
  826.                     $tradeIn->getTradeCode() .
  827.                     " finalisée | BACK ipln",
  828.                     "emails/toValidate.html.twig",
  829.                     [
  830.                         "tradeIn" => $tradeIn,
  831.                         "firstname" => $tradeIn->getUser()->getFirstname(),
  832.                         "tradeCode" => $tradeIn->getTradeCode(),
  833.                         "products" => $tradeIn->getProductTradeIn(),
  834.                         "total" => $tradeIn->getCalculatedAmount(),
  835.                         "paymentType" => $tradeIn->getPaymentLabel()
  836.                     ],
  837.                     $tradeIn
  838.                 );
  839.                 //On récupère le type de la notification selon le statut de la reprise en cours
  840.                 $adminNotificationType $this->adminNotificationRepository->findOneBy(
  841.                     [
  842.                         "type" => $tradeIn->getTStatus()->getSlug(),
  843.                     ]
  844.                 );
  845.                 //S'il existe des notifications pour ce statut alors on envoi aux admins
  846.                 if ($adminNotificationType) {
  847.                     $this->notificationSender->sendAdminEmail(
  848.                         "Reprise #" .
  849.                         $tradeIn->getTradeCode() .
  850.                         " créée | BACK ipln",
  851.                         "emails/admin_newTradeIn.html.twig",
  852.                         [
  853.                             "firstname" => $tradeIn->getUser()->getFirstname(),
  854.                             "tradeCode" => $tradeIn->getTradeCode(),
  855.                             "products" => $tradeIn->getProductTradeIn(),
  856.                             "total" => $tradeIn->getCalculatedAmount(),
  857.                             "paymentType" => $tradeIn->getPaymentLabel(),
  858.                             "tradeInPath" => $request->getUriForPath(
  859.                                 $this->generateUrl("admin.tradein.editable", [
  860.                                     "id" => $tradeIn->getId(),
  861.                                 ])
  862.                             ),
  863.                         ],
  864.                         $adminNotificationType,
  865.                         $tradeIn
  866.                     );
  867.                 }
  868.                 return $this->redirectToRoute("reprise.confirm");
  869.             }
  870.         }
  871.         return $this->render("front/trade_in/payment_method.html.twig", [
  872.             "tradeIn" => $tradeIn,
  873.             "totalPriceCash" => $totalPriceCash,
  874.             "totalPriceCoupon" => $totalPriceCoupon,
  875.             "paymentForm" => $formPayment->createView(),
  876.         ]);
  877.     }
  878.     /**
  879.      * @Route("/ajout-adresse", name="reprise.missing.address")
  880.      */
  881.     public function missingAddress(TradeInRepository $tradeInRepositoryRequest $requestOdooApi $odooApi)
  882.     {
  883.         if (!$this->session->get('trade_in_id')) {
  884.             $this->addFlash('notice'"Vous n'avez pas encore créé de reprise");
  885.             return $this->redirectToRoute('tradeIn.start');
  886.         }
  887.         $tradeIn $tradeInRepository->find($this->session->get('trade_in_id'));
  888.         if (empty($tradeIn)) {
  889.             $this->addFlash('notice'"Reprise introuvable, veuillez démarrer une nouvelle reprise.");
  890.             return $this->redirectToRoute('tradeIn.start');
  891.         }
  892.         $customerAddressForm $this->createForm(CustomerAddressType::class);
  893.         $customerAddressForm->handleRequest($request);
  894.         if ($customerAddressForm->isSubmitted() && $customerAddressForm->isValid()) {
  895.             try {
  896.                 $addAddress $this->prestashopApi->addAdressUser(
  897.                     $tradeIn->getUser()->getPsId(),
  898.                     $customerAddressForm->get('country')->getData(),
  899.                     $customerAddressForm->get('postcode')->getData(),
  900.                     $customerAddressForm->get('city')->getData(),
  901.                     $customerAddressForm->get('streetAddress')->getData(),
  902.                     $customerAddressForm->get('phone')->getData(),
  903.                     $tradeIn->getUser()->getFirstname(),
  904.                     $tradeIn->getUser()->getLastname()
  905.                 );
  906.             } catch (\Exception $e) {
  907.                 $this->logger->error('Prestashop API error: ' $e->getMessage());
  908.                 $this->addFlash('notice''Une erreur est survenue lors de l\'ajout de votre adresse. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.');
  909.                 return $this->redirectToRoute('reprise.missing.address');
  910.             }
  911.             try {
  912.                 $user $tradeIn->getUser();
  913.                 $odooCustomer $odooApi->select(OdooEntityEnum::CUSTOMER, ['id'], ['email' => $user->getEmail()]);
  914.                 $countryId $customerAddressForm->get('country')->getData();
  915.                 $odooCountryId OdooCountryEnum::getOdooIdFromPrestashopId($countryId);
  916.                 $userData = [
  917.                     'name' => $user->getFirstname() . ' ' $user->getLastname(),
  918.                     'street' => $customerAddressForm->get("streetAddress")->getData(),
  919.                     'street2' => '',
  920.                     'zip' => $customerAddressForm->get("postcode")->getData(),
  921.                     'city' => $customerAddressForm->get("city")->getData(),
  922.                     'country_id' => $odooCountryId,
  923.                     'phone' => $customerAddressForm->get("phone")->getData(),
  924.                 ];
  925.                 $odooApi->update(OdooEntityEnum::CUSTOMER$odooCustomer[0]['id'], $userData);
  926.             } catch (\Exception $e) {
  927.                 $this->addFlash('warning''Erreur lors de l\'ajout de votre adresse.');
  928.                 return $this->redirectToRoute('reprise.missing.address');
  929.             }
  930.             if ($addAddress && $addAddress['id']) {
  931.                 return $this->redirectToRoute("tradeIn.shipping_method");
  932.             } else {
  933.                 $this->addFlash('notice'"Erreur lors de l'ajout de votre adresse.");
  934.                 return $this->redirectToRoute('reprise.missing.address');
  935.             }
  936.         }
  937.         $tradeIn $tradeInRepository->find($this->session->get('trade_in_id'));
  938.         return $this->render('front/trade_in/missing_address.html.twig', [
  939.             'tradeIn' => $tradeIn,
  940.             'customerAddressForm' => $customerAddressForm->createView()
  941.         ]);
  942.     }
  943.     /**
  944.      * @Route("/confirmation-reprise", name="reprise.confirm")
  945.      */
  946.     public function confirm(TradeInRepository $tradeInRepository)
  947.     {
  948.         if (!$this->session->get("trade_in_id")) {
  949.             $this->addFlash("notice""Vous n'avez pas encore créé de reprise");
  950.             return $this->redirectToRoute("tradeIn.start");
  951.         }
  952.         $tradeIn $tradeInRepository->find($this->session->get("trade_in_id"));
  953.         $entityChangeLog = new EntityChangeLog();
  954.         $entityChangeLog->setValue("La reprise a été créée");
  955.         $entityChangeLog->setEntityId($tradeIn->getId());
  956.         $entityChangeLog->setEntityName("trade_in");
  957.         $entityChangeLog->setUser($tradeIn->getUser());
  958.         $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  959.         $this->em->persist($entityChangeLog);
  960.         $this->em->flush();
  961.         if ($this->session->get("trade_in_id")) {
  962.             $this->session->remove("trade_in_id");
  963.         }
  964.         return $this->render("front/trade_in/confirmation.html.twig", [
  965.             "tradeIn" => $tradeIn,
  966.         ]);
  967.     }
  968.     public function generateChronopost(
  969.         TradeIn                $tradeIn,
  970.         EntityManagerInterface $em,
  971.         StatusRepository       $statusRepository,
  972.         Request                $request
  973.     )
  974.     {
  975.         $user $tradeIn->getUser();
  976.         if (!empty($user->getPsId())) {
  977.             $addresses $this->prestashopApi->findAddressCustomer($user->getPsId());
  978.         }
  979.         if (isset($addresses["addresses"][0]["address1"])) {
  980.             $res $this->chronopost->generateChronopost(
  981.                 $user->getFirstname(),
  982.                 $user->getLastname(),
  983.                 $addresses["addresses"][0]["address1"],
  984.                 $addresses["addresses"][0]["city"],
  985.                 "FR"//TODO
  986.                 "FRANCE",
  987.                 $user->getEmail(),
  988.                 "",
  989.                 $addresses["addresses"][0]["postcode"],
  990.                 $tradeIn->getTradeCode()
  991.             );
  992.             if (isset($res->return->reservationNumber)) {
  993.                 $entityChangeLog = new EntityChangeLog();
  994.                 $entityChangeLog->setValue(
  995.                     'L\'étiquette Chronopost a été envoyée au client.'
  996.                 );
  997.                 $entityChangeLog->setEntityId($tradeIn->getId());
  998.                 $entityChangeLog->setEntityName("trade_in");
  999.                 $entityChangeLog->setUser($this->getUser());
  1000.                 $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  1001.                 $em->persist($entityChangeLog);
  1002.                 $em->flush();
  1003.                 $this->notificationSender->sendCustomerEmail(
  1004.                     "Reprise #" .
  1005.                     $tradeIn->getTradeCode() .
  1006.                     " finalisée | BACK ipln",
  1007.                     "emails/acceptedByAdmin.html.twig",
  1008.                     [
  1009.                         "firstname" => $tradeIn->getUser()->getFirstname(),
  1010.                         "tradeCode" => $tradeIn->getTradeCode(),
  1011.                         "products" => $tradeIn->getProductTradeIn(),
  1012.                         "total" => $tradeIn->selectedAmount(),
  1013.                         "paymentType" => $tradeIn->getPaymentLabel(),
  1014.                     ],
  1015.                     $tradeIn
  1016.                 );
  1017.                 if (isset($res->return->resultParcelValue->skybillNumber)) {
  1018.                     $tradeIn->setTrackingCode(
  1019.                         $res->return->resultParcelValue->skybillNumber
  1020.                     );
  1021.                 }
  1022.                 $statusFinish $statusRepository->findOneBy([
  1023.                     "slug" => [Status::parcels_in_transit],
  1024.                 ]);
  1025.                 $tradeIn->setTStatus($statusFinish);
  1026.                 //On récupère le type de la notification selon le statut de la reprise en cours
  1027.                 $adminNotificationType $this->adminNotificationRepository->findOneBy(
  1028.                     [
  1029.                         "type" => $tradeIn->getTStatus()->getSlug(),
  1030.                     ]
  1031.                 );
  1032.                 //S'il existe des notifications pour ce statut alors on envoi aux admins
  1033.                 if ($adminNotificationType) {
  1034.                     $this->notificationSender->sendAdminEmail(
  1035.                         $tradeIn->getTStatus()->getLabel() .
  1036.                         " - Reprise #" .
  1037.                         $tradeIn->getTradeCode() .
  1038.                         " a évolué | BACK ipln",
  1039.                         "emails/admin_tradeInUpdated.html.twig",
  1040.                         [
  1041.                             "firstname" => $tradeIn->getUser()->getFirstname(),
  1042.                             "tradeCode" => $tradeIn->getTradeCode(),
  1043.                             "products" => $tradeIn->getProductTradeIn(),
  1044.                             "total" => $tradeIn->getCalculatedAmount(),
  1045.                             "paymentType" => $tradeIn->getPaymentLabel(),
  1046.                             "tradeInPath" => $request->getUriForPath(
  1047.                                 $this->generateUrl("admin.tradein.editable", [
  1048.                                     "id" => $tradeIn->getId(),
  1049.                                 ])
  1050.                             ),
  1051.                             "tradeInStatus" => $tradeIn
  1052.                                 ->getTStatus()
  1053.                                 ->getLabel(),
  1054.                         ],
  1055.                         $adminNotificationType,
  1056.                         $tradeIn
  1057.                     );
  1058.                 }
  1059.                 $entityChangeLog = new EntityChangeLog();
  1060.                 $entityChangeLog->setValue(
  1061.                     'Génération de l\'étiquette Chronopost.'
  1062.                 );
  1063.                 $entityChangeLog->setEntityId($tradeIn->getId());
  1064.                 $entityChangeLog->setEntityName("trade_in");
  1065.                 $entityChangeLog->setUser($this->getUser());
  1066.                 $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  1067.                 $em->persist($entityChangeLog);
  1068.                 $em->flush();
  1069.             } else {
  1070.                 $entityChangeLog = new EntityChangeLog();
  1071.                 $entityChangeLog->setValue(
  1072.                     'Une erreur est survenue lors de la génération de l\'étiquette Chronopost. Elle n\'a pas été envoyée au client.'
  1073.                 );
  1074.                 $entityChangeLog->setEntityId($tradeIn->getId());
  1075.                 $entityChangeLog->setEntityName("trade_in");
  1076.                 $entityChangeLog->setUser($this->getUser());
  1077.                 $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  1078.                 $em->persist($entityChangeLog);
  1079.                 $em->flush();
  1080.             }
  1081.         } else {
  1082.             $entityChangeLog = new EntityChangeLog();
  1083.             $entityChangeLog->setValue(
  1084.                 'Une erreur est survenue lors de la génération de l\'étiquette Chronopost. Le client n\'a pas d\'adresse renseignée sur son compte.'
  1085.             );
  1086.             $entityChangeLog->setEntityId($tradeIn->getId());
  1087.             $entityChangeLog->setEntityName("trade_in");
  1088.             $entityChangeLog->setUser($this->getUser());
  1089.             $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  1090.             $em->persist($entityChangeLog);
  1091.             $em->flush();
  1092.         }
  1093.     }
  1094.     /**
  1095.      * @Route("/reponse-offre/{tradeCode}/{purposeHash}/{response}", name="tradeIn.response")
  1096.      */
  1097.     public function responseOffer(
  1098.         TradeInRepository      $tradeInRepository,
  1099.         string                 $tradeCode,
  1100.         string                 $purposeHash,
  1101.         string                 $response,
  1102.         Request                $request,
  1103.         EntityManagerInterface $em,
  1104.         StatusRepository       $statusRepository
  1105.     )
  1106.     {
  1107.         $tradeIn $tradeInRepository->findOneBy(["TradeCode" => $tradeCode]);
  1108.         if (
  1109.             ($tradeIn->getTStatus()->getSlug() == Status::against_offer_sent ||
  1110.                 $tradeIn->getTStatus()->getSlug() ==
  1111.                 Status::against_offer_sent_final) &&
  1112.             $tradeIn->getPurposeHash() == $purposeHash
  1113.         ) {
  1114.             if ($response == "acceptFinalOffer") {
  1115.                 $products $tradeIn->getProductTradeIn();
  1116.                 foreach ($products as $product) {
  1117.                     if ($product->isRefuse()) {
  1118.                         $productsAccessories $product->getProductTradeInAccessories();
  1119.                         if ($productsAccessories) {
  1120.                             foreach ($productsAccessories as $accessory) {
  1121.                                 $em->remove($accessory);
  1122.                             }
  1123.                         }
  1124.                         $em->remove($product);
  1125.                     }
  1126.                 }
  1127.                 $status $statusRepository->findOneBy([
  1128.                     "slug" => Status::accounting_entry,
  1129.                 ]);
  1130.                 $tradeIn->setTStatus($status);
  1131.                 $responseFormatted "acceptée";
  1132.             } elseif ($response == "acceptEstimateOffer") {
  1133.                 $products $tradeIn->getProductTradeIn();
  1134.                 foreach ($products as $product) {
  1135.                     if ($product->isRefuse()) {
  1136.                         $productsAccessories $product->getProductTradeInAccessories();
  1137.                         if ($productsAccessories) {
  1138.                             foreach ($productsAccessories as $accessory) {
  1139.                                 $em->remove($accessory);
  1140.                             }
  1141.                         }
  1142.                         $em->remove($product);
  1143.                     }
  1144.                 }
  1145.                 try {
  1146.                     $this->generateChronopost(
  1147.                         $tradeIn,
  1148.                         $em,
  1149.                         $statusRepository,
  1150.                         $request
  1151.                     );
  1152.                 } catch (\Exception $e) {
  1153.                     $this->logger->error('Prestashop API error: ' $e->getMessage());
  1154.                     $this->addFlash(
  1155.                         'notice',
  1156.                         'Une erreur est survenue lors de la génération de l\'étiquette Chronopost. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.'
  1157.                     );
  1158.                     return $this->redirectToRoute('tradeIn.response', [
  1159.                         'tradeCode' => $tradeIn->getTradeCode(),
  1160.                         'purposeHash' => $tradeIn->getPurposeHash(),
  1161.                         'response' => $response,
  1162.                     ]);
  1163.                 }
  1164.                 $responseFormatted "acceptée";
  1165.             } elseif ($response == "refuseFinalOffer") {
  1166.                 //Refuse by user with product in shop
  1167.                 $status $statusRepository->findOneBy([
  1168.                     "slug" => Status::tradein_refuse,
  1169.                 ]);
  1170.                 $tradeIn->setTStatus($status);
  1171.                 $responseFormatted "refusée";
  1172.             } elseif ($response == "refuseEstimateOffer") {
  1173.                 //Refuse by user without product in shop
  1174.                 $status $statusRepository->findOneBy([
  1175.                     "slug" => Status::tradein_refuse,
  1176.                 ]);
  1177.                 $tradeIn->setTStatus($status);
  1178.                 $responseFormatted "refusée";
  1179.             }
  1180.             $em->flush();
  1181.             $entityChangeLog = new EntityChangeLog();
  1182.             $entityChangeLog->setValue(
  1183.                 'L\'offre d\'un montant de ' .
  1184.                 $tradeIn->selectedAmount() .
  1185.                 "€ a été " .
  1186.                 $responseFormatted .
  1187.                 " par le client."
  1188.             );
  1189.             $entityChangeLog->setEntityId($tradeIn->getId());
  1190.             $entityChangeLog->setEntityName("trade_in");
  1191.             $entityChangeLog->setUser($tradeIn->getUser());
  1192.             $entityChangeLog->setAddedAt(new \DateTimeImmutable());
  1193.             $em->persist($entityChangeLog);
  1194.             $em->flush();
  1195.             //On récupère le type de la notification selon le statut de la reprise en cours
  1196.             $adminNotificationType $this->adminNotificationRepository->findOneBy(
  1197.                 [
  1198.                     "type" => $tradeIn->getTStatus()->getSlug(),
  1199.                 ]
  1200.             );
  1201.             //S'il existe des notifications pour ce statut alors on envoi aux admins
  1202.             if ($adminNotificationType) {
  1203.                 $this->notificationSender->sendAdminEmail(
  1204.                     "Reprise #" .
  1205.                     $tradeIn->getTradeCode() .
  1206.                     " a évolué | BACK ipln",
  1207.                     "emails/admin_tradeInUpdated.html.twig",
  1208.                     [
  1209.                         "firstname" => $tradeIn->getUser()->getFirstname(),
  1210.                         "tradeCode" => $tradeIn->getTradeCode(),
  1211.                         "products" => $tradeIn->getProductTradeIn(),
  1212.                         "total" => $tradeIn->getCalculatedAmount(),
  1213.                         "paymentType" => $tradeIn->getPaymentLabel(),
  1214.                         "tradeInPath" => $request->getUriForPath(
  1215.                             $this->generateUrl("admin.tradein.editable", [
  1216.                                 "id" => $tradeIn->getId(),
  1217.                             ])
  1218.                         ),
  1219.                         "tradeInStatus" => $tradeIn->getTStatus()->getLabel(),
  1220.                     ],
  1221.                     $adminNotificationType,
  1222.                     $tradeIn
  1223.                 );
  1224.             }
  1225.             return $this->render("front/trade_in/email_response.html.twig", [
  1226.                 "tradeIn" => $tradeIn,
  1227.                 "response" => $response,
  1228.                 "total" => $tradeIn->getCalculatedAmount(),
  1229.                 "responseFormatted" => $responseFormatted,
  1230.             ]);
  1231.         } else {
  1232.             return $this->redirectToRoute("index");
  1233.         }
  1234.     }
  1235.     private function createPrestashopAccount(
  1236.         string $email,
  1237.         string $password,
  1238.         string $firstname,
  1239.         string $lastname,
  1240.         string $phone,
  1241.         int    $countryId,
  1242.         string $postcode,
  1243.         string $address,
  1244.         string $city
  1245.     )
  1246.     {
  1247.         $userPresta $this->prestashopApi->findUserByEmail($email);
  1248.         if ($userPresta["accountExist"] == false) {
  1249.             $user $this->prestashopApi->createUser(
  1250.                 $firstname,
  1251.                 $lastname,
  1252.                 $phone,
  1253.                 $email,
  1254.                 $password,
  1255.                 $countryId,
  1256.                 $postcode,
  1257.                 $city,
  1258.                 $address
  1259.             );
  1260.         } else {
  1261.             $user $userPresta;
  1262.         }
  1263.         return $user["id"];
  1264.     }
  1265. }