b444061237
Commande console app:qualimat:sync : récupère les opérateurs de transport agréés depuis l'API publique qualimat.org, normalise et synchronise une table référentielle (upsert sur le SIRET + soft-delete des absents + journal). Prévue pour un cron quotidien. - migration : tables qualimat_carrier + qualimat_sync_log (COMMENT ON COLUMN sur chaque colonne) - QualimatRowMapper : normalisation pure (SIRET sans espaces, date dd/mm/yyyy -> ISO, skip sans SIRET) + tests unitaires - SyncQualimatCommand : options --file / --ppp / --dry-run, upsert DBAL transactionnel - activation de framework.http_client - tests fonctionnels de la commande (upsert/normalisation/journal/soft-delete)
139 lines
5.4 KiB
PHP
139 lines
5.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Module\Transport\Infrastructure\Console;
|
|
|
|
use Doctrine\DBAL\Connection;
|
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
|
|
|
use const JSON_THROW_ON_ERROR;
|
|
|
|
/**
|
|
* Test fonctionnel de `app:qualimat:sync` via l'option --file (pas d'appel
|
|
* reseau) : verifie l'upsert normalise, le journal et le soft-delete.
|
|
*
|
|
* @internal
|
|
*/
|
|
final class SyncQualimatCommandTest extends KernelTestCase
|
|
{
|
|
private Connection $connection;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
self::bootKernel();
|
|
|
|
/** @var Connection $connection */
|
|
$connection = self::getContainer()->get('doctrine.dbal.default_connection');
|
|
$this->connection = $connection;
|
|
$this->purge();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->purge();
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testFirstSyncInsertsNormalizesAndLogs(): void
|
|
{
|
|
$tester = $this->runSync([
|
|
[
|
|
'Nom' => '2C TRANS',
|
|
'Societe' => '2C TRANS',
|
|
'Adresse' => '66 Impasse Mendi',
|
|
'CodePostal' => '65500',
|
|
'Ville' => 'VIC EN BIGORRE',
|
|
'Telephone_1' => '+33|0608890316',
|
|
'Siret' => '444 156 285 000 25',
|
|
'Validite' => '14/05/2027',
|
|
'Statut' => 'Audité',
|
|
'Departement' => '65 - Hautes-Pyrénées',
|
|
],
|
|
// Item sans SIRET : doit etre ignore (compte dans rows_skipped).
|
|
['Nom' => 'SANS SIRET', 'Siret' => null, 'Validite' => '01/01/2030', 'Statut' => 'Valide'],
|
|
]);
|
|
|
|
$tester->assertCommandIsSuccessful();
|
|
|
|
self::assertSame(1, $this->countRows('SELECT COUNT(*) FROM qualimat_carrier'));
|
|
|
|
$row = $this->connection->fetchAssociative('SELECT * FROM qualimat_carrier');
|
|
self::assertNotFalse($row);
|
|
self::assertSame('44415628500025', $row['siret']);
|
|
self::assertSame('2C TRANS', $row['name']);
|
|
self::assertSame('2027-05-14', $row['validity_date']);
|
|
self::assertSame('+33|0608890316', $row['phone']);
|
|
self::assertSame(1, $this->countRows('SELECT COUNT(*) FROM qualimat_carrier WHERE is_active = TRUE'));
|
|
|
|
$log = $this->connection->fetchAssociative('SELECT * FROM qualimat_sync_log ORDER BY id DESC LIMIT 1');
|
|
self::assertNotFalse($log);
|
|
self::assertSame(2, (int) $log['rows_total']);
|
|
self::assertSame(1, (int) $log['rows_upserted']);
|
|
self::assertSame(1, (int) $log['rows_skipped']);
|
|
self::assertSame(0, (int) $log['rows_deactivated']);
|
|
}
|
|
|
|
public function testSecondSyncUpdatesAndSoftDeletesMissing(): void
|
|
{
|
|
$a = ['Nom' => 'A', 'Siret' => '111 111 111 00011', 'Validite' => '01/01/2030', 'Statut' => 'Audité'];
|
|
$b = ['Nom' => 'B', 'Siret' => '222 222 222 00022', 'Validite' => '01/01/2030', 'Statut' => 'Audité'];
|
|
|
|
$this->runSync([$a, $b])->assertCommandIsSuccessful();
|
|
self::assertSame(2, $this->countRows('SELECT COUNT(*) FROM qualimat_carrier WHERE is_active = TRUE'));
|
|
|
|
// 2e run sans B et avec A renomme : A est mis a jour, B est soft-delete.
|
|
$aRenamed = ['Nom' => 'A BIS', 'Siret' => '111 111 111 00011', 'Validite' => '02/02/2031', 'Statut' => 'Valide'];
|
|
$tester = $this->runSync([$aRenamed]);
|
|
$tester->assertCommandIsSuccessful();
|
|
|
|
// Toujours 2 lignes en base, mais une seule active.
|
|
self::assertSame(2, $this->countRows('SELECT COUNT(*) FROM qualimat_carrier'));
|
|
self::assertSame(1, $this->countRows('SELECT COUNT(*) FROM qualimat_carrier WHERE is_active = TRUE'));
|
|
self::assertSame(1, $this->countRows("SELECT COUNT(*) FROM qualimat_carrier WHERE siret = '22222222200022' AND is_active = FALSE"));
|
|
|
|
// A a bien ete mis a jour (nom + statut + date).
|
|
$a = $this->connection->fetchAssociative("SELECT * FROM qualimat_carrier WHERE siret = '11111111100011'");
|
|
self::assertNotFalse($a);
|
|
self::assertSame('A BIS', $a['name']);
|
|
self::assertSame('Valide', $a['status']);
|
|
self::assertSame('2031-02-02', $a['validity_date']);
|
|
|
|
$log = $this->connection->fetchAssociative('SELECT * FROM qualimat_sync_log ORDER BY id DESC LIMIT 1');
|
|
self::assertNotFalse($log);
|
|
self::assertSame(1, (int) $log['rows_upserted']);
|
|
self::assertSame(1, (int) $log['rows_deactivated']);
|
|
self::assertSame(0, (int) $log['rows_skipped']);
|
|
}
|
|
|
|
/**
|
|
* @param array<int, array<string, mixed>> $items
|
|
*/
|
|
private function runSync(array $items): CommandTester
|
|
{
|
|
$path = tempnam(sys_get_temp_dir(), 'qualimat_').'.json';
|
|
file_put_contents($path, json_encode($items, JSON_THROW_ON_ERROR));
|
|
|
|
$application = new Application(self::$kernel);
|
|
$tester = new CommandTester($application->find('app:qualimat:sync'));
|
|
$tester->execute(['--file' => $path]);
|
|
|
|
@unlink($path);
|
|
|
|
return $tester;
|
|
}
|
|
|
|
private function countRows(string $sql): int
|
|
{
|
|
return (int) $this->connection->fetchOne($sql);
|
|
}
|
|
|
|
private function purge(): void
|
|
{
|
|
$this->connection->executeStatement('DELETE FROM qualimat_carrier');
|
|
$this->connection->executeStatement('DELETE FROM qualimat_sync_log');
|
|
}
|
|
}
|