$attachments
+ */
+ private function injectAttachmentsList(string $html, array $attachments): string
+ {
+ $excluded = ['.asc', '.p7z'];
+ $filtered = [];
+
+ foreach ($attachments as $a) {
+ $name = $a['name'] ?? basename($a['path']);
+ $path = $a['path'] ?? '';
+ $ext = strtolower(pathinfo($name, \PATHINFO_EXTENSION));
+ if (\in_array('.'.$ext, $excluded, true) || str_contains(strtolower($name), 'smime')) {
+ continue;
+ }
+ $size = file_exists($path) ? filesize($path) : 0;
+ $filtered[] = ['name' => $name, 'size' => $size];
+ }
+
+ if ([] === $filtered) {
+ return $html;
+ }
+
+ $items = '';
+ foreach ($filtered as $f) {
+ $sizeStr = $this->formatFileSize($f['size']);
+ $items .= ''
+ .''
+ .''
+ .'📎 '
+ .''
+ .''.htmlspecialchars($f['name'], \ENT_QUOTES, 'UTF-8').'
'
+ .'Piece jointe ('.$sizeStr.')
'
+ .' '
+ .'
'
+ .' '
+ .' ';
+ }
+
+ $block = ''
+ .'Pieces jointes
'
+ .''
+ .' ';
+
+ // Injecte avant le footer dark
+ $marker = '= 1048576) {
+ return number_format($bytes / 1048576, 1, ',', ' ').' Mo';
+ }
+ if ($bytes >= 1024) {
+ return number_format($bytes / 1024, 0, ',', ' ').' Ko';
+ }
+
+ return $bytes.' o';
+ }
+
private function addUnsubscribeHeaders(Email $email, string $to): void
{
$token = $this->unsubscribeManager->generateToken($to);
diff --git a/src/Service/MeilisearchService.php b/src/Service/MeilisearchService.php
index e214a00..08c2e2f 100644
--- a/src/Service/MeilisearchService.php
+++ b/src/Service/MeilisearchService.php
@@ -2,8 +2,10 @@
namespace App\Service;
+use App\Entity\Advert;
use App\Entity\Customer;
use App\Entity\CustomerContact;
+use App\Entity\Devis;
use App\Entity\Domain;
use App\Entity\PriceAutomatic;
use App\Entity\Revendeur;
@@ -228,6 +230,76 @@ class MeilisearchService
}
}
+ public function indexDevis(Devis $devis): void
+ {
+ try {
+ $this->client->index('customer_devis')->addDocuments([$this->serializeDevis($devis)]);
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: Failed to index devis '.$devis->getId().': '.$e->getMessage());
+ }
+ }
+
+ public function removeDevis(int $devisId): void
+ {
+ try {
+ $this->client->index('customer_devis')->deleteDocument($devisId);
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: Failed to remove devis '.$devisId.': '.$e->getMessage());
+ }
+ }
+
+ /** @return list> */
+ public function searchDevis(string $query, int $limit = 20, ?int $customerId = null): array
+ {
+ try {
+ $options = ['limit' => $limit];
+ if (null !== $customerId) {
+ $options['filter'] = 'customerId = '.$customerId;
+ }
+
+ return $this->client->index('customer_devis')->search($query, $options)->getHits();
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: search devis error: '.$e->getMessage());
+
+ return [];
+ }
+ }
+
+ public function indexAdvert(Advert $advert): void
+ {
+ try {
+ $this->client->index('customer_advert')->addDocuments([$this->serializeAdvert($advert)]);
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: Failed to index advert '.$advert->getId().': '.$e->getMessage());
+ }
+ }
+
+ public function removeAdvert(int $advertId): void
+ {
+ try {
+ $this->client->index('customer_advert')->deleteDocument($advertId);
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: Failed to remove advert '.$advertId.': '.$e->getMessage());
+ }
+ }
+
+ /** @return list> */
+ public function searchAdverts(string $query, int $limit = 20, ?int $customerId = null): array
+ {
+ try {
+ $options = ['limit' => $limit];
+ if (null !== $customerId) {
+ $options['filter'] = 'customerId = '.$customerId;
+ }
+
+ return $this->client->index('customer_advert')->search($query, $options)->getHits();
+ } catch (\Throwable $e) {
+ $this->logger->error('Meilisearch: search adverts error: '.$e->getMessage());
+
+ return [];
+ }
+ }
+
public function setupIndexes(): void
{
try {
@@ -301,6 +373,30 @@ class MeilisearchService
$this->client->index('customer_website')->updateFilterableAttributes([
'customerId', 'type', 'state',
]);
+
+ try {
+ $this->client->createIndex('customer_devis', ['primaryKey' => 'id']);
+ } catch (\Throwable $e) {
+ $this->logger->warning('Meilisearch: setupIndexes (customer_devis) - '.$e->getMessage());
+ }
+ $this->client->index('customer_devis')->updateSearchableAttributes([
+ 'numOrder', 'customerName', 'customerEmail', 'state',
+ ]);
+ $this->client->index('customer_devis')->updateFilterableAttributes([
+ 'customerId', 'state',
+ ]);
+
+ try {
+ $this->client->createIndex('customer_advert', ['primaryKey' => 'id']);
+ } catch (\Throwable $e) {
+ $this->logger->warning('Meilisearch: setupIndexes (customer_advert) - '.$e->getMessage());
+ }
+ $this->client->index('customer_advert')->updateSearchableAttributes([
+ 'numOrder', 'customerName', 'customerEmail', 'state',
+ ]);
+ $this->client->index('customer_advert')->updateFilterableAttributes([
+ 'customerId', 'state',
+ ]);
}
/**
@@ -422,4 +518,40 @@ class MeilisearchService
'customerEmail' => $website->getCustomer()->getEmail(),
];
}
+
+ /** @return array */
+ private function serializeDevis(Devis $devis): array
+ {
+ $customer = $devis->getCustomer();
+
+ return [
+ 'id' => $devis->getId(),
+ 'numOrder' => $devis->getOrderNumber()->getNumOrder(),
+ 'state' => $devis->getState(),
+ 'totalHt' => $devis->getTotalHt(),
+ 'totalTtc' => $devis->getTotalTtc(),
+ 'customerId' => $customer?->getId(),
+ 'customerName' => $customer?->getFullName(),
+ 'customerEmail' => $customer?->getEmail(),
+ 'createdAt' => $devis->getCreatedAt()->format('Y-m-d'),
+ ];
+ }
+
+ /** @return array */
+ private function serializeAdvert(Advert $advert): array
+ {
+ $customer = $advert->getCustomer();
+
+ return [
+ 'id' => $advert->getId(),
+ 'numOrder' => $advert->getOrderNumber()->getNumOrder(),
+ 'state' => $advert->getState(),
+ 'totalHt' => $advert->getTotalHt(),
+ 'totalTtc' => $advert->getTotalTtc(),
+ 'customerId' => $customer?->getId(),
+ 'customerName' => $customer?->getFullName(),
+ 'customerEmail' => $customer?->getEmail(),
+ 'createdAt' => $advert->getCreatedAt()->format('Y-m-d'),
+ ];
+ }
}
diff --git a/src/Service/OrderNumberService.php b/src/Service/OrderNumberService.php
index 44c8b54..cacca20 100644
--- a/src/Service/OrderNumberService.php
+++ b/src/Service/OrderNumberService.php
@@ -16,10 +16,22 @@ class OrderNumberService
/**
* Genere le prochain numero de commande au format MM/YYYY-XXXXX.
- * Le compteur XXXXX est incremente par mois (reset a 00001 chaque nouveau mois).
+ * Reutilise en priorite un OrderNumber existant non utilise (isUsed = false),
+ * sinon cree un nouveau (compteur XXXXX reset chaque mois).
*/
public function generate(): OrderNumber
{
+ $unused = $this->repository->createQueryBuilder('o')
+ ->where('o.isUsed = false')
+ ->orderBy('o.createdAt', 'ASC')
+ ->setMaxResults(1)
+ ->getQuery()
+ ->getOneOrNullResult();
+
+ if (null !== $unused) {
+ return $unused;
+ }
+
$now = new \DateTimeImmutable();
$prefix = $now->format('m/Y').'-';
@@ -61,9 +73,22 @@ class OrderNumberService
/**
* Recupere le prochain numero sans le creer.
+ * Reutilise un OrderNumber existant non utilise (isUsed = false) en priorite,
+ * sinon calcule le prochain numero du mois courant.
*/
public function preview(): string
{
+ $unused = $this->repository->createQueryBuilder('o')
+ ->where('o.isUsed = false')
+ ->orderBy('o.createdAt', 'ASC')
+ ->setMaxResults(1)
+ ->getQuery()
+ ->getOneOrNullResult();
+
+ if (null !== $unused) {
+ return $unused->getNumOrder();
+ }
+
$now = new \DateTimeImmutable();
$prefix = $now->format('m/Y').'-';
diff --git a/src/Service/Pdf/AdvertPdf.php b/src/Service/Pdf/AdvertPdf.php
new file mode 100644
index 0000000..0f69160
--- /dev/null
+++ b/src/Service/Pdf/AdvertPdf.php
@@ -0,0 +1,234 @@
+ */
+ private array $items = [];
+
+ private string $qrBase64 = '';
+
+ public function __construct(
+ private readonly KernelInterface $kernel,
+ private readonly Advert $advert,
+ ?UrlGeneratorInterface $urlGenerator = null,
+ ) {
+ parent::__construct();
+
+ // Generation QR code vers la page de paiement
+ if (null !== $urlGenerator) {
+ $paymentUrl = $urlGenerator->generate('app_order_payment', [
+ 'numOrder' => $advert->getOrderNumber()->getNumOrder(),
+ ], UrlGeneratorInterface::ABSOLUTE_URL);
+
+ $builder = new Builder(
+ writer: new PngWriter(),
+ data: $paymentUrl,
+ size: 200,
+ margin: 10,
+ );
+ $this->qrBase64 = 'data:image/png;base64,'.base64_encode($builder->build()->getString());
+ }
+
+ $items = [];
+ foreach ($this->advert->getLines() as $line) {
+ $items[$line->getPos()] = [
+ 'title' => $line->getTitle(),
+ 'content' => $line->getDescription() ?? '',
+ 'priceHt' => (float) $line->getPriceHt(),
+ ];
+ }
+ ksort($items);
+ $this->items = $items;
+
+ $this->SetTitle($this->enc('Avis de Paiement N° '.$this->advert->getOrderNumber()->getNumOrder()));
+ }
+
+ public function Header(): void
+ {
+ $this->SetFont('Arial', '', 10);
+ $logo = $this->kernel->getProjectDir().'/public/logo_facture.png';
+ if (file_exists($logo)) {
+ $this->Image($logo, 65, 5, 80);
+ }
+
+ $formatter = new \IntlDateFormatter(
+ 'fr_FR',
+ \IntlDateFormatter::FULL,
+ \IntlDateFormatter::NONE,
+ 'Europe/Paris',
+ \IntlDateFormatter::GREGORIAN
+ );
+
+ $numText = $this->enc('AVIS DE PAIEMENT N° '.$this->advert->getOrderNumber()->getNumOrder());
+ $dateText = $this->enc('Saint-Quentin, '.$formatter->format($this->advert->getCreatedAt()));
+
+ $this->Text(15, 80, $numText);
+ $this->Text(15, 85, $dateText);
+
+ $this->SetFont('Arial', 'B', 12);
+
+ $y = 60;
+ $customer = $this->advert->getCustomer();
+
+ if (null !== $customer) {
+ $name = $customer->getRaisonSociale() ?: $customer->getFullName();
+ $this->Text(110, $y, $this->enc($name));
+
+ if ($address = $customer->getAddress()) {
+ $y += 5;
+ $this->Text(110, $y, $this->enc($address));
+ }
+
+ if ($address2 = $customer->getAddress2()) {
+ $y += 5;
+ $this->Text(110, $y, $this->enc($address2));
+ }
+
+ $y += 5;
+ $cityLine = ($customer->getZipCode() ?? '').' '.($customer->getCity() ?? '');
+ $this->Text(110, $y, $this->enc(trim($cityLine)));
+ }
+
+ $this->body();
+ }
+
+ private function body(): void
+ {
+ $this->SetFont('Arial', 'B', 10);
+ $this->SetXY(145, 100);
+ $this->Cell(40, 5, $this->enc('PRIX HT'), 0, 0, 'C');
+
+ $this->Line(145, 110, 145, 220);
+ $this->Line(185, 110, 185, 220);
+
+ $this->Line(0, 100, 5, 100);
+ $this->Line(0, 200, 5, 200);
+ }
+
+ public function generate(): void
+ {
+ $this->AliasNbPages();
+ $this->AddPage();
+ $this->SetFont('Arial', '', 12);
+
+ $startY = 110;
+ $this->SetY($startY);
+ $contentBottomLimit = 220;
+
+ foreach ($this->items as $item) {
+ if ($this->GetY() + 30 > $contentBottomLimit) {
+ $this->AddPage();
+ $this->body();
+ $this->SetY($startY);
+ }
+
+ $currentY = $this->GetY();
+
+ $this->SetX(20);
+ $this->SetFont('Arial', 'B', 11);
+ $this->Cell(95, 10, $this->enc($item['title']), 0, 0);
+
+ $this->SetFont('Arial', 'B', 11);
+ $this->SetXY(142, $currentY);
+ $this->Cell(39, 8, number_format($item['priceHt'], 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ $this->SetFont('Arial', '', 11);
+ $this->SetX(30);
+ if ('' !== $item['content']) {
+ $this->MultiCell(90, 5, $this->enc($item['content']), 0, 'L');
+ }
+
+ $this->Ln(5);
+ }
+
+ $this->displaySummary();
+ $this->displayQrCode();
+ }
+
+ private function displayQrCode(): void
+ {
+ if ('' === $this->qrBase64) {
+ return;
+ }
+
+ $this->SetAutoPageBreak(false);
+ $y = $this->GetPageHeight() - 55;
+
+ // QR code en bas a gauche
+ $tmpQr = tempnam(sys_get_temp_dir(), 'qr_').'.png';
+ $pngData = base64_decode(str_replace('data:image/png;base64,', '', $this->qrBase64));
+ file_put_contents($tmpQr, $pngData);
+
+ $this->Image($tmpQr, 15, $y, 30, 30);
+ @unlink($tmpQr);
+
+ // Texte a droite du QR
+ $this->SetXY(50, $y + 5);
+ $this->SetFont('Arial', 'B', 9);
+ $this->SetTextColor(0, 0, 0);
+ $this->Cell(100, 5, $this->enc('Scannez pour payer'), 0, 1, 'L');
+ $this->SetX(50);
+ $this->SetFont('Arial', '', 8);
+ $this->SetTextColor(100, 100, 100);
+ $this->Cell(100, 5, $this->enc('Flashez ce QR code pour acceder aux options de paiement.'), 0, 1, 'L');
+ }
+
+ private function displaySummary(): void
+ {
+ $totalHt = array_sum(array_column($this->items, 'priceHt'));
+ $totalTva = $totalHt * 0.20;
+ $totalTtc = $totalHt + $totalTva;
+
+ $this->SetY(-60);
+
+ $this->SetFont('Arial', '', 12);
+ $this->Cell(100, 10, $this->enc('Total HT :'), 0, 0, 'R');
+ $this->Cell(40, 10, number_format($totalHt, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ $this->Cell(135, 10, $this->enc('TVA (20%) :'), 0, 0, 'R');
+ $this->Cell(35, 10, number_format($totalTva, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ $this->SetFont('Arial', 'B', 12);
+ $this->Cell(135, 10, $this->enc('Total TTC :'), 0, 0, 'R');
+ $this->Cell(35, 10, number_format($totalTtc, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+ }
+
+ public function Footer(): void
+ {
+ $this->SetY(-32);
+ $this->Ln(10);
+ $this->SetFont('Arial', 'B', 8);
+ $this->SetTextColor(253, 140, 4);
+ $this->SetDrawColor(253, 140, 4);
+ $this->Cell(190, 5, $this->enc('Partenaire de vos projects de puis 1997'), 0, 1, 'C');
+ $this->Line(15, $this->GetY(), 195, $this->GetY());
+ $this->SetFont('Arial', '', 8);
+ $this->SetTextColor(0, 0, 0);
+ $this->Ln(2);
+ $this->Cell(190, 4, $this->enc('27, rue le Sérurier - 02100 SAINT-QUENTIN - Tél: 03 23 05 62 43'), 0, 1, 'C');
+ $this->Cell(190, 4, $this->enc('e-mail : s.com@siteconseil.fr - www.siteconseil.fr'), 0, 1, 'C');
+ $this->Cell(190, 4, $this->enc('S.A.R.L aux captial de 71400 ').EURO.' - '.$this->enc('N°SIRET 418 664 058 00025 - N° TVA FR 05 418 664 058 - CODE APE 6201 Z - R.C. St-Quentin 418 664 058'), 0, 1, 'C');
+
+ $this->SetFont('Arial', 'I', 7);
+ $this->SetTextColor(150, 150, 150);
+ $this->Cell(190, 4, $this->enc('Page ').$this->PageNo().' / {nb}', 0, 0, 'C');
+ }
+
+ private function enc(string $text): string
+ {
+ return mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
+ }
+}
diff --git a/src/Service/Pdf/DevisPdf.php b/src/Service/Pdf/DevisPdf.php
new file mode 100644
index 0000000..86c191d
--- /dev/null
+++ b/src/Service/Pdf/DevisPdf.php
@@ -0,0 +1,248 @@
+ */
+ private array $items = [];
+
+ private int $lastDevisPage = 0;
+
+ public function __construct(
+ private readonly KernelInterface $kernel,
+ private readonly Devis $devis,
+ ) {
+ parent::__construct();
+
+ $items = [];
+ foreach ($this->devis->getLines() as $line) {
+ $items[$line->getPos()] = [
+ 'title' => $line->getTitle(),
+ 'content' => $line->getDescription() ?? '',
+ 'priceHt' => (float) $line->getPriceHt(),
+ ];
+ }
+ ksort($items);
+ $this->items = $items;
+
+ $this->SetTitle($this->enc('Devis N° '.$this->devis->getOrderNumber()->getNumOrder()));
+ }
+
+ public function Header(): void
+ {
+ // Sur les pages CGV importees (au-dela de la derniere page devis), pas de header
+ if ($this->lastDevisPage > 0 && $this->PageNo() > $this->lastDevisPage) {
+ return;
+ }
+
+ $this->SetFont('Arial', '', 10);
+ $logo = $this->kernel->getProjectDir().'/public/logo_facture.png';
+ if (file_exists($logo)) {
+ $this->Image($logo, 65, 5, 80);
+ }
+
+ $formatter = new \IntlDateFormatter(
+ 'fr_FR',
+ \IntlDateFormatter::FULL,
+ \IntlDateFormatter::NONE,
+ 'Europe/Paris',
+ \IntlDateFormatter::GREGORIAN
+ );
+
+ $numDevisText = $this->enc('DEVIS N° '.$this->devis->getOrderNumber()->getNumOrder());
+ $dateText = $this->enc('Saint-Quentin, '.$formatter->format($this->devis->getCreatedAt()));
+
+ $this->Text(15, 80, $numDevisText);
+ $this->Text(15, 85, $dateText);
+
+ $this->SetFont('Arial', 'B', 12);
+
+ $y = 60;
+ $customer = $this->devis->getCustomer();
+
+ if (null !== $customer) {
+ $name = $customer->getRaisonSociale() ?: $customer->getFullName();
+ $this->Text(110, $y, $this->enc($name));
+
+ if ($address = $customer->getAddress()) {
+ $y += 5;
+ $this->Text(110, $y, $this->enc($address));
+ }
+
+ if ($address2 = $customer->getAddress2()) {
+ $y += 5;
+ $this->Text(110, $y, $this->enc($address2));
+ }
+
+ $y += 5;
+ $cityLine = ($customer->getZipCode() ?? '').' '.($customer->getCity() ?? '');
+ $this->Text(110, $y, $this->enc(trim($cityLine)));
+ }
+
+ $this->body();
+ }
+
+ private function body(): void
+ {
+ $this->SetFont('Arial', 'B', 10);
+ $this->SetXY(145, 100);
+ $this->Cell(40, 5, $this->enc('PRIX HT'), 0, 0, 'C');
+
+ $this->Line(145, 110, 145, 220);
+ $this->Line(185, 110, 185, 220);
+
+ $this->Line(0, 100, 5, 100);
+ $this->Line(0, 200, 5, 200);
+ }
+
+ public function generate(): void
+ {
+ $this->AliasNbPages();
+ $this->AddPage();
+ $this->SetFont('Arial', '', 12);
+
+ $startY = 110;
+ $this->SetY($startY);
+ $contentBottomLimit = 220;
+
+ foreach ($this->items as $item) {
+ if ($this->GetY() + 30 > $contentBottomLimit) {
+ $this->AddPage();
+ $this->body();
+ $this->SetY($startY);
+ }
+
+ $currentY = $this->GetY();
+
+ // Titre
+ $this->SetX(20);
+ $this->SetFont('Arial', 'B', 11);
+ $this->Cell(95, 10, $this->enc($item['title']), 0, 0);
+
+ // Prix HT
+ $this->SetFont('Arial', 'B', 11);
+ $this->SetXY(142, $currentY);
+ $this->Cell(39, 8, number_format($item['priceHt'], 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ // Description
+ $this->SetFont('Arial', '', 11);
+ $this->SetX(30);
+ if ('' !== $item['content']) {
+ $this->MultiCell(90, 5, $this->enc($item['content']), 0, 'L');
+ }
+
+ $this->Ln(5);
+ }
+
+ $this->displaySummary();
+ $this->appendCgv();
+ }
+
+ /**
+ * Importe les pages de public/cgv.pdf a la suite du devis, sans appliquer le Header/Footer devis.
+ */
+ private function appendCgv(): void
+ {
+ $cgvPath = $this->kernel->getProjectDir().'/public/cgv.pdf';
+ if (!file_exists($cgvPath)) {
+ return;
+ }
+
+ try {
+ $pageCount = $this->setSourceFile($cgvPath);
+
+ // Marque la derniere page devis : toutes les pages ajoutees apres auront le Header/Footer desactive
+ $this->lastDevisPage = $this->PageNo();
+
+ for ($i = 1; $i <= $pageCount; ++$i) {
+ $tpl = $this->importPage($i);
+ $size = $this->getTemplateSize($tpl);
+ $this->AddPage($size['orientation'] ?? 'P', [$size['width'], $size['height']]);
+ $this->useTemplate($tpl);
+
+ // Sur la DERNIERE page CGV : ajoute un champ signature DocuSeal independant
+ // en bas a gauche, sans declencher de saut de page automatique
+ if ($i === $pageCount) {
+ $this->SetAutoPageBreak(false);
+ $this->SetXY(15, $this->GetPageHeight() - 100);
+ $this->SetFont('Arial', '', 10);
+ $this->SetTextColor(0, 0, 0);
+ $this->Cell(60, 20, '{{SignCGV;type=signature;role=First Party}}', 0, 0, 'L');
+ }
+ }
+ } catch (\Throwable) {
+ // Silencieux : si CGV corrompu on garde juste le devis
+ }
+ }
+
+ private function displaySummary(): void
+ {
+ $totalHt = array_sum(array_column($this->items, 'priceHt'));
+ $totalTva = $totalHt * 0.20;
+ $totalTtc = $totalHt + $totalTva;
+
+ $this->SetY(-60);
+
+ // Zone signature (placeholder DocuSeal) en bas a gauche de la derniere page devis
+ $this->Cell(30, 10, '{{Sign;type=signature;role=First Party}}', 0, 0, 'L');
+
+ $this->SetFont('Arial', '', 12);
+ $this->Cell(100, 10, $this->enc('Total HT :'), 0, 0, 'R');
+ $this->Cell(40, 10, number_format($totalHt, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ $this->Cell(135, 10, $this->enc('TVA (20%) :'), 0, 0, 'R');
+ $this->Cell(35, 10, number_format($totalTva, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+
+ $this->SetFont('Arial', 'B', 12);
+ $this->Cell(135, 10, $this->enc('Total TTC :'), 0, 0, 'R');
+ $this->Cell(35, 10, number_format($totalTtc, 2, ',', ' ').' '.EURO, 0, 1, 'R');
+ }
+
+ public function Footer(): void
+ {
+ // Sur les pages CGV importees (au-dela de la derniere page devis), pas de footer
+ if ($this->lastDevisPage > 0 && $this->PageNo() > $this->lastDevisPage) {
+ return;
+ }
+
+ $this->SetY(-32);
+ $this->Ln(10);
+ $this->SetFont('Arial', 'B', 8);
+ $this->SetTextColor(253, 140, 4);
+ $this->SetDrawColor(253, 140, 4);
+ $this->Cell(190, 5, $this->enc('Partenaire de vos projects de puis 1997'), 0, 1, 'C');
+ $this->Line(15, $this->GetY(), 195, $this->GetY());
+ $this->SetFont('Arial', '', 8);
+ $this->SetTextColor(0, 0, 0);
+ $this->Ln(2);
+ $this->Cell(190, 4, $this->enc('27, rue le Sérurier - 02100 SAINT-QUENTIN - Tél: 03 23 05 62 43'), 0, 1, 'C');
+ $this->Cell(190, 4, $this->enc('e-mail : s.com@siteconseil.fr - www.siteconseil.fr'), 0, 1, 'C');
+ $this->Cell(190, 4, $this->enc('S.A.R.L aux captial de 71400 ').EURO.' - '.$this->enc('N°SIRET 418 664 058 00025 - N° TVA FR 05 418 664 058 - CODE APE 6201 Z - R.C. St-Quentin 418 664 058'), 0, 1, 'C');
+
+ // Numero de page avec alias {nb}
+ $this->SetFont('Arial', 'I', 7);
+ $this->SetTextColor(150, 150, 150);
+ $this->Cell(190, 4, $this->enc('Page ').$this->PageNo().' / {nb}', 0, 0, 'C');
+ }
+
+ /**
+ * Encode une chaine UTF-8 en Windows-1252 (requis par FPDF).
+ */
+ private function enc(string $text): string
+ {
+ return mb_convert_encoding($text, 'Windows-1252', 'UTF-8');
+ }
+}
diff --git a/symfony.lock b/symfony.lock
index e0e89f9..d78bd13 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -393,6 +393,15 @@
"templates/base.html.twig"
]
},
+ "symfony/uid": {
+ "version": "8.0",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "7.0",
+ "ref": "0df5844274d871b37fc3816c57a768ffc60a43a5"
+ }
+ },
"symfony/validator": {
"version": "8.0",
"recipe": {
diff --git a/templates/admin/clients/create.html.twig b/templates/admin/clients/create.html.twig
index bdbe511..0ede52a 100644
--- a/templates/admin/clients/create.html.twig
+++ b/templates/admin/clients/create.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Nouveau client - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Nouveau client - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/clients/index.html.twig b/templates/admin/clients/index.html.twig
index 2b740e4..ce56c5b 100644
--- a/templates/admin/clients/index.html.twig
+++ b/templates/admin/clients/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Clients - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Clients - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/clients/show.html.twig b/templates/admin/clients/show.html.twig
index b422745..613ae0c 100644
--- a/templates/admin/clients/show.html.twig
+++ b/templates/admin/clients/show.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}{{ customer.fullName }} - Client - CRM SITECONSEIL{% endblock %}
+{% block title %}{{ customer.fullName }} - Client - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
@@ -463,6 +463,219 @@
Aucun site internet.
{% endif %}
+ {# Tab: Avis de Paiement #}
+ {% elseif tab == 'avis' %}
+
+
Avis de paiement
+
+
+
+ {% if advertsList|length > 0 %}
+
+
+
+
+ Numero
+ Date
+ Devis lie
+ Lignes
+ Total HT
+ Total TTC
+ Etat
+ Actions
+
+
+
+ {% for a in advertsList %}
+
+ {{ a.orderNumber.numOrder }}
+ {{ a.createdAt|date('d/m/Y') }}
+
+ {% if a.devis %}
+ {{ a.devis.orderNumber.numOrder }}
+ {% else %}
+ —
+ {% endif %}
+
+ {{ a.lines|length }}
+ {{ a.totalHt }} €
+ {{ a.totalTtc }} €
+
+ {% if a.state == 'accepted' %}
+ Accepte
+ {% elseif a.state == 'refused' %}
+ Refuse
+ {% elseif a.state == 'send' %}
+ Envoye
+ {% elseif a.state == 'cancel' %}
+ Annule
+ {% else %}
+ Cree
+ {% endif %}
+
+
+ {% if a.state != 'cancel' %}
+
+ {% if a.advertFile %}
+
+ Voir PDF
+
+
+ {% else %}
+
+ {% endif %}
+ {% if a.advertFile and a.state == 'created' %}
+
+ {% endif %}
+ {% if a.state == 'send' %}
+
+ {% endif %}
+
+
+ {% else %}
+ —
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+
{{ advertsList|length }} avis de paiement
+ {% else %}
+
Aucun avis de paiement.
+ {% endif %}
+
+ {# Tab: Devis #}
+ {% elseif tab == 'devis' %}
+
+
+
+ {% if devisList|length > 0 %}
+
+
+
+
+ Numero
+ Date
+ Lignes
+ Total HT
+ Total TTC
+ Etat
+ Actions
+
+
+
+ {% for d in devisList %}
+
+ {{ d.orderNumber.numOrder }}
+ {{ d.createdAt|date('d/m/Y') }}
+ {{ d.lines|length }}
+ {{ d.totalHt }} €
+ {{ d.totalTtc }} €
+
+ {% if d.state == 'accepted' %}
+ Accepte
+ {% elseif d.state == 'refused' %}
+ Refuse
+ {% elseif d.state == 'send' %}
+ Envoye
+ {% elseif d.state == 'cancel' %}
+ Annule
+ {% else %}
+ Cree
+ {% endif %}
+
+
+ {% if d.state != 'cancel' %}
+
+ {% if d.unsignedPdf %}
+
+ Voir PDF
+
+ {% endif %}
+ {% if d.unsignedPdf %}
+
+ {% else %}
+
+ {% endif %}
+ {% if d.unsignedPdf and d.state == 'created' %}
+
+ {% endif %}
+ {% if d.state == 'send' %}
+
+ {% endif %}
+ {% if d.state == 'accepted' and d.advert is null %}
+
+ {% endif %}
+ {% if d.advert %}
+
+ Avis {{ d.advert.orderNumber.numOrder }}
+
+ {% endif %}
+ {% if d.submissionId %}
+
+ Evenements
+
+ {% endif %}
+
+ Modifier
+
+
+
+ {% else %}
+ —
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+
{{ devisList|length }} devis
+ {% else %}
+
Aucun devis.
+ {% endif %}
+
{# Tab: Securite #}
{% elseif tab == 'securite' %}
{% set user = customer.user %}
diff --git a/templates/admin/dashboard.html.twig b/templates/admin/dashboard.html.twig
index 4d9940e..a8c0509 100644
--- a/templates/admin/dashboard.html.twig
+++ b/templates/admin/dashboard.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/devis/create.html.twig b/templates/admin/devis/create.html.twig
new file mode 100644
index 0000000..db6fb4f
--- /dev/null
+++ b/templates/admin/devis/create.html.twig
@@ -0,0 +1,104 @@
+{% extends 'admin/_layout.html.twig' %}
+
+{% set isEdit = isEdit ?? false %}
+
+{% block title %}{{ isEdit ? 'Modifier' : 'Creer' }} un devis - SARL SITECONSEIL{% endblock %}
+
+{% block admin_content %}
+
+
+
{{ isEdit ? 'Modifier' : 'Creer' }} un devis
+
Retour
+
+
+
+
+
+
+
+
+
+
+
+
#1
+
+
+
+ EUR HT
+
+
×
+
+
+
+
+
+
+{% endblock %}
diff --git a/templates/admin/devis/events.html.twig b/templates/admin/devis/events.html.twig
new file mode 100644
index 0000000..5732373
--- /dev/null
+++ b/templates/admin/devis/events.html.twig
@@ -0,0 +1,65 @@
+{% extends 'admin/_layout.html.twig' %}
+
+{% block title %}Evenements devis {{ devis.orderNumber.numOrder }} - SARL SITECONSEIL{% endblock %}
+
+{% block admin_content %}
+
+
+
+
Evenements DocuSeal
+
Devis {{ devis.orderNumber.numOrder }}
+
+
Retour
+
+
+ {% if events|length > 0 %}
+
+
+
+
+ Date
+ Evenement
+ Submission
+ Submitter
+ Payload
+
+
+
+ {% for e in events %}
+
+ {{ e.createdAt|date('d/m/Y H:i:s') }}
+
+ {% set eventType = e.eventType %}
+ {% if eventType == 'form.viewed' %}
+ Vu
+ {% elseif eventType == 'form.started' %}
+ Demarre
+ {% elseif eventType == 'form.completed' %}
+ Signe
+ {% elseif eventType == 'form.declined' %}
+ Refuse
+ {% else %}
+ {{ eventType }}
+ {% endif %}
+
+ {{ e.submissionId ?? '—' }}
+ {{ e.submitterId ?? '—' }}
+
+ {% if e.payload %}
+
+ Voir payload
+ {{ e.payload }}
+
+ {% endif %}
+
+
+ {% endfor %}
+
+
+
+
{{ events|length }} evenement(s)
+ {% else %}
+
Aucun evenement pour ce devis.
+ {% endif %}
+
+{% endblock %}
diff --git a/templates/admin/facturation/index.html.twig b/templates/admin/facturation/index.html.twig
index 96c6ead..264f3f0 100644
--- a/templates/admin/facturation/index.html.twig
+++ b/templates/admin/facturation/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Facturation - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Facturation - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/logs/index.html.twig b/templates/admin/logs/index.html.twig
index 7c9e257..6924ac5 100644
--- a/templates/admin/logs/index.html.twig
+++ b/templates/admin/logs/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Logs - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Logs - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/logs/pdf.html.twig b/templates/admin/logs/pdf.html.twig
index 34b4aae..4ac8927 100644
--- a/templates/admin/logs/pdf.html.twig
+++ b/templates/admin/logs/pdf.html.twig
@@ -1,6 +1,6 @@
{% extends 'pdf/_base.html.twig' %}
-{% block title %}Log #{{ log.id }} - CRM SITECONSEIL{% endblock %}
+{% block title %}Log #{{ log.id }} - SARL SITECONSEIL{% endblock %}
{% block data_table_mt %}8px{% endblock %}
{% block data_td_pad %}5px{% endblock %}
diff --git a/templates/admin/logs/verify.html.twig b/templates/admin/logs/verify.html.twig
index bba8803..9024a87 100644
--- a/templates/admin/logs/verify.html.twig
+++ b/templates/admin/logs/verify.html.twig
@@ -1,6 +1,6 @@
{% extends 'legal/_layout.html.twig' %}
-{% block title %}Verification log #{{ id }} - CRM SITECONSEIL{% endblock %}
+{% block title %}Verification log #{{ id }} - SARL SITECONSEIL{% endblock %}
{% block description %}Verification de l'integrite du log #{{ id }}.{% endblock %}
{% block body %}
diff --git a/templates/admin/membres.html.twig b/templates/admin/membres.html.twig
index 7ecd283..e477a84 100644
--- a/templates/admin/membres.html.twig
+++ b/templates/admin/membres.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Administration - Membres - CRM SITECONSEIL{% endblock %}
+{% block title %}Administration - Membres - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/order_number/index.html.twig b/templates/admin/order_number/index.html.twig
index 52ae701..70e7654 100644
--- a/templates/admin/order_number/index.html.twig
+++ b/templates/admin/order_number/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Numerotation - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Numerotation - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/profil/index.html.twig b/templates/admin/profil/index.html.twig
index 6332b03..868aa1b 100644
--- a/templates/admin/profil/index.html.twig
+++ b/templates/admin/profil/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Mon profil - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Mon profil - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/revendeurs/create.html.twig b/templates/admin/revendeurs/create.html.twig
index 9da3ddf..a15ad74 100644
--- a/templates/admin/revendeurs/create.html.twig
+++ b/templates/admin/revendeurs/create.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Nouveau revendeur - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Nouveau revendeur - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/revendeurs/edit.html.twig b/templates/admin/revendeurs/edit.html.twig
index 01f77e9..11b0613 100644
--- a/templates/admin/revendeurs/edit.html.twig
+++ b/templates/admin/revendeurs/edit.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Modifier {{ revendeur.codeRevendeur }} - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Modifier {{ revendeur.codeRevendeur }} - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/revendeurs/index.html.twig b/templates/admin/revendeurs/index.html.twig
index 8a496e4..dcb3000 100644
--- a/templates/admin/revendeurs/index.html.twig
+++ b/templates/admin/revendeurs/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Revendeurs - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Revendeurs - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/services/esyweb.html.twig b/templates/admin/services/esyweb.html.twig
index 7b97ca5..462a4d7 100644
--- a/templates/admin/services/esyweb.html.twig
+++ b/templates/admin/services/esyweb.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Esy-Web - Sites Internet - CRM SITECONSEIL{% endblock %}
+{% block title %}Esy-Web - Sites Internet - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/services/index.html.twig b/templates/admin/services/index.html.twig
index 82dbbf7..19fc4f3 100644
--- a/templates/admin/services/index.html.twig
+++ b/templates/admin/services/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Services - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Services - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/services/ndd.html.twig b/templates/admin/services/ndd.html.twig
index 041a8e3..1cae62c 100644
--- a/templates/admin/services/ndd.html.twig
+++ b/templates/admin/services/ndd.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Noms de domaine - Services - CRM SITECONSEIL{% endblock %}
+{% block title %}Noms de domaine - Services - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/stats/index.html.twig b/templates/admin/stats/index.html.twig
index 13a787f..45f8054 100644
--- a/templates/admin/stats/index.html.twig
+++ b/templates/admin/stats/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Statistiques - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Statistiques - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/status/index.html.twig b/templates/admin/status/index.html.twig
index 0eb6f28..38bfbe7 100644
--- a/templates/admin/status/index.html.twig
+++ b/templates/admin/status/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Status des services - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Status des services - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/status/manage.html.twig b/templates/admin/status/manage.html.twig
index 9d4fad6..bdfbbad 100644
--- a/templates/admin/status/manage.html.twig
+++ b/templates/admin/status/manage.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Gerer les services - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Gerer les services - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/admin/sync/index.html.twig b/templates/admin/sync/index.html.twig
index 4e5c7ac..e406f67 100644
--- a/templates/admin/sync/index.html.twig
+++ b/templates/admin/sync/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Synchronisation - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Synchronisation - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
@@ -115,6 +115,48 @@
+ {# Sync Devis #}
+
+
+
+
+
+
Devis
+
Index Meilisearch : customer_devis
+
{{ totalDevis }} devis en base
+
+
+
+
+
+
+ {# Sync Avis de paiement #}
+
+
+
+
+
+
Avis de paiement
+
Index Meilisearch : customer_advert
+
{{ totalAdverts }} avis en base
+
+
+
+
+
+
{# Sync revendeurs #}
diff --git a/templates/admin/tarification/index.html.twig b/templates/admin/tarification/index.html.twig
index a77172e..069ebd0 100644
--- a/templates/admin/tarification/index.html.twig
+++ b/templates/admin/tarification/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'admin/_layout.html.twig' %}
-{% block title %}Tarification - Administration - CRM SITECONSEIL{% endblock %}
+{% block title %}Tarification - Administration - SARL SITECONSEIL{% endblock %}
{% block admin_content %}
diff --git a/templates/attestation/not_found.html.twig b/templates/attestation/not_found.html.twig
index e539d3c..5710e8a 100644
--- a/templates/attestation/not_found.html.twig
+++ b/templates/attestation/not_found.html.twig
@@ -1,6 +1,6 @@
{% extends 'legal/_layout.html.twig' %}
-{% block title %}Attestation introuvable - CRM SITECONSEIL{% endblock %}
+{% block title %}Attestation introuvable - SARL SITECONSEIL{% endblock %}
{% block body %}
diff --git a/templates/attestation/verify.html.twig b/templates/attestation/verify.html.twig
index 6b4d8a1..5bb39c6 100644
--- a/templates/attestation/verify.html.twig
+++ b/templates/attestation/verify.html.twig
@@ -1,6 +1,6 @@
{% extends 'legal/_layout.html.twig' %}
-{% block title %}Verification attestation {{ attestation.reference }} - CRM SITECONSEIL{% endblock %}
+{% block title %}Verification attestation {{ attestation.reference }} - SARL SITECONSEIL{% endblock %}
{% block description %}Verification de l'attestation RGPD {{ attestation.reference }}.{% endblock %}
{% block body %}
diff --git a/templates/base.html.twig b/templates/base.html.twig
index d6b6e3b..4764639 100644
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -3,7 +3,7 @@
-
{% block title %}CRM SITECONSEIL{% endblock %}
+
{% block title %}SARL SITECONSEIL{% endblock %}
{{ pwa() }}
{% block meta %}
diff --git a/templates/devis/process.html.twig b/templates/devis/process.html.twig
new file mode 100644
index 0000000..9ab228f
--- /dev/null
+++ b/templates/devis/process.html.twig
@@ -0,0 +1,121 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Devis {{ devis.orderNumber.numOrder }} - SARL SITECONSEIL{% endblock %}
+
+{% block body %}
+
+ {% for type, messages in app.flashes %}
+ {% for message in messages %}
+ {{ message }}
+ {% endfor %}
+ {% endfor %}
+
+
+
+
+
Devis
+
{{ devis.orderNumber.numOrder }}
+
Date : {{ devis.createdAt|date('d/m/Y') }}
+
+
+ {% if devis.state == 'accepted' %}
+ Signe
+ {% elseif devis.state == 'refused' %}
+ Refuse
+ {% elseif devis.state == 'cancel' %}
+ Annule
+ {% else %}
+ En attente de signature
+ {% endif %}
+
+
+
+
+
+
Emetteur
+
SARL SITECONSEIL
+
+ 27 rue Le Sérurier
+ 02100 Saint-Quentin, France
+ SIREN 943121517
+
+
+
+
Client
+
{{ customer.fullName }}
+
+ {% if customer.address %}{{ customer.address }} {% endif %}
+ {% if customer.zipCode or customer.city %}{{ customer.zipCode }} {{ customer.city }} {% endif %}
+ {% if customer.email %}{{ customer.email }}{% endif %}
+
+
+
+
+
Detail des prestations
+
+
+
+
+ #
+ Prestation
+ Prix HT
+
+
+
+ {% for line in devis.lines %}
+
+ {{ loop.index }}
+
+ {{ line.title }}
+ {% if line.description %}
+ {{ line.description }}
+ {% endif %}
+
+ {{ line.priceHt }} €
+
+ {% endfor %}
+
+
+
+
+
+
+
+ Total HT
+ {{ devis.totalHt }} €
+
+
+ TVA 20%
+ {{ devis.totalTva }} €
+
+
+ Total TTC
+ {{ devis.totalTtc }} €
+
+
+
+
+
+ {% if devis.state == 'send' %}
+
+ {% endif %}
+
+{% endblock %}
diff --git a/templates/devis/refused.html.twig b/templates/devis/refused.html.twig
new file mode 100644
index 0000000..b84f12d
--- /dev/null
+++ b/templates/devis/refused.html.twig
@@ -0,0 +1,33 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Devis refuse - SARL SITECONSEIL{% endblock %}
+
+{% block body %}
+
+
+
+
+
Devis refuse
+
+ Bonjour {{ customer.firstName }},
+ Votre refus du devis {{ devis.orderNumber.numOrder }} a bien ete enregistre.
+ Notre equipe a ete notifiee et reviendra vers vous si besoin.
+
+
+ {% if devis.raisonMessage %}
+
+
Motif transmis
+
{{ devis.raisonMessage }}
+
+ {% endif %}
+
+
+ Une question ? contact@siteconseil.fr
+
+
+
+{% endblock %}
diff --git a/templates/devis/signed.html.twig b/templates/devis/signed.html.twig
new file mode 100644
index 0000000..9b66747
--- /dev/null
+++ b/templates/devis/signed.html.twig
@@ -0,0 +1,46 @@
+{% extends 'base.html.twig' %}
+
+{% block title %}Devis signe - SARL SITECONSEIL{% endblock %}
+
+{% block body %}
+
+
+
+
+
Merci {{ customer.firstName }} !
+
+ Votre devis {{ devis.orderNumber.numOrder }} a bien ete signe .
+ Notre equipe a ete notifiee et vous recevrez prochainement votre facture par email.
+
+
+
+
+
+
Numero
+
{{ devis.orderNumber.numOrder }}
+
+
+
Date signature
+
{{ "now"|date('d/m/Y') }}
+
+
+
Total HT
+
{{ devis.totalHt }} €
+
+
+
Total TTC
+
{{ devis.totalTtc }} €
+
+
+
+
+
+ Une question ? contact@siteconseil.fr
+
+
+
+{% endblock %}
diff --git a/templates/dns_report/index.html.twig b/templates/dns_report/index.html.twig
index b1c0284..9244603 100644
--- a/templates/dns_report/index.html.twig
+++ b/templates/dns_report/index.html.twig
@@ -1,6 +1,6 @@
{% extends 'base.html.twig' %}
-{% block title %}Rapport DNS - CRM SITECONSEIL{% endblock %}
+{% block title %}Rapport DNS - SARL SITECONSEIL{% endblock %}
{% block header %}
diff --git a/templates/email/base.html.twig b/templates/email/base.html.twig
index 5867f6e..6349d80 100644
--- a/templates/email/base.html.twig
+++ b/templates/email/base.html.twig
@@ -3,7 +3,7 @@
- {% block title %}CRM SITECONSEIL{% endblock %}
+ {% block title %}SARL SITECONSEIL{% endblock %}