add webhooks for refused signature devis
This commit is contained in:
6
.env
6
.env
@@ -83,9 +83,9 @@ STRIPE_PK=pk_test_51SUA22173W4aeFB1nO6oFfDZ12HOTffDKtCshhZ8rkUg6kUO2ZaQC0tK72rhE
|
||||
STRIPE_SK=sk_test_51SUA22173W4aeFB16EB2LxGI0hNvNJzFshDI98zRImWBIhSfzqOGAz5TlPxSpUWbj3x4COm6kmSsaal9FpQR1A7M0022DvjbbR
|
||||
STRIPE_WEBHOOKS_SECRET=
|
||||
|
||||
SIGN_URL=https://eb44-82-67-166-187.ngrok-free.app
|
||||
STRIPE_BASEURL=https://eb44-82-67-166-187.ngrok-free.app
|
||||
CONTRAT_BASEURL=https://eb44-82-67-166-187.ngrok-free.app
|
||||
SIGN_URL=https://00ca-212-114-31-239.ngrok-free.app
|
||||
STRIPE_BASEURL=https://00ca-212-114-31-239.ngrok-free.app
|
||||
CONTRAT_BASEURL=https://00ca-212-114-31-239.ngrok-free.app
|
||||
|
||||
MINIO_S3_URL=
|
||||
MINIO_S3_CLIENT_ID=
|
||||
|
||||
@@ -51,9 +51,15 @@ class HomeController extends AbstractController
|
||||
$stats = $this->getUmamiStats();
|
||||
$updates = $this->getSystemUpdates();
|
||||
|
||||
$z = [];
|
||||
foreach ($this->devisRepository->waitSign() as $item) {
|
||||
if(!str_contains($item['state'],'refused')) {
|
||||
$z[] = $item;
|
||||
}
|
||||
}
|
||||
return $this->render('dashboard/home.twig', [
|
||||
'product' => $this->productRepository->count([]),
|
||||
'devis_wait_sign' => $this->devisRepository->waitSign(),
|
||||
'devis_wait_sign' => count($z),
|
||||
'customers' => $this->customerRepository->count([]),
|
||||
'nbVisitor' => $stats['visitors'],
|
||||
'nbView' => $stats['views'],
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Contrats;
|
||||
use App\Entity\ContratsPayments;
|
||||
use App\Entity\Devis;
|
||||
use App\Entity\Product;
|
||||
use App\Entity\ProductReserve;
|
||||
use App\Kernel;
|
||||
use App\Logger\AppLogger;
|
||||
use App\Repository\ContratsRepository;
|
||||
use App\Repository\DevisRepository;
|
||||
use App\Repository\ProductRepository;
|
||||
use App\Service\Mailer\Mailer;
|
||||
use App\Service\Pdf\PlPdf;
|
||||
@@ -159,4 +163,77 @@ class Webhooks extends AbstractController
|
||||
|
||||
return new Response('Invalid Signature', 400);
|
||||
}
|
||||
#[Route(path: '/webhooks/docuseal', name: 'webhooks_docuseal', options: ['sitemap' => false], methods: ['POST'])]
|
||||
public function docuseal(
|
||||
Mailer $mailer,
|
||||
EntityManagerInterface $entityManager,
|
||||
ContratsRepository $contratsRepository,
|
||||
DevisRepository $devisRepository,
|
||||
Client $client,
|
||||
Request $request,
|
||||
AppLogger $appLogger
|
||||
): Response {
|
||||
$contentRaw = $request->getContent();
|
||||
$headers = $request->headers;
|
||||
|
||||
// Vérification de sécurité (Header personnalisé)
|
||||
if ($headers->has('X-Src') && $headers->get('X-Src') === "Ludik_Sign") {
|
||||
$payload = json_decode($contentRaw);
|
||||
|
||||
// Validation de la structure du payload
|
||||
if (!isset($payload->data) || !isset($payload->data->metadata)) {
|
||||
return new Response("Invalid payload structure", 400);
|
||||
}
|
||||
|
||||
$content = $payload->data;
|
||||
$metadata = $content->metadata;
|
||||
$status = $content->status ?? '';
|
||||
|
||||
// --- TRAITEMENT DES DEVIS ---
|
||||
if (isset($metadata->type) && $metadata->type === "devis" && isset($metadata->id)) {
|
||||
$devis = $devisRepository->find($metadata->id);
|
||||
|
||||
if ($devis instanceof Devis) {
|
||||
|
||||
// Cas 1 : Signature refusée par le client
|
||||
if ($status === "declined") {
|
||||
$reason = $content->decline_reason ?? 'Aucune raison spécifiée';
|
||||
|
||||
// Mise à jour du statut
|
||||
$devis->setState("refused|" . $reason);
|
||||
$entityManager->persist($devis);
|
||||
$entityManager->flush();
|
||||
|
||||
// Notification au client (Confirmation de prise en compte du refus)
|
||||
$customer = $devis->getCustomer();
|
||||
if ($customer) {
|
||||
$mailer->send(
|
||||
$customer->getEmail(),
|
||||
$customer->getName() . " " . $customer->getSurname(),
|
||||
"[Intranet Ludikevent] - Le client a refusé la signature du devis n°" . $devis->getNum(),
|
||||
"mails/customer/devis_refuses.twig",
|
||||
[
|
||||
'devis' => $devis,
|
||||
'raison' => $reason,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
$appLogger->record('WEBHOOK', sprintf("Devis %s refusé par le client. Raison: %s", $devis->getNum(), $reason));
|
||||
|
||||
return new Response("ok-devis-declined");
|
||||
}
|
||||
|
||||
// Cas 2 : Signature complétée (Optionnel - à implémenter selon vos besoins)
|
||||
if ($status === "completed") {
|
||||
// Logique de succès (ex: passage en contrat)
|
||||
$appLogger->record('WEBHOOK', sprintf("Devis %s signé avec succès.", $devis->getNum()));
|
||||
return new Response("ok-devis-completed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Response("ignored");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,12 @@ class DevisRepository extends ServiceEntityRepository
|
||||
// }
|
||||
public function waitSign()
|
||||
{
|
||||
return count( $this->createQueryBuilder('d')
|
||||
return $this->createQueryBuilder('d')
|
||||
->andWhere('d.state != :status')
|
||||
->andWhere('d.state != :status2')
|
||||
->setParameter('status','signed')
|
||||
->setParameter('status2','cancel')
|
||||
->getQuery()->getArrayResult());
|
||||
->getQuery()->getArrayResult();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
45
templates/mails/customer/devis_refuses.twig
Normal file
45
templates/mails/customer/devis_refuses.twig
Normal file
@@ -0,0 +1,45 @@
|
||||
{% extends 'mails/base.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<mj-section background-color="#ffffff" padding-top="20px">
|
||||
<mj-column width="100%">
|
||||
<mj-text font-size="14px" color="#475569" font-family="Arial, sans-serif" line-height="1.6">
|
||||
Le devis n°<strong>{{ datas.devis.num }}</strong> a été <span style="color: #ef4444; font-weight: bold;">refusé</span> par le client <strong>{{ datas.devis.customer.name }} {{ datas.devis.customer.surname }}</strong>.
|
||||
</mj-text>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
||||
<mj-section background-color="#ffffff" padding="0px">
|
||||
<mj-column width="90%" background-color="#fef2f2" border="1px solid #fecaca" border-radius="8px">
|
||||
<mj-table font-family="Arial, sans-serif" font-size="14px" padding="15px">
|
||||
<tr>
|
||||
<td style="padding: 5px 0; color: #64748b;">N° Devis :</td>
|
||||
<td style="padding: 5px 0; text-align: right; font-weight: bold;">{{ datas.devis.num }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 5px 0; color: #64748b;">Client :</td>
|
||||
<td style="padding: 5px 0; text-align: right;">{{ datas.devis.customer.name }} {{ datas.devis.customer.surname }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 5px 0; color: #64748b;">Raison du refus :</td>
|
||||
<td style="padding: 5px 0; text-align: right; font-weight: bold; color: #ef4444;">{{ datas.raison }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 5px 0; color: #64748b;">Date :</td>
|
||||
<td style="padding: 5px 0; text-align: right;">{{ "now"|date("d/m/Y à H:i") }}</td>
|
||||
</tr>
|
||||
</mj-table>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
|
||||
<mj-section background-color="#ffffff">
|
||||
<mj-column width="100%">
|
||||
<mj-text font-size="13px" color="#64748b" font-family="Arial, sans-serif" font-style="italic" align="center">
|
||||
Ce devis est désormais marqué comme "Refusé" dans le CRM. Une relance commerciale est peut-être nécessaire.
|
||||
</mj-text>
|
||||
<mj-button background-color="#1e293b" color="white" font-size="14px" font-weight="bold" href="https://intranet.ludikevent.fr/crm/devis" border-radius="6px" padding-top="20px">
|
||||
GÉRER LE DEVIS
|
||||
</mj-button>
|
||||
</mj-column>
|
||||
</mj-section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user