2026-01-16 15:10:27 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Service\Signature;
|
|
|
|
|
|
2026-01-22 15:58:57 +01:00
|
|
|
use App\Entity\Contrats;
|
2026-01-16 15:34:41 +01:00
|
|
|
use App\Entity\CustomerOrder;
|
|
|
|
|
use App\Entity\Devis;
|
|
|
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
|
|
|
use Symfony\Component\HttpFoundation\RequestStack;
|
|
|
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|
|
|
|
use Symfony\Component\HttpKernel\KernelInterface;
|
|
|
|
|
use Vich\UploaderBundle\Storage\StorageInterface;
|
|
|
|
|
|
2026-01-16 15:10:27 +01:00
|
|
|
class Client
|
|
|
|
|
{
|
2026-01-16 15:34:41 +01:00
|
|
|
private \Docuseal\Api $docuseal;
|
|
|
|
|
private string $baseUrl;
|
|
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
|
private readonly RequestStack $requestStack,
|
|
|
|
|
private readonly UrlGeneratorInterface $urlGenerator,
|
|
|
|
|
private readonly EntityManagerInterface $entityManager,
|
|
|
|
|
private readonly KernelInterface $kernel,
|
|
|
|
|
private readonly StorageInterface $storage,
|
|
|
|
|
) {
|
|
|
|
|
// Configuration via les variables d'environnement
|
|
|
|
|
$key = $_ENV['ESYSIGN_APIEY'] ?? '';
|
2026-01-19 18:22:53 +01:00
|
|
|
$this->baseUrl = $_ENV['SIGN_URL'];
|
2026-01-16 15:34:41 +01:00
|
|
|
|
|
|
|
|
// L'URL API est le point d'entrée pour le SDK Docuseal
|
2026-01-19 18:22:53 +01:00
|
|
|
$apiUrl = rtrim("https://signature.esy-web.dev", '/') . '/api';
|
2026-01-16 15:34:41 +01:00
|
|
|
$this->docuseal = new \Docuseal\Api($key, $apiUrl);
|
2026-01-19 19:40:27 +01:00
|
|
|
$this->logo = $kernel->getProjectDir()."/public/provider/images/favicon.png";
|
2026-01-16 15:34:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Crée une soumission pour un Devis
|
|
|
|
|
*/
|
|
|
|
|
public function createSubmissionDevis(Devis $devis): string
|
|
|
|
|
{
|
|
|
|
|
// Si aucune signature n'est lancée, on initialise la soumission
|
|
|
|
|
if ($devis->getSignatureId() === null) {
|
|
|
|
|
|
|
|
|
|
// URL où le client sera redirigé après signature
|
|
|
|
|
$completedRedirectUrl = $this->baseUrl . $this->urlGenerator->generate(
|
|
|
|
|
'app_sign_complete',
|
|
|
|
|
['type' => 'devis', 'id' => $devis->getId()]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Récupération du fichier via VichUploader (champ devisDocuSealFile)
|
|
|
|
|
$relativeFileUrl = $this->storage->resolveUri($devis, 'devisDocuSealFile');
|
|
|
|
|
$fileUrl = $this->baseUrl . $relativeFileUrl;
|
|
|
|
|
|
|
|
|
|
$submission = $this->docuseal->createSubmissionFromPdf([
|
|
|
|
|
'name' => 'Devis N°' . $devis->getNum(), // Correction : getNum()
|
|
|
|
|
'completed_redirect_url' => $completedRedirectUrl,
|
|
|
|
|
'send_email' => true,
|
|
|
|
|
'documents' => [
|
|
|
|
|
[
|
|
|
|
|
'name' => 'devis_' . $devis->getNum() . '.pdf', // Correction : getNum()
|
|
|
|
|
'file' => $fileUrl,
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'submitters' => [
|
2026-01-19 18:22:53 +01:00
|
|
|
[
|
|
|
|
|
'role' => 'Ludikevent',
|
|
|
|
|
'email' => 'contact@ludikevent.fr',
|
|
|
|
|
'completed' => true,
|
2026-01-19 19:40:27 +01:00
|
|
|
'fields' => [
|
|
|
|
|
['name'=>'Sign','default_value'=>$this->logoBase64()]
|
|
|
|
|
]
|
2026-01-19 18:22:53 +01:00
|
|
|
],
|
2026-01-16 15:34:41 +01:00
|
|
|
[
|
|
|
|
|
'role' => 'Client',
|
|
|
|
|
'email' => $devis->getCustomer()->getEmail(),
|
|
|
|
|
'name' => $devis->getCustomer()->getSurname() . ' ' . $devis->getCustomer()->getName(),
|
2026-01-19 19:40:27 +01:00
|
|
|
'fields' => [
|
|
|
|
|
['name'=>'cgv','default_value'=>true],
|
|
|
|
|
['name'=>'assurance','default_value'=>true],
|
|
|
|
|
['name'=>'securite','default_value'=>true],
|
|
|
|
|
['name'=>'arrhes','default_value'=>true],
|
|
|
|
|
],
|
2026-01-16 15:34:41 +01:00
|
|
|
'metadata' => [
|
|
|
|
|
'id' => $devis->getId(),
|
|
|
|
|
'type' => 'devis'
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
]);
|
|
|
|
|
|
2026-01-19 19:40:27 +01:00
|
|
|
|
2026-01-16 15:34:41 +01:00
|
|
|
// Stockage de l'ID submitter de Docuseal dans ton entité
|
2026-01-19 18:22:53 +01:00
|
|
|
$devis->setSignatureId($submission['submitters'][1]['id']);
|
2026-01-19 19:40:27 +01:00
|
|
|
|
2026-01-16 15:34:41 +01:00
|
|
|
$this->entityManager->flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->getLinkSign($devis->getSignatureId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Retourne l'URL de signature publique pour le client
|
|
|
|
|
*/
|
|
|
|
|
public function getLinkSign(?string $submitterId): string
|
|
|
|
|
{
|
|
|
|
|
if (!$submitterId) {
|
|
|
|
|
throw new \InvalidArgumentException("ID Submitter absent.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$submissionData = $this->docuseal->getSubmitter($submitterId);
|
|
|
|
|
|
2026-01-19 19:40:27 +01:00
|
|
|
return rtrim("https://signature.esy-web.dev", '/') . "/s/" . $submissionData['slug'];
|
2026-01-16 15:34:41 +01:00
|
|
|
}
|
2026-01-16 15:10:27 +01:00
|
|
|
|
2026-01-16 15:34:41 +01:00
|
|
|
/**
|
|
|
|
|
* Récupère l'état d'un signataire (pour vérifier si c'est signé)
|
|
|
|
|
*/
|
|
|
|
|
public function getSubmiter(?string $submitterId): array
|
2026-01-16 15:10:27 +01:00
|
|
|
{
|
2026-01-16 15:34:41 +01:00
|
|
|
return $this->docuseal->getSubmitter($submitterId);
|
2026-01-16 15:10:27 +01:00
|
|
|
}
|
2026-01-19 11:20:16 +01:00
|
|
|
|
|
|
|
|
public function status(): bool
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
$this->docuseal->listTemplates();
|
|
|
|
|
return true;
|
|
|
|
|
} catch (\Throwable $e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-19 19:40:27 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Récupère le fichier logo et le convertit en chaîne Base64
|
|
|
|
|
* Utile pour l'intégration directe dans certains flux HTML ou API
|
|
|
|
|
*/
|
|
|
|
|
private function logoBase64(): ?string
|
|
|
|
|
{
|
|
|
|
|
// Vérifie si le fichier existe pour éviter une erreur
|
|
|
|
|
if (!file_exists($this->logo)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lecture du contenu du fichier
|
|
|
|
|
$binaryData = file_get_contents($this->logo);
|
|
|
|
|
|
|
|
|
|
// Récupération de l'extension pour le type MIME (png, jpg, etc.)
|
|
|
|
|
$extension = pathinfo($this->logo, PATHINFO_EXTENSION);
|
|
|
|
|
|
|
|
|
|
// Encodage en Base64
|
|
|
|
|
$base64 = base64_encode($binaryData);
|
|
|
|
|
|
|
|
|
|
// Retourne le format complet data:image/...
|
|
|
|
|
return 'data:image/' . $extension . ';base64,' . $base64;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getSubmition(mixed $submission_id)
|
|
|
|
|
{
|
|
|
|
|
return $this->docuseal->getSubmission($submission_id);
|
|
|
|
|
}
|
2026-01-22 11:05:29 +01:00
|
|
|
|
|
|
|
|
public function cancelSign(?string $getSignatureId)
|
|
|
|
|
{
|
|
|
|
|
$result = $this->docuseal->getSubmitter($getSignatureId);
|
|
|
|
|
$this->docuseal->archiveSubmission($result['submission_id']);
|
|
|
|
|
}
|
2026-01-22 15:58:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
public function createSubmissionContrat(Contrats $devis): string
|
|
|
|
|
{
|
|
|
|
|
// Si aucune signature n'est lancée, on initialise la soumission
|
|
|
|
|
if ($devis->getSignID() === null) {
|
|
|
|
|
|
|
|
|
|
// URL où le client sera redirigé après signature
|
|
|
|
|
$completedRedirectUrl = $this->baseUrl . $this->urlGenerator->generate(
|
|
|
|
|
'app_sign_complete',
|
|
|
|
|
['type' => 'contrat', 'id' => $devis->getId()]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Récupération du fichier via VichUploader (champ devisDocuSealFile)
|
|
|
|
|
$relativeFileUrl = $this->storage->resolveUri($devis, 'devisDocuSealFile');
|
|
|
|
|
$fileUrl = $this->baseUrl . $relativeFileUrl;
|
|
|
|
|
|
|
|
|
|
$submission = $this->docuseal->createSubmissionFromPdf([
|
|
|
|
|
'name' => 'Contrat N°' . $devis->getNumReservation(), // Correction : getNum()
|
|
|
|
|
'completed_redirect_url' => $completedRedirectUrl,
|
|
|
|
|
'send_email' => true,
|
|
|
|
|
'documents' => [
|
|
|
|
|
[
|
|
|
|
|
'name' => 'contrat_' . $devis->getNumReservation() . '.pdf', // Correction : getNum()
|
|
|
|
|
'file' => $fileUrl,
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
'submitters' => [
|
|
|
|
|
[
|
|
|
|
|
'role' => 'Ludikevent',
|
|
|
|
|
'email' => 'contact@ludikevent.fr',
|
|
|
|
|
'completed' => true,
|
|
|
|
|
'fields' => [
|
|
|
|
|
['name'=>'Sign','default_value'=>$this->logoBase64()]
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
'role' => 'Client',
|
|
|
|
|
'email' => $devis->getCustomer()->getEmail(),
|
|
|
|
|
'name' => $devis->getCustomer()->getSurname() . ' ' . $devis->getCustomer()->getName(),
|
|
|
|
|
'fields' => [
|
|
|
|
|
['name'=>'cgv','default_value'=>true],
|
|
|
|
|
['name'=>'assurance','default_value'=>true],
|
|
|
|
|
['name'=>'securite','default_value'=>true],
|
|
|
|
|
['name'=>'arrhes','default_value'=>true],
|
|
|
|
|
],
|
|
|
|
|
'metadata' => [
|
|
|
|
|
'id' => $devis->getId(),
|
|
|
|
|
'type' => 'contrat'
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
],
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Stockage de l'ID submitter de Docuseal dans ton entité
|
|
|
|
|
$devis->setSignID($submission['submitters'][1]['id']);
|
|
|
|
|
|
|
|
|
|
$this->entityManager->flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->getLinkSign($devis->getSignID());
|
|
|
|
|
}
|
2026-01-22 20:15:21 +01:00
|
|
|
|
|
|
|
|
public function eventSign(object $contrat): array
|
|
|
|
|
{
|
|
|
|
|
$events = [];
|
|
|
|
|
if ($contrat instanceof Contrats) {
|
|
|
|
|
$signId = $contrat->getSignID();
|
|
|
|
|
if (!$signId) return []; // Sécurité si pas d'ID de signature
|
|
|
|
|
|
|
|
|
|
$submiter = $this->getSubmiter($signId);
|
|
|
|
|
|
|
|
|
|
// Vérifier si submission_events existe pour éviter une erreur undefined index
|
|
|
|
|
if (!isset($submiter['submission_events'])) return [];
|
|
|
|
|
|
|
|
|
|
foreach ($submiter['submission_events'] as $event) {
|
|
|
|
|
$label = match($event['event_type']) {
|
|
|
|
|
'view_form' => "Contrat consulté",
|
|
|
|
|
'start_form' => "Début de procédure",
|
|
|
|
|
'complete_form' => "Contrat signé",
|
|
|
|
|
'decline_form' => "Signature refusée",
|
|
|
|
|
default => null
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if ($label) {
|
|
|
|
|
$events[] = [
|
|
|
|
|
'event_type' => $label,
|
|
|
|
|
'event_timestamp' => new \DateTimeImmutable($event['event_timestamp'])
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $events;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function signedData(Contrats $contrat) : string
|
|
|
|
|
{
|
|
|
|
|
$signId = $contrat->getSignID();
|
|
|
|
|
if (!$signId) return []; // Sécurité si pas d'ID de signature
|
|
|
|
|
|
|
|
|
|
$submiter = $this->getSubmiter($signId);
|
|
|
|
|
return $submiter['uuid']; // numéro de signature;
|
|
|
|
|
}
|
2026-01-16 15:10:27 +01:00
|
|
|
}
|