fix: called-off dispositions no longer block teamers

This commit is contained in:
Björn Fromme authored and Björn Fromme committed 2026-08-26 09:11:27 +02:00
1 parent cc280907e5
commit f3eae5462d
8 files changed
+186 -20

No files matched your search

@@ -32,9 +32,12 @@ class CreateController extends AbstractController
$user = $this->getUser();
$teamer = $user->getTeamer();
// Only allow applications on empty slots
$availableSlots = (int) $assignment->getAvailableDispositions();
if (0 > $availableSlots) {
// Only allow applications on empty slots. The teamer list already hides assignments without
// a free slot, so this only catches the way past it: a bookmark or a direct link. Called-off
// dispositions do not occupy a slot, and an assignment without a slot count is treated as
// full - both the same way App\Repository\AssignmentRepository decides what to list.
$availableSlots = (int) $assignment->getAvailableDispositions() - $assignment->getActiveDispositions()->count();
if (0 >= $availableSlots) {
$this->addFlash('error', 'Auf diesem Einsatz sind bereits alle Plätze belegt');
return $this->redirectToRoute('app_teamer_index');
@@ -6,7 +6,6 @@ use App\Controller\Traits\ReturnUrlTrait;
use App\Entity\Assignment;
use App\Entity\User;
use App\Repository\ApplicationRepository;
use App\Repository\DispositionRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -19,7 +18,6 @@ class DetailController extends AbstractController
public function __construct(
private readonly ApplicationRepository $applicationRepository,
private readonly DispositionRepository $dispositionRepository,
) {
}
@@ -39,13 +37,7 @@ class DetailController extends AbstractController
])
;
$disposition = $this
->dispositionRepository
->findOneBy([
'assignment' => $assignment,
'teamer' => $teamer,
])
;
$disposition = $assignment->getActiveDispositionByTeamer($teamer);
$isBookmarked = $teamer->getBookmarks()->contains($assignment);
+18
View File
@@ -497,6 +497,24 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
});
}
/**
* Deliberately skips called-off dispositions: once a teamer has been called off - by themselves
* or by the office - the assignment is open for them again, so the teamer views have to offer
* the application instead of reporting them as staffed.
*/
public function getActiveDispositionByTeamer(Teamer $teamer): ?Disposition
{
$dispositions = $this->getActiveDispositions()->filter(function (Disposition $disposition) use ($teamer) {
return $disposition->getTeamer() === $teamer;
});
if (0 === count($dispositions)) {
return null;
}
return $dispositions->first();
}
public function getActiveDispositions(): Collection
{
return $this->dispositions->filter(function (Disposition $disposition) {
+22 -5
View File
@@ -372,12 +372,31 @@ class AssignmentRepository extends ServiceEntityRepository
}
private function getAvailableAssignmentsIds(): array
{
$availableAssignments = $this
->getAvailableAssignmentsIdsQuery()
->getArrayResult()
;
return array_column($availableAssignments, 'id');
}
/**
* A called-off disposition does not occupy a slot any more: the assignment has to show up as
* available again - both for the teamer who was called off and for everybody else.
*/
public function getAvailableAssignmentsIdsQuery(): Query
{
$qb = $this->createQueryBuilder('assignment');
$availableAssignments = $qb
return $qb
->select('assignment.id', 'assignment.availableDispositions')
->leftJoin('assignment.dispositions', 'disposition')
->leftJoin(
'assignment.dispositions',
'disposition',
Join::WITH,
$qb->expr()->neq('disposition.status', ':dispositionCalledOff')
)
->innerJoin('assignment.destination', 'destination')
->where($qb->expr()->andX(
$qb->expr()->orX(
@@ -393,12 +412,10 @@ class AssignmentRepository extends ServiceEntityRepository
->groupBy('assignment.id', 'assignment.availableDispositions')
->having($qb->expr()->gt('assignment.availableDispositions', $qb->expr()->count('disposition.id')))
->setParameter('status', [Assignment::STATUS_DRAFT, Assignment::STATUS_CALLED_OFF])
->setParameter('dispositionCalledOff', Disposition::STATUS_CALLED_OFF)
->setParameter('now', new \DateTimeImmutable())
->getQuery()
->getArrayResult()
;
return array_column($availableAssignments, 'id');
}
public function getSelectableHotelCodes(): array