refactor: derive the bus escort from the travel date
This commit is contained in:
1 parent
2fc9806c69
commit
0e2021e96d
9 files changed
+59
-50
No files matched your search
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Drops the staffing matrix's Busbegleitung flag.
|
||||
*
|
||||
* Whether a date gets a bus escort follows from the date itself: one with boarding points has
|
||||
* bus travel, and App\Service\Assignment\AssignmentPlanner pre-selects the first of them. A flag
|
||||
* per product could only repeat that, and less precisely, since bus travel varies between the
|
||||
* dates of one product.
|
||||
*
|
||||
* Written by hand rather than taken from doctrine:migrations:diff, which also carries the
|
||||
* pre-existing drift of the dev database.
|
||||
*/
|
||||
final class Version20261016090000 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Drop staffing_rule.bus_escort';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE staffing_rule DROP bus_escort');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE staffing_rule ADD bus_escort TINYINT NOT NULL');
|
||||
}
|
||||
}
|
||||
@@ -62,9 +62,6 @@ class StaffingRule implements BlameableEntityInterface, TimestampableEntityInter
|
||||
#[ORM\Column]
|
||||
private bool $guiding = false;
|
||||
|
||||
#[ORM\Column]
|
||||
private bool $busEscort = false;
|
||||
|
||||
/** Previewed either way; only enabled rows generate. */
|
||||
#[ORM\Column]
|
||||
private bool $enabled = false;
|
||||
@@ -102,14 +99,6 @@ class StaffingRule implements BlameableEntityInterface, TimestampableEntityInter
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
|
||||
if (true === $this->busEscort && 0 === (int) $this->guides) {
|
||||
$context
|
||||
->buildViolation('Busbegleitung braucht mindestens eine Reiseleitung')
|
||||
->atPath('busEscort')
|
||||
->addViolation()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public function getSkiLevelCount(): int
|
||||
@@ -200,18 +189,6 @@ class StaffingRule implements BlameableEntityInterface, TimestampableEntityInter
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isBusEscort(): bool
|
||||
{
|
||||
return $this->busEscort;
|
||||
}
|
||||
|
||||
public function setBusEscort(bool $busEscort): static
|
||||
{
|
||||
$this->busEscort = $busEscort;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
|
||||
@@ -40,10 +40,6 @@ class StaffingRuleType extends AbstractType
|
||||
'label' => 'Guiding',
|
||||
'required' => false,
|
||||
])
|
||||
->add('busEscort', CheckboxType::class, [
|
||||
'label' => 'Busbegleitung',
|
||||
'required' => false,
|
||||
])
|
||||
->add('enabled', CheckboxType::class, [
|
||||
'label' => 'aktiv',
|
||||
'help' => 'Nur aktive Zeilen legen Einsätze an; die Vorschau zeigt alle',
|
||||
|
||||
@@ -18,8 +18,10 @@ use App\Service\Common\PickupOptions;
|
||||
* - with split, a Reiseleitung takes over each level through the combined profile, one place
|
||||
* per level, and the plain Reiseleitung keeps the remaining places;
|
||||
* - Guiding is the guiding fee on every guide-type assignment, not an assignment of its own;
|
||||
* - Busbegleitung pre-selects the first boarding point on exactly one assignment, the first
|
||||
* guide-type one - the plain Reiseleitung where there is one.
|
||||
* - a date with bus travel (boarding points) gets its first boarding point pre-selected as
|
||||
* Busbegleitung on exactly one assignment, the first guide-type one - the plain Reiseleitung
|
||||
* where there is one. Taken from the date, not the matrix: bus travel varies between the
|
||||
* dates of one product.
|
||||
*/
|
||||
final class AssignmentPlanner
|
||||
{
|
||||
@@ -61,7 +63,7 @@ final class AssignmentPlanner
|
||||
}
|
||||
}
|
||||
|
||||
$pickup = true === $rule->isBusEscort() ? $this->firstPickup($destination) : null;
|
||||
$pickup = $this->firstPickup($destination);
|
||||
$planned = [];
|
||||
|
||||
foreach ($roles as [$role, $places]) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
{{ form_row(form.skiAdvanced) }}
|
||||
{{ form_row(form.split) }}
|
||||
{{ form_row(form.guiding) }}
|
||||
{{ form_row(form.busEscort) }}
|
||||
{{ form_row(form.enabled) }}
|
||||
</div>
|
||||
<button type="submit" class="btn">
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
</div>
|
||||
<p class="pb-4">
|
||||
Für jeden künftigen Termin eines aktiven Produkts legt der Einsatz-Generator die Einsätze als
|
||||
Entwurf an. Termine, die schon einmal Einsätze hatten, bleiben unberührt.
|
||||
Entwurf an. Termine, die schon einmal Einsätze hatten, bleiben unberührt. Die Busbegleitung
|
||||
ergibt sich aus den Zustiegen des Termins: Hat er welche, ist der erste vorausgewählt.
|
||||
</p>
|
||||
<div class="data-table-wrapper">
|
||||
<div class="data-table-wrapper__inner">
|
||||
@@ -28,7 +29,6 @@
|
||||
<th>Ski Fortgeschrittene</th>
|
||||
<th>Split</th>
|
||||
<th>Guiding</th>
|
||||
<th>Busbegleitung</th>
|
||||
<th>aktiv</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
@@ -42,7 +42,6 @@
|
||||
<td>{{ _self.yes_no(rule.skiAdvanced) }}</td>
|
||||
<td>{{ _self.yes_no(rule.split) }}</td>
|
||||
<td>{{ _self.yes_no(rule.guiding) }}</td>
|
||||
<td>{{ _self.yes_no(rule.busEscort) }}</td>
|
||||
<td>{{ _self.yes_no(rule.enabled) }}</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-2 justify-end">
|
||||
@@ -66,7 +65,7 @@
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="9">
|
||||
<td colspan="8">
|
||||
Keine Daten...
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -39,7 +39,6 @@ class StaffingRuleTest extends TestCase
|
||||
yield 'split with more levels than guides' => [self::rule(1, beginner: true, advanced: true, split: true), ['split']];
|
||||
yield 'split without a level' => [self::rule(2, split: true), ['split']];
|
||||
yield 'guiding without a guide' => [self::rule(0, beginner: true, guiding: true), ['guiding']];
|
||||
yield 'bus escort without a guide' => [self::rule(0, beginner: true, busEscort: true), ['busEscort']];
|
||||
yield 'courses without guides' => [self::rule(0, beginner: true), []];
|
||||
}
|
||||
|
||||
@@ -49,7 +48,6 @@ class StaffingRuleTest extends TestCase
|
||||
bool $advanced = false,
|
||||
bool $split = false,
|
||||
bool $guiding = false,
|
||||
bool $busEscort = false,
|
||||
): StaffingRule {
|
||||
return (new StaffingRule())
|
||||
->setProductCode('DKIMP')
|
||||
@@ -58,7 +56,6 @@ class StaffingRuleTest extends TestCase
|
||||
->setSkiAdvanced($advanced)
|
||||
->setSplit($split)
|
||||
->setGuiding($guiding)
|
||||
->setBusEscort($busEscort)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -85,14 +85,14 @@ class AssignmentPlannerTest extends TestCase
|
||||
['busProId' => 5, 'city' => 'Göttingen', 'street' => null, 'time' => '08.03.2024 22:00:00'],
|
||||
]);
|
||||
|
||||
$planned = $this->plan(self::rule(guides: 2, busEscort: true), $destination);
|
||||
$planned = $this->plan(self::rule(guides: 2), $destination);
|
||||
|
||||
$this->assertSame(5, $planned[0]->pickup);
|
||||
}
|
||||
|
||||
public function testTheBusEscortIsSetOnExactlyOneAssignment(): void
|
||||
{
|
||||
$planned = $this->plan(self::rule(guides: 3, beginner: true, split: true, busEscort: true));
|
||||
$planned = $this->plan(self::rule(guides: 3, beginner: true, split: true), self::busTravel());
|
||||
|
||||
$this->assertSame([
|
||||
[StaffingRole::GUIDE, 2, 5, []],
|
||||
@@ -102,7 +102,7 @@ class AssignmentPlannerTest extends TestCase
|
||||
|
||||
public function testWithoutAPlainReiseleitungTheFirstCombinedOneEscortsTheBus(): void
|
||||
{
|
||||
$planned = $this->plan(self::rule(guides: 2, beginner: true, advanced: true, split: true, busEscort: true));
|
||||
$planned = $this->plan(self::rule(guides: 2, beginner: true, advanced: true, split: true), self::busTravel());
|
||||
|
||||
$this->assertSame(5, $planned[0]->pickup);
|
||||
$this->assertNull($planned[1]->pickup);
|
||||
@@ -110,16 +110,16 @@ class AssignmentPlannerTest extends TestCase
|
||||
|
||||
public function testNoBusEscortWithoutBoardingPoints(): void
|
||||
{
|
||||
$planned = $this->plan(self::rule(guides: 1, busEscort: true), self::destination([]));
|
||||
$planned = $this->plan(self::rule(guides: 1));
|
||||
|
||||
$this->assertNull($planned[0]->pickup);
|
||||
}
|
||||
|
||||
public function testNoBusEscortWhenTheMatrixSaysNo(): void
|
||||
public function testWithoutAGuideNobodyEscortsTheBus(): void
|
||||
{
|
||||
$planned = $this->plan(self::rule(guides: 1));
|
||||
$planned = $this->plan(self::rule(guides: 0, beginner: true), self::busTravel());
|
||||
|
||||
$this->assertNull($planned[0]->pickup);
|
||||
$this->assertSame([[StaffingRole::SKI_BEGINNER, 1, null, [StaffingFee::COURSE]]], self::summarize($planned));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,9 +127,14 @@ class AssignmentPlannerTest extends TestCase
|
||||
*/
|
||||
private function plan(StaffingRule $rule, ?Destination $destination = null): array
|
||||
{
|
||||
return (new AssignmentPlanner())->plan($rule, $destination ?? self::destination([
|
||||
return (new AssignmentPlanner())->plan($rule, $destination ?? self::destination([]));
|
||||
}
|
||||
|
||||
private static function busTravel(): Destination
|
||||
{
|
||||
return self::destination([
|
||||
['busProId' => 5, 'city' => 'Göttingen', 'street' => null, 'time' => '08.03.2024 22:00:00'],
|
||||
]));
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,7 +154,6 @@ class AssignmentPlannerTest extends TestCase
|
||||
bool $advanced = false,
|
||||
bool $split = false,
|
||||
bool $guiding = false,
|
||||
bool $busEscort = false,
|
||||
): StaffingRule {
|
||||
return (new StaffingRule())
|
||||
->setProductCode('DKIMP')
|
||||
@@ -158,7 +162,6 @@ class AssignmentPlannerTest extends TestCase
|
||||
->setSkiAdvanced($advanced)
|
||||
->setSplit($split)
|
||||
->setGuiding($guiding)
|
||||
->setBusEscort($busEscort)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ trait StaffingFixturesTrait
|
||||
->setGuides(2)
|
||||
->setSkiBeginner(true)
|
||||
->setGuiding(true)
|
||||
->setBusEscort(true)
|
||||
->setEnabled($enabled)
|
||||
;
|
||||
|
||||
|
||||
Reference in new issue
Block a user