src/ECommerceBundle/Service/CouponService.php line 37

Open in your IDE?
  1. <?php
  2. namespace App\ECommerceBundle\Service;
  3. use App\ECommerceBundle\Entity\Cart;
  4. use App\ECommerceBundle\Entity\CartHasProductPrice;
  5. use App\ECommerceBundle\Entity\Coupon;
  6. use App\ECommerceBundle\Entity\CouponHasProduct;
  7. use App\ECommerceBundle\Enum\CouponTypeEnum;
  8. use App\ECommerceBundle\Repository\CouponRepository;
  9. use App\ECommerceBundle\Repository\OrderHasCouponRepository;
  10. use App\ProductBundle\Entity\Product;
  11. use App\UserBundle\Entity\User;
  12. use Doctrine\ORM\EntityManagerInterface;
  13. use Symfony\Component\HttpFoundation\RequestStack;
  14. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  15. use Symfony\Contracts\Translation\TranslatorInterface;
  16. class CouponService
  17. {
  18. private EntityManagerInterface $em;
  19. private TranslatorInterface $translator;
  20. private SessionInterface $session;
  21. private CouponRepository $couponRepository;
  22. private OrderHasCouponRepository $orderHasCouponRepository;
  23. public function __construct(
  24. EntityManagerInterface $em,
  25. TranslatorInterface $translator,
  26. RequestStack $requestStack,
  27. CouponRepository $couponRepository,
  28. OrderHasCouponRepository $orderHasCouponRepository
  29. )
  30. {
  31. $this->em = $em;
  32. $this->translator = $translator;
  33. $this->session = $requestStack->getSession();
  34. $this->couponRepository = $couponRepository;
  35. $this->orderHasCouponRepository = $orderHasCouponRepository;
  36. }
  37. public function validateCoupon(Cart $cart, Coupon $coupon = null, bool $returnErrorAsText = false): bool|string
  38. {
  39. $session = $this->session;
  40. if ($coupon == null) {
  41. $coupon = $cart->getCoupon();
  42. }
  43. if (!$coupon->isActive()) {
  44. $message = $this->translator->trans("coupon_not_activated_yet_msg");
  45. if ($returnErrorAsText) {
  46. return $message;
  47. }
  48. $session->getFlashBag()->add('error', $message);
  49. return false;
  50. }
  51. if ($coupon->getStartDate() != null) {
  52. $startDate = $coupon->getStartDate();
  53. $currentDate = new \DateTime();
  54. if ($startDate->format("Y-m-d") > $currentDate->format("Y-m-d")) {
  55. $message = $this->translator->trans("coupon_not_activated_yet_msg");
  56. if ($returnErrorAsText) {
  57. return $message;
  58. }
  59. $session->getFlashBag()->add('error', $message);
  60. return false;
  61. }
  62. }
  63. if ($coupon->getExpiryDate() != null) {
  64. $expiryDate = $coupon->getExpiryDate();
  65. $currentDate = new \DateTime();
  66. if ($expiryDate->format("Y-m-d") < $currentDate->format("Y-m-d")) {
  67. $message = $this->translator->trans("coupon_expired_msg");
  68. if ($returnErrorAsText) {
  69. return $message;
  70. }
  71. $session->getFlashBag()->add('error', $message);
  72. return false;
  73. }
  74. }
  75. if ($coupon->getMinimumPurchaseAmount() != null) {
  76. $subTotal = $cart->getSubTotal();
  77. if ($coupon->getMinimumPurchaseAmount() >= $subTotal) {
  78. $message = $this->translator->trans("coupon_not_valid_min_purchase_amount_msg", [
  79. "%amount%" => number_format($coupon->getMinimumPurchaseAmount()),
  80. "%currency%" => $this->translator->trans("egp_txt"),
  81. ]);
  82. if ($returnErrorAsText) {
  83. return $message;
  84. }
  85. $session->getFlashBag()->add('error', $message);
  86. return false;
  87. }
  88. }
  89. if (!$coupon->isShipping()) {
  90. $relatedProducts = $this->couponRepository->getRelatedProductsBetweenCartAndCoupon($coupon, $cart);
  91. if ($relatedProducts < 1) {
  92. $message = $this->translator->trans("coupon_not_apply_on_cart_msg");
  93. if ($returnErrorAsText) {
  94. return $message;
  95. }
  96. $session->getFlashBag()->add('error', $message);
  97. return false;
  98. }
  99. }
  100. $user = $cart->getUser();
  101. if ($coupon->getLimitUsePerUser() > 0) {
  102. if ($user instanceof User) {
  103. $couponUsedCount = $this->couponRepository->couponUsedCountByUser($coupon, $user);
  104. if ($couponUsedCount >= $coupon->getLimitUsePerUser()) {
  105. $message = $this->translator->trans("coupon_passed_limit_msg");
  106. if ($returnErrorAsText) {
  107. return $message;
  108. }
  109. $session->getFlashBag()->add('error', $message);
  110. return false;
  111. }
  112. } else {
  113. $message = $this->translator->trans("login_before_use_this_coupon_msg");
  114. if ($returnErrorAsText) {
  115. return $message;
  116. }
  117. $session->getFlashBag()->add('error', $message);
  118. return false;
  119. }
  120. }
  121. if ($coupon->isFirstOrderOnly()) {
  122. if ($user instanceof User) {
  123. $numberOfUse = $this->orderHasCouponRepository->numberOfUse($coupon, $user);
  124. if ($numberOfUse > 0) {
  125. $message = $this->translator->trans("coupon_passed_limit_msg");
  126. if ($returnErrorAsText) {
  127. return $message;
  128. }
  129. $session->getFlashBag()->add('error', $message);
  130. return false;
  131. }
  132. } else {
  133. $message = $this->translator->trans("login_before_use_this_coupon_msg");
  134. if ($returnErrorAsText) {
  135. return $message;
  136. }
  137. $session->getFlashBag()->add('error', $message);
  138. return false;
  139. }
  140. }
  141. return true;
  142. }
  143. public function getCouponDiscount(Cart $cart): float
  144. {
  145. $coupon = $cart->getCoupon();
  146. if (!$coupon instanceof Coupon) {
  147. return 0;
  148. }
  149. if ($this->validateCoupon($cart, $coupon, true) !== true) {
  150. $cart->setCoupon(null);
  151. $this->em->persist($cart);
  152. $this->em->flush($cart);
  153. return 0;
  154. }
  155. if ($coupon->isShipping()) {
  156. return $this->getCouponShippingDiscount($cart, $coupon);
  157. }
  158. return $this->getCouponProductDiscount($cart, $coupon);
  159. }
  160. //Done
  161. private function getCouponShippingDiscount(Cart $cart, Coupon $coupon): float
  162. {
  163. $discount = 0;
  164. $shippingFees = $cart->getShippingFees();
  165. if ($coupon->getDiscountType() == CouponTypeEnum::FIXED_AMOUNT) {
  166. if ($coupon->getDiscountValue() > $shippingFees) {
  167. $discount = $shippingFees;
  168. } else {
  169. $discount = $coupon->getDiscountValue();
  170. }
  171. } elseif ($coupon->getDiscountType() == CouponTypeEnum::PERCENTAGE) {
  172. $discountItem = ($shippingFees / 100) * $coupon->getDiscountValue();
  173. $discount += $discountItem;
  174. }
  175. return $discount;
  176. }
  177. public function getCouponProductDiscount(Cart $cart, Coupon $coupon): float
  178. {
  179. $discount = 0;
  180. $totalItemPrice = 0;
  181. $relatedProducts = $this->em->getRepository(Coupon::class)->getRelatedProductsBetweenCartAndCoupon($coupon, $cart, false);
  182. $cartHasProductPrices = $this->em->getRepository(CartHasProductPrice::class)->getCartProductPriceByProductIdAndCartId($cart, $relatedProducts);
  183. foreach ($cartHasProductPrices as $cartHasProductPrice) {
  184. $productPrice = $cartHasProductPrice->getProductPrice();
  185. if ($productPrice->getPromotionalPercentage() > 0 and !$coupon->isAddDiscountAfterProductDiscount()) {
  186. continue;
  187. }
  188. $totalItemPrice += $productPrice->getSellPrice() * $cartHasProductPrice->getQty();
  189. }
  190. if ($coupon->getDiscountType() == CouponTypeEnum::FIXED_AMOUNT) {
  191. if ($coupon->getDiscountValue() > $totalItemPrice) {
  192. $discount = $totalItemPrice;
  193. } else {
  194. $discount = $coupon->getDiscountValue();
  195. }
  196. } elseif ($coupon->getDiscountType() == CouponTypeEnum::PERCENTAGE) {
  197. $discountItem = ($totalItemPrice / 100) * $coupon->getDiscountValue();
  198. $discount = $discountItem;
  199. }
  200. return $discount;
  201. }
  202. //Done
  203. private function isProductMatchWithCoupon(Coupon $coupon, Product $product): bool
  204. {
  205. $checkCouponHasProduct = $this->em->getRepository(CouponHasProduct::class)->findOneBy(array(
  206. 'coupon' => $coupon->getId(),
  207. 'product' => $product->getId(),
  208. ));
  209. return $checkCouponHasProduct instanceof CouponHasProduct;
  210. }
  211. }