createStub(EntityManagerInterface::class); $query = $this->getMockBuilder(Query::class) ->setConstructorArgs([$stubEm]) ->onlyMethods(['getResult', '_doExecute', 'getSQL']) ->getMock(); $query->method('getResult')->willReturn([]); $qb = $this->createStub(QueryBuilder::class); $qb->method('select')->willReturnSelf(); $qb->method('from')->willReturnSelf(); $qb->method('where')->willReturnSelf(); $qb->method('andWhere')->willReturnSelf(); $qb->method('setParameter')->willReturnSelf(); $qb->method('orderBy')->willReturnSelf(); $qb->method('getQuery')->willReturn($query); $em = $this->createStub(EntityManagerInterface::class); $em->method('createQueryBuilder')->willReturn($qb); return $em; } private function buildKernel(): KernelInterface { $tmpDir = sys_get_temp_dir().'/comptabilite_test_'.uniqid(); mkdir($tmpDir.'/public', 0777, true); // logo.jpg is optional — ComptaPdf checks file_exists before using it $kernel = $this->createStub(KernelInterface::class); $kernel->method('getProjectDir')->willReturn($tmpDir); return $kernel; } /** * Build a controller wired with a user token and a router that returns non-empty paths. * Required for methods that call getUser() and generateUrl()/redirectToRoute(). */ private function buildSignController(): \App\Controller\Admin\ComptabiliteController { $em = $this->buildEmWithQueryBuilder(); $kernel = $this->buildKernel(); $controller = new \App\Controller\Admin\ComptabiliteController($em, $kernel, false, 'http://docuseal.example'); $session = new Session(new MockArraySessionStorage()); $stack = $this->createStub(RequestStack::class); $stack->method('getSession')->willReturn($session); $twig = $this->createStub(\Twig\Environment::class); $twig->method('render')->willReturn(''); $router = $this->createStub(\Symfony\Component\Routing\RouterInterface::class); $router->method('generate')->willReturn('/admin/comptabilite'); $user = new User(); $user->setEmail('admin@e-cosplay.fr'); $user->setFirstName('Admin'); $user->setLastName('Test'); $user->setPassword('h'); $token = $this->createStub(TokenInterface::class); $token->method('getUser')->willReturn($user); $tokenStorage = $this->createStub(TokenStorageInterface::class); $tokenStorage->method('getToken')->willReturn($token); $container = $this->createStub(ContainerInterface::class); $container->method('has')->willReturnMap([ ['twig', true], ['router', true], ['security.authorization_checker', true], ['security.token_storage', true], ['request_stack', true], ['parameter_bag', true], ['serializer', false], ]); $container->method('get')->willReturnMap([ ['twig', $twig], ['router', $router], ['security.authorization_checker', $this->createStub(AuthorizationCheckerInterface::class)], ['security.token_storage', $tokenStorage], ['request_stack', $stack], ['parameter_bag', $this->createStub(ParameterBagInterface::class)], ]); $controller->setContainer($container); return $controller; } private function buildController(): ComptabiliteController { $em = $this->buildEmWithQueryBuilder(); $kernel = $this->buildKernel(); $controller = new ComptabiliteController($em, $kernel, false, 'http://docuseal.example'); $session = new Session(new MockArraySessionStorage()); $stack = $this->createStub(RequestStack::class); $stack->method('getSession')->willReturn($session); $twig = $this->createStub(Environment::class); $twig->method('render')->willReturn(''); $container = $this->createStub(ContainerInterface::class); $container->method('has')->willReturnMap([ ['twig', true], ['router', true], ['security.authorization_checker', true], ['security.token_storage', true], ['request_stack', true], ['parameter_bag', true], ['serializer', false], ]); $container->method('get')->willReturnMap([ ['twig', $twig], ['router', $this->createStub(RouterInterface::class)], ['security.authorization_checker', $this->createStub(AuthorizationCheckerInterface::class)], ['security.token_storage', $this->createStub(TokenStorageInterface::class)], ['request_stack', $stack], ['parameter_bag', $this->createStub(ParameterBagInterface::class)], ]); $controller->setContainer($container); return $controller; } public function testIndexReturns200(): void { $controller = $this->buildController(); $response = $controller->index(); $this->assertSame(200, $response->getStatusCode()); } public function testExportJournalVentesCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportJournalVentes($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportJournalVentesJson(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'json']); $response = $controller->exportJournalVentes($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportJournalVentesPreviousPeriod(): void { $controller = $this->buildController(); $request = new Request(['period' => 'previous', 'format' => 'csv']); $response = $controller->exportJournalVentes($request); $this->assertSame(200, $response->getStatusCode()); } public function testExportJournalVentesCustomPeriod(): void { $controller = $this->buildController(); $request = new Request(['period' => 'custom', 'from' => '2026-01-01', 'to' => '2026-03-31', 'format' => 'csv']); $response = $controller->exportJournalVentes($request); $this->assertSame(200, $response->getStatusCode()); } public function testExportCommissionsStripeCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportCommissionsStripe($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportCommissionsStripeJson(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'json']); $response = $controller->exportCommissionsStripe($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportCoutsServicesCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportCoutsServices($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportPdfJournalVentes(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('journal-ventes', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfCommissionsStripe(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('commissions-stripe', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfCoutsServices(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('couts-services', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfBalanceAgee(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('balance-agee', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testRapportFinancierReturnsPdf(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->rapportFinancier($request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testRapportFinancierPreviousPeriod(): void { $controller = $this->buildController(); $request = new Request(['period' => 'previous']); $response = $controller->rapportFinancier($request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportGrandLivreCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportGrandLivre($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportFecCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportFec($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportBalanceAgeeCsv(): void { $controller = $this->buildController(); $request = new Request(['format' => 'csv']); $response = $controller->exportBalanceAgee($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportReglementsCsv(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'csv']); $response = $controller->exportReglements($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('text/csv', $contentType); } public function testExportGrandLivreJson(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'json']); $response = $controller->exportGrandLivre($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportFecJson(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'json']); $response = $controller->exportFec($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportBalanceAgeeJson(): void { $controller = $this->buildController(); $request = new Request(['format' => 'json']); $response = $controller->exportBalanceAgee($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportReglementsJson(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current', 'format' => 'json']); $response = $controller->exportReglements($request); $this->assertSame(200, $response->getStatusCode()); $contentType = $response->headers->get('Content-Type') ?? ''; $this->assertStringContainsString('application/json', $contentType); } public function testExportPdfFec(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('fec', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfGrandLivre(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('grand-livre', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfReglements(): void { $controller = $this->buildController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdf('reglements', $request); $this->assertSame(200, $response->getStatusCode()); $this->assertSame('application/pdf', $response->headers->get('Content-Type')); } public function testExportPdfSignRedirectsToDocuSeal(): void { $docuSeal = $this->createStub(\App\Service\DocuSealService::class); $docuSeal->method('sendComptaForSignature')->willReturn(42); $docuSeal->method('getSubmitterSlug')->willReturn('abc123'); $controller = $this->buildSignController(); $request = new Request(['period' => 'current']); $session = new Session(new MockArraySessionStorage()); $request->setSession($session); $response = $controller->exportPdfSign('journal-ventes', $request, $docuSeal); $this->assertSame(302, $response->getStatusCode()); $this->assertStringContainsString('docuseal.example', $response->headers->get('Location') ?? ''); } public function testExportPdfSignDocuSealNoSlug(): void { $docuSeal = $this->createStub(\App\Service\DocuSealService::class); $docuSeal->method('sendComptaForSignature')->willReturn(42); $docuSeal->method('getSubmitterSlug')->willReturn(null); $controller = $this->buildSignController(); $request = new Request(['period' => 'current']); $response = $controller->exportPdfSign('journal-ventes', $request, $docuSeal); // No slug -> redirect to index $this->assertSame(302, $response->getStatusCode()); } public function testSignCallbackWithNoSession(): void { $controller = $this->buildSignController(); $request = new Request(); $session = new Session(new MockArraySessionStorage()); $request->setSession($session); $docuSeal = $this->createStub(\App\Service\DocuSealService::class); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(\Twig\Environment::class); // No submitter_id in session -> "Session de signature expiree" $response = $controller->signCallback('journal-ventes', $request, $docuSeal, $mailer, $twig); $this->assertSame(302, $response->getStatusCode()); } public function testSignCallbackWithSessionNoPdf(): void { $controller = $this->buildSignController(); $request = new Request(); $session = new Session(new MockArraySessionStorage()); $session->set('compta_submitter_id', 99); $request->setSession($session); $docuSeal = $this->createStub(\App\Service\DocuSealService::class); $docuSeal->method('getSubmitterData')->willReturn([ 'documents' => [], 'audit_log_url' => null, 'metadata' => [], ]); $mailer = $this->createStub(\App\Service\MailerService::class); $twig = $this->createStub(\Twig\Environment::class); $twig->method('render')->willReturn(''); $response = $controller->signCallback('journal-ventes', $request, $docuSeal, $mailer, $twig); $this->assertSame(302, $response->getStatusCode()); } public function testRapportFinancierSignRedirects(): void { $docuSeal = $this->createStub(\App\Service\DocuSealService::class); $docuSeal->method('sendComptaForSignature')->willReturn(10); $docuSeal->method('getSubmitterSlug')->willReturn('slug-rap'); $controller = $this->buildSignController(); $request = new Request(['period' => 'current']); $session = new Session(new MockArraySessionStorage()); $request->setSession($session); $response = $controller->rapportFinancierSign($request, $docuSeal); $this->assertSame(302, $response->getStatusCode()); } }