<?php
namespace App\Controller;
use App\Dto\OrderFreeOutput;
use App\Dto\OrderHistoryParams;
use App\Dto\VinChekInput;
use App\Entity\Order;
use App\Entity\Vin;
use App\Message\CheckPaymentMessage;
use App\Repository\OrderRepository;
use App\Service\Order\OrderService;
use App\Service\Report\ReportService;
use App\Service\TokenService;
use App\Service\Vin\VinService;
use Doctrine\ORM\EntityManagerInterface;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation AS Operation;
use OpenApi\Annotations as OA;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Uid\Uuid;
class OrderController extends AbstractController
{
public function __construct(
private OrderService $orderService,
private SerializerInterface $serializer,
private EntityManagerInterface $em,
private VinService $vinService,
private ReportService $reportService,
private TokenService $tokenService,
private MessageBusInterface $bus,
) {
}
/**
* @OA\Response(
* response="201",
* description="Returns created order",
* @Model(type=Order::class, groups={"index"})
* ),
* @OA\Response(
* response="400",
* description="Wrong input data"
* ),
* @OA\Parameter(
* name="User-Id",
* in="header",
* required=true,
* @OA\Schema(type="string", format="uuid")
* ),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="vin", type="string", example="4GDDU03A8VD268007"),
* @OA\Property(property="email", type="string", example="test@test.ru"),
* @OA\Property(property="code", type="string", example="1a2b3c"),
* ),
* )
*/
#[Route('/api/order', name: 'app_make_order', methods: ['POST'], format: 'json')]
public function handleMakeOrder(Request $request): Response
{
try {
$payload = \json_decode((string) $request->getContent(), true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException $e) {
throw new BadRequestHttpException(\sprintf('Bad request: %s', $e->getMessage()));
}
$vin = $payload['vin'] ?? null;
$email = $payload['email'] ?? null;
$code = $payload['code'] ?? null;
if ($vin === null || $email === null) {
throw new BadRequestHttpException('Fields: \'vin\' and \'email\' are required');
}
$vin = \strtoupper($vin);
$vinInstance = $this->em->getRepository(Vin::class)->findOneBy(['vin' => $vin]);
if (!$vinInstance instanceof Vin) {
throw new BadRequestHttpException(\sprintf('Vin (%s) doesn\'t exist, you need to create it firstly', $vin));
}
try {
$order = $this->orderService->makeOrder($vinInstance, $email, Order::SOURCE_WEB, $code, false);
$this->orderService->addPayInfo($order);
$this->em->flush();
$this->bus->dispatch(new CheckPaymentMessage($order));
} catch (\InvalidArgumentException $e) {
throw new BadRequestHttpException($e->getMessage());
}
return new Response($this->serializer->serialize(['order' => $order], 'json', ['groups' => 'index']));
}
/**
* @OA\Response(
* response="200",
* description="Returns requested order",
* @Model(type=Order::class, groups={"index"})
* ),
* @OA\Response(
* response="400",
* description="Returns if order is not found",
* ),
* @OA\Parameter(
* name="orderId",
* in="path",
* required=true,
* @OA\Schema(type="string", format="uuid")
* ),
* @OA\Parameter(
* name="User-Id",
* in="header",
* required=true,
* @OA\Schema(type="string", format="uuid")
* ),
*/
#[Route('/api/order/{orderId}', name: 'app_get_order', methods: ['GET'], format: 'json')]
public function handleGetOrder(string $orderId): Response
{
if (!Uuid::isValid($orderId)) {
throw new BadRequestHttpException(\json_encode(\sprintf('Invalid orderId (%s) was given', $orderId)));
}
$order = $this->em->find(Order::class, $orderId);
if (!$order) {
throw new NotFoundHttpException(\sprintf('Order %s not found', $orderId));
}
$this->orderService->addPayInfo($order);
$reportPath = $this->reportService->makeReport($order);
return new Response($this->serializer->serialize(['order' => $order], 'json', ['groups' => 'index']));
}
/**
* @Operation\Security(
* name="admin"
* ),
* @OA\Response(
* response="200",
* description="Returns requested order history",
* @Model(type=Order::class, groups={"order-history"})
* ),
* @OA\Parameter(
* name="orderId",
* in="query",
* required=false,
* @OA\Schema(type="string")
* ),
* @OA\Parameter(
* name="vin",
* in="query",
* required=false,
* @OA\Schema(type="string")
* ),
* @OA\Parameter(
* name="email",
* in="query",
* required=false,
* @OA\Schema(type="string")
* ),
* @OA\Parameter(
* name="fromDate",
* in="query",
* required=false,
* @OA\Schema(type="date-time")
* ),
* @OA\Parameter(
* name="toDate",
* in="query",
* required=false,
* @OA\Schema(type="date-time")
* ),
*/
#[Route('/api/order-history', name: 'app_get_order_history', methods: ['GET'], format: 'json')]
#[ParamConverter('orderHistory')]
public function getOrderHistory(OrderHistoryParams $orderHistoryParams, OrderRepository $orderRepository): Response
{
$orders = $orderRepository->getOrderHistory($orderHistoryParams);
return new Response($this->serializer->serialize(['orders' => $orders], 'json', ['groups' => ['orderHistory']]), Response::HTTP_OK);
}
/**
* @Operation\Security(
* name="api-token"
* ),
* @OA\Response(
* response="201",
* description="Returns link to report",
* @Model(type=OrderFreeOutput::class, groups={"index"})
* ),
* @OA\Response(
* response="400",
* description="Wrong input data"
* ),
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* type="object",
* @OA\Property(property="vin", type="string", example="4GDDU03A8VD268007"),
* @OA\Property(property="email", type="string", example="test@test.ru"),
* ),
* )
*/
#[Route('/api/vin-check', name: 'app_make_vin_check', methods: ['POST'])]
public function handleMakeOrderFree(Request $request): Response
{
$this->tokenService->checkToken($request);
try {
$vinChekInput = $this->serializer->deserialize($request->getContent(), VinChekInput::class, 'json');
} catch (\JsonException $e) {
throw new BadRequestHttpException(\sprintf('Bad request: %s', $e->getMessage()));
}
if ($vinChekInput->getVin() === null) {
throw new BadRequestHttpException('Field: \'vin\' is required');
}
$vinInstance = $this->vinService->checkVin($vinChekInput->getVin());
$email = $vinChekInput->getEmail();
try {
$order = $this->orderService->makeOrder($vinInstance, $email, Order::SOURCE_INT);
$this->bus->dispatch(new CheckPaymentMessage($order));
} catch (\InvalidArgumentException $e) {
throw new BadRequestHttpException($e->getMessage());
}
$orderFreeOutput = new OrderFreeOutput('OK', $order->getReportLink());
return new Response($this->serializer->serialize(['order' => $orderFreeOutput], 'json', ['groups' => 'index']));
}
}