fix: put the guiding fee on one guide place only

This commit is contained in:
fromme committed 2026-10-16 09:56:04 +02:00
1 parent f0ad5374e9
commit c7e0ad67e6
4 files changed
+53 -21

No files matched your search

+19 -13
View File
@@ -17,11 +17,13 @@ use App\Service\Common\PickupOptions;
* - without split, each ski level is a Kursleitung of its own, one place;
* - 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;
* - 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.
* dates of one product;
* - Guiding is the guiding fee on exactly one guide place, not an assignment of its own: the
* bus escort's. Where that assignment has more places, one place is split off to carry
* fee and pickup, so the others are neither guiding nor escorting the bus.
*/
final class AssignmentPlanner
{
@@ -64,6 +66,7 @@ final class AssignmentPlanner
}
$pickup = $this->firstPickup($destination);
$guiding = $rule->isGuiding();
$planned = [];
foreach ($roles as [$role, $places]) {
@@ -71,26 +74,29 @@ final class AssignmentPlanner
continue;
}
$fees = [];
$fees = true === $role->isCourse() ? [StaffingFee::COURSE] : [];
if (true === $role->isGuide() && true === $rule->isGuiding()) {
$fees[] = StaffingFee::GUIDING;
if (false === $role->isGuide()) {
$planned[] = new PlannedAssignment($role, $places, null, $fees);
continue;
}
if (true === $role->isCourse()) {
$fees[] = StaffingFee::COURSE;
}
$first = true === $guiding ? 1 : $places;
$planned[] = new PlannedAssignment(
$role,
$places,
true === $role->isGuide() ? $pickup : null,
$fees,
$first,
$pickup,
true === $guiding ? [StaffingFee::GUIDING, ...$fees] : $fees,
);
if (true === $role->isGuide()) {
$pickup = null;
if ($first < $places) {
$planned[] = new PlannedAssignment($role, $places - $first, null, $fees);
}
$guiding = false;
$pickup = null;
}
return $planned;
@@ -47,18 +47,23 @@ class AssignmentGenerateCommandTest extends KernelTestCase
$assignments = $this->assignments();
$this->assertCount(2, $assignments);
$this->assertCount(3, $assignments);
[$guide, $course] = $assignments;
[$guide, $secondGuide, $course] = $assignments;
$this->assertSame($destination->getId(), $guide->getDestination()->getId());
$this->assertSame('Reiseleitung', $guide->getJobProfile()->getName());
$this->assertSame(2, $guide->getAvailableDispositions());
$this->assertSame(1, $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('Reiseleitung', $secondGuide->getJobProfile()->getName());
$this->assertSame(1, $secondGuide->getAvailableDispositions());
$this->assertSame(0, $secondGuide->getPickup());
$this->assertCount(0, $secondGuide->getFees());
$this->assertSame('Kursleitung Ski Anfänger:innen', $course->getJobProfile()->getName());
$this->assertSame(0, $course->getPickup());
}
@@ -79,7 +84,7 @@ class AssignmentGenerateCommandTest extends KernelTestCase
$this->tester->execute([]);
$this->assertStringContainsString('davon 1 schon mit Einsätzen', $this->tester->getDisplay());
$this->assertCount(2, $this->assignments());
$this->assertCount(3, $this->assignments());
}
public function testADryRunWritesNothing(): void
@@ -90,7 +95,7 @@ class AssignmentGenerateCommandTest extends KernelTestCase
$this->assertSame(Command::SUCCESS, $this->tester->execute(['--dry-run' => true]));
$this->assertStringContainsString('2× Reiseleitung (Busbegleitung)', $this->tester->getDisplay());
$this->assertStringContainsString('1× Reiseleitung (Busbegleitung)', $this->tester->getDisplay());
$this->assertCount(0, $this->assignments());
}
@@ -93,7 +93,8 @@ class StaffingRuleControllerTest extends WebTestCase
$this->assertSame(Response::HTTP_OK, $this->client->getResponse()->getStatusCode());
$this->assertStringContainsString('DKIMP110127', $content);
$this->assertStringContainsString('Zeile inaktiv', $content);
$this->assertStringContainsString('2× Reiseleitung', $content);
$this->assertSame(2, substr_count($content, '1× Reiseleitung'));
$this->assertSame(1, substr_count($content, 'Skigebietsguiding (pro Einheit)'));
$this->assertStringContainsString('Busbegleitung ab Göttingen, 22:00 Uhr', $content);
$this->assertStringContainsString('1× Kursleitung Ski Anfänger:innen', $content);
$this->assertStringContainsString('Ski-/Snowboardkurs (pro Stunde)', $content);
@@ -56,14 +56,34 @@ class AssignmentPlannerTest extends TestCase
], self::summarize($planned));
}
public function testGuidingIsAFeeOnEveryGuideTypeAssignment(): void
public function testGuidingIsAFeeOnTheFirstGuideTypeAssignmentOnly(): void
{
$planned = $this->plan(self::rule(guides: 3, beginner: true, advanced: true, split: true, guiding: true));
$this->assertSame([
[StaffingRole::GUIDE, 1, null, [StaffingFee::GUIDING]],
[StaffingRole::GUIDE_SKI_BEGINNER, 1, null, [StaffingFee::COURSE]],
[StaffingRole::GUIDE_SKI_ADVANCED, 1, null, [StaffingFee::COURSE]],
], self::summarize($planned));
}
public function testGuidingSplitsOffOnePlaceWhichAlsoEscortsTheBus(): void
{
$planned = $this->plan(self::rule(guides: 3, guiding: true), self::busTravel());
$this->assertSame([
[StaffingRole::GUIDE, 1, 5, [StaffingFee::GUIDING]],
[StaffingRole::GUIDE, 2, null, []],
], self::summarize($planned));
}
public function testWithoutAPlainReiseleitungTheFirstCombinedOneGuides(): void
{
$planned = $this->plan(self::rule(guides: 2, beginner: true, advanced: true, split: true, guiding: true));
$this->assertSame([
[StaffingRole::GUIDE_SKI_BEGINNER, 1, null, [StaffingFee::GUIDING, StaffingFee::COURSE]],
[StaffingRole::GUIDE_SKI_ADVANCED, 1, null, [StaffingFee::GUIDING, StaffingFee::COURSE]],
[StaffingRole::GUIDE_SKI_ADVANCED, 1, null, [StaffingFee::COURSE]],
], self::summarize($planned));
}