feat: timeline for role house manager
closes #869b9vmmx
This commit is contained in:
@@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Controller\Administrative\Assignment;
|
namespace App\Controller\Administrative\Assignment;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
use App\Repository\AssignmentRepository;
|
use App\Repository\AssignmentRepository;
|
||||||
use App\Service\Assignment\TimelineService;
|
use App\Service\Assignment\TimelineService;
|
||||||
use App\Service\Common\TimelineFilterHandler;
|
use App\Service\Common\TimelineFilterHandler;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
@@ -20,17 +22,26 @@ class TimelineController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/administrative/timeline', name: 'app_administrative_timeline')]
|
#[Route('/administrative/timeline', name: 'app_administrative_timeline')]
|
||||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
#[IsGranted(new Expression('is_granted("ROLE_ADMINISTRATIVE") or is_granted("ROLE_HOUSE_MANAGER")'))]
|
||||||
public function index(): Response
|
public function index(): Response
|
||||||
{
|
{
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $this->getUser();
|
||||||
|
|
||||||
$period = $this->timelineService->getActiveWindow();
|
$period = $this->timelineService->getActiveWindow();
|
||||||
$this->filterHandler->setPeriod($period);
|
$this->filterHandler->setPeriod($period);
|
||||||
|
|
||||||
$filterDto = $this->filterHandler->getFilterSettings();
|
$filterDto = $this->filterHandler->getFilterSettings();
|
||||||
|
|
||||||
|
$hotelCodes = null;
|
||||||
|
if ($this->isGranted('ROLE_HOUSE_MANAGER')) {
|
||||||
|
$filterDto->setHotels([]);
|
||||||
|
$hotelCodes = $user->getHotelCodes();
|
||||||
|
}
|
||||||
|
|
||||||
$assignments = $this
|
$assignments = $this
|
||||||
->assignmentRepository
|
->assignmentRepository
|
||||||
->getListQuery($filterDto, 'destination.dateFrom')
|
->getListQuery($filterDto, 'destination.dateFrom', $hotelCodes)
|
||||||
->getResult()
|
->getResult()
|
||||||
;
|
;
|
||||||
$timelineData = $this->timelineService->preprocess($assignments);
|
$timelineData = $this->timelineService->preprocess($assignments);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Htmx\HxRedirectResponse;
|
|||||||
use App\Service\Assignment\TimelineService;
|
use App\Service\Assignment\TimelineService;
|
||||||
use App\Service\Common\TimelineFilterHandler;
|
use App\Service\Common\TimelineFilterHandler;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\ExpressionLanguage\Expression;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
@@ -26,10 +27,13 @@ class TimelineFilterController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/common/timeline/filter', name: 'app_common_timeline_filter')]
|
#[Route('/common/timeline/filter', name: 'app_common_timeline_filter')]
|
||||||
#[IsGranted('ROLE_ADMINISTRATIVE')]
|
#[IsGranted(new Expression('is_granted("ROLE_ADMINISTRATIVE") or is_granted("ROLE_HOUSE_MANAGER")'))]
|
||||||
public function index(Request $request): Response
|
public function index(Request $request): Response
|
||||||
{
|
{
|
||||||
$formData = $this->filterHandler->getFilterSettings();
|
$formData = $this->filterHandler->getFilterSettings();
|
||||||
|
if ($this->isGranted('ROLE_HOUSE_MANAGER')) {
|
||||||
|
$formData->setHotels([]);
|
||||||
|
}
|
||||||
|
|
||||||
$form = $this->createForm(TimelineFilterType::class, $formData);
|
$form = $this->createForm(TimelineFilterType::class, $formData);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Form;
|
|||||||
|
|
||||||
use App\Model\TimelineFilterDto;
|
use App\Model\TimelineFilterDto;
|
||||||
use App\Service\Assignment\TimelineService;
|
use App\Service\Assignment\TimelineService;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
@@ -13,6 +14,7 @@ class TimelineFilterType extends AbstractType
|
|||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly TimelineService $timelineService,
|
private readonly TimelineService $timelineService,
|
||||||
|
private readonly Security $security,
|
||||||
private readonly array $destinations,
|
private readonly array $destinations,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -50,21 +52,23 @@ class TimelineFilterType extends AbstractType
|
|||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
$destinations = $this->destinations;
|
if (false === $this->security->isGranted('ROLE_HOUSE_MANAGER')) {
|
||||||
$hotelChoices = [];
|
$destinations = $this->destinations;
|
||||||
sort($destinations);
|
$hotelChoices = [];
|
||||||
foreach ($destinations as $item) {
|
sort($destinations);
|
||||||
$hotelChoices[$item] = $item;
|
foreach ($destinations as $item) {
|
||||||
}
|
$hotelChoices[$item] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('hotels', MultiselectType::class, [
|
->add('hotels', MultiselectType::class, [
|
||||||
'label' => 'Haus/Destination',
|
'label' => 'Haus/Destination',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'empty_label' => 'nicht filtern',
|
'empty_label' => 'nicht filtern',
|
||||||
'choices' => $hotelChoices,
|
'choices' => $hotelChoices,
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
|||||||
@@ -31,6 +31,15 @@ class HouseManagerMenuBuilder extends AbstractMenuBuilder
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
$menu->addChild('Zeitleiste', [
|
||||||
|
'route' => 'app_administrative_timeline',
|
||||||
|
'linkAttributes' => [
|
||||||
|
'title' => 'Zeitleiste',
|
||||||
|
],
|
||||||
|
'extras' => [
|
||||||
|
'icon' => 'table',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
$this->addAdminItem($menu);
|
$this->addAdminItem($menu);
|
||||||
$this->addManagerItem($menu);
|
$this->addManagerItem($menu);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class AssignmentRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, Assignment::class);
|
parent::__construct($registry, Assignment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getListQuery(AssignmentFilterDto $filterDto, ?string $orderBy = null): Query
|
public function getListQuery(AssignmentFilterDto $filterDto, ?string $orderBy = null, ?array $hotelCodes = null): Query
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('assignment');
|
$qb = $this->createQueryBuilder('assignment');
|
||||||
|
|
||||||
@@ -56,6 +56,7 @@ class AssignmentRepository extends ServiceEntityRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->applyFilterSettings($filterDto, $qb);
|
$this->applyFilterSettings($filterDto, $qb);
|
||||||
|
$this->applyHotelCodeRestriction($qb, $hotelCodes);
|
||||||
|
|
||||||
return $qb->getQuery();
|
return $qb->getQuery();
|
||||||
}
|
}
|
||||||
@@ -231,6 +232,27 @@ class AssignmentRepository extends ServiceEntityRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function applyHotelCodeRestriction(QueryBuilder $qb, ?array $hotelCodes = null): void
|
||||||
|
{
|
||||||
|
if (null === $hotelCodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([] === $hotelCodes) {
|
||||||
|
$qb->andWhere('1 = 0');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->andWhere($qb->expr()->orX(
|
||||||
|
$qb->expr()->in($qb->expr()->substring('destination.hotelCode', 1, 3), ':hotelCodes'),
|
||||||
|
$qb->expr()->in($qb->expr()->substring('destination.hotelCode', -3, 3), ':hotelCodes'),
|
||||||
|
))
|
||||||
|
->setParameter('hotelCodes', $hotelCodes)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
public function getBookmarkQueryForTeamer(Teamer $teamer): Query
|
public function getBookmarkQueryForTeamer(Teamer $teamer): Query
|
||||||
{
|
{
|
||||||
// Find ids of assignments with available slots first
|
// Find ids of assignments with available slots first
|
||||||
|
|||||||
@@ -11,10 +11,14 @@
|
|||||||
}) }}" colspan="{{ colspan }}">
|
}) }}" colspan="{{ colspan }}">
|
||||||
{% if item.type == 'disposition' %}
|
{% if item.type == 'disposition' %}
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': item.assignmentUuid, 'r': return_url() }) }}"
|
{% if is_granted('ROLE_HOUSE_MANAGER') %}
|
||||||
class="inline-block text-xs font-semibold">
|
<span class="inline-block text-xs font-semibold">{{ item.jobProfile }}</span>
|
||||||
{{ item.jobProfile }}
|
{% else %}
|
||||||
</a>
|
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': item.assignmentUuid, 'r': return_url() }) }}"
|
||||||
|
class="inline-block text-xs font-semibold">
|
||||||
|
{{ item.jobProfile }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
<span>|</span>
|
<span>|</span>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
class="flex items-center space-x-2"
|
class="flex items-center space-x-2"
|
||||||
@@ -26,10 +30,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': item.assignmentUuid, 'r': return_url() }) }}"
|
{% if is_granted('ROLE_HOUSE_MANAGER') %}
|
||||||
class="text-xs font-semibold">
|
<span class="text-xs font-semibold">{{ item.jobProfile }}</span>
|
||||||
{{ item.jobProfile }}
|
{% else %}
|
||||||
</a>
|
<a href="{{ path('app_administrative_assignment_detail', { 'uuid': item.assignmentUuid, 'r': return_url() }) }}"
|
||||||
|
class="text-xs font-semibold">
|
||||||
|
{{ item.jobProfile }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
{{ form_row(filterForm.dateFrom) }}
|
{{ form_row(filterForm.dateFrom) }}
|
||||||
{{ form_row(filterForm.dateTo) }}
|
{{ form_row(filterForm.dateTo) }}
|
||||||
</div>
|
</div>
|
||||||
{{ form_row(filterForm.hotels) }}
|
{% if filterForm.hotels is defined %}
|
||||||
|
{{ form_row(filterForm.hotels) }}
|
||||||
|
{% endif %}
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
{{ form_widget(filterForm.apply, { 'attr': { 'class': 'btn' } }) }}
|
{{ form_widget(filterForm.apply, { 'attr': { 'class': 'btn' } }) }}
|
||||||
{{ form_widget(filterForm.reset, { 'attr': { 'class': 'btn btn--secondary' } }) }}
|
{{ form_widget(filterForm.reset, { 'attr': { 'class': 'btn btn--secondary' } }) }}
|
||||||
|
|||||||
Reference in New Issue
Block a user