/** * If the cart's shipping amount is not defined, then put an empty Money * value * * @param CartInterface $cart Cart */ public function validateEmptyShippingAmount(CartInterface $cart) { $shippingAmount = $cart->getShippingAmount(); if (!$shippingAmount instanceof MoneyInterface) { $cart->setShippingAmount($this->emptyMoneyWrapper->get()); } }
/** * 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; }
/** * When a cart goes below 0 (due to discounts), set the amount to 0. * * @param CartInterface $cart Cart */ public function validateNegativeAmount(CartInterface $cart) { $amount = $cart->getAmount(); if ($amount->getAmount() <= 0) { $cart->setAmount(Money::create(0, $amount->getCurrency())); } }
/** * Flushes all loaded cart and related entities. * * We only persist it if have lines loaded inside, so empty carts will never * be persisted * * @param CartInterface $cart Cart */ public function saveCart(CartInterface $cart) { if (!$cart->getCartLines()->isEmpty()) { $this->cartObjectManager->persist($cart); } $this->cartObjectManager->flush(); }
/** * A new Order has been created. * * This method adds Coupon logic in this transformation * * @param CartInterface $cart Cart * @param OrderInterface $order Order */ public function createOrderCouponsByCartCoupons(CartInterface $cart, OrderInterface $order) { $cartCouponAmount = $cart->getCouponAmount(); if ($cartCouponAmount instanceof MoneyInterface) { $order->setCouponAmount($cartCouponAmount); } /** * @var CouponInterface $coupons */ $coupons = $this->cartCouponManager->getCoupons($cart); if (empty($coupons)) { return; } /** * Before applying Coupons to Order, we should remove old references * if exist. */ $this->orderCouponTruncator->truncateOrderCoupons($order); /** * An event is dispatched for each convertible coupon. */ foreach ($coupons as $coupon) { $this->orderCouponEventDispatcher->dispatchOrderCouponOnApplyEvent($order, $coupon); } }
/** * Set Cart in session * * @param CartInterface $cart Cart * * @return $this Self object */ public function set(CartInterface $cart) { if (!$this->saveInSession) { return $this; } $this->session->set($this->sessionFieldName, $cart->getId()); return $this; }
/** * Cart view * * @param FormView $formView Form view * @param CartInterface $cart Cart * * @return Response Response * * @Route( * path = "", * name = "store_cart_view", * methods = {"GET"} * ) * * @AnnotationEntity( * class = { * "factory" = "elcodi.wrapper.cart", * "method" = "get", * "static" = false, * }, * name = "cart" * ) * @AnnotationForm( * class = "store_cart_form_type_cart", * name = "formView", * entity = "cart", * ) */ public function viewAction(FormView $formView, CartInterface $cart) { $relatedProducts = []; if ($cart->getCartLines()->count()) { $relatedProducts = $this->get('elcodi_store.provider.product_collection')->getRelatedProducts($cart->getCartLines()->first()->getProduct(), 3); } $cartCoupons = $this->get('elcodi.manager.cart_coupon')->getCartCoupons($cart); return $this->renderTemplate('Pages:cart-view.html.twig', ['cart' => $cart, 'cartCoupons' => $cartCoupons, 'form' => $formView, 'related_products' => $relatedProducts]); }
/** * Performs all processes to be performed after the order creation. * * Flushes all loaded order and related entities. * * @param CartInterface $cart Cart */ 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()); } }
/** * Validate cart integrity. * * @param CartInterface $cart Cart */ public function validateCartIntegrity(CartInterface $cart) { /** * Check every CartLine. * * @var CartLineInterface $cartLine */ foreach ($cart->getCartLines() as $cartLine) { $this->validateCartLine($cartLine); } }
/** * 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(); } }
/** * Method subscribed to PreCartLoad event. * * Iterate over all automatic Coupons and check if they apply. * If any applies, it will be added to the Cart * * @param CartInterface $cart Cart */ 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 } } }
/** * Calculates and load how many purchasables has this cart. * * @param CartInterface $cart Cart */ public function loadCartPurchasablesQuantities(CartInterface $cart) { $quantity = 0; /** * Calculate max shipping delay. */ foreach ($cart->getCartLines() as $cartLine) { /** * @var CartLineInterface $cartLine */ $quantity += $cartLine->getQuantity(); } $cart->setQuantity($quantity); }
/** * test createFromCart method * * @group order */ public function testCreateOrderFromCart() { $orderInitialState = $this->getParameter('elcodi.core.cart.order_initial_state'); $this->assertInstanceOf('Elcodi\\Component\\Cart\\Entity\\Interfaces\\OrderInterface', $this->order); $this->assertSame($this->order->getCart(), $this->cart); $this->assertTrue($this->cart->isOrdered()); $this->assertCount(2, $this->order->getOrderLines()); $this->assertInstanceOf('Elcodi\\Component\\Cart\\Entity\\Interfaces\\OrderHistoryInterface', $this->order->getLastOrderHistory()); $this->assertEquals($this->order->getLastOrderHistory()->getState(), $orderInitialState); $orderHistories = $this->order->getOrderHistories(); /** * @var OrderHistoryInterface $orderHistory */ foreach ($orderHistories as $orderHistory) { $this->assertInstanceOf('Elcodi\\Component\\Cart\\Entity\\Interfaces\\OrderHistoryInterface', $orderHistory); $this->assertEquals($orderHistory->getState(), $orderInitialState); } $this->getObjectManager('order')->clear(); $this->assertCount(1, $this->findAll('order')); }
/** * Cart view * * @param FormType $formType Form type * @param CartInterface $cart Cart * * @return array * * @AnnotationEntity( * class = { * "factory" = "elcodi.cart_wrapper", * "method" = "loadCart", * "static" = false, * }, * name = "cart" * ) * @AnnotationForm( * class = "store_cart_form_type_cart", * name = "formView", * entity = "cart", * ) */ public function viewAction(FormType $formType, CartInterface $cart) { $relatedProducts = []; if ($cart->getCartLines()->count()) { $relatedProducts = $this->get('store.product.service.product_collection_provider')->getRelatedProducts($cart->getCartLines()->first()->getProduct(), 3); } /** * Let's sort the cartLines if needed */ $cart->setCartLines($this->get('elcodi.cart_lines_sorter')->sortCartLines($cart->getCartLines())); $cartCoupons = $this->get('elcodi.cart_coupon_manager')->getCartCoupons($cart); $formView = $this->get('form.factory')->create($formType, $cart)->createView(); return $this->render('StoreCartBundle:Cart:view.html.twig', ['cart' => $cart, 'cartcoupon' => $cartCoupons, 'form' => $formView, 'related_products' => $relatedProducts]); }
/** * Get cart coupon objects * * @param CartInterface $cart Cart * * @return Collection Coupons */ public function getCoupons(CartInterface $cart) { /** * If Cart id is null means that this cart has been generated from * the scratch. This also means that cannot have any Coupon associated. * If is this case, we avoid this lookup. */ if ($cart->getId() == null) { return new ArrayCollection(); } $cartCoupons = $this->cartCouponRepository->createQueryBuilder('cc')->select(['c', 'cc'])->innerJoin('cc.coupon', 'c')->where('cc.cart = :cart')->setParameter('cart', $cart)->getQuery()->getResult(); $coupons = array_map(function (CartCouponInterface $cartCoupon) { return $cartCoupon->getCoupon(); }, $cartCoupons); return new ArrayCollection($coupons); }
/** * Add a Purchasable to Cart as a new CartLine * * This method creates a new CartLine and set item quantity * correspondingly. * * If the Purchasable is already in the Cart, it just increments * item quantity by $quantity * * @param CartInterface $cart Cart * @param PurchasableInterface $purchasable Product or Variant to add * @param integer $quantity Number of units to set or increase * * @return $this self Object */ public function addProduct(CartInterface $cart, PurchasableInterface $purchasable, $quantity) { /** * If quantity is not a number or is 0 or less, product is not added * into cart */ if (!is_int($quantity) || $quantity <= 0) { return $this; } foreach ($cart->getCartLines() as $cartLine) { /** * @var CartLineInterface $cartLine */ if ($cartLine->getPurchasable()->getId() == $purchasable->getId()) { /** * Product already in the Cart, increase quantity */ return $this->increaseCartLineQuantity($cartLine, $quantity); } } $cartLine = $this->cartLineFactory->create(); $cartLine->setPurchasable($purchasable)->setQuantity($quantity); $this->addLine($cart, $cartLine); return $this; }
/** * 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; }
/** * This method calculates all quantities given a Cart * * @param CartInterface $cart Cart * * @return CartInterface Cart */ private function calculateCartQuantities(CartInterface $cart) { $quantity = 0; /** * Calculate max shipping delay */ foreach ($cart->getCartLines() as $cartLine) { /** * @var CartLineInterface $cartLine */ $quantity += $cartLine->getQuantity(); } $cart->setQuantity($quantity); return $cart; }
/** * Purchasable related view * * @param CartInterface $cart Cart * * @return array * * @Route( * path = "/related", * name = "store_cart_related", * methods = {"GET"} * ) * * @AnnotationEntity( * class = { * "factory" = "elcodi.wrapper.cart", * "method" = "get", * "static" = false, * }, * name = "cart" * ) */ public function relatedAction(CartInterface $cart) { $purchasables = []; $cartLines = $cart->getCartLines(); /** * @var CartLineInterface $cartLine */ foreach ($cartLines as $cartLine) { $purchasables[] = $cartLine->getPurchasable(); } $relatedPurchasables = $this->get('elcodi.related_purchasables_provider')->getRelatedPurchasablesFromArray($purchasables, 3); return $this->renderTemplate('Modules:_purchasable-related.html.twig', ['purchasables' => $relatedPurchasables]); }
/** * Remove a Purchasable from Cart. * * This method removes a Purchasable from the Cart. * * If the Purchasable is already in the Cart, it just decreases * item quantity by $quantity * * @param CartInterface $cart Cart * @param PurchasableInterface $purchasable Product or Variant to add * @param int $quantity Number of units to set or increase * * @return $this Self object */ public function removePurchasable(CartInterface $cart, PurchasableInterface $purchasable, $quantity) { /** * If quantity is not a number or is 0 or less, product is not removed * from cart. */ if (!is_int($quantity) || $quantity <= 0) { return $this; } foreach ($cart->getCartLines() as $cartLine) { /** * @var CartLineInterface $cartLine */ if (get_class($cartLine->getPurchasable()) === get_class($purchasable) && $cartLine->getPurchasable()->getId() == $purchasable->getId()) { /** * Product already in the Cart, decrease quantity. */ return $this->decreaseCartLineQuantity($cartLine, $quantity); } } return $this; }
/** * Checkout payment step * * @param CartInterface $cart Cart * * @return Response Response * * @Route( * path = "/payment", * name = "store_checkout_payment", * methods = {"GET"} * ) * @EntityAnnotation( * class = { * "factory" = "elcodi.wrapper.cart", * "method" = "get", * "static" = false * }, * name = "cart" * ) */ public function paymentAction(CartInterface $cart) { /** * If some address is missing in loaded cart, then we should go back to * address screen */ if (!$cart->getDeliveryAddress() instanceof AddressInterface || !$cart->getBillingAddress() instanceof AddressInterface) { return $this->redirect($this->generateUrl('store_checkout_address')); } /** * Available payment methods */ $paymentMethods = $this->get('elcodi.wrapper.payment_methods')->get($cart); /** * Available shipping methods */ $shippingMethods = $this->get('elcodi.wrapper.shipping_methods')->get($cart); /** * By default, if the cart has not shipping data and we have available * some of them, we assign the first one. * Then we reload page to recalculate cart values */ if ($cart->getShippingMethod() == null && !empty($shippingMethods)) { $shippingMethodApplied = reset($shippingMethods); $cart->setShippingMethod($shippingMethodApplied->getId()); $this->get('elcodi.object_manager.cart')->flush($cart); return $this->redirect($this->generateUrl('store_checkout_payment')); } $cartCoupons = $this->get('elcodi.manager.cart_coupon')->getCartCoupons($cart); return $this->renderTemplate('Pages:checkout-payment.html.twig', ['shippingMethods' => $shippingMethods, 'paymentMethods' => $paymentMethods, 'cart' => $cart, 'cartCoupons' => $cartCoupons]); }
/** * 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) { $couponPercent = $coupon->getDiscount(); return $cart->getPurchasableAmount()->multiply($couponPercent / 100); }
/** * Common asserts for a test that empties lines. * * @param CartLineInterface $line The CartLineInterface needed */ private function assertRemovedLine(CartLineInterface $line) { $this->assertEmpty($this->cart->getCartLines()); $this->assertNotNull($this->cart->getId()); $this->assertEquals(UnitOfWork::STATE_NEW, $this->get('elcodi.object_manager.cart_line')->getUnitOfWork()->getEntityState($line)); }
/** * Get cart coupon objects. * * @param CartInterface $cart Cart * * @return CouponInterface[] Coupons */ public function getCoupons(CartInterface $cart) { /** * If Cart id is null means that this cart has been generated from * scratch. This also means that it cannot have any Coupon associated. * If is this case, we avoid this lookup. */ if ($cart->getId() === null) { return []; } return $this->cartCouponRepository->findCouponsByCart($cart); }
/** * Given ShippingRange zones are satisfied by a cart, * * @param CartInterface $cart Cart * @param ShippingRangeInterface $shippingRange Carrier Range * * @return boolean ShippingRange is satisfied by cart */ private function isShippingRangeZonesSatisfiedByCart(CartInterface $cart, ShippingRangeInterface $shippingRange) { $deliveryAddress = $cart->getDeliveryAddress(); $shippingRange->getToZone()->getName(); return $deliveryAddress === null || $this->zoneMatcher->isAddressContainedInZone($deliveryAddress, $shippingRange->getToZone()); }
/** * Check if cart meets basic requirements for a coupon * * @param CartInterface $cart Cart * @param CouponInterface $coupon Coupon * * @throws CouponIncompatibleException Coupon incompatible */ public function validateCoupon(CartInterface $cart, CouponInterface $coupon) { if ($cart->getTotalItemNumber() === 0) { throw new CouponIncompatibleException(); } $this->couponManager->checkCoupon($coupon); }
/** * Load cart total price. * * @param CartInterface $cart Cart */ public function loadCartTotalAmount(CartInterface $cart) { $currency = $this->currencyWrapper->get(); $finalAmount = clone $cart->getPurchasableAmount(); /** * Calculates the shipping amount. */ $shippingAmount = $cart->getShippingAmount(); if ($shippingAmount instanceof MoneyInterface) { $convertedShippingAmount = $this->currencyConverter->convertMoney($shippingAmount, $currency); $finalAmount = $finalAmount->add($convertedShippingAmount); } /** * Calculates the coupon amount. */ $couponAmount = $cart->getCouponAmount(); if ($couponAmount instanceof MoneyInterface) { $convertedCouponAmount = $this->currencyConverter->convertMoney($couponAmount, $currency); $finalAmount = $finalAmount->subtract($convertedCouponAmount); } $cart->setAmount($finalAmount); }