- <?php
- namespace Slivki\Controller;
- use libphonenumber\PhoneNumberUtil;
- use Slivki\BusinessFeature\VirtualWallet\Service\VirtualWalletChecker;
- use Slivki\Dao\GiftCertificate\GiftCertificateDaoInterface;
- use Slivki\Entity\Category;
- use Slivki\Entity\Comment;
- use Slivki\Entity\FoodFilterCounter;
- use Slivki\Entity\GiftCertificate;
- use Slivki\Entity\GiftCertificateOrder;
- use Slivki\Entity\Media;
- use Slivki\Entity\Offer;
- use Slivki\Entity\OfferOrderDetails;
- use Slivki\Entity\Seo;
- use Slivki\Entity\User;
- use Slivki\Entity\UserBalanceActivity;
- use Slivki\Entity\Visit;
- use Slivki\Enum\Order\PaymentType;
- use Slivki\Exception\Order\InsufficientBalanceFundsException;
- use Slivki\Repository\PurchaseCount\PurchaseCountRepositoryInterface;
- use Slivki\Repository\SeoRepository;
- use Slivki\Repository\User\CreditCardRepositoryInterface;
- use Slivki\Services\GiftCertificate\SplitPaymentGiftCertificateChecker;
- use Slivki\Services\GiftCertificateService;
- use Slivki\Services\Offer\CustomProductOfferSorter;
- use Slivki\Services\Offer\GiftCertificateSorter;
- use Slivki\Services\Offer\OfferCacheService;
- use Slivki\Services\PartnerBePaidService;
- use Slivki\Services\Payment\OnlineOrderPaymentMethodService;
- use Slivki\Services\Payment\PaymentService;
- use Slivki\Services\Seo\SeoResourceService;
- use Slivki\Services\Subscription\SubscriptionService;
- use Slivki\Util\CommonUtil;
- use Symfony\Component\HttpFoundation\JsonResponse;
- use Symfony\Component\HttpFoundation\Request;
- use Symfony\Component\HttpFoundation\Response;
- use Symfony\Component\Routing\Annotation\Route;
- use function in_array;
- class GiftCertificatesController extends SiteController
- {
-     /**
-      * @Route("/gift-certificate/select/{offerID}", name="giftCertificates")
-      */
-     public function giftCertificatesAction(
-         Request $request,
-         OfferCacheService $offerCacheService,
-         GiftCertificateService $giftCertificateService,
-         GiftCertificateSorter $giftCertificateSorter,
-         SeoResourceService $seoResourceService,
-         SubscriptionService $subscriptionService,
-         GiftCertificateDaoInterface $giftCertificateDao,
-         PurchaseCountRepositoryInterface $purchaseCountRepository,
-         $offerID
-     ): Response {
-         $response = new Response();
-         $entityManager = $this->getDoctrine()->getManager();
-         $offer = $offerCacheService->getOffer($offerID, false, true);
-         if (!$offer) {
-             $offer = $entityManager->find(Offer::class, $offerID);
-         }
-         if (null === $offer || !$offer->hasFreeCodes() || 0 === $giftCertificateDao->getCountActiveByOfferId($offerID)) {
-             return $this->redirect($seoResourceService->getOfferSeo($offerID)->getMainAlias());
-         }
-         $ratingData = $entityManager->getRepository(Comment::class)->getEntityRatingWithCount(Category::OFFER_CATEGORY_ID, $offerID);
-         $certificates = $giftCertificateService->getCertificates($offer);
-         $user = $this->getUser();
-         $sortType = $request->query->get('sort', CustomProductOfferSorter::DEFAULT_CUSTOM_PRODUCT_SORT);
-         $certificates = $giftCertificateSorter->sort($certificates, $sortType);
-         $purchaseCount = $purchaseCountRepository->findByOfferId((int) $offerID);
-         $data = [
-             'dishes' => $certificates,
-             'options' => [],
-             'offer' => $offer,
-             'rating' => $ratingData['rating'] * 100 / 5,
-             'ratingCount' => $ratingData['ratingCount'],
-             'codeCostRegular' => 0,
-             'minSumForFreeDelivery' => 0,
-             'minOrderSum' => 0,
-             'showDelivery' => false,
-             'isCertificate' => true,
-             'footerOfferConditionID' => $offerID,
-             'pickupLocations' => '',
-             'offerGeoLocationData' => '',
-             'defaultLocationID' => null,
-             'visitCount' => $entityManager->getRepository(Visit::class)->getVisitCount($offerID, Visit::TYPE_OFFER, 30, false),
-             'sortList' => $giftCertificateSorter::SORT_LIST,
-             'filterAction' => $entityManager->getRepository(FoodFilterCounter::class)->findOneBy(['entityID' => $offerID]),
-             'purchaseCountMonth' => null === $purchaseCount ? 0 : $purchaseCount->getPurchaseCountLastMonthWithCorrection(),
-         ];
-         if (null !== $user) {
-             if ($subscriptionService->isSubscriber($user)) {
-                 $data['allowedCodesToBuy'] = $subscriptionService->getSubscription($user)->getNumberOfCodes();
-             } elseif ($user->isBatchCodesAllowed()) {
-                 $data['allowedCodesToBuyBatchCodes'] = $user->getBatchCodesCount();
-             }
-         }
-         $data['codeCost'] = 0;
-         if (Offer::SOSEDI_OFFER_ID === $offerID) {
-             $hasSosediPurchase = $giftCertificateService->hasSosediPurchase($user);
-             $data['isFirstSosediPurchase'] = !$hasSosediPurchase;
-             $data['hasSosediPurchaseForUser'] = $hasSosediPurchase;
-         }
-         $data['topDishIDList'] = [];
-         for ($i = 0; $i < 3; $i++) {
-             if (isset($crtPurchaseCount[$i]['id'])) {
-                 $data['topDishIDList'][] = $crtPurchaseCount[$i]['id'];
-             }
-         }
-         $offerRepository = $entityManager->getRepository(Offer::class);
-         $data['director'] = $offerRepository->getDirector($offerID);
-         $data['logoMedia'] = $data['director']->getOnlinePaymentLogo();
-         if (!$data['logoMedia']) {
-             $data['logoMedia'] = $entityManager->getRepository(Media::class)->getDirectorLogo($data['director']->getID());
-         }
-         $data['formAction'] = '/gift-certificate/order/checkout';
-         $data['categoryName'] = 'Подарочные сертификаты';
-         $data['categoryURL'] = $entityManager->getRepository(Seo::class)->getSeoForEntity(SeoRepository::RESOURCE_URL_OFFER_CATEGORY, 24)->getMainAlias();
-         $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/order.html.twig' : 'Slivki/delivery/order.html.twig';
-         $response->setContent($this->renderView($view, $data));
-         return $response;
-     }
-     /**
-      * @Route("/gift-certificate/order/checkout", name="gift_certificate_order_checkout")
-      */
-     public function checkoutAction(
-         Request $request,
-         GiftCertificateService $giftCertificateService,
-         PartnerBePaidService $partnerBePaidService,
-         SeoResourceService $seoResourceService,
-         SubscriptionService $subscriptionService,
-         CreditCardRepositoryInterface $creditCardRepository,
-         OnlineOrderPaymentMethodService $onlineOrderPaymentMethodService,
-         VirtualWalletChecker $virtualWalletChecker
-     ): Response {
-         $response = new Response();
-         $offerID = $request->request->getInt('offerID');
-         $entityManager = $this->getDoctrine()->getManager();
-         $offer = $entityManager->find(Offer::class, $offerID);
-         if (!$offer->isActive() || !$offer->isInActivePeriod()) {
-            throw $this->createNotFoundException();
-         }
-         if (!$offer->hasFreeCodes()) {
-             return $this->redirect($seoResourceService->getOfferSeo($offerID)->getMainAlias());
-         }
-         $codeCost = $this->getOfferRepository()->getCodeCost($offer);
-         $counts = $request->request->get('count');
-         /** @var User $user */
-         $user = $this->getUser();
-         $codeCostRegular = $codeCost;
-         if (null !== $user && $subscriptionService->isSubscriber($user)) {
-             $codeCost = 0;
-             $allowedCodesCount = $subscriptionService->getSubscription($user)->getNumberOfCodes();
-         } elseif ($user->isBatchCodesAllowed()) {
-             $codeCost = 0;
-         }
-         $order = new GiftCertificateOrder();
-         $deviceType = CommonUtil::isMobileDevice($request) ? SiteController::DEVICE_TYPE_MOBILE : SiteController::DEVICE_TYPE_DESKTOP;
-         $order->setDeviceType($deviceType);
-         $order->setUser($this->getUser());
-         $order->setOffer($offer);
-         $codesCount = 0;
-         $totalAmount = 0;
-         $totalOfferAmount = 0;
-         $totalCodes = 0;
-         $items = [];
-         $isFreeStyle = in_array($offerID, Offer::FREESTYLE_OFFER_IDS, true);
-         $isSosedi = $offerID === 283793;
-         $hasSosediPurchase = false;
-         if ($isSosedi) {
-             $hasSosediPurchase = $giftCertificateService->hasSosediPurchase($user);
-         }
-         $isBuyOnlyCodeResponse = false;
-         $loopFirst = true;
-         foreach ($request->request->get('dishID') as $key => $certificateID) {
-             /** @var GiftCertificate $certificate */
-             $certificate = $entityManager->find(GiftCertificate::class, $certificateID);
-             if (!$certificate) {
-                 continue;
-             }
-             if ($certificate->isBuyOnlyCode()) {
-                 $isBuyOnlyCodeResponse = true;
-             }
-             $items[$key] = 0;
-             for ($i = 0; $i < $counts[$key]; $i++) {
-                 if (
-                     Offer::BLACK_START_BURGER_OFFER_ID !== $offer->getID()
-                     && isset($allowedCodesCount) && $totalCodes >= $allowedCodesCount
-                 ) {
-                     break;
-                 }
-                 if ($isFreeStyle || $isSosedi) {
-                     $codeTill = $offer->getCodeActiveTill()->setTime(23,59,59);
-                 } else {
-                     $codeTill =  new \DateTime("+" . $certificate->getActiveDays() ." days");
-                 }
-                 $details = new OfferOrderDetails();
-                 $details->setGiftCertificate($certificate);
-                 $details->setItemsCount(1);
-                 $details->setCodeActiveTill($codeTill);
-                 $purchasePrice = $certificate->getPriceOffer();
-                 if ($isSosedi) {
-                     if (!$hasSosediPurchase && $loopFirst && $i == 0 && $certificate->getPrice() != 100 && $certificate->getPrice() != 50) {
-                         $purchasePrice = $certificate->getPrice() * 0.9;
-                         $loopFirst = false;
-                     }
-                     $totalOfferAmount += $purchasePrice;
-                 }
-                 $details->setPurchasePrice($purchasePrice);
-                 $order->addOfferOrderDetails($details);
-                 $totalCodes++;
-                 $items[$key] += 1;
-             }
-             $codesCount += $certificate->getCodesPerItem() * $items[$key];
-             $totalAmount += $certificate->getPriceRegular() * $items[$key];
-             if (!$isSosedi) {
-                 $totalOfferAmount += $certificate->getPriceOffer() * $items[$key];
-             }
-         }
-         $codesCount = ceil($codesCount);
-         $allowedCodesToBuyBalance = false;
-         if ($codeCost !== 0 && $user->isBalanceAllowed($codesCount * $codeCost)) {
-             $codeCost = 0;
-             $allowedCodesToBuyBalance = true;
-         }
-         $order->setAmount($totalOfferAmount + $codesCount * $codeCost);
-         $order->setCodeCost($codeCost);
-         $order->setCodesCount($codesCount);
-         $entityManager->persist($order);
-         $entityManager->flush();
-         $view = CommonUtil::isMobileDevice($request) ? 'Slivki/mobile/delivery/delivery_checkout.html.twig'
-             : 'Slivki/delivery/delivery_checkout.html.twig';
-         $allowedPaymentMethodsForOffer = $onlineOrderPaymentMethodService->getAllowedPaymentMethodsForGiftCertificateOffer($offer, $offerID);
-         $allowedPaymentMethods = [
-             'delivery' => [
-                 PaymentType::ONLINE => 0,
-                 PaymentType::CASH => 0,
-                 PaymentType::TERMINAL => 0,
-                 PaymentType::SLIVKI_PAY => 0,
-             ],
-             'pickup' => [
-                 PaymentType::ONLINE => (int) $allowedPaymentMethodsForOffer->isOnline(),
-                 PaymentType::CASH => (int) $allowedPaymentMethodsForOffer->isCash(),
-                 PaymentType::TERMINAL => (int) $allowedPaymentMethodsForOffer->isTerminal(),
-                 PaymentType::SLIVKI_PAY => (int) $allowedPaymentMethodsForOffer->isSlivkiPay(),
-             ],
-         ];
-         $partnerBePaidService->setOrder($order);
-         $fullOrderAmount = $order->getAmount();
-         if ($allowedCodesToBuyBalance || $codeCost === 0) {
-             $fullOrderAmount += $codeCostRegular * $order->getCodesCount();
-         }
-         $data = [
-             'order' => $order,
-             'offer' => $offer,
-             'codeCost' => $codeCost,
-             'codeCostRegular' => $codeCostRegular,
-             'deliveryPrice' => 0,
-             'offerURL' => $entityManager->getRepository(Seo::class)->getOfferURL($offer->getID())->getMainAlias(),
-             'totalAmount' => $totalAmount,
-             'director' => $offer->getDirectors()->first(),
-             'robotsMeta' => 'noindex, follow',
-             'offerID' => $offerID,
-             'adresses' => null,
-             'showCheckAddressButton' => false,
-             'streetSuggest' => false,
-             'workHourFrom' => 0,
-             'workHourTo' => 0,
-             'showDelivery' => false,
-             'pickupEnabled' => false,
-             'deliveryEnabled' => false,
-             'pickupLocations' => '',
-             'defaultLocationID' => null,
-             'footerOfferConditionID' => $offerID,
-             'pickupDiscount' => 0,
-             'allowedPaymentMethods' => $allowedPaymentMethods,
-             'isGiftCertificate' => true,
-             'pickupDeliveryType' => null,
-             'activeCreditCards' => !$offer->isRecurrentDisabled() ? $creditCardRepository->findActiveByUser($user) : [],
-             'allowedCodesToBuyBalance' => $allowedCodesToBuyBalance,
-             'isBuyOnlyCodeResponse' => $isBuyOnlyCodeResponse,
-             'isSlivkiPayAllowed' => $virtualWalletChecker->availableSlivkiPayForCertificate($fullOrderAmount, $user),
-         ];
-         $data['categoryName'] = 'Подарочные сертификаты';
-         $data['categoryURL'] = $entityManager->getRepository(Seo::class)->getSeoForEntity(SeoRepository::RESOURCE_URL_OFFER_CATEGORY, 24)->getMainAlias();
-         $data['formAction'] = '/gift-certificate/order/pay';
-         $data['giftCertificate'] = true;
-         $content = $this->renderView($view, $data);
-         $response->setContent($content);
-         return $response;
-     }
-     /**
-      * @Route("/gift-certificate/order/pay", name="gift_certificate_order_pay")
-      */
-     public function payAction(
-         Request $request,
-         PartnerBePaidService $partnerBePaidService,
-         PaymentService $paymentService,
-         CreditCardRepositoryInterface $creditCardRepository,
-         SplitPaymentGiftCertificateChecker $splitPaymentGiftCertificateChecker,
-         SubscriptionService $subscriptionService,
-         PhoneNumberUtil $phoneNumberUtil,
-         SeoResourceService $seoResourceService,
-         VirtualWalletChecker $virtualWalletChecker
-     ): JsonResponse {
-         if (!$request->isMethod(Request::METHOD_POST)) {
-             throw $this->createNotFoundException();
-         }
-         $entityManager = $this->getDoctrine()->getManager();
-         $orderID = $request->request->getInt('orderID');
-         $order = $entityManager->find(GiftCertificateOrder::class, $orderID);
-         if (!$order || $order->getUser()->getID() != $this->getUser()->getID() || $order->getStatus() != GiftCertificateOrder::STATUS_INIT) {
-             throw $this->createNotFoundException();
-         }
-         $phone = $request->request->get('phone');
-         if (\mb_strlen($phone) > 0) {
-             $phoneNumberObject = $phoneNumberUtil->parse($phone);
-             if (!$phoneNumberUtil->isValidNumber($phoneNumberObject)) {
-                 return new JsonResponse(['error' => true, 'message' => 'Введен некорректный номер телефона']);
-             }
-         }
-         $order->setComment($request->request->get('comment'));
-         $order->setUsername($request->request->get('name'));
-         $order->setUserPhone($phone);
-         $paymentMethod = $request->request->getInt('paymentMethod', PaymentType::ONLINE);
-         $order->setPaymentType($paymentMethod);
-         $user = $order->getUser();
-         $codeCost = $this->getOfferRepository()->getCodeCost($order->getOffer(), $order->getCodesCount());
-         $resultCodeCost = $codeCost;
-         $subscriber = false;
-         if ($subscriptionService->isSubscriber($user)) {
-             $subscriber = true;
-             $codeCost = 0;
-         }
-         $isBatchCodes = false;
-         if ($user->isBatchCodesAllowed()) {
-             $isBatchCodes = true;
-             $codeCost = 0;
-         }
-         if ($paymentMethod === PaymentType::SLIVKI_PAY) {
-             $codeCostForSlivkiPay = $order->getCodesCount() * (float) $resultCodeCost;
-             try {
-                 $orderAmount = $order->getAmount();
-                 if ($codeCost === 0 || $user->isBalanceAllowed($codeCost * $order->getCodesCount())) {
-                     $orderAmount += $codeCostForSlivkiPay;
-                 }
-                 if (!$virtualWalletChecker->availableSlivkiPayForCertificate($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]);
-         }
-         if ($paymentMethod > PaymentType::ONLINE) {
-             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()
-             ]);
-         }
-         if ($splitPaymentGiftCertificateChecker->isCheck($order)) {
-             $amount = 0;
-             foreach ($order->getOfferOrderDetails() as $orderDetails) {
-                 $amount += $orderDetails->getPurchasePrice();
-             }
-             $order->setAmount($amount);
-         }
-         $partnerBePaidService->setOrder($order);
-         if ($user->isBalanceAllowed($codeCost * $order->getCodeCost())) {
-             $codeCost = 0;
-         }
-         $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']]);
-         }
-         $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);
-         $successModalView = CommonUtil::isMobileDevice($request)
-             ? 'Slivki/mobile/delivery/modal/success.html.twig'
-             : 'Slivki/delivery/modal/success.html.twig';
-         return new JsonResponse([
-             'error' => false,
-             'successModal' => $this->renderView(
-                 $successModalView, [
-                     'offerURL' => $seoResourceService->getOfferSeo($order->getOffer()->getID())->getMainAlias(),
-                 ],
-             ),
-         ]);
-     }
- }
-