✨ feat(SepaController): Ajoute la fonctionnalité de mandat SEPA pour les clients.
This commit is contained in:
35
migrations/Version20251012151847.php
Normal file
35
migrations/Version20251012151847.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20251012151847 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE TABLE customer_sepa (id SERIAL NOT NULL, customer_id INT DEFAULT NULL, iban VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_57C955EA9395C3F3 ON customer_sepa (customer_id)');
|
||||
$this->addSql('ALTER TABLE customer_sepa ADD CONSTRAINT FK_57C955EA9395C3F3 FOREIGN KEY (customer_id) REFERENCES customer (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('ALTER TABLE customer_sepa DROP CONSTRAINT FK_57C955EA9395C3F3');
|
||||
$this->addSql('DROP TABLE customer_sepa');
|
||||
}
|
||||
}
|
||||
47
src/Controller/Artemis/Customer/SepaController.php
Normal file
47
src/Controller/Artemis/Customer/SepaController.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller\Artemis\Customer;
|
||||
|
||||
use App\Entity\Account;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\CustomerContact;
|
||||
use App\Entity\CustomerSepa;
|
||||
use App\Repository\CustomerContactRepository;
|
||||
use App\Service\Stancer\Client;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use LasseRafn\InitialAvatarGenerator\InitialAvatar;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class SepaController extends AbstractController
|
||||
{
|
||||
#[Route('/artemis/customer/sepa', name: 'artemis_customer_sepa', methods: ['GET', 'POST'])]
|
||||
public function artemisCustomerSepa(Request $request,EntityManagerInterface $entityManager,CustomerContactRepository $customerContactRepository,Client $client): Response
|
||||
{
|
||||
/** @var Account $customer */
|
||||
$customer = $this->getUser();
|
||||
$contact = $customerContactRepository->findOneBy(['email'=>$customer->getEmail()]);
|
||||
|
||||
if($request->isMethod('POST')) {
|
||||
$data = $request->request->all();
|
||||
$mandate = $data['mandate'];
|
||||
|
||||
$customer = $contact->getCustomer();
|
||||
|
||||
$id = $client->sepa($mandate);
|
||||
|
||||
$sepa = new CustomerSepa();
|
||||
$sepa->setCustomer($customer);
|
||||
$sepa->setIban($id->id);
|
||||
$entityManager->persist($sepa);
|
||||
$entityManager->flush();
|
||||
|
||||
}
|
||||
return $this->render('artemis/customer/sepa.twig', [
|
||||
'sepas' => $contact->getCustomer()->getCustomerSepas(),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,6 +117,12 @@ class Customer
|
||||
#[ORM\ManyToOne(inversedBy: 'customers')]
|
||||
private ?Account $account = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, CustomerSepa>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: CustomerSepa::class, mappedBy: 'customer')]
|
||||
private Collection $customerSepas;
|
||||
|
||||
|
||||
public function __clone(): void
|
||||
{
|
||||
@@ -140,6 +146,7 @@ class Customer
|
||||
$this->customerOrders = new ArrayCollection();
|
||||
$this->websites = new ArrayCollection();
|
||||
$this->customerSplits = new ArrayCollection();
|
||||
$this->customerSepas = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -596,4 +603,34 @@ class Customer
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, CustomerSepa>
|
||||
*/
|
||||
public function getCustomerSepas(): Collection
|
||||
{
|
||||
return $this->customerSepas;
|
||||
}
|
||||
|
||||
public function addCustomerSepa(CustomerSepa $customerSepa): static
|
||||
{
|
||||
if (!$this->customerSepas->contains($customerSepa)) {
|
||||
$this->customerSepas->add($customerSepa);
|
||||
$customerSepa->setCustomer($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeCustomerSepa(CustomerSepa $customerSepa): static
|
||||
{
|
||||
if ($this->customerSepas->removeElement($customerSepa)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($customerSepa->getCustomer() === $this) {
|
||||
$customerSepa->setCustomer(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
50
src/Entity/CustomerSepa.php
Normal file
50
src/Entity/CustomerSepa.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\CustomerSepaRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: CustomerSepaRepository::class)]
|
||||
class CustomerSepa
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $iban = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'customerSepas')]
|
||||
private ?Customer $customer = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getIban(): ?string
|
||||
{
|
||||
return $this->iban;
|
||||
}
|
||||
|
||||
public function setIban(string $iban): static
|
||||
{
|
||||
$this->iban = $iban;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomer(): ?Customer
|
||||
{
|
||||
return $this->customer;
|
||||
}
|
||||
|
||||
public function setCustomer(?Customer $customer): static
|
||||
{
|
||||
$this->customer = $customer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
src/Repository/CustomerSepaRepository.php
Normal file
43
src/Repository/CustomerSepaRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\CustomerSepa;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<CustomerSepa>
|
||||
*/
|
||||
class CustomerSepaRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, CustomerSepa::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return CustomerSepa[] Returns an array of CustomerSepa objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('c')
|
||||
// ->andWhere('c.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('c.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?CustomerSepa
|
||||
// {
|
||||
// return $this->createQueryBuilder('c')
|
||||
// ->andWhere('c.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use App\Entity\Customer as AppCustomer;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Stancer\Config;
|
||||
use Stancer\Customer;
|
||||
use Stancer\Sepa;
|
||||
|
||||
class Client
|
||||
{
|
||||
@@ -49,4 +50,12 @@ class Client
|
||||
|
||||
return $stancerId;
|
||||
}
|
||||
|
||||
public function sepa($param)
|
||||
{
|
||||
$sepa = new Sepa();
|
||||
$sepa->setIban($param['iban']);
|
||||
$sepa->setName($param['titulaire_compte']);
|
||||
return$sepa->send();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,6 +204,12 @@
|
||||
<span class="ml-3">Facilité de paiement</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="px-4 py-2">
|
||||
<a href="{{ path('artemis_customer_sepa') }}" class="flex items-center p-2 text-base font-normal text-gray-900 dark:text-white {% if app.request.get('_route') == "artemis_cc_split"%}bg-gray-200 dark:bg-gray-700{% endif%} rounded-lg">
|
||||
<svg class="w-6 h-6 text-gray-500 dark:text-gray-400" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path><path d="M12 2.252A8.014 8.014 0 0117.748 12H12V2.252z"></path></svg>
|
||||
<span class="ml-3">Mendat de prévélevement</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
43
templates/artemis/customer/sepa.twig
Normal file
43
templates/artemis/customer/sepa.twig
Normal file
@@ -0,0 +1,43 @@
|
||||
{% extends 'artemis/base.twig' %}
|
||||
|
||||
{% block title %}Espace Client - Mandat de prélèvement{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% for sepa in sepas %}
|
||||
{{ dump(sepa) }}
|
||||
{% endfor %}
|
||||
<h2 class="text-3xl font-semibold text-gray-800 dark:text-gray-200">Créer un Mandat de Prélèvement</h2>
|
||||
|
||||
<div class="mt-5 bg-white dark:bg-gray-800 rounded-lg shadow-xl p-6 space-y-6">
|
||||
<p class="text-gray-700 dark:text-gray-300">
|
||||
Veuillez renseigner vos informations bancaires pour autoriser le prélèvement automatique de vos factures.
|
||||
</p>
|
||||
|
||||
<form method="POST" class="space-y-6">
|
||||
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-gray-100">Vos Coordonnées Bancaires</h3>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label for="iban" class="block text-sm font-medium text-gray-700 dark:text-gray-300">IBAN (International Bank Account Number) :</label>
|
||||
<input type="text" id="iban" name="mandate[iban]" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100" required
|
||||
placeholder="FRXX XXXX XXXX XXXX XXXX XXXX XXX"
|
||||
pattern="[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}"
|
||||
title="Veuillez entrer un IBAN valide.">
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label for="titulaire_compte" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Nom et Prénom du titulaire du compte :</label>
|
||||
<input type="text" id="titulaire_compte" name="mandate[titulaire_compte]" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100">
|
||||
</div>
|
||||
|
||||
<div class="pt-4">
|
||||
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-lg font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
|
||||
Valider le Mandat de Prélèvement
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user