src/Diplix/KMGBundle/Controller/Service/Api2Controller.php line 189

Open in your IDE?
  1. <?php
  2. namespace Diplix\KMGBundle\Controller\Service;
  3. use Cocur\Slugify\Slugify;
  4. use Diplix\Commons\DataHandlingBundle\Entity\SysLogEntry;
  5. use Diplix\Commons\DataHandlingBundle\Repository\SysLogRepository;
  6. use Diplix\KMGBundle\Controller\Availability\AvailabilityController;
  7. use Diplix\KMGBundle\Entity\Accounting\Job;
  8. use Diplix\KMGBundle\Entity\Address;
  9. use Diplix\KMGBundle\Entity\Availability;
  10. use Diplix\KMGBundle\Entity\Dispatching\ChatMessage;
  11. use Diplix\KMGBundle\Entity\Dispatching\DispatchQueueItem;
  12. use Diplix\KMGBundle\Entity\File;
  13. use Diplix\KMGBundle\Entity\Order;
  14. use Diplix\KMGBundle\Entity\OrderStatus;
  15. use Diplix\KMGBundle\Entity\PaymentType;
  16. use Diplix\KMGBundle\Entity\PriceList;
  17. use Diplix\KMGBundle\Entity\Role;
  18. use Diplix\KMGBundle\Entity\User;
  19. use Diplix\KMGBundle\Exception\OrderValidationException;
  20. use Diplix\KMGBundle\Form\OrderForm;
  21. use Diplix\KMGBundle\Form\Util\FormErrorsSerializer;
  22. use Diplix\KMGBundle\Helper\ClientConfigProvider;
  23. use Diplix\KMGBundle\PdfGeneration\JobPdf;
  24. use Diplix\KMGBundle\PriceCalculator\AbstractPriceCalculator;
  25. use Diplix\KMGBundle\Repository\AvailabilityRepository;
  26. use Diplix\KMGBundle\Repository\BasicRepository;
  27. use Diplix\KMGBundle\Repository\FileRepository;
  28. use Diplix\KMGBundle\Service\MobileNotifier;
  29. use Diplix\KMGBundle\Service\Notifier;
  30. use Diplix\KMGBundle\Service\OrderHandler;
  31. use Diplix\KMGBundle\Service\TaMiConnector;
  32. use Doctrine\ORM\EntityManagerInterface;
  33. use League\Flysystem\FilesystemOperator;
  34. use Symfony\Component\Form\FormError;
  35. use Symfony\Component\HttpFoundation\JsonResponse;
  36. use Symfony\Component\HttpFoundation\Request;
  37. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  38. use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
  39. use Symfony\Component\PropertyAccess\PropertyAccess;
  40. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  41. use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
  42. class Api2Controller extends ServiceBaseController
  43. {
  44.     public const LOG_TYPE 'Api2';
  45.     protected function hasRole($role)
  46.     {
  47.         $R $this->user->getRoles(true);
  48.         /** @var Role $RR */
  49.         foreach ($R as $RR)
  50.         {
  51.             /** @noinspection TypeUnsafeComparisonInspection */
  52.             if ($RR->getRole() == $role) return true;
  53.         }
  54.         return false;
  55.     }
  56.     protected function parseAndAuth(Request $request)
  57.     {
  58.         $data $this->parseRequest($request);
  59.         $this->loadUser($data['login'],$data['password'],false);
  60.         // do not detach user -> deprecated and kills further ops which rely on objects with an association with that user (e.g. deviceTokens)
  61.         return $data;
  62.     }
  63.     protected function storeToken(array $req$source='')
  64.     {
  65.         SysLogRepository::logMessage(
  66.             $this->managerRegistry->getConnection(),
  67.             SysLogEntry::SYS_INFO,
  68.             sprintf('User#%d reported token "%s" for platform "%s" (%s)',$this->user->getId(), $req['fcm_token']??'-',$req['platform']??'-',$source)
  69.         );
  70.         if ( (isset($req['fcm_token']) && (strlen($req['fcm_token'])>1)) )
  71.         {
  72.             $token $req['fcm_token'];
  73.             $platform = isset($req['platform']) ? $req['platform'] : 'unknown platform';
  74.             $isNewToken $this->userRepo->addFcmTokenToUser($this->user->getId(), $token,$platform);
  75.             $logToken substr($token,0,4).'(...)'.substr($token,-4);
  76.             if ($isNewToken)
  77.                 SysLogRepository::logMessage(
  78.                     $this->managerRegistry->getConnection(),
  79.                     SysLogEntry::SYS_INFO,
  80.                     sprintf('User#%d stored a new FCM token "%s" for platform "%s"',$this->user->getId(),$logToken,$platform)
  81.                 );
  82.         }
  83.     }
  84.     public function storeFcmTokenAction(Request $request)
  85.     {
  86.         $req $this->parseAndAuth($request);
  87.         // auth successful at this point
  88.         $this->storeToken($req,"storeFcmTokenAction");
  89.         return new JsonResponse(['success' => true]);
  90.     }
  91.     public function __construct(
  92.         protected FileRepository $fileRepository,
  93.         protected OrderHandler $orderHandler,
  94.         protected Notifier $notifier,
  95.         protected MobileNotifier $mobileNotifier,
  96.         protected TaMiConnector $taMiConnector,
  97.         protected FilesystemOperator $uploadsFilesystem,
  98.         protected UserPasswordHasherInterface $hasher,
  99.         private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
  100.     )
  101.     {
  102.         parent::__construct($this->hasher,$this->managerRegistry);
  103.     }
  104.     public function indexAction(Request $request)
  105.     {
  106.         $req $this->parseAndAuth($request);
  107.         // auth successful at this point
  108.         $this->storeToken($req,"indexAction");
  109.         $res = [
  110.             'success' => true,
  111.             'user' => [
  112.                 'firstName' =>$this->user->getFirstName(),
  113.                 'lastName' =>$this->user->getLastName(),
  114.                 'email' =>$this->user->getEmail(),
  115.                 'id' =>$this->user->getId(),
  116.             ]
  117.         ];
  118.         $m $this->user->getMember();
  119.         if ($m !== null)
  120.         {
  121.             $res['member'] = [
  122.                 'name' => $m->getName(),
  123.                 'number' =>$m->getNumber(),
  124.                 'code' =>$m->getShortCode(),
  125.                 'id' =>$m->getId()
  126.             ];
  127.         }
  128.         $c $this->user->getCustomer();
  129.         if ($c !== null)
  130.         {
  131.             $res['customer'] = [
  132.                 'name' =>$c->getName(),
  133.                 'number' =>$c->getCustomerNo(),
  134.                 'id' =>$c->getId()
  135.             ];
  136.         }
  137.         return new JsonResponse($res);
  138.     }
  139.     public static function prepare4json(&$data,$humanReadable=true)
  140.     {
  141.         $data['customer'] =  $data['customer']['id'];
  142.         $data['beOwner'] =   $data['beOwner']['id'];
  143.         $data['assignedTo'] =   $data['assignedTo'] !== null $data['assignedTo']['id'] : 0;
  144.         $data['orderStatus'] = $data['orderStatus']['id'];
  145.         $data['orderTime'] = $data['orderTime']->format(self::DATE_FORMAT);
  146.         $data['paymentType'] = $humanReadable $data['paymentType']['name'] : $data['paymentType']['id'];;
  147.         $ft $data['flightTime'];
  148.         $data['flightTime'] = $ft != null $ft->format('H:i') : null;
  149.         for ($a=0$a$ac=count($data['addressList']); $a++)
  150.         {
  151.             $data['addressList'][$a]['beCreated'] = $data['addressList'][$a]['beCreated']->format(self::DATE_FORMAT);
  152.             $data['addressList'][$a]['beEdited'] = $data['addressList'][$a]['beEdited']  !== null $data['addressList'][$a]['beEdited']->format(self::DATE_FORMAT) : null;
  153.             unset($data['addressList'][$a]['beDeleted']);
  154.             unset($data['addressList'][$a]['creditCardNo']);
  155.             unset($data['addressList'][$a]['creditCardMonth']);
  156.             unset($data['addressList'][$a]['creditCardYear']);
  157.         }
  158.     }
  159.     public function singleOrderAction(Request $request)
  160.     {
  161.         $req $this->parseAndAuth($request);
  162.         $repo $this->managerRegistry->getRepository(Order::class);
  163.         //if ($this->user->getMember()===null) throw new \Exception('Fetching a single order is not enabled for your account.');
  164.         $data = [];
  165.         $item $repo->getSingleAsArray($req['id']);
  166.         if ($item!=null)
  167.         {
  168.             self::prepare4json($item);
  169.             $data[]= $item;
  170.         }
  171.         return new JsonResponse([   'success'   => true,
  172.             'data'      => $data
  173.         ]);
  174.     }
  175.     public function ordersAction(Request $request)
  176.     {
  177.         $req $this->parseAndAuth($request);
  178.         // get filters owned orders
  179.         $filterStatus array_key_exists('status',$req) ? $req['status'] : 0;
  180.         $from = (new \DateTime())->sub(new \DateInterval('P3M'));
  181.         $to = (new \DateTime())->add(new \DateInterval('P3M'));
  182.         $from array_key_exists('from',$req) ? new \DateTime($req['from']) : $from ;
  183.         $to array_key_exists('until',$req) ? new \DateTime($req['until']) : $to ;
  184.         $repo $this->managerRegistry->getRepository(Order::class);
  185.         if ($this->user->getMember()!==null)
  186.         {
  187.             $data $repo->findAllForOverview(
  188.                 null,
  189.                 0,
  190.                 $filterStatus,
  191.                 $from,
  192.                 $to,
  193.                 $this->user->getMember()->getId());
  194.         }
  195.         else
  196.         {
  197.             $filterUserList $this->userRepo->findUsersISubstitute($this->user);
  198.             $filterUserList[] = $this->user;
  199.             $filterCustomerId 0// 0 = no additional filtering - already done through userlist
  200.             // no superadmin or orderadmin filters at the moment
  201.             $data $repo->findAllForOverview(
  202.                 $filterUserList,
  203.                 $filterCustomerId,
  204.                 $filterStatus,
  205.                 $from,
  206.                 $to);
  207.         }
  208.         // pre-process joined table fields
  209.         $ic count($data);
  210.         for ($i=0;$i<$ic;$i++)
  211.         {
  212.             $this->prepare4json($data[$i]);
  213.         }
  214.         return new JsonResponse([   'success'   => true,
  215.             'from'      => $from,
  216.             'until'        => $to,
  217.             'data'      => $data
  218.         ]);
  219.     }
  220.     const CODE_MINE 1;
  221.     const CODE_NOT_MINE 2;
  222.     protected function mnLog($it,$msg,$isError=false,$details=[])
  223.     {
  224.         $itid = ($it instanceof DispatchQueueItem $it->getId() : ($it !== null ? (string)$it 'null'));
  225.         $this->managerRegistry
  226.             ->getRepository(SysLogEntry::class)
  227.             ->log(($isError SysLogEntry::SYS_ERROR SysLogEntry::SYS_INFO), MobileNotifier::LOG_TYPE$msg$details00$itid);
  228.     }
  229.     public function acceptOrDenyOrderAction(Request $request)
  230.     {
  231.         $repo $this->managerRegistry->getRepository(Order::class);
  232.         $dqi $this->managerRegistry->getRepository(DispatchQueueItem::class);
  233.         try {
  234.             $code self::CODE_NOT_MINE;
  235.             $req $this->parseAndAuth($request);
  236.             if (!in_array($req['action'],['accept','decline']))
  237.             {
  238.                 throw new \Exception('Unbekannte action.');
  239.             }
  240.             $this->managerRegistry->getManager()->transactional(function(EntityManagerInterface $em) use ($repo,$dqi,$req,&$code) {
  241.                 $order null;
  242.                 if (isset($req['id']))
  243.                 {
  244.                     $order $repo->findOneBy(['id'=>$req['id']]);
  245.                 }
  246.                 else
  247.                 {
  248.                     $order $repo->findOneBy(['orderId'=>$req['orderId']]);
  249.                 }
  250.                 $refMsg $dqi->findOneBy(['id'=>$req['reference'] ?? 'null']);
  251.                 if (($order->getAssignedTo()===null) || ($order->getAssignedTo()->getId() != $this->user->getMember()->getId()) )
  252.                 {
  253.                     throw new \Exception(/*var_export($req,true).*/sprintf('Diese Fahrt(#%d:%s) ist Ihnen(%s) nicht zugeordnet.',$order->getId(),$order->getOrderId(),$this->user->getMember()->getId()),self::CODE_NOT_MINE);
  254.                 }
  255.                 if ($req['action']==='accept')
  256.                 {
  257.                     $order->setAssignmentConfirmed(true$this->user);
  258.                     $order->setAssignmentStatus(Order::AS_NONE);
  259.                     $code self::CODE_MINE;
  260.                     if ($refMsg!==null)
  261.                     {
  262.                         $refMsg->setResponse(DispatchQueueItem::R_CONFIRMED);
  263.                     }
  264.                     $this->mnLog($refMsg,'Fahrt angenommen');
  265.                 }
  266.                 else
  267.                 if ($req['action']==='decline')
  268.                 {
  269.                     if ($order->isAssignmentConfirmed())
  270.                     {
  271.                         throw new \Exception('Fahrt wurde bereits bestätigt. Bitte rufen Sie an um Ă„nderungen vorzunehmen.',self::CODE_MINE);
  272.                     }
  273.                     if ($order->getOrderStatus()->getId()==OrderStatus::STATUS_VERMITTELT)
  274.                     {
  275.                         $osOffen $em->find(OrderStatus::class,OrderStatus::STATUS_OPEN);
  276.                         $order->setOrderStatus($osOffen);
  277.                     }
  278.                     $order->setAssignedTo(null);
  279.                     if ($order->getXchgStatus() !== Order::XCHG_RECEIVED_FROM_OTHER// falls Fahrt von Fremdsystem darf der Status nicht geändert werden
  280.                     {
  281.                         $order->setXchgStatus(Order::XCHG_NONE);
  282.                     }
  283.                     $order->setXchgTo(null);
  284.                     $order->setAssignmentStatus(Order::AS_LAST_ASSIGNMENT_DENIED);
  285.                     if ($refMsg!==null)
  286.                     {
  287.                         $refMsg->setResponse(DispatchQueueItem::R_REFUSED);
  288.                     }
  289.                     $this->mnLog($refMsg,'Fahrt abgelehnt');
  290.                 }
  291.             });
  292.             // TODO: notifications/orderhandler??
  293.             $order null;
  294.             if (isset($req['id']))
  295.             {
  296.                 $order $repo->findOneBy(['id'=>$req['id']]);
  297.             }
  298.             else
  299.             {
  300.                 $order $repo->findOneBy(['orderId'=>$req['orderId']]);
  301.             }
  302.             $this->notifier->triggerOrderUpdateForMember($order); // having this line in finally() crashes since entity manager is already closed when an error occurs above
  303.             return new JsonResponse([   'success'   => true'mine'=>($code == self::CODE_MINE) ]);
  304.         }
  305.         catch (\Throwable $ex)
  306.         {
  307.             SysLogRepository::logMessage($this->managerRegistry->getConnection(),SysLogEntry::SYS_ERROR'acceptOrDenyOrderAction():'.$ex->getMessage());
  308.             return new JsonResponse([   'success'   => false'mine'=>($ex->getCode()==self::CODE_MINE), 'message'=>$ex->getMessage()??'' ]);
  309.         }
  310.     }
  311.     public function confirmMessageReceivedAction(Request $request)
  312.     {
  313.         try {
  314.             $req $this->parseAndAuth($request);
  315.             $mn $this->mobileNotifier;
  316.             $ok $mn->confirmReceived($req['guid'],true);
  317.             return new JsonResponse([ 'success'   => $ok ]);
  318.         }
  319.         catch (\Exception $ex)
  320.         {
  321.             SysLogRepository::logMessage($this->managerRegistry->getConnection(),SysLogEntry::SYS_ERROR'confirmMessageReceivedAction():'.$ex->getMessage());
  322.             return new JsonResponse([ 'success'   => false'message'=>$ex->getMessage() ]);
  323.         }
  324.     }
  325.     /**
  326.      * @param $id
  327.      * @return Order
  328.      */
  329.     protected function fetchOrderAndCheckAssignment($id)
  330.     {
  331.         return $this->fetchOrderAndCheckAssignmentByQuery(array('id' => $id));
  332.     }
  333.     /**
  334.      * @param $id
  335.      * @return Order
  336.      */
  337.     protected function fetchOrderAndCheckAssignmentByQuery(array $predicates)
  338.     {
  339.         $repo $this->managerRegistry->getRepository(Order::class);
  340.         /** @var Order $row */
  341.         $row $repo->findOneBy($predicates);
  342.         if ($row === null)
  343.         {
  344.             throw new NotFoundHttpException('Invalid id: '.var_export($predicates,true));
  345.         }
  346.         if ( ($row->getAssignedTo() === null) ||($row->getAssignedTo()->getId()!= $this->user->getMember()->getId()) )
  347.         {
  348.             throw $this->createAccessDeniedException('Fahrt ist Ihnen nicht zugeordnet.');
  349.         }
  350.         return $row;
  351.     }
  352.     public function jobPdfAction(Request $request$id)
  353.     {
  354.         $this->parseAndAuth($request);
  355.         $row $this->fetchOrderAndCheckAssignment($id);
  356.         $pdfFile $this->orderHandler->getJobPdf($row,$this->user,'App',true);
  357.         return $this->getDownloadResponse($pdfFile,basename($pdfFile));
  358.     }
  359.     public function updateJobByOrderIdAction(Request $request)
  360.     {
  361.         // todo merge with updateJobInfoAction()
  362.         $jr $this->managerRegistry->getRepository(Job::class);
  363.         $fr $this->fileRepository;
  364.         $req $this->parseAndAuth($request);
  365.         $row $this->fetchOrderAndCheckAssignmentByQuery(['orderId'=>$req['orderId']]);
  366.         $job $jr->findOrCreateForOrder($row);
  367.         $pp PropertyAccess::createPropertyAccessor();
  368.         // transform
  369.         foreach (['flightOnPositionTime',
  370.                      'departureAtOriginTime',
  371.                      'arrivalAtDestinationTime',] as $k)
  372.         {
  373.             if (isset($req[$k]) && $req[$k]!=null$req[$k] = new \DateTime($req[$k]);
  374.         }
  375.         foreach (["memberExtraKm"] as $k)
  376.         {
  377.             if (isset($req[$k])&& $req[$k]!=null)  $req[$k] = (int)$req[$k];
  378.         }
  379.         foreach ([  'flightOnPositionTime',
  380.                      'departureAtOriginTime',
  381.                      'arrivalAtDestinationTime',
  382.                      'passengerNotMet',
  383.                      'taxameter',
  384.                      'taxameterVat',
  385.                      'extraCostName',
  386.                      'extraCostPrice',
  387.                      'memberExtraKm',
  388.                      'confirmedByCustomerThrough',
  389.                      'approvedByDriver',
  390.                      'werksRundfahrt',
  391.                     'extraWaitingTimeRide',
  392.                     'extraWaitingTime',
  393.                     'instantRideAdditionalWaitingTime',
  394.                     // not allowed to set: instantRide
  395.                     // not allowed to set: hasMemberExtraKm
  396.                  ] as $k)
  397.         {
  398.             if (array_key_exists($k,$req))
  399.             {
  400.                 $pp->setValue($job,$k,$req[$k]);
  401.             }
  402.         }
  403.         if ($job->getConfirmedByCustomerThrough()>0)
  404.         {
  405.             $job->setApprovedByPassenger(true);
  406.         }
  407.         if ((array_key_exists('customerSignature',$req)) && ($req['customerSignature']!=null))
  408.         {
  409.             $stream '';
  410.             foreach ($req['customerSignature'] as $char)
  411.             {
  412.                 $stream.= chr($char);
  413.             }
  414.             $F File::fromPsr7StreamOrString($streamsprintf('signature_%s_%d.png',$row->getOrderId(),(new \DateTime())->getTimestamp()), $this->uploadsFilesystem,'signatures');
  415.             $fr->persistFlush($F);
  416.             $job->setCustomerSignature($F);
  417.         }
  418.         if ($job->isApprovedByDriver())
  419.         {
  420.             $jr->setApprovedByDriver($job);
  421.             $this->orderHandler->triggerJobCalculation($job);
  422.         }
  423.         $job->setLastChangeByMember(new \DateTime());
  424.         $jr->flush();
  425.         return new JsonResponse(['success' => true]);
  426.     }
  427.     public function updateJobInfoAction(Request $request$id)
  428.     {
  429.         $jr $this->managerRegistry->getRepository(Job::class);
  430.         $fr $this->fileRepository;
  431.         $req $this->parseAndAuth($request);
  432.         $row $this->fetchOrderAndCheckAssignment($id);
  433.         $job $jr->findOrCreateForOrder($row);
  434.         $pp PropertyAccess::createPropertyAccessor();
  435.         // transform
  436.         foreach (['flightOnPositionTime',
  437.                      'departureAtOriginTime',
  438.                      'arrivalAtDestinationTime',] as $k)
  439.         {
  440.             if ($req[$k]!=null$req[$k] = new \DateTime($req[$k]);
  441.         }
  442.         foreach ([  'flightOnPositionTime',
  443.                     'departureAtOriginTime',
  444.                     'arrivalAtDestinationTime',
  445.                     'passengerNotMet',
  446.                     'taxameter',
  447.                     'taxameterVat',
  448.                     'extraCostName',
  449.                     'extraCostPrice',
  450.                     'memberExtraKm',
  451.                     'confirmedByCustomerThrough',
  452.                     'approvedByDriver'
  453.                      ] as $k)
  454.         {
  455.             if ($k==="memberExtraKm"$req[$k] = (int)$req[$k];
  456.             $pp->setValue($job,$k,$req[$k]);
  457.         }
  458.         if ($job->getConfirmedByCustomerThrough()>0)
  459.         {
  460.             $job->setApprovedByPassenger(true);
  461.         }
  462.         if ((array_key_exists('customerSignature',$req)) && ($req['customerSignature']!=null))
  463.         {
  464.             $stream '';
  465.             foreach ($req['customerSignature'] as $char)
  466.             {
  467.                 $stream.= chr($char);
  468.             }
  469.             $F File::fromPsr7StreamOrString($streamsprintf('signature_%s_%d.png',$row->getOrderId(),(new \DateTime())->getTimestamp()), $this->uploadsFilesystem,'signatures');
  470.             $fr->persistFlush($F);
  471.             $job->setCustomerSignature($F);
  472.         }
  473.         if ($job->isApprovedByDriver())
  474.         {
  475.             $this->orderHandler->triggerJobCalculation($job);
  476.         }
  477.         $job->setLastChangeByMember(new \DateTime());
  478.         $jr->flush();
  479.         return new JsonResponse(['success' => true]);
  480.     }
  481.     public function chatMessageAction(Request $request)
  482.     {
  483.         $req $this->parseAndAuth($request);
  484.         $notifier $this->notifier;
  485.         $repo $this->managerRegistry->getRepository(ChatMessage::class);
  486.         $msg ChatMessage::textFrom($this->user,$req['message']);
  487.         $repo->persistFlush($msg);
  488.         $notifier->notifyWebSocketAboutChatMessage($msg);
  489.         return new JsonResponse(['success' => true'ref'=>$msg->getId() ]);
  490.     }
  491.     /**
  492.      * @return PriceList
  493.      * @throws \Exception
  494.      * todo : remove redudancy
  495.      */
  496.     protected function getDefaultPriceList()
  497.     {
  498.         $pl $this->user->getCustomer()->getDefaultPriceList();
  499.         if ($pl === null)
  500.         {
  501.             $pl $this->user->getCustomer()->getPriceLists()->get(0);
  502.             if ($pl === null) throw new \Exception("No priceList set");
  503.         }
  504.         return $pl;
  505.     }
  506.     protected function getDefaultPaymentType(User $user)
  507.     {
  508.         $pt $user->getCustomer()->getDefaultPaymentType();
  509.         if ($pt === null)
  510.         {
  511.             $pt $user->getCustomer()->getPaymentTypes()->get(0);
  512.             if ($pt === null) throw new \Exception("No paymentType set");
  513.         }
  514.         return $pt;
  515.     }
  516.     public function placeOrderAction(Request $request)
  517.     {
  518.         // TODO refactor order process (mail,tami,...) into service
  519.         $req $this->parseAndAuth($request);
  520.         if ($request->getMethod()!==Request::METHOD_POST)
  521.         {
  522.             return new JsonResponse(['success' => false'errorList' => ["Use POST !"]]);
  523.         }
  524.         $orderRepo $this->managerRegistry->getRepository(Order::class);
  525.         $tami $this->taMiConnector;
  526.         $oh $this->orderHandler;
  527.         // check request
  528.         $user $this->managerRegistry->getRepository(User::class)->findOneBy(['id'=>$this->user->getId()]);
  529.         $row =   $oh->getNewOrder($user,null,OrderStatus::STATUS_DRAFT);
  530.         $form $this->createForm(OrderForm::class,$row, [
  531.             OrderForm::OPT_CUSTOMER => $this->user->getCustomer(),
  532.             OrderForm::em => $this->managerRegistry->getManager(),
  533.             OrderForm::fromService => false,
  534.             'allow_extra_fields'=>true// omit extra fields warnings
  535.             'csrf_protection' => false
  536.         ]);
  537.         // auto-inject defaults
  538.         $req["ordererName"] = $this->user->getLastName();
  539.         $req["ordererMail"] = $this->user->getEmail();
  540.         $req["ordererPhone"] = $this->user->getPhone();
  541.         $req["paymentType"] = $this->getDefaultPaymentType($this->user)->getId();
  542.         $req["priceList"] = $this->getDefaultPriceList()->getId();
  543.         $req['lastEstimatedDistance'] = 0;
  544.         $req['lastEstimatedPrice'] = 0;
  545.         // tranform origin/destination to our internal address structure
  546.         if (isset($req['origin']) && isset($req['destination']))
  547.         {
  548.             // try to parse address
  549.             /** @var Address $a1 */
  550.             $a1 $row->getAddressList()->get(0);
  551.             /** @var Address $a2 */
  552.             $a2 $row->getAddressList()->get(1);
  553.             if (is_array($req['origin']))
  554.                 $a1->fromJson($req['origin']);
  555.             else
  556.                 CustomerEndpointController::tryParseAddress($a1,$req['origin']);
  557.             if (is_array($req['destination']))
  558.                 $a2->fromJson($req['destination']);
  559.             else
  560.                 CustomerEndpointController::tryParseAddress($a2,$req['destination']);
  561.             $a1->setSortOrder(0);
  562.             $a2->setSortOrder(1);
  563.             $req['addressList'] = [];
  564.             $req['addressList'][0] = $a1->jsonSerialize();
  565.             $req['addressList'][1] = $a2->jsonSerialize();
  566.             $req array_merge($req,$a1->jsonSerialize('addressList_0_'));
  567.             $req array_merge($req,$a2->jsonSerialize('addressList_1_'));
  568.         }
  569.         else
  570.         {
  571.             // the address is supposed to be transmitted in the correct structure like it has been submitted via form
  572.             // done via prepare4json which is also used in OrderHandler::sendToPlatform
  573.         }
  574.         $xchg = isset($req['xchg'])&&($req['xchg']);
  575.         $fes = new FormErrorsSerializer();
  576.         $form->submit($req);
  577.         if ($form->isValid())
  578.         {
  579.             if ($xchg)
  580.             {
  581.                 $row->setXchgStatus(Order::XCHG_RECEIVED_FROM_OTHER);
  582.                 $row->setXchgOrderId(  $req['original_order_id'] );
  583.                 $row->setOriginOrderId$req['original_order_id'] );
  584.             }
  585.             if ( (isset($req['commit']))&&($req['commit']== true) )
  586.             {
  587.                 try {
  588.                     $oh-> storeOrUpdate($row);
  589.                     $oh->initiateOrder($row);
  590.                 } catch (OrderValidationException $ex) {
  591.                     $form->addError(new FormError($ex->getMessage()));
  592.                 }
  593.                 // success
  594.                 if ( ($form->isValid()) && ($form->getErrors()->count() < 1))
  595.                 {
  596.                     SysLogRepository::logMessage(
  597.                         $this->managerRegistry->getConnection(),
  598.                         SysLogEntry::SYS_INFO,
  599.                         sprintf('API: Order %s placed.',$row->getOrderId())
  600.                     );
  601.                     return new JsonResponse(['success' => true'data' => $row->getOrderId()]);
  602.                 }
  603.                 // failed
  604.                 $errors $fes->serializeFormErrors($formtruetrue);
  605.                 SysLogRepository::logMessage(
  606.                     $this->managerRegistry->getConnection(),
  607.                     SysLogEntry::SYS_INFO,
  608.                     sprintf('API: Order rejected: %s',var_export($errors,true))
  609.                 );
  610.                 return new JsonResponse(['success' => false'errorList' => $errors]);
  611.             }
  612.             // simulation active
  613.             return new JsonResponse(['success' => true'data' => 'not committed']);
  614.         }
  615.         // form is not valid
  616.         $errors $fes->serializeFormErrors($formtruetrue);
  617.         return new JsonResponse(['success' => false'errorList' => $errors]);
  618.     }
  619.     public function announceReadyAction(Request $request)
  620.     {
  621.         $req $this->parseAndAuth($request);
  622.         $tomorrow $req['tomorrow'] === 'true';
  623.         /** @var AvailabilityRepository $repo */
  624.         $repo $this->managerRegistry->getRepository(Availability::class);
  625.         $ret $repo->announceReady($this->user->getMember(),$tomorrow);
  626.         return new JsonResponse(['success' => $ret'data' =>[]]);
  627.     }
  628.     public function cancelOrderAction(Request $request)
  629.     {
  630.         $req $this->parseAndAuth($request);
  631.         $repo $this->managerRegistry->getRepository(Order::class);
  632.         try
  633.         {
  634.             if ($request->getMethod()!==Request::METHOD_POST)
  635.             {
  636.                 throw new MethodNotAllowedException([Request::METHOD_POST],"Use POST !");
  637.             }
  638.             if (!isset($req['orderId']))
  639.             {
  640.                 throw new \RuntimeException("No orderId");
  641.             }
  642.             $row $repo->findOneBy(["orderId"=>$req['orderId'], 'customer'=> $this->user->getCustomer()->getId()]);
  643.             if ($row === null)
  644.             {
  645.                 throw new \RuntimeException('Unbekannte oder nicht zugehörige OrderId');
  646.             }
  647.             // bereits storniert -> erfolgsfall melden
  648.             if ($row->getOrderStatus()->getId() === OrderStatus::STATUS_CANCELED)
  649.             {
  650.                 return new JsonResponse(['success' => true'data' => $row->getOrderId() . " storniert"]);
  651.             }
  652.             $oh $this->orderHandler;
  653.             $oh->ensureThatOrderCanBeCancelled($row);
  654.             if ( (isset($req['commit']))&&($req['commit']== true) )
  655.             {
  656.                 $oh->cancelOrder($row);
  657.                 SysLogRepository::logMessage(
  658.                     $this->managerRegistry->getConnection(),
  659.                     SysLogEntry::SYS_INFO,
  660.                     sprintf('API: Order %s cancelled.',$row->getOrderId())
  661.                 );
  662.                 return new JsonResponse(['success' => true'data' => $row->getOrderId() . " storniert"]);
  663.             }
  664.             else
  665.             {
  666.                 return new JsonResponse(['success' => true'data' => 'not committed']);
  667.             }
  668.         }
  669.         catch (\Throwable $ex)
  670.         {
  671.             return new JsonResponse(['success' => false'errorList' => [ $ex->getMessage() ]]);
  672.         }
  673.     }
  674. }