<?php
declare(strict_types=1);
namespace App\Admin\Controller;
use App\Entity\AdmUser;
use App\Entity\Client;
use App\Entity\Equipment;
use App\Entity\Motorcycle;
use App\Entity\Reserve;
use App\Entity\Type\EquipmentType;
use App\Entity\Type\RentStatusType;
use App\Entity\Type\WeekDay;
use App\EntityService\ReserveEntityService;
use App\Repository\EquipmentRepository;
use App\Repository\MotorcycleRepository;
use App\Repository\ReserveRepository;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use MessageFormatter;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ReserveAdminController extends CRUDController
{
private const DEFAULT_CALENDAR_DAYS_LIMIT = 30;
private EntityManagerInterface $entityManager;
private ReserveRepository $reserveRepository;
private MotorcycleRepository $motorcycleRepository;
private EquipmentRepository $equipmentRepository;
private ReserveEntityService $reserveEntityService;
public function __construct(
EntityManagerInterface $entityManager,
ReserveRepository $reserveRepository,
MotorcycleRepository $motorcycleRepository,
EquipmentRepository $equipmentRepository,
ReserveEntityService $reserveEntityService
)
{
$this->entityManager = $entityManager;
$this->reserveRepository = $reserveRepository;
$this->motorcycleRepository = $motorcycleRepository;
$this->equipmentRepository = $equipmentRepository;
$this->reserveEntityService = $reserveEntityService;
}
public function getReserveCalendarAction(Request $request): JsonResponse
{
$days = $request->get('days');
if (!$days) {
$days = self::DEFAULT_CALENDAR_DAYS_LIMIT;
}
$mot = $this->motorcycleRepository->find(7);
$searchStartDate = new \DateTime();
$searchEndDate = new \DateTime();
$searchEndDate->setTime(23, 59, 59);
$searchStartDate->modify('- 1 day');
$searchEndDate->modify('- 1 day');
$graph = [];
for ($i = 0; $i <= $days; $i++) {
$searchStartDate->setTime(0,0);
$searchStartDate->modify('+ 1 day');
$searchEndDate->modify('+ 1 day');
$result = $this->reserveRepository->reserveList($searchStartDate, $searchEndDate);
$reserves = [];
$result->map(static function (Reserve $reserve) use (&$reserves, $searchStartDate, $searchEndDate) {
$motName = $reserve->getMotorcycle()->getFullName();
$startTime = $reserve->getStartDate();
$endDate = $reserve->getEndDate();
$endDay = (clone $searchEndDate)->setTime(23,59);
if ((int)$startTime->format('d') !== (int) $searchStartDate->format('d')) {
$startTime = clone $searchStartDate;
}
if ($endDate > $endDay) {
$endDate = $endDay;
}
$list = [];
while ($startTime <= $endDate) {
$list[] = $startTime->format('H:i');
$startTime->modify('+ 1 hour');
}
if ((int)$reserve->getEndDate()->format('d') !== (int) $searchEndDate->format('d') ||
(int)$reserve->getEndDate()->format('m') > (int) $searchEndDate->format('m')
) {
$list[] = '24:00';
}
array_pop($list);
$reserves[$motName]['reserves'][] = $list;
$reserves[$motName]['color'] = $reserve->getMotorcycle()->getColor();
});
$schedules = $this->prepareReserves($reserves);
$graph[] = [
'date' => sprintf(
'(%s) %s',
WeekDay::WEEKDAY_RU[(int)$searchStartDate->format('w')],
$searchStartDate->format('d.m.Y')),
'schedules' => $schedules
];
}
return new JsonResponse($graph);
}
private function prepareReserves($reserves): array
{
$schedules = [];
foreach ($reserves as $key => $value) {
$schedules[] = [
'name'=> $key,
'color' => $value['color'],
'reserves' => $value['reserves']
];
}
return $schedules;
}
public function createAcceptanceCertificateAction(Request $request): Response
{
/** @var AdmUser $admin */
$admin = $this->getUser();
/** @var Reserve $reserve */
$reserve = $this->reserveRepository->find($request->get('id'));
/** @var Client $client */
$client = $reserve->getClient();
/** @var Motorcycle $motorcycle */
$motorcycle = $reserve->getMotorcycle();
$this->reserveEntityService->toActiveStatus($reserve);
$this->entityManager->flush();
$equipment = [];
/** @var Equipment $eq */
foreach ($reserve->getEquipment() as $eq) {
$number = ' (№ ' . $eq->getSerialNumber() . ')';
$equipment[] = EquipmentType::RU_VALUES[$eq->getType()] . ' ' . $eq->getBrand() . ' ' . $eq->getModel() . ' ' . $eq->getSize() . $number ;
}
return $this->renderWithExtraParams('admin/Document/acceptance_certificate.html.twig', [
'admin' => [
'jobTitle' => $admin->getBiography(),
'name' => $admin->getLastname() . ' ' . $admin->getFirstname()
],
'currentDate' => (new DateTime())->format('d.m.Y'),
'client' => [
'number' => $client->getUserNumber(),
'fio' => $client->getFio(),
'signDate' => $client->getDateSigningContract()->format('d.m.Y')
],
'motorcycle' => [
'name' => $motorcycle->getFullName(),
'vin' => $motorcycle->getVinNumber(),
'year' => $motorcycle->getIssueYear()->format('Y'),
'registrationNumber' => $motorcycle->getRegistrationNumber(),
'paymentAmount' => $motorcycle->getPaymentAmount(),
'mileage' => $motorcycle->getMileage(),
],
'reserve' => [
'amount' => $reserve->getAmount(),
'amountWords' => $this->num2str($reserve->getAmount()),
'startDate' => $reserve->getStartDate()->format('d.m.Y H:i'),
'endDate' => $reserve->getEndDate()->format('d.m.Y H:i'),
'returnDate' => $reserve->getEndDate()->format('d.m.Y'),
'returnTimeIntervalStart' => $reserve->getEndDate()->format('H:i'),
'returnTimeIntervalEnd' => (clone $reserve->getEndDate())->modify('+ 15 minutes')->format('H:i'),
],
'equipment' => $equipment
]);
}
public function openReserveAction(Request $request): Response
{
$reserve = $this->reserveRepository->find($request->get('id'));
///На потом, достать весь экип у которого нет активной аренды (или типы аренды котрые раньше)
/// т текущий экип если уже брали
return $this->renderWithExtraParams('admin/Reserve/open_reserve_page.html.twig', [
'object' => $reserve,
'equipment' => $this->getEquipmentPrepare(),
'jsonEquipment' => json_encode($this->getEquipmentPrepare())
]);
}
public function closeReserveAction(Request $request): Response
{
$reserve = $this->reserveRepository->find($request->get('id'));
return $this->renderWithExtraParams('admin/Reserve/close_reserve_page.html.twig', [
'object' => $reserve,
]);
}
public function finaleCloseReserveAction(Request $request): Response
{
/** @var Reserve $reserve */
$reserve = $this->reserveRepository->find($request->get('id'));
$reserve->setStatus(RentStatusType::ENDED);
$this->entityManager->flush();
return $this->redirectToRoute('admin_app_reserve_active_list');
}
public function addToReserveAction(Request $request): Response
{
try {
$reserveId = $request->get('reserve');
$equipmentList = $request->get('equipment');
$startReserveMileage = $request->get('startMileage');
$endReserveMileage = $request->get('endMileage');
/** @var Reserve $reserve */
$reserve = $this->reserveRepository->find((int) $reserveId);
if ($startReserveMileage) {
$reserve->setStartRentMileage((int)$startReserveMileage);
$reserve->getMotorcycle()->setMileage((int)$startReserveMileage);
}
if ($endReserveMileage) {
$reserve->setEndRentMileage((int)$endReserveMileage);
$reserve->getMotorcycle()->setMileage((int)$endReserveMileage);
}
if (is_array($equipmentList)) {
foreach ($equipmentList as $item) {
/** @var Equipment $equipment */
$equipment = $this->equipmentRepository->find((int) $item);
$reserve->addEquipment($equipment);
}
}
$this->entityManager->flush();
return new JsonResponse();
}catch (\Throwable $e) {
return new JsonResponse($e->getMessage(), Response::HTTP_I_AM_A_TEAPOT);
}
}
private function getEquipmentPrepare(): array
{
$equipment = $this->equipmentRepository->findAll();
$res = [];
foreach ($equipment as $item) {
$image = $item->getImages()->first();
$res[EquipmentType::VALUES[$item->getType()]][] = [
'id' => $item->getId(),
'brand' => $item->getBrand(),
'model' => $item->getModel(),
'size' => $item->getSize(),
'image' => $image ? $image->getPath() : null
];
}
return $res;
}
private function num2str($num): string
{
$nul='ноль';
$ten=array(
array('','один','два','три','четыре','пять','шесть','семь', 'восемь','девять'),
array('','одна','две','три','четыре','пять','шесть','семь', 'восемь','девять'),
);
$a20=array('десять','одиннадцать','двенадцать','тринадцать','четырнадцать' ,'пятнадцать','шестнадцать','семнадцать','восемнадцать','девятнадцать');
$tens=array(2=>'двадцать','тридцать','сорок','пятьдесят','шестьдесят','семьдесят' ,'восемьдесят','девяносто');
$hundred=array('','сто','двести','триста','четыреста','пятьсот','шестьсот', 'семьсот','восемьсот','девятьсот');
$unit=array( // Units
array('копейка' ,'копейки' ,'копеек', 1),
array('рубль' ,'рубля' ,'рублей' ,0),
array('тысяча' ,'тысячи' ,'тысяч' ,1),
array('миллион' ,'миллиона','миллионов' ,0),
array('миллиард','милиарда','миллиардов',0),
);
//
list($rub,$kop) = explode('.',sprintf("%015.2f", floatval($num)));
$out = array();
if (intval($rub)>0) {
foreach(str_split($rub,3) as $uk=>$v) { // by 3 symbols
if (!intval($v)) continue;
$uk = sizeof($unit)-$uk-1; // unit key
$gender = $unit[$uk][3];
list($i1,$i2,$i3) = array_map('intval',str_split($v,1));
// mega-logic
$out[] = $hundred[$i1]; # 1xx-9xx
if ($i2>1) $out[]= $tens[$i2].' '.$ten[$gender][$i3]; # 20-99
else $out[]= $i2>0 ? $a20[$i3] : $ten[$gender][$i3]; # 10-19 | 1-9
// units without rub & kop
if ($uk>1) $out[]= $this->morph($v,$unit[$uk][0],$unit[$uk][1],$unit[$uk][2]);
} //foreach
}
else $out[] = $nul;
// $out[] = $this->morph(intval($rub), $unit[1][0],$unit[1][1],$unit[1][2]); // rub
// $out[] = $kop.' '.$this->morph($kop,$unit[0][0],$unit[0][1],$unit[0][2]); // kop
return trim(preg_replace('/ {2,}/', ' ', join(' ',$out)));
}
private function morph($n, $f1, $f2, $f5) {
$n = abs(intval($n)) % 100;
if ($n>10 && $n<20) return $f5;
$n = $n % 10;
if ($n>1 && $n<5) return $f2;
if ($n==1) return $f1;
return $f5;
}
}