custom/plugins/PremsIndividualOffer6/src/Storefront/Controller/OfferController.php line 144

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. /**
  3.  * PremSoft
  4.  * Copyright © 2020 Premsoft - Sven Mittreiter
  5.  *
  6.  * @copyright  Copyright (c) 2020, premsoft - Sven Mittreiter (http://www.premsoft.de)
  7.  * @author     Sven Mittreiter <info@premsoft.de>
  8.  */
  9. namespace Prems\Plugin\PremsIndividualOffer6\Storefront\Controller;
  10. use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\Aggregate\OfferItem\OfferItemEntity;
  11. use Prems\Plugin\PremsIndividualOffer6\Core\Offer\NotificationService;
  12. use Prems\Plugin\PremsIndividualOffer6\Core\Offer\PdfService;
  13. use Prems\Plugin\PremsIndividualOffer6\Core\Offer\Storefront\OfferService;
  14. use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\OfferDefinition;
  15. use Prems\Plugin\PremsIndividualOffer6\Core\Entity\Offer\OfferEntity;
  16. use Prems\Plugin\PremsIndividualOffer6\Exception\Offer\OfferNotFoundException;
  17. use Prems\Plugin\PremsIndividualOffer6\Core\Offer\Storefront\ConfigService;
  18. use Prems\Plugin\PremsIndividualOffer6\Storefront\Page\Listing\ListingPageLoader;
  19. use Prems\Plugin\PremsIndividualOffer6\Traits;
  20. use Shopware\Core\Checkout\Cart\Cart;
  21. use Shopware\Core\Checkout\Cart\Exception\CustomerNotLoggedInException;
  22. use Shopware\Core\Checkout\Cart\Exception\LineItemNotFoundException;
  23. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  24. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  25. use Shopware\Core\Checkout\Promotion\Cart\Discount\DiscountLineItem;
  26. use Shopware\Core\Content\Product\Exception\ProductNotFoundException;
  27. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
  28. use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\Metric\CountResult;
  29. use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
  30. use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
  31. use Shopware\Core\Framework\Validation\Exception\ConstraintViolationException;
  32. use Shopware\Core\PlatformRequest;
  33. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextService;
  34. use Shopware\Core\System\SalesChannel\SalesChannel\AbstractContextSwitchRoute;
  35. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  36. use Shopware\Storefront\Controller\StorefrontController;
  37. use Symfony\Component\HttpFoundation\JsonResponse;
  38. use Symfony\Component\HttpFoundation\ParameterBag;
  39. use Symfony\Component\HttpFoundation\Request;
  40. use Symfony\Component\HttpFoundation\RequestStack;
  41. use Symfony\Component\HttpFoundation\Response;
  42. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  43. use Symfony\Component\Routing\Annotation\Route;
  44. use Shopware\Core\Framework\Routing\Annotation\RouteScope;
  45. use Shopware\Storefront\Framework\Cache\Annotation\HttpCache;
  46. /**
  47.  * @RouteScope(scopes={"storefront"})
  48.  */
  49. class OfferController extends StorefrontController
  50. {
  51.     use Traits\DocumentCreateResponseTrait;
  52.     /**
  53.      * @var ListingPageLoader
  54.      */
  55.     private $listingPageLoader;
  56.     /**
  57.      * @var OfferService $offerService
  58.      */
  59.     private $offerService;
  60.     /**
  61.      * @var NotificationService $notificationService
  62.      */
  63.     private $notificationService;
  64.     /**
  65.      * @var ConfigService
  66.      */
  67.     public $configService;
  68.     private PdfService $pdfService;
  69.     /**
  70.      * @var CartService
  71.      */
  72.     private $cartService;
  73.     /**
  74.      * @var AbstractContextSwitchRoute
  75.      */
  76.     private $contextSwitchRoute;
  77.     public function __construct(
  78.         ListingPageLoader $listingPageLoader,
  79.         OfferService $offerService,
  80.         NotificationService $notificationService,
  81.         ConfigService $configService,
  82.         PdfService $pdfService,
  83.         CartService $cartService,
  84.         AbstractContextSwitchRoute $contextSwitchRoute
  85.     ) {
  86.         $this->listingPageLoader  $listingPageLoader;
  87.         $this->offerService $offerService;
  88.         $this->notificationService $notificationService;
  89.         $this->configService $configService;
  90.         $this->pdfService $pdfService;
  91.         $this->cartService $cartService;
  92.         $this->contextSwitchRoute $contextSwitchRoute;
  93.     }
  94.     /**
  95.      * Renders the PDF
  96.      *
  97.      * @param Request $request
  98.      * @param SalesChannelContext $salesChannelContext
  99.      * @return Response
  100.      * @throws \Twig\Error\LoaderError
  101.      * @throws \Twig\Error\RuntimeError
  102.      * @throws \Twig\Error\SyntaxError
  103.      *
  104.      * @HttpCache()
  105.      * @Route("/offer/renderpdf/{offerId}", name="frontend.PremsIndividualOffer.renderpdf", methods={"POST", "GET"}, defaults={"XmlHttpRequest": false})
  106.      */
  107.     public function renderPdf(Request $requestSalesChannelContext $salesChannelContext): Response
  108.     {
  109.         $this->denyAccessUnlessLoggedIn();
  110.         $offerId $request->attributes->get('offerId');
  111.         $pdfFile $this->pdfService->createPdfForOffer($offerId$salesChannelContext);
  112.         $download $request->query->getBoolean('download'false);
  113.         return $this->createResponse($pdfFile->getFileName(), $pdfFile->getFileBlob(), $download$pdfFile->getContentType());
  114.     }
  115.     /**
  116.      * Show all offers of a customer. If not logged in then redirected to login page
  117.      * @Route(
  118.      *     "/account/offer",
  119.      *     name="frontend.PremsIndividualOffer.index",
  120.      *     options={"seo"="false"},
  121.      *     methods={"GET"},
  122.      *     defaults={"XmlHttpRequest"=true}
  123.      * )
  124.      *
  125.      * @param SalesChannelContext $context
  126.      * @param Request $request
  127.      *
  128.      * @return Response
  129.      */
  130.     public function offerOverview(SalesChannelContext $contextRequest $request): Response
  131.     {
  132.         $session $request->getSession();
  133.         $this->denyAccessUnlessLoggedIn();
  134.         $page $this->listingPageLoader->load($request$context);
  135.         $offerSettings $this->configService->getConfig($context);
  136.         $offerStatusAggregations $this->offerService->getOfferStatusAggregations($context->getCustomer(), $context->getContext());
  137.         $openRequestCount $this->getCountForAggregation($offerStatusAggregations'offeredCount');
  138.         $receivedCount $this->getCountForAggregation($offerStatusAggregations'receivedCount');
  139.         $orderedCount $this->getCountForAggregation($offerStatusAggregations'orderedCount');
  140.         $declinedCount $this->getCountForAggregation($offerStatusAggregations'declinedCount');
  141.         $offerId null;
  142.         if ($session->has('PremsIndividualOfferId')) {
  143.             $offerId $session->get('PremsIndividualOfferId');
  144.             $session->remove('PremsIndividualOfferId');
  145.         }
  146.         return $this->renderStorefront('@PremsIndividualOffer6/storefront/page/individual_offer/index.html.twig', [
  147.             'page' => $page,
  148.             'openRequestCount' => $openRequestCount,
  149.             'receivedCount' => $receivedCount,
  150.             'orderedCount' => $orderedCount,
  151.             'declinedCount' => $declinedCount,
  152.             'offerSettings' => $offerSettings,
  153.             'offerId' => $offerId,
  154.             'flashBags' => $session->getFlashBag()->peekAll(),
  155.         ]);
  156.     }
  157.     /**
  158.      * @Route(
  159.      *   "/widgets/account/offer/detail/{id}",
  160.      *   name="frontend.PremsIndividualOffer.ajaxOfferDetail",
  161.      *   options={"seo"="false"},
  162.      *   methods={"GET"},
  163.      *   defaults={"XmlHttpRequest"=true})
  164.      *
  165.      * @param SalesChannelContext $context
  166.      * @param Request $request
  167.      */
  168.     public function ajaxOfferDetail(SalesChannelContext $contextRequest $request): Response
  169.     {
  170.         $this->denyAccessUnlessLoggedIn();
  171.         $offerSettings $this->configService->getConfig($context);
  172.         $offerId '';
  173.         if ($request->attributes->has('id')) {
  174.             $offerId = (string) $request->attributes->get('id');
  175.         }
  176.         if ($offerId === '') {
  177.             throw new MissingRequestParameterException('id');
  178.         }
  179.         $offer $this->offerService->getOfferById($offerId$context->getContext(), $context->getCustomer());
  180.         if (!$offer) {
  181.             throw new OfferNotFoundException("Offer $offerId not found");
  182.         }
  183.         $customerId $context->getCustomer()->getId();
  184.         $items $this->offerService->getItemsFromOffer($offerId$customerId$context);
  185.         return $this->renderStorefront('@PremsIndividualOffer6/storefront/page/individual_offer/offer-detail-list.html.twig',
  186.             [
  187.                 'offerDetails' => $items,
  188.                 'offerId' => $offerId,
  189.                 'offerSettings' => $offerSettings,
  190.                 'offer' => $offer,
  191.             ]);
  192.     }
  193.     /**
  194.      * Cancel the offer mode
  195.      * @Route(
  196.      *     "/individual_offer/cancel_offer_mode",
  197.      *     name="frontend.PremsIndividualOffer.cancelOfferMode",
  198.      *     options={"seo"="false"},
  199.      *     methods={"POST"}
  200.      * )
  201.      *
  202.      * @param SalesChannelContext $context
  203.      * @param Request $request
  204.      *
  205.      * @return Response
  206.      */
  207.     public function cancelOfferMode(SalesChannelContext $contextRequest $request): Response
  208.     {
  209.         $this->offerService->cancelOfferMode($context$request->getSession());
  210.         $this->addFlash('info'$this->trans('prems-individual-offer.status_messages.cancel_offer_mode'));
  211.         return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  212.     }
  213.     /**
  214.      * Cancel the offer mode
  215.      * @Route(
  216.      *     "/individual_offer/send-message",
  217.      *     name="frontend.PremsIndividualOffer.sendMessage",
  218.      *     options={"seo"="false"},
  219.      *     methods={"POST"}
  220.      * )
  221.      *
  222.      * @param SalesChannelContext $context
  223.      * @param Request $request
  224.      *
  225.      * @return Response
  226.      */
  227.     public function sendMessage(SalesChannelContext $contextRequest $request): Response
  228.     {
  229.         $customer $context->getCustomer();
  230.         $message $request->request->get('message''');
  231.         $offerId $request->request->get('offerId');
  232.         $offer $this->offerService->getOfferById($offerId$context->getContext(), $customer);
  233.         if (!empty($customer) && $offer && $message) {
  234.             $bag = new ParameterBag([
  235.                 'message' => $message,
  236.                 'customerSign' => $request->request->get('customerSign'),
  237.             ]);
  238.             $this->notificationService->customerGeneralMessageToAdmin($context$offer$bag);
  239.         } else {
  240.             return new JsonResponse([
  241.                 'status' => 0,
  242.             ]);
  243.         }
  244.         return new JsonResponse([
  245.             'status' => 1,
  246.             'message' => $this->trans('prems-individual-offer.messages.message_send_successfully')
  247.         ]);
  248.     }
  249.     /**
  250.      * Request for an offer
  251.      * @Route(
  252.      *     "/individual_offer/request",
  253.      *     name="frontend.PremsIndividualOffer.request",
  254.      *     methods={"POST","GET"}
  255.      * )
  256.      *
  257.      * @param SalesChannelContext $context
  258.      * @param Request $request
  259.      *
  260.      * @return Response
  261.      */
  262.     public function request(SalesChannelContext $contextRequest $request): Response
  263.     {
  264.         $session $request->getSession();
  265.         $this->denyAccessUnlessLoggedIn();
  266.         $customer $context->getCustomer();
  267.         if ($this->offerService->isOfferRequestAllowed($context)) {
  268.             $customerGroup $context->getCurrentCustomerGroup();
  269.             if (!$customerGroup) {
  270.                 $customerGroup $context->getFallbackCustomerGroup();
  271.             }
  272.             $offerSettings $this->configService->getConfig($context);
  273.             $event $this->offerService->createOfferRequest($customer$customerGroup$context);
  274.             $nested $event->getEventByEntityName(OfferDefinition::ENTITY_NAME);
  275.             if ($nested) {
  276.                 foreach ($nested->getIds() as $id) {
  277.                     $offer $this->offerService->getOfferById($id$context->getContext());
  278.                     $items $this->offerService->getItemsFromOffer($offer->getId(), $customer->getId(), $context);
  279.                     /** @var OfferItemEntity $item */
  280.                     foreach($items as $item) {
  281.                         //dirty hack, since the twig method is not available in the twig renderer here
  282.                         $item->decodedLineItem unserialize(base64_decode($item->getLineItem()), [LineItem::class, DiscountLineItem::class]);
  283.                     }
  284.                     $this->notificationService->customerCreatedOfferRequest($context$offer$items);
  285.                     $session->set('PremsIndividualOfferId'$id);
  286.                 }
  287.             }
  288.             if ($offerSettings->isClearBasketAfterOfferRequest()) {
  289.                 // Empty cart
  290.                 $cart $this->cartService->getCart($context->getToken(), $context);
  291.                 $items $cart->getLineItems();
  292.                 foreach($items as $item) {
  293.                     $this->cartService->remove($cart$item->getId(), $context);
  294.                 }
  295.             }
  296.             $this->addFlash('success'$this->trans('prems-individual-offer.status_messages.offer_request_created', ['%offerNumber%' => $offer->getOfferNumber()]));
  297.             return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  298.         } else {
  299.             $this->addFlash('error'$this->trans('prems-individual-offer.status_messages.not_allowed_to_create_offer_request'));
  300.             return $this->redirectToRoute('frontend.checkout.cart.page');
  301.         }
  302.     }
  303.     /**
  304.      * @Route("/individual_offer/line-item/add",
  305.      *     name="frontend.PremsIndividualOffer.line-item.add",
  306.      *     methods={"POST","GET"},
  307.      *     defaults={"XmlHttpRequest"=true})
  308.      *
  309.      * requires the provided items in the following form
  310.      * 'lineItems' => [
  311.      *     'anyKey' => [
  312.      *         'id' => 'someKey'
  313.      *         'quantity' => 2,
  314.      *         'type' => 'someType'
  315.      *     ],
  316.      *     'randomKey' => [
  317.      *         'id' => 'otherKey'
  318.      *         'quantity' => 2,
  319.      *         'type' => 'otherType'
  320.      *     ]
  321.      * ]
  322.      *
  323.      * @param Cart $cart
  324.      * @param RequestDataBag $requestDataBag
  325.      * @param Request $request
  326.      * @param SalesChannelContext $context
  327.      * @return Response
  328.      */
  329.     public function addLineItems(Cart $cartRequestDataBag $requestDataBagRequest $requestSalesChannelContext $context): Response
  330.     {
  331.         $session $request->getSession();
  332.         // Not allowed for guests
  333.         if (!($context && $context->getCustomer() && !$context->getCustomer()->getGuest())) {
  334.             $this->setPriceRequestDataBeforeLogin($requestDataBag$session);
  335.         }
  336.         $this->denyAccessUnlessLoggedIn();
  337.         $this->removeCartLineItems($cart$context$session);
  338.         /** @var RequestDataBag|null $lineItems */
  339.         $lineItems $requestDataBag->get('lineItems');
  340.         if (!$lineItems && !($lineItems=$this->getPriceRequestDataAfterLogin($session))) {
  341.             throw new MissingRequestParameterException('lineItems');
  342.         }
  343.         $count 0;
  344.         try {
  345.             $items = [];
  346.             /** @var RequestDataBag $lineItemData */
  347.             foreach ($lineItems as $lineItemData) {
  348.                 $lineItem = new LineItem(
  349.                     $lineItemData->getAlnum('id'),
  350.                     $lineItemData->getAlnum('type'),
  351.                     $lineItemData->get('referencedId'),
  352.                     $lineItemData->getInt('quantity'1)
  353.                 );
  354.                 $lineItem->setStackable($lineItemData->getBoolean('stackable'true));
  355.                 $lineItem->setRemovable($lineItemData->getBoolean('removable'true));
  356.                 $count += $lineItem->getQuantity();
  357.                 $items[] = $lineItem;
  358.             }
  359.             $cart $this->offerService->addCartItems($cart$items$context);
  360.             if ($cart->getErrors()->count() <= 0) {
  361.                 // Adding products to the offer
  362.                 $customer $context->getCustomer();
  363.                 if ($this->offerService->isOfferRequestAllowed($context)) {
  364.                     $customerGroup $context->getCurrentCustomerGroup();
  365.                     if (!$customerGroup) {
  366.                         $customerGroup $context->getFallbackCustomerGroup();
  367.                     }
  368.                     $event $this->offerService->createOfferRequest($customer$customerGroup$context);
  369.                     $nested $event->getEventByEntityName(OfferDefinition::ENTITY_NAME);
  370.                     if ($nested) {
  371.                         foreach ($nested->getIds() as $id) {
  372.                             $offer $this->offerService->getOfferById($id$context->getContext());
  373.                             $items $this->offerService->getItemsFromOffer($offer->getId(), $customer->getId(), $context);
  374.                             /** @var OfferItemEntity $item */
  375.                             foreach($items as $item) {
  376.                                 //dirty hack, since the twig method is not available in the twig renderer here
  377.                                 $item->decodedLineItem unserialize(base64_decode($item->getLineItem()), [LineItem::class, DiscountLineItem::class]);
  378.                             }
  379.                             $this->notificationService->customerCreatedOfferRequest($context$offer$items);
  380.                             $session->set('PremsIndividualOfferId'$id);
  381.                         }
  382.                     }
  383.                     /** @var OfferItemEntity $lineItem */
  384.                     foreach ($items as $lineItem) {
  385.                         // Deleting products form the cart after making offer
  386.                         $id $lineItem->getProductId();
  387.                         if (!$cart->has($id)) {
  388.                             throw new LineItemNotFoundException($id);
  389.                         }
  390.                         $cart $this->offerService->removeCartItem($cart$id$context);
  391.                     }
  392.                     $this->restoreCartLineItems($cart$context$session);
  393.                     $this->addFlash('success'$this->trans('prems-individual-offer.status_messages.offer_request_created', ['%offerNumber%' => $offer->getOfferNumber()]));
  394.                     return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  395.                 } else {
  396.                     $this->addFlash('error'$this->trans('prems-individual-offer.status_messages.not_allowed_to_create_offer_request'));
  397.                     return $this->createActionResponse($request);
  398.                 }
  399.             }
  400.         } catch (ProductNotFoundException $exception) {
  401.             $this->addFlash('danger'$this->trans('error.addToCartError'));
  402.         }
  403.         return $this->createActionResponse($request);
  404.     }
  405.     /**
  406.      * Accept an offer and add to basket
  407.      * @Route(
  408.      *     "/individual_offer/order",
  409.      *     name="frontend.PremsIndividualOffer.order",
  410.      *     methods={"GET"}
  411.      * )
  412.      *
  413.      * @param SalesChannelContext $context
  414.      * @param Request $request
  415.      *
  416.      * @return Response
  417.      */
  418.     public function order(SalesChannelContext $contextRequest $request): Response
  419.     {
  420.         $session $request->getSession();
  421.         $this->denyAccessUnlessLoggedIn();
  422.         $offerId '';
  423.         if ($request->query->has('offerId')) {
  424.             $offerId = (string) $request->query->get('offerId');
  425.         }
  426.         $customer $context->getCustomer();
  427.         if (!$offerId) {
  428.             throw new \Exception('No offer id specified');
  429.         }
  430.         /** @var OfferEntity $offer */
  431.         $offer $this->offerService->getOfferById($offerId$context->getContext(), $customer);
  432.         if (!$offer || !$this->offerService->hasAccessToOffer($offer$customer) || !$this->offerService->isOfferOrderable($offer)) {
  433.             $this->addFlash('danger'$this->trans('prems-individual-offer.status_messages.no_access_to_offer'));
  434.             return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  435.         }
  436.         // If offer mode is activated no second offer order is allowed
  437.         if ($this->offerService->getOfferMode($context$session)) {
  438.             $this->addFlash('danger'$this->trans('prems-individual-offer.status_messages.no_double_order_offer_mode_active'));
  439.             return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  440.         }
  441.         if ($offer->getShippingMethodId()) {
  442.             $requestDataBag = new RequestDataBag([SalesChannelContextService::SHIPPING_METHOD_ID => $offer->getShippingMethodId()]);
  443.             try {
  444.                 $this->contextSwitchRoute->switchContext($requestDataBag$context);
  445.             } catch (ConstraintViolationException $exception) {
  446.                 $this->addFlash('error'$this->trans('prems-individual-offer.status_messages.error_creating_offer_cart'));
  447.                 return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  448.             }
  449.         }
  450.         $this->offerService->addOfferToBasket($offer$context$session);
  451.         return $this->redirectToRoute('frontend.checkout.cart.page');
  452.     }
  453.     /**
  454.      * Decline an offer
  455.      * @Route(
  456.      *     "/individual_offer/decline",
  457.      *     name="frontend.PremsIndividualOffer.decline",
  458.      *     methods={"GET"}
  459.      * )
  460.      *
  461.      * @param SalesChannelContext $context
  462.      * @param Request $request
  463.      * @return Response
  464.      */
  465.     public function decline(SalesChannelContext $contextRequest $request): Response
  466.     {
  467.         $session $request->getSession();
  468.         $this->denyAccessUnlessLoggedIn();
  469.         $offerId '';
  470.         if ($request->query->has('offerId')) {
  471.             $offerId = (string) $request->query->get('offerId');
  472.         }
  473.         $customer $context->getCustomer();
  474.         $offer $this->offerService->getOfferById($offerId$context->getContext(), $customer);
  475.         if (!$offerId) {
  476.             throw new \Exception('No offer id specified');
  477.         }
  478.         if (!$offer || !$this->offerService->hasAccessToOffer($offer$customer) || !$this->offerService->isOfferDeclineable($offer)) {
  479.             $this->addFlash('error'$this->trans('prems-individual-offer.status_messages.no_access_to_offer'));
  480.             return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  481.         }
  482.         $this->offerService->declineOffer($offer$context->getContext());
  483.         $this->notificationService->customerDeclinedOffer($context$offer);
  484.         // If current offer is in offer mode (basket) then remove it
  485.         if ($this->offerService->getOfferMode($context$session) == $offerId) {
  486.             $this->offerService->cancelOfferMode($context$session);
  487.         }
  488.         $this->addFlash('success'$this->trans('prems-individual-offer.status_messages.declined_offer_successfully'));
  489.         return $this->redirectToRoute('frontend.PremsIndividualOffer.index');
  490.     }
  491.     /**
  492.      * @param Cart $cart
  493.      * @param SalesChannelContext $context
  494.      * @param SessionInterface $session
  495.      * @return void
  496.      */
  497.     private function removeCartLineItems(Cart $cartSalesChannelContext $contextSessionInterface $session): void
  498.     {
  499.         $session->remove('premsIndividualOffer.LineItems');
  500.         $cartLineItems = [];
  501.         // Remove Line Items from cart before adding new one
  502.         foreach ($cart->getLineItems() as $lItem) {
  503.             $lId $lItem->getId();
  504.             $cartLineItems [$lId] = [
  505.                 'id' => $lItem->getId(),
  506.                 'type' => $lItem->getType(),
  507.                 'referencedId' => $lItem->getReferencedId(),
  508.                 'quantity' => $lItem->getQuantity(),
  509.                 'stackable' => $lItem->isStackable(),
  510.                 'removable' => $lItem->isRemovable(),
  511.             ];
  512.             if (!$cart->has($lId)) {
  513.                 throw new LineItemNotFoundException($lId);
  514.             }
  515.             if ($lItem->isRemovable()) {
  516.                 $this->offerService->removeCartItem($cart$lId$context);
  517.             }
  518.         }
  519.         // Add Line items to session to restore them after offer request
  520.         $session->set('premsIndividualOffer.LineItems'$cartLineItems);
  521.     }
  522.     /**
  523.      * @param Cart $cart
  524.      * @param SalesChannelContext $context
  525.      * @param SessionInterface $session
  526.      * @return void
  527.      */
  528.     private function restoreCartLineItems(Cart $cartSalesChannelContext $contextSessionInterface $session): void
  529.     {
  530.         $lineItemsList $session->get('premsIndividualOffer.LineItems');
  531.         $items = [];
  532.         foreach ($lineItemsList as $item) {
  533.             $lineItem = new LineItem($item['id'], $item['type'], $item['referencedId'], $item['quantity']);
  534.             $lineItem->setStackable($item['stackable']);
  535.             $lineItem->setRemovable($item['removable']);
  536.             $items[] = $lineItem;
  537.         }
  538.         $this->offerService->addCartItems($cart$items$context);
  539.         $session->remove('premsIndividualOffer.LineItems');
  540.     }
  541.     /**
  542.      * @param RequestDataBag $requestDataBag
  543.      * @param SessionInterface $session
  544.      * @return void
  545.      */
  546.     private function setPriceRequestDataBeforeLogin(RequestDataBag $requestDataBagSessionInterface $session): void
  547.     {
  548.         $session->remove('premsIndividualOffer.storedPriceRequestData');
  549.         /** @var RequestDataBag|null $lineItems */
  550.         $lineItems $requestDataBag->get('lineItems');
  551.         if (!$lineItems) {
  552.             throw new MissingRequestParameterException('lineItems');
  553.         }
  554.         $session->set('premsIndividualOffer.storedPriceRequestData'$lineItems);
  555.     }
  556.     /**
  557.      * @param SessionInterface $session
  558.      * @return RequestDataBag
  559.      */
  560.     private function getPriceRequestDataAfterLogin(SessionInterface $session): RequestDataBag
  561.     {
  562.         return $session->get('premsIndividualOffer.storedPriceRequestData');
  563.     }
  564.     /**
  565.      * @throws CustomerNotLoggedInException
  566.      */
  567.     protected function denyAccessUnlessLoggedIn(bool $allowGuest false): void
  568.     {
  569.         /** @var RequestStack $requestStack */
  570.         $requestStack $this->get('request_stack');
  571.         $request $requestStack->getCurrentRequest();
  572.         if (!$request) {
  573.             throw new CustomerNotLoggedInException();
  574.         }
  575.         /** @var SalesChannelContext|null $context */
  576.         $context $request->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT);
  577.         if (
  578.             $context
  579.             && $context->getCustomer()
  580.             && (
  581.                 $allowGuest === true
  582.                 || $context->getCustomer()->getGuest() === false
  583.             )
  584.         ) {
  585.             return;
  586.         }
  587.         throw new CustomerNotLoggedInException();
  588.     }
  589.     /**
  590.      * @param AggregationResultCollection $aggregations
  591.      * @param string $aggregationName
  592.      * @return int
  593.      */
  594.     protected function getCountForAggregation(AggregationResultCollection $aggregationsstring $aggregationName): int
  595.     {
  596.         /** @var CountResult $aggregation */
  597.         $aggregation $aggregations->get($aggregationName);
  598.         return $aggregation->getCount();
  599.     }
  600. }