<?php
/*
* This file is part of the VPAutoUserBundle package.
*
* (c) CNSX <http://www.cnsx.net/>
*
*/
namespace App\Controller\Frontend;
use App\Api\RMS\SaleEventDataPersister;
use App\Controller\Controller;
use App\Entity\ExternalSale;
use App\Entity\News;
use App\Entity\Sale;
use App\Entity\SaleEvent;
use App\Entity\User;
use App\Entity\Vehicle;
use App\Form\Type\Frontend\CgvValidationType;
use App\Form\Type\Frontend\NewsletterType;
use App\Form\Type\Frontend\ProspectingProType;
use App\Form\Type\Frontend\VehicleFreeSearchType;
use App\Parameter\Provider;
use App\Parameter\ProviderInterface;
use App\Payment\Dto\Payment;
use App\Payment\PaymentFunnel;
use App\Repository\AuctionRepository;
use App\Repository\BannerRepository;
use App\Repository\NewsRepository;
use App\Repository\SaleHighlightRepository;
use App\Repository\SaleRepository;
use App\Repository\UserRepository;
use App\Repository\VehicleRepository;
use App\Salesforce\Api\ClientInterface;
use App\Salesforce\Utils\Constants;
use App\Twig\Extension\CountryExtension;
use App\Twig\Extension\OfferExtension;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class DefaultController extends Controller
{
public function __construct(
private readonly SaleRepository $saleRepository,
private readonly NewsRepository $newsRepository,
private readonly BannerRepository $bannerRepository,
private readonly UserRepository $userRepository,
private readonly AuctionRepository $auctionRepository,
private readonly VehicleRepository $vehicleRepository,
private readonly SaleHighlightRepository $saleHighlightRepository,
private readonly ClientInterface $client,
private readonly SessionInterface $session,
private readonly OfferExtension $offerExtension,
private readonly ProviderInterface $provider,
private readonly string $country)
{
}
public function indexAction(Request $request, Provider $provider)
{
$user = $this->getUser();
$nextSale = $this->saleRepository->findVeryNextSale();
$nextLiveFirst = $this->saleRepository->findCurrentOrNextLiveCompatible();
$nextLives = $this->saleRepository->findLiveCompatibleByDate($nextLiveFirst ? $nextLiveFirst->getStartDate() : new \DateTime());
$highlightEvent = null !== $nextLiveFirst ? $nextLiveFirst->getEvents()->first() : null;
$news = $this->newsRepository->findByType(News::TYPE_B2C);
$banners = $this->bannerRepository->findBanners($this->getParameter('vpauto_particular'), $request->getLocale());
$vehiclesSelection = $this->vehicleRepository->getVehiclesForAuctioneerSelection((int) $provider->getParameterValue('home.auctioneer.number_selection'));
$this->session->set('dimension', 'private');
if (null === $nextSale) {
return $this->render('Frontend/index_no_sales.html.twig', [
'news' => $news,
]);
}
$nbVehiclesSales = $this->saleRepository->countVehiclesForActiveByUserAndCustomer($user);
$nextSales = $this->getCurrentSales($this->country);
return $this->render('/Frontend/index.html.twig', [
'nextSale' => $nextSale,
'nextLiveFirst' => $nextLiveFirst,
'nextLives' => $nextLives,
'highlightEvent' => $highlightEvent,
'nbVehiclesSales' => $nbVehiclesSales,
'vehiclesSelection' => $vehiclesSelection,
'nextSales' => $nextSales,
'news' => $news,
'banners' => $banners,
'search_form' => $this->createForm(VehicleFreeSearchType::class, null, ['user' => $user])->createView(),
'type' => 'private',
]);
}
public function indexProAction(Request $request)
{
$user = $this->getUser();
$this->session->set('dimension', 'pro');
$banners = $this->bannerRepository->findBanners($this->getParameter('vpauto_professional'), $request->getLocale());
$currentSales = $this->getCurrentSalesForPro($this->country);
$datesForExternalSales = $this->getDatesForExternalSales($currentSales);
$nextLive = $this->saleRepository->findCurrentOrNextLiveCompatible();
$highlightEvent = null !== $nextLive ? $nextLive->getEvents()->first() : null;
return $this->render('/Frontend/index.html.twig', [
'news' => $this->newsRepository->findByType(News::TYPE_B2B),
'banners' => $banners,
'currentSales' => $currentSales,
'afterSales' => $this->saleRepository->findAllInAftersale(),
'search_form' => $this->createForm(VehicleFreeSearchType::class, null, ['user' => $user])->createView(),
'type' => 'pro',
'datesForExternalSales' => $datesForExternalSales,
'nextLive' => $nextLive,
'highlightEvent' => $highlightEvent,
]);
}
public function refreshSalesAction(Request $request)
{
if (!$request->isXmlHttpRequest()) {
throw new UnauthorizedHttpException('Unauthorized request');
}
$currentSales = $this->getCurrentSalesForPro($this->country);
$datesForExternalSales = $this->getDatesForExternalSales($currentSales);
return new JsonResponse($this->renderView('/Frontend/home/_sales_list.html.twig', [
'currentSales' => $currentSales,
'afterSales' => $this->saleRepository->findAllInAftersale(),
'datesForExternalSales' => $datesForExternalSales,
'nextLive' => $this->saleRepository->findCurrentOrNextLiveCompatible(),
]));
}
public function liveVisitorAction(Request $request, Provider $provider, EntityManagerInterface $em)
{
$isDisabled = (int) $provider->getParameterValue('live.disable_visitors');
if ($isDisabled) {
return $this->render('/Frontend/live_visitor_disabled.html.twig');
}
if (null !== $sale = $this->saleRepository->findCurrentLiveCompatible()) {
$sale->addOneLiveVisitor();
$em->flush();
}
$language = $request->getLocale();
$user = $this->userRepository->findOneByEmail($this->getParameter('vpauto.live.test_user').'@vpauto.'.$language);
$url = $this->createLiveUrlForUser($user, $this->provider, $em);
return $this->redirect($url);
}
public function livePaymentAction(PaymentFunnel $paymentFunnel, EntityManagerInterface $em)
{
$user = $this->getUser();
/** @var Sale $sale */
$sale = $this->saleRepository->findCurrentOrNextLiveCompatible();
if ($this->checkUserAccessToSale($user, $sale, $em)) {
$url = $this->createLiveUrlForUser($user, $this->provider, $em);
return $this->redirect($url);
}
$payment = new Payment(Payment::OPERATION_LIVE_ACCESS);
$payment->setSale($sale);
$payment->setFinishUrl($this->generateUrl('vpauto_frontend_live', [
'saleId' => $sale->getId(),
]));
$payment->setUser($this->getUser());
return $paymentFunnel->startAndRedirect($payment);
}
public function newsletterAction(Request $request)
{
$form = $this->createForm(NewsletterType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$newsletter = $form->getData();
if (
null !== $newsletter->getEmail()
&& null !== $newsletter->getLastName()
&& null !== $newsletter->getFirstName()
) {
if ('proAuto' === $form->get('type')->getData()) {
return $this->render('/Frontend/landing/newsletter-registered_pro.html.twig');
}
$sObject = [
'ExternalId__c' => $newsletter->getEmail(),
'LastName' => $newsletter->getLastName(),
'FirstName' => $newsletter->getFirstName(),
'PersonMailingPostalCode' => $newsletter->getZipCode(),
'PersonMailingCity' => $newsletter->getCity(),
'PersonMobilePhone' => $newsletter->getMobile(),
'Inscription_Newsletter__c' => true,
'Salle_de_vente_Newsletter__c' => $newsletter->getRoom() ? implode(';', $newsletter->getRoom()) : 'Toutes',
'SMS_Newsletter__c' => null !== $newsletter->getMobile() ? $newsletter->getSms() : false,
'RecordTypeId' => Constants::ACCOUNT_PERSON,
];
if ('proOther' === $form->get('type')->getData()) {
$sObject['Description'] = 'Professionnel d\'un autre secteur d\'activité';
}
$sfClient = $this->client->initiate();
if (false !== $exists = $sfClient->exists('Lead', ['Email' => $newsletter->getEmail()])) {
$convRes = $sfClient->convert($exists['id'], $newsletter->getId());
$sObject['Id'] = $convRes['accId'];
$sfClient->upsert('Id', (object) $sObject, 'Account');
} else {
$sfClient->upsert('ExternalId__c', (object) $sObject, 'Account');
}
return $this->render('/Frontend/landing/newsletter-registered.html.twig');
}
$this->session->getFlashbag()->add('error', 'Veuillez remplir les champs obligatoires.');
}
return $this->render('/Frontend/landing/newsletter-registration.html.twig', [
'form' => $form->createView(),
]);
}
public function assistanceContactAction(Request $request)
{
$user = $this->getCurrentUserOr403();
return $this->render('/Frontend/pro/assistance_contact.html.twig', [
'salesman' => $user->getSalesman(),
]);
}
public function cgvValidationAction(Request $request, EntityManagerInterface $em)
{
$user = $this->getCurrentUserOr403();
$form = $this->createForm(CgvValidationType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (null !== $user) {
$user->setCgvValidatedAt(new \DateTime());
$em->flush();
}
return $this->redirect($this->generateUrl('homepage_pro'));
}
return $this->render('/Frontend/cgv/validation.html.twig', [
'form' => $form->createView(),
]);
}
public function prospectingProAction(Request $request)
{
$form = $this->createForm(ProspectingProType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$sObject = (object) [
'LastName' => $form['lastName']->getData(),
'MobilePhone' => $form['mobile']->getData(),
'Company' => $form['company']->getData(),
'Email' => $form['email']->getData(),
'LeadSource' => 'Prospection campagne Salesfactory',
];
$sfClient = $this->client->initiate();
$data = $sfClient->upsert('Email', $sObject, 'Lead');
if (true !== $data[0]->success) {
$this->session->getFlashbag()->add('error', 'Une erreur est survenu, veuillez vérifier que les champs remplies sont correctement renseignés.');
} else {
$this->session->getFlashbag()->add('success', 'Votre inscription a bien été prise en compte.');
}
}
return $this->render('/Frontend/landing/prospecting-pro.html.twig', [
'form' => $form->createView(),
]);
}
private function formatTimerTargetDate($targetDate)
{
if ('DateTime' === $targetDate::class) {
return $targetDate->format('m/d/Y H:i:s');
}
return date('m/d/Y H:i:s', $targetDate);
}
private function getDatesForExternalSales(array $currentSales): array
{
$datesForExternalSales = [];
foreach ($currentSales as $currentSale) {
$sale = $currentSale['sale'];
if ($sale instanceof ExternalSale && SaleEventDataPersister::PROVIDER_NAME === $sale->getProvider()) {
$dates = $this->auctionRepository->findMinAndMaxClosedAtForSale($sale);
$dates = array_shift($dates);
if ($dates['max_closedAt'] != $dates['min_closedAt']) {
$datesForExternalSales[$sale->getId()] = ['max_closedAt' => new \DateTime($dates['max_closedAt']), 'min_closedAt' => new \DateTime($dates['min_closedAt'])];
}
}
}
return $datesForExternalSales;
}
private function getCurrentSales(string $country)
{
/** @var User|null $user */
$user = $this->getUser();
$nextSales = $currentSales = [];
$countries = [
'fr' => 'France',
'be' => 'Belgique',
'pt' => 'Portugal',
'es' => 'Espagne',
];
if (in_array($country, [CountryExtension::COUNTRY_BELGIUM, CountryExtension::COUNTRY_PORTUGAL, CountryExtension::COUNTRY_SPAIN])) {
foreach ($countries as $key => $countryName) {
$nextSales[$key] = $this->saleRepository->findActiveByUserAndPhysicalAndCountry($user, $countryName, 5);
$currentSales[$key] = $this->getCurrentSalesData($nextSales[$key]);
}
return $currentSales;
}
$nextSales = $this->saleRepository->findActiveByUserAndCustomer($user);
return $this->getCurrentSalesData($nextSales);
}
private function getCurrentSalesData(array $sales)
{
$currentSalesData = [];
foreach ($sales as $sale) {
$currentSaleData = [
'sale' => $sale,
'vehicles_for_carousel' => $this->vehicleRepository->getPicturesLotPhareByLiveSaleQuery($sale),
'count_active_vehicles' => $this->vehicleRepository->countAllValidBySale($sale),
'highlight' => $this->saleHighlightRepository->findOneRandomBySale($sale),
'count_vehicles_by_event' => $this->getCountVehiclesByEvent($sale),
];
$currentSalesData[] = $currentSaleData;
}
return $currentSalesData;
}
private function getCountVehiclesByEvent($sale): array
{
$countVehiclesByEvent = [];
foreach ($sale->getEvents() as $event) {
$countVehiclesByEvent[$event->getId()] = $this->vehicleRepository->countAllValidBySale($sale, $event);
}
return $countVehiclesByEvent;
}
private function getCurrentSalesForPro(string $country)
{
/** @var User|null $user */
$user = $this->getUser();
$allCurrent = $this->saleRepository->findAllCurrent($country);
$currentSales = [];
/** @var Sale $currentSale */
foreach ($allCurrent as $currentSale) {
$highlightVehicles = $this->vehicleRepository->findHighlightBySale($currentSale);
$userHighestOffers = [];
/** @var Vehicle $highlightVehicle */
foreach ($highlightVehicles as $highlightVehicle) {
$userHighestOffers[$highlightVehicle->getId()] = $this->offerExtension->getUserHighestOffer($user, $highlightVehicle);
}
$countAllValidVehicles = $this->vehicleRepository->countAllValidBySale($currentSale);
$currentSaleData = [
'sale' => $currentSale,
'count_active_vehicles' => $countAllValidVehicles,
'count_vehicles' => $countAllValidVehicles,
'highlight_vehicles' => [
'vehicles' => $highlightVehicles,
'highest_offers' => $userHighestOffers,
],
];
if (Sale::TYPE_PHYSICAL === $currentSale->getType()) {
$countVehiclesByEvent = [];
/** @var SaleEvent $event */
foreach ($currentSale->getEvents() as $event) {
$countVehiclesByEvent[$event->getId()] = $this->vehicleRepository->countAllValidBySale($currentSale, $event);
}
$currentSaleData['count_vehicles_by_event'] = $countVehiclesByEvent;
}
$currentSales[] = $currentSaleData;
}
return $currentSales;
}
}