feat(contrats): Améliore la gestion des contrats et des paiements.

- Rend le champ details non obligatoire dans add.twig
- Ajoute une valeur par défaut pour isSigned et type dans les entités.
- Corrige l'ajout des lignes et options au contrat.
- Ajoute la création automatique du client Stripe.
```
This commit is contained in:
Serreau Jovann
2026-02-06 11:06:38 +01:00
parent a6e5d5f4a8
commit 7ff3538bcd
8 changed files with 114 additions and 34 deletions

View File

@@ -0,0 +1,34 @@
<?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 Version20260206150000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Set default value for is_signed in contrats table';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contrats ALTER is_signed SET DEFAULT false');
$this->addSql('UPDATE contrats SET is_signed = false WHERE is_signed IS NULL');
$this->addSql('ALTER TABLE contrats ALTER is_signed SET NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contrats ALTER is_signed DROP DEFAULT');
$this->addSql('ALTER TABLE contrats ALTER is_signed DROP NOT NULL');
}
}

View File

@@ -0,0 +1,34 @@
<?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 Version20260206160000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Set default value for type in contrats_line table';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql("ALTER TABLE contrats_line ALTER type SET DEFAULT 'product'");
$this->addSql("UPDATE contrats_line SET type = 'product' WHERE type IS NULL");
$this->addSql("ALTER TABLE contrats_line ALTER type SET NOT NULL");
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contrats_line ALTER type DROP DEFAULT');
$this->addSql('ALTER TABLE contrats_line ALTER type DROP NOT NULL');
}
}

View File

@@ -291,7 +291,8 @@ class ContratController extends AbstractController
EntityManagerInterface $em,
UserPasswordHasherInterface $hasher,
CustomerRepository $customerRepository,
Security $security // Injection du service Security
Security $security, // Injection du service Security
\App\Service\Stripe\Client $stripeClient
): Response {
$session = $request->getSession();
$customer = $session->get('config_customer_id') ? $customerRepository->find($session->get('config_customer_id')) : null;
@@ -315,9 +316,17 @@ class ContratController extends AbstractController
$customer->setVerificationCode(null);
$customer->setVerificationCodeExpiresAt(null);
// Création Stripe automatique
try {
$stripeClient->createCustomer($customer);
} catch (\Exception $e) {
// Log l'erreur mais ne bloque pas le process, on pourra le refaire plus tard
// $logger->error('Erreur création Stripe auto : ' . $e->getMessage());
}
$em->flush();
$security->login($customer, 'form_login', 'main');
$security->login($customer, \App\Security\CustomerAuthenticator::class, 'main');
return $this->render('reservation/contrat/finish_activate.twig', [
'customer' => $customer,
@@ -493,6 +502,18 @@ class ContratController extends AbstractController
$existingPayment = $em->getRepository(ContratsPayments::class)->findOneBy($criteria);
if (!$existingPayment) {
// Check if customer exists in Stripe
$customer = $contrat->getCustomer();
if (!$customer->getCustomerId()) {
try {
$stripeClient->createCustomer($customer);
$em->flush();
} catch (\Exception $e) {
// Log error or handle it, maybe return null to show error
// For now we continue, assuming createPayment might fail gracefully or we just try
}
}
// Create new payment intent
if ($type === 'accompte') {
$result = $stripeClient->createPaymentAccompte($amount, $contrat);

View File

@@ -331,15 +331,16 @@ class ContratsController extends AbstractController
->setPriceSupDayHt($line['priceHtSupDay'])
->setCaution($line['caution']);
$this->em->persist($vc);
$contrat->addContratsLine($vc);
}
foreach ($postData['options'] ?? [] as $opt) {
$vo = (new ContratsOption())
->setContrat($contrat)
->setName($opt['name'])
->setDetails($opt['details'])
->setPrice($opt['priceHt']);
$this->em->persist($vo);
$contrat->addContratsOption($vo);
}
$contrat->setNumReservation($this->generateReservationNumber());

View File

@@ -68,8 +68,8 @@ class Contrats
#[ORM\Column(type: Types::TEXT,nullable: true)]
private ?string $notes = null;
#[ORM\Column]
private ?bool $isSigned = null;
#[ORM\Column(options: ['default' => false])]
private ?bool $isSigned = false;
#[ORM\Column(length: 255, nullable: true)]
private ?string $signID = null;

View File

@@ -28,8 +28,8 @@ class ContratsLine
#[ORM\Column]
private ?float $caution = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column(length: 255, options: ['default' => 'product'])]
private ?string $type = 'product';
public function getId(): ?int
{

View File

@@ -237,7 +237,7 @@
</div>
<div class="lg:col-span-2">
<label class="text-[9px] font-black text-slate-300 uppercase tracking-widest ml-1 mb-2 block">Détails</label>
<input type="text" name="options[{{ key }}][details]" value="{{ line.details }}" required class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
<input type="text" name="options[{{ key }}][details]" value="{{ line.details }}" class="w-full bg-slate-950/50 border-white/5 rounded-2xl text-white focus:ring-purple-500/20 focus:border-purple-500 transition-all py-3 px-5 text-sm font-mono">
</div>
{# 2. PRIX 1J #}
<div class="lg:col-span-3">

View File

@@ -89,16 +89,6 @@
{% endif %}
</div>
{# CAUTION #}
<div class="flex items-center gap-2 px-3 py-2 bg-gray-50 rounded-xl border border-gray-100">
<span class="text-[10px] font-bold text-gray-400 uppercase">Caution</span>
{% if contratPaymentPay(contrat, 'caution') %}
<span class="text-[10px] font-black text-green-600 bg-green-100 px-2 py-0.5 rounded-lg uppercase tracking-tight">Réceptionnée</span>
{% else %}
<span class="text-[10px] font-black text-red-500 bg-red-100 px-2 py-0.5 rounded-lg uppercase tracking-tight">Manquante</span>
{% endif %}
</div>
{# SOLDE #}
<div class="flex items-center gap-2 px-3 py-2 bg-gray-50 rounded-xl border border-gray-100">
<span class="text-[10px] font-bold text-gray-400 uppercase">Solde</span>