<?php
namespace App\Controller\Customer;
use App\Classes\Dictionaries\OrderState;
use App\Entity\Package;
use App\Entity\CodeLocationPackage;
use App\Entity\PackageCodeCustomer;
use App\Entity\PackageCodeSenderDelivery;
use App\Entity\PackageCodeSenderPostman;
use App\Entity\EventPackageDelivered;
use App\Entity\EventPackageStateChange;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use App\Entity\PackageCode;
use App\Form\Customer\TrackAndTraceSearchType;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Description of TrackAndTraceController
*
* @author martinjo
*/
class TrackAndTraceController extends AbstractController
{
/*
* @var Pokud někdo do get parametru vloží nevalidní kód, pak true
*/
public bool $warning = false;
/**
* Slouží k získání kódu balíku, pokud uživatel použije formulář.
* @param Request $request
* @param TranslatorInterface $translator
* @return Response
* @throws Exception
*/
public function trackAndTracePageGet(Request $request, EntityManagerInterface $em, TranslatorInterface $translator): Response
{
$form = $this->createForm(TrackAndTraceSearchType::class, [], []);
$form->handleRequest($request);
$packageCodeString = $request->query->get("code");
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$packageCodeString = $data['packageCode'];
return $this->redirectToRoute('customer_track_and_trace_get_parameter', ['code' => $packageCodeString]);
}
if (strlen($packageCodeString)>64) {
$this->warning = true;
}
if ($packageCodeString === null) {
$packageCodeString = "";
$this->warning = true;
}
return $this->trackAndTracePage($packageCodeString, $em, $translator);
}
/**
* Stranka zobrazuje zakaznikovy stav jeho balilu
* @param string $packageCodeString
* @param EntityManagerInterface $em
* @param TranslatorInterface $translator
*
* @return Response
* @throws Exception
*/
public function trackAndTracePage(string $packageCodeString, EntityManagerInterface $em, TranslatorInterface $translator): Response
{
$form = $this->createForm(TrackAndTraceSearchType::class, [], []);
$package = null;
$eventsViewMap = null;
if (!$this->warning) {
$packageCodeRepo = $em->getRepository(PackageCode::class);
$packageCode = $packageCodeRepo->findPackageCodeByString(mb_strtoupper($packageCodeString));
if ($packageCode instanceof PackageCodeCustomer || $packageCode instanceof PackageCodeSenderPostman) {
$codeLocation = $packageCode->getCodeLocation();
if (get_class($codeLocation) == CodeLocationPackage::class) {
$package = $codeLocation->getPackage();
}
$eventsViewMap = $this->getTackAndTraceEvents($package, $translator);
}
}
return $this->render(
'Customer/Postman/track_and_trace.html.twig',
[
'packageCode' => $packageCodeString,
'package' => $package,
'missingCode' => $this->warning,
'events' => $eventsViewMap,
'form' => $form->createView()
]
);
}
/**
* Funkce vybere udalosti z baliku a objednavky
* vrati pole hodnot [timestamp, description] pro view
* @param Package $package
* @param TranslatorInterface $translator
*
* @return array
* @throws Exception
*/
private function getTackAndTraceEvents(Package $package, TranslatorInterface $translator): array
{
$filteredEvents = [];
//vybereme udalosti objednavky
try {
$orderEvents = $package->getOrder()->getOrderEvents();
} catch (\Throwable $e) {
$orderEvents = [];
}
$wantedOrderEvents = [
"App\Entity\EventOrderCreated",
"App\Entity\EventOrderPaid",
];
foreach ($orderEvents as $event) {
if (in_array(get_class($event), $wantedOrderEvents, true)) {
$filteredEvents[] = $event;
}
}
$packageEvents = $package->getPackageEvents();
$wantedPackageEvents = [
"App\Entity\EventPackageReceived",
"App\Entity\EventPackageDelivered",
];
//vybereme udalosti baliku
foreach ($packageEvents as $event) {
$packageEventClass = get_class($event);
if ($packageEventClass === EventPackageDelivered::class) {
/** @var EventPackageDelivered $event */
$event->setCreated($event->getTimeDelivered());
$filteredEvents[] = $event;
} elseif (($packageEventClass === EventPackageStateChange::class)) {
/** @var EventPackageStateChange $event */ /* Kvuli phpstanu rozdeluji podminku*/
if ($event->getNewState() === OrderState::STATE_DONE) {
$filteredEvents[] = $event;
}
} elseif (in_array($packageEventClass, $wantedPackageEvents, true)) {
$filteredEvents[] = $event;
}
}
//seradime udalosti podle data vytvoreni
usort($filteredEvents, function ($a, $b) {
$diff = $a->getCreated()->getTimestamp() - $b->getCreated()->getTimestamp();
if ($diff === 0) {
//fix aby se neradilo odeslani z depa pred prijeti (muze nastat ze udalosti maji stejny cas)
return $a->getId() - $b->getId();
}
return $diff;
});
// vratime pole pro hodnot zobrazeni
return $this->mapEventsForView($filteredEvents, $translator);
}
/**
* Funkce prevede pole events na pole poli pro view
* delame to proto ze v events descriprion nejsou hodnoty vhodne pro zobrazeni klientovy
* @param array $events
* @param TranslatorInterface $translator
*
* @return array
*/
private function mapEventsForView(
array $events,
TranslatorInterface $translator
): array {
$stateDescriptionMap = [
"App\Entity\EventOrderCreated" => $translator->trans(
"Objednávka byla vytvořena.",
[],
'customer'
),
"App\Entity\EventOrderPaid" => $translator->trans(
"Přijata platba.",
[],
'customer'
),
"App\Entity\EventPackageReceived" => $translator->trans(
"Balík byl přijat na depo.",
[],
'customer'
),
"App\Entity\EventPackageDelivered" => $translator->trans(
"Balík byl doručen.",
[],
'customer'
),
"App\Entity\EventPackageStateChange" => $translator->trans(
"Balík byl odeslán z depa.",
[],
'customer'
),
];
$map = [];
foreach ($events as $event) {
$map[] = [
"created" => $event->getCreated(),
"description" => $stateDescriptionMap[get_class($event)],
];
}
return $map;
}
}