Files
crm_ecosplay/src/Controller/Admin/AttestationCustomController.php
Serreau Jovann 0e1f249cc3 fix: remplacement emails - contact@ devient client@, monitor@ devient notification@
- contact@e-cosplay.fr remplace par client@e-cosplay.fr dans 87 fichiers
  (PDFs, templates, emails, controllers, DocuSeal submitters)
- monitor@e-cosplay.fr remplace par notification@e-cosplay.fr dans 4 fichiers
  (webhooks DocuSeal, commandes DNS/NDD, controller echeancier)
- Ajout lien "En savoir plus sur notre association" vers www.e-cosplay.fr
  sur la page migration SITECONSEIL

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 15:11:08 +02:00

209 lines
8.2 KiB
PHP

<?php
namespace App\Controller\Admin;
use App\Entity\AttestationCustom;
use App\Service\DocuSealService;
use App\Service\Pdf\AttestationCustomPdf;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Attribute\IsGranted;
#[Route('/admin/attestations', name: 'app_admin_attestation_custom_')]
#[IsGranted('ROLE_ROOT')]
class AttestationCustomController extends AbstractController
{
public function __construct(
private EntityManagerInterface $em,
) {
}
#[Route('', name: 'index')]
public function index(): Response
{
$attestations = $this->em->getRepository(AttestationCustom::class)->findBy([], ['createdAt' => 'DESC']);
return $this->render('admin/attestation_custom/index.html.twig', [
'attestations' => $attestations,
]);
}
#[Route('/create', name: 'create', methods: ['POST'])]
public function create(Request $request, KernelInterface $kernel, UrlGeneratorInterface $urlGenerator): Response
{
$title = trim($request->request->getString('title'));
$itemsRaw = $request->request->all('items');
// Filtrer les items vides
$items = array_values(array_filter(array_map('trim', $itemsRaw), fn (string $v) => '' !== $v));
if ('' === $title || [] === $items) {
$this->addFlash('error', 'Le titre et au moins un element sont requis.');
return $this->redirectToRoute('app_admin_attestation_custom_index');
}
$attestation = new AttestationCustom($title, $items);
$this->em->persist($attestation);
$this->em->flush();
// Generer le PDF
$this->generatePdfForAttestation($attestation, $kernel, $urlGenerator);
$this->addFlash('success', 'Attestation '.$attestation->getReference().' creee.');
return $this->redirectToRoute('app_admin_attestation_custom_show', ['id' => $attestation->getId()]);
}
#[Route('/{id}', name: 'show', requirements: ['id' => '\d+'])]
public function show(int $id): Response
{
$attestation = $this->em->getRepository(AttestationCustom::class)->find($id);
if (null === $attestation) {
throw $this->createNotFoundException('Attestation introuvable');
}
return $this->render('admin/attestation_custom/show.html.twig', [
'attestation' => $attestation,
]);
}
#[Route('/{id}/regenerate-pdf', name: 'regenerate_pdf', requirements: ['id' => '\d+'], methods: ['POST'])]
public function regeneratePdf(int $id, KernelInterface $kernel, UrlGeneratorInterface $urlGenerator): Response
{
$attestation = $this->em->getRepository(AttestationCustom::class)->find($id);
if (null === $attestation) {
throw $this->createNotFoundException('Attestation introuvable');
}
$this->generatePdfForAttestation($attestation, $kernel, $urlGenerator);
$this->addFlash('success', 'PDF regenere.');
return $this->redirectToRoute('app_admin_attestation_custom_show', ['id' => $id]);
}
/**
* Envoie le PDF a DocuSeal pour signature manuelle et redirige vers DocuSeal.
*/
#[Route('/{id}/sign', name: 'sign', requirements: ['id' => '\d+'], methods: ['POST'])]
public function sign(
int $id,
DocuSealService $docuSeal,
#[\Symfony\Component\DependencyInjection\Attribute\Autowire('%kernel.project_dir%')] string $projectDir,
#[\Symfony\Component\DependencyInjection\Attribute\Autowire(env: 'DOCUSEAL_URL')] string $docuSealUrl,
\Symfony\Component\Routing\Generator\UrlGeneratorInterface $urlGenerator,
): Response {
$attestation = $this->em->getRepository(AttestationCustom::class)->find($id);
if (null === $attestation) {
throw $this->createNotFoundException('Attestation introuvable');
}
if (null === $attestation->getPdfUnsigned()) {
$this->addFlash('error', 'Le PDF doit etre genere avant la signature.');
return $this->redirectToRoute('app_admin_attestation_custom_show', ['id' => $id]);
}
$pdfPath = $projectDir.'/public/uploads/attestations/'.$attestation->getPdfUnsigned();
if (!file_exists($pdfPath)) {
$this->addFlash('error', 'Fichier PDF introuvable.');
return $this->redirectToRoute('app_admin_attestation_custom_show', ['id' => $id]);
}
/** @var \App\Entity\User $user */
$user = $this->getUser();
$redirectUrl = $urlGenerator->generate('app_admin_attestation_custom_show', [
'id' => $attestation->getId(),
], \Symfony\Component\Routing\Generator\UrlGeneratorInterface::ABSOLUTE_URL);
// @codeCoverageIgnoreStart
try {
$pdfBase64 = base64_encode(file_get_contents($pdfPath));
$result = $docuSeal->getApi()->createSubmissionFromPdf([
'name' => 'Attestation '.$attestation->getReference().' - '.$attestation->getTitle(),
'send_email' => false,
'flatten' => true,
'documents' => [[
'name' => 'attestation-'.$attestation->getReference().'.pdf',
'file' => 'data:application/pdf;base64,'.$pdfBase64,
]],
'submitters' => [[
'email' => 'client@e-cosplay.fr',
'name' => 'Association E-Cosplay',
'role' => 'First Party',
'send_email' => false,
'completed_redirect_url' => $redirectUrl,
'metadata' => [
'doc_type' => 'attestation_custom',
'attestation_custom_id' => $attestation->getId(),
],
]],
]);
// DocuSeal retourne soit {submitters: [{id}]} soit [{id}]
$submitterId = $result['submitters'][0]['id']
?? ($result[0]['id'] ?? ($result['id'] ?? null));
if (null !== $submitterId) {
$slug = $docuSeal->getSubmitterSlug((int) $submitterId);
if (null !== $slug) {
return $this->redirect(rtrim($docuSealUrl, '/').'/s/'.$slug);
}
}
$this->addFlash('error', 'Erreur DocuSeal : impossible de recuperer le lien de signature. Reponse: '.json_encode($result));
} catch (\Throwable $e) {
$this->addFlash('error', 'Erreur DocuSeal : '.$e->getMessage());
}
// @codeCoverageIgnoreEnd
return $this->redirectToRoute('app_admin_attestation_custom_show', ['id' => $id]);
}
#[Route('/{id}/delete', name: 'delete', requirements: ['id' => '\d+'], methods: ['POST'])]
public function delete(int $id): Response
{
$attestation = $this->em->getRepository(AttestationCustom::class)->find($id);
if (null === $attestation) {
throw $this->createNotFoundException('Attestation introuvable');
}
$this->em->remove($attestation);
$this->em->flush();
$this->addFlash('success', 'Attestation supprimee.');
return $this->redirectToRoute('app_admin_attestation_custom_index');
}
private function generatePdfForAttestation(AttestationCustom $attestation, KernelInterface $kernel, UrlGeneratorInterface $urlGenerator): void
{
$pdf = new AttestationCustomPdf($kernel, $attestation, $urlGenerator);
$pdf->generate();
$tmpPath = tempnam(sys_get_temp_dir(), 'att_custom_').'.pdf';
$pdf->Output('F', $tmpPath);
$attestation->setPdfUnsignedFile(new UploadedFile(
$tmpPath,
'attestation-'.$attestation->getReference().'.pdf',
'application/pdf',
null,
true,
));
$attestation->setUpdatedAt(new \DateTimeImmutable());
$this->em->flush();
@unlink($tmpPath);
}
}