Files
crm_ecosplay/tests/Service/Pdf/FacturePdfTest.php
Serreau Jovann 79c55ba0f9 test: ajout 163 tests unitaires (668->831) avec couverture 73%
Entites (76 tests) :
- PrestataireTest : constructeur, setters, getFullAddress, getTotalPaidHt
- FacturePrestataireTest : constructeur, getPeriodLabel 12 mois, Vich upload
- AdvertPaymentTest : constructeur, types constants, method
- AdvertEventTest : constructeur, getTypeLabel, 5 types + fallback
- FactureLineTest : constructeur, setters, optionnels nullable
- ActionLogTest : constructeur, 10 action constants, severity
- PaymentReminderTest : 8 steps, getStepLabel, getSeverity
- DocusealEventTest : constructeur, nullable fields

Commands (16 tests) :
- ReminderFacturesPrestataireCommandTest : 6 scenarios (aucun presta,
  tous OK, factures manquantes, SIRET vide, mois different)
- PaymentReminderCommandTest : 10 scenarios (skip recent, J+15 emails,
  suspension, termination, exception handling)

Services PDF (24 tests) :
- ComptaPdfTest : empty/FEC/multi-page, totaux Debit/Credit
- RapportFinancierPdfTest : recettes/depenses, bilan equilibre/deficit/excedent
- FacturePdfTest : lignes, TVA, customer address, paid badge, multi-page

Controllers (47 tests) :
- ComptabiliteControllerTest : 18 tests (index, 7 exports CSV, 2 JSON,
  4 PDF, 2 rapport financier)
- PrestatairesControllerTest : 19 tests (CRUD, factures, SIRET proxy)
- FactureControllerTest : 6 tests (search, send)
- FactureVerifyControllerTest : 4 tests (HMAC valid/invalid/not found)

Couverture : 51%->60% classes, 58%->73% methodes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 23:57:42 +02:00

231 lines
7.6 KiB
PHP

<?php
namespace App\Tests\Service\Pdf;
use App\Entity\Facture;
use App\Entity\FactureLine;
use App\Entity\OrderNumber;
use App\Service\Pdf\FacturePdf;
use Doctrine\Common\Collections\ArrayCollection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\KernelInterface;
class FacturePdfTest extends TestCase
{
private const HMAC_SECRET = 'test-hmac-secret';
private KernelInterface $kernel;
private string $projectDir;
protected function setUp(): void
{
$this->projectDir = sys_get_temp_dir().'/facture-pdf-test-'.bin2hex(random_bytes(4));
mkdir($this->projectDir.'/public', 0775, true);
$this->kernel = $this->createStub(KernelInterface::class);
$this->kernel->method('getProjectDir')->willReturn($this->projectDir);
}
protected function tearDown(): void
{
$this->removeDir($this->projectDir);
}
private function removeDir(string $dir): void
{
if (!is_dir($dir)) {
return;
}
foreach (scandir($dir) as $item) {
if ('.' === $item || '..' === $item) {
continue;
}
$path = $dir.'/'.$item;
is_dir($path) ? $this->removeDir($path) : unlink($path);
}
rmdir($dir);
}
private function makeFacture(string $numOrder = '04/2026-00001'): Facture
{
$orderNumber = new OrderNumber($numOrder);
return new Facture($orderNumber, self::HMAC_SECRET);
}
private function makeCustomer(bool $withRaisonSociale = false, bool $withAddress2 = false): \App\Entity\Customer
{
$customer = $this->createStub(\App\Entity\Customer::class);
$customer->method('getFullName')->willReturn('Jean Dupont');
$customer->method('getRaisonSociale')->willReturn($withRaisonSociale ? 'ACME SARL' : null);
$customer->method('getEmail')->willReturn('jean.dupont@example.com');
$customer->method('getAddress')->willReturn('42 rue des Tests');
$customer->method('getAddress2')->willReturn($withAddress2 ? 'Batiment B, etage 3' : null);
$customer->method('getZipCode')->willReturn('75001');
$customer->method('getCity')->willReturn('Paris');
return $customer;
}
public function testGenerateEmptyFactureProducesValidPdf(): void
{
$facture = $this->makeFacture();
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithLinesProducesValidPdf(): void
{
$facture = $this->makeFacture();
$facture->setTotalHt('100.00');
$facture->setTotalTva('0.00');
$facture->setTotalTtc('100.00');
$line1 = new FactureLine($facture, 'Hebergement Web', '60.00', 1);
$line1->setDescription('Hebergement annuel mutualisé');
$line2 = new FactureLine($facture, 'Nom de domaine', '40.00', 2);
$line2->setDescription('Renouvellement .fr annuel');
$facture->getLines()->add($line1);
$facture->getLines()->add($line2);
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
$this->assertGreaterThan(1000, \strlen($output));
}
public function testGenerateWithCustomerAddressProducesValidPdf(): void
{
$facture = $this->makeFacture();
$facture->setCustomer($this->makeCustomer(false, false));
$facture->setTotalHt('50.00');
$facture->setTotalTva('0.00');
$facture->setTotalTtc('50.00');
$line = new FactureLine($facture, 'Service test', '50.00', 1);
$facture->getLines()->add($line);
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithTvaProducesValidPdf(): void
{
$facture = $this->makeFacture();
$facture->setTotalHt('100.00');
$facture->setTotalTva('20.00');
$facture->setTotalTtc('120.00');
$line = new FactureLine($facture, 'Prestation avec TVA', '100.00', 1);
$facture->getLines()->add($line);
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithPaidFactureProducesValidPdf(): void
{
$facture = $this->makeFacture();
$facture->setTotalHt('200.00');
$facture->setTotalTva('0.00');
$facture->setTotalTtc('200.00');
$facture->setIsPaid(true);
$facture->setPaidAt(new \DateTimeImmutable('2026-02-15'));
$facture->setPaidMethod('Virement');
$line = new FactureLine($facture, 'Service payé', '200.00', 1);
$facture->getLines()->add($line);
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithLogoFileProducesValidPdf(): void
{
// Minimal valid 1x1 JPEG
$jpegData = base64_decode('/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAACf/EABQQAQAAAAAAAAAAAAAAAAAAAAD/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AJQAB/9k=');
file_put_contents($this->projectDir.'/public/logo.jpg', $jpegData);
$facture = $this->makeFacture();
$line = new FactureLine($facture, 'Test', '10.00', 1);
$facture->getLines()->add($line);
$facture->setTotalHt('10.00');
$facture->setTotalTva('0.00');
$facture->setTotalTtc('10.00');
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithManyLinesSpansMultiplePages(): void
{
$facture = $this->makeFacture();
$facture->setTotalHt('1500.00');
$facture->setTotalTva('0.00');
$facture->setTotalTtc('1500.00');
for ($i = 1; $i <= 15; ++$i) {
$line = new FactureLine($facture, 'Service '.$i, '100.00', $i);
$line->setDescription('Description detaillee pour le service numero '.$i.' avec quelques mots supplementaires.');
$facture->getLines()->add($line);
}
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithCustomerRaisonSocialeProducesValidPdf(): void
{
$facture = $this->makeFacture();
$facture->setCustomer($this->makeCustomer(true, true));
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
public function testGenerateWithSplitIndexProducesValidPdf(): void
{
$facture = $this->makeFacture('04/2026-00002');
$facture->setSplitIndex(2);
$pdf = new FacturePdf($this->kernel, $facture);
$pdf->generate();
$output = $pdf->Output('S');
$this->assertStringStartsWith('%PDF', $output);
}
}