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
|
|
|
<?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);
|
|
|
|
|
}
|
test: couverture 83% methodes (1046 tests, 2135 assertions)
Entites completes a 100% :
- AdvertTest : 12 nouveaux (state, customer, totals, hmac, lines, payments)
- CustomerTest : 3 nouveaux (isPendingDelete, revendeurCode, updatedAt)
- DevisTest : 6 nouveaux (customer, submissionId, lines, state constants)
- FactureTest : 10 nouveaux (state, totals, isPaid, lines, hmac, splitIndex)
- OrderNumberTest : 1 nouveau (markAsUnused)
- WebsiteTest : 1 nouveau (revendeurCode)
Services completes/ameliores :
- DocuSealServiceTest : 30 nouveaux (sendDevis, resendDevis, download, compta)
- AdvertServiceTest : 6 nouveaux (isTvaEnabled, getTvaRate, computeTotals)
- DevisServiceTest : 6 nouveaux (idem)
- FactureServiceTest : 8 nouveaux (idem + createPaidFactureFromAdvert)
- MailerServiceTest : 7 nouveaux (unsubscribe headers, VCF, formatFileSize)
- MeilisearchServiceTest : 42 nouveaux (index/remove/search tous types)
- RgpdServiceTest : 6 nouveaux (sendVerificationCode, verifyCode)
- OrderNumberServiceTest : 2 nouveaux (preview/generate unused)
- TarificationServiceTest : 1 nouveau (stripe error logger)
- ComptaPdfTest : 4 nouveaux (totaux, colonnes numeriques, signature)
- FacturePdfTest : 6 nouveaux (QR code, RIB, CGV Twig, footer skip)
Controllers ameliores :
- ComptabiliteControllerTest : 13 nouveaux (JSON, PDF, sign, callback)
- StatsControllerTest : 2 nouveaux (rich data, 6-month evolution)
- SyncControllerTest : 13 nouveaux (sync 6 types + purge)
- ClientsControllerTest : 7 nouveaux (show, delete, resendWelcome)
- FactureControllerTest : 2 nouveaux (generatePdf 404, send success)
- LegalControllerTest : 6 nouveaux (rgpdVerify GET/POST)
- TarificationControllerTest : 3 nouveaux (purge paths)
- AdminControllersTest : 9 nouveaux (dashboard search, services)
- WebhookStripeControllerTest : 3 nouveaux (invalid signatures)
- KeycloakAuthenticatorTest : 4 nouveaux (groups, domain check)
Commands :
- PaymentReminderCommandTest : 1 nouveau (formalNotice step)
- TestMailCommandTest : 2 nouveaux (force-dsn success/failure)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 00:13:00 +02:00
|
|
|
|
|
|
|
|
public function testGenerateWithQrCodeProducesValidPdf(): void
|
|
|
|
|
{
|
|
|
|
|
$facture = $this->makeFacture('04/2026-00010');
|
|
|
|
|
$facture->setTotalHt('50.00');
|
|
|
|
|
$facture->setTotalTva('0.00');
|
|
|
|
|
$facture->setTotalTtc('50.00');
|
|
|
|
|
|
|
|
|
|
$urlGenerator = $this->createStub(\Symfony\Component\Routing\Generator\UrlGeneratorInterface::class);
|
|
|
|
|
$urlGenerator->method('generate')->willReturn('https://crm.e-cosplay.fr/facture/verify/1/abc123');
|
|
|
|
|
|
|
|
|
|
$line = new FactureLine($facture, 'Service QR', '50.00', 1);
|
|
|
|
|
$facture->getLines()->add($line);
|
|
|
|
|
|
|
|
|
|
$pdf = new FacturePdf($this->kernel, $facture, $urlGenerator);
|
|
|
|
|
$pdf->generate();
|
|
|
|
|
|
|
|
|
|
$output = $pdf->Output('S');
|
|
|
|
|
|
|
|
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGenerateWithRibFileProducesValidPdf(): void
|
|
|
|
|
{
|
|
|
|
|
// Create a minimal valid PDF as the RIB file
|
|
|
|
|
$ribDir = $this->projectDir . '/public';
|
|
|
|
|
if (!is_dir($ribDir)) {
|
|
|
|
|
mkdir($ribDir, 0775, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a minimal PDF file for RIB using FPDI itself
|
|
|
|
|
$miniPdf = new \setasign\Fpdi\Fpdi();
|
|
|
|
|
$miniPdf->AddPage();
|
|
|
|
|
$ribPath = $ribDir . '/rib.pdf';
|
|
|
|
|
$miniPdf->Output('F', $ribPath);
|
|
|
|
|
|
|
|
|
|
$facture = $this->makeFacture('04/2026-00011');
|
|
|
|
|
$facture->setTotalHt('75.00');
|
|
|
|
|
$facture->setTotalTva('0.00');
|
|
|
|
|
$facture->setTotalTtc('75.00');
|
|
|
|
|
|
|
|
|
|
$line = new FactureLine($facture, 'Service RIB', '75.00', 1);
|
|
|
|
|
$facture->getLines()->add($line);
|
|
|
|
|
|
|
|
|
|
$pdf = new FacturePdf($this->kernel, $facture);
|
|
|
|
|
$pdf->generate();
|
|
|
|
|
|
|
|
|
|
$output = $pdf->Output('S');
|
|
|
|
|
|
|
|
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGenerateWithTwigAppendsCgvProducesValidPdf(): void
|
|
|
|
|
{
|
|
|
|
|
$facture = $this->makeFacture('04/2026-00012');
|
|
|
|
|
$facture->setTotalHt('80.00');
|
|
|
|
|
$facture->setTotalTva('0.00');
|
|
|
|
|
$facture->setTotalTtc('80.00');
|
|
|
|
|
|
|
|
|
|
$line = new FactureLine($facture, 'Service Twig', '80.00', 1);
|
|
|
|
|
$facture->getLines()->add($line);
|
|
|
|
|
|
|
|
|
|
// Create a mock Twig environment that returns minimal HTML for CGV
|
|
|
|
|
$twig = $this->createStub(\Twig\Environment::class);
|
|
|
|
|
$twig->method('render')->willReturn('<html><body><p>Conditions Generales de Vente</p></body></html>');
|
|
|
|
|
|
|
|
|
|
$pdf = new FacturePdf($this->kernel, $facture, null, $twig);
|
|
|
|
|
$pdf->generate();
|
|
|
|
|
|
|
|
|
|
$output = $pdf->Output('S');
|
|
|
|
|
|
|
|
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testGenerateWithCustomerNoAddress(): void
|
|
|
|
|
{
|
|
|
|
|
$facture = $this->makeFacture('04/2026-00013');
|
|
|
|
|
|
|
|
|
|
$customer = $this->createStub(\App\Entity\Customer::class);
|
|
|
|
|
$customer->method('getFullName')->willReturn('Jean Dupont');
|
|
|
|
|
$customer->method('getRaisonSociale')->willReturn(null);
|
|
|
|
|
$customer->method('getEmail')->willReturn('jean@example.com');
|
|
|
|
|
$customer->method('getAddress')->willReturn(null); // No address
|
|
|
|
|
$customer->method('getAddress2')->willReturn(null);
|
|
|
|
|
$customer->method('getZipCode')->willReturn(null);
|
|
|
|
|
$customer->method('getCity')->willReturn(null);
|
|
|
|
|
$facture->setCustomer($customer);
|
|
|
|
|
|
|
|
|
|
$pdf = new FacturePdf($this->kernel, $facture);
|
|
|
|
|
$pdf->generate();
|
|
|
|
|
|
|
|
|
|
$output = $pdf->Output('S');
|
|
|
|
|
|
|
|
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testFooterOnCgvPageSkipsFooter(): void
|
|
|
|
|
{
|
|
|
|
|
// Test that skipHeaderFooter=true makes Footer skip on pages after the last facture page
|
|
|
|
|
$facture = $this->makeFacture('04/2026-00014');
|
|
|
|
|
$facture->setTotalHt('30.00');
|
|
|
|
|
$facture->setTotalTva('0.00');
|
|
|
|
|
$facture->setTotalTtc('30.00');
|
|
|
|
|
|
|
|
|
|
$twig = $this->createStub(\Twig\Environment::class);
|
|
|
|
|
$twig->method('render')->willReturn('<html><body><p>CGV page 1</p></body></html>');
|
|
|
|
|
|
|
|
|
|
$pdf = new FacturePdf($this->kernel, $facture, null, $twig);
|
|
|
|
|
$pdf->generate();
|
|
|
|
|
|
|
|
|
|
$output = $pdf->Output('S');
|
|
|
|
|
$this->assertStringStartsWith('%PDF', $output);
|
|
|
|
|
}
|
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
|
|
|
}
|