<?php
namespace App\Controller\Main;
use App\Entity\Main\BankTransfer;
use App\Entity\Main\CardPayment;
use App\Entity\Main\Cart;
use App\Entity\Main\CartAction;
use App\Entity\Main\CartAddress;
use App\Entity\Main\CartCreditNote;
use App\Entity\Main\CodeHtml3DSLog;
use App\Entity\Main\DiscountCode;
use App\Entity\Main\ElectronicProductShipping;
use App\Entity\Main\Pack;
use App\Entity\Main\PackTemplate;
use App\Entity\Main\PaymentToken;
use App\Entity\Main\PaypalPayment;
use App\Entity\Main\Purchase;
use App\Entity\Main\SiteABTest;
use App\Entity\Main\SitePackTemplate;
use App\Entity\Main\Transaction;
use App\Entity\Main\UpsellCart;
use App\Entity\Main\User;
use App\Entity\Main\UserAddress;
use App\Entity\Main\UserCreditNote;
use App\Entity\Main\UserPayment;
use App\Entity\Main\UserSettings;
use App\Events\Main\Cart\CartCreditNoteUsedEvent;
use App\Events\Main\Pack\AddedNonEligiblePackEvent;
use App\Events\Main\Payment\PaymentErrorEvent;
use App\Events\Main\Payment\PaymentSwap3DSEvent;
use App\EventSubscribers\Main\CartSubscriber;
use App\EventSubscribers\Main\PackSubscriber;
use App\EventSubscribers\Main\PaymentSubscriber;
use App\Exceptions\Main\Cart\CartAlreadyPaidException;
use App\Services\CartManager;
use App\Services\EmailManager;
use App\Services\PackManager;
use App\Services\TrackingManager;
use App\Form\Main\BankTransferType;
use App\Form\Main\PaypalPaymentType;
use App\Form\Main\UserAddressType;
use App\Form\Main\UserPaymentType;
use App\Services\ABTestManager;
use App\Services\CartSwitchManager;
use App\Services\DeliveryProvidersManager;
use App\Services\FacebookApiEventsManager;
use App\Services\GeoIPManager;
use App\Services\SiteManager;
use App\Services\TranslationManager;
use App\Services\UserAddressManager;
use App\Tools\ConditionalPacks\FailedPackCondition;
use App\Tools\Forms\FormErrorsResolver;
use App\Tools\ShortId;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use JMS\Serializer\SerializerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Asset\Packages;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Throwable;
/**
* @Route(
* condition="not (context.getHost() matches '%coaching_domain.host.regexp%')"
* )
*/
class CartController extends AbstractController
{
use BrulafineControllerTrait;
public const UPSELL_PURCHASE_SUCCESS = "up_pur_ok";
/**
* @Route("/cart/", name="brulafine_cart_start", methods={"GET"})
* @param Request $request
* @return RedirectResponse
*/
public function defaultAction(Request $request)
{
return $this->redirectToRoute('brulafine_show_packs');
}
/**
* @param Request $request
* @param ABTestManager $ABTestManager
* @param FacebookApiEventsManager $facebookApiEventsManager
* @return Response
*/
#[Route(path: [
'fr' => '/nosPacks/',
'en' => '/ourPacks/',
'es' => '/nuestrosPacks/',
'it' => '/inostripacchi/',
], name: 'brulafine_show_packs')]
public function displayPackAction(
Request $request,
ABTestManager $ABTestManager,
FacebookApiEventsManager $facebookApiEventsManager
) {
$setup = $this->getSetup();
$defaultProposedPacks = $this->getPackFactory()->getDefaultProposedPacks($setup->getSite());
$personalisedPacks = $ABTestManager->getPacksForTracking($setup->getTracking(), $defaultProposedPacks);
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::VIEW_CONTENT, null, $setup->getTracking());
return $this->staticAction($this->getTemplatesDir() . '/Default/pack.html.twig', [
'defaultProposedPacks' => $personalisedPacks,
'tracking' => $setup->getTracking()
]);
}
/**
* @Route("/cart/custom", name="brulafine_updateCustomPack", methods={"POST"})
* @param Request $request
* @return Response
*/
public function updateCustomPack(Request $request)
{
$setup = $this->getSetup();
$packTemplateId = $request->request->get('packTemplateId', 0);
$items = $request->request->get('item', []);
$newTemplatePack = $this->getCartFactory()->getCustomTemplatePack($setup, $packTemplateId, $items);
if (null === $newTemplatePack) {
return $this->appendCookie(
new JsonResponse(['has_error' => true], JsonResponse::HTTP_NOT_FOUND),
$setup->getCookie()
);
}
return $this->appendCookie(
new JsonResponse(['view' => [
'customPack' => $this->renderView(
$this->getTemplatesDir() . '/Partials/customPackPartial.html.twig',
['sitePackTemplate' => $newTemplatePack]
),
]]),
$setup->getCookie()
);
}
/**
* @Route("/cart/template/{packTemplateId}", name="brulafine_cart",requirements={"packTemplateId" = "\w+"})
* @param Request $request
* @param mixed $packTemplateId
* @param GeoIPManager $geoIPManager
* @param FacebookApiEventsManager $facebookApiEventsManager
* @param EntityManagerInterface $entityManager
* @param CartManager $cartManager
* @param AuthorizationCheckerInterface $authorizationChecker
* @param TranslatorInterface $translator
* @return RedirectResponse|Response
*/
public function createCartAction(
Request $request,
mixed $packTemplateId,
GeoIPManager $geoIPManager,
FacebookApiEventsManager $facebookApiEventsManager,
EntityManagerInterface $entityManager,
CartManager $cartManager,
AuthorizationCheckerInterface $authorizationChecker,
TranslatorInterface $translator,
) {
$setup = $this->getSetup();
$cart = $setup->getCart();
$user = $setup->getUser();
$session = $request->getSession();
$is_custom_pack = false;
$switch_pack = $request->get('switch-pack');
/** @var PackTemplate $packTemplate */
$packTemplate = $entityManager
->getRepository(PackTemplate::class)
->findOneBy(['packTemplateId' => $packTemplateId]);
$sitePackTemplate = $entityManager
->getRepository(SitePackTemplate::class)
->findOneBy(['packTemplate' => $packTemplate, 'site' => $setup->getSite(), 'active' => 1]);
if (!$sitePackTemplate) {
$this->addFlash('error', 'flashMessages.site.pleaseSelectPack');
return $this->redirectToRoute('brulafine_show_packs');
}
if (!$cart instanceof Cart || null !== $switch_pack) {
$items = $request->get('item', []);
$items = array_map('intval', $items);
if (!empty($items)) {
$valid = array_filter($items, function ($value) {
return 0 == $value;
});
if ($valid === $items) {
$items = [];
}
}
$currentCart = $setup->getCart();
$currentCartAddress = null;
// check if there was an address, if yes reuse it.
if ($currentCart instanceof Cart && !$currentCart->isPaid()) {
if ($currentCart->getCartAddress() instanceof CartAddress) {
$currentCartAddress = $currentCart->getCartAddress();
$currentCartAddress->setCart(null);
$currentCart->setCartAddress(null);
}
$cartManager->cleanUpCurrentCart($currentCart);
}
$is_custom_pack = $packTemplate->getPackTemplateType() == PackTemplate::CUSTOM_PACK;
if ($is_custom_pack) {
$items = $request->get('item', []);
$items = array_map('intval', $items);
if ((!empty($items) && array_sum($items) <= 0) || empty($items)) {
$this->addFlash('error', 'flashMessages.site.selectAtLeastOneProduct');
return $this->redirectToRoute('brulafine_show_packs');
}
foreach ($items as $productQuantity) {
if ($productQuantity > 6) {
$this->addFlash('error', 'flashMessages.site.productMaxQuantity');
return $this->redirectToRoute('brulafine_show_packs');
}
}
}
// todo que faire avec le cart actuel ? (pour moi le trasher)
$cart = $cartManager->makeCartFromPackTemplate(
$packTemplate,
$setup->getSite(),
$setup->getTracking(),
$setup->getAffiliate(),
$items,
$user,
$currentCartAddress
);
}
if ($user instanceof User) {
$cart->setUser($user);
$cart->setTracking($user->getTracking());
}
$discountMessage = '';
$discountCodeName = $cartManager->getActualDiscountCode($cart);
$res = $cartManager->addDiscountCode($cart, $discountCodeName);
if ('success' === $res['status']) {
$discountMessage = $translator->trans( 'flashMessages.site.discountCodeIsApplied', array('%discountCodeName%' => $cart->getDiscountCode()->getDiscountCodeName()), TranslationManager::TRANSLATION_DOMAIN_FLASH);
}
$tld = $geoIPManager->getCountryCode($request->getClientIp());
$cart->setCartShippingCountry($tld);
$entityManager->flush();
$cartTotal = $cartManager->computeCartTotal($cart);
// definir l'arbre de vie du cart
// new -> cart cree <- autoExpirer un cart et ses packs apres x temps dans le NEW state (ajouter cartStampCreation && cartStampLastUpdate)
// pendingIdentification -> on attend d'identifier le client ou anonyme
// pendingPayement -> on attend le payement
// pendingShipping
// shipped.
$session->set('currentCartId', $cart->getCartId());
if (true === $authorizationChecker->isGranted('ROLE_USER')) {
if ('' !== $discountMessage) {
$this->addFlash('info', $discountMessage);
}
return $this->redirectToRoute('brulafine_shipping');
}
$session->set('seeTheCart', $cart->getCartId());
$regular_packs = $entityManager
->getRepository(SitePackTemplate::class)
->getCachedAutoPacksForSite($setup->getSite());
$request->attributes->set(
'submit_button',
$translator->trans(
'site.common.buttons.continue',
array(),
TranslationManager::TRANSLATION_DOMAIN_SITE
)
);
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::ADD_TO_CART, $cart, $setup->getTracking());
$response = $this->render($this->getTemplatesDir() . '/Default/cart.html.twig', [
'cart' => $cart,
'cartTotal' => $cartTotal,
'csrf_token' => $this->getLoginCsrfToken(),
'tracking' => $cart->getTracking(),
'site' => $setup->getSite(),
'regular_packs' => $regular_packs,
'is_custom_pack' => $is_custom_pack,
'discountMessage' => $discountMessage,
]);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart/discount", name="brulafine_discount")
* @param Request $request
* @param CartManager $cartFactory
* @return JsonResponse|RedirectResponse
* @throws Exception
*/
public function addDiscountCodeAction(Request $request, CartManager $cartFactory, EntityManagerInterface $entityManager, TranslatorInterface $translator)
{
$setup = $this->getSetup();
$user = $setup->getUser();
if (!$user instanceof User) {
$user = $entityManager->getRepository(User::class)->findOneBy(['id' => $request->getSession()->get(User::GUEST_USER_SESSION_KEY)]);
}
if (!$user instanceof User) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse(
[
'status' => 'error',
'message' => $translator->trans( 'flashMessages.site.addDiscountCodeError', [], TranslationManager::TRANSLATION_DOMAIN_FLASH),
'discountCodeName' => '',
'view' => [
'cartTableSummary' => ''
]
],
400
);
}
return $this->redirect($this->generateUrl("brulafine_home"));
}
// This request can't be accessed if there is no cart.
if (!$setup->getCart() instanceof Cart) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse(
[
'status' => 'error',
'message' => $translator->trans( 'flashMessages.site.addDiscountCodeError', [], TranslationManager::TRANSLATION_DOMAIN_FLASH),
'discountCodeName' => '',
'view' => [
'cartTableSummary' => ''
]
],
400
);
} else {
$this->addFlash('error', 'flashMessages.site.addDiscountCodeError');
return $this->redirectToRoute('brulafine_show_packs', []);
}
}
$result = $cartFactory->discountCodeApplying($user, $setup->getCart());
$gtmPromoCodeErrorEventContent = '<script>
dataLayer.push({"event":"codepromo","errorString":"'.$translator->trans( $result['message'], array(), TranslationManager::TRANSLATION_DOMAIN_FLASH).'","error_coupon":"'.$result['discountCodeName'].'"});
</script>';
if ($request->isXmlHttpRequest()) {
$response = [
'status' => $result['status'],
'message' => $translator->trans( $result['message'], array('%discountCodeName%' => $result['discountCodeName']), TranslationManager::TRANSLATION_DOMAIN_FLASH),
'discountCodeName' => $result['discountCodeName'],
'view' => [
'cartTableSummary' => $this->renderView(
$this->getTemplatesDir() . '/Partials/cartPartialSummary.html.twig',
['cart' => $result['cart'], 'cartTotal' => $result['cartTotal'], 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
'GTMPromoCodeEventContent' => $gtmPromoCodeErrorEventContent
]
];
if ($request->request->get('isSimpleOrder')) {
$response['view']['payPalTabContent'] = $this->renderView(
$this->getTemplatesDir() . '/Partials/payPal-tab-content.html.twig',
['cart' => $result['cart'], 'cartTotal' => $result['cartTotal'], 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
);
}
return new JsonResponse(
$response,
200
);
} else {
$this->addFlash($result['status'], $translator->trans( $result['message'], array('%discountCodeName%' => $result['discountCodeName']), TranslationManager::TRANSLATION_DOMAIN_FLASH));
return $this->redirectToRoute($result['redirectRoute'], $result['routeParams']);
}
}
/**
* @Route("/cart/credit-note", name="brulafine_credit_note")
* @param Request $request
* @param CartManager $cartFactory
* @return JsonResponse|RedirectResponse
* @throws Exception
*/
public function addCreditNoteAction(Request $request, CartManager $cartFactory, EntityManagerInterface $entityManager, TranslatorInterface $translator)
{
$setup = $this->getSetup();
$user = $setup->getUser();
if (!$user instanceof User) {
$user = $entityManager->getRepository(User::class)->findOneBy(['id' => $request->getSession()->get(User::GUEST_USER_SESSION_KEY)]);
}
if (!$user instanceof User) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse(
[
'status' => 'error',
'view' => [
'cartTableSummary' => ''
]
],
400
);
}
return $this->redirect($this->generateUrl("brulafine_home"));
}
$cart = $setup->getCart();
// This request can't be accessed if there is no cart.
if (!$cart instanceof Cart) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse(
[
'status' => 'error',
'view' => [
'cartTableSummary' => ''
]
],
400
);
} else {
return $this->redirectToRoute('brulafine_show_packs', []);
}
}
$requestData = (array) json_decode($request->request->get('data'));
if ($requestData['useCreditNoteSelected']) {
$cartCreditNote = $cart->hasCreditNoteAssigned(true);
/** @var UserCreditNote $userCreditNote */
$userCreditNote = $user->getCreditNotes()[0];
if (!$cartCreditNote instanceof CartCreditNote) {
//assign credit note to cart
$cartCreditNote = new CartCreditNote();
$cartCreditNote->setCart($cart);
}
$cartCreditNote->setValue($userCreditNote->getTotalValue());
$entityManager->persist($cartCreditNote);
$entityManager->flush();
} else {
$cartCreditNote = $cart->hasCreditNoteAssigned(true, true);
//remove value from credit note of the cart
if ($cartCreditNote instanceof CartCreditNote) {
$cartCreditNote->setValue(null);
$entityManager->persist($cartCreditNote);
$entityManager->flush();
}
}
$entityManager->refresh($cart);
$result = $cartFactory->creditNoteApplying($cart);
if ($request->isXmlHttpRequest()) {
$response = [
'status' => $result['status'],
'message' => $translator->trans( 'site.common.amountIsUpdated', array(), TranslationManager::TRANSLATION_DOMAIN_SITE),
'view' => [
'cartTableSummary' => $this->renderView(
$this->getTemplatesDir() . '/Partials/cartSummary.html.twig',
[
'cart' => $result['cart'],
'cartTotal' => $result['cartTotal'],
'updateCommand' => true,
'virement' => false,
'bankDescriptor' => false
]
)
],
'cart' => $result['cart'],
'cartTotal' => $result['cartTotal'],
];
$response['view']['payPalTabContent'] = $this->renderView(
$this->getTemplatesDir() . '/Partials/payPal-tab-content.html.twig',
[
'cart' => $result['cart'],
'cartTotal' => $result['cartTotal'],
'isSimpleOrder' => false
]
);
return new JsonResponse(
$response,
200
);
}
}
/**
* @Route("/cart/shipping", name="brulafine_shipping")
* @param Request $request
* @param UserAddressManager $userAddressManager
* @param LoggerInterface $logger
* @param CartSwitchManager $cartSwitchManager
* @return RedirectResponse|Response
* @throws Exception
*/
public function shippingAction(
Request $request,
UserAddressManager $userAddressManager,
LoggerInterface $logger,
CartSwitchManager $cartSwitchManager,
GeoIPManager $geoIPManager,
EventDispatcherInterface $eventDispatcher,
SiteManager $siteManager,
FacebookApiEventsManager $facebookApiEventsManager,
CartManager $cartManager,
EntityManagerInterface $entityManager,
TranslatorInterface $translator
) {
$setup = $this->getSetup();
$cart = $setup->getCart();
$user = $setup->getUser();
if ($user instanceof User && $user->getAddress() instanceof UserAddress) {
$currentUserAddress = clone($user->getAddress());
} else {
$currentUserAddress = new UserAddress();
}
if (!$cart instanceof Cart) {
return $this->redirectToRoute('brulafine_show_packs');
}
if ($request->isXmlHttpRequest() && $request->request->get('loadProvinces')) {
$userAddress = new UserAddress();
$form = $this->createForm(UserAddressType::class, $userAddress);
$form->handleRequest($request);
$response = $this->render($this->getTemplatesDir() . '/Partials/addressForm.html.twig', [
'form' => $form->createView(),
'cart' => $cart,
]);
return $this->appendCookie($response, $setup->getCookie());
}
if (!$user instanceof User) {
return $this->redirectToRoute('brulafine_cart', ['packTemplateId' => $cart->getPacks()[0]->getPackTemplate()->getPackTemplateId()]);
}
$conditionResult = $cartManager->isCartPurchasePossible($cart);
if ($conditionResult instanceof FailedPackCondition) {
$event = new AddedNonEligiblePackEvent($conditionResult->getPackTemplate(), $conditionResult->getTemplateCondition());
$eventDispatcher->dispatch($event, PackSubscriber::PACK_NON_ELIGIBLE_EVENT);
$cartManager->cleanUpCurrentCart($cart);
return $this->redirectToRoute('brulafine_show_packs');
}
$cartBill = $cartManager->getBill($cart);
$userAddress = new UserAddress();
$userAddress->setCountry($geoIPManager->getCountryCode($request->getClientIp()));
if ($user->getAddress() instanceof UserAddress) {
$userAddress = $user->getAddress();
}
$cart->setUser($user);
$entityManager->persist($cart);
$tld = $userAddress->getCountry();
$form = $this->createForm(UserAddressType::class, $userAddress);
$form->handleRequest($request);
$preventSells = $siteManager->getYamlConfigParameter("frontEnd")['disableSells'] ?? false;
if ($form->isSubmitted() && $form->isValid() && !$preventSells) {
// $form->getData() holds the submitted values
// but, the original `$task` variable has also been updated
$route = 'brulafine_payment';
/** @var UserAddress $submittedUserAddress */
$submittedUserAddress = $form->getData();
$entityManager->persist($submittedUserAddress);
// check if the address was actually changed.
if ($userAddressManager->checkUserAddressHasChanged($currentUserAddress, $submittedUserAddress)) {
$submittedUserAddress = $userAddressManager->updateUserAddressCountry($submittedUserAddress);
$submittedUserAddress->setIsValidate(false);
}
if ($cart->getCartAddress() instanceof CartAddress && !$userAddressManager->checkAddressIsSameForCart($submittedUserAddress, $cart->getCartAddress())) {
$userAddressManager->updateCartAddress($cart->getCartAddress(), $submittedUserAddress);
} else {
$cartAddress = $userAddressManager->getAddressForCart($submittedUserAddress);
$cart->setCartAddress($cartAddress);
$cartAddress->setCart($cart);
}
$user->setAddress($submittedUserAddress);
$cart->setUser($user);
try {
$entityManager->flush();
} catch (\Exception $e) {
$logger->critical("Can't manage to save the address for a cart & user. {$user->getId()}, cart : {$cart->getCartId()}" . $e->getMessage());
}
try {
$cartManager->transitState($cart, 'clientIdentification');
$cartManager->transitState($cart, 'clientAddressFilling');
$cartManager->transitState($cart, 'payment');
} catch (\Exception $e) {
$logger->critical("Can't change state of the cart to payment. {$user->getId()}, cart : {$cart->getCartId()}, state {$cart->getCartState()}");
}
$cart->setCartShippingCountry($submittedUserAddress->getCountry());
$entityManager->flush();
if ($request->getLocale() == 'fr' && $cart->allowPush() && $cartSwitchManager->shouldDisplaySwitchForCart($setup->getCart(), true)) {
$route = 'brulafine_push_check_pack_switch';
}
if ($tld !== $submittedUserAddress->getCountry() && $cartManager->getBill($cart) != $cartBill) {
$route = 'brulafine_shipping';
$this->addFlash('info', 'flashMessages.site.shippingPriceUpdated');
}
// If he got another order 30 mins before we are adding a confirmation page
if ($cartManager->hasOrderInDelay($user)) {
$route = 'brulafine_confirm';
}
return $this->redirectToRoute($route);
} elseif ($form->isSubmitted() && $form->isValid() && $preventSells) {
$errorMessage = $siteManager->getYamlConfigParameter("frontEnd")['disabledButtonTitle'];
$this->addFlash("errors", $errorMessage);
}
$discountMessage = '';
$discountCodeName = $cartManager->getActualDiscountCode($cart);
$res = $cartManager->addDiscountCode($cart, $discountCodeName);
if ('success' === $res['status']) {
$discountMessage = $translator->trans( 'flashMessages.site.discountCodeIsApplied', array('%discountCodeName%' => $cart->getDiscountCode()->getDiscountCodeName()), TranslationManager::TRANSLATION_DOMAIN_FLASH);
}
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::COMPLETE_REGISTRATION, $cart, $setup->getTracking());
$response = $this->render($this->getTemplatesDir() . '/Default/cart.html.twig', [
'form' => $form->createView(),
'cart' => $cart,
'cartTotal' => $cartManager->computeCartTotal($cart),
'defaultProposedPacks' => $this->getPackFactory()->getDefaultProposedPacks($setup->getSite()),
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
'is_custom_pack' => $cart->getPacks()[0]->getPackType() === PackTemplate::CUSTOM_PACK,
'regular_packs' => $entityManager->getRepository(SitePackTemplate::class)->getCachedAutoPacksForSite($setup->getSite()),
'discountMessage' => $discountMessage,
]);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart/commande", name="brulafine_commande")
* @param Request $request
* @param UserAddressManager $userAddressManager
* @param LoggerInterface $logger
* @param GeoIPManager $geoIPManager
* @param CartManager $cartFactory
* @param EntityManagerInterface $entityManager
* @param SerializerInterface $serializer
* @param DeliveryProvidersManager $deliveryProvidersManager
* @param FacebookApiEventsManager $facebookApiEventsManager
* @param ABTestManager $ABTestManager
* @param SiteManager $siteManager
* @return RedirectResponse|Response
*/
public function simpleOrderAction(
Request $request,
UserAddressManager $userAddressManager,
LoggerInterface $logger,
GeoIPManager $geoIPManager,
CartManager $cartFactory,
EntityManagerInterface $entityManager,
SerializerInterface $serializer,
DeliveryProvidersManager $deliveryProvidersManager,
FacebookApiEventsManager $facebookApiEventsManager,
ABTestManager $ABTestManager,
SiteManager $siteManager,
AuthorizationCheckerInterface $authorizationChecker
) {
$setup = $this->getSetup();
$environment = $this->getParameter('kernel.environment');
// This code is specific to ease testing of 3ds payments
if ($request->query->get('3ds') || ($siteManager->getYamlConfigParameter('site_force_3ds') && !in_array($environment, ['test', 'dev']))) {
$request->getSession()->set('force_3ds', true);
}
if (!$ABTestManager->hasTest($setup->getTracking(), SiteABTest::BRU_QUICK_CHECKOUT_ON) && $request->getLocale() != 'it') {
return $this->redirectToRoute('brulafine_show_packs');
}
$setup = $this->getSetup();
$cart = $setup->getCart();
if ($authorizationChecker->isGranted('ROLE_USER')) {
$route = 'brulafine_show_packs';
if ($cart instanceof Cart) {
$route = 'brulafine_shipping';
}
return $this->redirectToRoute($route);
}
$session = $request->getSession();
if (!$cart instanceof Cart) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "KO",
'message' => 'No cart!',
'redirect' => $this->generateUrl('brulafine_show_packs')
], 401);
}
return $this->redirectToRoute('brulafine_show_packs');
}
if ($request->isXmlHttpRequest() && !$request->request->get('user_id')) {
return new JsonResponse([
'result' => "KO",
'message' => 'We need user here please!',
], 401);
}
$userAddress = new UserAddress();
$userAddress->setCountry($geoIPManager->getCountryCode($request->getClientIp()));
/** @var User $user */
$user = $entityManager->getRepository(User::class)->findOneById($request->request->get('user_id'));
if ($user instanceof User && $user->getAddress() instanceof UserAddress) {
$userAddress = $user->getAddress();
}
$addressForm = $this->createForm(UserAddressType::class, $userAddress);
$addressForm->handleRequest($request);
if ($request->isXmlHttpRequest()) {
if ($addressForm->isSubmitted() && $addressForm->isValid()) {
/** @var UserAddress $submittedUserAddress */
$submittedUserAddress = $addressForm->getData();
$entityManager->persist($submittedUserAddress);
if ($user instanceof User && $user->getAddress() instanceof UserAddress) {
$currentUserAddress = clone($user->getAddress());
} else {
$currentUserAddress = new UserAddress();
}
// check if the address was actually changed.
if ($userAddressManager->checkUserAddressHasChanged($currentUserAddress, $submittedUserAddress)) {
$submittedUserAddress = $userAddressManager->updateUserAddressCountry($submittedUserAddress);
$submittedUserAddress->setIsValidate(false);
}
if ($cart->getCartAddress() instanceof CartAddress && !$userAddressManager->checkAddressIsSameForCart($submittedUserAddress, $cart->getCartAddress())) {
$userAddressManager->updateCartAddress($cart->getCartAddress(), $submittedUserAddress);
} else {
$cartAddress = $userAddressManager->getAddressForCart($submittedUserAddress);
$cart->setCartAddress($cartAddress);
$cartAddress->setCart($cart);
}
$user->setAddress($submittedUserAddress);
$cart->setUser($user);
try {
$entityManager->flush();
} catch (\Exception $e) {
$logger->critical("Can't manage to save the address for a cart & user. {$user->getId()}, cart : {$cart->getCartId()}");
}
try {
$cartFactory->transitState($cart, 'clientIdentification');
$cartFactory->transitState($cart, 'clientAddressFilling');
$cartFactory->transitState($cart, 'payment');
} catch (\Exception $e) {
$logger->critical("Can't change state of the cart to payment. {$user->getId()}, cart : {$cart->getCartId()}, state {$cart->getCartState()}");
}
$cart->setCartShippingCountry($submittedUserAddress->getCountry());
$entityManager->flush();
$detailedPickupPointAddress = null;
if (null != $cart->getPickUpPoint()) {
$detailedPickupPointAddress = $deliveryProvidersManager->getPickUpPointAddressFromCart($cart);
}
$discountCodeName = $cartFactory->getActualDiscountCode($cart);
try {
$res = $cartFactory->addDiscountCode($cart, $discountCodeName);
} catch (\Exception $e) {
return new JsonResponse([
'result' => "KO",
'message' => 'Problem with applying the code!',
], 401);
}
$cartTotal = $cartFactory->computeCartTotal($cart);
return new JsonResponse([
'result' => "OK",
'message' => 'valid',
'userAddress' => $serializer->serialize($userAddress, "json"),
'userEmail' => $user->getEmail(),
'detailedPickupPointAddress' => $detailedPickupPointAddress,
'view' => [
'payPalTabContent' => $this->renderView(
$this->getTemplatesDir() . '/Partials/payPal-tab-content.html.twig',
['cart' => $cart, 'cartTotal' => $cartTotal, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
)
]
], 200);
} else {
$formErrorsResolver = new FormErrorsResolver($addressForm);
$errors = $formErrorsResolver->resolve();
return new JsonResponse([
'result' => "KO",
'message' => 'There is errors in the form!',
'submit' => $addressForm->isSubmitted(),
'errors' => $errors
], 401);
}
}
$cardPayment = new CardPayment($request->getClientIp(), $request->headers->get('User-Agent'));
$paymentForm = $this->createForm(UserPaymentType::class, $cardPayment);
$paymentForm->handleRequest($request);
$formType = 'creditcard';
$environment = $this->container->getParameter('kernel.environment');
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::LEAD, $cart, $setup->getTracking());
$response = $this->render($this->getTemplatesDir() . '/Default/cart-simple-oder.html.twig', [
'addressForm' => $addressForm->createView(),
'paymentForm' => $paymentForm->createView(),
'forceTransfer' => $session->get('forceTransfert', 0),
'showBankTransfer' => $session->get('showBankTransfer', 0),
'cart' => $cart,
'tracking' => $setup->getTracking(),
'cartTotal' => $cartFactory->computeCartTotal($cart),
'formType' => $request->query->get('formType', $formType),
'disableCbForm' => false,
'environment' => $environment,
]);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart", name="brulafine_updateCart")
* @param Request $request
* @return Response
*/
public function updateCartAction(Request $request, LoggerInterface $logger, DeliveryProvidersManager $deliveryProvidersManager)
{
$setup = $this->getSetup();
try {
$this->getCartFactory()->updateCartProductQuantity(
$setup,
$request->request->get('packIndex'),
$request->request->get('packProductIndex'),
$request->request->get('productQuantity')
);
$cart = $setup->getCart();
$cartTotal = $this->getCartFactory()->computeCartTotal($cart);
$shippingPrices = $deliveryProvidersManager->getShippingOptions($cart);
$template = 'cartTablePack';
if ($cart->getPacks()[0]->getPackType() === Pack::CUSTOM_PACK) {
$template = 'cartTableCustomPack';
}
//check if User clicks Off or On the Coaching option and create an event for each
$tracking = $setup->getTracking();
$response = new JsonResponse(['view' => [
'cartTableBody' => $this->renderView(
$this->getTemplatesDir() . '/Partials/' . $template . '.html.twig',
['cartTotal' => $cartTotal, 'cart' => $cart, 'tracking' => $tracking, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
'cartTableSummary' => $this->renderView(
$this->getTemplatesDir() . '/Partials/cartPartialSummary.html.twig',
['cartTotal' => $cartTotal, 'cart' => $cart, 'tracking' => $tracking, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
'cartPopup' => $this->renderView(
$this->getTemplatesDir() . '/Partials/cartPopup.html.twig',
['cartTotal' => $cartTotal, 'cart' => $cart, 'tracking' => $tracking, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
'payPalTabContent' => $this->renderView(
$this->getTemplatesDir() . '/Partials/payPal-tab-content.html.twig',
['cart' => $cart, 'cartTotal' => $cartTotal, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
],
'shippingPrices' => $shippingPrices
]);
return $this->appendCookie($response, $setup->getCookie());
} catch (Exception $e) {
$response = new JsonResponse([
'has_error' => true,
'message' => $e->getMessage(),
'message1' => $e->getLine() . $e->getFile(),
], JsonResponse::HTTP_NOT_FOUND);
return $this->appendCookie($response, $setup->getCookie());
}
}
/**
* @Route("/cart/update/shipping-prices", name="brulafine_update_shipping_prices")
* @param Request $request
* @param DeliveryProvidersManager $deliveryProvidersManager
* @param EntityManagerInterface $entityManager
* @return Response
*/
public function updateCartShippingAction(Request $request, DeliveryProvidersManager $deliveryProvidersManager, EntityManagerInterface $entityManager)
{
$setup = $this->getSetup();
$cart = $setup->getCart();
if (!$cart instanceof Cart) {
$response = new JsonResponse(
[
'response' => 'KO',
'message' => 'You must have a cart here!'
]
);
return $this->appendCookie($response, $setup->getCookie());
}
$country = $request->request->get('addressCountry');
$shippingRule = $request->request->get('shippingRule');
if (null != $country) {
$cart->setCartShippingCountry($country);
$user = $cart->getUser();
if ($user instanceof User && $user->getAddress() instanceof UserAddress) {
$user->getAddress()->setCountry($country);
}
}
if (null != $shippingRule) {
$cart->setShippingRule($shippingRule);
}
if ($deliveryProvidersManager->ruleIsToAddress($shippingRule)) {
$cart->setPickUpPoint(null);
}
$shippingPrices = $deliveryProvidersManager->getShippingOptions($cart, $country);
if (count($shippingPrices) == 1) {
$cart->setShippingRule(null);
}
$entityManager->flush();
$cartTotal = $this->getCartFactory()->computeCartTotal($cart);
$tracking = $setup->getTracking();
$response = new JsonResponse(
[
'response' => 'OK',
'shippingPrices' => $shippingPrices,
'view' => [
'cartTableSummary' => $this->renderView(
$this->getTemplatesDir() . '/Partials/cartPartialSummary.html.twig',
['cartTotal' => $cartTotal, 'cart' => $cart, 'tracking' => $tracking, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
'payPalTabContent' => $this->renderView(
$this->getTemplatesDir() . '/Partials/payPal-tab-content.html.twig',
['cart' => $cart, 'cartTotal' => $cartTotal, 'isSimpleOrder' => $request->request->get('isSimpleOrder')]
),
]
]
);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart/switch", name="brulafine_push_check_pack_switch")
* @param Request $request
* @param CartSwitchManager $cartSwitchManager
* @return RedirectResponse|Response
*/
public function cartSwitchAction(Request $request, CartSwitchManager $cartSwitchManager)
{
$setup = $this->getSetup();
$cart = $setup->getCart();
if (!$cart instanceof Cart || !$cartSwitchManager->shouldDisplaySwitchForCart($setup->getCart())) {
return $this->redirectToRoute('brulafine_payment');
}
$currentPack = $this->getCartFactory()->getCurrentPack($cart);
if (!$currentPack) {
return $this->redirectToRoute('brulafine_payment');
}
$cart = $setup->getCart();
//cart gratuit
if (null !== ($discountCode = $cart->getDiscountCode()) && DiscountCode::FREE_PURCHASE === $discountCode->getDiscountCodeType()) {
return $this->redirectToRoute('brulafine_payment');
}
//si custom pack .. rien a faire ici
if ($cart->isWithCustomPack()) {
return $this->redirectToRoute('brulafine_payment');
}
// if cart doesn't allow push, move away
if (!$cart->allowPush()) {
return $this->redirectToRoute('brulafine_payment');
}
//si AB-testing activated .. and user must not view the switch then
//user has nothing to do here
if (!$cart->getUser() instanceof User) {
return $this->redirectToRoute('brulafine_show_packs');
} else {
$userSettings = $cart->getUser()->getSettings();
$show_cart_switch = $userSettings[UserSettings::AB_TEST]['show_cart_switch'] ?? true;
}
if (!$show_cart_switch) {
return $this->redirectToRoute('brulafine_payment');
}
// Chris don't want anymore to see only once the switch.
// $session = $request->getSession();
// if ($session->get('has_switched', false)) {
// return $this->redirectToRoute('brulafine_payment');
// }
$result = $this->getCartFactory()->getNextPackTemplate($cart);
if (!$result || null === $result['packTemplates']) {
// $session->set('has_switched', true);
return $this->redirectToRoute('brulafine_payment');
}
$possibleNextPacksData = $this->getCartFactory()->generatePossibleNextPacksData($result, $cart, $setup);
$response = $this->render($this->getTemplatesDir() . '/Default/push.html.twig', [
'currentPack' => $currentPack,
'currentCartBill' => $this->getCartFactory()->getBill($cart),
'currentCart' => $cart,
'possibleNextPacksData' => $possibleNextPacksData,
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
]);
// $session->set('has_switched', true);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart/payment/{packTemplateId}/{hasCoaching}", name="brulafine_payment",requirements={"packTemplateId" = "\d+", "hasCoaching" = "\d+"}, defaults={"packTemplateId" = "0", "hasCoaching" = "1"})
* @param Request $request
* @param LoggerInterface $logger
* @param UserAddressManager $userAddressManager
* @param EventDispatcherInterface $eventDispatcher
* @param GeoIPManager $geoIPManager
* @param FacebookApiEventsManager $facebookApiEventsManager
* @param EntityManagerInterface $entityManager
* @param SiteManager $siteManager
* @param ABTestManager $ABTestManager
* @param null|int $packTemplateId
* @param mixed $hasCoaching
* @return RedirectResponse|Response
*/
public function paymentAction(
Request $request,
LoggerInterface $logger,
UserAddressManager $userAddressManager,
EventDispatcherInterface $eventDispatcher,
GeoIPManager $geoIPManager,
FacebookApiEventsManager $facebookApiEventsManager,
EntityManagerInterface $entityManager,
SiteManager $siteManager,
ABTestManager $ABTestManager,
EmailManager $emailManager,
ShortId $shortId,
TrackingManager $trackingManager,
TranslatorInterface $translator,
null|int $packTemplateId = 0,
int $hasCoaching = 1
) {
$setup = $this->getSetup();
$cartFactory = $this->getCartFactory();
$user = $this->getUser();
$session = $request->getSession();
if (!$user instanceof User && $session->has(User::GUEST_USER_SESSION_KEY)) {
$user = $entityManager->getRepository(User::class)->findOneBy(['id' => $request->getSession()->get(User::GUEST_USER_SESSION_KEY)]);;
}
$environment = $this->getParameter("kernel.environment");
//detecte le cart a afficher et reellement payer
try {
$cart = $cartFactory->getPaymentCart($setup, $packTemplateId, $hasCoaching, $userAddressManager);
} catch (CartAlreadyPaidException $e) {
// The user should not reach this page with an already paid cart, send him to the last cart paid page
$cart = $cartFactory->getLastPaidCart($user);
if ($cart instanceof Cart) {
$cartFactory->removeCartFromSession();
$logger->notice($e->getMessage() . ", redirecting to the last paid cart over page {$cart->getCartId()}, {$cart->getCartCreateAt()->format("Y-m-d H:i:s")}");
return $this->redirectToRoute('brulafine_over', [
'shortId' => $shortId->encode($cart->getCartId())
]);
}
// if no paid cart is found, emulate previous behavior.
$cartFactory->removeCartFromSession();
$logger->notice($e->getMessage());
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'message' => 'System Error!',
'redirect' => $this->generateUrl('brulafine_show_packs')
], 401);
}
return $this->redirectToRoute('brulafine_show_packs');
} catch (Throwable $e) {
$cartFactory->removeCartFromSession();
$logger->notice($e->getMessage());
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'message' => 'System Error!',
'exception' => $e->getMessage(),
'redirect' => $this->generateUrl('brulafine_show_packs')
], 401);
}
return $this->redirectToRoute('brulafine_show_packs');
}
//sauve le cart a payer dans la DB
$session = $request->getSession();
$session->set('currentCartId', $cart->getCartId());
$entityManager->persist($cart);
$entityManager->flush();
$trStatuses = [Transaction::OK];
// si une transaction est deja en cours on le balance sur OVER
$transaction = $entityManager->getRepository(Transaction::class)->findOneBy([
'cart' => $cart,
'transactionStatus' => $trStatuses,
]);
if ($transaction instanceof Transaction) {
if (Transaction::OK === $transaction->getTransactionStatus()) {
$cartFactory->transitState($cart, 'paymentSuccess');
$entityManager->flush();
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'message' => 'Already payed!',
'redirect' => $this->generateUrl('brulafine_over', ['shortId' => $shortId->encode($cart->getCartId())])
], 401);
}
return $this->redirectToRoute('brulafine_over', [
'shortId' => $shortId->encode($cart->getCartId()),
]);
}
$this->addFlash(
'transactionMessage',
'flashMessages.site.cartAlreadyPaid'
);
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'message' => $translator->trans( 'flashMessages.site.cartAlreadyPaid', array(), TranslationManager::TRANSLATION_DOMAIN_FLASH),
], 401);
}
return $this->redirectToRoute('brulafine_payment', [
'packTemplateId' => $packTemplateId,
'hasCoaching' => $hasCoaching,
]);
}
$purchase = new Purchase();
$bypassPayment = false;
//FREE PURCHASE
if ($cartFactory->cartIsEligibleForFreePurchase($cart)) {
$purchase->setPaymentMethod(Purchase::PAYMENT_FREE);
$cart->setCartBillingType(Cart::BILLING_TYPE_FREE);
$bypassPayment = true;
}
//BANK TRANSFER
$bankTransfer = new BankTransfer($request->getClientIp(), $request->headers->get('User-Agent'));
$bankTransfertForm = $this->createForm(BankTransferType::class, $bankTransfer);
$bankTransfertForm->handleRequest($request);
if (!$bypassPayment && $bankTransfertForm->isSubmitted() && $bankTransfertForm->isValid()) {
$purchase->setPaymentMethod(Purchase::PAYMENT_BANK_TRANSFERT);
$cart->setCartBillingType(Cart::BILLING_TYPE_ALTERNATIVE);
$bypassPayment = true;
}
//PAYPAL
$paypalPayment = new PaypalPayment($request->getClientIp(), $request->headers->get('User-Agent'));
$paypalForm = $this->createForm(PaypalPaymentType::class, $paypalPayment);
$paypalForm->handleRequest($request);
if (!$bypassPayment && $paypalForm->isSubmitted() && $paypalForm->isValid()) {
$purchase->setPaymentMethod(Purchase::PAYMENT_PAYPAL);
$cart->setCartBillingType(Cart::BILLING_TYPE_PAYPAL);
$bypassPayment = true;
}
//recupere le client qui doit payer le cart
$user = $cart->getUser();
$site = $setup->getSite();
// This code is specific to ease testing of 3ds payments
if ($request->query->get('3ds') && !$bypassPayment || ($siteManager->getYamlConfigParameter('site_force_3ds') && !in_array($environment, ['test', 'dev']))) {
$session->set('force_3ds', true);
}
// Check if there is an AB test that force the 3DS for this customer.
$abTestManager = $ABTestManager;
if (!$bypassPayment && ($abTestManager->hasTest($trackingManager->getCurrentTracking(), SiteABTest::FORCED_3DS_PURCHASE_ON) || $abTestManager->cartHasTest($cart, SiteABTest::FORCED_3DS_PURCHASE_ON))) {
$session->set('force_3ds', true);
}
//get the submited payment infos (if so)
$cardPayment = new CardPayment($request->getClientIp(), $request->headers->get('User-Agent'));
$form = $this->createForm(UserPaymentType::class, $cardPayment);
$form->handleRequest($request);
if (!$bypassPayment && !($form->isSubmitted() && $form->isValid())) {
$now = date_create();
$disableCbFormData = $session->get('disableCbForm', ['userId' => -1, 'dateEnd' => $now]);
$disableCbForm = false !== $disableCbFormData
&& $user->getId() == $disableCbFormData['userId']
&& $now < $disableCbFormData['dateEnd'];
$formType = 'creditcard';
if (Purchase::PAYMENT_BANK_TRANSFERT == $purchase->getPaymentMethod()) {
$formType = 'banktransfer';
} elseif (UserPayment::TYPE_BCMC === $cardPayment->getCardType()) {
$formType = 'bancontact';
}
if ($form->isSubmitted() && !$form->isValid()) {
$errorMsg = $form->getErrors()->current() instanceof FormError ? $form->getErrors()->current()->getMessage() : '';
$paymentErrorEvent = new PaymentErrorEvent($errorMsg, null, $cart);
$eventDispatcher->dispatch($paymentErrorEvent, PaymentSubscriber::PAYMENT_ERROR);
if ($request->isXmlHttpRequest()) {
$formErrorsResolver = new FormErrorsResolver($form);
$errors = $formErrorsResolver->resolve();
if (!empty($errors)) {
$errorMsg = $translator->trans('site.purchaseForm.errors.2', [], TranslationManager::TRANSLATION_DOMAIN_SITE);
if (isset($errors['terms'])) {
$errorMsg = $translator->trans('site.purchaseForm.errors.1', [], TranslationManager::TRANSLATION_DOMAIN_SITE);
}
}
if (isset($errors['expirationYear']) || isset($errors['expirationMonth'])) {
$errorMsg = $translator->trans('site.purchaseForm.errors.3', [], TranslationManager::TRANSLATION_DOMAIN_SITE);
}
return new JsonResponse([
'result' => 'ko',
'formType' => $formType,
'disableCbForm' => $disableCbForm,
'message' => $errorMsg,
], 401);
}
}
$defaultPacks = $this->getPackFactory()->getDefaultProposedPacks($site);
$defaultProposedPack = $abTestManager->getPacksForTracking($setup->getTracking(), $defaultPacks);
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::ADD_PAYMENT_INFO, $cart, $setup->getTracking());
$response = $this->render($this->getTemplatesDir() . '/Default/payment.html.twig', [
'cart' => $cart,
'cartTotal' => $cartFactory->computeCartTotal($cart),
'form' => $form->createView(),
'bankTransferForm' => $bankTransfertForm->createView(),
'paypalForm' => $paypalForm->createView(),
'isBillingTypeAlternative' => $cart->getCartBillingType() === Cart::BILLING_TYPE_ALTERNATIVE,
'defaultProposedPacks' => $defaultProposedPack,
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
'forceTransfer' => $session->get('forceTransfer', 0),
'showBankTransfer' => $session->get('showBankTransfer', 0),
'disableCbForm' => $disableCbForm,
'tld' => $geoIPManager->getCountryCode($request->getClientIp()),
'formType' => $request->query->get('formType', $formType),
'environment' => $environment
]);
return $this->appendCookie($response, $setup->getCookie());
}
$commandeId = $shortId->encode($cart->getCartId());
if (Purchase::PAYMENT_PAYPAL == $purchase->getPaymentMethod()) {
$userPayment = $paypalPayment;
} else {
$userPayment = $form->getData();
}
// if set, always force the payment in 3ds.
if (!$bypassPayment && $session->get('force_3ds')) {
$purchase->setPaymentMethod(Purchase::PAYMENT_3DS);
$payment3DSSwapEvent = new PaymentSwap3DSEvent(PaymentSwap3DSEvent::REASON_OTHER, $cart);
$eventDispatcher->dispatch($payment3DSSwapEvent, PaymentSubscriber::PAYMENT_3DS_SWAP);
}
try {
$this->getBillingFactory()->processCart($cart, $site, $user, $userPayment, $purchase);
$cartTotal = $cartFactory->computeCartTotal($cart);
$this->addFlash('conversion_tag', 'show');
$session->set('justPurchased', true);
// if it's a paypal purchase we return json data
if (Purchase::PAYMENT_PAYPAL == $purchase->getPaymentMethod()) {
if (Purchase::STATUS_SUCCESS === $purchase->getStatus()) {
return $response = new JsonResponse(
[
'result' => 'ok'
, 'redirect' => $this->generateUrl('brulafine_over', ['shortId' => $commandeId])
],
200
);
} else {
return $response = new JsonResponse(['result' => 'fail'], 401);
}
}
if (Purchase::STATUS_SUCCESS === $purchase->getStatus()) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => 'ok',
'redirect' => $this->generateUrl('brulafine_over', ['shortId' => $commandeId]),
], 200);
} else {
return $this->redirectToRoute('brulafine_over', ['shortId' => $commandeId]);
}
}
if (Purchase::STATUS_FAILED === $purchase->getStatus()) {
$metaData = $purchase->getMetaData();
$msgError = 'flashMessages.site.errorDuringTransaction';
$errorText = $metaData['errorText'];
$disableCbForm = $metaData['disableCbForm'];
if ([] !== $disableCbForm) {
$session->set('disableCbForm', $disableCbForm);
}
$showBankTransfer = $metaData['showBankTransfer'];
if ($showBankTransfer) {
$session->set('showBankTransfer', 1);
}
$forceTransfert = $metaData['forceTransfert'];
if ($forceTransfert) {
$session->set('forceTransfert', 1);
}
$errorText = array_filter($errorText, function (string $value) {
return '' !== $value;
});
if (!empty($errorText) && is_array($errorText)) {
$this->addFlash('error', $errorText[0]);
if (isset($errorText[1])) {
$this->addFlash('additionnalInstructions', $errorText[1]);
}
} else {
$this->addFlash('error', $msgError);
}
$formType = 'creditcard';
if (Purchase::PAYMENT_BANK_TRANSFERT == $purchase->setPaymentMethod(Purchase::PAYMENT_BANK_TRANSFERT)) {
$formType = 'banktransfer';
} elseif (UserPayment::TYPE_BCMC === $userPayment->getCardType()) {
$formType = 'bancontact';
}
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'message' => $translator->trans($msgError, [], TranslationManager::TRANSLATION_DOMAIN_FLASH),
'formType' => $formType,
'forceTransfert' => $forceTransfert,
'showBankTransfer' => $showBankTransfer
], 401);
}
return $this->redirectToRoute('brulafine_payment', [
'packTemplateId' => 0,
'hasCoaching' => 1,
'formType' => $formType,
]);
}
if (Purchase::PAYMENT_BANK_TRANSFERT === $purchase->getPaymentMethod()) {
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ko",
'redirect' => $this->generateUrl('brulafine_over', ['shortId' => $commandeId]),
], 401);
}
return $this->redirectToRoute('brulafine_over', ['shortId' => $commandeId]);
}
if (Purchase::PAYMENT_3DS === $purchase->getPaymentMethod()) {
$code = new CodeHtml3DSLog();
$code->setDate(new \DateTime());
$code->setCode($purchase->getMetaData()['code']);
$code->setTransaction($purchase->getPreviousTransaction());
$entityManager->persist($code);
$entityManager->flush();
if ($request->isXmlHttpRequest()) {
$content = $this->render($this->getTemplatesDir() . '/Default/display-html-code.html.twig', [
'code' => $purchase->getMetaData()['code'],
])->getContent();
return new JsonResponse([
'result' => 'ok',
'mode' => '3ds',
'content' => $content
], 200);
}
return $this->render($this->getTemplatesDir() . '/Default/display-html-code.html.twig', [
'code' => $purchase->getMetaData()['code'],
]);
}
throw new \RuntimeException(sprintf('Undefined %s Purchase method', $purchase->getPaymentMethod()));
} catch (Throwable $e) {
$message = 'Une erreur est survenue apres transaction.' . PHP_EOL
. 'CLIENT EMAIL = ' . $user->getUsername() . PHP_EOL
. 'CART ID = ' . $cart->getCartId() . PHP_EOL
. 'ERROR TYPE = ' . get_class($e) . PHP_EOL
. 'ERROR CODE = ' . $e->getCode() . PHP_EOL
. 'ERROR Message = ' . $e->getMessage() . PHP_EOL
. 'ERROR TRACE = ' . $e->getTraceAsString() . PHP_EOL;
$emailManager->sendPaymentAlert("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded", $message);
$logger->error($e->getMessage());
$logger->critical("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded => " . $message);
$this->addFlash('conversion_tag', 'show');
$session->set('justPurchased', true);
if ($request->isXmlHttpRequest()) {
return new JsonResponse([
'result' => "ok",
'redirect' => $this->generateUrl('brulafine_over', ['shortId' => $commandeId]),
], 200);
}
return $this->redirectToRoute('brulafine_over', ['shortId' => $commandeId]);
}
}
/**
* This is used when the user is waiting for the paypal validation of his payment.
* Note : Normally the payment is instant and included in the flow, but in cas of problem this is the backup.
*
* @Route("/cart/paypal/payment/check/{cartId}", name="brulafine_paypal_payment_check")
* @param mixed $shortId
* @param mixed $cartId
* @return RedirectResponse|Response
*/
public function checkPaypalPaymentAction(ShortId $shortId, $cartId, EntityManagerInterface $entityManager)
{
$decodedId = $shortId->decode($cartId);
$cart = $entityManager->getRepository(Cart::class)->findOneByCartId($decodedId);
if ($cart instanceof Cart && $cart->isPaid()) {
$response = ['result' => 'ok', 'redirect' => $this->generateUrl("brulafine_over", ['shortId' => $cartId])];
} else {
$response = ['result' => 'fail'];
}
return new JsonResponse($response, 200);
}
/**
* @Route("/cart/3dspayment/{merkavId}/{transactionId}/3ds", name="brulafine_3dspayment")
* @param Request $request
* @param mixed $merkavId
* @param mixed $transactionId
* @return RedirectResponse
*/
public function externalPaymentAction(Request $request, $merkavId, $transactionId, LoggerInterface $logger, ShortId $shortId, EntityManagerInterface $entityManager)
{
// Stopped for 1 seconde
sleep(1);
$transactionRepo = $entityManager->getRepository(Transaction::class);
// First, check transaction:
$transaction = $transactionRepo->find($transactionId);
// If there is no transaction wait a little more
if (!$transaction instanceof Transaction) {
sleep(3);
$transaction = $transactionRepo->find($transactionId);
}
// If there is no transaction wait a little more
if (!$transaction instanceof Transaction) {
sleep(9);
$transaction = $transactionRepo->find($transactionId);
}
if (!$transaction instanceof Transaction) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedMissing');
$logger->critical("**3DS ERROR *** Missing transaction in 3DS callback. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_payment');
}
// Add the info that the user saw the return page.
$transaction->setVisitedReturnPage(true);
$entityManager->flush();
$cart = $transaction->getCart();
if (!$cart instanceof Cart) {
$logger->critical("**3DS ERROR *** Receiving a callback for a 3ds trx but can't find the cart! Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_payment');
}
if ($merkavId != $transaction->getTransactionMerkavId()) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongMkvId');
$logger->critical("**3DS ERROR *** Wrong transaction id in 3DS callback. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_payment');
}
// Check if this is the payment transaction is a bill.
if (!$transaction->getUpsellCart() instanceof UpsellCart && Transaction::BILL != $transaction->getTransactionType()) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongType');
$logger->error("**3DS ERROR *** Wrong transaction type in 3DS callback. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_payment');
// If there is a payment transaction, make sure that this is with the correct status (rebill for upsell)
} elseif ($transaction->getUpsellCart() instanceof UpsellCart && Transaction::REBILL != $transaction->getTransactionType()) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongType');
$logger->error("**3DS ERROR *** Wrong transaction type in 3DS callback. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_over', ['shortId' => $cart->getEncodedId($shortId)]);
}
// if this transaction is marked as failed or error then no need to wait anything ...
if (in_array($transaction->getTransactionStatus(), [Transaction::FAILED, Transaction::ERROR])) {
if (!$transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongStatus');
return $this->redirectToRoute('brulafine_payment');
} elseif ($transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $cart->getEncodedId($shortId)]);
}
}
// Starting from here it is possible that we loaded the transaction very fast but it wasn't already updated.
// Let's add a timer for a second chance.
if (Transaction::OK != $transaction->getTransactionStatus()) {
sleep(2);
}
$entityManager->refresh($transaction);
// Again if transaction became failed we stop here.
if (in_array($transaction->getTransactionStatus(), [Transaction::FAILED, Transaction::ERROR])) {
if (!$transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongStatus');
return $this->redirectToRoute('brulafine_payment');
} elseif ($transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $cart->getEncodedId($shortId)]);
}
}
// if not ok manage the return.
if (Transaction::OK != $transaction->getTransactionStatus()) {
if (!$transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('error', 'flashMessages.site.paymentNotFinalizedWrongStatus');
$logger->error("**3DS ERROR *** Wrong transaction status in 3DS callback. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_payment');
} elseif ($transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
$logger->error("**3DS ERROR *** Wrong transaction status in 3DS callback for an upsell purchase. Data => Transaction ID : {$transactionId}, Request : " . print_r($request, true));
return $this->redirectToRoute('brulafine_over', ['shortId' => $cart->getEncodedId($shortId)]);
} else {
$logger->critical("Unknow status for a return in the 3ds system. {$transaction->getTransactionId()} - status : {$transaction->getTransactionStatus()}");
return $this->redirectToRoute('brulafine_payment');
}
}
// if this was an upsell we add the info as flash.
if ($transaction->getUpsellCart() instanceof UpsellCart) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseOK');
}
return $this->redirectToRoute('brulafine_over', ['shortId' => $cart->getEncodedId($shortId)]);
}
/**
* @Route("/cart/over/{shortId}", name="brulafine_over",requirements={"shortId" = "[\w-]+"})
* @param Request $request
* @param PackManager $packFactory
* @param LoggerInterface $logger
* @param SiteManager $siteManager
* @param CartManager $cartFactory
* @param SessionInterface $session
* @param Packages $package
* @param ABTestManager $ABTestManager
* @param FacebookApiEventsManager $facebookApiEventsManager
* @param EventDispatcherInterface $eventDispatcher
* @param EntityManagerInterface $entityManager
* @param ShortId $shortIdGenerator
* @param EmailManager $emailManager
* @param null|string $shortId
* @return RedirectResponse|Response
* @throws Exception
*/
public function overAction(
Request $request,
PackManager $packFactory,
LoggerInterface $logger,
SiteManager $siteManager,
CartManager $cartFactory,
SessionInterface $session,
Packages $package,
ABTestManager $ABTestManager,
FacebookApiEventsManager $facebookApiEventsManager,
EventDispatcherInterface $eventDispatcher,
EntityManagerInterface $entityManager,
ShortId $shortIdGenerator,
EmailManager $emailManager,
string $shortId = null
): RedirectResponse|Response {
$displayConversionTag = $siteManager->canDisplayConversionTag();
$setup = $this->getSetup();
$locale = $request->getLocale();
try {
$cartId = $shortIdGenerator->decode($shortId);
} catch (\Throwable $e) {
$logger->critical("Receiving wrong cart id for cart over page : {$shortId} - can't process. -- {$request->headers->get('referer')} -- ");
return $this->redirectToRoute('brulafine_show_packs');
}
$user = $setup->getUser();
if (!$user instanceof User) {
$user = $entityManager->getRepository(User::class)->findOneBy(['id' => $request->getSession()->get(User::GUEST_USER_SESSION_KEY)]);
}
// Si le client arrive avec un cart en train d'etre paye
$cart = $entityManager->getRepository(Cart::class)->findOneBy(['cartId' => $cartId, 'user' => $user]);
if (!$cart instanceof Cart) {
return $this->redirectToRoute('brulafine_show_packs');
}
if (Cart::STATE_PENDING_PAYMENT == $cart->getCartState()) {
return $this->redirectToRoute('brulafine_payment');
}
if ($cart->isWaitingBankTransfer()) {
// on vire le cart de la session ... il n'y a plus de cart
$this->getCartFactory()->removeCartFromSession();
$response = $this->render($this->getTemplatesDir() . '/Default/bank-transfert.html.twig', [
'cart' => $cart,
'cartTotal' => $this->getCartFactory()->computeCartTotal($cart),
'site' => $setup->getSite(),
]);
return $this->appendCookie($response, $setup->getCookie());
}
$transaction = $entityManager->getRepository(Transaction::class)->findOneBy(['cart' => $cart], ['transactionId' => 'desc']);
if (!$transaction instanceof Transaction || Transaction::ERROR == $transaction->getTransactionStatus()) {
return $this->redirectToRoute('brulafine_payment');
}
// on vire le cart de la session ... il n'y a plus de cart
$this->getCartFactory()->removeCartFromSession();
//on regarde l'etat du cart
//si le cart a deja ete envoye on a rien a faire ici
if (!$cart->isInReview()) {
return $this->redirectToRoute('brulafine_user_commandes');
}
$user = $cart->getUser();
$upsellProducts = [];
if (!$cart->getPaymentTransaction() instanceof Transaction) {
$logger->critical("We have a cart in the over action that is not paid. {$cart->getCartId()} with the status {$cart->getCartState()}");
}
if ($cart->getSite()->hasUpsells() && $cart->canAddUpsells() && $siteManager->localeHasUpsells($locale)) {
$upsellPacks = $packFactory->getUpsellPacks();
$upsellProducts = $ABTestManager->getPacksForTracking($setup->getTracking(), $upsellPacks);
if (strtoupper($cart->getCartAddress()->getCountry()) == "BE") {
$filteredUpsellProducts = [];
$notAllowedUpsellPacks = ['Dormalis', 'Pack_Huile_Minceur'];
/** @var SitePackTemplate $upsellProduct */
foreach ($upsellProducts as $upsellProduct) {
if (!in_array($upsellProduct->getPackTemplate()->getPackTemplateName(), $notAllowedUpsellPacks)) {
$filteredUpsellProducts[] = $upsellProduct;
}
}
$upsellProducts = $filteredUpsellProducts;
}
}
$preUpsellPack = null;
if ($cart->getSite()->hasPreUpsells() && $cart->canAddUpsells()) {
$preUpsellPack = $cartFactory->getLinkedPreUpsellFromCart($cart);
}
// We enter into the upsell area, yeah !! :)
$purchaseSuccess = false;
if ($request->getMethod() === "POST" && !empty($upsellProducts) && $request->request->get('buyUpsell')) {
// here we buy the new stuff :)
$upsellCart = new UpsellCart($cart);
$entityManager->persist($upsellCart);
$selectedProduct = null;
$selectedId = (int) $request->request->get('id');
$selectedQuantity = (int) $request->request->get('quantity');
foreach ($upsellProducts as $upsellProduct) {
if ($upsellProduct->getSitePackTemplateId() === $selectedId) {
$selectedProduct = $upsellProduct;
break;
}
}
if ($selectedQuantity > UpsellCart::MAX_SINGLE_ITEM) {
$selectedQuantity = 10;
}
if ($selectedQuantity < 0) {
$selectedQuantity = 1;
}
if ($selectedProduct instanceof SitePackTemplate) {
$upsellPack = $packFactory->makeUpsellPackFromTemplate($upsellProduct->getPackTemplate(), $cart->getTracking());
$upsellPack->updateQuantity($selectedQuantity);
$upsellCart->addUpsellPack($upsellPack);
$entityManager->persist($upsellPack);
$entityManager->flush();
// ici on tente l'achat
$purchase = new Purchase();
//$purchase->setPaymentMethod(Purchase::PAYMENT_3DS);
$bypassPayment = false;
$userPayment = new CardPayment($request->getClientIp(), $request->headers->get('User-Agent'));
//**************
try {
$this->getBillingFactory()->processUpsellCart($upsellCart, $userPayment, $purchase);
$cartTotal = $cartFactory->computeCartTotal($upsellCart);
$upsellCart->setUpsellCartTotalAmount($cartTotal['packGrandTotal']);
$entityManager->flush();
$this->addFlash('upsell_conversion_tag', 'show');
$session->set('justPurchasedUpsell', true);
if (Purchase::STATUS_SUCCESS === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseOK');
$request->getSession()->set(self::UPSELL_PURCHASE_SUCCESS, true);
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
if (Purchase::STATUS_FAILED === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
if (Purchase::PAYMENT_3DS === $purchase->getPaymentMethod()) {
$code = new CodeHtml3DSLog();
$code->setDate(new \DateTime());
$code->setCode($purchase->getMetaData()['code']);
$code->setTransaction($purchase->getPreviousTransaction());
$entityManager->persist($code);
$entityManager->flush();
return $this->render($this->getTemplatesDir() . '/Default/display-html-code.html.twig', [
'code' => $purchase->getMetaData()['code'],
]);
}
throw new \RuntimeException(sprintf('Undefined %s Purchase method', $purchase->getPaymentMethod()));
} catch (Throwable $e) {
$message = 'Une erreur est survenue apres transaction.' . PHP_EOL
. 'CLIENT EMAIL = ' . $user->getUsername() . PHP_EOL
. 'CART ID = ' . $cart->getCartId() . PHP_EOL
. 'ERROR TYPE = ' . get_class($e) . PHP_EOL
. 'ERROR CODE = ' . $e->getCode() . PHP_EOL
. 'ERROR Message = ' . $e->getMessage() . PHP_EOL
. 'ERROR TRACE = ' . $e->getTraceAsString() . PHP_EOL;
$emailManager->sendPaymentAlert("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded", $message);
$logger->error($e->getMessage());
$logger->critical("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded => " . $message);
$this->addFlash('conversion_tag', 'show');
$session->set('justPurchased', true);
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
}
}
if ($request->getMethod() === "POST" && $request->request->get('justRejectPreUpsell')) {
$cartFactory->addNewAction($cart, CartAction::REFUSED_PREUPSELL);
}
// Here we enter in PreUpsell :)
if ($request->getMethod() === "POST" && $request->request->get('buyPreUpsell') && null != $preUpsellPack) {
// here we buy the new stuff :)
$upsellCart = new UpsellCart($cart);
$entityManager->persist($upsellCart);
if ($preUpsellPack instanceof SitePackTemplate) {
$upsellPack = $packFactory->makeUpsellPackFromTemplate($preUpsellPack->getPackTemplate(), $cart->getTracking());
$upsellCart->addUpsellPack($upsellPack);
$upsellCart->setIsPreUpsell(true);
$entityManager->persist($upsellPack);
$entityManager->flush();
// ici on tente l'achat
$purchase = new Purchase();
//$purchase->setPaymentMethod(Purchase::PAYMENT_3DS);
$bypassPayment = false;
$userPayment = new CardPayment($request->getClientIp(), $request->headers->get('User-Agent'));
//**************
try {
$this->getBillingFactory()->processUpsellCart($upsellCart, $userPayment, $purchase);
$cartTotal = $cartFactory->computeCartTotal($upsellCart);
$upsellCart->setUpsellCartTotalAmount($cartTotal['packGrandTotal']);
$entityManager->flush();
$this->addFlash('upsell_conversion_tag', 'show');
if (Purchase::STATUS_SUCCESS === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseOK');
$request->getSession()->set(self::UPSELL_PURCHASE_SUCCESS, true);
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
if (Purchase::STATUS_FAILED === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
if (Purchase::PAYMENT_3DS === $purchase->getPaymentMethod()) {
$code = new CodeHtml3DSLog();
$code->setDate(new \DateTime());
$code->setCode($purchase->getMetaData()['code']);
$code->setTransaction($purchase->getPreviousTransaction());
$entityManager->persist($code);
$entityManager->flush();
return $this->render($this->getTemplatesDir() . '/Default/display-html-code.html.twig', [
'code' => $purchase->getMetaData()['code'],
]);
}
throw new \RuntimeException(sprintf('Undefined %s Purchase method', $purchase->getPaymentMethod()));
} catch (Throwable $e) {
$message = 'Une erreur est survenue apres transaction.' . PHP_EOL
. 'CLIENT EMAIL = ' . $user->getUsername() . PHP_EOL
. 'CART ID = ' . $cart->getCartId() . PHP_EOL
. 'ERROR TYPE = ' . get_class($e) . PHP_EOL
. 'ERROR CODE = ' . $e->getCode() . PHP_EOL
. 'ERROR Message = ' . $e->getMessage() . PHP_EOL
. 'ERROR TRACE = ' . $e->getTraceAsString() . PHP_EOL;
$emailManager->sendPaymentAlert("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded", $message);
$logger->error($e->getMessage());
$logger->critical("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded => " . $message);
$this->addFlash('conversion_tag', 'show');
$session->set('justPurchased', true);
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_over', ['shortId' => $shortId]);
}
}
}
/** @var SitePackTemplate $sitePackTemplate */
$sitePackTemplate = $cartFactory->getSitePackTemplateForCart($cart);
if ($cartFactory->cartIsEligibleForPreUpsell($cart) && $cart->canAddUpsells() && !$sitePackTemplate->isPreUpsell()) {
$template = $this->getTemplatesDir() . '/Default/over_pre_upsale.html.twig';
} elseif (!$sitePackTemplate->isPreUpsell() && !$sitePackTemplate->isUpsell() && count($upsellProducts) !== 0) {
$template = $this->getTemplatesDir() . '/Default/over_upsell.html.twig';
} else {
$template = $this->getTemplatesDir() . '/Default/over.html.twig';
}
$upsellProductsArrayForTwig = [];
$upsellProductsArrayForTwigWithKeys = [];
foreach ($upsellProducts as $upsellProduct) {
/** @var PackTemplate $packTemplate */
$packTemplate = $upsellProduct->getPackTemplate();
$options = $packTemplate->getPackTemplateOptions();
$title = $options['title'][$locale] ?? '';
$product = [
'id' => $upsellProduct->getSitePackTemplateId(),
'name' => $packTemplate->getPackTemplateName(),
'title' => $title,
'desc_short' => $options['short_desc'][$locale] ?? '',
'description_medium' => $options['medium_desc'][$locale] ?? '',
'reduction_percent' => $options['reduc_percent'],
'price' => $options['normal_price'],
'reducted_price' => $options['reduc_price'],
'quantity' => 1,
'image' => $package->getUrl($options['image_link'][$locale] ?? ''),
'image_large' => $package->getUrl($options['image_large_link'][$locale] ?? ''),
'category' => $options['category'][$locale] ?? '',
'category_color' => $options['category_color'],
];
if (isset($options['suggest_pack'])) {
$product['pack'] = $options['suggest_pack'];
$product['pack_modal_title'] = $options['modal_title'][$locale] ?? '';
}
$upsellProductsArrayForTwig[] = $product;
$upsellProductsArrayForTwigWithKeys[$product['name']] = $product;
}
// le paiement a ete effectue correctement
$cartTotal = $this->getCartFactory()->computeCartTotal($cart);
/** @var CartCreditNote $cartCreditNote */
$cartCreditNote = $cart->getCreditNotes()[0];
if ($cartTotal['creditNoteAmount'] && !$cartCreditNote->isUsed()) {
$event = new CartCreditNoteUsedEvent($cart, $cartTotal);
$eventDispatcher->dispatch($event, CartSubscriber::CART_CREDIT_NOTE_USED);
}
$electronicProductShipping = $entityManager
->getRepository(ElectronicProductShipping::class)
->findOneBy(['user' => $user, 'status' => ElectronicProductShipping::ACTIVATED]);
if (null !== $electronicProductShipping) {
$coachingLink = true;
} else {
$coachingLink = false;
}
$cartLockTime = $cart->getCartLockedAt();
$now = new \DateTime();
if (!$cartLockTime instanceof \DateTime) {
$cartLockDelay = $siteManager->getYamlConfigParameter("frontEnd")['upsells']['delayBeforeCartLock'] ?? "PT30M";
$cartLockTime = $now->add(new \DateInterval($cartLockDelay));
}
$upsellTime = $cartLockTime->diff($now);
if (!$upsellTime->i && !$upsellTime->s) {
$upsellTime = new \DateInterval($cartLockDelay);
}
$upsellTime = ['mins' => $upsellTime->i, 'sec' => $upsellTime->s];
$justPurchasedUpsell = false;
if ($request->getSession()->has(self::UPSELL_PURCHASE_SUCCESS) && true === $request->getSession()->get(self::UPSELL_PURCHASE_SUCCESS)) {
$request->getSession()->remove(self::UPSELL_PURCHASE_SUCCESS);
$justPurchasedUpsell = true;
}
$defaultPacks = $this->getPackFactory()->getDefaultProposedPacks($setup->getSite());
$defaultProposedPack = $ABTestManager->getPacksForTracking($setup->getTracking(), $defaultPacks);
$facebookApiEventsManager->createEvent(FacebookApiEventsManager::PURCHASE, $cart, $setup->getTracking());
$response = $this->render($template, [
'cart' => $cart,
'cartTotal' => $cartTotal,
'cartShortId' => $shortIdGenerator->encode($cart->getCartId()),
'espace_link' => $coachingLink,
'defaultProposedPacks' => $defaultProposedPack,
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
'displayConversionTag' => $displayConversionTag,
'upsellProducts' => $upsellProducts,
'upsellProductsArray' => $upsellProductsArrayForTwigWithKeys,
'purchaseSuccess' => $purchaseSuccess,
'upsellProductsJs' => json_encode($upsellProductsArrayForTwig),
'lastFour' => $cart->getPaymentTransaction()->getPaymentToken() instanceof PaymentToken ? $cart->getPaymentTransaction()->getPaymentToken()->getLastFour() : PaymentToken::DEFAULT_EMPTY_LAST_FOUR,
'upsellTime' => $upsellTime,
'justPurchasedUpsell' => $justPurchasedUpsell,
'preUpsellPack' => $preUpsellPack
]);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/cart/confirm", name="brulafine_confirm")
* @return Response
* @throws Exception
*/
public function confirmAction(ABTestManager $abTestManager)
{
$setup = $this->getSetup();
//get current cart
$currentCart = $setup->getCart();
//if cart is empty fill it :)
if (!$currentCart) {
return $this->redirectToRoute('brulafine_show_packs');
}
//if the order is in more than 30 minutes don`t show confirm page
if (!$this->getCartFactory()->hasOrderInDelay($setup->getUser())) {
return $this->redirectToRoute('brulafine_show_packs');
}
//get last paid Cart
/** @var Cart $lastPaidCart */
$lastPaidCart = $this->getCartFactory()->getLastPaidCart($setup->getUser());
$defaultPacks = $this->getPackFactory()->getDefaultProposedPacks($setup->getSite());
$defaultProposedPack = $abTestManager->getPacksForTracking($setup->getTracking(), $defaultPacks);
$response = $this->render($this->getTemplatesDir() . '/Default/confirm.html.twig', [
'cart' => $currentCart,
'currentCartTotal' => $setup->getCartTotal(),
'lastPaidCart' => $lastPaidCart,
'lastPaidCartDate' => $lastPaidCart->getPaymentTransaction()->getTransactionStamp(),
'lastPaidCartTotal' => $this->getCartFactory()->computeCartTotal($lastPaidCart),
'defaultProposedPacks' => $defaultProposedPack,
'tracking' => $setup->getTracking(),
'site' => $setup->getSite(),
]);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* @Route("/offers/{offer}", name="brulafine_offers")
* @param Request $request
* @param LoggerInterface $logger
* @param SiteManager $siteManager
* @param CartManager $cartFactory
* @param SessionInterface $session
* @param Packages $package
* @param EntityManagerInterface $entityManager
* @param ShortId $shortIdTool
* @param $offer
* @return RedirectResponse|Response
* @throws Exception
*/
public function offersAction(
Request $request,
LoggerInterface $logger,
SiteManager $siteManager,
CartManager $cartFactory,
SessionInterface $session,
Packages $package,
EntityManagerInterface $entityManager,
ShortId $shortIdTool,
EmailManager $emailManager,
$offer
) {
// $displayConversionTag = $siteManager->canDisplayConversionTag();
$setup = $this->getSetup();
$environment = $this->getParameter("kernel.environment");
if ($request->query->get('3ds') || ($siteManager->getYamlConfigParameter('site_force_3ds') && !in_array($environment, ['test', 'dev']))) {
$session->set('force_3ds', true);
}
// we need to know which offer to load.
if (null == $offer || !in_array($offer, CartManager::$possibleOffers)) {
return $this->redirectToRoute('brulafine_show_packs');
}
// load the user - from the system or the session (for Guest users).
$user = $setup->getUser();
if (!$user instanceof User) {
$user = $entityManager->getRepository(User::class)->findOneBy(['id' => $request->getSession()->get(User::GUEST_USER_SESSION_KEY)]);
}
// we must have a user here.
if (!$user instanceof User) {
return $this->redirectToRoute('brulafine_show_packs');
}
// get last order
$lastOrder = $user->getLastOrder();
if (!$lastOrder instanceof Cart) {
return $this->redirectToRoute('brulafine_show_packs');
}
// if the main pack is preupsell or upsell we skip it
/** @var SitePackTemplate $sitePackTemplate */
$sitePackTemplate = $cartFactory->getSitePackTemplateForCart($lastOrder);
if (($offer == CartManager::OFFER_PREUPSELL && $sitePackTemplate->isPreUpsell()) || ($offer == CartManager::OFFER_UPSELL && $sitePackTemplate->isUpsell())) {
return $this->redirectToRoute('brulafine_show_packs');
}
// if the last cart is not eligible for PreUpsells (Custom packs for example) we redirect to upsell offer
if (!$cartFactory->cartIsEligibleForPreUpsell($lastOrder) && CartManager::OFFER_PREUPSELL == $offer) {
return $this->redirectToRoute('brulafine_offers', ["offer" => CartManager::OFFER_UPSELL]);
}
// use the address from the last order.
$cartAddress = $lastOrder->getCartAddress();
$duplicateCartAddress = clone $cartAddress;
$purchaseSuccess = false;
// get the offer data
$offerData = match ($offer) {
CartManager::OFFER_UPSELL => $cartFactory->getUpsellOfferData($lastOrder, $setup, $package, $request),
CartManager::OFFER_PREUPSELL => $cartFactory->getPreUpsellOfferData($lastOrder, $setup),
default => [],
};
$template = $this->getTemplatesDir() . '/Default/' . $offerData['template'];
$packForCart = $offerData['packForCart'];
// create offer cart to be able to calculate the shipping.
$offerCart = null;
if ($offerData['createCart']) {
$cartCreatedForLastOrderSessionName = 'offer["'.$offer.'"]["' . $packForCart->getPackTemplateId() . '"]CartCreatedForLastOrder';
if ($request->getSession()->get($cartCreatedForLastOrderSessionName) != $lastOrder->getCartId()) {
$offerCart = $cartFactory->makeCartFromPackTemplate($packForCart, $lastOrder->getSite(), $user->getTracking(), $lastOrder->getAffiliate(), [], $user, $duplicateCartAddress);
$offerCart->setCartState(Cart::STATE_ADDRESS_ASSIGNED);
$offerCart->setShippingRule($lastOrder->getShippingRule());
$offerCart->setPickUpPoint($lastOrder->getPickUpPoint());
$offerCart->setCartShippingCountry($lastOrder->getCartShippingCountry());
$offerCart->setCartBillingType(Cart::BILLING_TYPE_CREDITCARD);
$entityManager->flush();
$request->getSession()->set($cartCreatedForLastOrderSessionName, $lastOrder->getCartId());
$request->getSession()->set('offer["'.$offer.'"]pack["'.$packForCart->getPackTemplateId().'"]CartId', $offerCart->getCartId());
}
}
// we load the cart from the db by session cart id. Its because on upsell offer we create the cart after ajax request.
if (null == $offerCart && $packForCart) {
$offerCart = $entityManager->getRepository(Cart::class)->findOneBy(['cartId' => $request->getSession()->get('offer["'.$offer.'"]pack["'.$packForCart->getPackTemplateId().'"]CartId')]);
}
// we update the quantity of the selected pack.
if ($request->isXmlHttpRequest() && CartManager::OFFER_UPSELL == $offer) {
$cartFactory->updateOfferCartProductQuantity($offerCart, $request);
//update cart total.
$cartTotalForNewCart = $cartFactory->computeCartTotal($offerCart);
//return cart total to update data in the front end.
return new JsonResponse($cartTotalForNewCart, 200);
}
// add new action for the cart - justRejectPreUpsell
// users with rejected actions, we dont send them emails for the offers
if ($request->getMethod() === "POST" && $request->request->get('justRejectPreUpsell')) {
$cartFactory->addNewAction($lastOrder, CartAction::REFUSED_PREUPSELL);
return $this->redirectToRoute('brulafine_offers', ["offer" => CartManager::OFFER_UPSELL]);
}
// Here we buy the Offer :)
if ($request->getMethod() === "POST" &&
($request->request->get('buyPreUpsell') || $request->request->get('buyUpsell'))
) {
$purchase = new Purchase();
$bypassPayment = false;
$userPayment = new CardPayment($user->getUserIp(), $user->getUserAgent());
//**************
try {
$this->getBillingFactory()->processCart($offerCart, $offerCart->getSite(), $offerCart->getUser(), $userPayment, $purchase, true);
$this->addFlash('upsell_conversion_tag', 'show');
if (Purchase::STATUS_SUCCESS === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.offerPurchaseOK');
$request->getSession()->set(self::UPSELL_PURCHASE_SUCCESS, true);
return $this->redirectToRoute(
'brulafine_over',
[
'shortId' => $shortIdTool->encode($offerCart->getCartId())
]
);
}
if (Purchase::STATUS_FAILED === $purchase->getStatus()) {
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute(
'brulafine_over',
[
'shortId' => $shortIdTool->encode($offerCart->getCartId())
]
);
}
if (Purchase::PAYMENT_3DS === $purchase->getPaymentMethod()) {
$code = new CodeHtml3DSLog();
$code->setDate(new \DateTime());
$code->setCode($purchase->getMetaData()['code']);
$code->setTransaction($purchase->getPreviousTransaction());
$entityManager->persist($code);
$entityManager->flush();
return $this->render($this->getTemplatesDir() . '/Default/display-html-code.html.twig', [
'code' => $purchase->getMetaData()['code'],
]);
}
throw new \RuntimeException(sprintf('Undefined %s Purchase method', $purchase->getPaymentMethod()));
} catch (Throwable $e) {
$message = 'Une erreur est survenue apres transaction.' . PHP_EOL
. 'CLIENT EMAIL = ' . $user->getUsername() . PHP_EOL
. 'CART ID = ' . $lastOrder->getCartId() . PHP_EOL
. 'ERROR TYPE = ' . get_class($e) . PHP_EOL
. 'ERROR CODE = ' . $e->getCode() . PHP_EOL
. 'ERROR Message = ' . $e->getMessage() . PHP_EOL
. 'ERROR TRACE = ' . $e->getTraceAsString() . PHP_EOL;
$emailManager->sendPaymentAlert("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded", $message);
$logger->error($e->getMessage());
$logger->critical("[{$cartFactory->siteManager->getCurrentSite()->getSiteName()}] payment error after transaction succeeded => " . $message);
$this->addFlash('conversion_tag', 'show');
$session->set('justPurchased', true);
$this->addFlash('info', 'flashMessages.site.additionnalPurchaseNOTOK');
return $this->redirectToRoute('brulafine_offers', ['offer' => $offer]);
}
}
// after the payment we calculate the cart total of the last order
$cartTotal = $cartFactory->computeCartTotal($lastOrder);
$justPurchasedUpsell = false;
if ($request->getSession()->has(self::UPSELL_PURCHASE_SUCCESS)
&& true === $request->getSession()->get(self::UPSELL_PURCHASE_SUCCESS)) {
$request->getSession()->remove(self::UPSELL_PURCHASE_SUCCESS);
$justPurchasedUpsell = true;
}
$newCartTotal = null;
if ($offerCart) {
$newCartTotal = $cartFactory->computeCartTotal($offerCart);
}
$basicTemplateParams = [
'cart' => $lastOrder,
'cartTotal' => $cartTotal,
'newCartTotal' => $newCartTotal,
'cartShortId' => $offerCart ? $shortIdTool->encode($offerCart->getCartId()) : '',
'offer' => $offer,
'tracking' => $setup->getTracking(),
'purchaseSuccess' => $purchaseSuccess,
'justPurchasedUpsell' => $justPurchasedUpsell,
];
$templateParams = array_merge($basicTemplateParams, $offerData['templateData']);
$response = $this->render($template, $templateParams);
return $this->appendCookie($response, $setup->getCookie());
}
/**
* If the client got two orders he needs to confirm one or the other.
* Depending on the one we receive, we cancel it.
* @Route("/cart/confirm/{shortId}", name="brulafine_cancel_cart",requirements={"shortId" = "[\w-]+"})
* @param null|string $shortId
* @return RedirectResponse
*/
public function cancelCartAction(string $shortId = null, EntityManagerInterface $entityManager, ShortId $shortIdGenerator)
{
$setup = $this->getSetup();
$cartId = $shortIdGenerator->decode($shortId);
$redirect = 'brulafine_home';
//get cart
/** @var Cart $cart */
$cart = $entityManager->getRepository(Cart::class)->findOneBy(['cartId' => $cartId, 'user' => $setup->getUser()]);
if ($cart instanceof Cart) {
// the cart is the current one that he didn't pay.
if ($setup->getCart() instanceof Cart && $setup->getCart()->getCartId() === $cart->getCartId() && !$cart->isPurchased()) {
$this->getCartFactory()->cleanUpCurrentCart($setup->getCart());
$this->addFlash('info', "flashMessages.site.emptyCart");
} elseif ($cart->isPaidButNotShipped()) {
// request cancellation of the order
if ($this->getCartFactory()->transitState($cart, "requestCancelationFromClient")) {
$this->addFlash('info', "flashMessages.site.previouseOrderCanceled");
$redirect = 'brulafine_payment';
$entityManager->flush();
} else {
// normally shouldn't happen, except if the status of the cart has changed before he clicks
$this->addFlash('error', "flashMessages.site.errorOccuredTryAgain");
}
}
}
return $this->redirectToRoute($redirect);
}
/**
* @Route("/cart/secure/payment", name="brulafine_initiate_3ds_payment")
* @return Response
* @throws Exception
*/
public function generate3DSiframe(SessionInterface $session)
{
$code = $session->get(UserPayment::SESSION_3DS_CODE);
$session->remove(UserPayment::SESSION_3DS_CODE);
return $this->render(
$this->getTemplatesDir() . '/Default/3ds-iframe.html.twig',
[
'code' => $code
]
);
}
}