<?php
namespace Diplix\KMGBundle\Controller;
use Diplix\KMGBundle\Entity\Customer;
use Diplix\KMGBundle\Entity\Order;
use Diplix\KMGBundle\Entity\OrderStatus;
use Diplix\KMGBundle\Entity\Role;
use Diplix\KMGBundle\Entity\User;
use Diplix\KMGBundle\Service\Notifier;
use Diplix\KMGBundle\Service\OrderHandler;
use http\Exception\RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\PropertyAccess\PropertyAccess;
class InstantOrderController extends BaseController
{
public function __construct(
protected Notifier $notifier,
protected OrderHandler $orderHandler,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
)
{
}
protected function getPending()
{
$repo = $this->managerRegistry->getRepository(Order::class);
$allRelevant = $repo->getPendingInstantOrder($this->getCurrentUser());
return array_filter($allRelevant, function(array $o){ return $o['orderStatus']['id']==OrderStatus::STATUS_INSTANT_ORDER_PENDING;});
}
public function indexAction(Request $request)
{
if (!$this->isGranted(Role::ALLOW_INSTANT_ORDER))
{
throw $this->createAccessDeniedException();
}
return $this->render('@DiplixKMG/Orders/instant-order.html.twig');
}
public function getPendingAction(Request $request)
{
$repo = $this->managerRegistry->getRepository(Order::class);
if (!$this->isGranted(Role::ALLOW_INSTANT_ORDER))
{
throw $this->createAccessDeniedException();
}
$existing = $repo->getPendingInstantOrder($this->getCurrentUser());
return $this->getJsonDataResponse($request, true,[
'count'=>count($existing),
'orders' => $existing,
'homeAddress' => $this->getCurrentUser()->getHomeAddress()
]
);
}
protected function prepareOrder(array $setup)
{
$pa = PropertyAccess::createPropertyAccessor();
$oh = $this->orderHandler;
$u = $this->managerRegistry->getManager()->find(User::class, $this->getCurrentUser()->getId());
assert($u!==null);
$customer = $this->managerRegistry->getManager()->getReference(Customer::class, $this->getCustomerContextFromSession()->getId());
assert($customer !==null);
if ($u->getHomeAddress()===null)
{
throw new RuntimeException('Bitte hinterlegen Sie eine Heimatadresse');
}
$row = $oh->getNewOrder($u,$customer,OrderStatus::STATUS_INSTANT_ORDER_PENDING,null,true);
$row->setOrderTime( new \DateTime() );
foreach ($setup as $k=>$e)
{
if ($pa->isWritable($row,$k))
$pa->setValue($row,$k,$e);
}
$row->clearAddressList();
$row->addAddress(clone $u->getHomeAddress());
$row->addAddress(clone $u->getHomeAddress());
// overwrite destination address
$d = 'destination_';
foreach ($setup as $k=>$e)
{
if (strpos($k, $d) !== 0) continue;
$pa->setValue($row->getAddressList()[1],str_replace($d,'',$k),$e);
}
$row->setInstantOrderInitiated(new \DateTime());
$row->setInstantOrderStatus(Order::INSTANT_ORDER_REQUEST_PENDING);
return $row;
}
public function createAction(Request $request)
{
$oh = $this->orderHandler;
$nn = $this->notifier;
try {
if (!$this->isGranted(Role::ALLOW_INSTANT_ORDER))
{
throw $this->createAccessDeniedException();
}
if ($request->getMethod()!==Request::METHOD_POST)
{
throw new MethodNotAllowedHttpException([Request::METHOD_POST],"Verwenden Sie http/POST");
}
$exist = $this->getPending();
if (count($exist)>0)
{
throw new \Exception('Es wartet bereits eine Sofortbestellung. Bitte haben Sie einen Moment Geduld.');
}
$setup = $request->query->get('setup',[]);
$row = $this->prepareOrder($setup);
$oh->storeOrUpdate($row);
$repo = $this->managerRegistry->getRepository(Order::class);
$newAO = $repo->getSingleAsArray($row->getId()); // todo: create serializr
$nn->notifyTelegramAboutInstantOrder($row);
$nn->notifyWebsocketAboutInstantOrder($row);
return $this->getJsonDataResponse($request, true, ['order' => $newAO]);
}
catch (\Throwable $ex)
{
return $this->getJsonDataResponse($request,false,$ex,$ex->getMessage());
}
}
public function getPendingForDispoAction(Request $request)
{
$repo = $this->managerRegistry->getRepository(Order::class);
if (!$this->isGranted(Role::DISPO))
{
throw $this->createAccessDeniedException();
}
$existing = $repo->getPendingInstantOrdersForDispo();
return $this->getJsonDataResponse($request, true, ['count'=>count($existing),'orders' => $existing]);
}
public function dispoReplyAction(Request $request)
{
$repo = $this->managerRegistry->getRepository(Order::class);
$nn = $this->notifier;
try {
if (!$this->isGranted(Role::DISPO))
{
throw $this->createAccessDeniedException();
}
$data = \GuzzleHttp\json_decode($request->getContent(),true);
$id = $data['id'];
$comment = $data['comment'];
$action = $data['action'];
$order = $repo->findOneBy(['id'=>$id, 'instantOrderStatus'=>Order::INSTANT_ORDER_REQUEST_PENDING]);
if ($order===null)
{
throw new \Exception(sprintf('Bestellung #%d ungültig oder bereits bearbeitet.',$id));
}
$order->setInstantOrderResponded(new \DateTime());
$order->setInstantOrderRespondedBy($this->getUser());
$order->setOrderStatus($this->managerRegistry->getManager()->getReference(OrderStatus::class, OrderStatus::STATUS_DRAFT));
$oh = $this->orderHandler;
if ($action==='accept')
{
$order->setInstantOrderComment($comment);
$order->setInstantOrderStatus(Order::INSTANT_ORDER_ACCEPTED);
$oh->storeOrUpdate($order);
$oh->initiateOrder($order);
$nn->notifyWebsocketAboutInstantOrder($order,Notifier::M_INSTANT_RIDE_RESPONSE);
return $this->getJsonDataResponse($request,true,[],sprintf('Bestellung %s ausgelöst.',$order->getOrderId()));
}
else
if ($action==='decline')
{
$order->setInstantOrderStatus(Order::INSTANT_ORDER_DECLINED);
$order->setInstantOrderComment($comment);
$oh->storeOrUpdate($order);
$nn->notifyWebsocketAboutInstantOrder($order,Notifier::M_INSTANT_RIDE_RESPONSE);
return $this->getJsonDataResponse($request,true,[],sprintf('Bestellung wurde abgelehnt.'));
}
else
{
throw new \Exception(sprintf('Unbekannte Aktion: %s',$action));
}
}
catch (\Throwable $ex)
{
return $this->getJsonDataResponse($request,false,$ex,$ex->getMessage());
}
}
}