<?php
namespace App\Controller;
use App\Entity\Bondesortie;
use App\Entity\Client;
use App\Entity\Devis;
use App\Entity\User;
use App\Form\AdminEditType;
use App\Form\ClientType;
use App\Form\EmployeType;
use App\Form\RegistrationFormType;
use App\Form\TechnicienType;
use App\Repository\BondesortieRepository;
use App\Repository\ClientRepository;
use App\Repository\DevisRepository;
use App\Repository\InterventionRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use DateTimeImmutable;
use DateTimeInterface;
use NumberFormatter;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class HomeController extends AbstractController
{
#[Route('admin/home', name: 'app_home')]
public function scraping(DevisRepository $devisRepository, BondesortieRepository $bondesortieRepository, ClientRepository $clientRepository, Request $request): Response
{
return $this->render('home/index.html.twig', $this->buildDashboardData(
$devisRepository,
$bondesortieRepository,
$clientRepository,
$request
));
}
#[Route('admin/home/export-excel', name: 'app_home_export_excel', methods: ['GET'])]
public function exportExcel(DevisRepository $devisRepository, BondesortieRepository $bondesortieRepository, ClientRepository $clientRepository, Request $request): StreamedResponse
{
$data = $this->buildDashboardData(
$devisRepository,
$bondesortieRepository,
$clientRepository,
$request
);
$spreadsheet = $this->createDashboardSpreadsheet($data);
$writer = new Xlsx($spreadsheet);
$filename = $this->buildDashboardExportFilename($data['filters']);
$response = new StreamedResponse(static function () use ($writer): void {
$writer->save('php://output');
});
$response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$filename
));
return $response;
}
private function buildDashboardData(DevisRepository $devisRepository, BondesortieRepository $bondesortieRepository, ClientRepository $clientRepository, Request $request): array
{
$selectedClientId = trim((string) $request->query->get('client', ''));
$selectedDateFrom = trim((string) $request->query->get('date_from', ''));
$selectedDateTo = trim((string) $request->query->get('date_to', ''));
$selectedDateRange = trim((string) $request->query->get('dateRangePicker', ''));
$selectedType = trim((string) $request->query->get('type', ''));
$selectedUnpaidOnly = in_array((string) $request->query->get('unpaid_only', ''), ['1', 'true', 'on', 'yes'], true);
if ($selectedDateRange !== '') {
[$selectedDateFrom, $selectedDateTo] = $this->parseDashboardDateRange($selectedDateRange);
} else {
$selectedDateRange = $this->buildDashboardDateRangeValue($selectedDateFrom, $selectedDateTo);
}
$selectedClient = $selectedClientId !== '' ? $clientRepository->find($selectedClientId) : null;
$dateFrom = $this->createDateFilter($selectedDateFrom, false);
$dateTo = $this->createDateFilter($selectedDateTo, true);
$stats = $this->createDashboardStats();
if ($selectedType !== '' && !isset($stats[$selectedType])) {
$selectedType = '';
}
$devisStatuts = $selectedType === ''
? ['Facture', 'BL', 'BLP']
: (in_array($selectedType, ['Facture', 'BL', 'BLP'], true) ? [$selectedType] : []);
$devis = $devisStatuts !== []
? $this->findDashboardDevis($devisRepository, $selectedClient, $dateFrom, $dateTo, $devisStatuts)
: [];
$bondesorties = $selectedType === '' || $selectedType === 'BS'
? $this->findDashboardBondesorties($bondesortieRepository, $selectedClient, $dateFrom, $dateTo)
: [];
$documents = [];
foreach ($devis as $devi) {
$this->addDevisDashboardDocument($devi, $stats, $documents, $selectedUnpaidOnly);
}
foreach ($bondesorties as $bondesortie) {
$this->addBondesortieDashboardDocument($bondesortie, $stats, $documents, $selectedUnpaidOnly);
}
usort($documents, static function (array $left, array $right): int {
return $right['dateTimestamp'] <=> $left['dateTimestamp'];
});
$totals = [
'count' => array_sum(array_column($stats, 'count')),
'total' => array_sum(array_column($stats, 'total')),
'paid' => array_sum(array_column($stats, 'paid')),
'remaining' => array_sum(array_column($stats, 'remaining')),
];
return [
'clients' => $clientRepository->findBy([], ['raisonsocial' => 'ASC', 'nom' => 'ASC', 'prenom' => 'ASC']),
'filters' => [
'client' => $selectedClientId,
'client_label' => $selectedClient instanceof Client ? $this->formatClientLabel($selectedClient) : 'Tous les clients',
'date_from' => $selectedDateFrom,
'date_to' => $selectedDateTo,
'date_range' => $selectedDateRange,
'type' => $selectedType,
'type_label' => $selectedType !== '' ? $stats[$selectedType]['shortLabel'] : 'Tous les types',
'unpaid_only' => $selectedUnpaidOnly,
'payment_label' => $selectedUnpaidOnly ? 'Non payes seulement' : 'Tous les paiements',
],
'stats' => $stats,
'totals' => $totals,
'documents' => $documents,
'chart' => [
'labels' => array_values(array_map(static fn (array $item): string => $item['shortLabel'], $stats)),
'remaining' => array_values(array_map(static fn (array $item): float => round($item['remaining'], 3), $stats)),
'paid' => array_values(array_map(static fn (array $item): float => round($item['paid'], 3), $stats)),
'total' => array_values(array_map(static fn (array $item): float => round($item['total'], 3), $stats)),
],
];
}
private function parseDashboardDateRange(string $dateRange): array
{
if (str_contains($dateRange, ' to ')) {
$parts = explode(' to ', $dateRange);
} elseif (str_contains($dateRange, ' au ')) {
$parts = explode(' au ', $dateRange);
} else {
$parts = [$dateRange];
}
$dateFrom = $this->normalizeDashboardDateString($parts[0] ?? '');
$dateTo = $this->normalizeDashboardDateString($parts[1] ?? ($parts[0] ?? ''));
return [$dateFrom, $dateTo];
}
private function normalizeDashboardDateString(string $date): string
{
$date = trim($date);
if ($date === '') {
return '';
}
$months = [
'janv' => 'Jan', 'janvier' => 'Jan',
'fevr' => 'Feb', 'fevrier' => 'Feb', 'févr' => 'Feb', 'février' => 'Feb',
'mars' => 'Mar',
'avr' => 'Apr', 'avril' => 'Apr',
'mai' => 'May',
'juin' => 'Jun',
'juil' => 'Jul', 'juillet' => 'Jul',
'aout' => 'Aug', 'août' => 'Aug',
'sept' => 'Sep', 'septembre' => 'Sep',
'oct' => 'Oct', 'octobre' => 'Oct',
'nov' => 'Nov', 'novembre' => 'Nov',
'dec' => 'Dec', 'decembre' => 'Dec', 'déc' => 'Dec', 'décembre' => 'Dec',
];
$lowerDate = mb_strtolower($date);
$mappedDate = strtr($lowerDate, $months);
$formats = ['Y-m-d', 'd-m-Y', 'd/m/Y', 'd M, Y', 'd M Y'];
foreach ($formats as $format) {
$dateTime = DateTimeImmutable::createFromFormat($format, $format === 'Y-m-d' || $format === 'd-m-Y' || $format === 'd/m/Y' ? $date : $mappedDate);
if ($dateTime instanceof DateTimeImmutable) {
return $dateTime->format('Y-m-d');
}
}
return '';
}
private function buildDashboardDateRangeValue(string $dateFrom, string $dateTo): string
{
if ($dateFrom !== '' && $dateTo !== '') {
return $dateFrom.' to '.$dateTo;
}
if ($dateFrom !== '') {
return $dateFrom;
}
return $dateTo;
}
private function createDashboardSpreadsheet(array $data): Spreadsheet
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setTitle('Reste a payer');
$filters = $data['filters'];
$documents = $data['documents'];
$totals = $data['totals'];
$sheet->mergeCells('A1:G1');
$sheet->setCellValue('A1', 'Tableau de bord des restes a payer');
$sheet->getStyle('A1')->getFont()->setBold(true)->setSize(16)->getColor()->setRGB('FFFFFF');
$sheet->getStyle('A1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
$sheet->getStyle('A1:G1')->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('405189');
$sheet->mergeCells('A2:G2');
$sheet->setCellValue('A2', sprintf(
'Type: %s | Client: %s | Periode: %s | Paiement: %s',
$filters['type_label'],
$filters['client_label'],
$this->formatDashboardPeriodLabel($filters['date_from'], $filters['date_to']),
$filters['payment_label']
));
$sheet->getStyle('A2')->getFont()->setItalic(true)->getColor()->setRGB('495057');
$sheet->getStyle('A2')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
$headers = ['Type', 'Numero', 'Date', 'Client', 'Total TTC', 'Paye', 'Reste a payer'];
$sheet->fromArray($headers, null, 'A4');
$sheet->getStyle('A4:G4')->getFont()->setBold(true)->getColor()->setRGB('000000');
$sheet->getStyle('A4:G4')->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('D0E3FA');
$sheet->getStyle('A4:G4')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
$row = 5;
foreach ($documents as $document) {
$sheet->setCellValue("A$row", $document['typeLabel']);
$sheet->setCellValue("B$row", $document['number']);
if ($document['date'] instanceof DateTimeInterface) {
$sheet->setCellValue("C$row", \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($document['date']));
} else {
$sheet->setCellValue("C$row", '');
}
$sheet->setCellValue("D$row", $document['client']);
$sheet->setCellValue("E$row", round((float) $document['total'], 3));
$sheet->setCellValue("F$row", round((float) $document['paid'], 3));
$sheet->setCellValue("G$row", round((float) $document['remaining'], 3));
if ($row % 2 === 0) {
$sheet->getStyle("A$row:G$row")->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('F8F9FA');
}
$row++;
}
$totalRow = $row;
$sheet->setCellValue("A$totalRow", 'Total');
$sheet->mergeCells("A$totalRow:D$totalRow");
$sheet->setCellValue("E$totalRow", round((float) $totals['total'], 3));
$sheet->setCellValue("F$totalRow", round((float) $totals['paid'], 3));
$sheet->setCellValue("G$totalRow", round((float) $totals['remaining'], 3));
$sheet->getStyle("A$totalRow:G$totalRow")->getFont()->setBold(true)->getColor()->setRGB('9C0006');
$sheet->getStyle("A$totalRow:G$totalRow")->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setRGB('FFD9D9');
$sheet->getStyle("A$totalRow:D$totalRow")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
$lastRow = max($totalRow, 5);
$sheet->getStyle("C5:C$lastRow")->getNumberFormat()->setFormatCode('dd/mm/yyyy');
$sheet->getStyle("E5:G$lastRow")->getNumberFormat()->setFormatCode('#,##0.000');
$sheet->getStyle("A4:G$lastRow")->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN)->getColor()->setRGB('E9EBEC');
$sheet->getStyle("E5:G$lastRow")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
$sheet->getStyle("A4:G$lastRow")->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
foreach (range('A', 'G') as $column) {
$sheet->getColumnDimension($column)->setAutoSize(true);
}
$sheet->freezePane('A5');
$sheet->setAutoFilter("A4:G$lastRow");
return $spreadsheet;
}
private function formatDashboardPeriodLabel(string $dateFrom, string $dateTo): string
{
if ($dateFrom === '' && $dateTo === '') {
return 'Toutes les dates';
}
if ($dateFrom !== '' && $dateTo !== '') {
return $this->formatFilterDate($dateFrom).' au '.$this->formatFilterDate($dateTo);
}
if ($dateFrom !== '') {
return 'A partir du '.$this->formatFilterDate($dateFrom);
}
return 'Jusqu au '.$this->formatFilterDate($dateTo);
}
private function formatFilterDate(string $date): string
{
$dateTime = DateTimeImmutable::createFromFormat('Y-m-d', $date);
return $dateTime instanceof DateTimeImmutable ? $dateTime->format('d/m/Y') : $date;
}
private function buildDashboardExportFilename(array $filters): string
{
$parts = [
'reste_a_payer',
$filters['type'] !== '' ? $filters['type'] : 'tous_types',
$filters['client_label'] !== 'Tous les clients' ? $filters['client_label'] : 'tous_clients',
];
if ($filters['date_from'] !== '' || $filters['date_to'] !== '') {
$parts[] = ($filters['date_from'] !== '' ? str_replace('-', '', $filters['date_from']) : 'debut')
.'_au_'
.($filters['date_to'] !== '' ? str_replace('-', '', $filters['date_to']) : 'fin');
} else {
$parts[] = 'toutes_dates';
}
if ($filters['unpaid_only']) {
$parts[] = 'non_payes';
}
$filename = strtolower(implode('_', $parts));
$filename = preg_replace('/[^a-z0-9_]+/i', '_', $filename) ?? 'reste_a_payer';
$filename = trim($filename, '_');
return $filename.'.xlsx';
}
private function createDateFilter(string $date, bool $endOfDay): ?DateTimeImmutable
{
if ($date === '') {
return null;
}
$dateTime = DateTimeImmutable::createFromFormat('Y-m-d', $date);
if (!$dateTime instanceof DateTimeImmutable) {
return null;
}
return $endOfDay ? $dateTime->setTime(23, 59, 59) : $dateTime->setTime(0, 0, 0);
}
/**
* @return Devis[]
*/
private function findDashboardDevis(DevisRepository $devisRepository, ?Client $client, ?DateTimeInterface $dateFrom, ?DateTimeInterface $dateTo, array $statuts): array
{
$queryBuilder = $devisRepository->createQueryBuilder('d')
->leftJoin('d.client', 'c')
->addSelect('c')
->leftJoin('d.paymentdevis', 'paymentdevis')
->addSelect('paymentdevis')
->andWhere('d.statut IN (:statuts)')
->setParameter('statuts', $statuts)
->orderBy('d.date', 'DESC')
->addOrderBy('d.datecreation', 'DESC')
->addOrderBy('d.id', 'DESC');
if ($client instanceof Client) {
$queryBuilder
->andWhere('d.client = :client')
->setParameter('client', $client);
}
if ($dateFrom instanceof DateTimeInterface) {
$queryBuilder
->andWhere('COALESCE(d.date, d.datecreation) >= :dateFrom')
->setParameter('dateFrom', $dateFrom);
}
if ($dateTo instanceof DateTimeInterface) {
$queryBuilder
->andWhere('COALESCE(d.date, d.datecreation) <= :dateTo')
->setParameter('dateTo', $dateTo);
}
return $queryBuilder->getQuery()->getResult();
}
/**
* @return Bondesortie[]
*/
private function findDashboardBondesorties(BondesortieRepository $bondesortieRepository, ?Client $client, ?DateTimeInterface $dateFrom, ?DateTimeInterface $dateTo): array
{
$queryBuilder = $bondesortieRepository->createQueryBuilder('b')
->leftJoin('b.client', 'c')
->addSelect('c')
->orderBy('b.date', 'DESC')
->addOrderBy('b.datecreation', 'DESC')
->addOrderBy('b.id', 'DESC');
if ($client instanceof Client) {
$queryBuilder
->andWhere('b.client = :client')
->setParameter('client', $client);
}
if ($dateFrom instanceof DateTimeInterface) {
$queryBuilder
->andWhere('COALESCE(b.date, b.datecreation) >= :dateFrom')
->setParameter('dateFrom', $dateFrom);
}
if ($dateTo instanceof DateTimeInterface) {
$queryBuilder
->andWhere('COALESCE(b.date, b.datecreation) <= :dateTo')
->setParameter('dateTo', $dateTo);
}
return $queryBuilder->getQuery()->getResult();
}
private function createDashboardStats(): array
{
return [
'Facture' => [
'label' => 'Factures',
'shortLabel' => 'Facture',
'route' => 'app_devis_liste_facture',
'color' => 'primary',
'icon' => 'ri-file-list-3-line',
'count' => 0,
'total' => 0.0,
'paid' => 0.0,
'remaining' => 0.0,
],
'BL' => [
'label' => 'Bons de livraison',
'shortLabel' => 'BL',
'route' => 'app_devis_liste_bl',
'color' => 'success',
'icon' => 'ri-truck-line',
'count' => 0,
'total' => 0.0,
'paid' => 0.0,
'remaining' => 0.0,
],
'BLP' => [
'label' => 'BL particuliers',
'shortLabel' => 'BLP',
'route' => 'app_devis_particulier_index',
'color' => 'warning',
'icon' => 'ri-user-received-2-line',
'count' => 0,
'total' => 0.0,
'paid' => 0.0,
'remaining' => 0.0,
],
'BS' => [
'label' => 'Bons de sortie',
'shortLabel' => 'BS',
'route' => 'app_bondesortie_index',
'color' => 'danger',
'icon' => 'ri-archive-drawer-line',
'count' => 0,
'total' => 0.0,
'paid' => 0.0,
'remaining' => 0.0,
],
];
}
private function addDevisDashboardDocument(Devis $devis, array &$stats, array &$documents, bool $unpaidOnly): void
{
$type = $devis->getStatut();
if (!isset($stats[$type])) {
return;
}
$total = $this->firstPositiveAmount([$devis->getMontantNet(), $devis->getTotalttc(), $devis->getTotal()]);
$payment = $devis->getPaymentdevis()->first();
$remaining = $total;
if ($payment !== false) {
$remaining = $this->firstAvailableAmount([$payment->getMontant(), $payment->getReste()], $total);
}
$remaining = max(0.0, $remaining);
if (!$this->shouldKeepDashboardDocument($remaining, $unpaidOnly)) {
return;
}
$paid = max(0.0, $total - $remaining);
$date = $devis->getDate() ?? $devis->getDatecreation();
$this->addDashboardAmounts($stats[$type], $total, $paid, $remaining);
$documents[] = [
'id' => $devis->getId(),
'type' => $type,
'typeLabel' => $stats[$type]['shortLabel'],
'typeColor' => $stats[$type]['color'],
'number' => $devis->getNum() ?: '#'.$devis->getId(),
'date' => $date,
'dateTimestamp' => $date instanceof DateTimeInterface ? $date->getTimestamp() : 0,
'client' => $this->getDevisClientLabel($devis),
'total' => $total,
'paid' => $paid,
'remaining' => $remaining,
'url' => $type === 'BLP'
? $this->generateUrl('app_devis_particulier_show', ['id' => $devis->getId()])
: $this->generateUrl('app_devis_show', ['id' => $devis->getId()]),
];
}
private function addBondesortieDashboardDocument(Bondesortie $bondesortie, array &$stats, array &$documents, bool $unpaidOnly): void
{
$type = 'BS';
$total = $this->firstPositiveAmount([$bondesortie->getTotalttc(), $bondesortie->getTotaleht()]);
$remaining = $total;
if (!$this->shouldKeepDashboardDocument($remaining, $unpaidOnly)) {
return;
}
$paid = 0.0;
$date = $bondesortie->getDate() ?? $bondesortie->getDatecreation();
$this->addDashboardAmounts($stats[$type], $total, $paid, $remaining);
$documents[] = [
'id' => $bondesortie->getId(),
'type' => $type,
'typeLabel' => $stats[$type]['shortLabel'],
'typeColor' => $stats[$type]['color'],
'number' => $bondesortie->getNumbs() ?: '#'.$bondesortie->getId(),
'date' => $date,
'dateTimestamp' => $date instanceof DateTimeInterface ? $date->getTimestamp() : 0,
'client' => $this->getBondesortieClientLabel($bondesortie),
'total' => $total,
'paid' => $paid,
'remaining' => $remaining,
'url' => $this->generateUrl('app_bondesortie_show', ['id' => $bondesortie->getId()]),
];
}
private function shouldKeepDashboardDocument(float $remaining, bool $unpaidOnly): bool
{
return !$unpaidOnly || round($remaining, 3) > 0.001;
}
private function addDashboardAmounts(array &$stat, float $total, float $paid, float $remaining): void
{
$stat['count']++;
$stat['total'] += $total;
$stat['paid'] += $paid;
$stat['remaining'] += $remaining;
}
private function firstPositiveAmount(array $amounts): float
{
foreach ($amounts as $amount) {
$parsedAmount = $this->parseAmount($amount);
if ($parsedAmount > 0) {
return $parsedAmount;
}
}
return 0.0;
}
private function firstAvailableAmount(array $amounts, float $fallback): float
{
foreach ($amounts as $amount) {
if ($amount !== null && trim((string) $amount) !== '') {
return $this->parseAmount($amount);
}
}
return $fallback;
}
private function parseAmount($value): float
{
$normalized = trim((string) $value);
if ($normalized === '') {
return 0.0;
}
$normalized = preg_replace('/[^0-9,\.\-]/', '', $normalized) ?? '';
if (str_contains($normalized, ',') && !str_contains($normalized, '.')) {
$normalized = str_replace(',', '.', $normalized);
} else {
$normalized = str_replace(',', '', $normalized);
}
return is_numeric($normalized) ? (float) $normalized : 0.0;
}
private function getDevisClientLabel(Devis $devis): string
{
if ($devis->getClient() instanceof Client) {
return $this->formatClientLabel($devis->getClient());
}
$nomClient = trim((string) $devis->getNomclient());
return $nomClient !== '' ? $nomClient : '-';
}
private function getBondesortieClientLabel(Bondesortie $bondesortie): string
{
if ($bondesortie->getClient() instanceof Client) {
return $this->formatClientLabel($bondesortie->getClient());
}
$nomPrenom = trim((string) $bondesortie->getNomprenom());
return $nomPrenom !== '' ? $nomPrenom : '-';
}
private function formatClientLabel(Client $client): string
{
$raisonSociale = trim((string) $client->getRaisonsocial());
if ($raisonSociale !== '') {
return $raisonSociale;
}
$nomComplet = trim(sprintf('%s %s', (string) $client->getNom(), (string) $client->getPrenom()));
return $nomComplet !== '' ? $nomComplet : '-';
}
#[Route('admin/Listes_techniciens', name: 'app_listeassitant')]
public function listeassitant(Request $request, UserRepository $userRepository): Response
{
$assistant= $userRepository->findByRoleTechnicien();
return $this->render('registration/listeassistant.html.twig', [
'assistants' =>$assistant,
]);
}
#[Route('admin/Listes_clients', name: 'app_clients_liste')]
public function listeclient(Request $request, ClientRepository $clientRepository): Response
{
$assistant= $clientRepository->findAll();
return $this->render('registration/listeclient.html.twig', [
'clients' =>$assistant,
]);
}
#[Route('admin/technicien', name: 'app_assistant')]
public function addadmin(Request $request, UserPasswordHasherInterface $userPasswordHasher, MailerInterface $mailer, EntityManagerInterface $entityManager): Response
{
$user = new User();
$form = $this->createForm(TechnicienType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Generate a password
$password = $this->generatePassword(12);
// Encode the plain password
$user->setPassword(
$userPasswordHasher->hashPassword(
$user,
$password
)
);
$user->setRoles(['ROLE_TECHNICIEN']);
$user->setPhoto("user.png");
$entityManager->persist($user);
$entityManager->flush();
// Send email
$email = (new TemplatedEmail())
->from(new Address('support@smart-it-partner.com', 'Tricotage '))
->to($user->getEmail())
->subject('Démarrez Votre Parcours avec Tricotage en tant que Technicien')
->htmlTemplate('registration/send_email.html.twig')
->context([
'emails' => $user->getEmail(),
'password' => $password,'user'=>$user,
]);
$mailer->send($email);
return $this->redirectToRoute('app_listeassitant');
}
return $this->render('registration/ajouterassistant.html.twig', [
'registrationForm' => $form->createView(),
]);
}
#[Route('/techniciens/{id}/edit', name: 'app_techniciens_edit', methods: ['GET', 'POST'])]
public function edittechniciens(Request $request, User $user,UserRepository $userRepository): Response
{
$form = $this->createForm(TechnicienType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$userRepository->save($user, true);
return $this->redirectToRoute('app_listeassitant', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('registration/edittechniciens.html.twig', [
'user' => $user,
'registrationForm' => $form,
]);
}
#[Route('admin/clients', name: 'app_clients')]
public function addclients(Request $request, UserPasswordHasherInterface $userPasswordHasher, MailerInterface $mailer, EntityManagerInterface $entityManager): Response
{
$user = new Client();
$form = $this->createForm(ClientType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Generate a password
$user->setPhoto("user.png");
$entityManager->persist($user);
$entityManager->flush();
return $this->redirectToRoute('app_clients_liste');
}
return $this->render('registration/ajouterclient.html.twig', [
'registrationForm' => $form->createView(),
]);
}
#[Route('/verifier-client', name: 'verifier_client', methods: ['POST'])]
public function verifierClient(Request $request, ClientRepository $clientRepository): JsonResponse
{
// Récupérer la Raison Sociale envoyée par la requête AJAX
$raisonSociale = $request->request->get('raisonSociale');
// dump($raisonSociale);
// Vérifier si un client avec cette Raison Sociale existe
if ($raisonSociale) {
$client = $clientRepository->findOneBy(['raisonsocial' => $raisonSociale]);
// Si le client existe, retourner une réponse JSON
if ($client) {
return new JsonResponse([
'exists' => true,
'message' => 'Le client existe déjà avec cette Raison Sociale.'
]);
}
// Si le client n'existe pas, retourner une réponse JSON indiquant cela
return new JsonResponse([
'exists' => false,
'message' => 'Aucun client trouvé avec cette Raison Sociale.'
]);
}
// En cas de requête invalide ou sans Raison Sociale
return new JsonResponse([
'exists' => false,
'message' => 'Raison Sociale non fournie.'
], 400); // Code HTTP 400 pour indiquer une requête invalide
}
private function generatePassword($size)
{
$characters = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z");
$password = '';
for ($i = 0; $i < $size; $i++) {
$password .= ($i % 2) ? strtoupper($characters[array_rand($characters)]) : $characters[array_rand($characters)];
}
return $password;
}
#[Route('admin/edit_profil', name: 'app_editprofile',methods: ['GET', 'POST'])]
public function editprofile(Request $request, UserRepository $userRepository): Response
{
$user= $userRepository->findOneBy(['id'=>$this->getUser()->getid()]) ;
$name = $user->getPhoto();
$form = $this->createForm(AdminEditType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$logo = $form->get('photo')->getData();
if ($logo) {
$originalLogoname = pathinfo( $logo->getClientOriginalName(), PATHINFO_FILENAME);
$newLogoname = $originalLogoname.'-'.uniqid().'.'.$logo->guessExtension();
// Move the file to the directory where brochures are stored
try {
$logo->move(
$this->getParameter('admin_directory'),
$newLogoname
);
} catch (FileException $e) {
// ... handle exception if something happens during file upload
}
$user->setPhoto($newLogoname);
}
else
{
$user->setPhoto($name);
}
$userRepository->save($user,true);
$this->addFlash('success', 'Votre compte a été modifié avec succès');
return $this->redirectToRoute('app_editprofile');
}
return $this->render('editprofile/editprofile.html.twig', [
'users' => $user,
'form' => $form->createView(),
]);
}
#[Route('admin/edit_password', name: 'modifier-password')]
public function editpassword(Request $request, UserRepository $userRepository ,UserPasswordHasherInterface $userPasswordHasher): Response
{
$user = $this->getUser();
// Vérifier si l'utilisateur est connecté
if (!$user) {
throw $this->createAccessDeniedException('Vous devez être connecté pour modifier le mot de passe.');
}
$user= $userRepository->findOneBy(['id'=>$this->getUser()->getid()]) ;
// Récupérer les données du formulaire
$currentPassword = $request->request->get('current-password');
$newPassword = $request->request->get('new-password');
// Vérifier si le mot de passe actuel est correct
if (!$userPasswordHasher->isPasswordValid($user, $currentPassword)) {
$this->addFlash('error', 'Mot de passe actuel incorrect.');
return $this->redirectToRoute('app_editprofile');
}
// Encoder et définir le nouveau mot de passe
$encodedPassword = $userPasswordHasher->hashPassword($user, $newPassword);
$user->setPassword($encodedPassword);
// Enregistrer les modifications dans la base de données
$userRepository->save($user,true);
$this->addFlash('success', 'Le mot de passe a été modifié avec succès.');
return $this->redirectToRoute('app_editprofile');
}
#[Route('admin/intervention', name: 'app_intervention')]
public function intervention(Request $request, UserRepository $userRepository): Response
{
$assistant= $userRepository->findByRoleclient();
return $this->render('intervention/intervention.html.twig', [
'assistants' =>$assistant,
]);
}
#[Route('/deletetechnicien/{id}', name: 'app_tecnicien_delete')]
public function deletetechniciens(Request $request, User $user , UserRepository $userRepository): Response
{
// if ($this->isCsrfTokenValid('delete'.$devi->getId(), $request->request->get('_token'))) {
$userRepository->remove($user, true);
// }
return $this->redirectToRoute('app_listeassitant', [], Response::HTTP_SEE_OTHER);
}
//Fonction mettre a jous les deux table intervention et devis a jours: si on click sur les liste dans espace admin le champs lu sera true avec la fonction ajax dans base.html.twig à l'aide de data-value
#[Route('/update_elements', name: 'update_elements', methods: ['POST','GET'])]
public function updateElements(DevisRepository $devisRepository,InterventionRepository $interventionRepository,Request $request,EntityManagerInterface $entityManager): JsonResponse
{
$url= $request->request->get('url');
// Mettre à jour les demande devis
if ($url === 'app_devis_demande') {
// dump($url);
$devis = $devisRepository->findBy(['lu' => false, 'statut'=>'Demande devis']);
foreach ($devis as $devi) {
$devi->setLu(true);
// Peut-être d'autres opérations ici, selon vos besoins
}
}
if ($url === 'app_devis_index') {
$devis = $devisRepository->findBy(['lu' => false, 'statut'=>'Demande devis']);
foreach ($devis as $devi) {
$devi->setLu(true);
// Peut-être d'autres opérations ici, selon vos besoins
}
}
// Mettre à jour les contacts
if ($url === 'app_intervention_index') {
$intervention = $interventionRepository->findBy(['lu' => false]);
foreach ($intervention as $interventions) {
$interventions->setLu(true);
// Peut-être d'autres opérations ici, selon vos besoins
}
}
// Enregistrer les modifications dans la base de données
$entityManager->flush();
// Répondre avec un JSON pour indiquer le succès de l'opération
return new JsonResponse(['success' => true]);
}
//La fonction compte le nombre total de notifications dans l'espace administrateur, demandes de devis et interventions signalées par le technicien.
#[Route('/totalnotif', name: 'app_total_notif', methods: ['GET'])]
public function totalnotif(DevisRepository $devisRepository,InterventionRepository $interventionRepository,Request $request): Response
{
$totaldevis = $devisRepository->getDevisByTechnicianRoleNonLu();
$totalintervention=$interventionRepository->findBy(['lu'=>false]);
$output[]=array(count($totaldevis));
$output[]=array(count($totalintervention) );
$output[]=array(count($totaldevis) + count($totalintervention) );
// dump($output);
return new JsonResponse($output);
}
#[Route('/notifsintervention', name: 'app_notifsintervention')]
public function notifsmessage(UrlGeneratorInterface $router,InterventionRepository $interventionRepository)
{
$intervention = $interventionRepository->getInterventionsByTechnicianRoleNonLu();
$interventions = array();
foreach ($intervention as $r) {
$datee = $r->getDatecreation() ? $r->getDatecreation()->format('d-m-Y H:i') : null;
$data = [
'id' => $r->getId(),
'nomtech' => $r->getUser()->getNom() ,
'prenomtech' => $r->getUser()->getPrenom() ,
'datee' => $datee,
// 'url' => $router->generate('app_message_repondre', ['id' => $r->getId()])
// Ajoutez d'autres champs si nécessaire
];
$interventions[] = $data;
}
return new JsonResponse($interventions);
}
#[Route('/notifsdemandedevis', name: 'app_notifsdemande_devis')]
public function notifsdemandedevis(UrlGeneratorInterface $router,DevisRepository $devisRepository)
{
$devis = $devisRepository->getDevisByTechnicianRoleNonLu();
$deviss = array();
foreach ($devis as $r) {
$datee = $r->getDatecreation() ? $r->getDatecreation()->format('d-m-Y H:i') : null;
$data = [
'id' => $r->getId(),
'nomtech' => $r->getUser()->getNom() ,
'prenomtech' => $r->getUser()->getPrenom() ,
'nomclient' => $r->getClient()->getNom() ,
'prenomclient' => $r->getClient()->getPrenom() ,
'datee' => $datee,
'url' => $router->generate('app_confirmation_demande_devis', ['id' => $r->getId()])
// Ajoutez d'autres champs si nécessaire
];
$deviss[] = $data;
}
return new JsonResponse($deviss);
}
}