feat: creation automatique du client apres signature contrat
Webhook contrat form.completed : - Extrait les valeurs DocuSeal (RaisonSociale, SIRET, Adresse, Email, Telephone, Representant) remplies par le client - Cherche un Customer existant par SIRET, puis par email - Si existant : lie au contrat, met a jour SIRET si manquant - Si inexistant : cree User (ROLE_CUSTOMER) + Customer avec toutes les infos, lie au contrat - Envoie l'email de bienvenue avec lien creation mot de passe - Le contrat est automatiquement lie au Customer Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Attestation;
|
||||
use App\Entity\Customer;
|
||||
use App\Entity\Devis;
|
||||
use App\Entity\DocusealEvent;
|
||||
use App\Entity\Echeancier;
|
||||
use App\Service\UserManagementService;
|
||||
use App\Repository\AttestationRepository;
|
||||
use App\Repository\DevisRepository;
|
||||
use App\Service\DocuSealService;
|
||||
@@ -38,6 +40,7 @@ class WebhookDocuSealController extends AbstractController
|
||||
#[Autowire(env: 'DOCUSEAL_WEBHOOKS_SECRET')] string $secret,
|
||||
#[Autowire('%kernel.project_dir%')] string $projectDir,
|
||||
#[Autowire(env: 'STRIPE_SK')] string $stripeSk = '',
|
||||
?UserManagementService $userManagement = null,
|
||||
): Response {
|
||||
$payload = $this->parseAndValidate($request, $secretHeader, $secret);
|
||||
if ($payload instanceof Response) {
|
||||
@@ -65,7 +68,7 @@ class WebhookDocuSealController extends AbstractController
|
||||
|
||||
// Dispatch par type de document
|
||||
if ('contrat' === $docType) {
|
||||
return $this->handleContratEvent($eventType, $data, $metadata, $mailer, $twig, $em, $projectDir);
|
||||
return $this->handleContratEvent($eventType, $data, $metadata, $mailer, $twig, $em, $projectDir, $userManagement);
|
||||
}
|
||||
|
||||
if ('attestation_custom' === $docType) {
|
||||
@@ -199,6 +202,7 @@ class WebhookDocuSealController extends AbstractController
|
||||
Environment $twig,
|
||||
EntityManagerInterface $em,
|
||||
string $projectDir,
|
||||
?UserManagementService $userManagement = null,
|
||||
): JsonResponse {
|
||||
if ('form.completed' !== $eventType) {
|
||||
return new JsonResponse(['status' => 'ok', 'event' => $eventType, 'doc_type' => 'contrat']);
|
||||
@@ -214,6 +218,9 @@ class WebhookDocuSealController extends AbstractController
|
||||
return new JsonResponse(['status' => 'ignored', 'reason' => 'contrat not found']);
|
||||
}
|
||||
|
||||
// Extraire les valeurs remplies par le client dans DocuSeal
|
||||
$submitterValues = $this->extractDocuSealValues($data);
|
||||
|
||||
// Telecharger les PDFs signes
|
||||
$tmpFiles = [];
|
||||
|
||||
@@ -248,6 +255,13 @@ class WebhookDocuSealController extends AbstractController
|
||||
@unlink($f);
|
||||
}
|
||||
|
||||
// Creer automatiquement le client si il n'existe pas
|
||||
$customer = $this->findOrCreateCustomer($contrat, $submitterValues, $em, $userManagement, $mailer, $twig);
|
||||
if (null !== $customer) {
|
||||
$contrat->setCustomer($customer);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
// Pieces jointes
|
||||
$attachments = [];
|
||||
if (null !== $contrat->getPdfSigned()) {
|
||||
@@ -263,7 +277,7 @@ class WebhookDocuSealController extends AbstractController
|
||||
}
|
||||
}
|
||||
|
||||
// Mail client
|
||||
// Mail client : contrat signe
|
||||
try {
|
||||
$mailer->sendEmail(
|
||||
$contrat->getEmail(),
|
||||
@@ -297,7 +311,147 @@ class WebhookDocuSealController extends AbstractController
|
||||
// silencieux
|
||||
}
|
||||
|
||||
return new JsonResponse(['status' => 'ok', 'event' => 'contrat_signed', 'reference' => $contrat->getReference()]);
|
||||
return new JsonResponse(['status' => 'ok', 'event' => 'contrat_signed', 'reference' => $contrat->getReference(), 'customer_created' => null !== $customer]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extrait les valeurs remplies par le client dans DocuSeal (champs texte).
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function extractDocuSealValues(array $data): array
|
||||
{
|
||||
$values = [];
|
||||
|
||||
// DocuSeal envoie les valeurs dans data.values ou data.fields
|
||||
$fields = $data['values'] ?? ($data['fields'] ?? []);
|
||||
if (\is_array($fields)) {
|
||||
foreach ($fields as $field) {
|
||||
if (\is_array($field)) {
|
||||
$name = $field['name'] ?? ($field['field'] ?? '');
|
||||
$value = $field['value'] ?? '';
|
||||
if ('' !== $name && '' !== $value) {
|
||||
$values[$name] = (string) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trouve ou cree un Customer a partir des donnees du contrat et de DocuSeal.
|
||||
*
|
||||
* @param array<string, string> $submitterValues
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function findOrCreateCustomer(
|
||||
\App\Entity\Contrat $contrat,
|
||||
array $submitterValues,
|
||||
EntityManagerInterface $em,
|
||||
?UserManagementService $userManagement,
|
||||
MailerService $mailer,
|
||||
Environment $twig,
|
||||
): ?Customer {
|
||||
if (null !== $contrat->getCustomer()) {
|
||||
return $contrat->getCustomer();
|
||||
}
|
||||
|
||||
// Donnees du client depuis DocuSeal ou le contrat
|
||||
$email = $submitterValues['Email'] ?? $contrat->getEmail();
|
||||
$raisonSociale = $submitterValues['RaisonSociale'] ?? $contrat->getRaisonSociale();
|
||||
$siret = $submitterValues['SIRET'] ?? null;
|
||||
$adresse = $submitterValues['Adresse'] ?? null;
|
||||
$telephone = $submitterValues['Telephone'] ?? null;
|
||||
$representant = $submitterValues['Representant'] ?? null;
|
||||
|
||||
// Chercher un client existant par SIRET
|
||||
if (null !== $siret && '' !== $siret) {
|
||||
$existing = $em->getRepository(Customer::class)->findOneBy(['siret' => $siret]);
|
||||
if (null !== $existing) {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
// Chercher par email
|
||||
$existingByEmail = $em->createQuery(
|
||||
'SELECT c FROM App\Entity\Customer c JOIN c.user u WHERE u.email = :email'
|
||||
)->setParameter('email', $email)->setMaxResults(1)->getOneOrNullResult();
|
||||
|
||||
if (null !== $existingByEmail) {
|
||||
// Mettre a jour le SIRET si manquant
|
||||
if (null !== $siret && null === $existingByEmail->getSiret()) {
|
||||
$existingByEmail->setSiret($siret);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return $existingByEmail;
|
||||
}
|
||||
|
||||
// Creer le client
|
||||
if (null === $userManagement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extraire prenom/nom du representant
|
||||
$firstName = $raisonSociale;
|
||||
$lastName = '';
|
||||
if (null !== $representant && '' !== $representant) {
|
||||
$parts = explode(' ', $representant, 2);
|
||||
$firstName = $parts[0];
|
||||
$lastName = $parts[1] ?? '';
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $userManagement->createBaseUser($email, $firstName, $lastName, ['ROLE_CUSTOMER']);
|
||||
$customer = new Customer($user);
|
||||
$customer->setRaisonSociale($raisonSociale);
|
||||
|
||||
if (null !== $siret && '' !== $siret) {
|
||||
$customer->setSiret($siret);
|
||||
}
|
||||
if (null !== $adresse && '' !== $adresse) {
|
||||
$customer->setAddress($adresse);
|
||||
}
|
||||
if (null !== $telephone && '' !== $telephone) {
|
||||
$customer->setPhone($telephone);
|
||||
}
|
||||
if (null !== $firstName && '' !== $firstName) {
|
||||
$customer->setFirstName($firstName);
|
||||
}
|
||||
if ('' !== $lastName) {
|
||||
$customer->setLastName($lastName);
|
||||
}
|
||||
|
||||
$em->persist($customer);
|
||||
$em->flush();
|
||||
|
||||
// Envoyer l'email de bienvenue avec le lien de creation de mot de passe
|
||||
$setPasswordUrl = $this->generateUrl('app_set_password', [
|
||||
'token' => $user->getTempPassword(),
|
||||
], \Symfony\Component\Routing\Generator\UrlGeneratorInterface::ABSOLUTE_URL);
|
||||
|
||||
$mailer->sendEmail(
|
||||
$email,
|
||||
'Bienvenue - Votre espace client E-Cosplay',
|
||||
$twig->render('emails/client_created.html.twig', [
|
||||
'customer' => $customer,
|
||||
'user' => $user,
|
||||
'setPasswordUrl' => $setPasswordUrl,
|
||||
]),
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
);
|
||||
|
||||
return $customer;
|
||||
} catch (\Throwable) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user