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
424602
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();
    }
91712
public function tryAutomaticCoupons(CartInterface $cart)
    {
        if ($cart->getCartLines()->isEmpty()) {
            return;
        }

        $automaticCoupons = $this->getNonAppliedAutomaticCoupons($cart);

        foreach ($automaticCoupons as $coupon) {
            try {
                $this
                    ->cartCouponManager
                    ->addCoupon($cart, $coupon);
            } catch (AbstractCouponException $e) {
                // Silently tries next coupon on controlled exception
            }
        }
    }
112440
public function notifyCouponUsage(CouponInterface $coupon)
    {
        $couponUsedEvent = new CouponOnUsedEvent($coupon);

        $this->eventDispatcher->dispatch(
            ElcodiCouponEvents::COUPON_USED,
            $couponUsedEvent
        );

        return $this;
    }
1349759
public function validateNegativeAmount(CartInterface $cart)
    {
        $amount = $cart->getAmount();

        if ($amount->getAmount() <= 0) {
            $cart
                ->setAmount(Money::create(
                    0,
                    $amount->getCurrency()
                ));
        }
    }
928593
public function canBeApplied(
        CartInterface $cart,
        CouponInterface $coupon
    ) {
        return
            $coupon->getType() === self::id() &&
            1 === preg_match($this->regexp(), $coupon->getValue());
    }
1091412
public function addCouponByCode(
        CartInterface $cart,
        $couponCode
    ) {
        $coupon = $this
            ->couponRepository
            ->findOneBy([
                'code' => $couponCode,
                'enabled' => true,
            ]);

        if (!($coupon instanceof CouponInterface)) {
            throw new CouponNotAvailableException();
        }

        return $this
            ->addCoupon(
                $cart,
                $coupon
            );
    }
418592
public function saveCart(CartInterface $cart)
    {
        if (!$cart->getCartLines()->isEmpty()) {
            $this->cartObjectManager->persist($cart);
        }

        $this
            ->cartObjectManager
            ->flush();
    }
1249088
public function removeCouponByCode(
        CartInterface $cart,
        $couponCode
    ) {
        $coupon = $this
            ->couponRepository
            ->findOneBy([
                'code' => $couponCode,
            ]);

        if (!($coupon instanceof CouponInterface)) {
            return false;
        }

        return $this
            ->removeCoupon(
                $cart,
                $coupon
            );
    }
1275990
public function dispatchCartCouponOnRemoveEvent(
        CartCouponInterface $cartCoupon
    ) {
        $cart = $cartCoupon->getCart();
        $coupon = $cartCoupon->getCoupon();

        $event = new CartCouponOnRemoveEvent($cart, $coupon);
        $event->setCartCoupon($cartCoupon);
        $this->eventDispatcher->dispatch(
            ElcodiCartCouponEvents::CART_COUPON_ONREMOVE,
            $event
        );
    }
581381
public function validateDuplicatedCoupon(CartCouponOnApplyEvent $event)
    {
        $this
            ->duplicatedCouponValidator
            ->validateDuplicatedCoupon(
                $event->getCart(),
                $event->getCoupon()
            );
    }
819783
public function remove(CartId $cartId)
    {
        if (!$this->exists($cartId)) {
            throw CartNotFoundException::byId($cartId);
        }

        unset($this->carts[(string) $cartId]);
    }
1228212
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] : '';

        $totalElements = 0;
        $moneys = [];
        $freePerGroup = $m - $n;
        $freePerGroup = max($freePerGroup, 0);

        foreach ($cart->getCartLines() as $cartLine) {
            $purchasable = $cartLine->getPurchasable();
            $expressionEvaluator = $this->getExpressionLanguageInstance();
            $expressionResult =
                (
                    empty($expressionValue) ||
                    $expressionEvaluator->evaluate($expressionValue, [
                        'purchasable' => $purchasable,
                    ])
                ) &&
                $this->evaluatePurchasableType($purchasable, $modifiers);

            if (true === $expressionResult) {
                $partialElements = $cartLine->getQuantity();
                $totalElements += $partialElements;
                for ($i = 0; $i < $partialElements; ++$i) {
                    $partialPurchasable = $cartLine->getPurchasable();
                    $moneys[] = $partialPurchasable->getReducedPrice()->getAmount() > 0
                        ? $partialPurchasable->getReducedPrice()
                        : $partialPurchasable->getPrice();
                }
            }
        }

        usort($moneys, function (MoneyInterface $a, MoneyInterface $b) {
            $aCurrency = $a->getCurrency();
            $bPriceInACurrency = $this
                ->currencyConverter
                ->convertMoney(
                    $b,
                    $aCurrency
                );

            return $a->isGreaterThan($bPriceInACurrency)
                ? 1
                : -1;
        });
        $groups = floor($totalElements / $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;
    }
62984
public function getCouponAbsoluteValue(
        CartInterface $cart,
        CouponInterface $coupon
    ) {
        $currency = $this
            ->currencyWrapper
            ->get();

        $couponPrice = Money::create(
            0,
            $currency
        );

        foreach ($this->cartCouponApplicators as $cartCouponApplicator) {
            if ($cartCouponApplicator->canBeApplied(
                $cart,
                $coupon
            )) {
                return $cartCouponApplicator->getCouponAbsoluteValue(
                    $cart,
                    $coupon
                );
            }
        }

        return $couponPrice;
    }
147269
public function loadCartShippingAmount(CartInterface $cart)
    {
        $shippingMethodId = $cart->getShippingMethod();

        if (empty($shippingMethodId)) {
            return;
        }

        $shippingMethod = $this
            ->shippingWrapper
            ->getOneById($cart, $shippingMethodId);

        if ($shippingMethod instanceof ShippingMethod) {
            $cart->setShippingAmount(
                $shippingMethod->getPrice()
            );
        }
    }
593781
public function makeUse(CouponOnUsedEvent $event)
    {
        $coupon = $event->getCoupon();
        $coupon->makeUse();

        $this
            ->couponObjectManager
            ->flush($coupon);
    }
1194439
protected function validateIfItemProductActive(ItemInterface $item)
    {
        $product = $item->getProduct();

        if (!$product) {
            throw new ProductNotFoundException('item ' . $item->getId());
        }

        if (!$product->isValidShopProduct($this->defaultCurrency)) {
            throw new ProductNotValidException($product->getId());
        }

        return true;
    }
58587
protected function isValidCart(Cart $cart)
    {
        $customer = $this->getCustomerUser();

        return (null !== $customer && $cart->getCustomerId() == $customer->getId())
            ||
        (null === $customer && $cart->getCustomerId() === null);
    }