src/Controller/Front/TradeInController.php line 111
<?phpnamespace App\Controller\Front;use App\Entity\Bank;use App\Entity\BankAccount;use App\Entity\EntityChangeLog;use App\Entity\LoyaltyOffer;use App\Entity\Offer;use App\Entity\Product;use App\Entity\ProductTradeIn;use App\Entity\Status;use App\Entity\TradeIn;use App\Entity\User;use App\Enum\OdooCountryEnum;use App\Enum\OdooEntityEnum;use App\Form\CustomerAddressType;use App\Form\PaymentType;use App\Form\ProductTradeInType;use App\Form\ShippingType;use App\Form\StepOneType;use App\Repository\AdminNotificationRepository;use App\Repository\LoyaltyOfferRepository;use App\Repository\OfferRepository;use App\Repository\ProductRepository;use App\Repository\StatusRepository;use App\Repository\TradeInFileRepository;use App\Repository\TradeInRepository;use App\Repository\UserRepository;use App\Service\ChronopostTools;use App\Service\NotificationSender;use App\Service\OdooApi;use App\Service\PrestashopApi;use App\Service\TradeInService;use App\Tools\Tools;use Doctrine\ORM\EntityManagerInterface;use Psr\Log\LoggerInterface;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\RequestStack;use Symfony\Component\Mailer\MailerInterface;use Symfony\Component\Routing\Annotation\Route;use Symfony\Component\Form\FormError;use App\Service\LoyaltyService;/*** Class TradeInController* @package App\Controller\Front*/class TradeInController extends AbstractController{private RequestStack $requestStack;private PrestashopApi $prestashopApi;private \Symfony\Component\HttpFoundation\Session\SessionInterface $session;private $mailer;private EntityManagerInterface $em;private NotificationSender $notificationSender;private AdminNotificationRepository $adminNotificationRepository;private TradeInService $tradeInService;protected ChronopostTools $chronopost;private LoggerInterface $logger;private LoyaltyService $loyaltyService;/*** TradeInController constructor.* @param RequestStack $requestStack* @param PrestashopApi $prestashopApi*/public function __construct(RequestStack $requestStack,PrestashopApi $prestashopApi,MailerInterface $mailer,EntityManagerInterface $em,NotificationSender $notificationSender,AdminNotificationRepository $adminNotificationRepository,ChronopostTools $chronopostService,TradeInService $tradeInService,LoggerInterface $logger,LoyaltyService $loyaltyService){$this->requestStack = $requestStack;$this->chronopost = $chronopostService;$this->prestashopApi = $prestashopApi;$this->session = $this->requestStack->getSession();$this->mailer = $mailer;$this->em = $em;$this->notificationSender = $notificationSender;$this->adminNotificationRepository = $adminNotificationRepository;$this->tradeInService = $tradeInService;$this->logger = $logger;$this->loyaltyService = $loyaltyService;}/*** @Route("/reset-reprise", name="tradeIn.reset")*/public function resetTradeIn(){$session = $this->requestStack->getSession();if ($session->get("trade_in_id")) {$session->remove("trade_in_id");}return $this->redirectToRoute("tradeIn.start");}/*** @Route("/reprise", name="tradeIn.start")*/public function tradeIn(Request $request,UserRepository $userRepository,ProductRepository $productRepository,TradeInRepository $tradeInRepository,OfferRepository $offerRepository,EntityManagerInterface $em,StatusRepository $statusRepository,OdooApi $odooApi,LoyaltyOfferRepository $loyaltyOfferRepository,){$formStepOne = $this->createForm(StepOneType::class);$formStepOne->handleRequest($request);$session = $this->requestStack->getSession();if ($formStepOne->isSubmitted() && $formStepOne->isValid()) {if ($formStepOne->get("productTradeIn")->get("shutterCount")->getData() === 3) {if ($formStepOne->get("productTradeIn")->get("numberShutterCount")->getData() > 125000) {$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.");return $this->redirectToRoute("tradeIn.start");}}$formStepOneUser = $formStepOne->get("user");if ($session->get("trade_in_id")) {$session->remove("trade_in_id");}try {$userPresta = $this->prestashopApi->findUserByEmailPassword($formStepOneUser->get("email")->getData(),$formStepOneUser->get("plainPassword")->getData());if ($userPresta['accountExist'] === true && $userPresta['validPassword'] === false) {$formStepOneUser->get('plainPassword')->addError(new FormError('Mot de passe incorrect.'));return $this->render('trade_in/start.html.twig', ['formStepOne' => $formStepOne->createView(),]);}} catch (\Exception $e) {$this->logger->error('Prestashop API error: ' . $e->getMessage());$this->addFlash('notice','Une erreur est survenue lors de la connexion à votre compte PrestaShop. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.');return $this->redirectToRoute("tradeIn.start");}$user = $userRepository->findOneBy(["email" => $formStepOne->get("user")->get("email")->getData(),]);if (!$user) {$user = new User();$user->setEmail($formStepOneUser->get("email")->getData());if (!empty($userPresta["firstname"])) {$user->setFirstname($userPresta["firstname"]);$user->setLastname($userPresta["lastname"]);} else {$user->setFirstname($formStepOneUser->get("firstname")->getData());$user->setLastname($formStepOneUser->get("lastname")->getData());}$user->setRoles(["ROLE_CUSTOMER"]);if ($userPresta["accountExist"] == true && $userPresta["validPassword"] == true) {$user->setPsId($userPresta["psId"]);} elseif ($userPresta["accountExist"] == false) {try {$prestashopUser = $this->createPrestashopAccount($formStepOneUser->get("email")->getData(),$formStepOneUser->get("plainPassword")->getData(),$formStepOneUser->get("firstname")->getData(),$formStepOneUser->get("lastname")->getData(),$formStepOneUser->get("phone")->getData(),$formStepOneUser->get("country")->getData(),$formStepOneUser->get("postcode")->getData(),$formStepOneUser->get("streetAddress")->getData(),$formStepOneUser->get("city")->getData());} catch (\Exception $e) {$this->logger->error('Prestashop API error: ' . $e->getMessage());$this->addFlash('notice','Une erreur est survenue lors de la création de votre compte PrestaShop. Veuillez réessayer ou contacter un administrateur si l\'erreur persiste.');return $this->redirectToRoute("tradeIn.start");}if (isset($prestashopUser)) {$user->setPsId($prestashopUser);$user->setActive(true);} else {$this->addFlash("notice", "Erreur lors de la création de votre compte");return $this->redirectToRoute("tradeIn.start");}} else {$this->addFlash("notice", "Erreur avec le mot de passe indiqué");return $this->redirectToRoute("tradeIn.start");}$em->persist($user);$em->flush();}$statusInProgress = $statusRepository->findOneBy(["slug" => Status::trade_in_progress,]);$tradeIn = new TradeIn();$tradeIn->setTStatus($statusInProgress);$tradeIn->setUser($user);$tradeIn->setTradeCode(Tools::generateTradeCode());$tradeIn->setIsInStore(false);$offerAvailable = $offerRepository->findOneByOvercost();if ($offerAvailable) {$tradeIn->setOffer($offerAvailable);}if ($creatorCode = $session->get("creator")) {$tradeIn->setCreatorCode($creatorCode);}$userLoyaltyTierName = $this->loyaltyService->getUserTier($user->getEmail());if ($userLoyaltyTierName) {$loyaltyOffer = $loyaltyOfferRepository->findOneBy(['tierName' => $userLoyaltyTierName,'active' => true,]);if ($loyaltyOffer) {$tradeIn->addLoyaltyOffer($loyaltyOffer);}}$em->persist($tradeIn);$em->flush();$adminNotificationType = $this->adminNotificationRepository->findOneBy(["type" => $tradeIn->getTStatus()->getSlug(),]);$formStepOneProduct = $formStepOne->get("productTradeIn");$product = $productRepository->find($formStepOneProduct->get("product")->getData());$productTradeIn = new ProductTradeIn();$productTradeIn->setProduct($product);$productTradeIn->setPackaging($formStepOneProduct->get("packaging")->getData());$productTradeIn->setShutterCount($formStepOneProduct->get("shutterCount")->getData());$productTradeIn->setAccessories($formStepOneProduct->get("accessories")->getData());$productTradeIn->setProductQuality($formStepOneProduct->get("productQuality")->getData());$productTradeIn->setStatus(0); // NOT USE$productTradeIn->setTradeIn($tradeIn);$productTradeIn->setPrice($this->tradeInService->calculationProductPrice($productTradeIn, $product));$em->persist($productTradeIn);$em->flush();$tradeIn->setCalculatedAmount($productTradeIn->getPrice());$em->persist($tradeIn);$em->flush();$session->set("trade_in_id", $tradeIn->getId());// =========================// ODOO CONTACT RESOLUTION (Prestashop -> Odoo) with integration_id=1// =========================try {$psId = (int)$user->getPsId();if (!$psId) {return $this->redirectToRoute('reprise.missing.address');}// --------------------------------------------------// 1) integration_id fixed// --------------------------------------------------$integrationId = 1;// --------------------------------------------------// 2) Build address (form > Prestashop fallback)// --------------------------------------------------$countryId = $formStepOneUser->get('country')->getData();$odooCountryId = $countryId? OdooCountryEnum::getOdooIdFromPrestashopId($countryId): null;$address = ['street' => (string)($formStepOneUser->get('streetAddress')->getData() ?? ''),'street2' => '','zip' => (string)($formStepOneUser->get('postcode')->getData() ?? ''),'city' => (string)($formStepOneUser->get('city')->getData() ?? ''),'country_id' => $odooCountryId,'phone' => (string)($formStepOneUser->get('phone')->getData() ?? ''),];$hasAddress = static function (array $a): bool {foreach (['street', 'zip', 'city', 'country_id', 'phone'] as $k) {if (!empty($a[$k])) return true;}return false;};if (!$hasAddress($address)) {$psAddress = $this->prestashopApi->findAddressCustomer($psId);if (!$psAddress) {return $this->redirectToRoute('reprise.missing.address');}$address = ['street' => (string)($psAddress['address1'] ?? ''),'street2' => (string)($psAddress['address2'] ?? ''),'zip' => (string)($psAddress['postcode'] ?? ''),'city' => (string)($psAddress['city'] ?? ''),'country_id' => !empty($psAddress['id_country'])? OdooCountryEnum::getOdooIdFromPrestashopId($psAddress['id_country']): null,'phone' => (string)($psAddress['phone'] ?? ''),];if (!$hasAddress($address)) {return $this->redirectToRoute('reprise.missing.address');}}$fullName = trim(($user->getFirstname() ?? '') . ' ' . ($user->getLastname() ?? ''));// --------------------------------------------------// 3) Find or create res.partner// --------------------------------------------------$partnerId = null;$partners = $odooApi->select(OdooEntityEnum::CUSTOMER,['id', 'email'],['email' => $user->getEmail()]);if (!empty($partners) && !empty($partners[0]['id'])) {$partnerId = (int)$partners[0]['id'];} else {$createdPartner = $odooApi->create(OdooEntityEnum::CUSTOMER, ['type' => 'contact','name' => $fullName,'email' => $user->getEmail(),'street' => $address['street'],'street2' => $address['street2'],'zip' => $address['zip'],'city' => $address['city'],'country_id' => $address['country_id'],'phone' => $address['phone'],]);$partnerId = is_array($createdPartner)? (int)($createdPartner['id'] ?? $createdPartner[0] ?? 0): (int)$createdPartner;if (!$partnerId) {throw new \RuntimeException('Failed to create res.partner');}}// --------------------------------------------------// 4) integration.res.partner.external (integration_id mandatory)// --------------------------------------------------$external = $odooApi->select(OdooEntityEnum::INTEGRATION_EXTERNAL,['id'],['code' => (string)$psId,'integration_id' => $integrationId,]);$externalId = null;if (!empty($external) && !empty($external[0]['id'])) {$externalId = (int)$external[0]['id'];} else {$createdExternal = $odooApi->create(OdooEntityEnum::INTEGRATION_EXTERNAL,['code' => (string)$psId,'integration_id' => $integrationId,]);$externalId = is_array($createdExternal)? (int)($createdExternal['id'] ?? $createdExternal[0] ?? 0): (int)$createdExternal;if (!$externalId) {throw new \RuntimeException('Failed to create integration external');}}// --------------------------------------------------// 5) integration.res.partner.mapping (integration_id mandatory too!)// --------------------------------------------------$mapping = $odooApi->select(OdooEntityEnum::INTEGRATION_MAPPING,['id'],['external_partner_id' => $externalId,'partner_id' => $partnerId,'integration_id' => $integrationId,]);if (empty($mapping)) {$odooApi->create(OdooEntityEnum::INTEGRATION_MAPPING,['external_partner_id' => $externalId,'partner_id' => $partnerId,'integration_id' => $integrationId,]);}// --------------------------------------------------// 6) Final sync partner// --------------------------------------------------$odooApi->update(OdooEntityEnum::CUSTOMER, $partnerId, ['type' => 'contact','name' => $fullName,'email' => $user->getEmail(),'street' => $address['street'],'street2' => $address['street2'],'zip' => $address['zip'],'city' => $address['city'],'country_id' => $address['country_id'],'phone' => $address['phone'],]);$tradeIn->setOdooUserId($partnerId);$em->persist($tradeIn);$em->flush();} catch (\Exception $e) {$this->addFlash('warning','An error occurred while processing your account. ' . $e->getMessage());return $this->redirectToRoute('tradeIn.start');}// Send admin notification if availableif ($adminNotificationType) {$this->notificationSender->sendAdminEmail($tradeIn->getTStatus()->getLabel() . " - Reprise #" . $tradeIn->getTradeCode() . " a évolué | BACK ipln","emails/admin_tradeInUpdated.html.twig",["firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->getCalculatedAmount(),"paymentType" => "Non défini","tradeInPath" => $request->getUriForPath($this->generateUrl("admin.tradein.editable", ["id" => $tradeIn->getId(),])),"tradeInStatus" => $tradeIn->getTStatus()->getLabel(),],$adminNotificationType,$tradeIn);}return $this->redirectToRoute("tradeIn.addProduct");}$tradeInProgress = false;if ($session->get("trade_in_id") && $tradeInRepository->find($session->get("trade_in_id"))) {$tradeInProgress = true;}return $this->render("front/trade_in/begin.html.twig", ["formStepOne" => $formStepOne->createView(),"tradeInProgress" => $tradeInProgress]);}/*** @Route("/ajout-produit", name="tradeIn.addProduct")*/public function addProduct(Request $request,TradeInRepository $tradeInRepository,ProductRepository $productRepository,OfferRepository $offerRepository,EntityManagerInterface $em){if (!$this->session->get("trade_in_id")) {$this->addFlash("notice", "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute("tradeIn.start");}$tradeIn = $tradeInRepository->find($this->session->get("trade_in_id"));if (empty($tradeIn)) {$this->addFlash("notice","Reprise introuvable, veuillez démarrer une nouvelle reprise.");return $this->redirectToRoute("tradeIn.start");}$formStepTwo = $this->createForm(ProductTradeInType::class);$formStepTwo->handleRequest($request);if ($formStepTwo->isSubmitted() && $formStepTwo->isValid()) {if ($formStepTwo->get("shutterCount")->getData() === 3) {if ($formStepTwo->get("numberShutterCount")->getData() > 125000) {$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.");return $this->redirectToRoute("tradeIn.addProduct");}}$product = $productRepository->find($formStepTwo->get("product")->getData());$productTradeIn = new ProductTradeIn();$productTradeIn->setProduct($product);$productTradeIn->setPackaging($formStepTwo->get("packaging")->getData());$productTradeIn->setShutterCount($formStepTwo->get("shutterCount")->getData());$productTradeIn->setAccessories($formStepTwo->get("accessories")->getData());$productTradeIn->setProductQuality($formStepTwo->get("productQuality")->getData());$productTradeIn->setStatus(0); //NOT USE$productTradeIn->setTradeIn($tradeIn);$productTradeIn->setPrice($this->tradeInService->calculationProductPrice($productTradeIn, $product));$em->persist($productTradeIn);$offerAvailable = $offerRepository->findOneByOvercost();if ($offerAvailable) {$tradeIn->setOffer($offerAvailable);}$tradeIn->setCalculatedAmount($tradeIn->getCalculatedAmount() + $productTradeIn->getPrice());$em->persist($tradeIn);$em->flush();return $this->redirectToRoute("tradeIn.addProduct");}$offersData = $this->getBestLoyaltyOrOfferTotal($tradeIn);return $this->render("front/trade_in/add_product.html.twig", ["tradeIn" => $tradeIn,"formStepTwo" => $formStepTwo->createView(),"loyaltyOffer" => $offersData["loyaltyOffer"],"showLoyaltyOffer" => $offersData["showLoyaltyOffer"],"totalOffer" => $offersData["totalOffer"],"totalLoyalty" => $offersData["totalLoyalty"],]);}private function calculateOfferTotal(TradeIn $tradeIn, Offer $offer){if ($offer->getAmountType() === "percentage") {return (int)round($tradeIn->getCalculatedAmount()+ ($tradeIn->getCalculatedAmount() * $offer->getAmount() / 100));}if ($offer->getAmountType() === "euro") {return (int)round($tradeIn->getCalculatedAmount() + $offer->getAmount());}}private function getBestLoyaltyOrOfferTotal(TradeIn $tradeIn){$tradeInLoyaltyOffer = $tradeIn->getLoyaltyOffer();$loyaltyOfferValues = $tradeInLoyaltyOffer->getValues();$showLoyaltyOffer = false;$loyaltyOffer = null;$totalOffer = 0;$totalLoyalty = 0;$offer = $tradeIn->getOffer();$hasLoyalty = !empty($loyaltyOfferValues);if ($hasLoyalty) {$loyaltyOffer = $loyaltyOfferValues[0];$totalLoyalty = (int)round($tradeIn->getCalculatedAmount()+ ($tradeIn->getCalculatedAmount() * $loyaltyOffer->getPercentage() / 100));}if ($offer) {$totalOffer = $this->calculateOfferTotal($tradeIn, $offer);}if ($hasLoyalty && $offer) {$showLoyaltyOffer = $totalLoyalty >= $totalOffer;} elseif ($hasLoyalty) {$showLoyaltyOffer = true;}return ["loyaltyOffer" => $loyaltyOffer,"showLoyaltyOffer" => $showLoyaltyOffer,"totalOffer" => $totalOffer,"totalLoyalty" => $totalLoyalty,];}/*** @Route("/ajout-fichiers", name="tradeIn.addFiles")*/public function addFiles(Request $request,TradeInRepository $tradeInRepository){if (!$this->session->get("trade_in_id")) {$this->addFlash("notice", "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute("tradeIn.start");}$tradeIn = $tradeInRepository->find($this->session->get("trade_in_id"));if (empty($tradeIn)) {$this->addFlash("notice","Reprise introuvable, veuillez démarrer une nouvelle reprise.");return $this->redirectToRoute("tradeIn.start");}$offersData = $this->getBestLoyaltyOrOfferTotal($tradeIn);return $this->render("front/trade_in/add_files.html.twig", ["tradeIn" => $tradeIn,"loyaltyOffer" => $offersData["loyaltyOffer"],"showLoyaltyOffer" => $offersData["showLoyaltyOffer"],"totalOffer" => $offersData["totalOffer"],"totalLoyalty" => $offersData["totalLoyalty"],]);}/*** @Route("/choix-de-transport", name="tradeIn.shipping_method")*/public function shippingMethod(Request $request,TradeInRepository $tradeInRepository,ShippingType $shippingType,StatusRepository $statusRepository,EntityManagerInterface $em){if (!$this->session->get("trade_in_id")) {$this->addFlash("notice", "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute("tradeIn.start");}$tradeIn = $tradeInRepository->find($this->session->get("trade_in_id"));if (empty($tradeIn)) {$this->addFlash("notice","Reprise introuvable, veuillez démarrer une nouvelle reprise.");return $this->redirectToRoute("tradeIn.start");}$shippingTypeForm = $this->createForm(ShippingType::class, $tradeIn);$shippingTypeForm->handleRequest($request);if ($shippingTypeForm->isSubmitted() && $shippingTypeForm->isValid()) {$shippingType = $shippingTypeForm->get("shippingType")->getData();if ($shippingType === "ship_chronopost") {$tradeIn->setDepositCity(null);} elseif ($shippingType === "ship_lyon") {$tradeIn->setDepositCity(TradeIn::CONST_LYON);} elseif ($shippingType === "ship_paris") {$tradeIn->setDepositCity(TradeIn::CONST_PARIS);}$em->persist($tradeIn);$em->flush();return $this->redirectToRoute("tradeIn.payment_method");}return $this->render("front/trade_in/shipping_method.html.twig", ["tradeIn" => $tradeIn,"shippingTypeForm" => $shippingTypeForm->createView()]);}/*** @Route("/type-de-paiement", name="tradeIn.payment_method")*/public function tradeInPayment(Request $request,TradeInRepository $tradeInRepository,TradeInFileRepository $tradeInFileRepository,EntityManagerInterface $em,StatusRepository $statusRepository){if (!$this->session->get("trade_in_id")) {$this->addFlash("notice", "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute("tradeIn.start");}$tradeIn = $tradeInRepository->find($this->session->get("trade_in_id"));if (empty($tradeIn)) {$this->addFlash("notice","Reprise introuvable, veuillez démarrer une nouvelle reprise.");return $this->redirectToRoute("tradeIn.start");}$productTradeIn = $tradeIn->getProductTradeIn();$tradeInFile = $tradeInFileRepository->findBy(["ProductTradeIn" => $productTradeIn[0],]);if (empty($tradeInFile)) {$this->addFlash("notice","Aucune photos trouvé, merci d'ajouter les photos de votre produit");return $this->redirectToRoute("tradeIn.addFiles");}$userPsId = $tradeIn->getUser()->getPsId();if ($userPsId == null) {$psUser = $this->prestashopApi->findUserByEmail($tradeIn->getUser()->getEmail());if ($psUser['accountExist']) {$userPsId = $psUser['psId'];$tradeIn->getUser()->setPsId($userPsId);$em->persist($tradeIn->getUser());$em->flush();}}//Redirect if missing address of customertry {$addresses = $this->prestashopApi->findAddressCustomer($tradeIn->getUser()->getPsId());} catch (\Throwable $e) {$this->logger->error('Prestashop API error: ' . $e->getMessage());$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.');return $this->redirectToRoute('tradeIn.addFiles');}if (empty($addresses)) {return $this->redirectToRoute('reprise.missing.address');}$productsTradeIn = $tradeIn->getProductTradeIn();$totalPriceCash = 0;$totalPriceCoupon = 0;foreach ($productsTradeIn as $productTradeIn) {$totalPriceCash += $this->tradeInService->calculationProductPrice($productTradeIn,$productTradeIn->getProduct(),35);}foreach ($productsTradeIn as $productTradeIn) {$totalPriceCoupon += $this->tradeInService->calculationProductPrice($productTradeIn,$productTradeIn->getProduct(),25);}$offersData = $this->getBestLoyaltyOrOfferTotal($tradeIn);if ($offersData["showLoyaltyOffer"] && $offersData['loyaltyOffer']) {$totalPriceCoupon = (int)round($totalPriceCoupon + ($totalPriceCoupon * $offersData['loyaltyOffer']->getPercentage() / 100));$totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash * $offersData['loyaltyOffer']->getPercentage() / 100));} elseif (($offer = $tradeIn->getOffer())) {if ($offer->getAmountType() === 'percentage') {$totalPriceCoupon = (int)round($totalPriceCoupon + ($totalPriceCoupon * $offer->getAmount() / 100));if ($offer->getAmountRibPayment()) {$totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash * $offer->getAmountRibPayment() / 100));} else {$totalPriceCash = (int)round($totalPriceCash + ($totalPriceCash * $offer->getAmount() / 100));}} elseif ($offer->getAmountType() === 'euro') {$totalPriceCoupon = (int)round($totalPriceCoupon + $offer->getAmount());if ($offer->getAmountRibPayment()) {$totalPriceCash = (int)round($totalPriceCash + $offer->getAmountRibPayment());} else {$totalPriceCash = (int)round($totalPriceCash + $offer->getAmount());}}}$formPayment = $this->createForm(PaymentType::class, $tradeIn);$formPayment->handleRequest($request);if ($formPayment->isSubmitted() && $formPayment->isValid()) {if ($tradeIn->getTStatus()->getSlug() == Status::trade_in_progress) {if (!empty($formPayment->get("rib")->getData())) {$tradeIn->setPaymentType(TradeIn::PAYMENT_TYPE_RIB);$priceMargin = 35;$user = $tradeIn->getUser();$bankName = $formPayment->get("bankName")->getData();if ($bankName === 'Autre') {$bankName = $formPayment->get("bankNameOther")->getData();}$bankBic = $formPayment->get("bankBic")->getData();$bank = $em->getRepository(Bank::class)->findOneBy(['name' => $bankName,'bic' => $bankBic,]);if (!$bank) {$bank = new Bank();$bank->setName($bankName);$bank->setBic($bankBic);$bank->setIsUploaded(false);$em->persist($bank);}$bankAccount = new BankAccount();$bankAccount->setUser($user);$bankAccount->setBank($bank);$bankAccount->setRib($formPayment->get("rib")->getData());$bankAccount->setOwner($formPayment->get("ribOwner")->getData());$bankAccount->setIsUploaded(false);$em->persist($bankAccount);$em->flush();$tradeIn->setBankAccount($bankAccount);$em->persist($tradeIn);$em->flush();} elseif ($formPayment->get("paymentType")->getData() ==TradeIn::PAYMENT_TYPE_COUPON) {$tradeIn->setPaymentType(TradeIn::PAYMENT_TYPE_COUPON);$priceMargin = 25;} else {return $this->redirectToRoute("tradeIn.start");}$totalPrice = 0;foreach ($productsTradeIn as $productTradeIn) {$productPrice = $this->tradeInService->calculationProductPrice($productTradeIn,$productTradeIn->getProduct(),$priceMargin);if ($offersData["showLoyaltyOffer"]) {$productPrice =$productPrice +($productPrice *$offersData["loyaltyOffer"]->getPercentage() / 100);$productTradeIn->setPrice((int)round($productPrice));$totalPrice += $productTradeIn->getPrice();} else {if ($tradeIn->getOffer() &&$tradeIn->getOffer()->getAmountType() === "percentage") {// Add check on tradeIn method selected to select the right amount offerif ($tradeIn->getOffer()->getAmountRibPayment() != null &&$tradeIn->getPaymentType() === TradeIn::PAYMENT_TYPE_RIB) {$amountToAdd = $tradeIn->getOffer()->getAmountRibPayment();} else {$amountToAdd = $tradeIn->getOffer()->getAmount();}$productPrice =$productPrice +($productPrice *$amountToAdd) /100;}$productTradeIn->setPrice((int)round($productPrice));$totalPrice += $productTradeIn->getPrice();}}if (!$offersData["showLoyaltyOffer"] &&$tradeIn->getOffer() &&$tradeIn->getOffer()->getAmountType() === "euro") {$totalPrice =$totalPrice + $tradeIn->getOffer()->getAmount();}$status = $statusRepository->findOneBy(["slug" => Status::tradein_todo,]);$tradeIn->setCalculatedAmount($totalPrice);$tradeIn->setTStatus($status);$em->persist($tradeIn);$em->flush();$session = $this->requestStack->getSession();$this->notificationSender->sendCustomerEmail("Reprise #" .$tradeIn->getTradeCode() ." finalisée | BACK ipln","emails/toValidate.html.twig",["tradeIn" => $tradeIn,"firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->getCalculatedAmount(),"paymentType" => $tradeIn->getPaymentLabel()],$tradeIn);//On récupère le type de la notification selon le statut de la reprise en cours$adminNotificationType = $this->adminNotificationRepository->findOneBy(["type" => $tradeIn->getTStatus()->getSlug(),]);//S'il existe des notifications pour ce statut alors on envoi aux adminsif ($adminNotificationType) {$this->notificationSender->sendAdminEmail("Reprise #" .$tradeIn->getTradeCode() ." créée | BACK ipln","emails/admin_newTradeIn.html.twig",["firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->getCalculatedAmount(),"paymentType" => $tradeIn->getPaymentLabel(),"tradeInPath" => $request->getUriForPath($this->generateUrl("admin.tradein.editable", ["id" => $tradeIn->getId(),])),],$adminNotificationType,$tradeIn);}return $this->redirectToRoute("reprise.confirm");}}return $this->render("front/trade_in/payment_method.html.twig", ["tradeIn" => $tradeIn,"totalPriceCash" => $totalPriceCash,"totalPriceCoupon" => $totalPriceCoupon,"paymentForm" => $formPayment->createView(),]);}/*** @Route("/ajout-adresse", name="reprise.missing.address")*/public function missingAddress(TradeInRepository $tradeInRepository, Request $request, OdooApi $odooApi){if (!$this->session->get('trade_in_id')) {$this->addFlash('notice', "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute('tradeIn.start');}$tradeIn = $tradeInRepository->find($this->session->get('trade_in_id'));if (empty($tradeIn)) {$this->addFlash('notice', "Reprise introuvable, veuillez démarrer une nouvelle reprise.");return $this->redirectToRoute('tradeIn.start');}$customerAddressForm = $this->createForm(CustomerAddressType::class);$customerAddressForm->handleRequest($request);if ($customerAddressForm->isSubmitted() && $customerAddressForm->isValid()) {try {$addAddress = $this->prestashopApi->addAdressUser($tradeIn->getUser()->getPsId(),$customerAddressForm->get('country')->getData(),$customerAddressForm->get('postcode')->getData(),$customerAddressForm->get('city')->getData(),$customerAddressForm->get('streetAddress')->getData(),$customerAddressForm->get('phone')->getData(),$tradeIn->getUser()->getFirstname(),$tradeIn->getUser()->getLastname());} catch (\Exception $e) {$this->logger->error('Prestashop API error: ' . $e->getMessage());$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.');return $this->redirectToRoute('reprise.missing.address');}try {$user = $tradeIn->getUser();$odooCustomer = $odooApi->select(OdooEntityEnum::CUSTOMER, ['id'], ['email' => $user->getEmail()]);$countryId = $customerAddressForm->get('country')->getData();$odooCountryId = OdooCountryEnum::getOdooIdFromPrestashopId($countryId);$userData = ['name' => $user->getFirstname() . ' ' . $user->getLastname(),'street' => $customerAddressForm->get("streetAddress")->getData(),'street2' => '','zip' => $customerAddressForm->get("postcode")->getData(),'city' => $customerAddressForm->get("city")->getData(),'country_id' => $odooCountryId,'phone' => $customerAddressForm->get("phone")->getData(),];$odooApi->update(OdooEntityEnum::CUSTOMER, $odooCustomer[0]['id'], $userData);} catch (\Exception $e) {$this->addFlash('warning', 'Erreur lors de l\'ajout de votre adresse.');return $this->redirectToRoute('reprise.missing.address');}if ($addAddress && $addAddress['id']) {return $this->redirectToRoute("tradeIn.shipping_method");} else {$this->addFlash('notice', "Erreur lors de l'ajout de votre adresse.");return $this->redirectToRoute('reprise.missing.address');}}$tradeIn = $tradeInRepository->find($this->session->get('trade_in_id'));return $this->render('front/trade_in/missing_address.html.twig', ['tradeIn' => $tradeIn,'customerAddressForm' => $customerAddressForm->createView()]);}/*** @Route("/confirmation-reprise", name="reprise.confirm")*/public function confirm(TradeInRepository $tradeInRepository){if (!$this->session->get("trade_in_id")) {$this->addFlash("notice", "Vous n'avez pas encore créé de reprise");return $this->redirectToRoute("tradeIn.start");}$tradeIn = $tradeInRepository->find($this->session->get("trade_in_id"));$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue("La reprise a été créée");$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($tradeIn->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$this->em->persist($entityChangeLog);$this->em->flush();if ($this->session->get("trade_in_id")) {$this->session->remove("trade_in_id");}return $this->render("front/trade_in/confirmation.html.twig", ["tradeIn" => $tradeIn,]);}public function generateChronopost(TradeIn $tradeIn,EntityManagerInterface $em,StatusRepository $statusRepository,Request $request){$user = $tradeIn->getUser();if (!empty($user->getPsId())) {$addresses = $this->prestashopApi->findAddressCustomer($user->getPsId());}if (isset($addresses["addresses"][0]["address1"])) {$res = $this->chronopost->generateChronopost($user->getFirstname(),$user->getLastname(),$addresses["addresses"][0]["address1"],$addresses["addresses"][0]["city"],"FR", //TODO"FRANCE",$user->getEmail(),"",$addresses["addresses"][0]["postcode"],$tradeIn->getTradeCode());if (isset($res->return->reservationNumber)) {$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue('L\'étiquette Chronopost a été envoyée au client.');$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($this->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$em->persist($entityChangeLog);$em->flush();$this->notificationSender->sendCustomerEmail("Reprise #" .$tradeIn->getTradeCode() ." finalisée | BACK ipln","emails/acceptedByAdmin.html.twig",["firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->selectedAmount(),"paymentType" => $tradeIn->getPaymentLabel(),],$tradeIn);if (isset($res->return->resultParcelValue->skybillNumber)) {$tradeIn->setTrackingCode($res->return->resultParcelValue->skybillNumber);}$statusFinish = $statusRepository->findOneBy(["slug" => [Status::parcels_in_transit],]);$tradeIn->setTStatus($statusFinish);//On récupère le type de la notification selon le statut de la reprise en cours$adminNotificationType = $this->adminNotificationRepository->findOneBy(["type" => $tradeIn->getTStatus()->getSlug(),]);//S'il existe des notifications pour ce statut alors on envoi aux adminsif ($adminNotificationType) {$this->notificationSender->sendAdminEmail($tradeIn->getTStatus()->getLabel() ." - Reprise #" .$tradeIn->getTradeCode() ." a évolué | BACK ipln","emails/admin_tradeInUpdated.html.twig",["firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->getCalculatedAmount(),"paymentType" => $tradeIn->getPaymentLabel(),"tradeInPath" => $request->getUriForPath($this->generateUrl("admin.tradein.editable", ["id" => $tradeIn->getId(),])),"tradeInStatus" => $tradeIn->getTStatus()->getLabel(),],$adminNotificationType,$tradeIn);}$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue('Génération de l\'étiquette Chronopost.');$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($this->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$em->persist($entityChangeLog);$em->flush();} else {$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue('Une erreur est survenue lors de la génération de l\'étiquette Chronopost. Elle n\'a pas été envoyée au client.');$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($this->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$em->persist($entityChangeLog);$em->flush();}} else {$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue('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.');$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($this->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$em->persist($entityChangeLog);$em->flush();}}/*** @Route("/reponse-offre/{tradeCode}/{purposeHash}/{response}", name="tradeIn.response")*/public function responseOffer(TradeInRepository $tradeInRepository,string $tradeCode,string $purposeHash,string $response,Request $request,EntityManagerInterface $em,StatusRepository $statusRepository){$tradeIn = $tradeInRepository->findOneBy(["TradeCode" => $tradeCode]);if (($tradeIn->getTStatus()->getSlug() == Status::against_offer_sent ||$tradeIn->getTStatus()->getSlug() ==Status::against_offer_sent_final) &&$tradeIn->getPurposeHash() == $purposeHash) {if ($response == "acceptFinalOffer") {$products = $tradeIn->getProductTradeIn();foreach ($products as $product) {if ($product->isRefuse()) {$productsAccessories = $product->getProductTradeInAccessories();if ($productsAccessories) {foreach ($productsAccessories as $accessory) {$em->remove($accessory);}}$em->remove($product);}}$status = $statusRepository->findOneBy(["slug" => Status::accounting_entry,]);$tradeIn->setTStatus($status);$responseFormatted = "acceptée";} elseif ($response == "acceptEstimateOffer") {$products = $tradeIn->getProductTradeIn();foreach ($products as $product) {if ($product->isRefuse()) {$productsAccessories = $product->getProductTradeInAccessories();if ($productsAccessories) {foreach ($productsAccessories as $accessory) {$em->remove($accessory);}}$em->remove($product);}}try {$this->generateChronopost($tradeIn,$em,$statusRepository,$request);} catch (\Exception $e) {$this->logger->error('Prestashop API error: ' . $e->getMessage());$this->addFlash('notice','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.');return $this->redirectToRoute('tradeIn.response', ['tradeCode' => $tradeIn->getTradeCode(),'purposeHash' => $tradeIn->getPurposeHash(),'response' => $response,]);}$responseFormatted = "acceptée";} elseif ($response == "refuseFinalOffer") {//Refuse by user with product in shop$status = $statusRepository->findOneBy(["slug" => Status::tradein_refuse,]);$tradeIn->setTStatus($status);$responseFormatted = "refusée";} elseif ($response == "refuseEstimateOffer") {//Refuse by user without product in shop$status = $statusRepository->findOneBy(["slug" => Status::tradein_refuse,]);$tradeIn->setTStatus($status);$responseFormatted = "refusée";}$em->flush();$entityChangeLog = new EntityChangeLog();$entityChangeLog->setValue('L\'offre d\'un montant de ' .$tradeIn->selectedAmount() ."€ a été " .$responseFormatted ." par le client.");$entityChangeLog->setEntityId($tradeIn->getId());$entityChangeLog->setEntityName("trade_in");$entityChangeLog->setUser($tradeIn->getUser());$entityChangeLog->setAddedAt(new \DateTimeImmutable());$em->persist($entityChangeLog);$em->flush();//On récupère le type de la notification selon le statut de la reprise en cours$adminNotificationType = $this->adminNotificationRepository->findOneBy(["type" => $tradeIn->getTStatus()->getSlug(),]);//S'il existe des notifications pour ce statut alors on envoi aux adminsif ($adminNotificationType) {$this->notificationSender->sendAdminEmail("Reprise #" .$tradeIn->getTradeCode() ." a évolué | BACK ipln","emails/admin_tradeInUpdated.html.twig",["firstname" => $tradeIn->getUser()->getFirstname(),"tradeCode" => $tradeIn->getTradeCode(),"products" => $tradeIn->getProductTradeIn(),"total" => $tradeIn->getCalculatedAmount(),"paymentType" => $tradeIn->getPaymentLabel(),"tradeInPath" => $request->getUriForPath($this->generateUrl("admin.tradein.editable", ["id" => $tradeIn->getId(),])),"tradeInStatus" => $tradeIn->getTStatus()->getLabel(),],$adminNotificationType,$tradeIn);}return $this->render("front/trade_in/email_response.html.twig", ["tradeIn" => $tradeIn,"response" => $response,"total" => $tradeIn->getCalculatedAmount(),"responseFormatted" => $responseFormatted,]);} else {return $this->redirectToRoute("index");}}private function createPrestashopAccount(string $email,string $password,string $firstname,string $lastname,string $phone,int $countryId,string $postcode,string $address,string $city){$userPresta = $this->prestashopApi->findUserByEmail($email);if ($userPresta["accountExist"] == false) {$user = $this->prestashopApi->createUser($firstname,$lastname,$phone,$email,$password,$countryId,$postcode,$city,$address);} else {$user = $userPresta;}return $user["id"];}}