<?php
namespace App\Utils;
use App\Entity\Gos\Cart;
use App\Entity\Gos\Country;
use App\Entity\Gos\Coupon;
use App\Entity\Gos\PaymentMethod;
use App\Entity\Gos\PortalSettings;
use App\Entity\Gos\ProductAssociation;
use App\Entity\Gos\ProductCart;
use App\Entity\Gos\ProductPack;
use App\Entity\Gos\ProductPackItem;
use App\Entity\Gos\ProductVariant;
use App\Entity\Gos\Uniqskills\Course;
use App\Entity\Gos\User;
use App\Enum\UpsellingTypes;
use App\Utils\Cart\CartPriceCalculator;
use App\Utils\FacebookPixel\Api\FacebookPixelService;
use App\Utils\Region\CountryService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
class AddToCart
{
private ?Request $request;
private EntityManagerInterface $em;
private CartServices $cartServices;
private TranslatorInterface $translator;
private CountryService $countryService;
private FacebookPixelService $facebookPixelService;
private PortalSettingsService $portalSettingsService;
private CouponClass $couponClass;
private $paymentMethod;
private $portalSettings;
private $cart = null;
private $user;
private $productsForGA = [];
private $status = false;
private $message = false;
private CartPriceCalculator $cartPriceCalculator;
public function __construct(
RequestStack $requestStack,
EntityManagerInterface $entityManager,
Security $security,
CartServices $cartServices,
TranslatorInterface $translator,
CountryService $countryService,
FacebookPixelService $facebookPixelService,
PortalSettingsService $portalSettingsService,
CouponClass $couponClass,
CartPriceCalculator $cartPriceCalculator
) {
$this->request = $requestStack->getCurrentRequest();
$this->em = $entityManager;
$this->user = $security->getUser();
$this->cartServices = $cartServices;
$this->translator = $translator;
$this->countryService = $countryService;
$this->facebookPixelService = $facebookPixelService;
$this->portalSettingsService = $portalSettingsService;
$this->couponClass = $couponClass;
$this->cartPriceCalculator = $cartPriceCalculator;
$this->findPortalSettings();
$this->findCart();
$this->findPaymentMethod();
}
public function addVoucherToCart($voucherCode)
{
$voucherCoupon = $this->em->getRepository(Coupon::class)->findVoucherCode($voucherCode);
$voucherVariant = $voucherCoupon->getGift()->getOrderProductVariant()->getProductVariant()->getProductVariantNoComplete();
if ($this->request === null)
{
return false;
}
$this->request->request->set('productVariantNoComplete', $voucherVariant);
$this->request->request->set('coupon', $voucherCoupon->getCode());
$this->request->request->set('returnCart', true);
return $this->addToCart();
}
public function addToCart($user = null, string $productVariantNo = null)
{
$this->user = $user;
$repoPC = $this->em->getRepository(ProductCart::class);
if ($this->request->get('clearCart'))
{
/** @var ProductCart $productCart */
foreach ($this->cart->getProductCart() as $productCart)
{
$this->cartServices->removeProductFromCart($user, $productCart->getId());
}
$this->em->flush();
$this->em->refresh($this->cart);
}
if (
$this->request->get('portalHash')
|| (
$this->cart->getPortalSettings() === null
&& $this->request->getSession()->has('portalSettingsHash')
)
)
{
$this->findPortalSettings();
if ($this->portalSettings)
{
$this->cart->setPortalSettings($this->portalSettings);
}
$this->em->flush();
$this->em->refresh($this->cart);
}
$newProductVariant = $this->findProductVariantToAdd($productVariantNo);
$newProductPack = $this->findProductPackToAdd();
if (empty($newProductVariant) && empty($newProductPack))
{
$this->addCoupon(); // Add coupon to existing products in cart anyway
return ['error' => 'Product not found'];
}
if (isset($newProductVariant['error']))
{
return $newProductVariant;
}
$this->addToCartProductPack($newProductPack);
$this->addToCartProductVariant($newProductVariant);
$this->addCoupon();
if ($this->request->request->get('returnCart', false))
{
return array(
'status' => $this->status,
'redirect' => 1
);
}
$price = $this->cartPriceCalculator->getCartPrice($this->cart); // return price with postage cost
foreach ($this->productsForGA as $key => $product)
{
$this->productsForGA[$key]['price'] = $price[$product['ppiId'] ?? $product['pvId']]->totalPriceAfterCouponGross;
}
return [
'quantity' => $repoPC->sumProductCart($this->cart->getHash()),
'cartTotalPrice' => $price['totalPriceAfterCouponGross'],
'message' => $this->message,
'status' => $this->status,
'products' => $this->productsForGA
];
}
public function getHash(): string
{
return $this->cart->getHash();
}
private function findProductVariantToAdd(?string $productVariantNo)
{
$newProductVariant = array();
$productVariantNoComplete = $productVariantNo ?: $this->request->get('productVariantNoComplete');
if (!empty($productVariantNoComplete))
{
$arrayProductVariantNo = explode(',', $productVariantNoComplete);
$newProductVariant = $this->em->getRepository(ProductVariant::class)
->findProductVariantToAdd($arrayProductVariantNo);
if (!empty($newProductVariant)
&& ($this->request->request->get('source') == 'uniqskills'
|| $this->request->query->get('source') == 'uniqskills'))
{
foreach ($newProductVariant as $npv)
{
$this->facebookPixelService
->setEvent('AddToCart', $npv->getId())
->request();
/** @var $npv ProductVariant */
$userCountry = $this->countryService->getCountry($this->request, $this->user);
$exploded = explode('/', parse_url($this->request->headers->get('referer'), PHP_URL_PATH));
$isInCart = end($exploded) === 'cart';
if (((empty($npv->getCountry()) && $userCountry && $userCountry->getAlpha2() != 'PL')
|| $userCountry != $npv->getCountry()) && !$isInCart)
{
return [
'status' => false,
'error' => 'wrongCountry',
'message' => $this->translator->trans(
'errors.order.wrongCountry',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
)
];
}
}
}
$portal = $this->portalSettingsService->getPortalSettings();
if ($portal && $portal->getUseFbPixelInIframe() === true)
{
foreach ($newProductVariant as $npv)
{
$this->facebookPixelService
->setEvent('AddToCart', $npv->getId())
->request();
}
}
}
return $newProductVariant;
}
private function findProductPackToAdd()
{
$newProductPack = array();
$productPackId = $this->request->get('productPackId');
if (!empty($productPackId))
{
$arrayProductPackId = explode(',', $productPackId);
$newProductPack = $this->em->getRepository(ProductPack::class)
->findProductPackToAdd($arrayProductPackId);
}
return $newProductPack;
}
private function findCart()
{
$cartHash = $this->getCartHash();
if (!empty($cartHash))
{
$this->cart = $this->em->getRepository(Cart::class)->findOneByHash($cartHash);
}
if (empty($this->cart))
{
$this->cart = $this->cartServices->createCart($this->user instanceof User ? $this->user : false);
}
$this->request->getSession()->set('cartHash', $this->cart->getHash());
}
private function findPortalSettings()
{
$hash = $this->request->getSession()->get('portalSettingsHash');
$this->portalSettings = $this->em->getRepository(PortalSettings::class)->findOneByHash($hash);
}
private function findPaymentMethod()
{
$this->paymentMethod = $this->em->getRepository(PaymentMethod::class)->findOneBySlug('invoice');
}
private function getCartHash()
{
if ($this->user instanceof User && $this->user->getCart())
{
return $this->user->getCart()->getHash();
}
if ($this->request->getSession()->has('cartHash'))
{
return $this->request->getSession()->get('cartHash');
}
return $this->request->cookies->get('cartHash', $this->request->get('cartHash'));
}
/**
* Add coupon
*/
public function addCoupon($couponCode = null)
{
if (!$couponCode)
{
$couponCode = $this->request->request->get('coupon', $this->request->query->get('coupon', false));
}
if ($couponCode)
{
$couponCodes = explode('|', $couponCode);
foreach ($couponCodes as $code)
{
$coupon = $this->couponClass->add($this->cart, $code);
$this->em->refresh($this->cart);
if (isset($coupon['message']))
{
$this->request->getSession()->getFlashBag()->add('warningCart', $coupon['message']);
}
}
}
}
private function createProductCart(ProductVariant $productVariant = null, $productPack = null, $additionalUpselling = false)
{
$productCart = (new ProductCart())
->setPaymentMethod($this->paymentMethod)
->setQuantity(1)
->setCart($this->cart);
if ($additionalUpselling === true) $productCart->setUpsellingType(UpsellingTypes::FORCED);
if ($productVariant)
{
$productCart->setProductVariant($productVariant);
if ($productPack)
{
$productCart->setCycleProductPack($productPack);
}
}
elseif ($productPack)
{
$productCart->setProductPack($productPack);
}
$countClients = $this->request->request->get('countClients', false);
if ($countClients && $countClients > 1)
{
$productCart->setQuantity($countClients);
}
$this->couponClass->assignCouponsToProductCart($productCart);
return $productCart;
}
public function addToCartProductVariant($newProductVariant, $additionalUpselling = false): void
{
$repoPC = $this->em->getRepository(ProductCart::class);
$isGift = $this->request->get('gift', false);
foreach ($newProductVariant as $newPV)
{
/** @var ProductCart $productCart */
$productCart = $repoPC->findCartOnProductVariant($this->cart->getHash(), $newPV->getId());
if ($productCart and $additionalUpselling === true) continue;
/** @var ProductVariant $newPV */
if ($newPV->isSaleDisabled())
{
$this->message = $this->translator->trans(
'errors.order.saleDisabled',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
);
if ($productCart)
{
$this->cart->removeProductCart($productCart);
$this->em->persist($productCart);
$this->em->flush();
}
return;
}
/** @var ProductVariant $newPV */
if ($newPV->isActive())
{
if ($productCart)
{
$quantity = $productCart->getQuantity();
if ($productCart->hasUniqskillsMultiUserCourse()
&& $quantity === $productCart->getProductVariant()->getMaxUsers())
{
$this->status = true;
return;
}
else
$productCart->setQuantity($newPV->getBuyMaxOne() ? 1 : ++$quantity);
}
else
{
if ($this->checkIfProductIsCorrectCountry($newPV))
{
$this->setCountryToCart($newPV);
$productCart = $this->createProductCart($newPV, null, $additionalUpselling);
}
else
{
$this->message = $this->translator->trans(
'errors.order.wrongCountry',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
);
if ($productCart)
{
$this->cart->removeProductCart($productCart);
$this->em->persist($productCart);
$this->em->flush();
}
return;
}
}
if ($isGift)
{
$productCart->setIsGift(true);
}
if ($this->request->request->get('productAssociationId'))
{
$productAssociationId = $this->request->request->get('productAssociationId');
$productAssociation = $this->em->getRepository(ProductAssociation::class)->find($productAssociationId);
if ($productAssociation)
{
$productCart->setProductAssociation($productAssociation);
}
}
if ($this->request->get('source') == 'uniqskills')
{
$productCart->setLifetimeLanding($this->request->get('lifetimeLanding', false));
$courseSlug = $this->request->get('courseSlug');
$course = $this->em->getRepository(Course::class)->findOneBySlug($courseSlug);
if (!is_null($course)) $productCart->setCourse($course);
}
$upsellingType = (int)$this->request->get('upsellingType');
if ($upsellingType && UpsellingTypes::isValidValue($upsellingType))
{
$productCart->setUpsellingType($upsellingType);
}
if (
$this->request->get('parentProductCart')
&&
$parentProductCart = $repoPC->find($this->request->get('parentProductCart'))
)
{
$productCart->setParent($parentProductCart);
$productCart->setQuantity($parentProductCart->getQuantity());
}
$this->em->persist($this->cart);
$this->em->persist($productCart);
$this->em->flush();
$this->em->refresh($this->cart);
$productVariant = $productCart->getProductVariant();
$this->productsForGA[] = array(
'pvId' => $productVariant->getId(),
'productVariantNoComplete' => $productVariant->getProductVariantNoComplete(),
'tradeName' => $productVariant->getTradeName(),
'price' => 0,
'brand' => $productVariant->getMasterProduct()->getProductGroups() ? $productVariant->getMasterProduct()->getProductGroups()->getName() : '',
'category' => $productVariant->getMasterProduct()->getProductType() ? $productVariant->getMasterProduct()->getProductType()->getName() : '',
'quantity' => $productCart->getQuantity(),
'coupon' => $productCart->getCoupon() ? $productCart->getCoupon()->getCode() : null
);
$this->status = true;
}
else
{
$this->message = $this->translator->trans(
'errors.order.notAvailable',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
);
if ($productCart)
{
$this->cart->removeProductCart($productCart);
$this->em->persist($productCart);
$this->em->flush();
}
}
}
}
public function setButtonParameterCookie(Response $response): void
{
if ($this->request && $this->request->request->get('bp'))
{
$bp = $this->request->cookies->get('bp', array());
if (!empty($bp))
{
$bp = json_decode($bp);
}
$bp[] = $this->request->request->get('bp');
$response->headers->setCookie(new Cookie("bp", json_encode(array_unique($bp)), time() + (3600 * 24 * 30)));
}
}
public function addToCartProductPack($newProductPack): void
{
$repoPC = $this->em->getRepository(ProductCart::class);
foreach ($newProductPack as $newPP)
{
/** @var ProductPack $newPP */
/** @var ProductCart $productCart */
$productCart = $repoPC->findCartOnProductPack($this->cart->getHash(), $newPP->getId());
if ($newPP->isActive())
{
if ($productCart)
{
$quantity = $productCart->getQuantity();
$productCart->setQuantity($newPP->getBuyMaxOne() ? 1 : ++$quantity);
}
else
{
if ($this->checkIfPackIsCorrectCountry($newPP))
{
$this->setCountryToCartFromPack($newPP);
if ($this->request->request->get('isCycle'))
{
/** @var ProductPackItem $firstPackItem */
$firstPackItem = $newPP->getProductPackItem()->first();
$firstProductVariant = $firstPackItem->getProductVariant();
$productCart = $repoPC->findCartOnProductVariant($this->cart->getHash(), $firstProductVariant->getId());
if (!$productCart)
{
$productCart = $this->createProductCart($firstProductVariant, $newPP);
}
}
else
{
$productCart = $this->createProductCart(null, $newPP);
}
}
else
{
$this->message = $this->translator->trans(
'errors.order.wrongCountry',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
);
return;
}
}
$this->em->persist($productCart);
$this->em->flush();
$this->em->refresh($this->cart);
$this->facebookPixelService
->setEvent('AddToCart', $newPP->getId(), true)
->request();
foreach ($newPP->getProductPackItem() as $item)
{
$pv = $item->getProductVariant();
$this->productsForGA[] = [
'ppiId' => $item->getId(),
'ppId' => $newPP->getId(),
'pvId' => $pv->getId(),
'productVariantNoComplete' => $pv->getProductVariantNoComplete(),
'tradeName' => $pv->getTradeName(),
'price' => 0,
'brand' => $pv->getMasterProduct()->getProductGroups() ? $pv->getMasterProduct()->getProductGroups()->getName() : '',
'category' => $pv->getMasterProduct()->getProductType() ? $pv->getMasterProduct()->getProductType()->getName() : '',
'quantity' => $productCart->getQuantity() ?? 1,
'coupon' => $productCart->getCoupon() ? $productCart->getCoupon()->getCode() : null
];
}
$this->status = true;
}
else
{
$this->message = $this->translator->trans(
'errors.order.notAvailable',
[],
'messages',
$this->request->getSession()->get('userLocale', 'pl')
);
if ($productCart)
{
$this->cart->removeProductCart($productCart);
$this->em->persist($productCart);
$this->em->flush();
}
}
}
}
private function checkIfPackIsCorrectCountry(ProductPack $pp): bool
{
/** @var ProductPackItem $productPackItem */
$productPackItem = $pp->getProductPackItem()->first();
return $this->checkIfProductIsCorrectCountry($productPackItem->getProductVariant());
}
private function checkIfProductIsCorrectCountry(ProductVariant $pv = null)
{
if ($this->cart->getProductCart()->count() < 1 && $this->cart->getCountry())
{
$this->cart->setCountry(null);
}
if (empty($this->cart->getCountry()) || empty($pv))
{
return true;
}
if ($pv->getCountry())
{
if ($pv->getCountry() === $this->cart->getCountry())
return true;
else
return false;
}
else
{
if ($this->cart->getCountry()->getAlpha2() === 'PL')
return true;
else
return false;
}
}
private function setCountryToCartFromPack(ProductPack $pp): void
{
/** @var ProductPackItem $productPackItem */
$productPackItem = $pp->getProductPackItem()->first();
$this->setCountryToCart($productPackItem->getProductVariant());
}
private function setCountryToCart(ProductVariant $pv = null)
{
if (empty($this->cart->getCountry()))
{
if ($pv && $pv->getCountry())
{
$this->cart->setCountry($pv->getCountry());
}
else
{
$poland = $this->em->getRepository(Country::class)->findOneByAlpha2('PL');
$this->cart->setCountry($poland);
}
}
}
}