feat: generate draft assignments from a staffing matrix

This commit is contained in:
fromme committed 2026-10-15 18:11:51 +02:00
1 parent 3116d23199
commit 2fc9806c69
41 files changed
+2618

No files matched your search

@@ -0,0 +1,118 @@
<?php
declare(strict_types=1);
namespace App\Tests\Command;
use App\Entity\Assignment;
use App\Tests\Service\Assignment\StaffingFixturesTrait;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Tester\CommandTester;
/**
* End to end against db_test: the matrix, the import's columns, the configured ids and the
* "never twice" rule have to agree, which no unit test can show.
*/
class AssignmentGenerateCommandTest extends KernelTestCase
{
use StaffingFixturesTrait;
private EntityManagerInterface $entityManager;
private CommandTester $tester;
protected function setUp(): void
{
self::bootKernel();
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
$this->resetStaffingTables(self::getContainer()->get(Connection::class));
$this->tester = new CommandTester((new Application(self::$kernel))->find('app:assignment-generate'));
}
public function testDraftsAreCreatedForEnabledRowsOnly(): void
{
$this->staffingRule($this->entityManager, 'DKIMP');
$this->staffingRule($this->entityManager, 'DGSMP', enabled: false);
$destination = $this->staffingDestination($this->entityManager, 'DKIMP110127', 'DKIMP');
$this->staffingDestination($this->entityManager, 'DGSMP110127', 'DGSMP');
$this->entityManager->flush();
$this->assertSame(Command::SUCCESS, $this->tester->execute([]));
$assignments = $this->assignments();
$this->assertCount(2, $assignments);
[$guide, $course] = $assignments;
$this->assertSame($destination->getId(), $guide->getDestination()->getId());
$this->assertSame('Reiseleitung', $guide->getJobProfile()->getName());
$this->assertSame(2, $guide->getAvailableDispositions());
$this->assertSame(5, $guide->getPickup());
$this->assertSame(['Skigebietsguiding (pro Einheit)'], $guide->getFees()->map(static fn ($fee) => $fee->getName())->toArray());
$this->assertSame(Assignment::STATUS_DRAFT, $guide->getStatus());
$this->assertSame('system', $guide->getCreatedBy());
$this->assertSame('Kursleitung Ski Anfänger:innen', $course->getJobProfile()->getName());
$this->assertSame(0, $course->getPickup());
}
public function testADeletedDraftIsNotCreatedAgain(): void
{
$this->staffingRule($this->entityManager, 'DKIMP');
$this->staffingDestination($this->entityManager, 'DKIMP110127', 'DKIMP');
$this->entityManager->flush();
$this->tester->execute([]);
foreach ($this->assignments() as $assignment) {
$assignment->setDeleted();
}
$this->entityManager->flush();
$this->tester->execute([]);
$this->assertStringContainsString('davon 1 schon mit Einsätzen', $this->tester->getDisplay());
$this->assertCount(2, $this->assignments());
}
public function testADryRunWritesNothing(): void
{
$this->staffingRule($this->entityManager, 'DKIMP');
$this->staffingDestination($this->entityManager, 'DKIMP110127', 'DKIMP');
$this->entityManager->flush();
$this->assertSame(Command::SUCCESS, $this->tester->execute(['--dry-run' => true]));
$this->assertStringContainsString('2× Reiseleitung (Busbegleitung)', $this->tester->getDisplay());
$this->assertCount(0, $this->assignments());
}
public function testAMissingJobProfileStopsTheRunBeforeItWrites(): void
{
$this->staffingRule($this->entityManager, 'DKIMP');
$this->staffingDestination($this->entityManager, 'DKIMP110127', 'DKIMP');
$this->entityManager->flush();
self::getContainer()->get(Connection::class)->executeStatement('UPDATE job_profile SET deleted_at = NOW() WHERE id = 21');
$this->assertSame(Command::FAILURE, $this->tester->execute([]));
$this->assertCount(0, $this->assignments());
}
/**
* @return list<Assignment>
*/
private function assignments(): array
{
$this->entityManager->clear();
return $this->entityManager->getRepository(Assignment::class)->findBy([], ['id' => 'ASC']);
}
}