src/Controller/MobileApi/UserController.php line 1004

Open in your IDE?
  1. <?php
  2. namespace Slivki\Controller\MobileApi;
  3. use Slivki\Dto\GiftCertificate\Factory\GiftCertificateAddressDtoFactory;
  4. use Slivki\Dto\User\OrderHistory\Factory\TireOrderHistoryDtoFactory;
  5. use Slivki\Dto\User\OrderHistory\FoodOrderProductDto;
  6. use Slivki\Entity\City;
  7. use Slivki\Entity\FoodOrder;
  8. use Slivki\Entity\GiftCertificateOrder;
  9. use Slivki\Entity\MobileUserToken;
  10. use Slivki\Entity\OfferOrder;
  11. use Slivki\Entity\OfferOrderDetails;
  12. use Slivki\Entity\SiteSettings;
  13. use Slivki\Entity\TireOrder;
  14. use Slivki\Entity\User;
  15. use Slivki\Entity\UserBalanceActivity;
  16. use Slivki\Entity\UserBalanceActivityType;
  17. use Slivki\Entity\UserConfirmation;
  18. use Slivki\Entity\UserGroup;
  19. use Slivki\Entity\UserPhone;
  20. use Slivki\Enum\Bonus\Bonus;
  21. use Slivki\Enum\User\UserOrderHistoryType;
  22. use Slivki\Exception\Sms\SmsLimitReachedException;
  23. use Slivki\Factory\QRCode\QRCodeGeneratorDtoFactory;
  24. use Slivki\Factory\User\OrderHistory\FoodOrderHistoryDtoFactory;
  25. use Slivki\Helpers\PhoneNumberHelper;
  26. use Slivki\Message\Command\Bonus\AddBonusCommand;
  27. use Slivki\Repository\User\MobileUserTokenRepositoryInterface;
  28. use Slivki\Repository\UserPhone\UserPhoneRepositoryInterface;
  29. use Slivki\Services\Encoder;
  30. use Slivki\Services\ImageService;
  31. use Slivki\Services\Mailer;
  32. use Slivki\Services\QRCodeGenerator\QRCodeAggregator;
  33. use Slivki\Services\Sms\Security\SmsLimiterService;
  34. use Slivki\Services\Subscription\SubscriptionService;
  35. use Slivki\Services\User\AuthorizationCodeSender;
  36. use Slivki\Services\User\UserPhoneService;
  37. use Slivki\Services\UserGetter;
  38. use Slivki\Util\Logger;
  39. use Slivki\Validator\PhoneNumber\PhoneNumberRegionValidator;
  40. use OpenApi\Annotations as OA;
  41. use Symfony\Component\HttpFoundation\File\UploadedFile;
  42. use Symfony\Component\HttpFoundation\JsonResponse;
  43. use Symfony\Component\HttpFoundation\Request;
  44. use Symfony\Component\HttpFoundation\Response;
  45. use Symfony\Component\HttpKernel\KernelInterface;
  46. use Symfony\Component\Messenger\MessageBusInterface;
  47. use Symfony\Component\Routing\Annotation\Route;
  48. use function random_int;
  49. use function array_map;
  50. class UserController extends MobileApiController
  51. {
  52.     private SubscriptionService $subscriptionService;
  53.     private TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory;
  54.     private FoodOrderHistoryDtoFactory $foodOrderHistoryDtoFactory;
  55.     private MobileUserTokenRepositoryInterface $mobileUserTokenRepository;
  56.     private MessageBusInterface $commandBus;
  57.     public function __construct(
  58.         KernelInterface $kernel,
  59.         SubscriptionService $subscriptionService,
  60.         TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory,
  61.         FoodOrderHistoryDtoFactory $foodOrderHistoryDtoFactory,
  62.         MobileUserTokenRepositoryInterface $mobileUserTokenRepository,
  63.         MessageBusInterface $commandBus
  64.     ) {
  65.         parent::__construct($kernel);
  66.         $this->subscriptionService $subscriptionService;
  67.         $this->tireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory;
  68.         $this->foodOrderHistoryDtoFactory $foodOrderHistoryDtoFactory;
  69.         $this->mobileUserTokenRepository $mobileUserTokenRepository;
  70.         $this->commandBus $commandBus;
  71.     }
  72.     /**
  73.      * Авторизация
  74.      * @Route("/mobile/api/v2/user/login", methods={"POST"});
  75.      * @OA\Response(
  76.      *     response = 200,
  77.      *     description = "Возвращает токен юзера при авторизации по логину и паролю. В случае авторизации по номеру телефона отправляет SMS с кодом.",
  78.      *     @OA\Schema(
  79.      *        @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
  80.      *        @OA\Property(property = "isPartner", type = "boolean", description = "Является ли юзер партнером"),
  81.      *        type="object",
  82.      *     )
  83.      * )
  84.      * @OA\Response(
  85.      *     response = 400,
  86.      *     description = "Неверный email, пароль или номер телефона"
  87.      * )
  88.      * @OA\Response(
  89.      *     response = 404,
  90.      *     description = "Пользователь не найден"
  91.      * )
  92.      * @OA\Response(
  93.      *     response = 429,
  94.      *     description = "Лимит по отправленым sms"
  95.      * )
  96.      * @OA\RequestBody(
  97.      *     required=true,
  98.      *       @OA\MediaType(
  99.      *           mediaType="application/json",
  100.      *           @OA\Schema(
  101.      *               type="object",
  102.      *               @OA\Property(
  103.      *                  property = "login",
  104.      *                  description = "логин или номер телефона",
  105.      *                  type="string",
  106.      *                  example="",
  107.      *               ),
  108.      *               @OA\Property(
  109.      *                  property = "password",
  110.      *                  description = "пароль",
  111.      *                  type="string",
  112.      *                  example="",
  113.      *               ),
  114.      *           ),
  115.      *       ),
  116.      * ),
  117.      * @OA\Tag(name="User")
  118.      * @throws \Exception
  119.      */
  120.     public function loginAction(
  121.         Request $request,
  122.         PhoneNumberRegionValidator $phoneNumberRegionValidator,
  123.         AuthorizationCodeSender $authorizationCodeSender,
  124.         SmsLimiterService $smsLimiterService,
  125.         PhoneNumberHelper $phoneNumberHelper,
  126.         UserPhoneService $userPhoneService,
  127.         UserPhoneRepositoryInterface $userPhoneRepository
  128.     ): JsonResponse {
  129.         $logger Logger::instance('DEBUG');
  130.         if ($request->headers->has('SLIVKI-APP-VERSION') && $request->headers->get('SLIVKI-APP-VERSION') === '1.4.1') {
  131.             $logger->info('SKIP APP LOGIN');
  132.             return new JsonResponse([], Response::HTTP_UPGRADE_REQUIRED);
  133.         }
  134.         $statusCode 200;
  135.         $errorMessage '';
  136.         $data json_decode($request->getContent());
  137.         $logger->info(print_r($datatrue));
  138.         $entityManager $this->getDoctrine()->getManager();
  139.         if (isset($data->password) && $data->password != '') {
  140.             if (!filter_var($data->loginFILTER_VALIDATE_EMAIL)) {
  141.                 return $this->getResponse([], 400'wrong email');
  142.             } else {
  143.                 $user $entityManager->getRepository(User::class)->loadUserByUsername($data->loginfalse);
  144.                 if (!$user || $user->getStatus() == User::STATUS_LOCKED) {
  145.                     return $this->getResponse([], 404'User not found');
  146.                 }
  147.                 $encoder = new Encoder();
  148.                 if (!$encoder->isPasswordValid($user->getPassword(), $data->password$user->getSalt())) {
  149.                     return $this->getResponse([], 400'Wrong password');
  150.                 }
  151.                 $token null;
  152.                 if ($request->headers->has(self::SUPERFOOD_HEADER_NAME)) {
  153.                     $token $user->getToken();
  154.                     if (!$token) {
  155.                         $token uniqid($user->getID(), true);
  156.                         $user->setToken($token);
  157.                         $entityManager->flush();
  158.                     }
  159.                 } else {
  160.                     $token $this->mobileUserTokenRepository->createIfNotExist($user)->getToken();
  161.                     $this->commandBus->dispatch(new AddBonusCommand($user->getID(), Bonus::APP_LOGIN));
  162.                 }
  163.                 $data = [
  164.                     'userToken' => $token,
  165.                     'isPartner' => $user->hasRole(UserGroup::ROLE_SUPPLIER_ID)
  166.                 ];
  167.                 return $this->getResponse($data200'');
  168.             }
  169.         } else {
  170.             $phoneNumber $phoneNumberHelper->convert($data->login);
  171.             $phoneNumberRegionValidator->validate('+' $phoneNumber);
  172.             $userPhone $userPhoneRepository->findConfirmedByPhoneNumber($phoneNumber);
  173.             if ($userPhone instanceof UserPhone) {
  174.                 $user $userPhone->getUser();
  175.                 if (User::STATUS_LOCKED === $user->getStatus()) {
  176.                     return $this->getResponse([], Response::HTTP_NOT_FOUND'User not found');
  177.                 }
  178.             }
  179.             $code random_int(10009999);
  180.             $logger->info(print_r($data->logintrue) . ' -> ' . \json_encode($request->headers->all()));
  181.             try {
  182.                 if ($request->getClientIp() !== null) {
  183.                     $smsLimiterService->limit(
  184.                         $phoneNumberHelper->convert($data->login),
  185.                         $request->getClientIp(),
  186.                     );
  187.                 }
  188.                 $smsLineResponse $authorizationCodeSender->send($phoneNumber$code$request->getHost());
  189.                 if ($smsLineResponse->isError()) {
  190.                     return $this->getResponse([], Response::HTTP_TOO_MANY_REQUESTS$smsLineResponse->getMessage());
  191.                 }
  192.             } catch (SmsLimitReachedException $exception) {
  193.                 return $this->getResponse([], Response::HTTP_TOO_MANY_REQUESTS$errorMessage);
  194.             }
  195.             if (null === $userPhone) {
  196.                 $user = new User();
  197.                 $user->setCreatedOn(new \DateTime());
  198.                 $user->setDefaultPassword();
  199.                 $user->setStatus(User::STATUS_REGISTERED);
  200.                 $entityManager->persist($user);
  201.                 $userPhone $userPhoneService->addUserPhone($user$phoneNumber);
  202.                 $entityManager->getRepository(User::class)->addDirectorGroupToUserByUser($user);
  203.             }
  204.             $userPhone->setAuthCode($code);
  205.             $entityManager->flush();
  206.             return $this->getResponse([], $statusCode$errorMessage);
  207.         }
  208.     }
  209.     /**
  210.      * Google авторизация
  211.      * @Route("/mobile/api/v2/user/login/google", methods={"POST"});
  212.      * @OA\Response(
  213.      *     response = 200,
  214.      *     description = "Возвращает токен юзера при авторизации по google uid.",
  215.      *     @OA\Schema(
  216.      *        @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
  217.      *        type="object",
  218.      *     )
  219.      * )
  220.      * @OA\Response(
  221.      *     response = 400,
  222.      *     description = "uid не найден"
  223.      * )
  224.      * @OA\Response(
  225.      *     response = 404,
  226.      *     description = "Пользователь не найден"
  227.      * )
  228.      * @OA\RequestBody(
  229.      *     required=true,
  230.      *       @OA\MediaType(
  231.      *           mediaType="application/json",
  232.      *           @OA\Schema(
  233.      *               type="object",
  234.      *               @OA\Property(
  235.      *                  property = "uid",
  236.      *                  description = "uid",
  237.      *                  type="string",
  238.      *                  example="",
  239.      *               ),
  240.      *           ),
  241.      *       ),
  242.      * ),
  243.      * @OA\Tag(name="User")
  244.      */
  245.     public function googleLoginAction(Request $request) {
  246.         $data json_decode($request->getContent());
  247.         if (!isset($data->uid)) {
  248.             return $this->getResponse([], 400);
  249.         }
  250.         Logger::instance('MOBILE API')->info('UID ' $data->uid);
  251.         return $this->getResponse([], 404);
  252.     }
  253.     /**
  254.      * Проверка кода авторизации
  255.      * @Route("/mobile/api/v2/user/check-code", methods={"POST"});
  256.      * @OA\Response(
  257.      *     response = 200,
  258.      *     description = "Возвращает токен юзера в случае успеха.",
  259.      *     @OA\Schema(
  260.      *        @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
  261.      *        type="object",
  262.      *     )
  263.      * )
  264.      * @OA\Response(
  265.      *     response = 404,
  266.      *     description = "Номер телефона не найден"
  267.      * )
  268.      * @OA\RequestBody(
  269.      *     required=true,
  270.      *       @OA\MediaType(
  271.      *           mediaType="application/json",
  272.      *           @OA\Schema(
  273.      *               type="object",
  274.      *               @OA\Property(
  275.      *                  property = "phoneNumber",
  276.      *                  description = "номер телефона",
  277.      *                  type="string",
  278.      *                  example="",
  279.      *               ),
  280.      *               @OA\Property(
  281.      *                  property = "code",
  282.      *                  description = "код авторизации",
  283.      *                  type="integer",
  284.      *                  example="",
  285.      *               ),
  286.      *           ),
  287.      *       ),
  288.      * ),
  289.      * @OA\Tag(name="User")
  290.      */
  291.     public function checkCode(
  292.         Request $request,
  293.         UserPhoneService $userPhoneService,
  294.         PhoneNumberHelper $phoneNumberHelper,
  295.         UserPhoneRepositoryInterface $userPhoneRepository
  296.     ): JsonResponse {
  297.         $entityManager $this->getDoctrine()->getManager();
  298.         $data json_decode($request->getContent());
  299.         $phoneNumber $phoneNumberHelper->convert($data->phoneNumber);
  300.         $userPhone $userPhoneRepository->findByPhoneNumberAndAuthCode($phoneNumber$data->code);
  301.         if (null === $userPhone) {
  302.             return $this->getResponse([], Response::HTTP_NOT_FOUND);
  303.         }
  304.         if (!$userPhone->isConfirmed()) {
  305.             $userPhoneService->confirmUserPhone($userPhone);
  306.             $user $userPhone->getUser();
  307.             if ($user->getStatus() === User::STATUS_REGISTERED) {
  308.                 $user->setStatus(User::STATUS_CONFIRMED);
  309.             }
  310.             $entityManager->flush();
  311.         }
  312.         if ($request->headers->has(self::SUPERFOOD_HEADER_NAME)) {
  313.             $token $user->getToken();
  314.             if (!$token) {
  315.                 $token uniqid($user->getID(), true);
  316.                 $user->setToken($token);
  317.                 $entityManager->flush();
  318.             }
  319.         } else {
  320.             $user $userPhone->getUser();
  321.             $token $this->mobileUserTokenRepository->createIfNotExist($user)->getToken();
  322.             $this->commandBus->dispatch(new AddBonusCommand($user->getID(), Bonus::APP_LOGIN));
  323.         }
  324.         return $this->getResponse(['userToken' => $token], 200);
  325.     }
  326.     /**
  327.      * Проверка токена
  328.      * @Route("/mobile/api/v2/user/check", methods={"GET"});
  329.      * @OA\Response(
  330.      *     response = 401,
  331.      *     description = "Пользователь не найден"
  332.      * )
  333.      * @OA\Parameter(
  334.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  335.      *     in = "header",
  336.      *     description = "Токен юзера",
  337.      *     required = true,
  338.      *     @OA\Schema(type="string"),
  339.      *)
  340.      * @OA\Tag(name="User")
  341.      */
  342.     public function tokenCheckAction(): JsonResponse
  343.     {
  344.         return $this->getResponse([], 200);
  345.     }
  346.     /**
  347.      * Баланс пользователя
  348.      * @Route("/mobile/api/v2/user/balance", methods={"GET"});
  349.      * @OA\Response(
  350.      *     response = 200,
  351.      *     description = "Баланс пользователя",
  352.      *     @OA\Schema(
  353.      *        @OA\Property(property = "balance", type = "decimal", description = "баланс пользователя"),
  354.      *        @OA\Property(property = "isHot", type = "boolean", description = "есть ли непогашенные коды"),
  355.      *        type="object",
  356.      *     )
  357.      * )
  358.      * @OA\Response(
  359.      *     response = 401,
  360.      *     description = "Пользователь не найден"
  361.      * )
  362.      * @OA\Parameter(
  363.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  364.      *     in = "header",
  365.      *     description = "Токен юзера",
  366.      *     required = true,
  367.      *     @OA\Schema(type="string"),
  368.      *)
  369.      * @OA\Tag(name="User")
  370.      */
  371.     public function getBalanceAction(UserGetter $userGetter): JsonResponse
  372.     {
  373.         $user $userGetter->get();
  374.         $isHot false;
  375.         $entityManager =  $this->getDoctrine()->getManager();
  376.         $dql "select offerOrderDetails from Slivki:OfferOrderDetails offerOrderDetails
  377.             join offerOrderDetails.offerOrder offerOrder
  378.             where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder and offerOrderDetails.used = false
  379.             and offerOrderDetails.codeActiveTill >= CURRENT_TIMESTAMP() and offerOrderDetails.codeActiveTill <= DATE_ADD(CURRENT_TIMESTAMP(),3, 'day')
  380.             order by offerOrderDetails.ID desc";
  381.         $query $entityManager->createQuery($dql);
  382.         $query->setParameter('user'$user);
  383.         $codes $query->getResult();
  384.         if (count($codes) > 0) {
  385.             $isHot true;
  386.         }
  387.         return $this->getResponse(['balance' => $user->getFullBalance(), 'isHot' => $isHot], 200);
  388.     }
  389.     /**
  390.      * @Route("/mobile/api/v2/user", methods={"GET"});
  391.      * @OA\Response(
  392.      *     response=200,
  393.      *     description="Информация о пользователе",
  394.      *     @OA\Schema(
  395.      *        @OA\Property(property="ID", type="integer", description="User Id"),
  396.      *        @OA\Property(property="email", type="varchar", description="email пользователя"),
  397.      *        @OA\Property(property="phoneNumber", type="varchar", description="номер телефона пользователя"),
  398.      *        @OA\Property(property="name", type="varchar", description="имя пользователя"),
  399.      *        @OA\Property(property="cityID", type="object", description="город пользователя",
  400.      *          @OA\Property(property="ID", type="integer", description="ID города"),
  401.      *          @OA\Property(property="name", type="varchar", description="название города"),
  402.      *          @OA\Property(property="latitude", type="number", description="Широта"),
  403.      *          @OA\Property(property="longitude", type="number", description="Долгота"),
  404.      *        ),
  405.      *        @OA\Property(property="balance", type="decimal", description="баланс пользователя"),
  406.      *        @OA\Property(property="profileImage", type="varchar", description="изображение пользователя"),
  407.      *        @OA\Property(property="isHot", type="boolean", description="есть ли непогашенные коды"),
  408.      *        @OA\Property(property="activeRoles", type="object", description="Не скрытые роли пользователя"),
  409.      *        @OA\Property(property="isSubscriber", type="object", description="Является ли юзер подписчиком"),
  410.      *        @OA\Property(property="freeCodesCount", type="integer", description="Количество бесплатних кодов (null = неограниченно)"),
  411.      *        @OA\Property(property="tariff", type="text", description="Название тарифа"),
  412.      *        type="object",
  413.      *     )
  414.      * )
  415.      * @OA\Response(
  416.      *     response=404,
  417.      *     description="Пользователь не найден"
  418.      * )
  419.      * @OA\Parameter(
  420.      *     name="HTTP-SLIVKi-USER-TOKEN",
  421.      *     in="header",
  422.      *     description="Токен юзера",
  423.      *     required=true,
  424.      *     @OA\Schema(type="string"),
  425.      *)
  426.      * @OA\Tag(name="User")
  427.      */
  428.     public function getUserAction(
  429.         ImageService $imageService,
  430.         SubscriptionService $subscriptionService,
  431.         UserGetter $userGetter
  432.     ): JsonResponse {
  433.         Logger::instance('SS-DEBUG')->info('START');
  434.         $user $userGetter->get();
  435.         $city $user->getCity();
  436.         $phoneNumber $user->getPhones()->first();
  437.         $phoneNumber $phoneNumber $phoneNumber->getPhoneNumber() : '';
  438.         $profileImageMedia $user->getProfileImageMedia();
  439.         $profileImage ImageService::DEFAULT_AVATAR;
  440.         if ($profileImageMedia) {
  441.             $profileImage $imageService->getImageURL($profileImageMedia100100);
  442.         }
  443.         $cityData = [
  444.             'ID' => 1,
  445.             'name' =>'Минск',
  446.             'latitude' => 53.902284,
  447.             'longitude' => 27.561831,
  448.         ];
  449.         if ($city) {
  450.             $cityData = [
  451.                 'ID' => $city->getID(),
  452.                 'name' => $city->getName(),
  453.                 'latitude' => null !== $city->getCoordinate() ? $city->getCoordinate()->getLatitude() : null,
  454.                 'longitude' => null !== $city->getCoordinate() ? $city->getCoordinate()->getLongitude() : null,
  455.             ];
  456.         }
  457.         $isHot false;
  458.         $entityManager =  $this->getDoctrine()->getManager();
  459.         $dql "select offerOrderDetails,offerOrder from Slivki:OfferOrderDetails offerOrderDetails
  460.             join offerOrderDetails.offerOrder offerOrder
  461.             where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder and offerOrderDetails.used = false
  462.             and offerOrderDetails.codeActiveTill >= CURRENT_TIMESTAMP() and offerOrderDetails.codeActiveTill <= DATE_ADD(CURRENT_TIMESTAMP(),3, 'day')
  463.             order by offerOrderDetails.ID desc";
  464.         $query $entityManager->createQuery($dql);
  465.         $query->setParameter('user'$user);
  466.         $codes $query->getResult();
  467.         if (count($codes) > 0) {
  468.             $isHot true;
  469.         }
  470.         $subscription $subscriptionService->getSubscription($user);
  471.         $freeCodesCount $subscriptionService->isSubscriber($user) ? : -1;
  472.         if ($subscriptionService->isSubscriber($user) && null === $subscription->getNumberOfCodes()) {
  473.             $freeCodesCount null;
  474.         }
  475.         $data = [
  476.             'ID' => $user->getID(),
  477.             'email' => $user->getEmail(),
  478.             'phoneNumber' => $phoneNumber,
  479.             'name' => $user->getFirstName(),
  480.             'cityID' => $cityData,
  481.             'balance' => $user->getFullBalance(),
  482.             'profileImage' => $this->getParameter('base_url') . $profileImage,
  483.             'isHot' => $isHot,
  484.             'roles' => $user->getActiveRoles(),
  485.             'isSubscriber' => $subscriptionService->isSubscriber($user),
  486.             'freeCodesCount' => $freeCodesCount,
  487.             'tariff' => $subscriptionService->isSubscriber($user) ? $subscription->getPlanResponse()->getName() : ''
  488.         ];
  489.         return $this->getResponse($data200);
  490.     }
  491.     /**
  492.      * Изменить имя
  493.      * @Route("/mobile/api/v2/user/update/name", methods={"PUT"});
  494.      * @OA\Response(
  495.      *     response = 400,
  496.      *     description = "Имя не может быть пустым"
  497.      * )
  498.      * @OA\Response(
  499.      *     response = 404,
  500.      *     description = "Пользователь не найден"
  501.      * )
  502.      * @OA\RequestBody(
  503.      *     required=true,
  504.      *       @OA\MediaType(
  505.      *           mediaType="application/json",
  506.      *           @OA\Schema(
  507.      *               type="object",
  508.      *               @OA\Property(
  509.      *                  property = "name",
  510.      *                  description = "Новое имя",
  511.      *                  type="string",
  512.      *                  example="",
  513.      *               ),
  514.      *           ),
  515.      *       ),
  516.      * ),
  517.      * @OA\Parameter(
  518.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  519.      *     in = "header",
  520.      *     description = "Токен юзера",
  521.      *     required = true,
  522.      *     @OA\Schema(type="string"),
  523.      *)
  524.      * @OA\Tag(name="User")
  525.      */
  526.     public function updateUserNameAction(Request $requestUserGetter $userGetter): JsonResponse
  527.     {
  528.         $user $userGetter->get();
  529.         $data json_decode($request->getContent());
  530.         $name trim($data->name);
  531.         if ($name == '') {
  532.             return $this->getResponse([], 400);
  533.         }
  534.         $user->setFirstName($name);
  535.         $this->getDoctrine()->getManager()->flush();
  536.         return $this->getResponse([], 200);
  537.     }
  538.     /**
  539.      * Изменить город
  540.      * @Route("/mobile/api/v2/user/update/city", methods={"PUT"});
  541.      * @OA\Response(
  542.      *     response = 400,
  543.      *     description = "Город не найден"
  544.      * )
  545.      * @OA\Response(
  546.      *     response = 404,
  547.      *     description = "Пользователь не найден"
  548.      * )
  549.      * @OA\RequestBody(
  550.      *     required=true,
  551.      *       @OA\MediaType(
  552.      *           mediaType="application/json",
  553.      *           @OA\Schema(
  554.      *               type="object",
  555.      *               @OA\Property(
  556.      *                  property = "cityID",
  557.      *                  description = "ID города",
  558.      *                  type="integer",
  559.      *                  example="",
  560.      *               ),
  561.      *           ),
  562.      *       ),
  563.      * ),
  564.      * @OA\Parameter(
  565.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  566.      *     in = "header",
  567.      *     description = "Токен юзера",
  568.      *     required = true,
  569.      *     @OA\Schema(type="string"),
  570.      *)
  571.      * @OA\Tag(name="User")
  572.      */
  573.     public function updateUserCityAction(Request $requestUserGetter $userGetter) {
  574.         $user $userGetter->get();
  575.         $data json_decode($request->getContent());
  576.         $entityManager $this->getDoctrine()->getManager();
  577.         $city $entityManager->find(City::class, $data->cityID);
  578.         if (!$city) {
  579.             return $this->getResponse([], 400'City not found');
  580.         }
  581.         $user->setCity($city);
  582.         $entityManager->flush();
  583.         return $this->getResponse([], 200);
  584.     }
  585.     /**
  586.      * Изменить пароль
  587.      * @Route("/mobile/api/v2/user/update/password", methods={"PUT"});
  588.      * @OA\Response(
  589.      *     response = 400,
  590.      *     description = "Пароль слишком короткий"
  591.      * )
  592.      * @OA\Response(
  593.      *     response = 403,
  594.      *     description = "Неверный текущий пароль"
  595.      * )
  596.      * @OA\Response(
  597.      *     response = 404,
  598.      *     description = "Пользователь не найден"
  599.      * )
  600.      * @OA\RequestBody(
  601.      *     required=true,
  602.      *       @OA\MediaType(
  603.      *           mediaType="application/json",
  604.      *           @OA\Schema(
  605.      *               type="object",
  606.      *               @OA\Property(
  607.      *                  property = "password",
  608.      *                  description = "новый пароль",
  609.      *                  type="string",
  610.      *                  example="",
  611.      *               ),
  612.      *               @OA\Property(
  613.      *                  property = "currentPassword",
  614.      *                  description = "текущий пароль",
  615.      *                  type="string",
  616.      *                  example="",
  617.      *               ),
  618.      *           ),
  619.      *       ),
  620.      * ),
  621.      * @OA\Parameter(
  622.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  623.      *     in = "header",
  624.      *     description = "Токен юзера",
  625.      *     required = true,
  626.      *     @OA\Schema(type="string"),
  627.      *)
  628.      * @OA\Tag(name="User")
  629.      */
  630.     public function updateUserPasswordAction(Request $requestUserGetter $userGetter)
  631.     {
  632.         $user $userGetter->get();
  633.         $data json_decode($request->getContent());
  634.         $password trim($data->password);
  635.         $currentPassword trim($data->currentPassword);
  636.         if ($currentPassword != $user->getPasswordClear()) {
  637.             return $this->getResponse([], 403'Wrong current password');
  638.         }
  639.         if (mb_strlen($password) < 6) {
  640.             return $this->getResponse([], 400'Password too short');
  641.         }
  642.         $user->encryptPassword($password);
  643.         $this->getDoctrine()->getManager()->flush();
  644.         return $this->getResponse([], 200);
  645.     }
  646.     /**
  647.      * Отправить код на email
  648.      * @Route("/mobile/api/v2/user/email-code/send", methods={"POST"});
  649.      * @OA\Response(
  650.      *     response = 403,
  651.      *     description = "Неверный email"
  652.      * )
  653.      * @OA\Response(
  654.      *     response = 404,
  655.      *     description = "Пользователь не найден"
  656.      * )
  657.      * @OA\RequestBody(
  658.      *     required=true,
  659.      *       @OA\MediaType(
  660.      *           mediaType="application/json",
  661.      *           @OA\Schema(
  662.      *               type="object",
  663.      *               @OA\Property(
  664.      *                  property = "email",
  665.      *                  description = "email пользователя",
  666.      *                  type="string",
  667.      *                  example="",
  668.      *               ),
  669.      *           ),
  670.      *       ),
  671.      * ),
  672.      * @OA\Parameter(
  673.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  674.      *     in = "header",
  675.      *     description = "Токен юзера",
  676.      *     required = true,
  677.      *     @OA\Schema(type="string"),
  678.      *)
  679.      * @OA\Tag(name="User")
  680.      */
  681.     public function sendEmailCode(Request $requestMailer $mailerUserGetter $userGetter)
  682.     {
  683.         $user $userGetter->get();
  684.         $data json_decode($request->getContent());
  685.         $email trim(mb_strtolower($data->email));
  686.         $entityManager $this->getDoctrine()->getManager();
  687.         $result $entityManager->getRepository(User::class)->findByEmail($email);
  688.         if (count($result) > 0) {
  689.             return $this->getResponse([], 403);
  690.         }
  691.         $code rand(10009999);
  692.         $confirmation = new UserConfirmation();
  693.         $confirmation->setUserID($user->getID());
  694.         $confirmation->setEmail($email);
  695.         $confirmation->setAuthCode($code);
  696.         $entityManager->persist($confirmation);
  697.         $entityManager->flush();
  698.         $message $mailer->createMessage();
  699.         $message->setSubject('Подтверждение адреса email');
  700.         $message->setFrom('info@slivki.by''Slivki.by');
  701.         $message->setTo($email);
  702.         $message->setBody('Код подтверждения: ' $code);
  703.         $mailer->send($message);
  704.         return $this->getResponse([], 200);
  705.     }
  706.     /**
  707.      * Изменить email
  708.      * @Route("/mobile/api/v2/user/update/email", methods={"PUT"});
  709.      * @OA\Response(
  710.      *     response = 403,
  711.      *     description = "Неверный email"
  712.      * )
  713.      * @OA\Response(
  714.      *     response = 404,
  715.      *     description = "Пользователь не найден"
  716.      * )
  717.      * @OA\RequestBody(
  718.      *     required=true,
  719.      *       @OA\MediaType(
  720.      *           mediaType="application/json",
  721.      *           @OA\Schema(
  722.      *               type="object",
  723.      *               @OA\Property(
  724.      *                  property = "email",
  725.      *                  description = "email пользователя",
  726.      *                  type="string",
  727.      *                  example="",
  728.      *               ),
  729.      *               @OA\Property(
  730.      *                  property = "code",
  731.      *                  description = "код подтверждения",
  732.      *                  type="integer",
  733.      *                  example="",
  734.      *               ),
  735.      *           ),
  736.      *       ),
  737.      * ),
  738.      * @OA\Parameter(
  739.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  740.      *     in = "header",
  741.      *     description = "Токен юзера",
  742.      *     required = true,
  743.      *     @OA\Schema(type="string"),
  744.      *)
  745.      * @OA\Tag(name="User")
  746.      */
  747.     public function updateUserEmailAction(Request $requestUserGetter $userGetter)
  748.     {
  749.         $user $userGetter->get();
  750.         $data json_decode($request->getContent());
  751.         $email trim(mb_strtolower($data->email));
  752.         $entityManager $this->getDoctrine()->getManager();
  753.         $result $entityManager->getRepository(UserConfirmation::class)->findBy(
  754.             [
  755.                 'userID' => $user->getID(),
  756.                 'email' => $email,
  757.                 'authCode' => $data->code
  758.             ]
  759.         );
  760.         if (count($result) == 0) {
  761.             return $this->getResponse([], 403);
  762.         }
  763.         $user->setEmail($email);
  764.         $entityManager->remove($result[0]);
  765.         $entityManager->flush();
  766.         return $this->getResponse([], 200);
  767.     }
  768.     /**
  769.      * Отправить код по номеру телефона
  770.      * @Route("/mobile/api/v2/user/phone-code/send", methods={"POST"});
  771.      * @OA\Response(
  772.      *     response = 403,
  773.      *     description = "Неверный номер телефона"
  774.      * )
  775.      * @OA\Response(
  776.      *     response = 404,
  777.      *     description = "Пользователь не найден"
  778.      * )
  779.      * @OA\RequestBody(
  780.      *     required=true,
  781.      *       @OA\MediaType(
  782.      *           mediaType="application/json",
  783.      *           @OA\Schema(
  784.      *               type="object",
  785.      *               @OA\Property(
  786.      *                  property = "phoneNumber",
  787.      *                  description = "Номер телефона пользователя",
  788.      *                  type="string",
  789.      *                  example="",
  790.      *               ),
  791.      *           ),
  792.      *       ),
  793.      * ),
  794.      * @OA\Parameter(
  795.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  796.      *     in = "header",
  797.      *     description = "Токен юзера",
  798.      *     required = true,
  799.      *     @OA\Schema(type="string"),
  800.      *)
  801.      * @OA\Tag(name="User")
  802.      */
  803.     public function sendPhoneCode(
  804.         Request $request,
  805.         UserGetter $userGetter,
  806.         AuthorizationCodeSender $authorizationCodeSender,
  807.         UserPhoneService $userPhoneService
  808.     ): JsonResponse {
  809.         $user $userGetter->get();
  810.         $data json_decode($request->getContent());
  811.         $logger Logger::instance('DEBUG');
  812.         $logger->info(print_r($datatrue));
  813.         $phoneNumber trim($data->phoneNumber);
  814.         $logger->info(print_r($phoneNumbertrue));
  815.         $entityManager $this->getDoctrine()->getManager();
  816.         $result $entityManager->getRepository(UserPhone::class)->findBy(['phoneNumber' => $phoneNumber'confirmed' => true]);
  817.         if (count($result) > 0) {
  818.             foreach ($result as $row) {
  819.                 if ($row->getUser() !== $user) {
  820.                     $logger->info('403');
  821.                     return $this->getResponse([], 403);
  822.                 }
  823.             }
  824.         }
  825.         $code random_int(10009999);
  826.         $userPhone =  $entityManager->getRepository(UserPhone::class)->findOneBy(['user' => $user]);
  827.         if (!$userPhone) {
  828.             $userPhoneService->addUserPhone($user$phoneNumber);
  829.         }
  830.         $userPhone->setAuthCode($code);
  831.         $entityManager->flush();
  832.         $authorizationCodeSender->send($phoneNumber$code$request->getHost());
  833.         return $this->getResponse([], 200);
  834.     }
  835.     /**
  836.      * Изменить номер телефона
  837.      * @Route("/mobile/api/v2/user/update/phone", methods={"PUT"});
  838.      * @OA\Response(
  839.      *     response = 403,
  840.      *     description = "Неверный номер телефона"
  841.      * )
  842.      * @OA\Response(
  843.      *     response = 404,
  844.      *     description = "Пользователь не найден"
  845.      * )
  846.      * @OA\RequestBody(
  847.      *     required=true,
  848.      *       @OA\MediaType(
  849.      *           mediaType="application/json",
  850.      *           @OA\Schema(
  851.      *               type="object",
  852.      *               @OA\Property(
  853.      *                  property = "phoneNumber",
  854.      *                  description = "Номер телефона пользователя",
  855.      *                  type="string",
  856.      *                  example="",
  857.      *               ),
  858.      *               @OA\Property(
  859.      *                  property = "code",
  860.      *                  description = "код подтверждения",
  861.      *                  type="integer",
  862.      *                  example="",
  863.      *               ),
  864.      *           ),
  865.      *       ),
  866.      * ),
  867.      * @OA\Parameter(
  868.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  869.      *     in = "header",
  870.      *     description = "Токен юзера",
  871.      *     required = true,
  872.      *     @OA\Schema(type="string"),
  873.      *)
  874.      * @OA\Tag(name="User")
  875.      */
  876.     public function updatePhoneAction(
  877.         Request $request,
  878.         UserGetter $userGetter,
  879.         UserPhoneService $userPhoneService
  880.     ): JsonResponse {
  881.         $user $userGetter->get();
  882.         $data json_decode($request->getContent());
  883.         $phoneNumber trim($data->phoneNumber);
  884.         $entityManager $this->getDoctrine()->getManager();
  885.         $userPhone $entityManager->getRepository(UserPhone::class)->findOneBy(['user' => $user'authCode' => $data->code]);
  886.         if (!$userPhone || $phoneNumber == '') {
  887.             return $this->getResponse([], 403);
  888.         }
  889.         $userPhoneService->changePhoneNumber($userPhone$phoneNumber);
  890.         return $this->getResponse([], 200);
  891.     }
  892.     /**
  893.      * Список промокодов пользователя
  894.      * @Route("/mobile/api/v2/user/codes/{pageNumber}", methods={"GET"});
  895.      * @OA\Response(
  896.      *     response=200,
  897.      *     description="Список промокодов пользователя",
  898.      *     @OA\JsonContent(
  899.      *        @OA\Property(property="ID", type="integer", description="ID кода"),
  900.      *        @OA\Property(property="offerID", type="integer", description="ID акции"),
  901.      *        @OA\Property(property="offerActive", type="boolean", description="Флаг активности акции"),
  902.      *        @OA\Property(property="offerName", type="varchar", description="Название акции"),
  903.      *        @OA\Property(property="code", type="varchar", description="Промокод"),
  904.      *        @OA\Property(property="codeCreatedAt", type="datetime", description="Дата покупки промокода"),
  905.      *        @OA\Property(property="isUsed", type="boolean", description="Флаг использования промокода пользователем"),
  906.      *        @OA\Property(property="usedAt", type="datetime", description="Дата использования промокода пользователем"),
  907.      *        @OA\Property(property="isUsedBySupplier", type="boolean", description="Флаг использования промокода поставщиком"),
  908.      *        @OA\Property(property="codeActiveTill", type="boolean", description="Дата до которой можно использовать промокод"),
  909.      *        @OA\Property(property="offerType", type="integer", description="тип оффера. 0 обычный, 1 - онлайн ордер, 2 оноайл ордер без возможности купить код отдельно, 3 трайпл, 4 шм, 5 сертификаты"),
  910.      *        @OA\Property(property="companyName", type="string", description="Название компании"),
  911.      *        type="object",
  912.      *        example = {
  913.      *          "ID": 1,
  914.      *          "offerID": 1,
  915.      *          "offerActive": true,
  916.      *          "offerName": "Название акции",
  917.      *          "code": "1234-123",
  918.      *          "codeCreatedAt": "2020-01-01 01:00:03",
  919.      *          "isUsed": true,
  920.      *          "usedAt": "2020-01-03 02:00:03",
  921.      *          "isUsedBySupplier": true,
  922.      *          "codeActiveTill": "2020-01-01 01:00:03",
  923.      *          "offerType": 1,
  924.      *          "offerType": "Название компании",
  925.      *        }
  926.      *     )
  927.      * )
  928.      * @OA\Parameter(
  929.      *     name="pageNumber",
  930.      *     in="path",
  931.      *     description="Номер страницы",
  932.      *     @OA\Schema(type="integer"),
  933.      * )
  934.      * @OA\Tag(name="User")
  935.      */
  936.     public function getUserCodes(
  937.         ImageService $imageService,
  938.         UserGetter $userGetter,
  939.         QRCodeAggregator $codeAggregator,
  940.         QRCodeGeneratorDtoFactory $codeGeneratorDtoFactory,
  941.         int $pageNumber
  942.     ): JsonResponse {
  943.         $user $userGetter->get();
  944.         $entityManager $this->getDoctrine()->getManager();
  945.         $limit 10;
  946.         $offset $limit * ($pageNumber 1);
  947.         $dql "select offerOrderDetails,offerOrder,offer from Slivki:OfferOrderDetails offerOrderDetails
  948.             join offerOrderDetails.offerOrder offerOrder
  949.             join offerOrder.offer offer
  950.             where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder
  951.             and not offerOrder instance of Slivki\Entity\FoodOrder
  952.             and not offerOrder instance of Slivki\Entity\GiftCertificateOrder
  953.             and not offerOrder instance of Slivki\Entity\SubscriptionOrder
  954.             and not offerOrder instance of Slivki\Entity\TireOrder
  955.             order by offerOrderDetails.ID desc";
  956.         $query $entityManager->createQuery($dql);
  957.         $query->setParameter('user'$user);
  958.         $query->setMaxResults($limit 1);
  959.         $query->setFirstResult($offset);
  960.         $codes = [];
  961.         /** @var OfferOrderDetails $offerOrderDetail */
  962.         foreach ($query->getResult() as $offerOrderDetail) {
  963.             $offerOrder $offerOrderDetail->getOfferOrder();
  964.             $offer $offerOrder->getOffer();
  965.             $director $offer->findFirstDirector();
  966.             $encoder null !== $offer $codeAggregator->aggregate((int) $offer->getID()) : null;
  967.             $messageEncode $encoder !== null $encoder->encode($codeGeneratorDtoFactory->create($offerOrderDetailtrue)) : null;
  968.             $codes[] = [
  969.                 'ID' => $offerOrderDetail->getID(),
  970.                 'offerID' => $offer->getID(),
  971.                 'offerActive' => $offer->isActive(),
  972.                 'offerName' => $offer->getTitle(),
  973.                 'imageURL' => 'https://www.slivki.by' . ($offer->getTeaserMedia() ? $imageService->getImageURL($offer->getTeaserMedia(), 500324) : ImageService::FALLBACK_IMAGE),
  974.                 'code' => $offerOrderDetail->getCode(),
  975.                 'isUsed' => $offerOrderDetail->isUsed(),
  976.                 'isUsedBySupplier' => $offerOrderDetail->isMarkedUsedBySupplier(),
  977.                 'codeCreatedAt' => $offerOrderDetail->getCreatedOn()->format('Y-m-d H:i:s'),
  978.                 'useMessageEncode' => (bool) $messageEncode,
  979.                 'messageEncode' => $messageEncode,
  980.                 'usedAt' => !$offerOrderDetail->getMarkedUsedBySupplierChecktime() ? null $offerOrderDetail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s'),
  981.                 'codeActiveTill' => $offerOrderDetail->getCodeActiveTill() ? $offerOrderDetail->getCodeActiveTill()->format('d-m-Y H:i:s') : '',
  982.                 'offerType' => $offer->getOfferType(),
  983.                 'allowedOnlineOrderTypes' => $offer->getAllowedOnlineOrderTypesOnApp(),
  984.                 'companyName' => null === $director '' $director->getName(),
  985.             ];
  986.         }
  987.         $result['isLast'] = count($codes) <= $limit;
  988.         $result['codes'] = array_slice($codes0$limit);
  989.         return $this->getResponse($result200);
  990.     }
  991.     /**
  992.      * Изменить пароль
  993.      * @Route("/mobile/api/v2/user/reset-password", methods={"POST"});
  994.      * @OA\Response(
  995.      *     response = 403,
  996.      *     description = "Не удалось отправить пароль"
  997.      * )
  998.      * @OA\Response(
  999.      *     response = 404,
  1000.      *     description = "Пользователь не найден"
  1001.      * )
  1002.      * @OA\Parameter(
  1003.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  1004.      *     in = "header",
  1005.      *     description = "Токен юзера",
  1006.      *     required = true,
  1007.      *     @OA\Schema(type="string"),
  1008.      *)
  1009.      * @OA\Tag(name="User")
  1010.      */
  1011.     public function resetUserPasswordAction(Request $requestMailer $mailerUserGetter $userGetter)
  1012.     {
  1013.         $user $userGetter->get();
  1014.         if (!$this->sendPassword($mailer$user->getEmail())) {
  1015.             return $this->getResponse([], 403);
  1016.         }
  1017.         return $this->getResponse([], 200);
  1018.     }
  1019.     /**
  1020.      * @Route("/mobile/api/v2/user/code/set-used", methods={"POST"});
  1021.      * @OA\Response(
  1022.      *     response = 200,
  1023.      *     description = "Установка флага 'использован' коду",
  1024.      *     @OA\Schema(
  1025.      *        @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
  1026.      *        type="object",
  1027.      *        example = {"userBalance": 7.50}
  1028.      *     )
  1029.      * )
  1030.      * @OA\Response(
  1031.      *     response = 401,
  1032.      *     description = "Юзер ненайден"
  1033.      * )
  1034.      * @OA\Response(
  1035.      *     response = 403,
  1036.      *     description = "Промокод истек по времени или погашен партнером"
  1037.      * )
  1038.      * @OA\Response(
  1039.      *     response = 404,
  1040.      *     description = "Промокод ненайден"
  1041.      * )
  1042.      * @OA\Parameter(
  1043.      *     name = "offerOrderDetailID",
  1044.      *     in = "query",
  1045.      *     description = "ID заказа",
  1046.      *     required = true,
  1047.      *     @OA\Schema(type="integer"),
  1048.      *)
  1049.      * @OA\Parameter(
  1050.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  1051.      *     in = "header",
  1052.      *     description = "Токен юзера",
  1053.      *     required = true,
  1054.      *     @OA\Schema(type="string"),
  1055.      *)
  1056.      * @OA\Tag(name="User")
  1057.      * )
  1058.      */
  1059.     public function setUserCodeUsed(Request $requestUserGetter $userGetter)
  1060.     {
  1061.         $userGetter->get();
  1062.         $data json_decode($request->getContent());
  1063.         $offerOrderDetailID $data->offerOrderDetailID;
  1064.         $code $this->getOfferOrderDetailsRepository()->find($offerOrderDetailID);
  1065.         $now = new \DateTime();
  1066.         if (!$code) {
  1067.             return $this->getResponse([], 404);
  1068.         }
  1069.         if ($code->isMarkedUsedBySupplier() || $code->getCodeActiveTill() < $now) {
  1070.             return $this->getResponse([], 403);
  1071.         }
  1072.         if ($code->isUsed()) {
  1073.             $code->setUsed(false);
  1074.         } else {
  1075.             $code->setUsed(true);
  1076.         }
  1077.         $this->getDoctrine()->getManager()->flush();
  1078.         return $this->getResponse([], 200);
  1079.     }
  1080.     /**
  1081.      * Добавить в избранные
  1082.      * @Route("/mobile/api/v2/user/favorite/add", methods={"POST"});
  1083.      * @OA\Response(
  1084.      *     response = 200,
  1085.      *     description = "Добавление акции в избранное",
  1086.      *     @OA\Schema(
  1087.      *        @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
  1088.      *        type="object",
  1089.      *        example = {"userBalance": 7.50}
  1090.      *     )
  1091.      * )
  1092.      * @OA\Response(
  1093.      *     response = 404,
  1094.      *     description = "Юзер или акция ненайдена"
  1095.      * )
  1096.      * @OA\Parameter(
  1097.      *     name = "offerID",
  1098.      *     in = "query",
  1099.      *     description = "ID акции",
  1100.      *     required = true,
  1101.      *     @OA\Schema(type="integer"),
  1102.      *)
  1103.      * @OA\Parameter(
  1104.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  1105.      *     in = "header",
  1106.      *     description = "Токен юзера",
  1107.      *     required = true,
  1108.      *     @OA\Schema(type="string"),
  1109.      *)
  1110.      * @OA\Tag(name="User")
  1111.      * )
  1112.      */
  1113.     public function userFavoriteOfferAdd(Request $requestUserGetter $userGetter)
  1114.     {
  1115.         $user $userGetter->get();
  1116.         $data json_decode($request->getContent());
  1117.         $offerID $data->offerID;
  1118.         $entityManager $this->getDoctrine()->getManager();
  1119.         $offer $this->getOfferRepository()->find($offerID);
  1120.         if (!$offer) {
  1121.             return $this->getResponse([], 404);
  1122.         }
  1123.         $user->addFavouriteOffer($offer);
  1124.         $entityManager->flush();
  1125.         return $this->getResponse([], 200);
  1126.     }
  1127.     /**
  1128.      * Удалить с избранных
  1129.      * @Route("/mobile/api/v2/user/favorite/delete", methods={"DELETE"});
  1130.      * @OA\Response(
  1131.      *     response = 200,
  1132.      *     description = "Удаление акции з избранных",
  1133.      *     @OA\Schema(
  1134.      *        @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
  1135.      *        type="object",
  1136.      *        example = {"userBalance": 7.50}
  1137.      *     )
  1138.      * )
  1139.      * @OA\Response(
  1140.      *     response = 404,
  1141.      *     description = "Юзер или акция ненайдена"
  1142.      * )
  1143.      * @OA\Parameter(
  1144.      *     name = "offerID",
  1145.      *     in = "query",
  1146.      *     description = "ID акции",
  1147.      *     required = true,
  1148.      *     @OA\Schema(type="integer"),
  1149.      *)
  1150.      * @OA\Parameter(
  1151.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  1152.      *     in = "header",
  1153.      *     description = "Токен юзера",
  1154.      *     required = true,
  1155.      *     @OA\Schema(type="string"),
  1156.      *)
  1157.      * @OA\Tag(name="User")
  1158.      * )
  1159.      */
  1160.     public function userFavoriteOfferDelete(Request $requestUserGetter $userGetter)
  1161.     {
  1162.         $user $userGetter->get();
  1163.         $data json_decode($request->getContent());
  1164.         $offerID $data->offerID;
  1165.         $entityManager $this->getDoctrine()->getManager();
  1166.         $offer $this->getOfferRepository()->find($offerID);
  1167.         if (!$offer) {
  1168.             return $this->getResponse([], 404);
  1169.         }
  1170.         $user->deleteFavouriteOffer($offer);
  1171.         $entityManager->flush();
  1172.         return $this->getResponse([], 200);
  1173.     }
  1174.     /**
  1175.      * Фидбек
  1176.      * @Route("/mobile/api/v2/user/feedback", methods={"POST"});
  1177.      * @OA\Response(
  1178.      *     response = 200,
  1179.      *     description = "Фидбек принят",
  1180.      * )
  1181.      * @OA\Response(
  1182.      *     response = 404,
  1183.      *     description = "Юзер не найден"
  1184.      * )
  1185.      * @OA\Response(
  1186.      *     response = 401,
  1187.      *     description = "Не авторизован"
  1188.      * )
  1189.      * @OA\Response(
  1190.      *     response = 400,
  1191.      *     description = "Отсутсвуют обязательные параметры в запросе"
  1192.      * )
  1193.      * @OA\Parameter(
  1194.      *     name = "HTTP-SLIVKi-USER-TOKEN",
  1195.      *     in = "header",
  1196.      *     description = "Токен юзера",
  1197.      *     required = true,
  1198.      *     @OA\Schema(type="string"),
  1199.      *),
  1200.      * @OA\RequestBody(
  1201.      *     required=true,
  1202.      *       @OA\MediaType(
  1203.      *           mediaType="multipart/form-data",
  1204.      *           @OA\Schema(
  1205.      *               type="object",
  1206.      *               @OA\Property(
  1207.      *                  property = "message",
  1208.      *                  description = "Сообщение",
  1209.      *                  type="string",
  1210.      *                  example="",
  1211.      *               ),
  1212.      *               @OA\Property(
  1213.      *                  property = "phone",
  1214.      *                  description = "Номер телефона пользователя",
  1215.      *                  type="string",
  1216.      *                  example="",
  1217.      *               ),
  1218.      *               @OA\Property(
  1219.      *                  property = "email",
  1220.      *                  description = "Email пользователя",
  1221.      *                  type="string",
  1222.      *                  example="",
  1223.      *               ),
  1224.      *               @OA\Property(
  1225.      *                  property = "phoneVersion",
  1226.      *                  description = "Модель устройства",
  1227.      *                  type="string",
  1228.      *                  example="",
  1229.      *               ),
  1230.      *               @OA\Property(
  1231.      *                  property = "os",
  1232.      *                  description = "ОС устройства",
  1233.      *                  type="string",
  1234.      *                  example="",
  1235.      *               ),
  1236.      *               @OA\Property(
  1237.      *                  property = "appVersion",
  1238.      *                  description = "Версия приложения",
  1239.      *                  type="string",
  1240.      *                  example="",
  1241.      *               ),
  1242.      *               @OA\Property(
  1243.      *                  property = "images",
  1244.      *                  description = "Загрузка изображений",
  1245.      *                  type="array",
  1246.      *                  example="",
  1247.      *                  @OA\Items(),
  1248.      *               ),
  1249.      *           ),
  1250.      *       ),
  1251.      * ),
  1252.      * @OA\Tag(name="User")
  1253.      */
  1254.     public function userFeedback(Request $requestMailer $mailer)
  1255.     {
  1256.         $message $request->request->get('message');
  1257.         if (!$message) {
  1258.             return $this->getResponse([], 400);
  1259.         }
  1260.         $appVersion $request->request->get('appVersion');
  1261.         $phone $request->request->get('phone');
  1262.         $email $request->request->get('email');
  1263.         $phoneVersion $request->request->get('phoneVersion');
  1264.         $os $request->request->get('os');
  1265.         $body '<b>Фидбек:</b><br>';
  1266.         $body .= $message '<br><br>';
  1267.         $body .= "<b>Номер телефона пользователя:</b> $phone<br>";
  1268.         $body .= "<b>Email пользователя:</b> $email<br>";
  1269.         $body .= "<b>Модель устройства:</b> $phoneVersion<br>";
  1270.         $body .= "<b>ОС устройства:</b> $os<br>";
  1271.         $body .= "<b>Версия приложения:</b> $appVersion<br><br>";
  1272.         $mailerMessage $mailer->createMessage();
  1273.         $mailerMessage->setSubject("Фидбек с мобильного приложения")
  1274.             ->setFrom("info@slivki.by"'Slivki.by')
  1275.             ->setTo("info@slivki.by")
  1276.             ->addCc('dobrovolskaya@slivki.com')
  1277.             ->addCc('dmitry.kazak@slivki.com')
  1278.             ->setBody($body'text/html');
  1279.         /** @var UploadedFile $uploadedFile */
  1280.         foreach ($request->files->get('images', []) as $uploadedFile) {
  1281.             $mailerMessage->attachFromPath($uploadedFile->getRealPath(), $uploadedFile->getClientOriginalName(), $uploadedFile->getMimeType());
  1282.         }
  1283.         $mailer->send($mailerMessage);
  1284.         return $this->getResponse([], 200);
  1285.     }
  1286.     /**
  1287.      * Восстановление пароля
  1288.      * @Route("/mobile/api/v2/restore-password", methods={"GET"});
  1289.      * @OA\Response(
  1290.      *     response = 200,
  1291.      *     description = "Пароль выслан",
  1292.      * )
  1293.      * @OA\Response(
  1294.      *     response = 400,
  1295.      *     description = "Email не найден"
  1296.      * )
  1297.      * @OA\Parameter(
  1298.      *     name = "email",
  1299.      *     in = "query",
  1300.      *     description = "Email",
  1301.      *     required = true,
  1302.      *     @OA\Schema(type="string"),
  1303.      *)
  1304.      * @OA\Tag(name="User")
  1305.      */
  1306.     public function restorePassword(Request $requestMailer $mailer) {
  1307.         $email trim($request->query->get('email'''));
  1308.         if ($email == '') {
  1309.             return $this->getResponse([], 400);
  1310.         }
  1311.         $entityManager $this->getDoctrine()->getManager();
  1312.         $user $entityManager->getRepository(User::class)->findOneByEmail($email);
  1313.         if (!$user) {
  1314.             return $this->getResponse([], 400);
  1315.         }
  1316.         $message $mailer->createMessage();
  1317.         $message->setSubject("Восстановление пароля")
  1318.             ->setFrom("info@slivki.by"'Slivki.by')
  1319.             ->setTo($user->getEmail())
  1320.             ->setBody(
  1321.                 $this->renderView('Slivki/emails/lost_password.html.twig', [
  1322.                     'password' => $user->getPasswordClear()
  1323.                 ]),
  1324.                 'text/html'
  1325.             );
  1326.         $mailer->send($message);
  1327.         return $this->getResponse([], 200);
  1328.     }
  1329.     /**
  1330.      * Авторизация по номеру телефона
  1331.      * @Route("/mobile/api/v2/user/login/phone", methods={"POST"});
  1332.      * @OA\Response(
  1333.      *     response = 200,
  1334.      *     description = "Возвращает токен юзера.",
  1335.      *     @OA\Schema(
  1336.      *        @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
  1337.      *        type="object",
  1338.      *     )
  1339.      * )
  1340.      * @OA\Response(
  1341.      *     response = 401,
  1342.      *     description = "Сервис не авторизован"
  1343.      * )
  1344.      * @OA\Response(
  1345.      *     response = 403,
  1346.      *     description = "Юзер не заблокирован"
  1347.      * )
  1348.      * @OA\RequestBody(
  1349.      *     required=true,
  1350.      *       @OA\MediaType(
  1351.      *           mediaType="application/json",
  1352.      *           @OA\Schema(
  1353.      *               type="object",
  1354.      *               @OA\Property(
  1355.      *                  property = "phoneNumber",
  1356.      *                  description = "номер телефона",
  1357.      *                  type="string",
  1358.      *                  example="",
  1359.      *               ),
  1360.      *           ),
  1361.      *       ),
  1362.      * ),
  1363.      * @OA\Parameter(
  1364.      *     name = "HTTP-SLIVKi-PARTNER-TOKEN",
  1365.      *     in = "header",
  1366.      *     description = "Токен юзера",
  1367.      *     required = true,
  1368.      *     @OA\Schema(type="string"),
  1369.      *)
  1370.      * @OA\Tag(name="User")
  1371.      */
  1372.     public function phoneLoginAction(
  1373.         Request $request,
  1374.         PhoneNumberHelper $phoneNumberHelper,
  1375.         UserPhoneRepositoryInterface $userPhoneRepository,
  1376.         UserPhoneService $userPhoneService
  1377.     ): JsonResponse {
  1378.         if ($request->headers->get('HTTP-SLIVKi-PARTNER-TOKEN') != User::OPLATI_PARTNER_TOKEN) {
  1379.             return $this->getResponse([], 401);
  1380.         }
  1381.         $data json_decode($request->getContent());
  1382.         $logger Logger::instance('DEBUG');
  1383.         $logger->info(print_r($datatrue));
  1384.         $entityManager $this->getDoctrine()->getManager();
  1385.         $phoneNumber $phoneNumberHelper->convert($data->phoneNumber);
  1386.         $userPhone $userPhoneRepository->findConfirmedByPhoneNumber($phoneNumber);
  1387.         if ($userPhone) {
  1388.             $user $userPhone->getUser();
  1389.             if ($user && $user->getStatus() == User::STATUS_LOCKED) {
  1390.                 return $this->getResponse([], 403'User is locked');
  1391.             }
  1392.             $user->setStatus(User::STATUS_CONFIRMED);
  1393.         }
  1394.         if (!$userPhone) {
  1395.             $user = new User();
  1396.             $user->setCreatedOn(new \DateTime());
  1397.             $user->setStatus(User::STATUS_CONFIRMED);
  1398.             $entityManager->persist($user);
  1399.             $userPhone $userPhoneService->addUserPhone($user$phoneNumber);
  1400.             $userPhoneService->confirmUserPhone($userPhone);
  1401.             $entityManager->getRepository(User::class)->addDirectorGroupToUserByUser($user);
  1402.         }
  1403.         $entityManager->flush();
  1404.         $mobileToken $entityManager->getRepository(MobileUserToken::class)->findOneByUser($userPhone->getUser());
  1405.         if (!$mobileToken) {
  1406.             $token md5(microtime() . rand(10100));
  1407.             $mobileToken = new MobileUserToken();
  1408.             $mobileToken->setToken($token);
  1409.             $mobileToken->setUser($user);
  1410.             $entityManager->persist($mobileToken);
  1411.             $entityManager->flush();
  1412.         }
  1413.         return $this->getResponse(['userToken' => $mobileToken->getToken()], 200);
  1414.     }
  1415.     /**
  1416.      * @Route("/mobile/api/v2/user/order-history/{pageNumber}", methods={"GET"});
  1417.      * @OA\Response(
  1418.      *     response=Response::HTTP_OK,
  1419.      *     description="История покупок",
  1420.      *     @OA\JsonContent(
  1421.      *        @OA\Property(property="type", type="string", description="Тип активности"),
  1422.      *        @OA\Property(property="data", type="string", description="Данные активности"),
  1423.      *        type="object",
  1424.      *   )
  1425.      * )
  1426.      * @OA\Response(
  1427.      *     response=Response::HTTP_UNAUTHORIZED,
  1428.      *     description="Юзер не найден"
  1429.      * )
  1430.      * @OA\Parameter(
  1431.      *     name="pageNumber",
  1432.      *     in="path",
  1433.      *     description="Номер страницы",
  1434.      *     required=true,
  1435.      *     @OA\Schema(type="integer"),
  1436.      *)
  1437.      * @OA\Parameter(
  1438.      *     name="HTTP-SLIVKi-USER-TOKEN",
  1439.      *     in="header",
  1440.      *     description="Токен юзера",
  1441.      *     required=true,
  1442.      *     @OA\Schema(type="string"),
  1443.      *)
  1444.      * @OA\Tag(name="User"),
  1445.      */
  1446.     public function getUserOrderHistoryAction(
  1447.         ImageService $imageService,
  1448.         QRCodeAggregator $codeAggregator,
  1449.         UserGetter $userGetter,
  1450.         GiftCertificateAddressDtoFactory $certificateAddressDtoFactory,
  1451.         QRCodeGeneratorDtoFactory $codeGeneratorDtoFactory,
  1452.         $pageNumber 1
  1453.     ): JsonResponse {
  1454.         $limit 32;
  1455.         $offset $limit * ($pageNumber 1);
  1456.         $result $this->getUserOrders(
  1457.             $userGetter->get(),
  1458.             $imageService,
  1459.             $codeAggregator,
  1460.             $certificateAddressDtoFactory,
  1461.             $this->tireOrderHistoryDtoFactory,
  1462.             $codeGeneratorDtoFactory,
  1463.             $limit,
  1464.             $offset,
  1465.         );
  1466.         return $this->getResponse($result200);
  1467.     }
  1468.     private function getUserOrders(
  1469.         User $user,
  1470.         ImageService $imageService,
  1471.         QRCodeAggregator $codeAggregator,
  1472.         GiftCertificateAddressDtoFactory $certificateAddressDtoFactory,
  1473.         TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory,
  1474.         QRCodeGeneratorDtoFactory $codeGeneratorDto,
  1475.         $limit,
  1476.         $offset
  1477.     ): array {
  1478.         $result = [];
  1479.         $entityManager $this->getDoctrine()->getManager();
  1480.         $dql "select offerOrder from Slivki:AbstractOrderBase offerOrder where offerOrder not instance of Slivki:SubscriptionOrder and offerOrder.userID  = :userID and offerOrder.status > 0 order by offerOrder.ID DESC";
  1481.         $offerOrders $entityManager->createQuery($dql)
  1482.             ->setParameter('userID'$user->getID())
  1483.             ->getResult();
  1484.         $balanceActivity $this->getBalanceActivity($user);
  1485.         $all array_merge($balanceActivity$offerOrders);
  1486.         usort($all, static function ($item1$item2) {
  1487.             return $item2->getCreatedOn()->format('U') - $item1->getCreatedOn()->format('U');
  1488.         });
  1489.         $offerUtilRuntime = [];
  1490.         $offerOrders array_slice($all$offset$limit);
  1491.         foreach ($offerOrders as $offerOrder) {
  1492.             $encoder null;
  1493.             if (null !== $offerOrder->getOffer()) {
  1494.                 $encoder $codeAggregator->aggregate((int) $offerOrder->getOffer()->getID());
  1495.             }
  1496.             if ($offerOrder instanceof UserBalanceActivity) {
  1497.                 $bonusTypeBalanceActivityList UserBalanceActivityType::BONUS_ACTIVITIES;
  1498.                 $siteSettings $entityManager->getRepository(SiteSettings::class)->getSiteSettingsCached();
  1499.                 if (in_array($offerOrder->getType()->getID(), $bonusTypeBalanceActivityList)) {
  1500.                     $name $offerOrder->getType()->getName();
  1501.                     $type str_replace("%s"$siteSettings->getMonthlyCodeCount(), $name);
  1502.                     $result[] = (object) ["type" => "bonus""data" => ['typeName' => $type'amount' => $offerOrder->getAmount(), 'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')]];
  1503.                 } else {
  1504.                     $result[] = (object) ["type" => "payments""data" => ['typeName' => $offerOrder->getType()->getName(), 'amount' => $offerOrder->getAmount(), 'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')]];
  1505.                 }
  1506.             } else if ($offerOrder instanceof OfferOrder && !($offerOrder instanceof FoodOrder || $offerOrder instanceof GiftCertificateOrder || $offerOrder instanceof TireOrder)) {
  1507.                     $offer $offerOrder->getOffer();
  1508.                     $offerOrderDetails $offerOrder->getOfferOrderDetails();
  1509.                     if ($offerOrderDetails) {
  1510.                         foreach ($offerOrderDetails as $offerOrderDetail) {
  1511.                             $messageEncode null;
  1512.                             if ($encoder !== null) {
  1513.                                 $messageEncode $encoder->encode($codeGeneratorDto->create($offerOrderDetailtrue));
  1514.                             }
  1515.                             $result[] = (object) ["type" => "codes""data" => [
  1516.                                 'ID' => $offerOrderDetail->getID(),
  1517.                                 'orderID' => $offerOrder->getID(),
  1518.                                 'offerID' => $offer->getID(),
  1519.                                 'offerActive' => $offer->isActive(),
  1520.                                 'offerName' => $offer->getTitle(),
  1521.                                 'imageURL' => 'https://www.slivki.by' . ($offer->getTeaserMedia() ? $imageService->getImageURL($offer->getTeaserMedia(), 500324) : ImageService::FALLBACK_IMAGE),
  1522.                                 'code' => $offerOrderDetail->getCode(),
  1523.                                 'isUsed' => $offerOrderDetail->isUsed(),
  1524.                                 'isUsedBySupplier' => $offerOrderDetail->isMarkedUsedBySupplier(),
  1525.                                 'codeCreatedAt' => $offerOrderDetail->getCreatedOn()->format('Y-m-d H:i:s'),
  1526.                                 'usedAt' => !$offerOrderDetail->getMarkedUsedBySupplierChecktime() ? null $offerOrderDetail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s'),
  1527.                                 'codeActiveTill' => $offerOrderDetail->getCodeActiveTill() ? $offerOrderDetail->getCodeActiveTill()->format('d-m-Y H:i:s') : '',
  1528.                                 'offerType' => $offer->getOfferType(),
  1529.                                 'allowedOnlineOrderTypes' => $offer->getAllowedOnlineOrderTypesOnApp(),
  1530.                                 'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s'),
  1531.                                 'useMessageEncode' => (bool) $messageEncode,
  1532.                                 'messageEncode' => $messageEncode,
  1533.                             ]];
  1534.                         }
  1535.                     }
  1536.             } else if($offerOrder instanceof GiftCertificateOrder) {
  1537.                 $offer $offerOrder->getOffer();
  1538.                 $giftCertificates = [];
  1539.                 /** @var OfferOrderDetails $detail */
  1540.                 $complexName '';
  1541.                 foreach ($offerOrder->getOfferOrderDetails() as $detail) {
  1542.                     if (!$detail) {
  1543.                         continue;
  1544.                     }
  1545.                     $giftCertificate $detail->getGiftCertificate();
  1546.                     if ($giftCertificate) {
  1547.                         if ($giftCertificate->getCodesPerItem() < 1) {
  1548.                             $complexName .= $giftCertificate->getName() . ', ';
  1549.                         }
  1550.                         $messageEncode null;
  1551.                         if ($encoder !== null) {
  1552.                             $messageEncode $encoder->encode($codeGeneratorDto->create($detailtrue));
  1553.                         }
  1554.                         $price $giftCertificate->getPriceOffer();
  1555.                         $offerPrice $giftCertificate->getPriceRegular();
  1556.                         if ($giftCertificate->getBundlePromoCount() > 0)  {
  1557.                             $price = \round($price $giftCertificate->getBundlePromoCount(), 2);
  1558.                             $offerPrice = \round($offerPrice $giftCertificate->getBundlePromoCount(), 2);
  1559.                         }
  1560.                         $giftCertificates[] = [
  1561.                             'name' => $giftCertificate->getName(),
  1562.                             'imageURL' => $imageService->getImageURLCachedWithDomain($offer->getMobileTeaserMedia(), 7640),
  1563.                             'price' => (string) $price,
  1564.                             'offerPrice' => (string) $offerPrice,
  1565.                             'itemsCount' => $detail->getItemsCount(),
  1566.                             'code' => $detail->getCode(),
  1567.                             'useMessageEncode' => (bool) $messageEncode,
  1568.                             'messageEncode' => $messageEncode,
  1569.                             'codeActiveTill' => $detail->getCodeActiveTill()->format('Y-m-d H:i:s'),
  1570.                             'isUsed' => $detail->isUsed(),
  1571.                             'isUsedBySupplier' => $detail->isMarkedUsedBySupplier(),
  1572.                             'codeCreatedAt' => $detail->getCreatedOn()->format('Y-m-d H:i:s'),
  1573.                             'usedAt' => $detail->getMarkedUsedBySupplierChecktime() ? $detail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s') : null,
  1574.                             'certificateURL' => '/mobile/api/v2/gift-certificate/' $detail->getID() . '/pdf',
  1575.                             'addresses' => array_map(
  1576.                                 [$certificateAddressDtoFactory'create'],
  1577.                                 $giftCertificate->getGeoLocations()->toArray(),
  1578.                             ),
  1579.                         ];
  1580.                     }
  1581.                 }
  1582.                 if ($complexName != '') {
  1583.                     $giftCertificates[0]['items'] = $giftCertificates;
  1584.                     $giftCertificates[0]['name'] = trim($complexName', ');
  1585.                     $giftCertificates = [$giftCertificates[0]];
  1586.                 }
  1587.                 $result[] = (object) array("type" => "gift-certificate""data" => [
  1588.                     'id' => $offerOrder->getID(),
  1589.                     'offerID' => $offer->getID(),
  1590.                     'rating' => $offer->getRating() + 0.0001,
  1591.                     'companyName' => $offer->getCompanyName(),
  1592.                     'title' => $offer->getTitle(),
  1593.                     'giftCertificates' => $giftCertificates,
  1594.                     'discount' => $offer->getDiscount(),
  1595.                     'codeCost' => $offer->getCodeCost(),
  1596.                     'amount' => $offerOrder->getAmount(),
  1597.                     'orderDate' => $offerOrder->getCreatedOn(),
  1598.                     'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')
  1599.                 ]);
  1600.             } else if ($offerOrder instanceof FoodOrder) {
  1601.                 $offer $offerOrder->getOffer();
  1602.                 $foodOrderHistory $this->foodOrderHistoryDtoFactory->create($offerOrder);
  1603.                 $amountOfferPrice $foodOrderHistory->getOrderProductsSum();
  1604.                 $amountPrice $foodOrderHistory->getOrderProductsRegularSum();
  1605.                 $codeCost $foodOrderHistory->getCodePrice();
  1606.                 $codesCount $foodOrderHistory->getCodesCount();
  1607.                 $result[] = (object) array("type" => "online-orders""data" => [
  1608.                     'id' => $foodOrderHistory->getOrderId(),
  1609.                     'offerID' => $foodOrderHistory->getOfferId(),
  1610.                     'rating' => $offer->getRating() + 0.0001,
  1611.                     'imageUrl' => $foodOrderHistory->getOfferImageUrl(),
  1612.                     'companyName' => $offer->getCompanyName(),
  1613.                     'title' => $offer->getTitle(),
  1614.                     'dishes' => array_values(array_map(
  1615.                         static fn (FoodOrderProductDto $product): array => [
  1616.                             'name' => $product->getName(),
  1617.                             'price' => $product->getRegularPrice(),
  1618.                             'offerPrice' => $product->getPurchasePrice(),
  1619.                             'itemsCount' => $product->getAmount(),
  1620.                             'imageUrl' => $product->getImageUrl(),
  1621.                         ],
  1622.                         $foodOrderHistory->getProducts(),
  1623.                     )),
  1624.                     'options' => array_values(array_map(
  1625.                         static fn (FoodOrderProductDto $option): array => [
  1626.                             'name' => $option->getName(),
  1627.                             'price' => $option->getRegularPrice(),
  1628.                             'offerPrice' => $option->getPurchasePrice(),
  1629.                             'itemsCount' => $option->getAmount(),
  1630.                             'imageUrl' => $option->getImageUrl(),
  1631.                         ],
  1632.                         $foodOrderHistory->getOptions(),
  1633.                     )),
  1634.                     'discount' => $offer->getDiscount(),
  1635.                     'codesCount' => $codesCount,
  1636.                     'codeCost' => (string)$codeCost,
  1637.                     'productsAmount' => number_format($amountOfferPrice $codesCount $codeCost2'.'''),
  1638.                     'amount' => number_format($amountPrice2'.'''),
  1639.                     'orderDate' => $foodOrderHistory->getOrderedAt()->format('Y-m-d H:i:s'),
  1640.                     'createdOn' => $foodOrderHistory->getOrderedAt()->format('Y-m-d H:i:s'),
  1641.                     'usedPartnerCashbackSum' => $offerOrder->getUsedPartnerCashbackSum(),
  1642.                     'deliveryPrice' => (float) number_format($foodOrderHistory->getDeliveryPrice(), 2'.'''),
  1643.                 ]);
  1644.             } else if ($offerOrder instanceof TireOrder) {
  1645.                 $result[] = [
  1646.                     'type' => UserOrderHistoryType::TIRE,
  1647.                     'data' => $tireOrderHistoryDtoFactory->create($offerOrder),
  1648.                 ];
  1649.             }
  1650.         }
  1651.         return $result;
  1652.     }
  1653.     private function getBalanceActivity(User $user) {
  1654.         $userID $user->getID();
  1655.         $entityManager $this->getDoctrine()->getManager();
  1656.         $userRegistrationBonusCancel $user->getBalanceActivityByType($entityManager->find(UserBalanceActivityType::class, UserBalanceActivity::TYPE_REGISTRATION_BONUS_CANCEL));
  1657.         $userRegistrationBonusCancelCondition '';
  1658.         if ($userRegistrationBonusCancel->count() > 0) {
  1659.             $userRegistrationBonusCancelCondition ' AND UserBalanceActivity.type != ' UserBalanceActivity::TYPE_REGISTRATION_BONUS
  1660.                 'AND UserBalanceActivity.type != ' UserBalanceActivity::TYPE_REGISTRATION_BONUS_CANCEL;
  1661.         }
  1662.         $dql "SELECT UserBalanceActivity
  1663.           FROM Slivki:UserBalanceActivity UserBalanceActivity
  1664.           WHERE UserBalanceActivity.user = $userID $userRegistrationBonusCancelCondition
  1665.           ORDER BY UserBalanceActivity.createdOn DESC";
  1666.         $query $entityManager->createQuery($dql);
  1667.         $balanceActivity $query->getResult();
  1668.         return $balanceActivity;
  1669.     }
  1670. }