feat: entite Contrat + CRUD admin + formulaire creation
Entite Contrat: - email, raisonSociale, type (migration_siteconseil), state (draft/send/signed/cancelled) - submissionId, submitterCompanyId, submitterCustomerId (DocuSeal) - 3 PDFs Vich (unsigned, signed, audit) - customer (ManyToOne nullable, lie apres signature) - Reference CTR_XXXXX, getTypeLabel() Controller admin /admin/contrats: - index: liste des contrats avec statut - create: email + raison sociale + type de contrat - show: detail avec infos client, contrat, PDFs, actions - cancel: annulation Templates: - index: tableau + modal creation (email, raison sociale, select type) - show: 2 blocs (client + contrat), boutons PDF/signe/audit/annuler Vich mappings: contrat_pdf, contrat_signed_pdf, contrat_audit_pdf Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,18 @@ vich_uploader:
|
||||
uri_prefix: /uploads/eflex/audit
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/eflex/audit'
|
||||
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
contrat_pdf:
|
||||
uri_prefix: /uploads/contrats
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/contrats'
|
||||
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
contrat_signed_pdf:
|
||||
uri_prefix: /uploads/contrats/signed
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/contrats/signed'
|
||||
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
contrat_audit_pdf:
|
||||
uri_prefix: /uploads/contrats/audit
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/contrats/audit'
|
||||
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
|
||||
attestation_custom_pdf:
|
||||
uri_prefix: /uploads/attestations
|
||||
upload_destination: '%kernel.project_dir%/public/uploads/attestations'
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Entity\Contrat;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
@@ -11,9 +14,75 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
#[IsGranted('ROLE_EMPLOYE')]
|
||||
class ContratController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private EntityManagerInterface $em,
|
||||
) {
|
||||
}
|
||||
|
||||
#[Route('', name: 'index')]
|
||||
public function index(): Response
|
||||
{
|
||||
return $this->render('admin/contrats/index.html.twig');
|
||||
$contrats = $this->em->getRepository(Contrat::class)->findBy([], ['createdAt' => 'DESC']);
|
||||
|
||||
return $this->render('admin/contrats/index.html.twig', [
|
||||
'contrats' => $contrats,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/create', name: 'create', methods: ['POST'])]
|
||||
public function create(Request $request): Response
|
||||
{
|
||||
$email = trim($request->request->getString('email'));
|
||||
$raisonSociale = trim($request->request->getString('raisonSociale'));
|
||||
$type = $request->request->getString('type');
|
||||
|
||||
if ('' === $email || '' === $raisonSociale || '' === $type) {
|
||||
$this->addFlash('error', 'Tous les champs sont requis.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_contrats_index');
|
||||
}
|
||||
|
||||
if (!isset(Contrat::TYPE_LABELS[$type])) {
|
||||
$this->addFlash('error', 'Type de contrat invalide.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_contrats_index');
|
||||
}
|
||||
|
||||
$contrat = new Contrat($email, $raisonSociale, $type);
|
||||
$this->em->persist($contrat);
|
||||
$this->em->flush();
|
||||
|
||||
$this->addFlash('success', 'Contrat '.$contrat->getReference().' cree.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_contrats_show', ['id' => $contrat->getId()]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'show', requirements: ['id' => '\d+'])]
|
||||
public function show(int $id): Response
|
||||
{
|
||||
$contrat = $this->em->getRepository(Contrat::class)->find($id);
|
||||
if (null === $contrat) {
|
||||
throw $this->createNotFoundException('Contrat introuvable');
|
||||
}
|
||||
|
||||
return $this->render('admin/contrats/show.html.twig', [
|
||||
'contrat' => $contrat,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}/cancel', name: 'cancel', requirements: ['id' => '\d+'], methods: ['POST'])]
|
||||
public function cancel(int $id): Response
|
||||
{
|
||||
$contrat = $this->em->getRepository(Contrat::class)->find($id);
|
||||
if (null === $contrat) {
|
||||
throw $this->createNotFoundException('Contrat introuvable');
|
||||
}
|
||||
|
||||
$contrat->setState(Contrat::STATE_CANCELLED);
|
||||
$this->em->flush();
|
||||
|
||||
$this->addFlash('success', 'Contrat annule.');
|
||||
|
||||
return $this->redirectToRoute('app_admin_contrats_index');
|
||||
}
|
||||
}
|
||||
|
||||
312
src/Entity/Contrat.php
Normal file
312
src/Entity/Contrat.php
Normal file
@@ -0,0 +1,312 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Vich\UploaderBundle\Mapping\Attribute as Vich;
|
||||
|
||||
#[ORM\Entity]
|
||||
#[Vich\Uploadable]
|
||||
class Contrat
|
||||
{
|
||||
public const STATE_DRAFT = 'draft';
|
||||
public const STATE_SEND = 'send';
|
||||
public const STATE_SIGNED = 'signed';
|
||||
public const STATE_CANCELLED = 'cancelled';
|
||||
|
||||
public const TYPE_MIGRATION_SITECONSEIL = 'migration_siteconseil';
|
||||
|
||||
public const TYPE_LABELS = [
|
||||
self::TYPE_MIGRATION_SITECONSEIL => 'Contrat Migration SARL SITECONSEIL',
|
||||
];
|
||||
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private string $email;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private string $raisonSociale;
|
||||
|
||||
#[ORM\Column(length: 50)]
|
||||
private string $type;
|
||||
|
||||
#[ORM\Column(length: 20, options: ['default' => 'draft'])]
|
||||
private string $state = self::STATE_DRAFT;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?string $submissionId = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $submitterCompanyId = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?int $submitterCustomerId = null;
|
||||
|
||||
// ── PDF Unsigned ──
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $pdfUnsigned = null;
|
||||
|
||||
#[Vich\UploadableField(mapping: 'contrat_pdf', fileNameProperty: 'pdfUnsigned')]
|
||||
private ?File $pdfUnsignedFile = null;
|
||||
|
||||
// ── PDF Signed ──
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $pdfSigned = null;
|
||||
|
||||
#[Vich\UploadableField(mapping: 'contrat_signed_pdf', fileNameProperty: 'pdfSigned')]
|
||||
private ?File $pdfSignedFile = null;
|
||||
|
||||
// ── PDF Audit ──
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $pdfAudit = null;
|
||||
|
||||
#[Vich\UploadableField(mapping: 'contrat_audit_pdf', fileNameProperty: 'pdfAudit')]
|
||||
private ?File $pdfAuditFile = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Customer::class)]
|
||||
#[ORM\JoinColumn(nullable: true, onDelete: 'SET NULL')]
|
||||
private ?Customer $customer = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private \DateTimeImmutable $createdAt;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $signedAt = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $updatedAt = null;
|
||||
|
||||
public function __construct(string $email, string $raisonSociale, string $type)
|
||||
{
|
||||
$this->email = $email;
|
||||
$this->raisonSociale = $raisonSociale;
|
||||
$this->type = $type;
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getReference(): string
|
||||
{
|
||||
return 'CTR_'.str_pad((string) ($this->id ?? 0), 5, '0', \STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
public function getEmail(): string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function setEmail(string $email): static
|
||||
{
|
||||
$this->email = $email;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRaisonSociale(): string
|
||||
{
|
||||
return $this->raisonSociale;
|
||||
}
|
||||
|
||||
public function setRaisonSociale(string $raisonSociale): static
|
||||
{
|
||||
$this->raisonSociale = $raisonSociale;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function getTypeLabel(): string
|
||||
{
|
||||
return self::TYPE_LABELS[$this->type] ?? $this->type;
|
||||
}
|
||||
|
||||
public function setType(string $type): static
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getState(): string
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function setState(string $state): static
|
||||
{
|
||||
$this->state = $state;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubmissionId(): ?string
|
||||
{
|
||||
return $this->submissionId;
|
||||
}
|
||||
|
||||
public function setSubmissionId(?string $submissionId): static
|
||||
{
|
||||
$this->submissionId = $submissionId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubmitterCompanyId(): ?int
|
||||
{
|
||||
return $this->submitterCompanyId;
|
||||
}
|
||||
|
||||
public function setSubmitterCompanyId(?int $submitterCompanyId): static
|
||||
{
|
||||
$this->submitterCompanyId = $submitterCompanyId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubmitterCustomerId(): ?int
|
||||
{
|
||||
return $this->submitterCustomerId;
|
||||
}
|
||||
|
||||
public function setSubmitterCustomerId(?int $submitterCustomerId): static
|
||||
{
|
||||
$this->submitterCustomerId = $submitterCustomerId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfUnsigned(): ?string
|
||||
{
|
||||
return $this->pdfUnsigned;
|
||||
}
|
||||
|
||||
public function setPdfUnsigned(?string $pdfUnsigned): static
|
||||
{
|
||||
$this->pdfUnsigned = $pdfUnsigned;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfUnsignedFile(): ?File
|
||||
{
|
||||
return $this->pdfUnsignedFile;
|
||||
}
|
||||
|
||||
public function setPdfUnsignedFile(?File $file): static
|
||||
{
|
||||
$this->pdfUnsignedFile = $file;
|
||||
if (null !== $file) {
|
||||
$this->updatedAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfSigned(): ?string
|
||||
{
|
||||
return $this->pdfSigned;
|
||||
}
|
||||
|
||||
public function setPdfSigned(?string $pdfSigned): static
|
||||
{
|
||||
$this->pdfSigned = $pdfSigned;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfSignedFile(): ?File
|
||||
{
|
||||
return $this->pdfSignedFile;
|
||||
}
|
||||
|
||||
public function setPdfSignedFile(?File $file): static
|
||||
{
|
||||
$this->pdfSignedFile = $file;
|
||||
if (null !== $file) {
|
||||
$this->updatedAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfAudit(): ?string
|
||||
{
|
||||
return $this->pdfAudit;
|
||||
}
|
||||
|
||||
public function setPdfAudit(?string $pdfAudit): static
|
||||
{
|
||||
$this->pdfAudit = $pdfAudit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPdfAuditFile(): ?File
|
||||
{
|
||||
return $this->pdfAuditFile;
|
||||
}
|
||||
|
||||
public function setPdfAuditFile(?File $file): static
|
||||
{
|
||||
$this->pdfAuditFile = $file;
|
||||
if (null !== $file) {
|
||||
$this->updatedAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCustomer(): ?Customer
|
||||
{
|
||||
return $this->customer;
|
||||
}
|
||||
|
||||
public function setCustomer(?Customer $customer): static
|
||||
{
|
||||
$this->customer = $customer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
public function getSignedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->signedAt;
|
||||
}
|
||||
|
||||
public function setSignedAt(?\DateTimeImmutable $signedAt): static
|
||||
{
|
||||
$this->signedAt = $signedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(?\DateTimeImmutable $updatedAt): static
|
||||
{
|
||||
$this->updatedAt = $updatedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
<div class="page-container">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-2xl font-bold heading-page">Contrats</h1>
|
||||
<button type="button" data-modal-open="modal-contrat" class="btn-gold px-4 py-2 font-bold uppercase text-[10px] tracking-wider text-gray-900">Creer un contrat</button>
|
||||
</div>
|
||||
|
||||
{% for type, messages in app.flashes %}
|
||||
@@ -14,13 +15,79 @@
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="glass p-12 text-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto mb-4 text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
<p class="text-gray-400 font-bold uppercase text-sm tracking-wider mb-2">Contrats</p>
|
||||
<p class="text-gray-300 text-xs">Cette section sera disponible prochainement.</p>
|
||||
<p class="text-gray-300 text-xs mt-1">Creez un contrat, faites-le signer, puis l'espace client sera cree automatiquement.</p>
|
||||
{% if contrats|length > 0 %}
|
||||
<div class="glass overflow-x-auto overflow-hidden">
|
||||
<table class="w-full text-sm">
|
||||
<thead>
|
||||
<tr class="glass-dark text-white">
|
||||
<th class="px-4 py-3 text-left font-bold uppercase text-xs tracking-widest">Reference</th>
|
||||
<th class="px-4 py-3 text-left font-bold uppercase text-xs tracking-widest">Client</th>
|
||||
<th class="px-4 py-3 text-left font-bold uppercase text-xs tracking-widest">Email</th>
|
||||
<th class="px-4 py-3 text-left font-bold uppercase text-xs tracking-widest">Type</th>
|
||||
<th class="px-4 py-3 text-center font-bold uppercase text-xs tracking-widest">Statut</th>
|
||||
<th class="px-4 py-3 text-left font-bold uppercase text-xs tracking-widest">Date</th>
|
||||
<th class="px-4 py-3 text-center font-bold uppercase text-xs tracking-widest">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for c in contrats %}
|
||||
<tr class="border-b border-white/20 hover:bg-white/50">
|
||||
<td class="px-4 py-3 font-mono font-bold text-[10px]">{{ c.reference }}</td>
|
||||
<td class="px-4 py-3 font-bold text-xs">{{ c.raisonSociale }}</td>
|
||||
<td class="px-4 py-3 text-xs text-gray-500">{{ c.email }}</td>
|
||||
<td class="px-4 py-3 text-xs">{{ c.typeLabel }}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
{% if c.state == 'signed' %}
|
||||
<span class="px-2 py-0.5 bg-green-500/20 text-green-700 font-bold uppercase text-[10px]">Signe</span>
|
||||
{% elseif c.state == 'send' %}
|
||||
<span class="px-2 py-0.5 bg-blue-500/20 text-blue-700 font-bold uppercase text-[10px]">Envoye</span>
|
||||
{% elseif c.state == 'cancelled' %}
|
||||
<span class="px-2 py-0.5 bg-red-500/20 text-red-700 font-bold uppercase text-[10px]">Annule</span>
|
||||
{% else %}
|
||||
<span class="px-2 py-0.5 bg-yellow-100 text-yellow-800 font-bold uppercase text-[10px]">Brouillon</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-xs text-gray-500">{{ c.createdAt|date('d/m/Y') }}</td>
|
||||
<td class="px-4 py-3 text-center">
|
||||
<a href="{{ path('app_admin_contrats_show', {id: c.id}) }}" class="px-3 py-1 bg-gray-900 text-white hover:bg-[#fabf04] hover:text-gray-900 font-bold uppercase text-[10px] transition-all">Voir</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="glass p-8 text-center text-gray-400 font-bold">Aucun contrat.</div>
|
||||
{% endif %}
|
||||
|
||||
{# Modal creation #}
|
||||
<div id="modal-contrat" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50">
|
||||
<div class="glass-heavy p-6 w-full max-w-lg">
|
||||
<h2 class="text-lg font-bold uppercase mb-4">Nouveau contrat</h2>
|
||||
<form method="post" action="{{ path('app_admin_contrats_create') }}">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mb-4">
|
||||
<div class="md:col-span-2">
|
||||
<label for="ctr-raisonSociale" class="block text-[9px] font-bold uppercase tracking-wider text-gray-400 mb-1">Raison sociale du client *</label>
|
||||
<input type="text" id="ctr-raisonSociale" name="raisonSociale" required class="input-glass w-full px-3 py-2 text-xs font-bold" placeholder="Ex: SARL Mon Entreprise">
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label for="ctr-email" class="block text-[9px] font-bold uppercase tracking-wider text-gray-400 mb-1">Email du client *</label>
|
||||
<input type="email" id="ctr-email" name="email" required class="input-glass w-full px-3 py-2 text-xs font-bold" placeholder="client@exemple.fr">
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label for="ctr-type" class="block text-[9px] font-bold uppercase tracking-wider text-gray-400 mb-1">Type de contrat *</label>
|
||||
<select id="ctr-type" name="type" required class="input-glass w-full px-3 py-2 text-xs font-bold">
|
||||
<option value="">— Selectionner —</option>
|
||||
<option value="migration_siteconseil">Contrat Migration SARL SITECONSEIL</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-2">
|
||||
<button type="button" data-modal-close="modal-contrat" class="px-4 py-2 glass font-bold uppercase text-[10px] tracking-widest">Annuler</button>
|
||||
<button type="submit" class="btn-gold px-4 py-2 font-bold uppercase text-[10px] tracking-wider text-gray-900">Creer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
84
templates/admin/contrats/show.html.twig
Normal file
84
templates/admin/contrats/show.html.twig
Normal file
@@ -0,0 +1,84 @@
|
||||
{% extends 'admin/_layout.html.twig' %}
|
||||
|
||||
{% block title %}Contrat {{ contrat.reference }} - Association E-Cosplay{% endblock %}
|
||||
|
||||
{% block admin_content %}
|
||||
<div class="page-container">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold heading-page">{{ contrat.reference }}</h1>
|
||||
<p class="text-xs text-gray-400 mt-1">{{ contrat.typeLabel }} - {{ contrat.raisonSociale }}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
{% if contrat.state == 'signed' %}
|
||||
<span class="px-3 py-1 bg-green-500/20 text-green-700 font-bold uppercase text-xs">Signe</span>
|
||||
{% elseif contrat.state == 'send' %}
|
||||
<span class="px-3 py-1 bg-blue-500/20 text-blue-700 font-bold uppercase text-xs">Envoye</span>
|
||||
{% elseif contrat.state == 'cancelled' %}
|
||||
<span class="px-3 py-1 bg-red-500/20 text-red-700 font-bold uppercase text-xs">Annule</span>
|
||||
{% else %}
|
||||
<span class="px-3 py-1 bg-yellow-100 text-yellow-800 font-bold uppercase text-xs">Brouillon</span>
|
||||
{% endif %}
|
||||
<a href="{{ path('app_admin_contrats_index') }}" class="px-4 py-2 glass font-bold uppercase text-xs tracking-widest hover:bg-gray-900 hover:text-white transition-all">Retour</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% for type, messages in app.flashes %}
|
||||
{% for message in messages %}
|
||||
<div class="mb-4 p-4 glass font-medium text-sm {{ type == 'success' ? 'border-green-300 text-green-800' : 'border-red-300 text-red-800' }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
{# Informations #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
||||
<div class="glass p-5">
|
||||
<h2 class="text-sm font-bold uppercase tracking-wider mb-3">Client</h2>
|
||||
<div class="space-y-2 text-sm">
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Raison sociale :</span> <span class="font-bold">{{ contrat.raisonSociale }}</span></p>
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Email :</span> <span class="font-bold">{{ contrat.email }}</span></p>
|
||||
{% if contrat.customer %}
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Compte client :</span> <a href="{{ path('app_admin_clients_show', {id: contrat.customer.id}) }}" class="font-bold" style="color: #fabf04;">{{ contrat.customer.fullName }}</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="glass p-5">
|
||||
<h2 class="text-sm font-bold uppercase tracking-wider mb-3">Contrat</h2>
|
||||
<div class="space-y-2 text-sm">
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Reference :</span> <span class="font-mono font-bold">{{ contrat.reference }}</span></p>
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Type :</span> <span class="font-bold">{{ contrat.typeLabel }}</span></p>
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Cree le :</span> <span class="font-bold">{{ contrat.createdAt|date('d/m/Y H:i') }}</span></p>
|
||||
{% if contrat.signedAt %}
|
||||
<p><span class="text-[9px] font-bold uppercase tracking-wider text-gray-400">Signe le :</span> <span class="font-bold text-green-600">{{ contrat.signedAt|date('d/m/Y H:i') }}</span></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Actions #}
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
{% if contrat.pdfUnsigned %}
|
||||
<a href="{{ vich_uploader_asset(contrat, 'pdfUnsignedFile') }}" target="_blank"
|
||||
class="px-4 py-2 bg-gray-900 text-white font-bold uppercase text-[10px] tracking-wider hover:bg-[#fabf04] hover:text-gray-900 transition-all">
|
||||
Voir PDF
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if contrat.pdfSigned %}
|
||||
<a href="{{ vich_uploader_asset(contrat, 'pdfSignedFile') }}" target="_blank"
|
||||
class="px-4 py-2 bg-green-500/20 text-green-700 font-bold uppercase text-[10px] tracking-wider hover:bg-green-500 hover:text-white transition-all">
|
||||
Contrat signe
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if contrat.pdfAudit %}
|
||||
<a href="{{ vich_uploader_asset(contrat, 'pdfAuditFile') }}" target="_blank"
|
||||
class="px-4 py-2 bg-blue-500/20 text-blue-700 font-bold uppercase text-[10px] tracking-wider hover:bg-blue-500 hover:text-white transition-all">
|
||||
Audit signature
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if contrat.state in ['draft', 'send'] %}
|
||||
<form method="post" action="{{ path('app_admin_contrats_cancel', {id: contrat.id}) }}" data-confirm="Annuler ce contrat ?">
|
||||
<button type="submit" class="px-4 py-2 bg-red-500/20 text-red-700 hover:bg-red-500 hover:text-white font-bold uppercase text-[10px] tracking-wider transition-all">Annuler</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user