From bd99d1af430ea7782bc71a2252455da492165106 Mon Sep 17 00:00:00 2001 From: Serreau Jovann Date: Fri, 16 Jan 2026 14:52:30 +0100 Subject: [PATCH] =?UTF-8?q?```=20=E2=9C=A8=20feat(Form/CustomerAddType):?= =?UTF-8?q?=20Ajoute=20formulaire=20pour=20cr=C3=A9er=20un=20nouveau=20cli?= =?UTF-8?q?ent.=20=E2=9C=A8=20feat(Form/CustomerAddAddressType):=20Cr?= =?UTF-8?q?=C3=A9e=20un=20formulaire=20pour=20g=C3=A9rer=20les=20adresses?= =?UTF-8?q?=20client.=20=E2=9C=A8=20feat(template/customer):=20Affiche=20e?= =?UTF-8?q?t=20permet=20l'=C3=A9dition=20des=20infos=20client=20et=20adres?= =?UTF-8?q?ses.=20=E2=99=BB=EF=B8=8F=20refactor(Form/CustomerType):=20Simp?= =?UTF-8?q?lifie=20le=20formulaire=20client.=20=F0=9F=90=9B=20fix(template?= =?UTF-8?q?/customer):=20Corrige=20l'affichage=20de=20la=20fiche=20client.?= =?UTF-8?q?=20```?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dashboard/CustomerController.php | 78 +++++-- src/Form/CustomerAddAddressType.php | 59 +++++ src/Form/CustomerAddType.php | 108 +++++++++ src/Form/CustomerType.php | 1 + templates/dashboard/customer/add.twig | 26 +++ templates/dashboard/customer/show.twig | 209 ++++++++++-------- 6 files changed, 373 insertions(+), 108 deletions(-) create mode 100644 src/Form/CustomerAddAddressType.php create mode 100644 src/Form/CustomerAddType.php diff --git a/src/Controller/Dashboard/CustomerController.php b/src/Controller/Dashboard/CustomerController.php index c30b11d..532c772 100644 --- a/src/Controller/Dashboard/CustomerController.php +++ b/src/Controller/Dashboard/CustomerController.php @@ -3,8 +3,12 @@ namespace App\Controller\Dashboard; use App\Entity\Customer; +use App\Entity\CustomerAddress; +use App\Form\CustomerAddAddressType; +use App\Form\CustomerAddType; use App\Form\CustomerType; use App\Logger\AppLogger; +use App\Repository\CustomerAddressRepository; use App\Repository\CustomerRepository; use App\Service\Search\Client; use Doctrine\ORM\EntityManagerInterface; @@ -50,11 +54,23 @@ class CustomerController extends AbstractController $this->appLogger->record('VIEW', 'Consultation de la page de création client'); $customer = new Customer(); - $form = $this->createForm(CustomerType::class, $customer); + $form = $this->createForm(CustomerAddType::class, $customer); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { + + $data= $request->request->all()['customer_add']; + + $userAddresse = new CustomerAddress(); + $userAddresse->setCustomer($customer); + $userAddresse->setAddress($data['adresse']); + $userAddresse->setCity($data['city']); + $userAddresse->setZipcode($data['zipcode']); + $userAddresse->setCountry($data['country']); + $userAddresse->setAddress2($data['adresse2']); + $userAddresse->setAddress3($data['adresse3']); + $entityManager->persist($userAddresse); // 1. Sauvegarde en base de données $entityManager->persist($customer); $entityManager->flush(); @@ -84,6 +100,7 @@ class CustomerController extends AbstractController public function edit( int $id, CustomerRepository $customerRepository, + CustomerAddressRepository $addressRepository, // Injecté pour charger l'adresse Request $request, EntityManagerInterface $entityManager, \App\Service\Stripe\Client $stripeClient, @@ -95,40 +112,75 @@ class CustomerController extends AbstractController throw $this->createNotFoundException('Client introuvable'); } + // --- LOGIQUE ADRESSE (ADD OU EDIT) --- + $idAddr = $request->query->get('idAddr'); + + if ($idAddr) { + // Mode ÉDITION d'adresse : on cherche l'adresse existante + $address = $addressRepository->findOneBy([ + 'id' => $idAddr, + 'customer' => $customer // Sécurité : on vérifie que l'adresse appartient bien au client + ]); + + if (!$address) { + $this->addFlash('error', 'Adresse introuvable ou non associée à ce client.'); + return $this->redirectToRoute('app_crm_customer_edit', ['id' => $customer->getId()]); + } + } else { + // Mode AJOUT : nouvelle instance + $address = new CustomerAddress(); + $address->setCustomer($customer); + } + + $formAddress = $this->createForm(CustomerAddAddressType::class, $address); + $formAddress->handleRequest($request); + + if ($formAddress->isSubmitted() && $formAddress->isValid()) { + // Si c'est une nouvelle adresse, on doit faire persist + if (!$address->getId()) { + $entityManager->persist($address); + $logAction = 'Ajout'; + } else { + $logAction = 'Modification'; + } + + $entityManager->flush(); + + $appLogger->record($idAddr ? 'EDIT' : 'CREATE', sprintf('%s adresse pour le client : %s', $logAction, $customer->getName())); + $this->addFlash('success', sprintf('L\'adresse a été %s avec succès.', $idAddr ? 'modifiée' : 'ajoutée')); + + // On redirige vers la fiche sans le paramètre idAddr pour nettoyer l'URL + return $this->redirectToRoute('app_crm_customer_edit', ['id' => $customer->getId()]); + } + + // --- LOGIQUE FORMULAIRE CLIENT (Reste identique) --- $form = $this->createForm(CustomerType::class, $customer); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - // 1. Log de l'action - $appLogger->record('EDIT', sprintf('Modification du client : %s %s', $customer->getSurname(), $customer->getName())); - - // 2. Mise à jour sur Stripe (si le client possède un CustomerId) if ($customer->getCustomerId()) { - // Tu peux créer une méthode updateCustomer dans ton service Stripe - // ou simplement utiliser le client natif ici pour l'exemple : try { $stripeClient->updateCustomer($customer); } catch (\Exception $e) { - $this->addFlash('warning', 'Modifié localement, mais erreur de synchro Stripe : ' . $e->getMessage()); + $this->addFlash('warning', 'Erreur synchro Stripe : ' . $e->getMessage()); } } - - // 3. Sauvegarde en base de données $entityManager->flush(); - + $appLogger->record('EDIT', sprintf('Modification du client : %s %s', $customer->getSurname(), $customer->getName())); $this->addFlash('success', 'Les informations du client ont été mises à jour.'); return $this->redirectToRoute('app_crm_customer_edit', ['id' => $customer->getId()]); } - // Si c'est juste une consultation (GET), on log la vue - if (!$form->isSubmitted()) { + if ($request->isMethod('GET')) { $appLogger->record('VIEW', sprintf('Consultation de la fiche client : %s', $customer->getName())); } return $this->render('dashboard/customer/show.twig', [ 'customer' => $customer, + 'formAddress' => $formAddress->createView(), 'form' => $form->createView(), + 'editingAddress' => (bool)$idAddr // Pour changer le texte du bouton dans le Twig ]); } #[Route(path: '/crm/customer/delete/{id}', name: 'app_crm_customer_delete', methods: ['GET', 'POST'])] diff --git a/src/Form/CustomerAddAddressType.php b/src/Form/CustomerAddAddressType.php new file mode 100644 index 0000000..0ee5264 --- /dev/null +++ b/src/Form/CustomerAddAddressType.php @@ -0,0 +1,59 @@ +add('address', TextType::class, [ + 'label' => 'Adresse', + 'required' => true, + ]) + ->add('address2', TextType::class, [ + 'label' => 'Adresse 2', + 'required' => false, + ]) + ->add('address3', TextType::class, [ + 'label' => 'Adresse 3', + 'required' => false, + ]) + ->add('zipcode', TextType::class, [ + 'label' => 'Code postale', + 'required' => true, + ]) + ->add('city', TextType::class, [ + 'label' => 'Ville', + 'required' => true, + ]) + ->add('country', ChoiceType::class, [ + 'label' => 'Pays', + 'required' => true, + 'choices' => [ + 'France' => 'fr', + + ] + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => CustomerAddress::class, + ]); + } +} diff --git a/src/Form/CustomerAddType.php b/src/Form/CustomerAddType.php new file mode 100644 index 0000000..f7f2169 --- /dev/null +++ b/src/Form/CustomerAddType.php @@ -0,0 +1,108 @@ +add('civ', ChoiceType::class, [ + 'label' => 'Civilité', + 'choices' => [ + 'Monsieur' => 'M.', + 'Madame' => 'Mme', + ], + 'expanded' => false, + 'multiple' => false, + ]) + ->add('surname', TextType::class, [ + 'label' => 'Prénom', + 'attr' => ['placeholder' => 'ex: Jean'], + 'required' => true, + ]) + ->add('name', TextType::class, [ + 'label' => 'Nom', + 'attr' => ['placeholder' => 'ex: DUPONT'], + 'required' => true, + ]) + ->add('type', ChoiceType::class, [ + 'label' => 'Type de client', + 'choices' => [ + 'Particulier' => 'personal', + 'Entreprise' => 'company', + 'Association' => 'association', + 'Mairie / Collectivité' => 'mairie', + ], + ]) + ->add('email', EmailType::class, [ + 'label' => 'Adresse Email', + 'attr' => ['placeholder' => 'contact@exemple.fr'], + 'required' => true, + ]) + ->add('phone', TelType::class, [ // TelType est plus adapté pour mobile + 'label' => 'Téléphone', + 'attr' => ['placeholder' => '06 .. .. .. ..'], + 'required' => true, + ]) + ->add('siret', TextType::class, [ + 'label' => 'Numéro SIRET', + 'required' => false, + 'attr' => ['placeholder' => '14 chiffres'], + 'help' => 'Obligatoire pour les entreprises et mairies', + ]) + + ->add('adresse', TextType::class, [ + 'label' => 'Adresse', + 'required' => true, + 'mapped' => false, + ]) + ->add('adresse2', TextType::class, [ + 'label' => 'Adresse 2', + 'required' => false, + 'mapped' => false, + ]) + ->add('adresse3', TextType::class, [ + 'label' => 'Adresse 3', + 'required' => false, + 'mapped' => false, + ]) + ->add('zipcode', TextType::class, [ + 'label' => 'Code postale', + 'required' => true, + 'mapped' => false, + ]) + ->add('city', TextType::class, [ + 'label' => 'Ville', + 'required' => true, + 'mapped' => false, + ]) + ->add('country', ChoiceType::class, [ + 'label' => 'Pays', + 'required' => true, + 'mapped' => false, + 'choices' => [ + 'France' => 'fr', + + ] + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Customer::class, + ]); + } +} diff --git a/src/Form/CustomerType.php b/src/Form/CustomerType.php index c23d2f2..fbf0f93 100644 --- a/src/Form/CustomerType.php +++ b/src/Form/CustomerType.php @@ -5,6 +5,7 @@ namespace App\Form; use App\Entity\Customer; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\CountryType; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TelType; use Symfony\Component\Form\Extension\Core\Type\TextType; diff --git a/templates/dashboard/customer/add.twig b/templates/dashboard/customer/add.twig index 158ab06..2eaa375 100644 --- a/templates/dashboard/customer/add.twig +++ b/templates/dashboard/customer/add.twig @@ -80,6 +80,32 @@ {{ form_widget(form.phone) }} +
+
+ {{ form_label(form.adresse) }} + {{ form_widget(form.adresse) }} +
+
+ {{ form_label(form.adresse2) }} + {{ form_widget(form.adresse2) }} +
+
+ {{ form_label(form.adresse3) }} + {{ form_widget(form.adresse3) }} +
+
+ {{ form_label(form.zipcode) }} + {{ form_widget(form.zipcode) }} +
+
+ {{ form_label(form.city) }} + {{ form_widget(form.city) }} +
+
+ {{ form_label(form.country) }} + {{ form_widget(form.country) }} +
+
{# ACTIONS : Boutons espacés #} diff --git a/templates/dashboard/customer/show.twig b/templates/dashboard/customer/show.twig index 1772c07..bcf8ab5 100644 --- a/templates/dashboard/customer/show.twig +++ b/templates/dashboard/customer/show.twig @@ -1,13 +1,12 @@ {% extends 'dashboard/base.twig' %} {% block title %}Modifier le Client{% endblock %} -{% block title_header %}Fiche Client{% endblock %} +{% block title_header %}Fiche Client{% endblock %} {% block actions %} - {# Bouton Retour #} - - - Annuler + + + Retour au listing {% endblock %} @@ -15,158 +14,178 @@
{{ form_start(form) }} - - {# HEADER DE LA FICHE - GLASSMORPHISM #} -
+ {# HEADER DE LA FICHE #} +
-
+
{{ customer.surname|first|upper }}{{ customer.name|first|upper }}

- Fiche Client + Dossier Personnel {{ customer.surname|upper }} {{ customer.name }}

- ID Interne: #{{ customer.id }} + ID #{{ customer.id }} {% if customer.customerId %} - - - Stripe ID: {{ customer.customerId }} - - {% else %} - - Non synchronisé Stripe - + + + Stripe Sync + {% endif %}
- -
- {# GRILLE PRINCIPALE #} + {# GRILLE PRINCIPALE INFOS #}
- - {# COLONNE GAUCHE : ÉDITION DES DONNÉES #}
- Identité du client + Coordonnées de base
- {# LIGNE 1 : CIV / NOM / PRENOM #}
-
- {{ form_label(form.civ) }} - {{ form_widget(form.civ) }} -
-
- {{ form_label(form.surname) }} - {{ form_widget(form.surname) }} -
-
- {{ form_label(form.name) }} - {{ form_widget(form.name) }} -
+
{{ form_row(form.civ) }}
+
{{ form_row(form.surname) }}
+
{{ form_row(form.name) }}
- -
- - Contact & Société -
- - {# LIGNE 2 : EMAIL / TEL #}
-
- {{ form_label(form.email) }} - {{ form_widget(form.email) }} -
-
- {{ form_label(form.phone) }} - {{ form_widget(form.phone) }} -
+
{{ form_row(form.email) }}
+
{{ form_row(form.phone) }}
- - {# LIGNE 3 : TYPE / SIRET #}
-
- {{ form_label(form.type) }} - {{ form_widget(form.type) }} -
-
- {{ form_label(form.siret) }} - {{ form_widget(form.siret) }} -
+
{{ form_row(form.type) }}
+
{{ form_row(form.siret) }}
- {# COLONNE DROITE : STATUT & DANGER ZONE #}
- {# ACTIVITÉ #}

- Statut du compte + Résumé

- Type Client - {% set types = { - 'personal': 'Particulier', - 'company': 'Entreprise', - 'association': 'Association', - 'mairie': 'Mairie' - } %} - - {# Puis plus bas dans ton code : #} - - {{ types[customer.type] ?? customer.type|upper }} -
+ Contrat + + {{ customer.type|default('Standard') }} + +
- {# ZONE DE DANGER #}
- {{ form_end(form) }} + + {# SECTION ADRESSES #} +
+ + {# LISTE DES ADRESSES #} +
+

+ + Carnet d'adresses ({{ customer.customerAddresses|length }}) +

+ +
+ {% for address in customer.customerAddresses %} +
+
+
+

{{ address.address }}

+ {% if address.address2 %}

{{ address.address2 }}

{% endif %} +

+ {{ address.zipcode }} {{ address.city }} — {{ address.country }} +

+
+
+ + + +
+
+
+ {% else %} +
+

Aucune adresse enregistrée

+
+ {% endfor %} +
+
+ + {# FORMULAIRE D'ADRESSE (AJOUT/EDIT) #} +
+
+
+

+ + {{ editingAddress ? 'Modifier l\'adresse' : 'Ajouter une adresse' }} +

+
+ + {{ form_start(formAddress) }} +
+ {{ form_row(formAddress.address) }} + {{ form_row(formAddress.address2) }} + {{ form_row(formAddress.address3) }} +
+ {{ form_row(formAddress.zipcode) }} + {{ form_row(formAddress.city) }} +
+ {{ form_row(formAddress.country) }} + +
+ + + {% if editingAddress %} + + Annuler la modification + + {% endif %} +
+
+ {{ form_end(formAddress) }} +
+
+
{% endblock %}