src/Controller/MainController.php line 214
<?phpnamespace App\Controller;use App\Entity\Expense;use App\Entity\FinancialPart;use App\Entity\FixedPages;use App\Entity\Letter;use App\Entity\News;use App\Entity\Page;use App\Entity\PictureLead;use App\Entity\Santa;use App\Entity\Services;use App\Entity\User;use App\Entity\UserTemplate;use App\Enum\IncomeEnum;use App\Enum\PdfConverter;use App\Enum\SantaEnum;use App\Repository\MetaRepository;use App\Repository\PageRepository;use App\Services\SpacesUploader;use GuzzleHttp\ClientInterface;use Symfony\Bridge\Twig\Mime\TemplatedEmail;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;use Symfony\Component\HttpFoundation\JsonResponse;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\RequestStack;use Symfony\Component\HttpFoundation\Response;use Symfony\Component\Mime\Address;use Symfony\Component\Mime\Email;use Symfony\Component\Routing\Annotation\Route;use Symfony\Component\Mailer\MailerInterface;use App\Entity\Gallery;use Doctrine\ORM\EntityManagerInterface;use Liip\ImagineBundle\Imagine\Cache\CacheManager;use Symfony\Component\Validator\Constraints\Uuid;use Symfony\Contracts\HttpClient\HttpClientInterface;use Symfony\Contracts\Translation\TranslatorInterface;use Gedmo\Translatable\TranslatableListener;use PhpOffice\PhpSpreadsheet\IOFactory;class MainController extends AbstractController{private EntityManagerInterface $entityManager;private TranslatableListener $translatableListener;public function __construct(EntityManagerInterface $entityManager,TranslatableListener $translatableListener){$this->translatableListener = $translatableListener;$this->entityManager = $entityManager;}#[Route('/{_locale}/ipad', name: 'page_ipad', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function iphone(MetaRepository $metaRepository, PageRepository $pageRepository){$page = $pageRepository->find(11);$editable = false;$pantum = false;return $this->render('@web/page/template.html.twig', ['page' => $page,'editable' => $editable,'ipad' => true,]);}#[Route('/{_locale}/links', name: 'page_links', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function links(){return $this->render('@web/page/links.html.twig', []);}#[Route('/{_locale}/pantum', name: 'page_pantum', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function pantum(MetaRepository $metaRepository, PageRepository $pageRepository){$page = $pageRepository->find(11);$editable = false;$pantum = true;return $this->render('@web/page/template.html.twig', ['page' => $page,'editable' => $editable,'pantum' => $pantum]);}#[Route('/{_locale}/ipad/may', name: 'page_mayis9', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function page_mayis9(MetaRepository $metaRepository, PageRepository $pageRepository){$page = $pageRepository->find(4);$editable = false;return $this->render('@web/page/template.html.twig', ['page' => $page,'editable' => $editable]);}#[Route('/iphone', name: 'page_iphone', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function ipad(MetaRepository $metaRepository){return $this->render('@web/page/iphone.html.twig');}#[Route('/gallery', name: 'page_gallery')]public function index(MetaRepository $metaRepository){$gallery = $this->entityManager->getRepository(Gallery::class)->findBy(['isShow' => true], ['id' => 'DESC'], 20);return $this->render('@web/page/gallery.html.twig', ['gallery' => $gallery]);}#[Route('/{_locale}', name: 'page_index', requirements: ['_locale' => 'en|ru|hy|es|it|fr|el|ua|ka|de'], defaults: ['_locale' => 'hy'])]public function empty(MetaRepository $metaRepository){$banner = $this->entityManager->getRepository(FixedPages::class)->find(1);$services = $this->entityManager->getRepository(Services::class)->findAll();$news = $this->entityManager->getRepository(News::class)->findAll();return $this->render('@web/page/index.html.twig', ['banner' => $banner,'services' => $services,'news' => $news]);}#[Route('{_locale}/services', name: 'page_services')]public function services(MetaRepository $metaRepository){$services = $this->entityManager->getRepository(Services::class)->findAll();return $this->render('@web/page/services.html.twig', ['services' => $services]);}#[Route('{_locale}/service/view/{id}', name: 'page_service')]public function service(Services $services){return $this->render('@web/page/service.html.twig', ['service' => $services]);}#[Route('{_locale}/partner/managment', name: 'page_partner_nviraberir')]public function partnerNviraberir(){return $this->render('@web/page/partner-nviraberir.html.twig');}#[Route('{_locale}/wine', name: 'page_wine')]public function wine(){return $this->render('@web/page/wine.html.twig', ['editable' => false]);}#[Route('{_locale}/privacy-policy', name: 'page_policy')]public function policy(){$page = $this->entityManager->getRepository(FixedPages::class)->find(2);return $this->render('@web/page/fixed.html.twig', ['page' => $page]);}#[Route('{_locale}/terms-of-use', name: 'page_terms')]public function terms(){$page = $this->entityManager->getRepository(FixedPages::class)->find(3);return $this->render('@web/page/fixed.html.twig', ['page' => $page]);}#[Route('{_locale}/about-us', name: 'page_about')]public function aboutUs(MetaRepository $metaRepository){$page = $this->entityManager->getRepository(FixedPages::class)->find(4);return $this->render('@web/page/about.html.twig', ['page' => $page]);}#[Route('{_locale}/support', name: 'page_contact_us')]public function contactUs(MetaRepository $metaRepository){return $this->render('@web/page/contact-us.html.twig');}#[Route('/pyunik/view', name: 'page_pyunik_view', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'ru'])]public function pagePyunik(PageRepository $pageRepository){$editable = false;return $this->render('@web/page/template-pyunik.html.twig', ['editable' => $editable]);}#[Route('{_locale}/view-image', name: 'page_view_image', requirements: ['_locale' => 'en|ru|hy'], defaults: ['_locale' => 'en'])]public function page_view_image(Request $request){$template = null;$image = null;$code = $request->get('code');if ($code) {$image = $this->entityManager->getRepository(Gallery::class)->findOneBy(['documentNumber' => $code]);if ($image) {$template = $this->entityManager->getRepository(Page::class)->find($image->getTemplateId());} else {return $this->redirectToRoute('page_index');}}// Redirect to Armenian locale if template ID is 62 and current locale is not hyif ($template->getId() == 62 && $request->getLocale() !== $image->getLocale()) {return $this->redirectToRoute('page_view_image', ['_locale' => $image->getLocale(),'code' => $code]);}// Render templates[$templateName, $params] = $this->resolveViewImageTemplateData($template, $image);return $this->render($templateName, $params);}private function resolveViewImageTemplateData(Page $template, Gallery $image): array{if ($template->getId() == 62) {$letter = $this->entityManager->getRepository(Letter::class)->find($image->getLetterId());return ['@web/page/template-christmas.html.twig', ['editable' => false,'viewImage' => true,'page' => $template,'letter' => $letter,'image' => $image]];} elseif ($template->getId() == 56) {return ['@web/page/template-dalma.html.twig', ['editable' => false,'dalma' => true,'page' => $template,'image' => $image]];} elseif ($template->getId() == 60) {return ['@web/page/template-sherep.html.twig', ['editable' => false,'dalma' => true,'page' => $template,'image' => $image]];} elseif (str_contains($template->getSlug(), 'violations')) {return ['@web/page/view-violations.html.twig', ['editable' => false,'dalma' => true,'page' => $template,'image' => $image]];}elseif (str_contains($template->getSlug(), 'engagement')) {return ['@web/page/view-engagement.html.twig', ['editable' => false,'dalma' => true,'page' => $template,'image' => $image]];} else {return ['@web/page/view-image.html.twig', ['editable' => false,'page' => $template,'image' => $image]];}}#[Route('{_locale}/request-picture-email', name: 'page_request_picture_email', methods: ['POST'])]public function requestPictureEmail(Request $request, MailerInterface $mailer, ParameterBagInterface $parameterBag): JsonResponse{$code = trim((string)$request->request->get('code'));$email = trim((string)$request->request->get('email'));if (!$code || !$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {return new JsonResponse(['success' => false, 'error' => 'invalid'], 400);}$image = $this->entityManager->getRepository(Gallery::class)->findOneBy(['documentNumber' => $code]);if (!$image) {return new JsonResponse(['success' => false, 'error' => 'not_found'], 404);}$template = $this->entityManager->getRepository(Page::class)->find($image->getTemplateId());if (!$template) {return new JsonResponse(['success' => false, 'error' => 'not_found'], 404);}[$templateName, $params] = $this->resolveViewImageTemplateData($template, $image);$html = $this->renderView($templateName, $params);// Capture the lead first so a PDF/mail hiccup never loses the email address.$lead = new PictureLead();$lead->setEmail($email);$lead->setCode($code);$lead->setLocale($request->getLocale());$this->entityManager->persist($lead);$this->entityManager->flush();try {$filename = 'lead_' . time() . '_' . bin2hex(random_bytes(4));$htmlDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/html/' . $filename . '.html';file_put_contents($htmlDir, $html);$pdfDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/pdf/' . $filename . '.pdf';PdfConverter::convertHtmlToPdf($htmlDir, $pdfDir);$mail = (new Email())->from(new Address('support@infinitemoment.life', 'The Infinite Moment'))->to($email)->subject('Your Infinite Moment Gazette')->html($this->renderView('email/picture_delivery.html.twig', ['code' => $code]))->attachFromPath($pdfDir, $filename . '.pdf', 'application/pdf');$mailer->send($mail);} catch (\Throwable $e) {return new JsonResponse(['success' => false, 'error' => 'mail_failed'], 200);}return new JsonResponse(['success' => true]);}#[Route('/image/test')]public function test(ParameterBagInterface $parameterBag, CacheManager $cacheManager){$imagePath = 'https://infinitemoment.nyc3.cdn.digitaloceanspaces.com/691df26f50fe7.jpg';$filteredPath = $cacheManager->resolve($imagePath, 'small_thumb');$page = $this->entityManager->getRepository(Page::class)->find(10);$origFile = "https://infinitemoment.nyc3.cdn.digitaloceanspaces.com/6912214177e31.jpg";$imgName = pathinfo($origFile, PATHINFO_BASENAME);$destImg = '/var/www/infinitemoment/public/uploads/img/' . $imgName;PdfConverter::resizeImage($origFile, $destImg);$html = $this->renderView('@web/page/template-tmp.html.twig', ['page' => $page,'preview' => false,'image' => 'https://infinitemoment.am/uploads/img/' . $imgName,'editable' => false]);$filename = (string)time();$htmlDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/html/' . $filename . '.html';file_put_contents($htmlDir, $html);$pdfDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/pdf/' . $filename . '.pdf';PdfConverter::convertHtmlToPdf($htmlDir, $pdfDir);}#[Route('/image/delete', name: 'image_delete', methods: ['GET'])]public function delete(Request $request){$ids = ['54302020250427', '21442120250427', '05461720250501', '14131420250509', '15221620250601', '45452020250811', '48002120250901', '35391420250904'];if (!empty($ids)) {foreach ($ids as $id) {$image = $this->entityManager->getRepository(Gallery::class)->findOneBy(['documentNumber' => $id]);if ($image) {// Delete file from filesystem$filePath = $this->getParameter('brochures_directory') . '/' . $image->getImage();if (file_exists($filePath)) {unlink($filePath);}// Remove entity$this->entityManager->remove($image);}}$this->entityManager->flush();$this->addFlash('success', 'Selected images deleted successfully.');} else {$this->addFlash('warning', 'No images selected.');}die;}#[Route('{_locale}/santa', name: 'page_santa', requirements: ['_locale' => 'en|ru|hy|es|it|fr|el|ua|ka|de'], defaults: ['_locale' => 'hy'])]public function pageSanta(Request $request,$_locale,SpacesUploader $spacesUploader,TranslatorInterface $translator,MetaRepository $metaRepository,MailerInterface $mailer) {if ($request->isMethod('POST')) {$action = $request->request->get('action');$santa = new Santa();$brochureFile = $request->files->get('image');$brochureFileName = $spacesUploader->upload($brochureFile);$gift = $request->get('gift') ?: time();$santa->setEmail($request->get('email'));$santa->setFromName($request->get('fromName'));$santa->setFromEmail($request->get('fromEmail'));$santa->setGift($gift);$santa->setPhone($request->get('phone'));$santa->setMessage($request->get('comment'));$santa->setImage($brochureFileName);$santa->setLocale($_locale);$santa->setStatus(SantaEnum::SANTA_PROGRESS);$santa->setName($request->get('name'));$this->entityManager->persist($santa);$this->entityManager->flush();if ($action === 'pay_now') {if ($this->getUser()) {return $this->redirect('/payment/confirm?santa_id=' . $santa->getId());}$message = empty($request->get('comment')) ? 1 : 2;return $this->redirect('https://anyrentalcars.com/armenia/infinite?' .'santa_id=' . $santa->getId() .'&locale=' . $santa->getLocale() .'&message=' . $message);}if ($action === 'request') {$santa->setStatus(SantaEnum::SANTA_REQUEST);$this->entityManager->flush();$this->addFlash('success', $translator->trans('Your request has been sent successfully!'));return $this->redirectToRoute('page_index');}}return $this->render('@web/page/santa.html.twig');}#[Route('/payment/reject', name: 'page_reject')]public function pageReject(Request $request){if ($request->get('santa_id')) {$santa = $this->entityManager->getRepository(Santa::class)->find($request->get('santa_id'));$santa->setStatus(SantaEnum::SANTA_REJECTED);return $this->render('@web/page/payment_reject.html.twig');}return $this->redirectToRoute('page_index');}#[Route('/payment/confirm', name: 'page_confirm')]public function pageConfirm(Request $request, HttpClientInterface $client){if ($request->get('santa_id')) {$santa = $this->entityManager->getRepository(Santa::class)->find($request->get('santa_id'));$santa->setStatus(SantaEnum::SANTA_PAID);$this->entityManager->flush();$payload = ['id' => $santa->getId(),'name' => $santa->getName(),'locale' => $santa->getLocale(),'gift' => $santa->getGift(),'message' => $santa->getMessage(),];// Pass the payload to Twigreturn $this->render('@web/page/payment_confirm.html.twig', ['payload' => json_encode($payload),]);}return $this->redirectToRoute('page_index');}#[Route('/send_santa_api', name: 'send_santa_api')]public function sendSantaApi(Request $request, HttpClientInterface $client, RequestStack $requestStack, ParameterBagInterface $parameterBag, MailerInterface $mailer, TranslatorInterface $translator){$payload = json_decode($request->getContent(), true);$santa = $this->entityManager->getRepository(Santa::class)->find($payload['id']);$santa->setStatus(SantaEnum::SANTA_PROCESS);$this->entityManager->flush();// Call the other API$response = $client->request('POST', 'https://santa2025.store/receive_letter_api', ['json' => $payload,'headers' => ['Accept' => 'application/json','Content-Type' => 'application/json','User-Agent' => 'Mozilla/5.0 (Symfony Server)','Referer' => 'https://santa2025.store',],'timeout' => 1500,]);$data = $response->toArray(); // The API response$videoUrl = $data['video_url'] ?? null;$santa->setStatus(SantaEnum::SANTA_COMPLETED);$this->entityManager->flush();$letter = $this->entityManager->getRepository(Letter::class)->findOneBy(['externalId' => $data['letter_id']]);$gallery = $this->entityManager->getRepository(Gallery::class)->findOneBy(['letterId' => $letter->getId()]);$this->entityManager->persist($gallery);$this->entityManager->flush();$preview = false;$viewImage = false;$current = $requestStack->getCurrentRequest();$main = $requestStack->getMainRequest(); // Symfony 5.3+; may be null$locale = $gallery->getLocale();$this->translatableListener->setTranslatableLocale($locale);$page = $this->entityManager->getRepository(Page::class)->createQueryBuilder('p')->where('p.id = :id')->setParameter('id', $gallery->getTemplateId())->getQuery()->getOneOrNullResult();$requestToUse = $main ?? $current ?? $request; // fallback to injected $request paramif ($requestToUse) {// The important one: attributes _locale (LocaleListener checks this)$requestToUse->attributes->set('_locale', $locale);// Also set request locale and session (if available)$requestToUse->setLocale($locale);if ($requestToUse->hasSession()) {$requestToUse->getSession()->set('_locale', $locale);}}// 2) Set translator locale$translator->setLocale($locale);// Optional: also set locale on PHP intl (not usually required)\Locale::setDefault($locale);$html = $this->renderView('@web/page/template-santa-tmp.html.twig', ['page' => $page,'preview' => $preview,'viewImage' => $viewImage,'letter' => $letter,'gallery' => $gallery,'image' => $gallery->getImage(),'editable' => false]);$filename = (string)time();$htmlDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/html/' . $filename . '.html';file_put_contents($htmlDir, $html);$pdfDir = $parameterBag->get('kernel.project_dir') . '/public/uploads/pdf/' . $filename . '.pdf';PdfConverter::convertHtmlToPdf($htmlDir, $pdfDir);$subject = $translator->trans('email_subject', ['%number%' => $gallery->getDocumentNumber(),'%name%' => $santa->getName(),]);$email = (new Email())->from(new Address('support@infinitemoment.life', 'Infinite Moment Santa'))->to($santa->getEmail())->subject($subject)->html($this->renderView('email/santa_'.$santa->getLocale().'.html.twig',['subject' => $santa, 'video_url' => $videoUrl]))->attachFromPath($pdfDir, $filename . '.pdf', 'application/pdf');$mailer->send($email);if ($santa->getFromEmail()) {$email = (new Email())->from(new Address('support@infinitemoment.life', 'Infinite Moment Santa'))->to($santa->getFromEmail(),'developerhovsepyan@gmail.com')->subject($subject)->html($this->renderView('email/santa_'.$santa->getLocale().'.html.twig',['subject' => $santa,'video_url' => $videoUrl]))->attachFromPath($pdfDir, $filename . '.pdf', 'application/pdf');$mailer->send($email);}return new JsonResponse(['video_url' => $videoUrl]);}private const ADMIN_ID = 7;#[Route('/import-excel-public', name: 'import_excel_public')]public function importFromPublic(EntityManagerInterface $em): Response{$filePath = $this->getParameter('kernel.project_dir') . '/public/uploads/Infinite July.xlsx';// $filePath = '/mnt/data/Infinite July.xlsx'; // sandboxif (!file_exists($filePath)) {return new Response("Excel NOT FOUND: " . $filePath);}$spreadsheet = IOFactory::load($filePath);// ✅ Your file has sheet name "July"$sheet = $spreadsheet->getSheetByName('July') ?? $spreadsheet->getSheet(0);$maxRow = (int)$sheet->getHighestRow();// coin value => index in entity fields$coinIndexMap = [20000 => 1, 10000 => 2, 5000 => 3, 2000 => 4, 1000 => 5,500 => 6, 200 => 7, 100 => 8, 50 => 9, 20 => 10, 10 => 11, 1 => 15];$userAliases = ['anahit' => 'anahit old',];$created = 0;$skippedNoLocation = 0;$skippedNoDate = 0;$skippedNoPage = 0;$skippedDuplicate = 0;$skippedNoUserMatch = 0;/*** ✅ Your Excel structure is fixed blocks:* Header row: 2,17,32,... (step 15)* Coins: row+1..row+11 (10 AMD row is row+11)* Total row: row+12*/for ($row = 2; $row <= $maxRow; $row += 15) {// Location is in C(row)$location = trim((string)($sheet->getCell("C$row")->getValue() ?? ''));if ($location === '') {$skippedNoLocation++;continue;}// Date is in E(row)$rawDate = $sheet->getCell("E$row")->getValue();// fallback for formulas / calculated cellsif ($rawDate === null || $rawDate === '') {$rawDate = $sheet->getCell("E$row")->getCalculatedValue();}$currentDay = $this->parseExcelDate2025($rawDate);if (!$currentDay) {$skippedNoDate++;continue;}// Find Page by name = location$page = $em->getRepository(Page::class)->createQueryBuilder('p')->where('LOWER(p.name) = LOWER(:name)')->setParameter('name', $location)->setMaxResults(1)->getQuery()->getOneOrNullResult();if (!$page) {$skippedNoPage++;continue;}$type = 1; // Day// Skip duplicates$existing = $em->getRepository(FinancialPart::class)->findOneBy(['page' => $page,'currentDay' => $currentDay,'type' => $type,]);if ($existing) {$skippedDuplicate++;continue;}$fp = new FinancialPart();$fp->setCreatedAt(new \DateTime());$fp->setCurrentDay($currentDay);$fp->setType($type);$fp->setPage($page);// currency like admin$this->setCurrency($fp);// init quantitiesforeach ([1,2,3,4,5,6,7,8,9,10,11,15] as $i) {$setCash = "setCoinQuantity$i";$setTr = "setTransferQuantity$i";if (method_exists($fp, $setCash)) $fp->$setCash(0);if (method_exists($fp, $setTr)) $fp->$setTr(0);}// ✅ Coins are on next rows: row+1 .. row+11for ($r = $row + 1; $r <= $row + 11 && $r <= $maxRow; $r++) {$coinType = $this->toIntDigits($sheet->getCell("C$r")->getValue());$qty = $this->toIntDigits($sheet->getCell("D$r")->getValue());// Some rows have qty empty but value 0 -> ignoreif ($coinType <= 0 || $qty <= 0) continue;if (!isset($coinIndexMap[$coinType])) continue;$idx = $coinIndexMap[$coinType];$setCash = "setCoinQuantity$idx";if (method_exists($fp, $setCash)) {$fp->$setCash($qty);}}// ✅ Users are on row+1 in columns H..K$userNames = [];$usersRow = $row + 1;if ($usersRow <= $maxRow) {foreach (['H','I','J','K'] as $col) {$name = trim((string)($sheet->getCell($col . $usersRow)->getValue() ?? ''));if ($name !== '') $userNames[] = $name;}}$userNames = array_values(array_unique($userNames));$userCount = count($userNames);$percentPerUser = match ($userCount) {1 => 66,2 => 33,3 => 25,default => 0,};$matchedUsers = 0;$managerUser = null; // first matched = managerforeach ($userNames as $excelUserName) {$user = $this->findUserByExcelName($em, $excelUserName, $userAliases);if (!$user) continue;if ($managerUser === null) $managerUser = $user;$us = new UserSalary();$us->setUser($user);$us->setPercent($percentPerUser);$us->setSalary(0);$us->setExpense(0);$fp->addUserSalary($us);$em->persist($us);$matchedUsers++;}if ($matchedUsers === 0 || $managerUser === null) {$skippedNoUserMatch++;continue;}// ✅ same as FinancialPartAdmin$this->ensureAdminAndManager($fp, $em, $managerUser);$this->calculateSalaryLikeAdmin($fp, $managerUser);$em->persist($fp);$created++;}$em->flush();return new Response(sprintf("Import done. Created: %d | Skipped(no Location): %d | Skipped(no Date): %d | Skipped(no Page): %d | Skipped(duplicate): %d | Skipped(no user match): %d",$created, $skippedNoLocation, $skippedNoDate, $skippedNoPage, $skippedDuplicate, $skippedNoUserMatch));}private function ensureAdminAndManager(FinancialPart $fp, EntityManagerInterface $em, User $managerUser): void{$adminExists = false;$managerExists = false;foreach ($fp->getUserSalary() as $salary) {$uid = $salary->getUser()?->getId();if ($uid === self::ADMIN_ID) $adminExists = true;if ($uid === $managerUser->getId()) $managerExists = true;}if (!$adminExists) {$adminSalary = new UserSalary();$adminSalary->setUser($em->getReference(User::class, self::ADMIN_ID));$adminSalary->setPercent(40);$adminSalary->setSalary(0);$adminSalary->setExpense(0);$fp->addUserSalary($adminSalary);$em->persist($adminSalary);}if (!$managerExists) {$managerSalary = new UserSalary();$managerSalary->setUser($em->getReference(User::class, $managerUser->getId()));$managerSalary->setPercent(60);$managerSalary->setSalary(0);$managerSalary->setExpense(0);$fp->addUserSalary($managerSalary);$em->persist($managerSalary);}}private function calculateSalaryLikeAdmin(FinancialPart $fp, User $managerUser): void{$this->setCurrency($fp);foreach ($fp->getUserSalary() as $salary) {$salary->setSalary(0);$salary->setExpense(0);}$coins = [1 => 20000, 2 => 10000, 3 => 5000, 4 => 2000, 5 => 1000,6 => 500, 7 => 200, 8 => 100, 9 => 50, 10 => 20, 11 => 10, 15 => 1,];$totalPrice = 0;foreach ($coins as $i => $value) {$cash = method_exists($fp, "getCoinQuantity$i") ? ((int)($fp->{"getCoinQuantity$i"}() ?? 0)) : 0;$transfer = method_exists($fp, "getTransferQuantity$i") ? ((int)($fp->{"getTransferQuantity$i"}() ?? 0)) : 0;$totalPrice += ($cash + $transfer) * $value;}$adminExpense = $totalPrice * 0.05;$currentPrice = $totalPrice - $adminExpense;$managerProportion = $currentPrice * 0.60;$managerSalaryPrice = $managerProportion;$managerSalaryRow = null;foreach ($fp->getUserSalary() as $salary) {$uid = $salary->getUser()?->getId();if ($uid === self::ADMIN_ID) {$salary->setSalary($currentPrice - $managerProportion);$salary->setExpense($adminExpense);continue;}if ($uid === $managerUser->getId()) {$managerSalaryRow = $salary;continue;}$userSalaryPrice = $managerProportion * (((int)($salary->getPercent() ?? 0)) / 100);$salary->setSalary($userSalaryPrice);$managerSalaryPrice -= $userSalaryPrice;}if ($managerSalaryRow) {$managerSalaryRow->setSalary($managerSalaryPrice);}$fp->setTotalPrice((int)$totalPrice);}private function setCurrency(FinancialPart $fp): void{$fp->setCoinType1(20000);$fp->setCoinType2(10000);$fp->setCoinType3(5000);$fp->setCoinType4(2000);$fp->setCoinType5(1000);$fp->setCoinType6(500);$fp->setCoinType7(200);$fp->setCoinType8(100);$fp->setCoinType9(50);$fp->setCoinType10(20);$fp->setCoinType11(10);$fp->setCoinType15(1);}private function toIntDigits(mixed $v): int{if ($v === null) return 0;if (is_int($v)) return $v;if (is_float($v)) return (int)round($v);$s = trim((string)$v);if ($s === '') return 0;$digits = preg_replace('/\D+/', '', $s);if ($digits === '' || $digits === null) return 0;return (int)$digits;}private function normalizeName(string $s): string{$s = mb_strtolower(trim($s));$s = preg_replace('/\s+/', ' ', $s);return $s ?? '';}private function findUserByExcelName(EntityManagerInterface $em, string $excelName, array $aliases): ?User{$norm = $this->normalizeName($excelName);if (isset($aliases[$norm])) {$target = $aliases[$norm];$u = $em->getRepository(User::class)->createQueryBuilder('u')->where('LOWER(u.name) = LOWER(:name)')->setParameter('name', $target)->setMaxResults(1)->getQuery()->getOneOrNullResult();if ($u) return $u;}$u = $em->getRepository(User::class)->createQueryBuilder('u')->where('LOWER(u.name) = LOWER(:name)')->setParameter('name', $excelName)->setMaxResults(1)->getQuery()->getOneOrNullResult();if ($u) return $u;return $em->getRepository(User::class)->createQueryBuilder('u')->where('LOWER(u.name) LIKE :q')->setParameter('q', '%' . $norm . '%')->setMaxResults(1)->getQuery()->getOneOrNullResult();}// ✅ Works for your file (Excel numeric dates + DateTime + strings)private function parseExcelDate2025(mixed $raw): ?\DateTime{if ($raw === null || $raw === '') return null;if ($raw instanceof \DateTimeInterface) {$dt = new \DateTime($raw->format('Y-m-d'));$dt->setDate(2025, (int)$dt->format('m'), (int)$dt->format('d'));$dt->setTime(0, 0, 0);return $dt;}if (is_numeric($raw)) {try {$dt = ExcelDate::excelToDateTimeObject((float)$raw);$dt->setDate(2025, (int)$dt->format('m'), (int)$dt->format('d'));$dt->setTime(0, 0, 0);return $dt;} catch (\Throwable) {}}$s = trim((string)$raw);if ($s === '') return null;$formats = ['d.m.Y','d/m/Y','Y-m-d','d-m-Y','m/d/Y'];foreach ($formats as $fmt) {$dt = \DateTime::createFromFormat($fmt, $s);if ($dt instanceof \DateTime) {$dt->setDate(2025, (int)$dt->format('m'), (int)$dt->format('d'));$dt->setTime(0, 0, 0);return $dt;}}$ts = strtotime($s);if ($ts !== false) {$dt = (new \DateTime())->setTimestamp($ts);$dt->setDate(2025, (int)$dt->format('m'), (int)$dt->format('d'));$dt->setTime(0, 0, 0);return $dt;}return null;}#[Route('/user-account', name: 'user_account', methods: ['GET'])]public function userAccount(Request $request): Response{if (!$this->getUser()){return $this->redirectToRoute('app_login');}$templates = $this->entityManager->getRepository(UserTemplate::class)->findBy(['user' => $this->getUser()]);return $this->render('@web/page/user-account.html.twig',['templates' => $templates,'editable' => false,]);}#[Route('/user-gallery', name: 'user_gallery', methods: ['GET'])]public function userGallery(Request $request): Response{if (!$this->getUser()){return $this->redirectToRoute('app_login');}$gallery = $this->entityManager->getRepository(Gallery::class)->findBy(['user' => $this->getUser()],['id' => 'DESC'],20);return $this->render('@web/page/user-gallery.html.twig',['gallery' => $gallery,'editable' => false,]);}#[Route('/user-sallary', name: 'user_sallary', methods: ['GET'])]public function userSallary(Request $request): Response{if (!$this->getUser()){return $this->redirectToRoute('app_login');}$stats = $this->entityManager->getRepository(FinancialPart::class)->searchStats($request->query->all(), [IncomeEnum::TYPE_DAILY, IncomeEnum::TYPE_ADDITIONAL]);$statsDebt = $this->entityManager->getRepository(FinancialPart::class)->searchStats($request->query->all(), [IncomeEnum::TYPE_DEBT]);$statsExpense = $this->entityManager->getRepository(Expense::class)->searchStats($request->query->all());return $this->render('@web/page/user-sallary.html.twig',['editable' => false,'stats' => $stats,'statsDebt' => $statsDebt,'statsExpense' => $statsExpense,]);}#[Route('/setData', name: 'setData', methods: ['POST'])]public function setData(Request $request): Response{$json = $request->getContent();$file = $this->getParameter('kernel.project_dir'). '/var/data_' . date('Y-m-d_H-i-s') . '.json';file_put_contents($file, $json);return new Response('Saved to ' . basename($file));}}