<?php
namespace WebBundle\Controller;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\ORM\NoResultException;
use Exception;
use OpenApi\Annotations as OA;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use WebBundle\Entity\BuyOrder;
use WebBundle\Entity\BuyOrderArticle;
use WebBundle\Entity\OrderAddress;
use WebBundle\Enum\BuyOrderStatusEnum;
use WebBundle\Filler\OrderFiller;
use WebBundle\Helper\App;
use WebBundle\Helper\OrderHelper;
use WebBundle\Helper\ResponseApiHelper;
use WebBundle\Helper\UserHelper;
use WebBundle\Repository\BuyOrderRepository;
use WebBundle\Repository\OrderAddressRepository;
use WebBundle\Repository\UserRepository;
use WebBundle\Service\OrderAddressService;
use WebBundle\Service\OrderHistoryService;
use WebBundle\Service\OrderRefundService;
use WebBundle\Service\OrderService;
use WebBundle\Service\UserService;
use WebBundle\Service\VatService;
class OrderController extends ExtendedController
{
/** @required */
public OrderFiller $orderFiller;
/** @required */
public OrderRefundService $orderRefundService;
/** @required */
public UserService $userService;
public const COUNT_ORDERS_ON_POPUP = 6;
public const HEIGHT_STRING = 60;
protected BuyOrderRepository $buyOrderRepository;
protected OrderService $orderService;
protected OrderAddressService $orderAddressService;
protected OrderHistoryService $orderHistoryService;
private OrderAddressRepository $orderAddressRepository;
private VatService $vatService;
protected array $messages = [
'notToken' => 'Token is not correct',
'notOrder' => 'Order not found',
'notArticle' => 'Article not found',
'notPay' => 'Order not ready to pay'
];
/**
* @param OrderService $orderService
* @param OrderAddressService $orderAddressService
* @param OrderHistoryService $orderHistoryService
* @param VatService $vatService
* @param BuyOrderRepository $buyOrderRepository
* @param UserRepository $userRepository
* @param OrderAddressRepository $orderAddressRepository
* @throws Exception
*/
public function __construct(
OrderService $orderService,
OrderAddressService $orderAddressService,
OrderHistoryService $orderHistoryService,
VatService $vatService,
BuyOrderRepository $buyOrderRepository,
OrderAddressRepository $orderAddressRepository
) {
parent::__construct();
$this->orderService = $orderService;
$this->orderAddressService = $orderAddressService;
$this->orderHistoryService = $orderHistoryService;
$this->vatService = $vatService;
$this->buyOrderRepository = $buyOrderRepository;
$this->orderAddressRepository = $orderAddressRepository;
}
/**
* @IsGranted("ROLE_ADMIN")
* @param string $hash
* @return JsonResponse|RedirectResponse
* @throws NonUniqueResultException
* @throws Exception
*/
public function sendEmailTest(string $hash)
{
$res = [];
if (App::isDev()) {
if ($order = $this->orderService->getOrderObj($hash)) {
if ($order->getStatus() > BuyOrderStatusEnum::AWAITING_CALCULATION) {
$this->orderHistoryService->saveHistoryAndSendEmail(
$order,
'delivery_calculated',
OrderHistoryService::SEND_EMAIL
);
return $this->redirectToRoute('app_buy_order', ['orderId' => $hash]);
} else {
$res['err'] = 'Order status must be three or more.';
}
} else {
$res['err'] = 'Order not found';
}
} else {
$res['err'] = 'Production environment';
}
return new JsonResponse($res);
}
/**
* Создание черновика заказа
*
* @param Request $request
* @return JsonResponse
* @throws Exception
*
* @OA\Response(
* response=200,
* description="ОК. Создание нового заказа",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="order", type="object", description="Информация по целевому заказу",
* @OA\Property(property="hash", description="Уникальный идентификатор заказа", example="0917aac1aec6197ccf38afa3c9314192"),
* @OA\Property(property="name", description="Назваине проекта", example="Подборка для ванной"),
* @OA\Property(property="createDate", description="Дата создания текстом", example="16 августа 2020 г."),
* @OA\Property(property="createDateTimestamp", description="Дата создания в формате милисекунд", example="1470805363"),
* @OA\Property(property="updateDate", description="Дата обновления текстом", example="22 сентября 2021 г."),
* @OA\Property(property="updateDateTimestamp", description="Дата обновления в формате милисекунд", example="1470805363"),
* @OA\Property(property="items", description="количество артикулов в заказе", example="3"),
* @OA\Property(property="weight", description="Общий вес заказа", example="55 kg"),
* @OA\Property(property="totalPrice", description="Общая стоимость заказа", example="505 €"),
* @OA\Property(property="status", type="object", description="Статус заказа",
* @OA\Property(property="id", description="Цировой код статуса", example="1"),
* @OA\Property(property="text", description="Статус заказа текстом", example="Черновик заказа")
* )
* ),
* @OA\Property(property="list", type="array", description="Список заказов пользователя",
* @OA\Items(
* @OA\Property(property="hash", description="Уникальный идентификатор заказа", example="0917aac1aec6197ccf38afa3c9314192"),
* @OA\Property(property="name", description="Назваине проекта", example="Подборка для ванной"),
* @OA\Property(property="createDate", description="Дата создания текстом", example="16 августа 2020 г."),
* @OA\Property(property="createDateTimestamp", description="Дата создания в формате милисекунд", example="1470805363"),
* @OA\Property(property="updateDate", description="Дата обновления текстом", example="22 сентября 2021 г."),
* @OA\Property(property="updateDateTimestamp", description="Дата обновления в формате милисекунд", example="1470805363"),
* @OA\Property(property="items", description="количество артикулов в заказе", example="3"),
* @OA\Property(property="weight", description="Общий вес заказа", example="55 kg"),
* @OA\Property(property="totalPrice", description="Общая стоимость заказа", example="505 €"),
* @OA\Property(property="status", type="object", description="Статус заказа",
* @OA\Property(property="id", description="Цировой код статуса", example="1"),
* @OA\Property(property="text", description="Статус заказа текстом", example="Черновик заказа")
* )
* )
* )
* )
* )
* @OA\RequestBody(
* description="Вмесмто обычного post['name'] параметра можно передать json в теле запроса",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="name", description="Название заказа", example="Test order")
* )
* )
* @OA\Parameter(
* name="_locale",
* in="path",
* required=true,
* description="локаль",
* @OA\Schema(type="string")
* )
* @OA\Parameter(
* name="name",
* in="query",
* required=false,
* description="Название заказа, так же можно передать через json в теле запроса",
* @OA\Schema(type="string")
* )
* @OA\Tag(name="Заказы")
*/
public function create(Request $request): JsonResponse
{
$token = UserHelper::getInstance()->getToken();
$name = $request->request->get('name');
if (!$name) {
$json = json_decode($request->getContent(), true);
if (empty($json['name'])) {
return new JsonResponse(['status' => false, 'message' => 'Name is not defined'], 400);
} else {
$name = $json['name'];
}
}
$order = $this->orderService->create($token, $request->request->get('name'), true);
return new JsonResponse([
'order' => $order,
'list' => $this->orderService->getListOrder($token)
]);
}
/**
* Редактирование имени заказа
*
* @param Request $request
* @return JsonResponse
* @throws Exception
*
* @OA\Response(
* response=200,
* description="ОК. Редактирование имени заказа",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="order", type="object", description="Информация по целевому заказу",
* @OA\Property(property="hash", description="Уникальный идентификатор заказа", example="0917aac1aec6197ccf38afa3c9314192"),
* @OA\Property(property="name", description="Назваине проекта", example="Подборка для ванной"),
* @OA\Property(property="createDate", description="Дата создания текстом", example="16 августа 2020 г."),
* @OA\Property(property="createDateTimestamp", description="Дата создания в формате милисекунд", example="1470805363"),
* @OA\Property(property="updateDate", description="Дата обновления текстом", example="22 сентября 2021 г."),
* @OA\Property(property="updateDateTimestamp", description="Дата обновления в формате милисекунд", example="1470805363"),
* @OA\Property(property="items", description="количество артикулов в заказе", example="3"),
* @OA\Property(property="weight", description="Общий вес заказа", example="55 kg"),
* @OA\Property(property="totalPrice", description="Общая стоимость заказа", example="505 €"),
* @OA\Property(property="status", type="object", description="Статус заказа",
* @OA\Property(property="id", description="Цировой код статуса", example="1"),
* @OA\Property(property="text", description="Статус заказа текстом", example="Черновик заказа")
* )
* ),
* @OA\Property(property="list", type="array", description="Список заказов пользователя",
* @OA\Items(
* @OA\Property(property="hash", description="Уникальный идентификатор заказа", example="0917aac1aec6197ccf38afa3c9314192"),
* @OA\Property(property="name", description="Назваине проекта", example="Подборка для ванной"),
* @OA\Property(property="createDate", description="Дата создания текстом", example="16 августа 2020 г."),
* @OA\Property(property="createDateTimestamp", description="Дата создания в формате милисекунд", example="1470805363"),
* @OA\Property(property="updateDate", description="Дата обновления текстом", example="22 сентября 2021 г."),
* @OA\Property(property="updateDateTimestamp", description="Дата обновления в формате милисекунд", example="1470805363"),
* @OA\Property(property="items", description="количество артикулов в заказе", example="3"),
* @OA\Property(property="weight", description="Общий вес заказа", example="55 kg"),
* @OA\Property(property="totalPrice", description="Общая стоимость заказа", example="505 €"),
* @OA\Property(property="status", type="object", description="Статус заказа",
* @OA\Property(property="id", description="Цировой код статуса", example="1"),
* @OA\Property(property="text", description="Статус заказа текстом", example="Черновик заказа")
* )
* )
* )
* )
* )
* @OA\RequestBody(
* description="Вмесмто обычного post['name'] и post['hash'] параметра можно передать json в теле запроса",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="name", description="Название заказа", example="Test order"),
* @OA\Property(property="hash", description="идентификатор заказ", example="0917aac1aec6197ccf38afa3c9314192")
* )
* )
* @OA\Parameter(
* name="_locale",
* in="path",
* required=true,
* description="локаль",
* @OA\Schema(type="string")
* )
* @OA\Parameter(
* name="name",
* in="query",
* required=false,
* description="Название заказа, так же можно передать через json в теле запроса",
* @OA\Schema(type="string")
* )
* @OA\Parameter(
* name="hash",
* in="query",
* required=false,
* description="идентификатор заказа, так же можно передать через json в теле запроса",
* @OA\Schema(type="string")
* )
* @OA\Tag(name="Заказы")
*/
public function edit(Request $request): JsonResponse
{
$token = UserHelper::getInstance()->getToken();
$name = $request->request->get('name');
$hash = $request->request->get('hash');
$json = json_decode($request->getContent(), true);
if (!$name) {
if (empty($json['name'])) {
return new JsonResponse(['status' => false, 'message' => 'Name is not defined'], 400);
} else {
$name = $json['name'];
}
}
if (!$hash) {
if (empty($json['hash'])) {
return new JsonResponse(['status' => false, 'message' => 'Hash is not defined'], 400);
} else {
$hash = $json['hash'];
}
}
return new JsonResponse([
'order' => $this->orderService->editName($hash, $name),
'list' => $this->orderService->getListOrder($token)
]);
}
/**
* Страница заказа
*
* @param string $hash
* @return Response
* @throws Exception
*/
public function indexAction(string $hash): Response
{
$res = $this->orderService->checkHashRedirect($hash);
if ($res) {
return $res;
}
$order = $this->orderService->getOrder($hash, true);
$request = App::getRequest();
if (!$order) {
throw $this->createNotFoundException('Order not found');
}
switch ($request->get('shareFormat')) {
case 'pdf':
return $this->orderService->getPdfInPage(
$this->generateUrl(
'app_order',
[
'_locale' => App::getCurLocale(true),
'hash' => $order['hash'],
'share' => 'pdf'
],
UrlGeneratorInterface::ABSOLUTE_URL
),
['orderNumber' => $order['number'] ?: $order['hash']]
);
case 'excel':
$exOrder = $this->buyOrderRepository->getOrder($order['hash']);
return $this->orderService->convertToExcel($exOrder);
}
return $this->renderReact('@Web/Order/show.html.twig', [
'title' => $order['title'],
'initialState' => ['order' => $order]
]);
}
/**
* Функция для инициализации возврата средств клиентом в заказе
* https://te.remote.team/#/discus/81B16B1E-73F2-C38C-D1D3-66D826089072/
*
* @param Request $request
* @param string $hash
* @return JsonResponse
*/
public function refundCompensation(Request $request, string $hash): JsonResponse
{
return new JsonResponse($this->orderRefundService->refundOrCompensation($hash, $request->request->all()));
}
/**
* @param string $hash
* @param int $responseOld
* @return JsonResponse
* @throws Exception
*/
public function resetTimerAction(string $hash, int $responseOld = 0): JsonResponse
{
$this->orderService->timer = true;
try {
$order = $this->orderService->change($hash, '{"reset":true}');
} catch (NoResultException $e) {
OrderHelper::Alert([
'subject' => 'Ошибка запроса reset-timer для заказа',
'message' => 'Заказа нет или он удалён',
'hash ' => $hash,
'responseOld ' => $responseOld,
], 'rzagorudko|dfomenkov131122');
$order = null;
}
if ($order) {
if (!empty($responseOld)) {
$response = $this->orderFiller->fillArrayWithOldOrderData($order);
} else {
$response = $this->orderService->orderData($order);
$response['fetchRequestNum'] = App::getRequest()->request->get('fetchRequestNum');
}
} else {
$response = new ResponseApiHelper();
$response->validate('Order', '', 'empty', 'NULL');
$response = $response->result();
}
return new JsonResponse($response);
}
/**
* @param string $hash
* @param bool $full
* @return JsonResponse
* @throws Exception
*/
public function apiOrderAction(string $hash, ?bool $full = false): JsonResponse
{
if (App::getRequest()->request->get('data')) {
$order = $this->orderService->change($hash, App::getRequest()->request->get('data'));
$orderArray = $this->orderService->orderData($order, ['full' => $full]);
}
$response = $orderArray ?? $this->orderService->getOrder($hash);
$response['fetchRequestNum'] = App::getRequest()->request->get('fetchRequestNum');
return new JsonResponse($response);
}
/**
* @param string $hash
* @param bool $debug
* @return JsonResponse
* @throws Exception
*/
public function apiHistoryAction(string $hash, bool $debug): JsonResponse
{
$history = $this->orderService->getHistory($hash, $debug);
return new JsonResponse($history);
}
/**
* Запросы ручного расчета доставки
*
* @param Request $request
* @param string $hash
* @return JsonResponse
* @throws Exception
*/
public function requestDeliveryAction(Request $request, string $hash): JsonResponse
{
$data = json_decode($request->get('data'), true);
if (!App::getCurUser() || !empty($data['email'])) {
$data = $this->userService->checkEmail($data['email'], $data['token'] ?? null);
if (!$data->getStatus()) {
$response['email_exist'] = ['exist' => 'checked', 'message' => ''];
$response['email_exist_db'] = ['exist' => !$data->getStatus(), 'message' => $data->getError()];
$response['status'] = 200;
return new JsonResponse($response);
}
}
if ($data) {
$order = $this->orderService->requestCalculateDeliveryByHash($hash, $request->get('data'));
return new JsonResponse($order ?? $this->orderService->getOrder($hash));
}
return new JsonResponse(['err' => 'Can not parsed json']);
}
/**
* Перемещение артикулов из заказов в другие заказы
*
* @param Request $request
* @return JsonResponse
* @throws Exception
*/
public function transferItemsAction(Request $request): JsonResponse
{
$data = json_decode($request->get('data'), true);
if ($data) {
return new JsonResponse($this->orderService->transferItems($data));
}
return new JsonResponse(['err' => 'Can not parsed json']);
}
/**
* Удаления артикула/ов из заказа
*
* @param Request $request
* @return JsonResponse
* @throws Exception
*/
public function delItemsAction(Request $request): JsonResponse
{
$data = json_decode($request->get('data'), true);
if (!$data){
return new JsonResponse(['err' => 'Can not parsed json']);
}
$error = null;
$order = null;
if (empty($data['ides']) || count($data['ides']) == 0) {
$error = 'ides is empty';
} elseif (empty($data['hash'])) {
$error = 'hash is empty';
} else {
/** @var BuyOrder $order */
$order = $this->buyOrderRepository->getOrder($data['hash']);
if (!$order) {
$error = 'order not found';
} else {
$order = $this->orderService->delItems($order, $data['ides']);
}
}
return new JsonResponse([
'error' => $error,
'order' => $order,
]);
}
/**
* Удаления адреса заказа
*
* @param Request $request
* @return JsonResponse
* @throws Exception
*/
public function delAddressesAction(Request $request): JsonResponse
{
$data = json_decode($request->get('data'), true);
if (!$data) {
return new JsonResponse(['err' => 'Can not parsed json']);
}
$error = null;
$status = false;
if (empty($data['ides']) || count($data['ides']) == 0) {
$error = 'ides is empty';
} else {
$token = UserHelper::getInstance()->getToken();
$orderAddresses = $this->orderAddressRepository->getAddressByIdes($data['ides']);
/** @var OrderAddress $orderAddress */
foreach ($orderAddresses as $orderAddress) {
if (
$orderAddress->getToken() == $token ||
$this->get('security.authorization_checker')->isGranted('ROLE_ORDER_MASTER')
) {
if (! $orderAddress->getFrozen()) {
$this->orderAddressService->delete($orderAddress);
}
$status = true;
} else {
$error = 'Access denied';
}
}
}
return new JsonResponse([
'error' => $error,
'status' => $status,
]);
}
/**
* Проверяем, что email не занят в другой учетной записи
*
* @return JsonResponse
* @throws Exception
*/
public function checkEmailAction(Request $request): JsonResponse
{
$email = $request->get('email');
$emailInfo = $this->userService->checkEmail($email);
$responseArr = [
'status' => (int) $emailInfo->getStatus(),
'email_exist' => (int) !$emailInfo->getStatus(),
];
if (!$emailInfo->getStatus()) {
$responseArr['err'] = $emailInfo->getError();
}
return new JsonResponse($responseArr);
}
/**
* @param string $vat
* @return JsonResponse
* @throws Exception
*/
public function checkVATAction(string $vat): JsonResponse
{
return new JsonResponse($this->vatService->checkVAT($vat));
}
/**
* @return JsonResponse|null
* @throws Exception
*/
public function ordersShortListAction(): ?JsonResponse
{
$token = UserHelper::getInstance()->getToken();
return new JsonResponse($this->orderService->orderShortList($token));
}
/**
* Список заказов для выпадающего списка
*
* @param null $height
* @return Response
* @throws Exception
*/
public function lastOrderAction($height = null): Response
{
$countString = ($height) ? floor($height / 2 / self::HEIGHT_STRING) : self::COUNT_ORDERS_ON_POPUP;
return $this->render('@Web/BuyOrder/last-orders.html.twig', [
'orders' => $this->orderService->getOrders(UserHelper::getInstance()->getToken()),
'countString' => $countString
]);
}
/**
* Удаление формируемого заказа
* @param string $orderId
* @return JsonResponse
* @throws Exception
*/
public function deleteAction(string $orderId): JsonResponse
{
$res = $this->orderService->delete($orderId);
$res['list'] = $this->lastOrderAction()->getContent();
return new JsonResponse(['status' => 0, 'response' => $res]);
}
/**
* @param $hash
* @return RedirectResponse
* @throws NonUniqueResultException
*/
public function recoveryCancelOrderAction($hash): RedirectResponse
{
return $this->orderService->recoveryCancelOrder($hash);
}
/**
* Удаление формируемого заказа
* @param string $hash
* @return JsonResponse
* @throws Exception
*/
public function deleteAllDataUserAction(string $hash): JsonResponse
{
return new JsonResponse($this->orderService->delAllData($hash));
}
/**
* Добавление артикула в заказ
*
* @param int $itemId
* @param ?float $itemCount
* @param ?int $type
* @return JsonResponse
* @throws Exception
*/
public function addItemAction(int $itemId, ?float $itemCount = null, ?int $type = BuyOrderArticle::TYPE_NORMAL): JsonResponse
{
$ordersAmount = [];
if (!empty($_POST['orders'])) {
$ordersAmount = $_POST['orders'];
}
$result = $this->orderService->changeElement($itemId, $ordersAmount, $itemCount, $type);
if ($result) {
$result['action'] = 'add';
} else {
$result['err'] = 'Fail operation';
}
return new JsonResponse([
'status' => 0,
'response' => [
'res' => $result,
]
]);
}
/**
* Редактирование имени заказа
*
* @param string $hash
* @param string $name
* @return JsonResponse
* @throws Exception
*/
public function editAction(string $hash, string $name): JsonResponse
{
$this->orderService->changeName($hash, $name);
return new JsonResponse([
'status' => 0,
'response' => [
'res' => 'ok',
'list' => $this->lastOrderAction()->getContent(),
]
]);
}
/**
* Список заказов для меню выбора
*
* @param Request $request
* @param int $articleId
* @param mixed $type
* @return JsonResponse|RedirectResponse
* @throws Exception
*/
public function listAction(Request $request, int $articleId, $type = BuyOrderArticle::TYPE_NORMAL): Response
{
$response = $this->orderService->getOrderAddList(
$articleId,
(int) $type,
(float) $request->request->get('articleCount', $request->request->get('itemCount', 0.1))
);
if (!empty($response['redirect'])) {
return new RedirectResponse($response['redirect']);
}
return new JsonResponse($response);
}
/**
* Синхронизация заказа с 1с.
*
* @param $hash
* @return RedirectResponse
* @throws Exception
*/
public function syncAction($hash): RedirectResponse
{
if ($this->isGranted('ROLE_ADMIN') || $this->isGranted('ROLE_CONS')) {
$this->orderService->syncOrder($hash);
}
return $this->redirect(
$this->generateUrl('app_buy_order', ['orderId' => $hash], 0)
);
}
/**
* Переотправка заказа с 1с.
*
* @param string $hash
* @return RedirectResponse
* @throws Exception
*/
public function recreateAction(string $hash): RedirectResponse
{
if ($this->isGranted('ROLE_ADMIN')
|| $this->isGranted('ROLE_CONS')
) {
$this->orderService->recreateOrderTo1C($hash);
}
return $this->redirect(
$this->generateUrl('app_buy_order', ['orderId' => $hash], 0)
);
}
public function overpaymentAction(Request $request, string $orderId, bool $type): Response
{
$res = new ResponseApiHelper();
$result = $this->orderRefundService->overPayment(
$orderId,
$type,
$request->get('redirect') && !$type ? ['redirect' => 1] : $request->request->all()
);
if (!empty($result['err'])) {
$res->setResponse('res', 'err');
$res->setResponse('err', $result['err']);
} else {
$res->setResponse('res', 'ok');
$res->setResponse('status', $result['status']);
$res->setResponse('id', $result['id']);
}
if ($request->get('redirect') == 1) {
$params = ['orderId' => $orderId];
if (isset($result['already'])) {
if ($result['already']) {
$params['msgVariant'] = $result['status']['id'];
} else {
$params['showRequisites'] = 1;
}
}
return new RedirectResponse($this->generateUrl('app_buy_order', $params));
}
return $this->json($res->result());
}
/**
* @param string $hash
* @param string $id
* @return JsonResponse
* @throws Exception
*/
public function emailResendAction(string $hash, string $id): JsonResponse
{
$order = $this->orderService->getOrderObj($hash);
$success = $this->orderHistoryService->emailResend($order, $id);
return new JsonResponse(['success' => $success]);
}
/**
* Подписка или отписка на статусы заказа
*
* @param string $hash
* @return Response
* @throws Exception
*/
public function subscribeOrUnsubscribeToOrderStatusesAction(string $hash): Response
{
$order = $this->orderService->getOrderObj($hash, true);
$newOrderStatus = !$order->getEmailSend();
$order->setEmailSend($newOrderStatus);
$this->buyOrderRepository->save($order);
$orderId = $order->getId();
return $this->renderReact('@Web/Order/subscribe_status.html.twig', [
'orderId' => $orderId,
'subscribeStatus' => $newOrderStatus,
]);
}
}