<?php
namespace Slivki\Controller\MobileApi;
use Slivki\Dto\GiftCertificate\Factory\GiftCertificateAddressDtoFactory;
use Slivki\Dto\User\OrderHistory\Factory\TireOrderHistoryDtoFactory;
use Slivki\Dto\User\OrderHistory\FoodOrderProductDto;
use Slivki\Entity\City;
use Slivki\Entity\FoodOrder;
use Slivki\Entity\GiftCertificateOrder;
use Slivki\Entity\MobileUserToken;
use Slivki\Entity\OfferOrder;
use Slivki\Entity\OfferOrderDetails;
use Slivki\Entity\SiteSettings;
use Slivki\Entity\TireOrder;
use Slivki\Entity\User;
use Slivki\Entity\UserBalanceActivity;
use Slivki\Entity\UserBalanceActivityType;
use Slivki\Entity\UserConfirmation;
use Slivki\Entity\UserGroup;
use Slivki\Entity\UserPhone;
use Slivki\Enum\Bonus\Bonus;
use Slivki\Enum\User\UserOrderHistoryType;
use Slivki\Exception\Sms\SmsLimitReachedException;
use Slivki\Factory\QRCode\QRCodeGeneratorDtoFactory;
use Slivki\Factory\User\OrderHistory\FoodOrderHistoryDtoFactory;
use Slivki\Helpers\PhoneNumberHelper;
use Slivki\Message\Command\Bonus\AddBonusCommand;
use Slivki\Repository\User\MobileUserTokenRepositoryInterface;
use Slivki\Repository\UserPhone\UserPhoneRepositoryInterface;
use Slivki\Services\Encoder;
use Slivki\Services\ImageService;
use Slivki\Services\Mailer;
use Slivki\Services\QRCodeGenerator\QRCodeAggregator;
use Slivki\Services\Sms\Security\SmsLimiterService;
use Slivki\Services\Subscription\SubscriptionService;
use Slivki\Services\User\AuthorizationCodeSender;
use Slivki\Services\User\UserPhoneService;
use Slivki\Services\UserGetter;
use Slivki\Util\Logger;
use Slivki\Validator\PhoneNumber\PhoneNumberRegionValidator;
use OpenApi\Annotations as OA;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use function random_int;
use function array_map;
class UserController extends MobileApiController
{
private SubscriptionService $subscriptionService;
private TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory;
private FoodOrderHistoryDtoFactory $foodOrderHistoryDtoFactory;
private MobileUserTokenRepositoryInterface $mobileUserTokenRepository;
private MessageBusInterface $commandBus;
public function __construct(
KernelInterface $kernel,
SubscriptionService $subscriptionService,
TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory,
FoodOrderHistoryDtoFactory $foodOrderHistoryDtoFactory,
MobileUserTokenRepositoryInterface $mobileUserTokenRepository,
MessageBusInterface $commandBus
) {
parent::__construct($kernel);
$this->subscriptionService = $subscriptionService;
$this->tireOrderHistoryDtoFactory = $tireOrderHistoryDtoFactory;
$this->foodOrderHistoryDtoFactory = $foodOrderHistoryDtoFactory;
$this->mobileUserTokenRepository = $mobileUserTokenRepository;
$this->commandBus = $commandBus;
}
/**
* Авторизация
* @Route("/mobile/api/v2/user/login", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Возвращает токен юзера при авторизации по логину и паролю. В случае авторизации по номеру телефона отправляет SMS с кодом.",
* @OA\Schema(
* @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
* @OA\Property(property = "isPartner", type = "boolean", description = "Является ли юзер партнером"),
* type="object",
* )
* )
* @OA\Response(
* response = 400,
* description = "Неверный email, пароль или номер телефона"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\Response(
* response = 429,
* description = "Лимит по отправленым sms"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "login",
* description = "логин или номер телефона",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "password",
* description = "пароль",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Tag(name="User")
* @throws \Exception
*/
public function loginAction(
Request $request,
PhoneNumberRegionValidator $phoneNumberRegionValidator,
AuthorizationCodeSender $authorizationCodeSender,
SmsLimiterService $smsLimiterService,
PhoneNumberHelper $phoneNumberHelper,
UserPhoneService $userPhoneService,
UserPhoneRepositoryInterface $userPhoneRepository
): JsonResponse {
$logger = Logger::instance('DEBUG');
if ($request->headers->has('SLIVKI-APP-VERSION') && $request->headers->get('SLIVKI-APP-VERSION') === '1.4.1') {
$logger->info('SKIP APP LOGIN');
return new JsonResponse([], Response::HTTP_UPGRADE_REQUIRED);
}
$statusCode = 200;
$errorMessage = '';
$data = json_decode($request->getContent());
$logger->info(print_r($data, true));
$entityManager = $this->getDoctrine()->getManager();
if (isset($data->password) && $data->password != '') {
if (!filter_var($data->login, FILTER_VALIDATE_EMAIL)) {
return $this->getResponse([], 400, 'wrong email');
} else {
$user = $entityManager->getRepository(User::class)->loadUserByUsername($data->login, false);
if (!$user || $user->getStatus() == User::STATUS_LOCKED) {
return $this->getResponse([], 404, 'User not found');
}
$encoder = new Encoder();
if (!$encoder->isPasswordValid($user->getPassword(), $data->password, $user->getSalt())) {
return $this->getResponse([], 400, 'Wrong password');
}
$token = null;
if ($request->headers->has(self::SUPERFOOD_HEADER_NAME)) {
$token = $user->getToken();
if (!$token) {
$token = uniqid($user->getID(), true);
$user->setToken($token);
$entityManager->flush();
}
} else {
$token = $this->mobileUserTokenRepository->createIfNotExist($user)->getToken();
$this->commandBus->dispatch(new AddBonusCommand($user->getID(), Bonus::APP_LOGIN));
}
$data = [
'userToken' => $token,
'isPartner' => $user->hasRole(UserGroup::ROLE_SUPPLIER_ID)
];
return $this->getResponse($data, 200, '');
}
} else {
$phoneNumber = $phoneNumberHelper->convert($data->login);
$phoneNumberRegionValidator->validate('+' . $phoneNumber);
$userPhone = $userPhoneRepository->findConfirmedByPhoneNumber($phoneNumber);
if ($userPhone instanceof UserPhone) {
$user = $userPhone->getUser();
if (User::STATUS_LOCKED === $user->getStatus()) {
return $this->getResponse([], Response::HTTP_NOT_FOUND, 'User not found');
}
}
$code = random_int(1000, 9999);
$logger->info(print_r($data->login, true) . ' -> ' . \json_encode($request->headers->all()));
try {
if ($request->getClientIp() !== null) {
$smsLimiterService->limit(
$phoneNumberHelper->convert($data->login),
$request->getClientIp(),
);
}
$smsLineResponse = $authorizationCodeSender->send($phoneNumber, $code, $request->getHost());
if ($smsLineResponse->isError()) {
return $this->getResponse([], Response::HTTP_TOO_MANY_REQUESTS, $smsLineResponse->getMessage());
}
} catch (SmsLimitReachedException $exception) {
return $this->getResponse([], Response::HTTP_TOO_MANY_REQUESTS, $errorMessage);
}
if (null === $userPhone) {
$user = new User();
$user->setCreatedOn(new \DateTime());
$user->setDefaultPassword();
$user->setStatus(User::STATUS_REGISTERED);
$entityManager->persist($user);
$userPhone = $userPhoneService->addUserPhone($user, $phoneNumber);
$entityManager->getRepository(User::class)->addDirectorGroupToUserByUser($user);
}
$userPhone->setAuthCode($code);
$entityManager->flush();
return $this->getResponse([], $statusCode, $errorMessage);
}
}
/**
* Google авторизация
* @Route("/mobile/api/v2/user/login/google", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Возвращает токен юзера при авторизации по google uid.",
* @OA\Schema(
* @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
* type="object",
* )
* )
* @OA\Response(
* response = 400,
* description = "uid не найден"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "uid",
* description = "uid",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Tag(name="User")
*/
public function googleLoginAction(Request $request) {
$data = json_decode($request->getContent());
if (!isset($data->uid)) {
return $this->getResponse([], 400);
}
Logger::instance('MOBILE API')->info('UID ' . $data->uid);
return $this->getResponse([], 404);
}
/**
* Проверка кода авторизации
* @Route("/mobile/api/v2/user/check-code", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Возвращает токен юзера в случае успеха.",
* @OA\Schema(
* @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
* type="object",
* )
* )
* @OA\Response(
* response = 404,
* description = "Номер телефона не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "phoneNumber",
* description = "номер телефона",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "code",
* description = "код авторизации",
* type="integer",
* example="",
* ),
* ),
* ),
* ),
* @OA\Tag(name="User")
*/
public function checkCode(
Request $request,
UserPhoneService $userPhoneService,
PhoneNumberHelper $phoneNumberHelper,
UserPhoneRepositoryInterface $userPhoneRepository
): JsonResponse {
$entityManager = $this->getDoctrine()->getManager();
$data = json_decode($request->getContent());
$phoneNumber = $phoneNumberHelper->convert($data->phoneNumber);
$userPhone = $userPhoneRepository->findByPhoneNumberAndAuthCode($phoneNumber, $data->code);
if (null === $userPhone) {
return $this->getResponse([], Response::HTTP_NOT_FOUND);
}
if (!$userPhone->isConfirmed()) {
$userPhoneService->confirmUserPhone($userPhone);
$user = $userPhone->getUser();
if ($user->getStatus() === User::STATUS_REGISTERED) {
$user->setStatus(User::STATUS_CONFIRMED);
}
$entityManager->flush();
}
if ($request->headers->has(self::SUPERFOOD_HEADER_NAME)) {
$token = $user->getToken();
if (!$token) {
$token = uniqid($user->getID(), true);
$user->setToken($token);
$entityManager->flush();
}
} else {
$user = $userPhone->getUser();
$token = $this->mobileUserTokenRepository->createIfNotExist($user)->getToken();
$this->commandBus->dispatch(new AddBonusCommand($user->getID(), Bonus::APP_LOGIN));
}
return $this->getResponse(['userToken' => $token], 200);
}
/**
* Проверка токена
* @Route("/mobile/api/v2/user/check", methods={"GET"});
* @OA\Response(
* response = 401,
* description = "Пользователь не найден"
* )
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function tokenCheckAction(): JsonResponse
{
return $this->getResponse([], 200);
}
/**
* Баланс пользователя
* @Route("/mobile/api/v2/user/balance", methods={"GET"});
* @OA\Response(
* response = 200,
* description = "Баланс пользователя",
* @OA\Schema(
* @OA\Property(property = "balance", type = "decimal", description = "баланс пользователя"),
* @OA\Property(property = "isHot", type = "boolean", description = "есть ли непогашенные коды"),
* type="object",
* )
* )
* @OA\Response(
* response = 401,
* description = "Пользователь не найден"
* )
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function getBalanceAction(UserGetter $userGetter): JsonResponse
{
$user = $userGetter->get();
$isHot = false;
$entityManager = $this->getDoctrine()->getManager();
$dql = "select offerOrderDetails from Slivki:OfferOrderDetails offerOrderDetails
join offerOrderDetails.offerOrder offerOrder
where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder and offerOrderDetails.used = false
and offerOrderDetails.codeActiveTill >= CURRENT_TIMESTAMP() and offerOrderDetails.codeActiveTill <= DATE_ADD(CURRENT_TIMESTAMP(),3, 'day')
order by offerOrderDetails.ID desc";
$query = $entityManager->createQuery($dql);
$query->setParameter('user', $user);
$codes = $query->getResult();
if (count($codes) > 0) {
$isHot = true;
}
return $this->getResponse(['balance' => $user->getFullBalance(), 'isHot' => $isHot], 200);
}
/**
* @Route("/mobile/api/v2/user", methods={"GET"});
* @OA\Response(
* response=200,
* description="Информация о пользователе",
* @OA\Schema(
* @OA\Property(property="ID", type="integer", description="User Id"),
* @OA\Property(property="email", type="varchar", description="email пользователя"),
* @OA\Property(property="phoneNumber", type="varchar", description="номер телефона пользователя"),
* @OA\Property(property="name", type="varchar", description="имя пользователя"),
* @OA\Property(property="cityID", type="object", description="город пользователя",
* @OA\Property(property="ID", type="integer", description="ID города"),
* @OA\Property(property="name", type="varchar", description="название города"),
* @OA\Property(property="latitude", type="number", description="Широта"),
* @OA\Property(property="longitude", type="number", description="Долгота"),
* ),
* @OA\Property(property="balance", type="decimal", description="баланс пользователя"),
* @OA\Property(property="profileImage", type="varchar", description="изображение пользователя"),
* @OA\Property(property="isHot", type="boolean", description="есть ли непогашенные коды"),
* @OA\Property(property="activeRoles", type="object", description="Не скрытые роли пользователя"),
* @OA\Property(property="isSubscriber", type="object", description="Является ли юзер подписчиком"),
* @OA\Property(property="freeCodesCount", type="integer", description="Количество бесплатних кодов (null = неограниченно)"),
* @OA\Property(property="tariff", type="text", description="Название тарифа"),
* type="object",
* )
* )
* @OA\Response(
* response=404,
* description="Пользователь не найден"
* )
* @OA\Parameter(
* name="HTTP-SLIVKi-USER-TOKEN",
* in="header",
* description="Токен юзера",
* required=true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function getUserAction(
ImageService $imageService,
SubscriptionService $subscriptionService,
UserGetter $userGetter
): JsonResponse {
Logger::instance('SS-DEBUG')->info('START');
$user = $userGetter->get();
$city = $user->getCity();
$phoneNumber = $user->getPhones()->first();
$phoneNumber = $phoneNumber ? $phoneNumber->getPhoneNumber() : '';
$profileImageMedia = $user->getProfileImageMedia();
$profileImage = ImageService::DEFAULT_AVATAR;
if ($profileImageMedia) {
$profileImage = $imageService->getImageURL($profileImageMedia, 100, 100);
}
$cityData = [
'ID' => 1,
'name' =>'Минск',
'latitude' => 53.902284,
'longitude' => 27.561831,
];
if ($city) {
$cityData = [
'ID' => $city->getID(),
'name' => $city->getName(),
'latitude' => null !== $city->getCoordinate() ? $city->getCoordinate()->getLatitude() : null,
'longitude' => null !== $city->getCoordinate() ? $city->getCoordinate()->getLongitude() : null,
];
}
$isHot = false;
$entityManager = $this->getDoctrine()->getManager();
$dql = "select offerOrderDetails,offerOrder from Slivki:OfferOrderDetails offerOrderDetails
join offerOrderDetails.offerOrder offerOrder
where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder and offerOrderDetails.used = false
and offerOrderDetails.codeActiveTill >= CURRENT_TIMESTAMP() and offerOrderDetails.codeActiveTill <= DATE_ADD(CURRENT_TIMESTAMP(),3, 'day')
order by offerOrderDetails.ID desc";
$query = $entityManager->createQuery($dql);
$query->setParameter('user', $user);
$codes = $query->getResult();
if (count($codes) > 0) {
$isHot = true;
}
$subscription = $subscriptionService->getSubscription($user);
$freeCodesCount = $subscriptionService->isSubscriber($user) ? 0 : -1;
if ($subscriptionService->isSubscriber($user) && null === $subscription->getNumberOfCodes()) {
$freeCodesCount = null;
}
$data = [
'ID' => $user->getID(),
'email' => $user->getEmail(),
'phoneNumber' => $phoneNumber,
'name' => $user->getFirstName(),
'cityID' => $cityData,
'balance' => $user->getFullBalance(),
'profileImage' => $this->getParameter('base_url') . $profileImage,
'isHot' => $isHot,
'roles' => $user->getActiveRoles(),
'isSubscriber' => $subscriptionService->isSubscriber($user),
'freeCodesCount' => $freeCodesCount,
'tariff' => $subscriptionService->isSubscriber($user) ? $subscription->getPlanResponse()->getName() : ''
];
return $this->getResponse($data, 200);
}
/**
* Изменить имя
* @Route("/mobile/api/v2/user/update/name", methods={"PUT"});
* @OA\Response(
* response = 400,
* description = "Имя не может быть пустым"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "name",
* description = "Новое имя",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function updateUserNameAction(Request $request, UserGetter $userGetter): JsonResponse
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$name = trim($data->name);
if ($name == '') {
return $this->getResponse([], 400);
}
$user->setFirstName($name);
$this->getDoctrine()->getManager()->flush();
return $this->getResponse([], 200);
}
/**
* Изменить город
* @Route("/mobile/api/v2/user/update/city", methods={"PUT"});
* @OA\Response(
* response = 400,
* description = "Город не найден"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "cityID",
* description = "ID города",
* type="integer",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function updateUserCityAction(Request $request, UserGetter $userGetter) {
$user = $userGetter->get();
$data = json_decode($request->getContent());
$entityManager = $this->getDoctrine()->getManager();
$city = $entityManager->find(City::class, $data->cityID);
if (!$city) {
return $this->getResponse([], 400, 'City not found');
}
$user->setCity($city);
$entityManager->flush();
return $this->getResponse([], 200);
}
/**
* Изменить пароль
* @Route("/mobile/api/v2/user/update/password", methods={"PUT"});
* @OA\Response(
* response = 400,
* description = "Пароль слишком короткий"
* )
* @OA\Response(
* response = 403,
* description = "Неверный текущий пароль"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "password",
* description = "новый пароль",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "currentPassword",
* description = "текущий пароль",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function updateUserPasswordAction(Request $request, UserGetter $userGetter)
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$password = trim($data->password);
$currentPassword = trim($data->currentPassword);
if ($currentPassword != $user->getPasswordClear()) {
return $this->getResponse([], 403, 'Wrong current password');
}
if (mb_strlen($password) < 6) {
return $this->getResponse([], 400, 'Password too short');
}
$user->encryptPassword($password);
$this->getDoctrine()->getManager()->flush();
return $this->getResponse([], 200);
}
/**
* Отправить код на email
* @Route("/mobile/api/v2/user/email-code/send", methods={"POST"});
* @OA\Response(
* response = 403,
* description = "Неверный email"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "email",
* description = "email пользователя",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function sendEmailCode(Request $request, Mailer $mailer, UserGetter $userGetter)
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$email = trim(mb_strtolower($data->email));
$entityManager = $this->getDoctrine()->getManager();
$result = $entityManager->getRepository(User::class)->findByEmail($email);
if (count($result) > 0) {
return $this->getResponse([], 403);
}
$code = rand(1000, 9999);
$confirmation = new UserConfirmation();
$confirmation->setUserID($user->getID());
$confirmation->setEmail($email);
$confirmation->setAuthCode($code);
$entityManager->persist($confirmation);
$entityManager->flush();
$message = $mailer->createMessage();
$message->setSubject('Подтверждение адреса email');
$message->setFrom('info@slivki.by', 'Slivki.by');
$message->setTo($email);
$message->setBody('Код подтверждения: ' . $code);
$mailer->send($message);
return $this->getResponse([], 200);
}
/**
* Изменить email
* @Route("/mobile/api/v2/user/update/email", methods={"PUT"});
* @OA\Response(
* response = 403,
* description = "Неверный email"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "email",
* description = "email пользователя",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "code",
* description = "код подтверждения",
* type="integer",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function updateUserEmailAction(Request $request, UserGetter $userGetter)
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$email = trim(mb_strtolower($data->email));
$entityManager = $this->getDoctrine()->getManager();
$result = $entityManager->getRepository(UserConfirmation::class)->findBy(
[
'userID' => $user->getID(),
'email' => $email,
'authCode' => $data->code
]
);
if (count($result) == 0) {
return $this->getResponse([], 403);
}
$user->setEmail($email);
$entityManager->remove($result[0]);
$entityManager->flush();
return $this->getResponse([], 200);
}
/**
* Отправить код по номеру телефона
* @Route("/mobile/api/v2/user/phone-code/send", methods={"POST"});
* @OA\Response(
* response = 403,
* description = "Неверный номер телефона"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "phoneNumber",
* description = "Номер телефона пользователя",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function sendPhoneCode(
Request $request,
UserGetter $userGetter,
AuthorizationCodeSender $authorizationCodeSender,
UserPhoneService $userPhoneService
): JsonResponse {
$user = $userGetter->get();
$data = json_decode($request->getContent());
$logger = Logger::instance('DEBUG');
$logger->info(print_r($data, true));
$phoneNumber = trim($data->phoneNumber);
$logger->info(print_r($phoneNumber, true));
$entityManager = $this->getDoctrine()->getManager();
$result = $entityManager->getRepository(UserPhone::class)->findBy(['phoneNumber' => $phoneNumber, 'confirmed' => true]);
if (count($result) > 0) {
foreach ($result as $row) {
if ($row->getUser() !== $user) {
$logger->info('403');
return $this->getResponse([], 403);
}
}
}
$code = random_int(1000, 9999);
$userPhone = $entityManager->getRepository(UserPhone::class)->findOneBy(['user' => $user]);
if (!$userPhone) {
$userPhoneService->addUserPhone($user, $phoneNumber);
}
$userPhone->setAuthCode($code);
$entityManager->flush();
$authorizationCodeSender->send($phoneNumber, $code, $request->getHost());
return $this->getResponse([], 200);
}
/**
* Изменить номер телефона
* @Route("/mobile/api/v2/user/update/phone", methods={"PUT"});
* @OA\Response(
* response = 403,
* description = "Неверный номер телефона"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "phoneNumber",
* description = "Номер телефона пользователя",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "code",
* description = "код подтверждения",
* type="integer",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function updatePhoneAction(
Request $request,
UserGetter $userGetter,
UserPhoneService $userPhoneService
): JsonResponse {
$user = $userGetter->get();
$data = json_decode($request->getContent());
$phoneNumber = trim($data->phoneNumber);
$entityManager = $this->getDoctrine()->getManager();
$userPhone = $entityManager->getRepository(UserPhone::class)->findOneBy(['user' => $user, 'authCode' => $data->code]);
if (!$userPhone || $phoneNumber == '') {
return $this->getResponse([], 403);
}
$userPhoneService->changePhoneNumber($userPhone, $phoneNumber);
return $this->getResponse([], 200);
}
/**
* Список промокодов пользователя
* @Route("/mobile/api/v2/user/codes/{pageNumber}", methods={"GET"});
* @OA\Response(
* response=200,
* description="Список промокодов пользователя",
* @OA\JsonContent(
* @OA\Property(property="ID", type="integer", description="ID кода"),
* @OA\Property(property="offerID", type="integer", description="ID акции"),
* @OA\Property(property="offerActive", type="boolean", description="Флаг активности акции"),
* @OA\Property(property="offerName", type="varchar", description="Название акции"),
* @OA\Property(property="code", type="varchar", description="Промокод"),
* @OA\Property(property="codeCreatedAt", type="datetime", description="Дата покупки промокода"),
* @OA\Property(property="isUsed", type="boolean", description="Флаг использования промокода пользователем"),
* @OA\Property(property="usedAt", type="datetime", description="Дата использования промокода пользователем"),
* @OA\Property(property="isUsedBySupplier", type="boolean", description="Флаг использования промокода поставщиком"),
* @OA\Property(property="codeActiveTill", type="boolean", description="Дата до которой можно использовать промокод"),
* @OA\Property(property="offerType", type="integer", description="тип оффера. 0 обычный, 1 - онлайн ордер, 2 оноайл ордер без возможности купить код отдельно, 3 трайпл, 4 шм, 5 сертификаты"),
* @OA\Property(property="companyName", type="string", description="Название компании"),
* type="object",
* example = {
* "ID": 1,
* "offerID": 1,
* "offerActive": true,
* "offerName": "Название акции",
* "code": "1234-123",
* "codeCreatedAt": "2020-01-01 01:00:03",
* "isUsed": true,
* "usedAt": "2020-01-03 02:00:03",
* "isUsedBySupplier": true,
* "codeActiveTill": "2020-01-01 01:00:03",
* "offerType": 1,
* "offerType": "Название компании",
* }
* )
* )
* @OA\Parameter(
* name="pageNumber",
* in="path",
* description="Номер страницы",
* @OA\Schema(type="integer"),
* )
* @OA\Tag(name="User")
*/
public function getUserCodes(
ImageService $imageService,
UserGetter $userGetter,
QRCodeAggregator $codeAggregator,
QRCodeGeneratorDtoFactory $codeGeneratorDtoFactory,
int $pageNumber
): JsonResponse {
$user = $userGetter->get();
$entityManager = $this->getDoctrine()->getManager();
$limit = 10;
$offset = $limit * ($pageNumber - 1);
$dql = "select offerOrderDetails,offerOrder,offer from Slivki:OfferOrderDetails offerOrderDetails
join offerOrderDetails.offerOrder offerOrder
join offerOrder.offer offer
where offerOrder.user = :user and offerOrder instance of Slivki\Entity\OfferOrder
and not offerOrder instance of Slivki\Entity\FoodOrder
and not offerOrder instance of Slivki\Entity\GiftCertificateOrder
and not offerOrder instance of Slivki\Entity\SubscriptionOrder
and not offerOrder instance of Slivki\Entity\TireOrder
order by offerOrderDetails.ID desc";
$query = $entityManager->createQuery($dql);
$query->setParameter('user', $user);
$query->setMaxResults($limit + 1);
$query->setFirstResult($offset);
$codes = [];
/** @var OfferOrderDetails $offerOrderDetail */
foreach ($query->getResult() as $offerOrderDetail) {
$offerOrder = $offerOrderDetail->getOfferOrder();
$offer = $offerOrder->getOffer();
$director = $offer->findFirstDirector();
$encoder = null !== $offer ? $codeAggregator->aggregate((int) $offer->getID()) : null;
$messageEncode = $encoder !== null ? $encoder->encode($codeGeneratorDtoFactory->create($offerOrderDetail, true)) : null;
$codes[] = [
'ID' => $offerOrderDetail->getID(),
'offerID' => $offer->getID(),
'offerActive' => $offer->isActive(),
'offerName' => $offer->getTitle(),
'imageURL' => 'https://www.slivki.by' . ($offer->getTeaserMedia() ? $imageService->getImageURL($offer->getTeaserMedia(), 500, 324) : ImageService::FALLBACK_IMAGE),
'code' => $offerOrderDetail->getCode(),
'isUsed' => $offerOrderDetail->isUsed(),
'isUsedBySupplier' => $offerOrderDetail->isMarkedUsedBySupplier(),
'codeCreatedAt' => $offerOrderDetail->getCreatedOn()->format('Y-m-d H:i:s'),
'useMessageEncode' => (bool) $messageEncode,
'messageEncode' => $messageEncode,
'usedAt' => !$offerOrderDetail->getMarkedUsedBySupplierChecktime() ? null : $offerOrderDetail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s'),
'codeActiveTill' => $offerOrderDetail->getCodeActiveTill() ? $offerOrderDetail->getCodeActiveTill()->format('d-m-Y H:i:s') : '',
'offerType' => $offer->getOfferType(),
'allowedOnlineOrderTypes' => $offer->getAllowedOnlineOrderTypesOnApp(),
'companyName' => null === $director ? '' : $director->getName(),
];
}
$result['isLast'] = count($codes) <= $limit;
$result['codes'] = array_slice($codes, 0, $limit);
return $this->getResponse($result, 200);
}
/**
* Изменить пароль
* @Route("/mobile/api/v2/user/reset-password", methods={"POST"});
* @OA\Response(
* response = 403,
* description = "Не удалось отправить пароль"
* )
* @OA\Response(
* response = 404,
* description = "Пользователь не найден"
* )
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function resetUserPasswordAction(Request $request, Mailer $mailer, UserGetter $userGetter)
{
$user = $userGetter->get();
if (!$this->sendPassword($mailer, $user->getEmail())) {
return $this->getResponse([], 403);
}
return $this->getResponse([], 200);
}
/**
* @Route("/mobile/api/v2/user/code/set-used", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Установка флага 'использован' коду",
* @OA\Schema(
* @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
* type="object",
* example = {"userBalance": 7.50}
* )
* )
* @OA\Response(
* response = 401,
* description = "Юзер ненайден"
* )
* @OA\Response(
* response = 403,
* description = "Промокод истек по времени или погашен партнером"
* )
* @OA\Response(
* response = 404,
* description = "Промокод ненайден"
* )
* @OA\Parameter(
* name = "offerOrderDetailID",
* in = "query",
* description = "ID заказа",
* required = true,
* @OA\Schema(type="integer"),
*)
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
* )
*/
public function setUserCodeUsed(Request $request, UserGetter $userGetter)
{
$userGetter->get();
$data = json_decode($request->getContent());
$offerOrderDetailID = $data->offerOrderDetailID;
$code = $this->getOfferOrderDetailsRepository()->find($offerOrderDetailID);
$now = new \DateTime();
if (!$code) {
return $this->getResponse([], 404);
}
if ($code->isMarkedUsedBySupplier() || $code->getCodeActiveTill() < $now) {
return $this->getResponse([], 403);
}
if ($code->isUsed()) {
$code->setUsed(false);
} else {
$code->setUsed(true);
}
$this->getDoctrine()->getManager()->flush();
return $this->getResponse([], 200);
}
/**
* Добавить в избранные
* @Route("/mobile/api/v2/user/favorite/add", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Добавление акции в избранное",
* @OA\Schema(
* @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
* type="object",
* example = {"userBalance": 7.50}
* )
* )
* @OA\Response(
* response = 404,
* description = "Юзер или акция ненайдена"
* )
* @OA\Parameter(
* name = "offerID",
* in = "query",
* description = "ID акции",
* required = true,
* @OA\Schema(type="integer"),
*)
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
* )
*/
public function userFavoriteOfferAdd(Request $request, UserGetter $userGetter)
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$offerID = $data->offerID;
$entityManager = $this->getDoctrine()->getManager();
$offer = $this->getOfferRepository()->find($offerID);
if (!$offer) {
return $this->getResponse([], 404);
}
$user->addFavouriteOffer($offer);
$entityManager->flush();
return $this->getResponse([], 200);
}
/**
* Удалить с избранных
* @Route("/mobile/api/v2/user/favorite/delete", methods={"DELETE"});
* @OA\Response(
* response = 200,
* description = "Удаление акции з избранных",
* @OA\Schema(
* @OA\Property(property = "userBalance", type = "decimal", description = "баланс пользователя"),
* type="object",
* example = {"userBalance": 7.50}
* )
* )
* @OA\Response(
* response = 404,
* description = "Юзер или акция ненайдена"
* )
* @OA\Parameter(
* name = "offerID",
* in = "query",
* description = "ID акции",
* required = true,
* @OA\Schema(type="integer"),
*)
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
* )
*/
public function userFavoriteOfferDelete(Request $request, UserGetter $userGetter)
{
$user = $userGetter->get();
$data = json_decode($request->getContent());
$offerID = $data->offerID;
$entityManager = $this->getDoctrine()->getManager();
$offer = $this->getOfferRepository()->find($offerID);
if (!$offer) {
return $this->getResponse([], 404);
}
$user->deleteFavouriteOffer($offer);
$entityManager->flush();
return $this->getResponse([], 200);
}
/**
* Фидбек
* @Route("/mobile/api/v2/user/feedback", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Фидбек принят",
* )
* @OA\Response(
* response = 404,
* description = "Юзер не найден"
* )
* @OA\Response(
* response = 401,
* description = "Не авторизован"
* )
* @OA\Response(
* response = 400,
* description = "Отсутсвуют обязательные параметры в запросе"
* )
* @OA\Parameter(
* name = "HTTP-SLIVKi-USER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*),
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "message",
* description = "Сообщение",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "phone",
* description = "Номер телефона пользователя",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "email",
* description = "Email пользователя",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "phoneVersion",
* description = "Модель устройства",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "os",
* description = "ОС устройства",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "appVersion",
* description = "Версия приложения",
* type="string",
* example="",
* ),
* @OA\Property(
* property = "images",
* description = "Загрузка изображений",
* type="array",
* example="",
* @OA\Items(),
* ),
* ),
* ),
* ),
* @OA\Tag(name="User")
*/
public function userFeedback(Request $request, Mailer $mailer)
{
$message = $request->request->get('message');
if (!$message) {
return $this->getResponse([], 400);
}
$appVersion = $request->request->get('appVersion');
$phone = $request->request->get('phone');
$email = $request->request->get('email');
$phoneVersion = $request->request->get('phoneVersion');
$os = $request->request->get('os');
$body = '<b>Фидбек:</b><br>';
$body .= $message . '<br><br>';
$body .= "<b>Номер телефона пользователя:</b> $phone<br>";
$body .= "<b>Email пользователя:</b> $email<br>";
$body .= "<b>Модель устройства:</b> $phoneVersion<br>";
$body .= "<b>ОС устройства:</b> $os<br>";
$body .= "<b>Версия приложения:</b> $appVersion<br><br>";
$mailerMessage = $mailer->createMessage();
$mailerMessage->setSubject("Фидбек с мобильного приложения")
->setFrom("info@slivki.by", 'Slivki.by')
->setTo("info@slivki.by")
->addCc('dobrovolskaya@slivki.com')
->addCc('dmitry.kazak@slivki.com')
->setBody($body, 'text/html');
/** @var UploadedFile $uploadedFile */
foreach ($request->files->get('images', []) as $uploadedFile) {
$mailerMessage->attachFromPath($uploadedFile->getRealPath(), $uploadedFile->getClientOriginalName(), $uploadedFile->getMimeType());
}
$mailer->send($mailerMessage);
return $this->getResponse([], 200);
}
/**
* Восстановление пароля
* @Route("/mobile/api/v2/restore-password", methods={"GET"});
* @OA\Response(
* response = 200,
* description = "Пароль выслан",
* )
* @OA\Response(
* response = 400,
* description = "Email не найден"
* )
* @OA\Parameter(
* name = "email",
* in = "query",
* description = "Email",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function restorePassword(Request $request, Mailer $mailer) {
$email = trim($request->query->get('email', ''));
if ($email == '') {
return $this->getResponse([], 400);
}
$entityManager = $this->getDoctrine()->getManager();
$user = $entityManager->getRepository(User::class)->findOneByEmail($email);
if (!$user) {
return $this->getResponse([], 400);
}
$message = $mailer->createMessage();
$message->setSubject("Восстановление пароля")
->setFrom("info@slivki.by", 'Slivki.by')
->setTo($user->getEmail())
->setBody(
$this->renderView('Slivki/emails/lost_password.html.twig', [
'password' => $user->getPasswordClear()
]),
'text/html'
);
$mailer->send($message);
return $this->getResponse([], 200);
}
/**
* Авторизация по номеру телефона
* @Route("/mobile/api/v2/user/login/phone", methods={"POST"});
* @OA\Response(
* response = 200,
* description = "Возвращает токен юзера.",
* @OA\Schema(
* @OA\Property(property = "userToken", type = "varchar", description = "токен пользователя"),
* type="object",
* )
* )
* @OA\Response(
* response = 401,
* description = "Сервис не авторизован"
* )
* @OA\Response(
* response = 403,
* description = "Юзер не заблокирован"
* )
* @OA\RequestBody(
* required=true,
* @OA\MediaType(
* mediaType="application/json",
* @OA\Schema(
* type="object",
* @OA\Property(
* property = "phoneNumber",
* description = "номер телефона",
* type="string",
* example="",
* ),
* ),
* ),
* ),
* @OA\Parameter(
* name = "HTTP-SLIVKi-PARTNER-TOKEN",
* in = "header",
* description = "Токен юзера",
* required = true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User")
*/
public function phoneLoginAction(
Request $request,
PhoneNumberHelper $phoneNumberHelper,
UserPhoneRepositoryInterface $userPhoneRepository,
UserPhoneService $userPhoneService
): JsonResponse {
if ($request->headers->get('HTTP-SLIVKi-PARTNER-TOKEN') != User::OPLATI_PARTNER_TOKEN) {
return $this->getResponse([], 401);
}
$data = json_decode($request->getContent());
$logger = Logger::instance('DEBUG');
$logger->info(print_r($data, true));
$entityManager = $this->getDoctrine()->getManager();
$phoneNumber = $phoneNumberHelper->convert($data->phoneNumber);
$userPhone = $userPhoneRepository->findConfirmedByPhoneNumber($phoneNumber);
if ($userPhone) {
$user = $userPhone->getUser();
if ($user && $user->getStatus() == User::STATUS_LOCKED) {
return $this->getResponse([], 403, 'User is locked');
}
$user->setStatus(User::STATUS_CONFIRMED);
}
if (!$userPhone) {
$user = new User();
$user->setCreatedOn(new \DateTime());
$user->setStatus(User::STATUS_CONFIRMED);
$entityManager->persist($user);
$userPhone = $userPhoneService->addUserPhone($user, $phoneNumber);
$userPhoneService->confirmUserPhone($userPhone);
$entityManager->getRepository(User::class)->addDirectorGroupToUserByUser($user);
}
$entityManager->flush();
$mobileToken = $entityManager->getRepository(MobileUserToken::class)->findOneByUser($userPhone->getUser());
if (!$mobileToken) {
$token = md5(microtime() . rand(10, 100));
$mobileToken = new MobileUserToken();
$mobileToken->setToken($token);
$mobileToken->setUser($user);
$entityManager->persist($mobileToken);
$entityManager->flush();
}
return $this->getResponse(['userToken' => $mobileToken->getToken()], 200);
}
/**
* @Route("/mobile/api/v2/user/order-history/{pageNumber}", methods={"GET"});
* @OA\Response(
* response=Response::HTTP_OK,
* description="История покупок",
* @OA\JsonContent(
* @OA\Property(property="type", type="string", description="Тип активности"),
* @OA\Property(property="data", type="string", description="Данные активности"),
* type="object",
* )
* )
* @OA\Response(
* response=Response::HTTP_UNAUTHORIZED,
* description="Юзер не найден"
* )
* @OA\Parameter(
* name="pageNumber",
* in="path",
* description="Номер страницы",
* required=true,
* @OA\Schema(type="integer"),
*)
* @OA\Parameter(
* name="HTTP-SLIVKi-USER-TOKEN",
* in="header",
* description="Токен юзера",
* required=true,
* @OA\Schema(type="string"),
*)
* @OA\Tag(name="User"),
*/
public function getUserOrderHistoryAction(
ImageService $imageService,
QRCodeAggregator $codeAggregator,
UserGetter $userGetter,
GiftCertificateAddressDtoFactory $certificateAddressDtoFactory,
QRCodeGeneratorDtoFactory $codeGeneratorDtoFactory,
$pageNumber = 1
): JsonResponse {
$limit = 32;
$offset = $limit * ($pageNumber - 1);
$result = $this->getUserOrders(
$userGetter->get(),
$imageService,
$codeAggregator,
$certificateAddressDtoFactory,
$this->tireOrderHistoryDtoFactory,
$codeGeneratorDtoFactory,
$limit,
$offset,
);
return $this->getResponse($result, 200);
}
private function getUserOrders(
User $user,
ImageService $imageService,
QRCodeAggregator $codeAggregator,
GiftCertificateAddressDtoFactory $certificateAddressDtoFactory,
TireOrderHistoryDtoFactory $tireOrderHistoryDtoFactory,
QRCodeGeneratorDtoFactory $codeGeneratorDto,
$limit,
$offset
): array {
$result = [];
$entityManager = $this->getDoctrine()->getManager();
$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";
$offerOrders = $entityManager->createQuery($dql)
->setParameter('userID', $user->getID())
->getResult();
$balanceActivity = $this->getBalanceActivity($user);
$all = array_merge($balanceActivity, $offerOrders);
usort($all, static function ($item1, $item2) {
return $item2->getCreatedOn()->format('U') - $item1->getCreatedOn()->format('U');
});
$offerUtilRuntime = [];
$offerOrders = array_slice($all, $offset, $limit);
foreach ($offerOrders as $offerOrder) {
$encoder = null;
if (null !== $offerOrder->getOffer()) {
$encoder = $codeAggregator->aggregate((int) $offerOrder->getOffer()->getID());
}
if ($offerOrder instanceof UserBalanceActivity) {
$bonusTypeBalanceActivityList = UserBalanceActivityType::BONUS_ACTIVITIES;
$siteSettings = $entityManager->getRepository(SiteSettings::class)->getSiteSettingsCached();
if (in_array($offerOrder->getType()->getID(), $bonusTypeBalanceActivityList)) {
$name = $offerOrder->getType()->getName();
$type = str_replace("%s", $siteSettings->getMonthlyCodeCount(), $name);
$result[] = (object) ["type" => "bonus", "data" => ['typeName' => $type, 'amount' => $offerOrder->getAmount(), 'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')]];
} else {
$result[] = (object) ["type" => "payments", "data" => ['typeName' => $offerOrder->getType()->getName(), 'amount' => $offerOrder->getAmount(), 'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')]];
}
} else if ($offerOrder instanceof OfferOrder && !($offerOrder instanceof FoodOrder || $offerOrder instanceof GiftCertificateOrder || $offerOrder instanceof TireOrder)) {
$offer = $offerOrder->getOffer();
$offerOrderDetails = $offerOrder->getOfferOrderDetails();
if ($offerOrderDetails) {
foreach ($offerOrderDetails as $offerOrderDetail) {
$messageEncode = null;
if ($encoder !== null) {
$messageEncode = $encoder->encode($codeGeneratorDto->create($offerOrderDetail, true));
}
$result[] = (object) ["type" => "codes", "data" => [
'ID' => $offerOrderDetail->getID(),
'orderID' => $offerOrder->getID(),
'offerID' => $offer->getID(),
'offerActive' => $offer->isActive(),
'offerName' => $offer->getTitle(),
'imageURL' => 'https://www.slivki.by' . ($offer->getTeaserMedia() ? $imageService->getImageURL($offer->getTeaserMedia(), 500, 324) : ImageService::FALLBACK_IMAGE),
'code' => $offerOrderDetail->getCode(),
'isUsed' => $offerOrderDetail->isUsed(),
'isUsedBySupplier' => $offerOrderDetail->isMarkedUsedBySupplier(),
'codeCreatedAt' => $offerOrderDetail->getCreatedOn()->format('Y-m-d H:i:s'),
'usedAt' => !$offerOrderDetail->getMarkedUsedBySupplierChecktime() ? null : $offerOrderDetail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s'),
'codeActiveTill' => $offerOrderDetail->getCodeActiveTill() ? $offerOrderDetail->getCodeActiveTill()->format('d-m-Y H:i:s') : '',
'offerType' => $offer->getOfferType(),
'allowedOnlineOrderTypes' => $offer->getAllowedOnlineOrderTypesOnApp(),
'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s'),
'useMessageEncode' => (bool) $messageEncode,
'messageEncode' => $messageEncode,
]];
}
}
} else if($offerOrder instanceof GiftCertificateOrder) {
$offer = $offerOrder->getOffer();
$giftCertificates = [];
/** @var OfferOrderDetails $detail */
$complexName = '';
foreach ($offerOrder->getOfferOrderDetails() as $detail) {
if (!$detail) {
continue;
}
$giftCertificate = $detail->getGiftCertificate();
if ($giftCertificate) {
if ($giftCertificate->getCodesPerItem() < 1) {
$complexName .= $giftCertificate->getName() . ', ';
}
$messageEncode = null;
if ($encoder !== null) {
$messageEncode = $encoder->encode($codeGeneratorDto->create($detail, true));
}
$price = $giftCertificate->getPriceOffer();
$offerPrice = $giftCertificate->getPriceRegular();
if ($giftCertificate->getBundlePromoCount() > 0) {
$price = \round($price / $giftCertificate->getBundlePromoCount(), 2);
$offerPrice = \round($offerPrice / $giftCertificate->getBundlePromoCount(), 2);
}
$giftCertificates[] = [
'name' => $giftCertificate->getName(),
'imageURL' => $imageService->getImageURLCachedWithDomain($offer->getMobileTeaserMedia(), 764, 0),
'price' => (string) $price,
'offerPrice' => (string) $offerPrice,
'itemsCount' => $detail->getItemsCount(),
'code' => $detail->getCode(),
'useMessageEncode' => (bool) $messageEncode,
'messageEncode' => $messageEncode,
'codeActiveTill' => $detail->getCodeActiveTill()->format('Y-m-d H:i:s'),
'isUsed' => $detail->isUsed(),
'isUsedBySupplier' => $detail->isMarkedUsedBySupplier(),
'codeCreatedAt' => $detail->getCreatedOn()->format('Y-m-d H:i:s'),
'usedAt' => $detail->getMarkedUsedBySupplierChecktime() ? $detail->getMarkedUsedBySupplierChecktime()->format('Y-m-d H:i:s') : null,
'certificateURL' => '/mobile/api/v2/gift-certificate/' . $detail->getID() . '/pdf',
'addresses' => array_map(
[$certificateAddressDtoFactory, 'create'],
$giftCertificate->getGeoLocations()->toArray(),
),
];
}
}
if ($complexName != '') {
$giftCertificates[0]['items'] = $giftCertificates;
$giftCertificates[0]['name'] = trim($complexName, ', ');
$giftCertificates = [$giftCertificates[0]];
}
$result[] = (object) array("type" => "gift-certificate", "data" => [
'id' => $offerOrder->getID(),
'offerID' => $offer->getID(),
'rating' => $offer->getRating() + 0.0001,
'companyName' => $offer->getCompanyName(),
'title' => $offer->getTitle(),
'giftCertificates' => $giftCertificates,
'discount' => $offer->getDiscount(),
'codeCost' => $offer->getCodeCost(),
'amount' => $offerOrder->getAmount(),
'orderDate' => $offerOrder->getCreatedOn(),
'createdOn' => $offerOrder->getCreatedOn()->format('Y-m-d H:i:s')
]);
} else if ($offerOrder instanceof FoodOrder) {
$offer = $offerOrder->getOffer();
$foodOrderHistory = $this->foodOrderHistoryDtoFactory->create($offerOrder);
$amountOfferPrice = $foodOrderHistory->getOrderProductsSum();
$amountPrice = $foodOrderHistory->getOrderProductsRegularSum();
$codeCost = $foodOrderHistory->getCodePrice();
$codesCount = $foodOrderHistory->getCodesCount();
$result[] = (object) array("type" => "online-orders", "data" => [
'id' => $foodOrderHistory->getOrderId(),
'offerID' => $foodOrderHistory->getOfferId(),
'rating' => $offer->getRating() + 0.0001,
'imageUrl' => $foodOrderHistory->getOfferImageUrl(),
'companyName' => $offer->getCompanyName(),
'title' => $offer->getTitle(),
'dishes' => array_values(array_map(
static fn (FoodOrderProductDto $product): array => [
'name' => $product->getName(),
'price' => $product->getRegularPrice(),
'offerPrice' => $product->getPurchasePrice(),
'itemsCount' => $product->getAmount(),
'imageUrl' => $product->getImageUrl(),
],
$foodOrderHistory->getProducts(),
)),
'options' => array_values(array_map(
static fn (FoodOrderProductDto $option): array => [
'name' => $option->getName(),
'price' => $option->getRegularPrice(),
'offerPrice' => $option->getPurchasePrice(),
'itemsCount' => $option->getAmount(),
'imageUrl' => $option->getImageUrl(),
],
$foodOrderHistory->getOptions(),
)),
'discount' => $offer->getDiscount(),
'codesCount' => $codesCount,
'codeCost' => (string)$codeCost,
'productsAmount' => number_format($amountOfferPrice + $codesCount * $codeCost, 2, '.', ''),
'amount' => number_format($amountPrice, 2, '.', ''),
'orderDate' => $foodOrderHistory->getOrderedAt()->format('Y-m-d H:i:s'),
'createdOn' => $foodOrderHistory->getOrderedAt()->format('Y-m-d H:i:s'),
'usedPartnerCashbackSum' => $offerOrder->getUsedPartnerCashbackSum(),
'deliveryPrice' => (float) number_format($foodOrderHistory->getDeliveryPrice(), 2, '.', ''),
]);
} else if ($offerOrder instanceof TireOrder) {
$result[] = [
'type' => UserOrderHistoryType::TIRE,
'data' => $tireOrderHistoryDtoFactory->create($offerOrder),
];
}
}
return $result;
}
private function getBalanceActivity(User $user) {
$userID = $user->getID();
$entityManager = $this->getDoctrine()->getManager();
$userRegistrationBonusCancel = $user->getBalanceActivityByType($entityManager->find(UserBalanceActivityType::class, UserBalanceActivity::TYPE_REGISTRATION_BONUS_CANCEL));
$userRegistrationBonusCancelCondition = '';
if ($userRegistrationBonusCancel->count() > 0) {
$userRegistrationBonusCancelCondition = ' AND UserBalanceActivity.type != ' . UserBalanceActivity::TYPE_REGISTRATION_BONUS
. 'AND UserBalanceActivity.type != ' . UserBalanceActivity::TYPE_REGISTRATION_BONUS_CANCEL;
}
$dql = "SELECT UserBalanceActivity
FROM Slivki:UserBalanceActivity UserBalanceActivity
WHERE UserBalanceActivity.user = $userID $userRegistrationBonusCancelCondition
ORDER BY UserBalanceActivity.createdOn DESC";
$query = $entityManager->createQuery($dql);
$balanceActivity = $query->getResult();
return $balanceActivity;
}
}