feat(command): Crée une commande pour l'envoi automatisé d'emails de suivi.

'Traitement des devis en attente de signature'
This commit is contained in:
Serreau Jovann
2026-01-29 15:57:46 +01:00
parent 21ecf299e5
commit 8dd8704686
2 changed files with 145 additions and 0 deletions

107
src/Command/MailCommand.php Normal file
View File

@@ -0,0 +1,107 @@
<?php
namespace App\Command;
use App\Entity\Devis;
use App\Repository\ProductRepository;
use App\Repository\OptionsRepository;
use App\Service\Mailer\Mailer;
use App\Service\Signature\Client;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Mime\Part\DataPart;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
#[AsCommand(
name: 'app:mail',
description: 'Envoi automatisé des emails de suivi (devis, contrats, relances)',
)]
class MailCommand extends Command
{
public function __construct(private readonly KernelInterface $kernel,private readonly UploaderHelper $uploaderHelper,private readonly Client $client,private readonly Mailer $mailer,private readonly EntityManagerInterface $entityManager)
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$now = new \DateTime();
// 1. Devis en attente de signature
$io->title('Traitement des devis en attente de signature');
$devisWaiting = $this->entityManager->getRepository(Devis::class)->findBy(['state' => 'wait-sign']);
foreach ($devisWaiting as $devis) {
$createdAt = $devis->getCreateA(); // Date de création
// On calcule la différence en jours entre aujourd'hui et la date de création
if ($createdAt instanceof \DateTimeInterface) {
$diff = $createdAt->diff($now)->days;
// On ne traite que si le devis a au moins 3 jours d'ancienneté
if ($diff >= 3) {
$customer = $devis->getCustomer();
$fullName = $customer->getName() . " " . $customer->getSurname();
$email = $customer->getEmail();
$doc = $this->uploaderHelper->asset($devis,'devisFile');
$files =[];
$files[] = new DataPart(file_get_contents($this->kernel->getProjectDir()."/public".$doc),"Devis N°".$devis->getNum(),"application/pdf");
$this->mailer->send(
$email,
$fullName,
"[Reservation Ludikevent] - Vous avez toujours un devis à signer ! - DEVIS N°" . $devis->getNum(),
"mails/task/task-nosigned.twig",
[
'devis' => $devis,
'customer' => $customer,
'sign' => $this->client->getLinkSign($devis->getSignatureId()),
],
$files);
$io->text("Mail envoyé à : $email (Devis " . $devis->getNum() . ", créé il y a $diff jours)");
}
}
}
$io->info('Analyse des devis envoyés non signés...');
// 2. Contrat en attente de signature
$io->title('Traitement des contrats en attente de signature');
// TODO: Logique de récupération et d'envoi
$io->info('Analyse des contrats en attente de signature électronique...');
// 3. Contrat en attente de paiement acompte
$io->title('Traitement des contrats en attente de paiement acompte');
// TODO: Logique de récupération et d'envoi
$io->info('Vérification des acomptes non reçus...');
// 4. Contrat en attente de paiement caution
$io->title('Traitement des contrats en attente de paiement caution');
// TODO: Logique de récupération et d'envoi
$io->info('Vérification des dépôts de garantie manquants...');
// 5. Mail J-3 avant début événement
$io->title('Mail J-3 avant début événement');
// TODO: Logique de récupération et d'envoi
$io->info('Préparation des rappels logistiques (J-3)...');
// 6. Mail J-1 avant début événement
$io->title('Mail J-1 avant début événement');
// TODO: Logique de récupération et d'envoi
$io->info('Envoi des dernières informations (J-1)...');
// 7. Mail après événement à +3j (Satisfaction / Facture finale)
$io->title('Mail après événement à +3j');
// TODO: Logique de récupération et d'envoi
$io->info('Envoi des questionnaires de satisfaction et remerciements...');
$io->success('Toutes les tâches d\'envoi d\'emails ont été traitées.');
return Command::SUCCESS;
}
}

View File

@@ -0,0 +1,38 @@
{% extends 'mails/base.twig' %}
{% block content %}
<mj-section background-color="#ffffff" padding="40px 20px" border-radius="20px">
<mj-column>
{# Affichage des totaux via vos filtres personnalisés #}
<mj-text font-size="16px" color="#333333">
<strong>Total du devis :</strong> {{ datas.devis|totalQuoto }}
</mj-text>
<mj-text font-size="16px" color="#333333">
<strong>Acompte:</strong> {{ datas.devis|totalQuotoAccompte }}
</mj-text>
{# Calcul des arrhes de 25% basé sur le montant total #}
{# On suppose que totalQuoto renvoie un nombre ou est convertible #}
<mj-text font-size="18px" color="#e74c3c" font-weight="bold">
Arrhes à régler (25%) : {{ (datas.devis|totalQuoto * 0.25)|number_format(2, ',', ' ') }}
</mj-text>
<mj-divider border-color="#f4f4f4" />
<mj-text font-size="14px" color="#555555">
Bonjour {{ datas.customer.name }} {{ datas.customer.surname }},
</mj-text>
<mj-text font-size="14px" color="#555555" line-height="20px">
Votre devis n°<strong>{{ datas.devis.num }}</strong> est toujours en attente de signature.
</mj-text>
<mj-button background-color="#3498db" color="white" href="{{ datas.sign }}">
Voir et signer mon devis
</mj-button>
</mj-column>
</mj-section>
{% endblock %}