/** * Checks if given Coupon is valid. To determine its validity, this service * will evaluate all rules if there are any. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return boolean Coupon is valid */ public function checkCouponValidity(CartInterface $cart, CouponInterface $coupon) { $rules = $coupon->getRules(); return $rules->forAll(function ($_, AbstractRuleInterface $rule) use($cart, $coupon) { return $this->ruleManager->evaluateByRule($rule, ['cart' => $cart, 'coupon' => $coupon]); }); }
/** * Calculate coupon absolute value. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return MoneyInterface|false Absolute value for this coupon in this cart */ public function getCouponAbsoluteValue(CartInterface $cart, CouponInterface $coupon) { $currency = $this->currencyWrapper->get(); $couponPrice = Money::create(0, $currency); $value = $coupon->getValue(); preg_match($this->regexp(), $value, $match); $m = (int) $match[1]; $n = (int) $match[2]; $expressionValue = isset($match[3]) ? $match[3] : ''; $modifiers = isset($match[4]) ? $match[4] : ''; $freePerGroup = $m - $n; $freePerGroup = max($freePerGroup, 0); foreach ($cart->getCartLines() as $cartLine) { $moneys = []; $purchasable = $cartLine->getPurchasable(); $expressionEvaluator = $this->getExpressionLanguageInstance(); $expressionResult = (empty($expressionValue) || $expressionEvaluator->evaluate($expressionValue, ['purchasable' => $purchasable])) && $this->evaluatePurchasableType($purchasable, $modifiers); if (true === $expressionResult) { $partialElements = $cartLine->getQuantity(); for ($i = 0; $i < $partialElements; ++$i) { $partialPurchasable = $cartLine->getPurchasable(); $moneys[] = $partialPurchasable->getReducedPrice()->getAmount() > 0 ? $partialPurchasable->getReducedPrice() : $partialPurchasable->getPrice(); } $groups = $partialElements / $m; if ($groups > 0) { $nbMoneys = $groups * $freePerGroup; $moneysToDiscount = array_slice($moneys, 0, $nbMoneys); foreach ($moneysToDiscount as $moneyToDiscount) { $couponPrice = $couponPrice->add($this->currencyConverter->convertMoney($moneyToDiscount, $currency)); } } } } return $couponPrice; }
/** * Checks if given Coupon is valid. To determine its validity, this service * will evaluate all rules if there are any. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return boolean Coupon is valid */ public function checkCouponValidity(CartInterface $cart, CouponInterface $coupon) { $rule = $coupon->getRule(); if (null === $rule) { return true; } try { return $this->ruleManager->evaluate($rule, ['cart' => $cart, 'coupon' => $coupon]); } catch (\Exception $e) { // Maybe log something in case of exception? } return false; }
/** * Check if cart meets minimum price requirements for a coupon. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @throws CouponBelowMinimumPurchaseException Minimum value not reached */ public function validateCartCouponMinimumPrice(CartInterface $cart, CouponInterface $coupon) { $couponMinimumPrice = $coupon->getMinimumPurchase(); if ($couponMinimumPrice->getAmount() === 0) { return; } $productMoney = $cart->getProductAmount(); if ($couponMinimumPrice->getCurrency() != $productMoney->getCurrency()) { $couponMinimumPrice = $this->currencyConverter->convertMoney($couponMinimumPrice, $productMoney->getCurrency()); } if ($productMoney->isLessThan($couponMinimumPrice)) { throw new CouponBelowMinimumPurchaseException(); } }
/** * Checks if given Coupon is valid. To determine its validity, this service * will evaluate all rules if there are any. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @throws CouponRulesNotValidateException Rules not valid */ public function validateCartCouponRules(CartInterface $cart, CouponInterface $coupon) { $rule = $coupon->getRule(); if (null === $rule) { return; } try { $isValid = $this->ruleManager->evaluate($rule, ['cart' => $cart, 'coupon' => $coupon]); if (!$isValid) { throw new CouponRulesNotValidateException(); } return; } catch (Exception $e) { // Maybe log something in case of exception? } throw new CouponRulesNotValidateException(); }
/** * Check if this coupon can be applied when other coupons had previously * been applied. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @throws CouponNotStackableException Coupon is not stackable */ public function validateStackableCoupon(CartInterface $cart, CouponInterface $coupon) { $cartCoupons = $this->cartCouponRepository->findBy(['cart' => $cart]); /** * If there are no previously applied coupons we can skip the check. */ if (0 == count($cartCoupons)) { return; } $appliedCouponsCanBeStacked = array_reduce($cartCoupons, function ($previousCouponsAreStackable, CartCouponInterface $cartCoupon) { return $previousCouponsAreStackable && $cartCoupon->getCoupon()->getStackable(); }, true); /** * Checked coupon can be stackable and everything that was * previously applied is also stackable. */ if ($coupon->getStackable() && $appliedCouponsCanBeStacked) { return; } throw new CouponNotStackableException(); }
/** * Given a cart and a coupon, returns the real value of the coupon. * If the type of the coupon is not valid, then an empty Money instance will * be returned, with value 0. * * @param CartInterface $cart Abstract Cart object * @param CouponInterface $coupon Coupon * * @return MoneyInterface Coupon price */ public function getCouponAbsolutePrice(CartInterface $cart, CouponInterface $coupon) { $currency = $this->currencyWrapper->get(); $couponPrice = Money::create(0, $currency); switch ($coupon->getType()) { case ElcodiCouponTypes::TYPE_PERCENT: $couponPercent = $coupon->getDiscount(); $couponPrice = $cart->getProductAmount()->multiply($couponPercent / 100); break; case ElcodiCouponTypes::TYPE_AMOUNT: $amount = $coupon->getPrice(); $couponPrice = $this->currencyConverter->convertMoney($amount, $currency); break; } return $couponPrice; }
/** * Check if a coupon can be currently used. * * @param CouponInterface $coupon * * @return bool */ private function canBeUsed(CouponInterface $coupon) { $count = $coupon->getCount(); if ($count === 0) { return true; } if ($coupon->getUsed() < $count) { return true; } return false; }
/** * Check if a coupon has manual enforcement * * @param CouponInterface $coupon Coupon * * @return bool */ protected function isManual(CouponInterface $coupon) { return $coupon->getEnforcement() === ElcodiCouponTypes::ENFORCEMENT_MANUAL; }
/** * Calculate coupon absolute value. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return MoneyInterface|false Absolute value for this coupon in this cart. */ public function getCouponAbsoluteValue(CartInterface $cart, CouponInterface $coupon) { $couponPercent = $coupon->getDiscount(); return $cart->getPurchasableAmount()->multiply($couponPercent / 100); }
/** * Given a cart and a coupon, returns the real value of the coupon * * @param CartInterface $cart Abstract Cart object * @param CouponInterface $coupon Coupon * * @return MoneyInterface Coupon price */ protected function getPriceCoupon(CartInterface $cart, CouponInterface $coupon) { $currency = $this->currencyWrapper->getCurrency(); switch ($coupon->getType()) { case ElcodiCouponTypes::TYPE_AMOUNT: $amount = $coupon->getPrice(); return $this->currencyConverter->convertMoney($amount, $currency); case ElcodiCouponTypes::TYPE_PERCENT: $couponPercent = $coupon->getDiscount(); return $cart->getProductAmount()->multiply($couponPercent / 100); } }
/** * Calculate coupon absolute value. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return MoneyInterface|false Absolute value for this coupon in this cart */ public function getCouponAbsoluteValue(CartInterface $cart, CouponInterface $coupon) { $currency = $this->currencyWrapper->get(); $amount = $coupon->getPrice(); return $this->currencyConverter->convertMoney($amount, $currency); }
/** * Creates a new coupon instance, given an existing Coupon as reference * * You can specify a DateTime new coupon will be valid from. * If not specified, current DateTime will be used * * If given coupon is valid forever, new coupon will also be * Otherwise, this method will add to validFrom, the same interval than given Coupon * * Also can be specified how new Coupon name must be defined. * If none, automatic generator will add to existing name, 10 random digits. * * Given Coupon name: FOO * New Coupon name: FOO_a67b6786a6 * * Coupons are only generated, and are not persisted in Manager not Flushed * * @param CouponInterface $coupon Reference coupon * @param DateTime $dateFrom Date From. If null, takes actual dateTime * * @return CouponInterface Coupon generated */ public function duplicateCoupon(CouponInterface $coupon, DateTime $dateFrom = null) { /** * Creates a valid date interval given the referent Coupon */ if (!$dateFrom instanceof DateTime) { $dateFrom = new DateTime(); } $dateTo = null; if ($coupon->getValidTo() instanceof DateTime) { $interval = $coupon->getValidFrom()->diff($coupon->getValidTo()); $dateTo = clone $dateFrom; $dateTo->add($interval); } /** * @var CouponInterface $couponGenerated */ $couponGenerated = $this->couponFactory->create(); $couponGenerated->setCode($this->couponCodeGenerator->generate())->setName($coupon->getName())->setType($coupon->getType())->setPrice($coupon->getPrice())->setDiscount($coupon->getDiscount())->setCount($coupon->getCount())->setPriority($coupon->getPriority())->setMinimumPurchase($coupon->getMinimumPurchase())->setValidFrom($dateFrom)->setValidTo($dateTo)->setEnabled(true); return $couponGenerated; }
/** * Can be applied. * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @return bool Can be applied */ public function canBeApplied(CartInterface $cart, CouponInterface $coupon) { return $coupon->getType() === self::id() && 1 === preg_match($this->regexp(), $coupon->getValue()); }