<?
php
namespace App\Controller;
use App\Entity\Stock;
use App\Entity\Produit;
use App\Entity\Categorie;
use App\Entity\Vente;
use App\Entity\Achat;
use App\Entity\Mouvement;
use App\Form\AchatType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class MainController extends AbstractController
{
// ============================
// Page principale
// ============================
#[Route('/main', name: 'app_main')]
public function index(SessionInterface $session, Request $request, EntityManagerInterface $em): Response
{
// Vérification session
if (!$session->has('user_id')) {
return $this->redirectToRoute('app_login');
}
$userNom = $session->get('user_nom', 'Utilisateur');
$userLevel = $session->get('user_level', 'Utilisateur');
// Détermination page
$page = $request->query->get('page', 'accueil');
$allowedPages = ['accueil', 'produit', 'vente', 'achat', 'inventaire', 'parametre', 'admin'];
if (!in_array($page, $allowedPages)) $page = 'accueil';
if (in_array($page, ['parametre', 'admin']) && $userLevel !== 'Administrateur') $page = 'accueil';
// Variables communes
$produits = [];
$categories = [];
$vente = [];
$achats = [];
$numTicket = 0;
$total = 0;
$stocks = [];
// ============================
// Gestion PRODUITS
// ============================
if ($page === 'produit') {
$categories = $em->getRepository(Categorie::class)->findAll();
$produits = $em->getRepository(Produit::class)->findBy([], ['idProd' => 'DESC']);
// Suppression produit
if ($request->query->get('delete')) {
$id = $request->query->get('delete');
$produitToDelete = $em->getRepository(Produit::class)->find($id);
if ($produitToDelete) {
$em->remove($produitToDelete);
$em->flush();
$this->addFlash('success', " 🗑️ Produit supprimé avec succès.");
return $this->redirectToRoute('app_main', ['page' => 'produit']);
}
}
// Ajouter / Modifier produit
if ($request->isMethod('POST')) {
$data = $request->request;
$editMode = $data->get('editMode') === '1';
$idProd = $data->get('idProd');
$produit = $editMode ? $em->getRepository(Produit::class)->find($idProd) : new Produit();
$categorie = $em->getRepository(Categorie::class)->find($data->get('idCategorie'));
$nom = trim($data->get('Nom'));
$produitExistant = $em->getRepository(Produit::class)->findOneBy(['nom' => $nom]);
if ($produitExistant && !$editMode) {
$this->addFlash('error', " ⚠️Ce produit existe déjà !");
return $this->redirectToRoute('app_main', ['page' => 'produit']);
}
if (!$editMode) {
if (!$idProd) {
$this->addFlash('error', " ⚠️L'ID du produit est obligatoire !");
return $this->redirectToRoute('app_main', ['page' => 'produit']);
}
$produit->setIdProd($idProd);
$em->persist($produit);
// Création stock initial si inexistant
$stock = new Stock();
$stock->setProduit($produit);
$stock->setQuantite(0);
$em->persist($stock);
}
$produit->setNom($nom);
$produit->setPrixUnitaire((float)$data->get('PrixUnitaire'));
$produit->setCommentaire($data->get('Commentaire'));
if ($categorie) $produit->addCategorie($categorie);
$em->flush();
$this->addFlash('success', $editMode ? " ✏️ Produit modifié !" : "✅ Produit ajouté !");
return $this->redirectToRoute('app_main', ['page' => 'produit']);
}
}
// ============================
// Gestion VENTE
// ============================
if ($page === 'vente') {
$vente = $session->get('vente', []);
// Numéro de ticket
if (!$session->has('Num_Ticket')) {
$dernier = $em->getRepository(Vente::class)
->createQueryBuilder('v')
->select('MAX([Link])')
->getQuery()
->getSingleScalarResult();
$session->set('Num_Ticket', $dernier ? ((int)$dernier + 1) : 1);
}
$numTicket = $session->get('Num_Ticket');
// Produits avec stock
$produitsObj = $em->getRepository(Produit::class)->findBy([], ['nom' => 'ASC']);
foreach ($produitsObj as $p) {
$stock = $em->getRepository(Stock::class)->findOneBy(['produit' => $p]);
$produits[] = [
'produit' => $p,
'stock' => $stock ? $stock->getQuantite() : 0
];
}
// Ajout produit (AJAX)
if ($request->isMethod('POST') && $request->request->has('ajouterProduit')) {
$nomProduit = trim($request->request->get('nomProduit', ''));
$quantite = (float) $request->request->get('Quantite', 0);
$produit = $em->getRepository(Produit::class)->findOneBy(['nom' => $nomProduit]);
if (!$produit) return $this->json(['error' => "Le produit \"$nomProduit\" n'existe pas."]);
$stock = $em->getRepository(Stock::class)->findOneBy(['produit' => $produit]);
$stockDispo = $stock ? $stock->getQuantite() : 0;
if ($quantite > $stockDispo) {
return $this->json(['error' => "Quantité insuffisante en stock. Disponible : $stockDispo"]);
}
// Mise à jour session
$found = false;
foreach ($vente as &$item) {
if ($item['idProd'] === $produit->getIdProd()) {
$item['Quantite'] += $quantite;
$found = true;
break;
}
}
unset($item);
if (!$found) {
$vente[] = [
'idProd' => $produit->getIdProd(),
'Nom' => $produit->getNom(),
'PrixUnitaire' => $produit->getPrixUnitaire(),
'Quantite' => $quantite,
];
}
$session->set('vente', $vente);
// Calcul total
$total = array_reduce($vente, fn($carry, $item) => $carry + ($item['PrixUnitaire'] * $item['Quantite']), 0);
// Générer HTML
$venteHtml = '';
foreach ($vente as $index => $item) {
$venteHtml .= '<tr data-index="'.$index.'">';
$venteHtml .= '<td>'.$item['Nom'].'</td>';
$venteHtml .= '<td contenteditable="true" class="editable-qty">'.$item['Quantite'].'</td>';
$venteHtml .= '<td>'.number_format($item['PrixUnitaire'], 0, ',', ' ').' Ar</td>';
$venteHtml .= '<td>'.number_format($item['PrixUnitaire'] * $item['Quantite'], 0, ',', ' ').' Ar</td>';
❌
$venteHtml .= '<td><button type="button" class="btn-supprimer"
onclick="supprimerProduit('.$index.')"> </button></td>';
$venteHtml .= '</tr>';
}
return $this->json([
'venteHtml' => $venteHtml,
'total' => number_format($total, 0, ',', ' ')
]);
}
// Enregistrer vente
if ($request->isMethod('POST') && $request->request->has('enregistrerVente')) {
if (empty($vente)) {
$this->addFlash('error', " ⚠️Vente vide !");
return $this->redirectToRoute('app_main', ['page' => 'vente']);
}
$venteImpossible = false;
$messagesErreur = [];
foreach ($vente as $item) {
$produit = $em->getRepository(Produit::class)->find($item['idProd']);
if (!$produit) continue;
$stock = $em->getRepository(Stock::class)->findOneBy(['produit' => $produit]);
$stockDispo = $stock ? $stock->getQuantite() : 0;
if ($item['Quantite'] > $stockDispo) {
$venteImpossible = true;
$messagesErreur[] = "Le produit {$produit->getNom()} n'a que $stockDispo en stock.";
}
}
if ($venteImpossible) {
$this->addFlash('error', implode('<br>', $messagesErreur));
return $this->redirectToRoute('app_main', ['page' => 'vente']);
}
$dateVente = new \DateTime();
foreach ($vente as $item) {
$produit = $em->getRepository(Produit::class)->find($item['idProd']);
if (!$produit) continue;
$venteEntity = new Vente();
$venteEntity->setProduit($produit);
$venteEntity->setQuantite($item['Quantite']);
$venteEntity->setPrixUnitaire($item['PrixUnitaire']);
$venteEntity->setDateVente($dateVente);
$venteEntity->setNumTicket($numTicket);
$em->persist($venteEntity);
if ($stock = $em->getRepository(Stock::class)->findOneBy(['produit' => $produit])) {
$stock->setQuantite($stock->getQuantite() - $item['Quantite']);
$mouv = new Mouvement();
$mouv->setProduit($produit);
$mouv->setQuantite(-$item['Quantite']);
$mouv->setType('vente');
$mouv->setDate(new \DateTime());
$em->persist($mouv);
}
}
$em->flush();
$session->remove('vente');
$session->remove('Num_Ticket');
$this->addFlash('success', " ✅ Vente enregistrée. Ticket N°" . sprintf("%03d", $numTicket));
return $this->redirectToRoute('app_main', ['page' => 'vente']);
}
// Calcul total pour affichage
$total = array_reduce($vente, fn($carry, $item) => $carry + ($item['PrixUnitaire'] * $item['Quantite']), 0);
}
// ============================
// Gestion ACHAT
// ============================
if ($page === 'achat') {
$produits = $em->getRepository(Produit::class)->findBy([], ['nom' => 'ASC']);
$achats = $em->getRepository(Achat::class)->findBy([], ['id' => 'DESC']);
$achat = new Achat();
$form = $this->createForm(AchatType::class, $achat);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$stock = $em->getRepository(Stock::class)->findOneBy(['produit' => $achat->getProduit()]);
if (!$