<?php 
 
namespace Slivki\Controller; 
 
use Doctrine\DBAL\Connection; 
use Doctrine\Persistence\ManagerRegistry; 
use libphonenumber\PhoneNumberUtil; 
use Slivki\BusinessFeature\VirtualWallet\Service\VirtualWalletChecker; 
use Slivki\Dao\FastDelivery\OfferFastDeliveryDaoInterface; 
use Slivki\Dao\Offer\DeliveryZoneDaoInterface; 
use Slivki\Dao\Order\OfferOrderPurchaseCountDaoInterface; 
use Slivki\Entity\City; 
use Slivki\Entity\Director; 
use Slivki\Entity\EntityOption; 
use Slivki\Entity\FoodOfferExtension; 
use Slivki\Entity\FoodOfferOptionExtension; 
use Slivki\Entity\FoodOrder; 
use Slivki\Entity\GeoLocation; 
use Slivki\Entity\Media\OfferExtensionMedia; 
use Slivki\Entity\Offer; 
use Slivki\Entity\OfferExtension; 
use Slivki\Entity\OfferExtensionOnlineCategory; 
use Slivki\Entity\OfferExtensionVariant; 
use Slivki\Entity\OfferOrder; 
use Slivki\Entity\OfferOrderDetails; 
use Slivki\Entity\OnlineOrderHistory; 
use Slivki\Entity\PriceDeliveryType; 
use Slivki\Entity\Seo; 
use Slivki\Entity\Street; 
use Slivki\Entity\UserAddress; 
use Slivki\Entity\UserBalanceActivity; 
use Slivki\Entity\Visit; 
use Slivki\Enum\OfferCode\PurchaseCountPeriod; 
use Slivki\Enum\Order\PaymentType; 
use Slivki\Exception\Offer\OfferExtension\Visibility\OfferExtensionNotVisibleException; 
use Slivki\Exception\Order\InsufficientBalanceFundsException; 
use Slivki\Handler\Order\OnlineOrderHistoryHandler; 
use Slivki\Helpers\PhoneNumberHelper; 
use Slivki\Helpers\WeightParserHelper; 
use Slivki\Repository\Delivery\FoodFilterCounterRepositoryInterface; 
use Slivki\Repository\Director\DirectorRepositoryInterface; 
use Slivki\Repository\Offer\DeliveryZoneRepositoryInterface; 
use Slivki\Repository\Offer\FoodOfferExtensionRepositoryInterface; 
use Slivki\Repository\PurchaseCount\PurchaseCountRepositoryInterface; 
use Slivki\Repository\SeoRepository; 
use Slivki\Repository\StreetRepository; 
use Slivki\Repository\User\CreditCardRepositoryInterface; 
use Slivki\Services\ImageService; 
use Slivki\Services\Mailer; 
use Slivki\Services\MapProviders\CoordinatesYandex; 
use Slivki\Services\Offer\CustomProductOfferSorter; 
use Slivki\Services\Offer\DeliveryZoneSorter; 
use Slivki\Services\Offer\OfferCacheService; 
use Slivki\Services\Offer\ProductFastDeliveryService; 
use Slivki\Services\OfferExtension\FoodByOnlineCategoriesBuilder; 
use Slivki\Services\OfferExtension\VisibilityFilterService; 
use Slivki\Services\Order\PricePromocodeForOnlineOrder; 
use Slivki\Services\PartnerBePaidService; 
use Slivki\Services\Payment\PaymentService; 
use Slivki\Services\Seo\SeoResourceService; 
use Slivki\Services\ShippingSchedulerService; 
use Slivki\Services\Subscription\SubscriptionService; 
use Slivki\Util\CommonUtil; 
use Slivki\Util\Iiko\AbstractDelivery; 
use Slivki\Util\Iiko\Dominos; 
use Slivki\Util\Iiko\IikoUtil; 
use Slivki\Util\Iiko\SushiChefArts; 
use Slivki\Util\Iiko\SushiHouse; 
use Slivki\Util\Iiko\SushiVesla; 
use Slivki\Util\Logger; 
use Symfony\Component\DependencyInjection\ContainerInterface; 
use Symfony\Component\HttpFoundation\JsonResponse; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Routing\Annotation\Route; 
 
use function array_search; 
use function array_unshift; 
use function array_column; 
use function array_map; 
use function array_filter; 
use function in_array; 
use function is_subclass_of; 
use function count; 
use function array_key_exists; 
use function array_merge; 
 
class IikoOrderController extends SiteController 
{ 
    private const KILOGRAM = 1000; 
    public const NEARLY = 'Ближайшее'; 
 
    /** @Route("/delivery/select/{offerID}", name = "deliveryOrder") */ 
    public function indexAction( 
        Request $request, 
        ContainerInterface $container, 
        FoodFilterCounterRepositoryInterface $foodFilterCounterRepository, 
        SeoResourceService $seoResourceService, 
        SubscriptionService $subscriptionService, 
        PurchaseCountRepositoryInterface $purchaseCountRepository, 
        OfferCacheService $offerCacheService, 
        DirectorRepositoryInterface $directorRepository, 
        OfferFastDeliveryDaoInterface $offerFastDeliveryDao, 
        $offerID 
    ) { 
        $response = new Response(); 
 
        $entityManager = $this->getDoctrine()->getManager(); 
 
        /** @var Offer|false $offerCached */ 
        $offerCached = $offerCacheService->getOffer($offerID, true, true); 
 
        if (false === $offerCached 
            || !$offerCached->hasFreeCodes() 
            || !($offerCached->isFoodOnlineOrderAllowedOnSite() || $offerCached->isAvailableOnFood())) { 
            return $this->redirect($seoResourceService->getOfferSeo($offerID)->getMainAlias()); 
        } 
 
        $orderUtil = AbstractDelivery::instance($offerCached); 
        $orderUtil->setContainer($container); 
 
        $isDominos = $orderUtil instanceof Dominos; 
        $isSushiHouse = $orderUtil instanceof SushiHouse; 
 
        $data['isDominos'] = $isDominos; 
        $data['showSortingIndexOrder'] = !($isSushiHouse || $isDominos); 
 
        $cityID = $entityManager->getRepository(Offer::class)->getCityID($offerID); 
        $city = $entityManager->find(City::class, $cityID); 
        $request->getSession()->set(City::CITY_ID_SESSION_KEY, $city->getID()); 
        $request->getSession()->set(City::CITY_DOMAIN_SESSION_KEY, $city->getDomain()); 
 
        $data['offer'] = $offerCached; 
        Logger::instance('IIKO-DEBUG')->info($offerID); 
 
        $director = $directorRepository->getById((int) $offerCached->getDirectorID()); 
 
        $data['company'] = $director; 
 
        $data['domain'] = $orderUtil->getDomain(); 
        if (null !== $offerCached->getOnlineOrderSettings() && $offerCached->getOnlineOrderSettings()->getDomain()) { 
            $data['domain'] = $offerCached->getOnlineOrderSettings()->getDomain(); 
        } 
 
        $data['dishes'] = []; 
 
        $user = $this->getUser(); 
        if (null !== $user) { 
            if ($subscriptionService->isSubscriber($user)) { 
                $data['allowedCodesToBuy'] = $subscriptionService->getSubscription($user)->getNumberOfCodes(); 
            } elseif ($user->isBatchCodesAllowed()) { 
                $data['allowedCodesToBuyBatchCodes'] = $user->getBatchCodesCount(); 
            } 
        } 
 
        $codeCost = $this->getOfferRepository()->getCodeCost($offerCached); 
 
        $data['options'] = []; 
        $data['robotsMeta'] = 'noindex, follow'; 
        $data['offerID'] = $offerID; 
        $data['director'] = $director; 
        $data['minSumForFreeDelivery'] = $orderUtil->getMinSumForFreeDelivery(); 
        $data['minOrderSum'] = $orderUtil->getMinOrderSum(); 
        $data['foodOffer'] = true; 
        $data['formAction'] = '/delivery/order/checkout'; 
        $data['showDelivery'] = true; 
        $data['categoryName'] = $orderUtil::CATEGORY_NAME; 
        $data['footerOfferConditionID'] = $offerID; 
        $data['categoryURL'] = $entityManager->getRepository(Seo::class)->getSeoForEntity(SeoRepository::RESOURCE_URL_OFFER_CATEGORY, $orderUtil::CATEGORY_ID)->getMainAlias(); 
        $data['deliveryPrice'] = $orderUtil->getDeliveryPriceSettings(); 
 
        $data['pickupEnabled'] = $orderUtil->isPickupEnabled(); 
        $data['deliveryEnabled'] = $orderUtil->isDeliveryEnabled(); 
        $data['isBuyCodeDisable'] = $offerCached->isBuyCodeDisable(); 
        $data['isOnlineOrderAllowed'] = $offerCached->isFoodOnlineOrderAllowedOnSite(); 
        $data['isAvailableOnFood'] = $offerCached->isAvailableOnFood(); 
 
        $data['visitCount'] = $entityManager->getRepository(Visit::class)->getVisitCount($orderUtil::OFFER_ID, Visit::TYPE_OFFER, 30, true); 
        $data['filterAction'] = $foodFilterCounterRepository->findByOfferId((int) $offerID); 
 
        $purchaseCount = $purchaseCountRepository->findByOfferId((int) $offerID); 
        $data['purchaseCountMonth'] = null === $purchaseCount ? 0 : $purchaseCount->getPurchaseCountLastMonthWithCorrection(); 
 
        $data['sortList'] = CustomProductOfferSorter::SORT_LIST; 
        $data['codeCost'] = $codeCost; 
        if (!$offerFastDeliveryDao->isOfferHasActiveFastDelivery($offerID)) { 
            unset($data['sortList'][CustomProductOfferSorter::FAST_CUSTOM_PRODUCT_SORT]); 
        } 
 
        $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/order.html.twig' : 'Slivki/delivery/order.html.twig'; 
        $response->setContent($this->renderView($view, $data)); 
 
        return $response; 
    } 
 
    /** @Route("/delivery/order/checkout", name = "deliveryOrderCheckout") */ 
    public function checkoutAction( 
        Request $request, 
        ShippingSchedulerService $shippingSchedulerService, 
        ContainerInterface $container, 
        ManagerRegistry $registry, 
        SeoResourceService $seoResourceService, 
        SubscriptionService $subscriptionService, 
        DeliveryZoneDaoInterface $deliveryZoneDao, 
        DeliveryZoneSorter $deliveryZoneSorter, 
        PricePromocodeForOnlineOrder $pricePromocodeForOnlineOrder 
    ) { 
        ini_set('memory_limit', '1g'); 
        $additionalDominos = null; 
        $response = new Response(); 
 
        $offerID = $request->request->getInt('offerID'); 
        $entityManager = $this->getDoctrine()->getManager(); 
        $requestBasket = $request->request->get('basket'); 
        $pickupDeliveryType = empty($request->request->get('pickupDeliveryType')) ? FoodOfferExtension::DELIVERY_METHOD : $request->request->getInt('pickupDeliveryType'); 
        if (!$requestBasket) { 
            return $this->redirectToRoute('deliveryOrder', ['offerID' => $offerID]); 
        } 
        $request->getSession()->set(OnlineOrderHistory::SORT_SESSION_NAME, $request->request->get('dishSortBy')); 
 
        /** @var Offer $offer */ 
        $offer = $entityManager->find(Offer::class, $offerID); 
 
 
        $slivkiDeliveryOption = $entityManager->getRepository(EntityOption::class)->findBy([ 
            'entityID' => $offerID, 
            'name' => EntityOption::OPTION_SLIVKI_DELIVERY 
        ]); 
 
        if (!$offer->hasFreeCodes()) { 
            return $this->redirect($seoResourceService->getOfferSeo($offerID)->getMainAlias()); 
        } 
 
        $iikoUtil = AbstractDelivery::instance($offer); 
        $iikoUtil->setContainer($container); 
        $isSushiVesla = $iikoUtil instanceof SushiVesla; 
        $isDominos = $iikoUtil instanceof Dominos; 
        if ($isDominos) { 
            $dominosSpesialData = [ 
                'amountPizza' => 0, 
            ]; 
        } 
 
        $requestBasket = json_decode($requestBasket, true); 
        $basket = []; 
        foreach ($requestBasket as $basketItem) { 
            $key = array_key_first($basketItem); 
            $variants = []; 
            if (is_array($basketItem[$key])) { 
                foreach ($basketItem[$key] as $variantItem) { 
                    $variantKey = array_key_first($variantItem); 
                    $variants[$variantKey] = $variantItem[$variantKey]; 
                } 
            } else { 
                $variants = $basketItem[$key]; 
            } 
            $basket[$key] = $variants; 
        } 
 
        $totalDishCount = 0; 
        foreach ($basket as $dishID => $variants) { 
            $extension = $entityManager->find(OfferExtension::class, $dishID); 
            if (!$extension || $extension instanceof FoodOfferOptionExtension) { 
                continue; 
            } 
            $dishCount = 0; 
            if (!is_array($variants)) { 
                $dishCount = $variants; 
            } else { 
                foreach ($variants as $variantID => $variantCount) { 
                    $extensionVariant = $entityManager->find(OfferExtensionVariant::class, $variantID); 
                    if (!$extensionVariant) { 
                        continue; 
                    } 
 
                    $dishCount += $variantCount; 
                     
                    if ($isDominos) { 
                        $dominosSpesialData['amountPizza'] += $variantCount; 
                    } 
                } 
            } 
            $totalDishCount += $dishCount; 
        } 
         
        if ($isDominos && $dominosSpesialData['amountPizza'] === 0) { 
            return new JsonResponse(['status' => 'error', 'error' => true, 'message' => 'Скидка на доп. меню действует только при заказе пиццы']); 
        } 
 
        if ($totalDishCount == 0) { 
            return $this->redirectToRoute('deliveryOrder', ['offerID' => $offerID]); 
        } 
 
        $user = $this->getUser(); 
 
        /** @var OfferOrder $order */ 
        $order = new FoodOrder(); 
        $order->setUser($user); 
        $order->setStatus(FoodOrder::STATUS_INIT); 
        $order->setOffer($offer); 
 
        $totalAmount = 0; 
        $totalOfferAmount = 0; 
        $codesCount = 0; 
        $city = $entityManager->find(City::class, $iikoUtil::CITY_ID); 
        $request->getSession()->set(City::CITY_ID_SESSION_KEY, $city->getID()); 
        $request->getSession()->set(City::CITY_DOMAIN_SESSION_KEY, $city->getDomain()); 
 
        $offersDetails = []; 
 
        foreach ($basket as $dishID => $variants) { 
            /** @var OfferExtension $extension */ 
            $extension = $entityManager->find(OfferExtension::class, $dishID); 
            if (!$extension) { 
                continue; 
            } 
            if (is_array($variants)) { 
                foreach ($variants as $variantID => $variantCount) { 
                    /** @var OfferExtensionVariant $extensionVariant */ 
                    $extensionVariant = $entityManager->find(OfferExtensionVariant::class, $variantID); 
                    if (!$extensionVariant) { 
                        continue; 
                    } 
                    $productsPerCode = $extension->getProductsPerCode(); 
                    if ($productsPerCode > 0) { 
                        $codesCount += $productsPerCode == 1 ? $variantCount : $variantCount/$productsPerCode; 
                    } 
 
                    $variantOfferPrice = PriceDeliveryType::calcDeliveryPickupPrice( 
                        $extension, 
                        $pickupDeliveryType, 
                        $extensionVariant->getRegularPrice(), 
                        $extensionVariant->getOfferPrice(), 
                        $additionalDominos 
                    ); 
 
                    $totalOfferAmount += $variantCount * $variantOfferPrice; 
                    $totalAmount += $variantCount * $extensionVariant->getRegularPrice(); 
 
                    $details = new OfferOrderDetails(); 
                    $details->setOfferExtension($extension); 
                    $details->setOfferExtensionVariant($extensionVariant); 
                    $details->setItemsCount($variantCount); 
                    $order->addOfferOrderDetails($details); 
                } 
            } else { 
                $count = (int) $variants; 
                if (0 === $count) { 
                    continue; 
                } 
 
                $product = $isSushiVesla 
                    ? $iikoUtil->getProductByDB($extension->getPartnerItemID(), $registry) 
                    : $iikoUtil->getProduct($extension->getPartnerItemID()); 
 
                if ($product->regularPrice == 0) { 
                    $product->regularPrice = $extension->getPrice(); 
                } 
 
                $totalAmount += $count * $product->regularPrice; 
 
                $recalculatedOfferPriceValue = PriceDeliveryType::calcDeliveryPickupPrice( 
                    $extension, 
                    $pickupDeliveryType, 
                    $product->regularPrice, 
                    $extension->getCurrentPrice(null, $pickupDeliveryType), 
                ); 
                $product->offerPrice = $recalculatedOfferPriceValue; 
 
                $totalOfferAmount += $count * $product->offerPrice; 
 
                if (!$extension instanceof FoodOfferOptionExtension) { 
                    $productsPerCode = $extension->getProductsPerCode(); 
                    if ($productsPerCode > 0) { 
                        $codesCount += $productsPerCode == 1 ? $count : $count/$productsPerCode; 
                    } 
                } 
                $details = new OfferOrderDetails(); 
                $details->setOfferExtension($extension); 
                $details->setItemsCount($count); 
                $order->addOfferOrderDetails($details); 
            } 
        } 
 
        $codesCount = \ceil($codesCount); 
        $totalAmountWithoutCode = $totalOfferAmount; 
        $codeCost = $pricePromocodeForOnlineOrder->getPrice($order, $offer, $codesCount, $totalAmountWithoutCode); 
        $codeCostRegular = $codeCost; 
 
        $user = $order->getUser(); 
        $allowedCodesToBuyBalance = false; 
        if ($subscriptionService->isSubscriber($user) || $user->isBatchCodesAllowed()) { 
            $codeCost = 0; 
        } elseif ($user->isBalanceAllowed($codesCount * $codeCost)) { 
            $codeCost = 0; 
            $allowedCodesToBuyBalance = true; 
        } 
 
        $totalOfferAmount += $codesCount * $codeCost; 
        $order->setCodesCount($codesCount); 
        $order->setCodeCost($codeCostRegular); 
        $deliveryPrice = $iikoUtil->getMinSumForFreeDelivery() > 0 && $totalAmountWithoutCode < $iikoUtil->getMinSumForFreeDelivery() ? $iikoUtil->getDeliveryPriceSettings() : 0; 
 
        // Delivery price will be calculated after choosing the address 
        if (null !== $offer->getOfferDeliveryZone() && $offer->getOfferDeliveryZone()->count() > 0) { 
            $deliveryPrice = 0; 
        } 
 
        if ($pickupDeliveryType === FoodOfferExtension::DELIVERY_METHOD_PICKUP) { 
            $deliveryPrice = 0; 
        } 
 
        $order->setAmount($totalOfferAmount + $deliveryPrice); 
        $order->setDeliveryCost($deliveryPrice); 
        if (CommonUtil::isMobileDevice($request)) { 
            $order->setDeviceType(SiteController::DEVICE_TYPE_MOBILE); 
        } else { 
            $order->setDeviceType(SiteController::DEVICE_TYPE_DESKTOP); 
        } 
        $entityManager->persist($order); 
        $entityManager->flush(); 
        $entityManager->detach($order); 
 
        $deliveryAddresses = $user->getAvailableUserAddresses($offerID); 
        $defaultDeliveryAddress = empty($deliveryAddresses) ? false : $deliveryAddresses[0]; 
 
        $deliveryAddressesGift = $user->getAvailableUserAddressesGift($offerID); 
        if ($order->isOnlineGift()) { 
            $defaultDeliveryAddress = $deliveryAddressesGift[0] ?? false; 
            $deliveryAddresses = $deliveryAddressesGift; 
        } 
 
        $brandboxEnabled = $offer->getBrandboxEnabled(); 
        $deliveryEnabled = $iikoUtil->isDeliveryEnabled(); 
        $pickupEnabled = $iikoUtil->isPickupEnabled(); 
 
        $isAjaxScheduleForDelivery = false; 
        $schedule = $shippingSchedulerService->getEmptySchedule($iikoUtil, $pickupDeliveryType); 
        if ( 
            ($brandboxEnabled && $pickupDeliveryType === FoodOfferExtension::DELIVERY_METHOD && $deliveryAddresses) || 
            (!$brandboxEnabled && $deliveryEnabled && $deliveryAddresses) 
        ) { 
            $schedule = $shippingSchedulerService->getDeliverySchedule($iikoUtil, $pickupDeliveryType); 
        } 
 
        $citySelect = ''; 
        $citySelectData = $iikoUtil->getCitySelectData($entityManager); 
        if ($citySelectData) { 
            $citySelect = $this->renderView(CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/city_select.html.twig' 
                : 'Slivki/delivery/city_select.html.twig', ['deliveryLocations' => $citySelectData]); 
        } 
 
        $workHourFrom = 0; 
        $workHourTo = 0; 
 
        $pickupLocations = ''; 
        $defaultLocationID = null; 
        /** @var GeoLocation $geoLocation */ 
        foreach ($offer->getGeoLocations() as $geoLocation) { 
            if (!$geoLocation->isActive()) { 
                continue; 
            } 
 
            if (!$defaultLocationID) { 
                $defaultLocationID = $geoLocation->getID(); 
            } 
 
            $pickupPointScheduleParsed = $geoLocation->getPickupPointScheduleParsed(); 
            if (!$pickupPointScheduleParsed) { 
                continue; 
            } 
 
            $pickupLocations .= $this->renderView('Slivki/delivery/pickup_location_item.html.twig', [ 
                'location' => $geoLocation, 
            ]); 
        } 
 
        $nearestTime = 'Ближайшее'; 
 
        $deliveryTimeFrom = $iikoUtil->getDeliveryTimeFrom(); 
        $deliveryTimeTill = $iikoUtil->getDeliveryTimeTill(); 
 
        $additionalDominos = !(null === $additionalDominos); 
        $this->reCalcOrder( 
            $order, 
            0, 
            $pickupDeliveryType, 
            $subscriptionService->isSubscriber($this->getUser()), 
            $pricePromocodeForOnlineOrder 
        ); 
 
        $data = [ 
            'order' => $order, 
            'offer' => $offer, 
            'codeCost' => $codeCost, 
            'codeCostRegular' => $codeCostRegular, 
            'deliveryPrice' => $deliveryPrice, 
            'offerURL' => $entityManager->getRepository(Seo::class)->getOfferURL($offer->getID())->getMainAlias(), 
            'totalAmount' => $totalAmount + $deliveryPrice, 
            'director' => $offer->getDirectors()->first(), 
            'robotsMeta' => 'noindex, follow', 
            'offerID' => $offerID, 
            'showCheckAddressButton' => $iikoUtil::SHOW_CHECK_ADDRESS_BUTTON, 
            'streetSuggest' => $iikoUtil::STREET_SUGGEST, 
            'workHourFrom' => $workHourFrom, 
            'workHourTo' => $workHourTo, 
            'citySelect' => $citySelect, 
            'multipleLocationDelivery' => $iikoUtil::MULTIPLE_LOCATIONS_DELIVERY, 
            'formAction' => '/delivery/order/check-payment', 
            'categoryName' => $iikoUtil::CATEGORY_NAME, 
            'categoryURL' => $entityManager->getRepository(Seo::class)->getSeoForEntity(SeoRepository::RESOURCE_URL_OFFER_CATEGORY, $iikoUtil::CATEGORY_ID)->getMainAlias(), 
            'pickupLocations' => $pickupLocations, 
            'nearestTimeLabel' => $nearestTime, 
            'showDelivery' => true, 
            'defaultLocationID' => $defaultLocationID, 
            'pickupEnabled' => $pickupEnabled, 
            'deliveryEnabled' => $deliveryEnabled, 
            'allowedPaymentMethods' => $iikoUtil->getAllowedPaymentMethods(), 
            'footerOfferConditionID' => $offerID, 
            'pickupDiscount' => $iikoUtil->getPickupDiscount(), 
            'pickupDeliveryType' => $pickupDeliveryType, 
            'deliveryTimeFrom' => $deliveryTimeFrom, 
            'deliveryTimeTill' => $deliveryTimeTill, 
            'orderPeriodInDays' => $iikoUtil->getOrderPeriodInDays(), 
            'offersDetails' => $offersDetails, 
            'schedule' => $schedule, 
            'deliveryAddresses' => $deliveryAddresses, 
            'deliveryAddressesGift' => $deliveryAddressesGift, 
            'defaultDeliveryAddress' => $defaultDeliveryAddress, 
            'brandboxEnabled' => $brandboxEnabled, 
            'additionalDominos' => $additionalDominos, 
            'isSushiVesla' => $isSushiVesla, 
            'isDominos' => $isDominos, 
            'isAjaxScheduleForDelivery' => $isAjaxScheduleForDelivery, 
            'isOnlineGift' => $offer->isOnlineOrderGiftEnabled(), 
            'allowedCodesToBuyBalance' => $allowedCodesToBuyBalance, 
            'deliveryZones' => $deliveryZoneSorter->sortByDefault($deliveryZoneDao->findByOfferId($offerID)), 
            'offerForSlivkiDelivery' => $slivkiDeliveryOption, 
        ]; 
 
        $data['iikoOrder'] = true; 
 
        $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/delivery_checkout.html.twig' : 'Slivki/delivery/delivery_checkout.html.twig'; 
 
        $content = $this->renderView($view, $data); 
        $response->setContent($content); 
 
        $response->headers->addCacheControlDirective('no-cache', true); 
        $response->headers->addCacheControlDirective('max-age', 0); 
        $response->headers->addCacheControlDirective('must-revalidate', true); 
        $response->headers->addCacheControlDirective('no-store', true); 
 
        return $response; 
    } 
 
    /** 
     * @Route("/delivery/order/payment/{orderID}", name="delivery_order_payment") 
     */ 
    public function deliveryOrderPaymentAction( 
        Request $request, 
        PartnerBePaidService $partnerBePaidService, 
        OnlineOrderHistoryHandler $onlineOrderHistoryHandler, 
        SubscriptionService $subscriptionService, 
        CreditCardRepositoryInterface $creditCardRepository, 
        DirectorRepositoryInterface $directorRepository, 
        VirtualWalletChecker $virtualWalletChecker, 
        PricePromocodeForOnlineOrder $pricePromocodeForOnlineOrder, 
        $orderID 
    ) { 
        $entityManager = $this->getDoctrine()->getManager(); 
        $response = new Response(); 
        /** @var FoodOrder $order */ 
        $order = $entityManager->find(FoodOrder::class, $orderID); 
        if (!$order) { 
            throw $this->createNotFoundException(); 
        } 
 
        $user = $order->getUser(); 
        $offer = $order->getOffer(); 
        $offerID = $offer->getID(); 
        $iikoUtil = IikoUtil::instance($offer); 
        $iikoUtil->setContainer($this->kernel->getContainer()); 
 
        $isPickup = $order->getDeliveryAddress()->isPickup(); 
 
        $detailIdCount = []; 
        $totalAmount = 0; 
        /** @var OfferOrderDetails $details */ 
        $extensionIds = []; 
        foreach ($order->getOfferOrderDetails() as $details) { 
            $extension = $details->getOfferExtension(); 
            $extensionIds[] = $extension->getId(); 
 
            if ($iikoUtil instanceof SushiHouse) { 
                if (isset($detailIdCount[$extension->getID()])) { 
                    $detailIdCount[$extension->getID()] += $details->getItemsCount(); 
                } else { 
                    $detailIdCount[$extension->getID()] = $details->getItemsCount(); 
                } 
            } 
 
            $variant = $details->getOfferExtensionVariant(); 
            $regularPrice = $variant ? $variant->getRegularPrice() : $details->getOfferExtension()->getPrice(); 
            $totalAmount += $details->getItemsCount() * $regularPrice; 
 
            $sortByFromDelivery = $request->getSession()->get(OnlineOrderHistory::SORT_SESSION_NAME); 
            if (null !== $sortByFromDelivery) { 
                $onlineOrderHistoryHandler->handle( 
                    $order, 
                    $extension->getID(), 
                    $sortByFromDelivery 
                ); 
            } 
        } 
 
        $request->getSession()->set(OnlineOrderHistory::SORT_SESSION_NAME, null); 
 
        $pickupDeliveryType = $isPickup ? FoodOfferExtension::DELIVERY_METHOD_PICKUP : FoodOfferExtension::DELIVERY_METHOD; 
 
        $deliveryCost = 0; 
        if ($pickupDeliveryType === FoodOfferExtension::DELIVERY_METHOD || !$isPickup) { 
            $totalAmount += $order->getDeliveryCost(); 
 
            $deliveryCost = $order->getDeliveryCost(); 
        } 
 
        $codeCost = $order->getCodeCost(); 
        $regularCodeCost = $codeCost; 
 
        $allowedCodesToBuyBalance = false; 
        if ($subscriptionService->isSubscriber($user) || $user->isBatchCodesAllowed()) { 
            $codeCost = 0; 
        } elseif ($user->isBalanceAllowed($codeCost * $order->getCodesCount())) { 
            $codeCost = 0; 
            $allowedCodesToBuyBalance = true; 
        } 
 
        $partnerBePaidService->setOrder($order); 
        $paymentToken = $partnerBePaidService->getPaymentToken($order, null, $codeCost); 
 
        $view = CommonUtil::isMobileDevice($request) 
            ? 'Slivki/mobile/delivery/delivery_payment.html.twig' 
            : 'Slivki/delivery/delivery_payment.html.twig'; 
 
        $offersDetails = []; 
 
        $director = $directorRepository->findById($offer->getDirectorID()); 
 
        $fullOrderAmount = $order->getAmount(); 
        if ($allowedCodesToBuyBalance) { 
            $fullOrderAmount += $regularCodeCost * $order->getCodesCount(); 
        } 
 
        $this->reCalcOrder( 
            $order, 
            0, 
            $pickupDeliveryType, 
            $subscriptionService->isSubscriber($this->getUser()), 
            $pricePromocodeForOnlineOrder 
        ); 
 
        $content =  $this->renderView($view, [ 
            'order' => $order, 
            'offer' => $offer, 
            'offerURL' => $entityManager->getRepository(Seo::class)->getOfferURL($offerID)->getMainAlias(), 
            'offerID' => $offerID, 
            'categoryName' => $iikoUtil::CATEGORY_NAME, 
            'deliveryPrice' => $deliveryCost, 
            'codeCost' => $codeCost, 
            'totalAmount' => $totalAmount, 
            'showCheckAddressButton' => false, 
            'categoryURL' => $entityManager->getRepository(Seo::class)->getSeoForEntity(SeoRepository::RESOURCE_URL_OFFER_CATEGORY, $iikoUtil::CATEGORY_ID)->getMainAlias(), 
            'isPickup' => $isPickup, 
            'allowedPaymentMethods' => $iikoUtil->getAllowedPaymentMethods()[$isPickup ? 'pickup' : 'delivery'], 
            'pickupDiscount' => $isPickup ? $iikoUtil->getPickupDiscount() : 0, 
            'pickupDeliveryType' => $pickupDeliveryType, 
            'paymentToken' => $paymentToken['checkout']['token'], 
            'offersDetails' => $offersDetails, 
            'additionalDominos' => false, 
            'isDominos' => $iikoUtil instanceof Dominos, 
            'activeCreditCards' => !$offer->isRecurrentDisabled() ? $creditCardRepository->findActiveByUser($user) : [], 
            'directorName' => $director instanceof Director ? $director->getName() : '', 
            'allowedCodesToBuyBalance' => $allowedCodesToBuyBalance, 
            'isSlivkiPayAllowed' => $virtualWalletChecker->availableSlivkiPay($fullOrderAmount, $user), 
            'allowedCashbackSumToPay' => $iikoUtil->getAllowedCashbackSumToPay($order, $entityManager), 
            'allowedFastDeliveryForSushiHouse' => $iikoUtil->enabledFastDelivery($order), 
        ]); 
        $response->setContent($content); 
 
        return $response; 
    } 
 
    /** @Route("/delivery/order/check-payment", name = "deliveryOrderCheckPayment") */ 
    public function checkPaymentAction( 
        Request $request, 
        CoordinatesYandex $coordinatesYandex, 
        DeliveryZoneRepositoryInterface $deliveryZoneRepository, 
        ShippingSchedulerService $shippingSchedulerService, 
        SubscriptionService $subscriptionService, 
        PhoneNumberUtil $phoneNumberUtil, 
        PhoneNumberHelper $phoneNumberHelper, 
        PricePromocodeForOnlineOrder $pricePromocodeForOnlineOrder, 
        VisibilityFilterService $visibilityFilterService 
    ) { 
        if (!$request->isMethod(Request::METHOD_POST)) { 
            throw $this->createNotFoundException(); 
        } 
 
        $entityManager = $this->getDoctrine()->getManager(); 
        $orderID = $request->request->getInt('orderID'); 
        $pickupDeliveryType = $request->request->get('pickupDeliveryType'); 
        $pickupDeliveryType = $pickupDeliveryType ? (int) $pickupDeliveryType : null; 
        $isOnlineOrderGift = $request->request->getBoolean('isOnlineGift'); 
 
        $discount = 0; 
        /** @var FoodOrder $order */ 
        $order = $entityManager->find(FoodOrder::class, $orderID); 
        if (!$order || $order->getUser()->getID() != $this->getUser()->getID() || $order->getStatus() != FoodOrder::STATUS_INIT) { 
            throw $this->createNotFoundException(); 
        } 
        $order->setComment($request->request->get('comment')); 
        $order->setDeliveryTime($request->request->get('deliveryTime')); 
        $order->setIsOnlineGift($isOnlineOrderGift); 
        $iikoUtil = IikoUtil::instance($order->getOffer()); 
        $iikoUtil->setContainer($this->kernel->getContainer()); 
 
        $possibilityOrder = $iikoUtil->getPossibilityOrderStatus($order); 
        if ($possibilityOrder['status'] === 'error') { 
            return new JsonResponse(['status' => 'error', 'error' => true, 'message' => $possibilityOrder['message']]); 
        } 
 
        $isSushiHouse = $iikoUtil instanceof SushiHouse; 
        $isSushiVesla = $iikoUtil instanceof SushiVesla; 
 
        if (!$isSushiHouse && !$isSushiVesla) { 
            $this->reCalcOrder( 
                $order, 
                0, 
                $pickupDeliveryType, 
                $subscriptionService->isSubscriber($this->getUser()), 
                $pricePromocodeForOnlineOrder 
            ); 
        } 
 
        $request->getSession()->set("pickupDiscount", null); 
        if ($request->request->has('pickup')) { 
            $addressID = $request->request->getInt('pickupAddressID'); 
            $discount = $request->request->getInt('pickupDiscount'); 
            $request->getSession()->set("pickupDiscount", $discount); 
            $geoLocation = $entityManager->find(GeoLocation::class, $addressID); 
            $userAddresses = $entityManager->getRepository(UserAddress::class)->findBy(['user' => $this->getUser(), 'geoLocation' => $geoLocation]); 
            $address = null; 
            foreach ($userAddresses as $location) { 
                if ($location->getGeoLocation()->getID() == $addressID) { 
                    $address = $location; 
                    break; 
                } 
            } 
            if (!$address) { 
                $address = new UserAddress(); 
                $address->setUser($this->getUser()); 
                $address->setGeoLocation($geoLocation); 
                $address->setOfferID($order->getOffer()->getID()); 
                $entityManager->persist($address); 
            } 
 
            $address->setPickup(true); 
        } else { 
            $address = $entityManager->find(UserAddress::class, $request->request->getInt('addressID')); 
            $geoLocation = null; 
        } 
        if ($address) { 
            $name = $request->request->get('name', ''); 
            $phone = $request->request->get('phone', ''); 
 
            if (trim($name) == '' || trim($phone) == '') { 
                return new JsonResponse(['error' => true]); 
            } 
 
            if (\mb_strlen($phone) > 0) { 
                $phoneNumberObject = $phoneNumberUtil->parse($phone); 
 
                if (!$phoneNumberUtil->isValidNumber($phoneNumberObject)) { 
                    return new JsonResponse(['error' => true, 'message' => 'Введен некорректный номер телефона']); 
                } 
            } 
 
            $address->setPhone($phone); 
            $address->setName($name); 
            $address->setIsOnlineGift($isOnlineOrderGift); 
            if ($isOnlineOrderGift) { 
                $address->setNameGift($request->request->get('nameGift')); 
                $address->setPhoneNumberGift( 
                    $phoneNumberHelper->convert($request->request->get('phoneNumberGift'), ''), 
                ); 
            } 
 
            $order->setDeliveryAddress($address); 
        } else { 
            return new JsonResponse(['error' => true, 'message' => 'Не выбран адрес']); 
        } 
 
        $result = $iikoUtil->checkOrder($entityManager, $order, $subscriptionService); 
 
        if (!$result || $result->resultState > 0) { 
            $message = null; 
            if ($result) { 
                switch ($result->resultState) { 
                    case 1: 
                        if (isset($result->problem)) { 
                            $message = $result->problem; 
                        } 
                        if (isset($result->minSumForFreeDelivery)) { 
                            $message = \sprintf('Минимальная сумма заказа %s руб.', (string) $result->minSumForFreeDelivery); 
                        } 
                        break; 
                    case 2: 
                        $message = 'Извините, в данное время заказ невозможен. Пожалуйста, выберите другое время'; 
                        break; 
                    case 3: 
                        $message = 'Извините, на данный адрес доставка не осуществляется'; 
                        break; 
                    case 4: 
                    case 5: 
                        $message = 'На данный момент заказ одного из товаров невозможен'; 
                        break; 
                    case 9999: 
                        $message = 'Заказы принимаются с 11:00 по 22:20'; 
                        break; 
                } 
            } 
            return new JsonResponse(['error' => true, 'message' => $message]); 
        } 
 
        try { 
            $visibilityFilterService->assertAllVisibleOrFail(array_map( 
                static fn (OfferOrderDetails $orderDetail) => $orderDetail->getOfferExtension(), 
                $order->getOfferOrderDetails()->toArray(), 
            )); 
        } catch (OfferExtensionNotVisibleException $e) { 
            return new JsonResponse(['error' => true, 'message' => $e->getMessage()]); 
        } 
 
        if ($request->request->get('deliveryTime') !== self::NEARLY) { 
            if ($request->request->get('deliveryTime') === null) { 
                $checkSchedule = [ 
                    'status' => 'error', 
                    'message' => 'Выберите время', 
                ]; 
            } else { 
                $checkSchedule = $iikoUtil->checkSchedule($shippingSchedulerService, $geoLocation, $entityManager, $pickupDeliveryType, $request->request->get('deliveryTime')); 
            } 
 
            if ($checkSchedule['status'] === 'error') { 
                return new JsonResponse(['status' => $checkSchedule['status'], 'message' => $checkSchedule['message'], 'error' => true], Response::HTTP_OK); 
            } 
        } 
 
        if (null !== $order->getOffer()->getOfferDeliveryZone() && $order->getOffer()->getOfferDeliveryZone()->count() > 0) { 
            if (null === $address->isPickup()) { 
                $points = $address->getCoordinatesForDeliveryZone() ?? $coordinatesYandex->getGeoCoordinates( 
                    $address->buildFullAddress(), 
                    ['offerId' => (int)$order->getOffer()->getID()] 
                ); 
 
                $deliveryZone = $deliveryZoneRepository->getPolygonByPoint($order->getOffer(), $points); 
 
                if (null !== $deliveryZone) { 
                    $user = $order->getUser(); 
 
                    $codeCost = $order->getCodeCost(); 
                    if ($subscriptionService->isSubscriber($user) || $user->isBatchCodesAllowed() || $user->isBalanceAllowed($codeCost * $order->getCodesCount())) { 
                        $codeCost = 0; 
                    } 
 
                    $total = $order->getAmount() - ($order->getCodesCount() * $codeCost); 
 
                    if ($total < $deliveryZone->getMinOrderAmount()) { 
                        return new JsonResponse([ 
                            'error' => true, 
                            'message' => \sprintf('До минимальной суммы заказа в этой зоне %s р.', (string) ($deliveryZone->getMinOrderAmount() - $total)), 
                        ]); 
                    } 
 
                    $order->setDeliveryZoneLocationId($deliveryZone->getGeoLocationId()); 
                    $order->setDeliveryCost($deliveryZone->getPaidDeliveryAmount()); 
                    if ($total >= $deliveryZone->getFreeDeliveryAmount()) { 
                        $order->setDeliveryCost(0); 
                    } 
 
                    if (null === $address->getCoordinatesForDeliveryZone()) { 
                        $coordinates = explode(' ', $points); 
 
                        $address->setLatitude($coordinates[1]); 
                        $address->setLongitude($coordinates[0]); 
                    } 
                } else { 
                    return new JsonResponse([ 
                        'error' => true, 
                        'message' => 'Данный адрес не входит в зону доставки. Выберите другой адрес.', 
                    ]); 
                } 
            } else { 
                $order->setDeliveryZoneLocationId($address->getGeoLocation()->getID()); 
            } 
        } 
 
        $this->reCalcOrder( 
            $order, 
            $discount, 
            $pickupDeliveryType, 
            $subscriptionService->isSubscriber($this->getUser()), 
            $pricePromocodeForOnlineOrder 
        ); 
 
        $entityManager->flush(); 
 
        return new JsonResponse(['error' => false, 'redirectURL' => '/delivery/order/payment/' . $order->getID() ]); 
    } 
 
    /** 
     * @Route("/delivery/order/pay/{orderID}", name="deliveryOrderPay") 
     */ 
    public function payAction( 
        Request $request, 
        PartnerBePaidService $partnerBePaidService, 
        PaymentService $paymentService, 
        CreditCardRepositoryInterface $creditCardRepository, 
        SubscriptionService $subscriptionService, 
        ContainerInterface $container, 
        PricePromocodeForOnlineOrder $pricePromocodeForOnlineOrder, 
        VirtualWalletChecker $virtualWalletChecker, 
        $orderID 
    ) { 
        $paymentMethod = $request->request->getInt('paymentMethod'); 
        $entityManager = $this->getDoctrine()->getManager(); 
        $order = $entityManager->find(FoodOrder::class, $orderID); 
        if (null === $order) { 
            return new JsonResponse(['error' => true]); 
        } 
        $iikoUtil = IikoUtil::instance($order->getOffer()); 
        $iikoUtil->setContainer($container); 
        $order->setPaymentType($paymentMethod); 
        $order->setPaymentMethodID(OfferOrder::METHOD_BEPAID); 
        $isUsePartnerCashbackBalance = $request->request->getBoolean('usePartnerCashbackBalance'); 
        $order->setUsePartnerCashbackBalance($isUsePartnerCashbackBalance); 
        if ($isUsePartnerCashbackBalance) { 
            $allowedCashbackSumToPay = $iikoUtil->getAllowedCashbackSumToPay($order, $entityManager); 
            $order->setUsedPartnerCashbackSum($allowedCashbackSumToPay); 
        } 
 
        $order->setUseFastDelivery( 
            $request->request->getBoolean('useFastDelivery') 
        ); 
 
        $codeCost = $order->getCodeCost(); 
        $codeCostRegular = $codeCost; 
        $user = $order->getUser(); 
 
        $subscriber = false; 
        if ($subscriptionService->isSubscriber($user)) { 
            $subscriber = true; 
            $codeCost = 0; 
        } 
 
        $isBatchCodes = false; 
        if ($user->isBatchCodesAllowed()) { 
            $isBatchCodes = true; 
            $codeCost = 0; 
        } 
 
        if (in_array($paymentMethod, [PaymentType::CASH, PaymentType::TERMINAL], true)) { 
            if ($subscriber || $isBatchCodes) { 
                $order->setAmount($codeCost); 
                $paymentService->createCode( 
                    $order, 
                    $order->getCodesCount(), 
                    false, 
                    null, 
                    false, 
                    $isBatchCodes ? UserBalanceActivity::TYPE_REDUCTION_BATCH_CODES : null 
                ); 
 
                return new JsonResponse(['error' => false]); 
            } 
 
            $order->setAmount($order->getCodesCount() * $codeCost); 
            $entityManager->flush(); 
 
            return new JsonResponse([ 
                'redirectURL' => $this->redirectToRoute('buyCode', [ 
                        'offerID' => $order->getOffer()->getID(), 
                        'codesCount' =>  $order->getCodesCount(), 
                        'orderID' => $order->getID() 
                    ] 
                )->getTargetUrl() 
            ]); 
        } 
 
        $deliveryType = $order->getDeliveryAddress()->isPickup() ? FoodOfferExtension::DELIVERY_METHOD_PICKUP : FoodOfferExtension::DELIVERY_METHOD; 
        $discount = $request->getSession()->get("pickupDiscount") ? $request->getSession()->get("pickupDiscount") : 0; 
 
        $this->reCalcOrder( 
            $order, 
            $discount, 
            $deliveryType, 
            $subscriptionService->isSubscriber($user), 
            $pricePromocodeForOnlineOrder 
        ); 
 
        if ($paymentMethod === PaymentType::SLIVKI_PAY) { 
            $codeCostForSlivkiPay = $order->getCodesCount() * (float) $order->getCodeCost(); 
            try { 
                $orderAmount = $order->getAmount(); 
                if ($order->getUsedPartnerCashbackSum() > 0) { 
                    $orderAmount -= $order->getUsedPartnerCashbackSum(); 
                } 
 
                if ($codeCost === 0 || $user->isBalanceAllowed($codeCost * $order->getCodesCount())) { 
                    $orderAmount += $codeCostForSlivkiPay; 
                } 
 
                if (!$virtualWalletChecker->availableSlivkiPay($orderAmount, $user)) { 
                    return new JsonResponse( 
                        [ 
                            'error' => true, 
                            'message' => 'Недостаточно средств на балансе SlivkiPay', 
                            'slivkiPay' => true, 
                        ] 
                    ); 
                } 
 
                $paymentService->payOrder($user, $orderAmount); 
                $paymentService->createCode($order, $order->getCodesCount(), false); 
            } catch (InsufficientBalanceFundsException $exception) { 
                return new JsonResponse(['error' => true]); 
            } 
 
            return new JsonResponse(['error' => false]); 
        } 
 
        $order->setPaymentType(PaymentType::ONLINE); 
 
        if ($user->isBalanceAllowed($codeCost * $order->getCodesCount())) { 
            $codeCost = 0; 
        } 
 
        $iikoUtil->modifyOrder($order, $entityManager); 
 
        $entityManager->flush(); 
 
        $partnerBePaidService->setOrder($order); 
 
        $card = $creditCardRepository->findById($request->request->getInt('creditCardID')); 
        if (null === $card || !$card->isOwner($this->getUser()->getID())) { 
            $paymentToken = $partnerBePaidService->getPaymentToken($order, null, $codeCost); 
            if (!$paymentToken) { 
                return new JsonResponse(['error' => true]); 
            } 
 
            $partnerBePaidService->createBePaidPaiment($order, $paymentToken['checkout']['token']); 
 
            return new JsonResponse([ 
                'token' => $paymentToken['checkout']['token'], 
            ]); 
        } 
 
        $offerSettings = $order->getOffer()->getOnlineOrderSettings(); 
        if (($iikoUtil::SPLIT_PAYMENT || ($offerSettings && $offerSettings->isSplitPayment())) 
            && (!$subscriber && !$user->isBatchCodesAllowed() && !$user->isBalanceAllowed($codeCostRegular * $order->getCodesCount())) 
        ) { 
            $amount = $order->getAmount() - $order->getCodesCount() * $codeCost; 
        } else { 
            $amount = $order->getAmount(); 
        } 
 
        $result = $partnerBePaidService->checkoutByToken($order, $card->getID(), $amount); 
        if (!$result) { 
            return new JsonResponse(['error' => true]); 
        } 
 
        if (is_array($result) && isset($result['token'])) { 
            return new JsonResponse(['token' => $result['token']]); 
        } 
 
        $partnerBePaidService->createBePaidPaiment($order, $result); 
         
        return new JsonResponse(['error' => false]); 
    } 
 
    /** @Route("/delivery/street/suggest/{offerID}") */ 
    public function deliveryStreetSuggest(Request $request, $offerID): JsonResponse 
    { 
        /** @var StreetRepository $street */ 
        $street = $this->getDoctrine()->getManager()->getRepository(Street::class); 
        $streets = $street->getStreets($offerID, $request->query->get('q')); 
 
        return new JsonResponse($streets); 
    } 
 
    /** @Route("/delivery/feedback/{offerID}") */ 
    public function feedbackAction(Request $request, Mailer $mailer, $offerID) { 
        $text = $request->request->get('name') . ', ' . $request->request->get('email') . "\n" . $request->request->get('message') . "\n"; 
        $subj =''; 
        if (is_numeric($offerID)) { 
            $offerID = (int)$offerID; 
            $offer = $this->getDoctrine()->getManager()->find(Offer::class, $offerID); 
            if ($offer) { 
                $subj = 'Жалоба на акцию: ' . $offer->getTitle(); 
            } else { 
                $subj = 'Фидбек с доставки суши'; 
            } 
        } 
        else if ($offerID == 'subscription-landing') { 
            $subj = 'Фидбек с лендинга подписки'; 
        } 
        else if ($offerID == 'auth') { 
            $subj = 'Фидбек с попапа авторизации'; 
        } 
        $message = $mailer->createMessage($subj, $text); 
        $message->setFrom('info@slivki.by', 'Slivki.by'); 
        $message->setTo('1@slivki.by') 
            ->addTo('info@slivki.by') 
            ->addTo('yuri@slivki.com') 
            ->addCc('dmitry.kazak@slivki.com'); 
        $mailer->send($message); 
        return new Response(); 
    } 
 
    private function reCalcOrder( 
        FoodOrder $order, 
        $discount = 0, 
        $typePrice = null, 
        bool $isSubscriber = false, 
        PricePromocodeForOnlineOrder $pricePromocodeForOnlineOrder 
    ) { 
        /** @var OfferOrderDetails $details */ 
        $orderSum = 0; 
        $additionalInfo = $order->getAdditionalInfo(); 
 
        $additionalDominos = false; 
        if (isset($additionalInfo['dominosCoupon'])) { 
            $additionalDominos = true; 
        } 
 
        $iikoUtil = AbstractDelivery::instance($order->getOffer()); 
        $iikoUtil->setContainer($this->kernel->getContainer()); 
 
        foreach ($order->getOfferOrderDetails() as $details) { 
            $variant = $details->getOfferExtensionVariant(); 
            if ($variant) { 
                $extension = $variant->getOfferExtension(); 
 
                if ($additionalDominos) { 
                    $variantAdditionalDominos = $variant; 
                } else { 
                    $variantAdditionalDominos = null; 
                } 
 
                $purchasePrice = PriceDeliveryType::calcDeliveryPickupPrice( 
                    $extension, 
                    $typePrice, 
                    $variant->getRegularPrice(), 
                    $variant->getOfferPrice(), 
                    $variantAdditionalDominos 
                ); 
            } else { 
                $extension = $details->getOfferExtension(); 
                $product = $iikoUtil->getProduct($extension->getPartnerItemID()); 
 
                $purchasePrice = PriceDeliveryType::calcDeliveryPickupPrice( 
                    $extension, 
                    $typePrice, 
                    $product->regularPrice, 
                    $extension->getCurrentPrice(null, $typePrice), 
                ); 
            } 
 
            $orderSum += $details->getItemsCount() * $purchasePrice; 
            $details->setPurchasePrice($purchasePrice); 
        } 
 
        $deliveryCost = $order->getDeliveryCost(); 
 
        if ( 
            ($typePrice !== null && (int) $typePrice === FoodOfferExtension::DELIVERY_METHOD_PICKUP) 
            || (null !== $order->getDeliveryAddress() && $order->getDeliveryAddress()->isPickup()) 
        ) { 
            $deliveryCost = 0; 
        } 
        $order->setDeliveryCost($deliveryCost); 
 
        $regularCodeCost = $pricePromocodeForOnlineOrder->getPrice( 
            $order, 
            $order->getOffer(), 
            $order->getCodesCount(), 
            $orderSum + $deliveryCost 
        ); 
 
        $codeCost = 0; 
        if (!$isSubscriber 
            && !$order->getUser()->isBatchCodesAllowed() 
            && !$order->getUser()->isBalanceAllowed($regularCodeCost * $order->getCodesCount()) 
        ) { 
            $codeCost = $regularCodeCost; 
        } 
 
        $orderSum += $codeCost * $order->getCodesCount() + $deliveryCost; 
        if ($discount > 0) { 
            $orderSum -= ($orderSum * ($discount / 100)); 
        } 
 
        if ($order->getUsedPartnerCashbackSum() > 0) { 
            $orderSum -= $order->getUsedPartnerCashbackSum(); 
        } 
 
        $order->setAmount($orderSum); 
    } 
 
    /** 
     * @Route("/delivery/check-address", name="delivery_check_address") 
     */ 
    public function checkAddressAction( 
        Request $request, 
        SubscriptionService $subscriptionService, 
        VisibilityFilterService $visibilityFilterService 
    ): JsonResponse { 
        $entityManager = $this->getDoctrine()->getManager(); 
        $orderID = $request->request->getInt('orderID'); 
        $addressID = $request->request->getInt('addressID'); 
        $deliveryTime = $request->request->get('deliveryTime'); 
        $order = $entityManager->find(FoodOrder::class, $orderID); 
        $order->setDeliveryTime($deliveryTime); 
        $order->setPaymentType($request->request->getInt('paymentType', 1)); 
        $address = $entityManager->find(UserAddress::class, $addressID); 
        $order->setDeliveryAddress($address); 
        $orderInfo = IikoUtil::instance($order->getOffer())->checkOrder($entityManager, $order, $subscriptionService); 
        if (!$orderInfo) { 
            return new JsonResponse(['error' => true]); 
        } 
        $entityManager->flush(); 
 
        $response = $this->getCheckAddressResponse($orderInfo); 
 
        try { 
            $visibilityFilterService->assertAllVisibleOrFail(array_map( 
                static fn (OfferOrderDetails $orderDetail) => $orderDetail->getOfferExtension(), 
                $order->getOfferOrderDetails()->toArray(), 
            )); 
        } catch (OfferExtensionNotVisibleException $e) { 
            return new JsonResponse([ 
                'status' => 'error', 
                'error' => true, 
                'deliveryPrice' => $response['deliveryPrice'], 
                'message' => $e->getMessage(), 
            ]); 
        } 
 
        return new JsonResponse($response); 
    } 
 
    /** @Route("/delivery/reload/offer/{offerId}/type/{typePrice}", name="deliveryReloadDish") */ 
    public function reloadDish( 
        Request $request, 
        ImageService $imageService, 
        ProductFastDeliveryService $productFastDeliveryService, 
        CustomProductOfferSorter $productSorter, 
        ContainerInterface $container, 
        FoodFilterCounterRepositoryInterface $foodFilterCounterRepository, 
        CustomProductOfferSorter $customProductOfferSorter, 
        OfferOrderPurchaseCountDaoInterface $offerOrderPurchaseCountDao, 
        OfferCacheService $offerCacheService, 
        FoodOfferExtensionRepositoryInterface $foodOfferExtensionRepository, 
        WeightParserHelper $weightParserHelper, 
        ShippingSchedulerService $shippingSchedulerService, 
        FoodByOnlineCategoriesBuilder $foodByOnlineCategoriesBuilder, 
        VisibilityFilterService $visibilityFilterService, 
        $offerId, 
        $typePrice 
    ) { 
        $offerCached = $offerCacheService->getOffer($offerId, true, true); 
 
        $data['offer'] = $offerCached; 
        $orderUtil = AbstractDelivery::instance($offerCached); 
        $orderUtil->setContainer($container); 
        $data['filterAction'] = $foodFilterCounterRepository->findByOfferId((int) $offerCached->getID()); 
        $isSushiVesla = $orderUtil instanceof SushiVesla; 
        $isDominos = $orderUtil instanceof Dominos; 
        $isSushiHouse = $orderUtil instanceof SushiHouse; 
        $isSushiChefArts = $orderUtil instanceof SushiChefArts; 
        $data['isDominos'] = $isDominos; 
        $data['showSortingIndexOrder'] = $isSushiVesla || $isDominos ? false : true; 
 
        $allDishes = []; 
        if ($isSushiVesla) { 
            $allDishes = $foodOfferExtensionRepository->findActiveByOfferIdAndShippingType($offerId, $typePrice); 
        } 
 
        $shippingType = FoodOfferExtension::LABEL_SHIPPING_TYPE[$typePrice]; 
 
        if ($isSushiVesla) { 
            $dishes = $orderUtil->getProductsDBByShippingType( 
                array_filter($allDishes, static fn (OfferExtension $offerExtension): bool => !is_subclass_of($offerExtension, FoodOfferExtension::class)), 
            ); 
        } else { 
            $dishes = $orderUtil->getDishes(); 
        } 
 
        $extensions = $foodOfferExtensionRepository->findActiveByOfferIdAndShippingType($offerId, $typePrice); 
        $extensions = array_combine( 
            array_map(static fn (FoodOfferExtension $e) => $e->getPartnerItemID(), $extensions), 
            $extensions, 
        ); 
 
        $dishPurchaseCount = $offerOrderPurchaseCountDao->getPurchaseCountsForPeriodByOffer((int) $offerId, PurchaseCountPeriod::LAST_MONTH); 
        $dishPurchaseDayCount = $offerOrderPurchaseCountDao->getPurchaseCountsForPeriodByOffer((int) $offerId, PurchaseCountPeriod::LAST_DAY); 
 
        $data['dishes'] = []; 
        $data['showPricePerKilogram'] = false; 
 
        foreach ($dishes as $dish) { 
            if (!array_key_exists($dish->id, $extensions)) { 
                continue; 
            } 
 
            $offerExtension = $extensions[$dish->id]; 
            $dish->productsPerCode = $offerExtension->getProductsPerCode(); 
            $dish->offerPrice = $offerExtension->getCurrentPrice(null, $typePrice); 
            $dish->sauceNeed = $offerExtension->isSauceNeed(); 
            $dish->rating = (float) $offerCached->getRating(); 
 
            $dish->onlineCategories = array_map( 
                static fn (OfferExtensionOnlineCategory $category): string => $category->getName(), 
                $offerExtension->getActiveOnlineCategories()->getValues(), 
            ); 
 
            if (isset($dish->regularPrice) && $dish->regularPrice == 0) { 
                $dish->regularPrice = $offerExtension->getPrice(); 
            } 
 
            $dishSizeFull = $dish->sizeFull; 
            $dish->sizeFull = ''; 
            $dish->pricePerKilogram = null; 
            $dish->itemCount = (int) $offerExtension->getComponentsCount(); 
 
            $dish->offerPrice = (float) PriceDeliveryType::calcDeliveryPickupPrice( 
                $offerExtension, 
                $typePrice, 
                $dish->regularPrice, 
                $dish->offerPrice, 
            ); 
 
            if ($extensions[$dish->id]->getWeight()) { 
                $dish->sizeFull = $offerExtension->getWeight() . ' г'; 
                $dish->pricePerKilogram = $this->calcPricePerKilogram( 
                    $dish->offerPrice, 
                    (float) $offerExtension->getWeight(), 
                ); 
 
                $data['showPricePerKilogram'] = true; 
            } 
 
            if ($offerExtension->getComponentsCount()) { 
                if ($dish->sizeFull != '') { 
                    $dish->sizeFull .= ', '; 
                } 
                $dish->sizeFull .= $offerExtension->getComponentsCount() . ' шт'; 
            } 
 
            if ($dish->sizeFull === '') { 
                $dish->sizeFull = $dishSizeFull; 
            } 
 
            if (null === $dish->pricePerKilogram && !empty($dish->sizeFull)) { 
                $dish->pricePerKilogram = $this->calcPricePerKilogram( 
                    $dish->offerPrice, 
                    (float) $weightParserHelper->parse($dish->sizeFull), 
                ); 
 
                $data['showPricePerKilogram'] = true; 
            } 
 
            $dish->originId = $dish->id; 
            $dish->position = $offerExtension->getPosition() ?: CustomProductOfferSorter::DEFAULT_POSITION; 
            $dish->id = $offerExtension->getID(); 
            $dish->description = str_replace("\n", '<br/>', $dish->description); 
            $dish->imageURL = null; 
            if (isset($dish->images[count($dish->images) - 1])) { 
                if ($dish->images[count($dish->images) - 1] instanceof OfferExtensionMedia) { 
                    $dish->imageURL = $imageService->getImageURLCached($dish->images[count($dish->images) - 1], 540, 0); 
                } else if ($dish->images[count($dish->images) - 1]) { 
                    $dish->imageURL = $dish->images[count($dish->images) - 1]->imageUrl; 
                } 
            } 
 
            $key = array_search($dish->id, array_column($dishPurchaseCount, 'id'), true); 
            $dish->purchaseCount = isset($dishPurchaseCount[$key]['cnt']) && $key !== false ? $dishPurchaseCount[$key]['cnt'] : 0; 
 
            $keyDay = array_search($dish->id, array_column($dishPurchaseDayCount, 'id'), true); 
            $dish->purchaseDayCount = isset($dishPurchaseDayCount[$keyDay]['cnt']) && $keyDay !== false 
                ? $dishPurchaseDayCount[$keyDay]['cnt'] 
                : 0; 
 
            $deliveryTime = $productFastDeliveryService->findProductFastDelivery($offerCached, $dish->originId); 
 
            $dish->fastDeliveryTime = CustomProductOfferSorter::DEFAULT_POSITION; 
            if ($deliveryTime) { 
                $dish->fastDelivery = $deliveryTime; 
                $dish->fastDeliveryTime = (int) $deliveryTime['time']; 
            } 
 
            if (isset($dish->variants) && count($dish->variants) > 0) { 
                $offerExtensionVariants = array_reduce( 
                    $extensions[$dish->originId]->getVariants()->getValues(), 
                    static function (array $variants, OfferExtensionVariant $variant) 
                    { 
                        $variants[$variant->getPartnerID()] = $variant; 
 
                        return $variants; 
                    }, 
                    [], 
                ); 
 
                foreach ($dish->variants as $key => $variant) { 
                    if (!array_key_exists($variant->id, $offerExtensionVariants)) { 
                        unset($dish->variants[$key]); 
                        continue; 
                    } 
 
                    /** 
                     * @var $offerExtensionVariant OfferExtensionVariant 
                     */ 
                    $offerExtensionVariant = $offerExtensionVariants[$dish->variants[$key]->partnerId]; 
 
                    $dish->variants[$key]->id = $offerExtensionVariant->getID(); 
                    if (PriceDeliveryType::PERCENT_PRICE === $offerExtension->getPriceDeliveryType()) { 
                        $dish->variants[$key]->offerPrice = (float) PriceDeliveryType::calcDeliveryPickupPrice( 
                            $offerExtension, 
                            $typePrice, 
                            $dish->variants[$key]->regularPrice, 
                            $offerExtension->getCurrentPrice(null, $typePrice), 
                        ); 
                    } 
                } 
            } 
 
            $data['dishes'][] = $dish; 
        } 
 
        $data['dishes'] = $visibilityFilterService->filterInvisibleExtensions($data['dishes']); 
 
        $sortType = $request->query->get('sort', CustomProductOfferSorter::DEFAULT_CUSTOM_PRODUCT_SORT); 
        $data['dishes'] = $productSorter->sort($data['dishes'], $sortType); 
 
        $dishGroup = $orderUtil->getDishGroups(); 
 
        $foodDishExtensionId = $request->query->get('extension'); 
        if (null !== $foodDishExtensionId) { 
            $dishKey = array_search($foodDishExtensionId, \array_column($data['dishes'], 'id')); 
            $foodCourtExtensionDish = $data['dishes'][$dishKey]; 
            unset($data['dishes'][$dishKey]); 
 
            array_unshift($data['dishes'], $foodCourtExtensionDish); 
 
            if (0 < count($dishGroup)) { 
                $category = $isSushiHouse ? $foodCourtExtensionDish->parentGroup : $foodCourtExtensionDish->groupName; 
                $keyDishGroup = array_search($category, $dishGroup); 
                $group = $dishGroup[$keyDishGroup]; 
                unset($dishGroup[$keyDishGroup]); 
 
                array_unshift($dishGroup, $group); 
            } 
        } 
 
        $data['topDishIDList'] = []; 
        for ($i = 0; $i < 3; $i++) { 
            if (isset($dishPurchaseCount[$i]['id'])) { 
                $data['topDishIDList'][] = $dishPurchaseCount[$i]['id']; 
            } 
        } 
 
        if ($orderUtil::DISH_BY_GROUP) { 
            $dishByGroupLabel = []; 
            $dishByGroupContent = []; 
 
            if ($isSushiHouse || $isSushiChefArts) { 
                foreach ($data['dishes'] as $dish) { 
                    $dishByGroupContent[$dish->groupName][] = $dish; 
                    if (!in_array($dish->parentGroup, $dishByGroupLabel)) { 
                        $dishByGroupLabel[$dish->groupName] = $dish->parentGroup; 
                    } 
                } 
 
                if ($isSushiHouse) { 
                    $dishByGroupContent = $this->customSortDishByGroup($dishByGroupContent, $dishGroup); 
                } 
            } 
 
            if ($isDominos) { 
                foreach ($data['dishes'] as $dish) { 
                    $dish->parentGroup = $dish->groupName; 
                    $dishByGroupContent[$dish->groupName][] = $dish; 
                    if (!in_array($dish->groupName, $dishByGroupLabel, true)) { 
                        $dishByGroupLabel[$dish->groupName] = $dish->groupName; 
                    } 
                } 
            } 
 
            $data['dishByGroup'] = [ 
                'content' => $dishByGroupContent, 
                'label' => $dishByGroupLabel, 
            ]; 
        } 
 
        $dishGroup = $foodByOnlineCategoriesBuilder->create($offerId,$data['dishes']); 
        if (!empty($dishGroup)) { 
            $data['dishByGroup'] = array_key_exists('dishByGroup', $data) 
                ? [ 
                    'content' => array_merge($dishGroup['content'], $data['dishByGroup']['content']), 
                    'label' => array_merge($dishGroup['label'], $data['dishByGroup']['label']), 
                ] 
                : $dishGroup; 
        } 
 
        $options = $isSushiVesla 
            ? $orderUtil->getOptionsDBByShippingType( 
                $imageService, 
                \array_filter($allDishes, static fn (OfferExtension $offerExtension): bool => $offerExtension instanceof FoodOfferOptionExtension) 
            ) 
            : $this->getOptions($imageService, $offerCached, $orderUtil, 0, $isDominos ? $shippingType : null); 
 
        $data['options'] = $customProductOfferSorter->sort( 
            $visibilityFilterService->filterInvisibleExtensions($options), 
            CustomProductOfferSorter::DEFAULT_CUSTOM_PRODUCT_SORT, 
        ); 
 
        $data['sortList'] = CustomProductOfferSorter::SORT_LIST; 
        $data['isAvailableOnFood'] = $offerCached->isAvailableOnFood(); 
 
        $data['isAvailableOrderForToday'] = $shippingSchedulerService->availableOrderForToday($orderUtil, $offerCached, $typePrice); 
 
        if ($isDominos) { 
            $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/delivery_teaser_reload_pickup.html.twig' : 'Slivki/delivery/delivery_teaser_reload_pickup.html.twig'; 
        } else { 
            $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/delivery_teaser_reload.html.twig' : 'Slivki/delivery/delivery_teaser_reload.html.twig'; 
        } 
 
        return $this->render($view, $data); 
    } 
 
    private function calcPricePerKilogram(float $offerPrice, int $weight): ?float 
    { 
        if (!$weight) { 
            return null; 
        } 
 
        return \round(self::KILOGRAM * $offerPrice / $weight, 2); 
    } 
 
    /** @Route("/expresspizza-orders") */ 
    public function expressPizzaOrdersAction(Request $request) { 
        $offerID = 282278; 
        $pass = '67380b434f'; 
        $objectCode = '0017-4-009'; 
 
        if ($pass != $request->query->get('pass')) { 
            return new Response('ERROR: Wrong password!'); 
        } 
 
        $date = \DateTime::createFromFormat('U', $request->query->get('date')); 
 
        if (!$date) { 
            return new Response('ERROR: Wrong date format!'); 
        } 
 
        $entityManager = $this->getDoctrine()->getManager(); 
        /** @var Connection $connection */ 
        $connection = $entityManager->getConnection(); 
 
        $sql = "select" 
                . " offer_order.id as order_id," 
                . " offer_order.paid_at as order_datetime," 
                . " offer_order.delivery_time as delivery_datetime," 
                . " user_address.name as client_name," 
                . " user_address.phone as client_phone," 
                . " user_address.pickup as pickup," 
                . " street.name as street_name," 
                . " user_address.house as house," 
                . " user_address.block as block," 
                . " user_address.entrance as entrance," 
                . " user_address.floor as floor," 
                . " user_address.doorphone as doorphone," 
                . " user_address.appartment as appartment," 
                . " offer_extension.partner_item_id as product_code," 
                . " offer_extension.name as product_name," 
                . " offer_order_details.items_count as items_count," 
                . " offer_extension.dish_delivery_price as delivery_price," 
                . " offer_extension.pickup_price as pickup_price," 
                . " offer_order.parameter_int_0 as payment_type," 
                . " offer_order.comment as comment," 
                . " coalesce(geo_location.pickup_point_partner_id, '$objectCode') as object_code" 
            . " from offer_order_details" 
            . " inner join offer_order on offer_order.id = offer_order_details.offer_order_id" 
            . " inner join user_address on offer_order.delivery_address_id = user_address.id" 
            . " left join street on user_address.street_id = street.id" 
            . " left join geo_location on user_address.geo_location_id = geo_location.id" 
            . " inner join offer_extension on offer_extension.id = offer_order_details.offer_extension_id" 
            . " where offer_order.offer_id = $offerID and offer_order.status > 0 and" 
                . " offer_order.paid_at >= '" . $date->format('Y-m-d H:i') . "'" 
            . " order by offer_order.id"; 
 
        $orderDetails = $connection->executeQuery($sql)->fetchAll(\PDO::FETCH_ASSOC); 
 
        $result = []; 
        foreach ($orderDetails as $orderDetail) { 
            $orderDateTime = new \DateTime($orderDetail['order_datetime']); 
            $deliveryDateTime = new \DateTime(); 
            if ($orderDetail['delivery_datetime'] != 'Ближайшее') { 
                $deliveryDateTime = new \DateTime($orderDetail['delivery_datetime']); 
            } 
 
            $comment = ''; 
 
            if (trim($orderDetail['entrance'])) { 
                $comment .= 'П' . trim($orderDetail['entrance']) . ' '; 
            } 
 
            if (trim($orderDetail['floor'])) { 
                $comment .= 'Э' . trim($orderDetail['floor']) . ' '; 
            } 
 
            if (trim($orderDetail['doorphone'])) { 
                $comment .= 'Д' . trim($orderDetail['doorphone']) . ' '; 
            } 
 
            $paymentType = ''; 
            switch ($orderDetail['payment_type']) { 
                case 1: 
                    $paymentType = 'Оплата: онлайн, '; 
                    break; 
                case 2: 
                    $paymentType = 'Оплата: наличные, '; 
                    break; 
                case 3: 
                    $paymentType = 'Оплата: терминал, '; 
            } 
            $comment .= $paymentType; 
 
            $comment .= trim($orderDetail['comment']); 
 
            $result[] = join(chr(9), [ 
                $orderDetail['object_code'], // Код объекта 
                $orderDetail['order_id'], // Номер заказа 
                $orderDateTime->format('d.m.Y'), // Дата заказа 
                $orderDateTime->format('H:i'), // Время заказа 
                $deliveryDateTime->format('H:i'), // Изготовить к какому времени 
                $orderDetail['client_name'], // Имя клиента – Контакт 
                str_replace('+375', '+375 ', $orderDetail['client_phone']), // Контактный телефон. 
                $orderDetail['pickup'] ? 0 : 1, // Тип получения: на месте (0) или доставка (1). 
                trim($orderDetail['street_name']) ?: ' ', // Улица доставки 
                trim($orderDetail['house']) ?: ' ', // Номер дома 
                trim($orderDetail['block']) ?: ' ', // Корпус 
                trim($orderDetail['appartment']) ?: ' ', // Квартира 
                ' ', // Код группы 
                $orderDetail['product_code'], // Код товара 
                ' ', // IDNT Номер выгрузки (оставляйте пустым) 
                $orderDetail['product_name'], // Название товара 
                $orderDetail['items_count'], // Количество 
                $orderDetail['pickup'] ? $orderDetail['pickup_price'] : $orderDetail['delivery_price'], // Цена 
                str_replace(["\r\n", "\n"],' ', $comment), // Примечание 
            ]); 
        } 
 
        $result[] = chr(9) . 'OK'; 
 
        return new Response(join("\r\n", $result)); 
    } 
 
    private function customSortDishByGroup(array $dishByGroupContent, array $sort): array 
    { 
        uasort($dishByGroupContent, function ($dishGroup1, $dishGroup2) use ($sort) { 
            if (!count($dishGroup1)) { 
                return 1; 
            } 
            if (!count($dishGroup2)) { 
                return -1; 
            } 
            $dishGroup1Key = array_search($dishGroup1[0]->parentGroup, $sort); 
            $dishGroup2Key = array_search($dishGroup2[0]->parentGroup, $sort); 
            return $dishGroup1Key < $dishGroup2Key ? -1 : 1; 
        }); 
 
        return $dishByGroupContent; 
    } 
}