système de réduction pour l'app en fonction des clients, correcion de la base, maintenant les reductions sont appliquer automatiquement sur le client en fonction du montant dépenser, ajout d'un système de verif pour changer en fonction des modif, les reductions sont automatiquement changer ou crée en fonction des dépenses du client donc j'ai enlever le edit et new pcq on en a plus besoin encore 2 3 truc a régler mais le plus gros est fait, FAUT UPDATE LA BASE AVEC LES MIGRATIONS EN COURS SINON CA MARCHERA PAS

This commit is contained in:
joshua 2025-04-06 17:11:21 +02:00
parent e7206e3c8c
commit 01f23682b3
11 changed files with 253 additions and 185 deletions

View File

@ -39,7 +39,7 @@
"symfony/string": "7.1.*",
"symfony/translation": "7.1.*",
"symfony/twig-bundle": "7.1.*",
"symfony/ux-icons": "^2.21",
"symfony/ux-icons": "^2.24",
"symfony/ux-turbo": "^2.20",
"symfony/validator": "7.1.*",
"symfony/web-link": "7.1.*",

24
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7fff997f78db4185bb53c4543a245c74",
"content-hash": "d1751dd70a356412dfadda645c7118ec",
"packages": [
{
"name": "amphp/amp",
@ -8164,16 +8164,16 @@
},
{
"name": "symfony/ux-icons",
"version": "v2.21.0",
"version": "v2.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/ux-icons.git",
"reference": "c3b3fd29b3f90e977b267251ef15ea06f3cec553"
"reference": "39f689b41081f7788ee9c4a188817599d546bfb2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/ux-icons/zipball/c3b3fd29b3f90e977b267251ef15ea06f3cec553",
"reference": "c3b3fd29b3f90e977b267251ef15ea06f3cec553",
"url": "https://api.github.com/repos/symfony/ux-icons/zipball/39f689b41081f7788ee9c4a188817599d546bfb2",
"reference": "39f689b41081f7788ee9c4a188817599d546bfb2",
"shasum": ""
},
"require": {
@ -8197,8 +8197,8 @@
"type": "symfony-bundle",
"extra": {
"thanks": {
"name": "symfony/ux",
"url": "https://github.com/symfony/ux"
"url": "https://github.com/symfony/ux",
"name": "symfony/ux"
}
},
"autoload": {
@ -8233,7 +8233,7 @@
"twig"
],
"support": {
"source": "https://github.com/symfony/ux-icons/tree/v2.21.0"
"source": "https://github.com/symfony/ux-icons/tree/v2.24.0"
},
"funding": [
{
@ -8249,7 +8249,7 @@
"type": "tidelift"
}
],
"time": "2024-10-21T19:01:22+00:00"
"time": "2025-04-04T17:32:18+00:00"
},
{
"name": "symfony/ux-turbo",
@ -11242,7 +11242,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": true,
"prefer-lowest": false,
"platform": {
@ -11250,6 +11250,6 @@
"ext-ctype": "*",
"ext-iconv": "*"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@ -1,19 +1,22 @@
<?php
// src/Controller/ClientsController.php
namespace App\Controller;
use App\Entity\Clients;
use App\Entity\Reductions;
use App\Form\ClientsType;
use App\Repository\ClientsRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Annotation\Route;
#[Route('/clients')]
final class ClientsController extends AbstractController
{
#[Route(name: 'app_clients_index', methods: ['GET'])]
public function index(ClientsRepository $clientsRepository): Response
{
@ -30,6 +33,12 @@ final class ClientsController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$montantTotal = $client->getTotalDepense();
if($montantTotal > 1000){
$this->appliquerReductionEtCreerSiNecessaire($client, $entityManager);
}
$entityManager->persist($client);
$entityManager->flush();
@ -42,7 +51,6 @@ final class ClientsController extends AbstractController
]);
}
#[Route('/{id}/edit', name: 'app_clients_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Clients $client, EntityManagerInterface $entityManager): Response
{
@ -50,6 +58,13 @@ final class ClientsController extends AbstractController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$montantTotal = $client->getTotalDepense();
if($montantTotal > 1000){
$this->appliquerReductionEtCreerSiNecessaire($client, $entityManager);
}
$entityManager->flush();
return $this->redirectToRoute('app_clients_index', [], Response::HTTP_SEE_OTHER);
@ -62,13 +77,62 @@ final class ClientsController extends AbstractController
}
#[Route('/{id}', name: 'app_clients_delete', methods: ['POST'])]
public function delete(Request $request, Clients $client, EntityManagerInterface $entityManager, int $id, ): Response
public function delete(Request $request, Clients $client, EntityManagerInterface $entityManager): Response
{
if ($this->isCsrfTokenValid('delete'.$client->getId(), $request->getPayload()->getString('_token'))) {
if ($this->isCsrfTokenValid('delete'.$client->getId(), $request->request->get('_token'))) {
$entityManager->remove($client);
$entityManager->flush();
}
return $this->redirectToRoute('app_clients_index', [], Response::HTTP_SEE_OTHER);
}
// Méthode pour appliquer ou créer une réduction pour un client
// src/Controller/ClientsController.php
private function appliquerReductionEtCreerSiNecessaire(Clients $client, EntityManagerInterface $entityManager)
{
$montantTotal = $client->getTotalDepense();
$entityManager->persist($client);
$reductions = $entityManager->getRepository(Reductions::class)
->createQueryBuilder('r')
->where('r.montant_min <= :montantTotal')
->andWhere('r.actif = :actif')
->andWhere('r.DateDebut <= :currentDate')
->andWhere('r.DateFin >= :currentDate')
->setParameter('montantTotal', $montantTotal)
->setParameter('actif', true)
->setParameter('currentDate', new \DateTime())
->getQuery()
->getResult();
$newReduction = new Reductions();
if ($montantTotal >= 2000) {
$montantMin = 2000;
$pourcentage = 10;
} elseif ($montantTotal >= 1000) {
$montantMin = 1000;
$pourcentage = 5;
}
$newReduction->setPourcentage($pourcentage)
->setMontantMin($montantMin)
->setDateDebut(new \DateTime())
->setDateFin((new \DateTime())->modify('+1 year'))
->setActif(true)
->setClient($client);
$entityManager->persist($newReduction);
$entityManager->flush();
if (!$client->getReductions()->contains($newReduction)) {
$client->addReduction($newReduction);
}
$entityManager->flush();
}
}

View File

@ -40,10 +40,17 @@ class Clients
#[ORM\ManyToMany(targetEntity: Commandes::class, mappedBy: 'Client')]
private Collection $commandes;
#[ORM\Column]
private ?float $totalDepense = null;
#[ORM\OneToMany(targetEntity: Reductions::class, mappedBy: 'client', cascade: ['persist', 'remove'])]
private Collection $reductions;
public function __construct()
{
$this->tables = new ArrayCollection();
$this->commandes = new ArrayCollection();
$this->reductions = new ArrayCollection();
}
public function getId(): ?int
@ -149,4 +156,60 @@ class Clients
return $this;
}
public function getTotalDepense(): ?float
{
return $this->totalDepense;
}
public function setTotalDepense(float $totalDepense): static
{
$this->totalDepense = $totalDepense;
return $this;
}
// Dans l'entité Clients
public function appliquerReduction(): void
{
$montantTotal = $this->getTotalDepense();
// Vérifie s'il y a des réductions valides disponibles
$reductions = $this->getReductions(); // Récupérer toutes les réductions du client
foreach ($reductions as $reduction) {
// Vérifie si la réduction est valide (date de validité et montant minimum)
if ($reduction->getDateDebut() <= new \DateTime() && $reduction->getDateFin() >= new \DateTime()) {
if ($montantTotal >= $reduction->getMontantMin()) {
// Applique la réduction en pourcentage au total des dépenses
$reductionMontant = ($montantTotal * $reduction->getPourcentage()) / 100;
$nouveauTotal = $montantTotal - $reductionMontant; // Nouveau montant après réduction
$this->setTotalDepense($nouveauTotal); // Mise à jour du total des dépenses du client
// Met à jour l'objet client avec la réduction
break; // Si une réduction a été appliquée, on arrête
}
}
}
}
public function getReductions(): Collection
{
return $this->reductions;
}
public function addReduction(Reductions $reduction): static
{
if (!$this->reductions->contains($reduction)) {
$this->reductions->add($reduction);
}
return $this;
}
public function removeReduction(Reductions $reduction): static
{
$this->reductions->removeElement($reduction);
return $this;
}
}

View File

@ -39,9 +39,6 @@ class Plats
#[ORM\ManyToMany(targetEntity: Commandes::class, inversedBy: 'plats')]
private Collection $Commande;
#[ORM\ManyToOne(inversedBy: 'plats')]
private ?Reductions $Reduction = null;
public function __construct()
{
$this->Commande = new ArrayCollection();
@ -147,16 +144,4 @@ class Plats
return $this;
}
public function getReduction(): ?Reductions
{
return $this->Reduction;
}
public function setReduction(?Reductions $Reduction): static
{
$this->Reduction = $Reduction;
return $this;
}
}

View File

@ -16,88 +16,30 @@ class Reductions
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $Description = null;
#[ORM\Column]
private ?int $pourcentage = null;
#[ORM\Column]
private ?float $Prix = null;
private ?int $montant_min = null;
#[ORM\Column]
private ?int $Pourcentage = null;
#[ORM\Column(length: 255)]
private ?string $MontantFixe = null;
private ?bool $actif = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $DateDebut = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $DateFin = null;
/**
* @var Collection<int, Plats>
*/
#[ORM\OneToMany(targetEntity: Plats::class, mappedBy: 'Reduction')]
private Collection $plats;
public function __construct()
{
$this->plats = new ArrayCollection();
}
#[ORM\ManyToOne(targetEntity: Clients::class, inversedBy: 'reductions')]
#[ORM\JoinColumn(nullable: false)]
private ?Clients $client = null;
public function getId(): ?int
{
return $this->id;
}
public function getDescription(): ?string
{
return $this->Description;
}
public function setDescription(string $Description): static
{
$this->Description = $Description;
return $this;
}
public function getPrix(): ?float
{
return $this->Prix;
}
public function setPrix(float $Prix): static
{
$this->Prix = $Prix;
return $this;
}
public function getPourcentage(): ?int
{
return $this->Pourcentage;
}
public function setPourcentage(int $Pourcentage): static
{
$this->Pourcentage = $Pourcentage;
return $this;
}
public function getMontantFixe(): ?string
{
return $this->MontantFixe;
}
public function setMontantFixe(string $MontantFixe): static
{
$this->MontantFixe = $MontantFixe;
return $this;
}
public function getDateDebut(): ?\DateTimeInterface
{
return $this->DateDebut;
@ -122,33 +64,50 @@ class Reductions
return $this;
}
/**
* @return Collection<int, Plats>
*/
public function getPlats(): Collection
public function getPourcentage(): ?int
{
return $this->plats;
return $this->pourcentage;
}
public function addPlat(Plats $plat): static
public function setPourcentage(int $pourcentage): static
{
if (!$this->plats->contains($plat)) {
$this->plats->add($plat);
$plat->setReduction($this);
}
$this->pourcentage = $pourcentage;
return $this;
}
public function removePlat(Plats $plat): static
public function getMontantMin(): ?int
{
if ($this->plats->removeElement($plat)) {
// set the owning side to null (unless already changed)
if ($plat->getReduction() === $this) {
$plat->setReduction(null);
}
}
return $this->montant_min;
}
public function setMontantMin(int $montant_min): static
{
$this->montant_min = $montant_min;
return $this;
}
public function isActif(): ?bool
{
return $this->actif;
}
public function setActif(bool $actif): static
{
$this->actif = $actif;
return $this;
}
public function getClient(): ?Clients
{
return $this->client;
}
public function setClient(?Clients $client): static
{
$this->client = $client;
return $this;
}
}

View File

@ -4,6 +4,7 @@ namespace App\Form;
use App\Entity\Clients;
use App\Entity\Commandes;
use App\Entity\Reductions;
use App\Entity\Tables;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
@ -25,7 +26,7 @@ class ClientsType extends AbstractType
'multiple' => true,
'expanded' => true,
])
->add('totalDepense')
;
}

View File

@ -27,10 +27,6 @@ class PlatsType extends AbstractType
'multiple' => true,
'expanded' => true,
])
->add('Reduction', EntityType::class, [
'class' => Reductions::class,
'choice_label' => 'description',
])
;
}

View File

@ -2,7 +2,10 @@
namespace App\Form;
use App\Entity\Clients;
use App\Entity\Reductions;
use http\Client;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@ -12,16 +15,19 @@ class ReductionsType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('Description')
->add('Prix')
->add('Pourcentage')
->add('MontantFixe')
->add('Taux')
->add('DateDebut', null, [
'widget' => 'single_text',
])
->add('DateFin', null, [
'widget' => 'single_text',
])
->add('client', EntityType::class, [
'class' => Clients::class,
'choice_label' => 'nom',
'multiple' => false,
'expanded' => true,
])
;
}

View File

@ -2,60 +2,59 @@
{% block title %}Client index{% endblock %}
{% block head %}
<head>
<meta charset="UTF-8">
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
<link href="https://fonts.cdnfonts.com/css/brittany-signature" rel="stylesheet">
</head>
{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/ControllerVues/list.css') }}"> <!-- Ajout du fichier CSS -->
<link rel="stylesheet" href="{{ asset('css/Index/index.css') }}"> <!-- Ajout du fichier CSS -->
<link rel="stylesheet" href="{{ asset('css/Compte/index.css') }}"> <!-- Ajout du fichier CSS -->
<link rel="stylesheet" href="{{ asset('css/GestionUtilisateurs/GestionUtilisateurs.css') }}"> <!-- Ajout du fichier CSS -->
{% endblock %}
{% block container_modal %}
<div id="container_modal">
<h1>Clients index</h1>
<div id="container_modal">
<h1>Clients index</h1>
<table class="table">
<thead>
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Prenom</th>
<th>Nom</th>
<th>Email</th>
<th>Telephone</th>
<th>actions</th>
<th>Depense</th>
<th>Réduction Appliquée</th> <!-- Nouvelle colonne -->
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for client in clients %}
<tr>
<td>{{ client.id }}</td>
<td>{{ client.Prenom }}</td>
<td>{{ client.Nom }}</td>
<td>{{ client.Email }}</td>
<td>{{ client.Telephone }}</td>
<td>
<form method="post" action="{{ path('app_clients_delete', {'id': client.id}) }}" onsubmit="return confirm('Es-tu sur de vouloir le supprimer ?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ client.id) }}">
{{ include('clients/_delete_form.html.twig') }}
</form>
<a href="{{ path('app_clients_edit', {'id': client.id}) }}">Modifier</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="6">no records found</td>
</tr>
{% endfor %}
</tbody>
</table>
</thead>
<tbody>
{% for client in clients %}
<tr>
<td>{{ client.id }}</td>
<td>{{ client.Prenom }}</td>
<td>{{ client.Nom }}</td>
<td>{{ client.Email }}</td>
<td>{{ client.Telephone }}</td>
<td>{{ client.totalDepense }}</td>
<a href="{{ path('app_clients_new') }}">Créer un nouveau client</a>
</div>
<td>
{% if client.reductions|length > 0 %}
{% for reduction in client.reductions %}
<span>Réduction de {{ reduction.pourcentage }}% - Valide jusqu'à {{ reduction.DateFin|date('d/m/Y') }}</span><br>
{% endfor %}
{% else %}
Aucune réduction
{% endif %}
</td>
<td>
<form method="post" action="{{ path('app_clients_delete', {'id': client.id}) }}" onsubmit="return confirm('Es-tu sûr de vouloir le supprimer ?');">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ client.id) }}">
{{ include('clients/_delete_form.html.twig') }}
</form>
<a href="{{ path('app_clients_edit', {'id': client.id}) }}">Modifier</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="8">Aucun client trouvé</td>
</tr>
{% endfor %}
</tbody>
</table>
<a href="{{ path('app_clients_new') }}">Créer un nouveau client</a>
</div>
{% endblock %}

View File

@ -27,12 +27,11 @@
<thead>
<tr>
<th>Id</th>
<th>Description</th>
<th>Prix</th>
<th>Pourcentage</th>
<th>MontantFixe</th>
<th>Montant Minimum</th>
<th>DateDebut</th>
<th>DateFin</th>
<th>Client</th>
<th>actions</th>
</tr>
</thead>
@ -40,18 +39,16 @@
{% for reduction in reductions %}
<tr>
<td>{{ reduction.id }}</td>
<td>{{ reduction.Description }}</td>
<td>{{ reduction.Prix }}</td>
<td>{{ reduction.Pourcentage }}</td>
<td>{{ reduction.MontantFixe }}</td>
<td>{{ reduction.DateDebut ? reduction.DateDebut|date('Y-m-d H:i:s') : '' }}</td>
<td>{{ reduction.DateFin ? reduction.DateFin|date('Y-m-d H:i:s') : '' }}</td>
<td>{{ reduction.pourcentage }}%</td>
<td>{{ reduction.montantMin }} €</td>
<td>{{ reduction.DateDebut ? reduction.DateDebut|date('d/m/Y H:i:s') : 'Non spécifié' }}</td>
<td>{{ reduction.DateFin ? reduction.DateFin|date('d/m/Y H:i:s') : 'Non spécifié' }}</td>
<td>{{ reduction.client.nom }}</td>
<td>
<form method="post" action="{{ path('app_reductions_delete', {'id': reduction.id}) }}" onsubmit="return confirm('Es-tu sur de vouloir le supprimer ?'); ">
<form method="post" action="{{ path('app_reductions_delete', {'id': reduction.id}) }}" onsubmit="return confirm('Êtes-vous sûr de vouloir supprimer cette réduction ?'); ">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ reduction.id) }}">
{{ include('reductions/_delete_form.html.twig') }}
<button type="submit" class="btn btn-danger">Supprimer</button>
</form>
<a href="{{ path('app_reductions_edit', {'id': reduction.id}) }}">Modifier</a>
</td>
</tr>
{% else %}
@ -61,8 +58,6 @@
{% endfor %}
</tbody>
</table>
<a href="{{ path('app_reductions_new') }}">Créer une réduction</a>
</div>
{% endblock %}