src/ECommerceBundle/Service/CartService.php line 175

Open in your IDE?
  1. <?php
  2. namespace App\ECommerceBundle\Service;
  3. use App\ECommerceBundle\Entity\Cart;
  4. use App\ECommerceBundle\Entity\CartHasCookie;
  5. use App\ECommerceBundle\Entity\CartHasProductPrice;
  6. use App\ECommerceBundle\Entity\CartHasUser;
  7. use App\ECommerceBundle\Repository\CartHasProductPriceRepository;
  8. use App\ECommerceBundle\Repository\CartRepository;
  9. use App\NewShippingBundle\Entity\ShippingTime;
  10. use App\NewShippingBundle\Entity\Zone;
  11. use App\NewShippingBundle\Service\AvailableShippingTimesService;
  12. use App\OnlinePaymentBundle\Entity\PaymentMethod;
  13. use App\OnlinePaymentBundle\Enum\PaymentMethodEnum;
  14. use App\ProductBundle\Entity\Product;
  15. use App\ShippingBundle\Entity\ShippingAddress;
  16. use App\UserBundle\Entity\User;
  17. use Doctrine\ORM\EntityManagerInterface;
  18. use PN\ServiceBundle\Service\UserService;
  19. use Symfony\Component\HttpFoundation\Request;
  20. use Symfony\Component\HttpFoundation\RequestStack;
  21. use Symfony\Contracts\Translation\TranslatorInterface;
  22. class CartService
  23. {
  24. const CART_COOKIE_NAME = "cart-cookie";
  25. private ?Cart $cart = null;
  26. private ?Request $request;
  27. public function __construct(
  28. private readonly EntityManagerInterface $em,
  29. RequestStack $requestStack,
  30. private readonly TranslatorInterface $translator,
  31. private readonly UserService $userService,
  32. private readonly CartTotalsService $cartTotalsService,
  33. private readonly CartRepository $cartRepository,
  34. private readonly CartHasProductPriceRepository $cartHasProductPriceRepository,
  35. private readonly AvailableShippingTimesService $availableShippingTimesService
  36. )
  37. {
  38. $this->request = $requestStack->getCurrentRequest();
  39. }
  40. public
  41. function getCart(
  42. User $user = null,
  43. bool $createCartIfNotExist = false,
  44. bool $recalculateTotals = false
  45. ): ?Cart
  46. {
  47. if ($this->cart instanceof Cart and $recalculateTotals === false) {
  48. return $this->cart;
  49. }
  50. $user = $user === null ? $this->userService->getUser() : $user;
  51. if ($user instanceof User) {
  52. $cart = $this->getCartByUser($user, $createCartIfNotExist);
  53. $this->mergeCookieCartWithPersonalCart($cart);
  54. } else {
  55. $cart = $this->getCartFromCookie($createCartIfNotExist);
  56. }
  57. if (!$cart instanceof Cart) {
  58. return null;
  59. }
  60. $this->initCart($cart);
  61. $this->addShippingTimeToCart($cart);
  62. return $this->cart;
  63. }
  64. public function initCart(Cart $cart): void
  65. {
  66. $allCartHasProductPrices = $cart->getCartHasProductPrices();
  67. $cartHasProductPrices = $this->cartHasProductPriceRepository->getCartValidProductPriceByCart($cart);
  68. foreach ($allCartHasProductPrices as $cartHasProductPrice) {
  69. $key = array_search($cartHasProductPrice, $cartHasProductPrices);
  70. if ($key === false) {
  71. $cart->removeCartHasProductPrice($cartHasProductPrice);
  72. }
  73. }
  74. foreach ($cartHasProductPrices as $cartHasProductPrice) {
  75. $cart->addCartHasProductPrice($cartHasProductPrice);
  76. }
  77. $cart->setSubTotal($this->cartTotalsService->getCartSubTotal($cart));
  78. $cart->setShippingFees($this->cartTotalsService->getCartShippingFees($cart));
  79. $cart->setExtraFees($this->cartTotalsService->getCartExtraFees($cart));
  80. $cart->setDiscount($this->cartTotalsService->getCartDiscount($cart));
  81. $cart->setGrandTotal($this->cartTotalsService->getCartGrandTotal($cart));
  82. $this->cart = $cart;
  83. }
  84. public function checkStock(Cart $cart): bool
  85. {
  86. $return = true;
  87. $session = $this->request->getSession();
  88. $cartHasProductPrices = $this->cartHasProductPriceRepository->getCartValidProductPriceByCart($cart);
  89. foreach ($cartHasProductPrices as $cartHasProductPrice) {
  90. if ($cartHasProductPrice->getQty() > $cartHasProductPrice->getProductPrice()->getStock()) {
  91. $message = $this->translator->trans("have_only_product_in_stock_msg", [
  92. "%%stock" => $cartHasProductPrice->getProductPrice()->getStock(),
  93. "%productName%" => $cartHasProductPrice->getProductPrice()->getProduct()->getTitle()
  94. ]);
  95. $session->getFlashBag()->add('error', $message);
  96. $return = false;
  97. }
  98. }
  99. return $return;
  100. }
  101. public function removeCart(?Cart $cart = null): bool
  102. {
  103. if ($cart == null) {
  104. return false;
  105. }
  106. $this->cartRepository->remove($cart);
  107. return true;
  108. }
  109. public function getPaymentMethods(Cart $cart): array
  110. {
  111. if ($cart->getGrandTotal() < 500) {
  112. return $this->em->getRepository(PaymentMethod::class)->findByActiveTypes([
  113. PaymentMethodEnum::CREDIT_CARD->value,
  114. PaymentMethodEnum::CASH_ON_DELIVERY->value,
  115. ]);
  116. }
  117. return $this->em->getRepository(PaymentMethod::class)->findByActive();
  118. }
  119. private function getCartByUser(User $user, bool $createCartIfNotExist = false): ?Cart
  120. {
  121. $cart = ($this->cart instanceof Cart and $this->cart->getUser() === $user) ? $this->cart : null;
  122. if ($cart instanceof Cart) {
  123. return $this->cart;
  124. }
  125. $cart = $this->cartRepository->getCartByUser($user);
  126. if ($cart instanceof Cart) {
  127. return $this->cart = $cart;
  128. } elseif ($createCartIfNotExist === false) {
  129. return null;
  130. }
  131. $cart = new Cart();
  132. $cartHasUser = new CartHasUser();
  133. $cartHasUser->setCart($cart);
  134. $cartHasUser->setUser($user);
  135. $cart->setCartHasUser($cartHasUser);
  136. $this->em->persist($cart);
  137. $this->em->flush();
  138. return $cart;
  139. }
  140. private function getCartFromCookie(bool $createCartIfNotExist = false): ?Cart
  141. {
  142. if ($this->request->cookies->has(self::CART_COOKIE_NAME)) {
  143. $cartCookieHash = $this->request->cookies->get(self::CART_COOKIE_NAME);
  144. } else {
  145. // create a new cart with cookie token
  146. $cartCookieHash = md5(time());
  147. //set Cookie
  148. setcookie(self::CART_COOKIE_NAME, $cartCookieHash, time() + 60 * 60 * 24 * 30, "/", null, false, true);
  149. $this->request->cookies->set(self::CART_COOKIE_NAME, $cartCookieHash);
  150. }
  151. $cart = ($this->cart instanceof Cart and $this->cart->getCookieHash() === $cartCookieHash) ? $this->cart : null;
  152. if (!$cart instanceof Cart) {
  153. $cart = $this->cartRepository->getCartByCookie($cartCookieHash);
  154. if ($cart instanceof Cart) {
  155. return $this->cart = $cart;
  156. }
  157. }
  158. if ($createCartIfNotExist === false) {
  159. return null;
  160. }
  161. $cart = new Cart();
  162. $cartHasCookie = new CartHasCookie();
  163. $cartHasCookie->setCart($cart);
  164. $cartHasCookie->setCookie($cartCookieHash);
  165. $cart->setCartHasCookie($cartHasCookie);
  166. $this->em->persist($cartHasCookie);
  167. $this->em->flush();
  168. return $cart;
  169. }
  170. private function mergeCookieCartWithPersonalCart(Cart $cart = null): void
  171. {
  172. if ($cart == null) {
  173. return;
  174. }
  175. if (!$this->request->cookies->has(self::CART_COOKIE_NAME)) {
  176. return;
  177. }
  178. $cookieCart = $this->getCartFromCookie();
  179. if ($cookieCart == null) {
  180. return;
  181. }
  182. //check if cart has products
  183. $cookieCartHasProductPrices = $this->cartHasProductPriceRepository->getCartValidProductPriceByCart($cookieCart);
  184. if (count($cookieCartHasProductPrices) == 0) {
  185. return;
  186. }
  187. $cartHasProductPrice = new CartHasProductPrice();
  188. foreach ($cookieCartHasProductPrices as $cartHasProductPrice) {
  189. $productPrice = $cartHasProductPrice->getProductPrice();
  190. $personalCartProductPrice = $this->em->getRepository(CartHasProductPrice::class)->findOneBy(['cart' => $cart, 'productPrice' => $productPrice]);
  191. if ($personalCartProductPrice) {
  192. $newQty = $personalCartProductPrice->getQty() + $cartHasProductPrice->getQty();
  193. if ($newQty <= $productPrice->getStock()) {
  194. $personalCartProductPrice->setQty($newQty);
  195. $this->em->persist($personalCartProductPrice);
  196. }
  197. } else {
  198. $cartHasProductPrice->setCart($cart);
  199. $cart->addCartHasProductPrice($cartHasProductPrice);
  200. $this->em->persist($cartHasProductPrice);
  201. }
  202. }
  203. $this->em->flush();
  204. // remove cookie cart
  205. $this->em->remove($cookieCart);
  206. $this->em->flush();
  207. // remove cookie
  208. setcookie(self::CART_COOKIE_NAME, NULL, 0, "/", NULL, FALSE, TRUE);
  209. $this->em->refresh($cart);
  210. }
  211. public function addShippingTimeToCart(Cart $cart, bool $forceUpdate = false): void
  212. {
  213. if (!$cart->getShippingAddress() instanceof ShippingAddress and !$cart->getCartGuestData()?->getZone()) {
  214. return;
  215. }
  216. $isShippingTimeUpdated = false;
  217. foreach ($cart->getCartHasProductPrices() as $cartHasProductPrice) {
  218. if ($cartHasProductPrice->getShippingTime() instanceof ShippingTime and !$forceUpdate) {
  219. continue;
  220. }
  221. $product = $cartHasProductPrice->getProductPrice()->getProduct();
  222. $targetZone = $cart->getShippingAddress()?->getZone() ?? $cart->getCartGuestData()->getZone();
  223. $shippingTimes = $this->getSuitableShippingTimeForProduct(product: $product, targetZone: $targetZone);
  224. if (count($shippingTimes) > 0) {
  225. $cartHasProductPrice->setShippingTime($shippingTimes[0]);
  226. $this->em->persist($cartHasProductPrice);
  227. $isShippingTimeUpdated = true;
  228. }
  229. }
  230. if (!$isShippingTimeUpdated) {
  231. return;
  232. }
  233. $this->em->flush();
  234. }
  235. public function getSuitableShippingTimeForProduct(Product $product, Zone $targetZone): array
  236. {
  237. return $this->availableShippingTimesService->getProductShippingTimes(product: $product, targetZone: $targetZone);
  238. }
  239. }