<?php
namespace App\Controller;
use App\Entity\Client;
use App\Entity\Commande;
use App\Entity\Transaction;
use App\Entity\Tarif;
use App\Entity\Facture;
use App\Entity\PlanningReservation;
use App\Form\ClientType;
use App\Repository\PlanningReservationRepository;
use App\Repository\PaysRepository;
use App\Service\CreditService;
use App\Service\EntitySaver;
use App\Service\SogecommerceService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use IntlDateFormatter;
class ClientController extends AbstractController
{
private $sogecommerceService;
/**
* @var TokenStorageInterface
*/
private $tokenStorage;
/**
* @var GuardAuthenticatorHandler
*/
private $guardHandler;
/**
* @var RouterInterface
*/
private $router;
private EntitySaver $entitySaver;
private $entityManager;
public function __construct(
SogecommerceService $sogecommerceService,
TokenStorageInterface $tokenStorage,
GuardAuthenticatorHandler $guardHandler,
RouterInterface $router,
Security $security,
EntitySaver $entitySaver,
EntityManagerInterface $entityManager
)
{
// dump($this->getUser());die;
$this->security = $security;
$this->router = $router;
$this->tokenStorage = $tokenStorage;
$this->guardHandler = $guardHandler;
$this->sogecommerceService = $sogecommerceService;
$this->entitySaver = $entitySaver;
$this->entityManager = $entityManager;
}
#[Route('/register', name: 'client_register')]
public function register(
Request $request,
EntityManagerInterface $entityManager,
Security $security,
PaysRepository $paysRepository
): Response
{
$client = new Client();
// Création du formulaire
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
// Initialiser uniquement si le formulaire n’est pas soumis
if (!$form->isSubmitted()) {
$client->setCiv('mr');
}
if ($form->isSubmitted() && $form->isValid()) {
$recaptchaToken = $form->get('recaptcha_token')->getData();
// Vérifier auprès de Google
$clientGoogle = new \Symfony\Component\HttpClient\HttpClient();
$response = $clientGoogle::create()->request('POST', 'https://www.google.com/recaptcha/api/siteverify', [
'body' => [
'secret' => $_ENV['GOOGLE_RECAPTCHA_SECRET'],
'response' => $recaptchaToken,
'remoteip' => $request->getClientIp(),
],
]);
$data = $response->toArray();
if ($data['success'] === true && $data['score'] >= 0.5 && $data['action'] === 'registration') {
// ✅ Captcha validé → tu continues ton inscription
} else {
// ❌ Captcha échoué → renvoyer une erreur
$this->addFlash('error', 'Échec du reCAPTCHA, veuillez réessayer.');
$pays = $paysRepository->findList();
return $this->render('client/register.html.twig', [
'form' => $form->createView(),
'path_name' => 'client_register',
'pays' => $pays
]);
}
// Hashage du mot de passe
$hashedPassword = password_hash($client->getPassword(), PASSWORD_BCRYPT);
$client->setPassword($hashedPassword);
$client->setDeleted(false);
$client->setCreated();
$client->setChanged();
// dump($client);die;
// Enregistrement en base de données
$entityManager->persist($client);
$entityManager->flush();
// Créer un jeton d'authentification
$token = new UsernamePasswordToken($client, null, 'main', $client->getRoles());
$this->tokenStorage->setToken($token);
// Démarrez la session pour cet utilisateur
$this->guardHandler->authenticateWithToken($token, $request);
// Ajout d'une notification flash de bienvenue
$this->addFlash('success', 'Bienvenue dans votre espace client !');
$pm = $request->query->get('pm');
// Rédirection vers le processus de paiement
if($pm != ""){
// Enregistrement des informations de commande
$commandes = $this->entitySaver->getCommandesEncours();
$tmp = [];
$user = $this->security->getUser();
// Récupération du bon de commande
$bon_commande_id = $this->entitySaver->getBonCommandeEncours($user->getId(), $this->entityManager);
// Enregistrement des informations de commandes + redirection de la liste des commandes en cours
foreach($commandes as &$item){
$item['client_id'] = $user->getId();
$commande = new Commande();
$commande->setTarifId($item['tarif_id']);
$commande->setQte($item['qte']);
$commande->setClientId($item['client_id']);
$commande->setBonCommandeId($bon_commande_id);
$commande->setDateCommande($item['date_commande']);
$commande->setStatutId(1);
$commande->setCreated();
$commande->setChanged();
$tmp[] = $commande;
}
$this->entitySaver->saveMany($tmp);
$this->entitySaver->initCommandes();
return new RedirectResponse($this->router->generate('front_reserve', [null, 'step' => 'recap']));
}
else
return new RedirectResponse($this->router->generate('client_espace'));
} else if ($form->isSubmitted() && !$form->isValid()) {
// Formulaire non valide : obtenir les erreurs
$errors = $form->getErrors(true, false);
// Parcourir les erreurs une par une
foreach ($errors as $error) {
if ($error instanceof \Symfony\Component\Form\FormError) {
$origin = $error->getOrigin(); // Récupère l'origine de l'erreur (champ)
$fieldName = $origin ? $origin->getName() : 'global'; // Nom du champ ou "global"
// Ajout du message d'erreur dans les flashs ou logs
$this->addFlash('error', sprintf(
'Erreur dans le champ "%s" : %s',
$fieldName,
$error->getMessage()
));
}
}
}
$pays = $paysRepository->findList();
return $this->render('client/register.html.twig', [
'form' => $form->createView(),
'path_name' => 'client_register',
'pays' => $pays
]);
}
#[Route('/espace-client', name: 'client_espace')]
public function espace(): Response
{
// Récupérez l'utilisateur connecté
$user = $this->security->getUser();
$this->redirectToLogin($user);
return $this->render('client/espace_client.html.twig', [
'user' => $user,
'path_name' => 'client_espace',
]);
}
#[Route('/espace-client/mes-coordonnees', name: 'client_coordonnees')]
public function coordonnees(): Response
{
// Récupérez l'utilisateur connecté
$user = $this->getUser();
$this->redirectToLogin($user);
return $this->render('client/coordonnees.html.twig', [
'user' => $user,
'path_name' => 'client_coordonnees',
]);
}
#[Route('/espace-client/mes-commandes', name: 'client_commande_encours')]
public function mes_commandes(Request $request, EntityManagerInterface $entityManager): Response
{
$user = $this->getUser();
$this->redirectToLogin($user);
$bon_commande_id = $this->entitySaver->getBonCommandeEncours($user->getId(), $entityManager);
$conditions = [
'client_id' => $user->getId(),
'statut_id' => 1,
'bon_commande_id' => $bon_commande_id
];
$repository = $entityManager->getRepository(Commande::class);
$commandes = $repository->findByFilters($conditions);
$repositoryTrf = $entityManager->getRepository(Tarif::class);
$tarifsDb = $repositoryTrf->findAll();
$tarifs = [];
foreach($tarifsDb as $item){
$tarifs[$item->getId()] = $item;
}
$total = 0;
$bon_commande_id = 0;
foreach($commandes as $itemCmd){
$total += $itemCmd->qte * $tarifs[$itemCmd->tarif_id]->pu;
$bon_commande_id = $itemCmd->getBonCommandeId();
}
// 20% designe le TVA
$total = $total + $total * 0.20;
// Convertir en chaîne pour s'assurer de la compatibilité
if (strlen((string)$bon_commande_id) < 6) {
$bon_commande_id = str_pad($bon_commande_id, 6, '0', STR_PAD_LEFT);
}
$form = $this->sogecommerceService->generatePaymentForm([
'vads_amount' => $total * 100, // Amount in cents
'vads_failure_url' => 'https://preprod.panda-coworking.com'.$this->generateUrl('payment_failure', [], false),
'vads_cust_name' => $user->getPrenom() . ' ' . $user->getNom(),
'vads_url_return' => 'https://preprod.panda-coworking.com'.$this->generateUrl('front_retour', [], false),
'vads_trans_id' => $bon_commande_id // Unique transaction ID
]);
return $this->render('client/mes_commandes.html.twig', [
'commandes' => $commandes,
'tarifs' => $tarifs,
'path_name' => 'mes_commandes',
'paymentForm' => $form
]);
}
#[Route('/espace-client/reserver-la-salle-de-reunion', name: 'client_reserver_salle_reunion')]
public function reserver_salle_reunion(Request $request, EntityManagerInterface $entityManager): Response
{
$connectedClient = $this->getUser();
$this->redirectToLogin($connectedClient);
$connectedClientId = $connectedClient ? $connectedClient->getId() : null;
// Liste des reservations pour cette semaine
// Date actuelle
$dateFiltre = $request->query->get('d');
$date = new \DateTime();
if(!empty($dateFiltre)){
$date = new \DateTime($dateFiltre);
}
$formatter = new IntlDateFormatter(
'fr_FR', // Locale en français
IntlDateFormatter::LONG, // Format long (ex. "février 2025")
IntlDateFormatter::NONE, // Pas besoin de l'heure
null,
null,
'MMMM' // Format uniquement pour afficher le mois en toutes lettres
);
$date1 = $date;
$mois_annee = $formatter->format($date1->modify('this week sunday'));
// $mois_annee = $date->modify('this week sunday')->format('F Y');
$date_lundi = $date->modify('this week monday')->format('Y-m-d');
$date_mardi = $date->modify('this week tuesday')->format('Y-m-d');
$date_mercred = $date->modify('this week wednesday')->format('Y-m-d');
$date_jeudi = $date->modify('this week thursday')->format('Y-m-d');
$date_vendredi = $date->modify('this week friday')->format('Y-m-d');
$date_samedi = $date->modify('this week saturday')->format('Y-m-d');
$date_dimanche = $date->modify('this week sunday')->format('Y-m-d');
$titre_tableau = 'Semaine du '.$date->modify('this week monday')->format('d').' au '.$date->modify('this week sunday')->format('d').' '.$mois_annee;
$dateNext = $date->modify('next week monday')->format('Y-m-d');
$dateLast = $date->modify('-14 days')->format('Y-m-d');
$options = [
'statut_id' => 1
];
$dates = [$date_lundi, $date_dimanche];
$repository = $entityManager->getRepository(PlanningReservation::class);
$plannings = $repository->findByFilters($options, $dates);
// Regroupement en PHP
$groupedByDate = [];
foreach ($plannings as $event) {
$dateKey = $event->getDateReservation()->format('Y-m-d');
$client_id = $event->getClientId();
// Chercher le client par son ID
$client = $entityManager->getRepository(Client::class)->findOneBy(['id' => $client_id]);
// Si le client n'est pas trouvé ou ne correspond pas au client connecté, ignorer cet événement
$isMyAccount = 1;
if (!$client || $client->getId() !== $connectedClientId) {
$isMyAccount = 0;
}
$timeValue = $event->getHeureDebut();
// Préparer les informations client
$clientData = [
'id' => $client->getId(),
'nom' => $client->getNom(),
'email' => $client->getEmail(),
'isMyAccount' => $isMyAccount,
// Ajouter d'autres champs si nécessaires
];
// Initialiser la clé si elle n'existe pas
if (!isset($groupedByDate[$dateKey])) {
$groupedByDate[$dateKey] = [];
}
// Ajouter les données de l'événement et du client
$groupedByDate[$dateKey][] = [
'time' => $timeValue,
'client' => $clientData,
];
}
return $this->render('client/reserver_salle_reunion.html.twig', [
'path_name' => 'client_reserver_salle_reunion',
'reservations' => json_encode($groupedByDate),
'user'=>$connectedClient,
'titre_tableau' => $titre_tableau,
'date_next' => $dateNext,
'date_last' => $dateLast,
'dates' => json_encode([$date_lundi, $date_mardi, $date_mercred, $date_jeudi, $date_vendredi, $date_samedi, $date_dimanche])
]);
}
#[Route('/espace-client/factures', name: 'client_factures')]
public function factures(Request $request, EntityManagerInterface $entityManager): Response
{
$user = $this->getUser();
$this->redirectToLogin($user);
$conditions = [
'client_id' => $user->getId()
];
$repository = $entityManager->getRepository(Facture::class);
$factures = $repository->findByFilters($conditions);
return $this->render('client/factures.html.twig', [
'path_name' => 'client_factures',
'factures' => $factures
]);
}
#[Route('/success', name: 'client_success')]
public function success(): Response
{
return $this->render('client/success.html.twig');
}
// Suppression commande
#[Route('/api/ajax/remove-data', name: 'ajax_remove_data')]
public function remove_cmd(Request $request, EntityManagerInterface $entityManager): JsonResponse
{
$user = $this->getUser();
$res = [
'success' => false
];
if ($request->isMethod('POST')) {
$idCmd = $request->request->get('idCmd');
$commande = $entityManager->getRepository(Commande::class)->findOneBy([
'id' => intval($idCmd),
'client_id' => $user->getId()
]);
if(!empty($commande)){
$commande->setStatutId(3);
$commande->setChanged();
$entityManager->persist($commande);
$entityManager->flush();
$res = ['success' => true];
// Vérification si on a aucune commande
$commandeAll = $entityManager->getRepository(Commande::class)->findByFilters([
'client_id' => $user->getId(),
'statut_id' => 1
]);
if(empty($commandeAll)){
$res['isEmpty'] = true;
}
}
}
return new JsonResponse($res);
}
#[Route('/api/ajax/reserver/sdr', name: 'ajax_reserver_sdr')]
public function reserver_sdr(Request $request, EntityManagerInterface $entityManager) :JsonResponse
{
$user = $this->getUser();
$res = ['success' => false];
if ($request->isMethod('POST')) {
$date = $request->request->get('date');
$heure_debut = $request->request->get('heure');
$tarif = $entityManager->getRepository(Tarif::class)->findOneBy([
'titre' => 'SDR'
]);
// Vérifier si le client a assez de crédit
if($user->cr_sdr > 0){
if(!empty($tarif)){
// Vérifier si le créneau est disponible
$reservation = $entityManager->getRepository(PlanningReservation::class)->findOneBy([
'date_reservation' => new \DateTime($date),
'heure_debut' => $heure_debut,
'tarif_id' => $tarif->getId()
]);
if(empty($reservation)){
$heure = new \DateTime($heure_debut);
$heure = $heure->modify('+1 hour');
// TVA 0 car aucun tva n'est applicable à un crédit
// $tva = $tarif->getPu() * 0.2;
$tva = $tarif->getPu() * 0;
// Enregistrement d'une ligne pour debiter son crédit
$unite = 'sdr';
$transaction = new Transaction();
$transaction->setClientId($user->getId());
$transaction->setType(-1);
$transaction->setTarifId($tarif->getId());
$transaction->setQte(1);
$transaction->setPu($tarif->getPu());
$transaction->setTotal($tarif->getPu());
$transaction->setTva($tva);
$transaction->setDateMouvement(date('Y-m-d H:i:s'));
$transaction->setDateValeur(date('Y-m-d H:i:s'));
$transaction->setStatutId(2);
$transaction->setUnite($unite);
$transaction->setCreated();
$transaction->setChanged();
// save
$entityManager->persist($transaction);
$entityManager->flush();
// Enregistrement reservation_salle
$reservation = new PlanningReservation();
$reservation->setClientId($user->getId());
$reservation->setTransactionId($transaction->getId());
$reservation->setTarifId($tarif->getId());
$reservation->setDateReservation($date);
$reservation->setHeureDebut($heure_debut);
$reservation->setHeureFin($heure->format('H:i'));
$reservation->setStatutId(1);
$reservation->setCreated();
$reservation->setChanged();
// save
$entityManager->persist($reservation);
// Garbage collector
$entityManager->flush();
$res = [
'success' => true,
'id_unite' => $unite
];
}
}
} else {
$res['status'] = 403;
}
}
return new JsonResponse($res);
}
#[Route('/api/ajax/annuler/sdr', name: 'ajax_annuler_reservation', methods: ["POST"])]
public function annuler_reservation(Request $request, EntityManagerInterface $em, PlanningReservationRepository $planningReservationRepository, CreditService $creditService): JsonResponse
{
$date = $request->request->get('date');
$heure_debut = $request->request->get('heure');
$client = $this->getUser(); // Récupère l'utilisateur connecté
// Trouve la réservation correspondante
$reservation = $planningReservationRepository->findOneBy([
'date_reservation' => new \DateTime($date),
'heure_debut' => $heure_debut,
'client_id' => $client->getId()
]);
if (!$reservation) {
return new JsonResponse(['success' => false, 'message' => 'Réservation non trouvée ou non autorisée.'], 403);
}
// Vérifiez si la réservation est passée
$now = new \DateTime();
$reservationDateTime = new \DateTime($date . ' ' . $heure_debut);
if ($reservationDateTime <= $now) {
return new JsonResponse([
'success' => false,
'message' => 'Impossible d\'annuler une réservation passée.'
], 400);
}
// Supprime la réservation
$em->remove($reservation);
$em->flush();
// Récupère le crédit
$creditService->addCreditToUser($client,1);
return new JsonResponse(['success' => true, 'id_unite' => 'sdr']);
}
#[Route('/api/ajax/deverouille', name: 'ajax_deverouille')]
public function deverouille(Request $request, EntityManagerInterface $entityManager) {
// Si un crédit a été utilisé et qu'on est dans la tranche horaire qui a été utilisée :
// Un Appel ajax est fait à une url, ce qui dévérouille la porte physiquement
$date = new \Datetime();
$date1 = $date;
$client = $this->getUser();
// Il faut ajouter 10mn pour pouvoir déverouille la porte -10mn avant
$heure_actuel = $date->modify('+10 minutes')->format('H:i');
$date_actuel = $date->format('Y-m-d');
$options = [
'date_actuel' => $date_actuel,
'heure_actuel' => $heure_actuel,
'client_id' => $client->getId()
];
$repository = $entityManager->getRepository(PlanningReservation::class);
$plannings = $repository->findByDeverouille($options);
// dump($plannings);die;
$formatter = new IntlDateFormatter(
'fr_FR', // Locale en français
IntlDateFormatter::LONG, // Format long (ex. "février 2025")
IntlDateFormatter::NONE, // Pas besoin de l'heure
null,
null,
'MMMM' // Format uniquement pour afficher le mois en toutes lettres
);
$mois_plus1 = $formatter->format($date1->modify('now +1 months'));
return $this->render('client/deverouille.html.twig', [
'plannings' => $plannings,
'mois_plus1' => $mois_plus1
]);
}
#[Route('/api/ajax/deverouille/confirm', name: 'ajax_deverouille_step')]
public function deverouille_confirm(Request $request, EntityManagerInterface $entityManager): JsonResponse
{
$user = $this->getUser();
$res = [
'success' => false
];
if ($request->isMethod('POST')) {
$tp = $request->request->get('tp');
$titre = '';
$unite = '';
$date = new \Datetime();
$heure_debut = $date->format('H:i');
$heure_fin = '19:00';
$date_debut = $date->format('Y-m-d');
$date_fin = $date->format('Y-m-d');
switch($tp){
case 'd':
$titre = 'Demi-journée';
$unite = 'mijourne';
$heure_fin = $date->modify('+4 hours')->format('H:i');
break;
case 'j':
$titre = 'Journée';
$unite = 'journe';
break;
case 'm':
$titre = 'Mois';
$unite = 'mois';
$date_fin = $date->modify('+1 month')->format('Y-m-d');
break;
}
$tarif = $entityManager->getRepository(Tarif::class)->findOneBy([
'titre' => $titre
]);
if(!empty($tarif)){
// TVA 0 car déduit depuis son crédit
$tva = $tarif->getPu() * 0;
$transaction = new Transaction();
$transaction->setClientId($user->getId());
$transaction->setType(-1);
$transaction->setTarifId($tarif->getId());
$transaction->setQte(1);
$transaction->setPu($tarif->getPu());
$transaction->setTotal($tarif->getPu());
$transaction->setTva($tva);
$transaction->setDateMouvement($date->format('Y-m-d H:i:s'));
$transaction->setDateValeur($date->format('Y-m-d H:i:s'));
$transaction->setStatutId(2);
$transaction->setUnite($unite);
$transaction->setCreated();
$transaction->setChanged();
$entityManager->persist($transaction);
$entityManager->flush();
// Enregistrement reservation_salle
$reservation = new PlanningReservation();
$reservation->setClientId($user->getId());
$reservation->setTransactionId($transaction->getId());
$reservation->setTarifId($tarif->getId());
$reservation->setDateReservation($date_debut);
$reservation->setDateReservationFin($date_fin);
$reservation->setHeureDebut($heure_debut);
$reservation->setHeureFin($heure_fin);
$reservation->setStatutId(1);
$reservation->setCreated();
$reservation->setChanged();
// save
$entityManager->persist($reservation);
$entityManager->flush();
$res = [
'success' => true,
'id_unite' => $unite
];
}
}
return new JsonResponse($res);
}
#[Route('/api/ajax/deverouille/open', name: 'ajax_open_step', methods: ['GET'])]
public function open(): JsonResponse {
header('Content-Type: application/json'); // Définir la réponse en JSON
//bon url : http://coworking.arobases.fr:1665/control?cmd=pulse,0,0,30
$url = "http://coworking.arobases.fr:1665/control?cmd=pulse,0,0,30";
$ch = curl_init(); // Initialiser cURL
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Désactiver la vérification SSL si besoin
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // Timeout de 10 secondes
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Récupérer le code HTTP
if (curl_errno($ch)) {
$res = json_encode(['error' => curl_error($ch)]);
} else {
http_response_code($httpCode);
$res = $response;
}
curl_close($ch);
return new JsonResponse($res);
}
private function redirectToLogin($client) {
if(empty($client)){
return $this->redirectToRoute('login');
// die;
}
}
}