WIP: Implementation of stuff goes on

This commit is contained in:
Björn Fromme
2023-10-05 12:53:17 +02:00
parent 96d6170907
commit 1097b84447
23 changed files with 443 additions and 118 deletions
+1 -3
View File
@@ -6,7 +6,7 @@ import { German } from 'flatpickr/dist/l10n/de';
export default class extends Controller { export default class extends Controller {
static targets = [ 'field' ] static targets = [ 'field' ]
static values = { format: String, minDate: String, maxDate: String, disableWeekends: Boolean, mode: String } static values = { format: String, minDate: String, maxDate: String, disableWeekends: Boolean }
initialize() { initialize() {
flatpickr.localize(German); flatpickr.localize(German);
@@ -17,12 +17,10 @@ export default class extends Controller {
} }
connect() { connect() {
const mode = this.modeValue || 'single'
const dateFormat = this.formatValue || 'd.m.Y' const dateFormat = this.formatValue || 'd.m.Y'
const minDate = this.minDateValue const minDate = this.minDateValue
const maxDate = this.maxDateValue const maxDate = this.maxDateValue
const options = { const options = {
mode,
dateFormat: 'Y-m-d', dateFormat: 'Y-m-d',
altInput: true, altInput: true,
altFormat: dateFormat, altFormat: dateFormat,
+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20231005094552 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE assignment ADD destination_bus_pro_id INT DEFAULT NULL, ADD pickup_date DATE NOT NULL COMMENT \'(DC2Type:date_immutable)\', ADD pickup INT DEFAULT NULL, DROP bus_pro_code, CHANGE available available INT DEFAULT NULL, CHANGE benefits benefits JSON NOT NULL COMMENT \'(DC2Type:json)\'');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE assignment ADD bus_pro_code VARCHAR(64) NOT NULL, DROP destination_bus_pro_id, DROP pickup_date, DROP pickup, CHANGE available available INT NOT NULL, CHANGE benefits benefits LONGTEXT DEFAULT NULL');
}
}
+39
View File
@@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20231005100242 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE assignment DROP FOREIGN KEY FK_30C544BA7E3C61F9');
$this->addSql('DROP INDEX IDX_30C544BA7E3C61F9 ON assignment');
$this->addSql('ALTER TABLE assignment CHANGE owner_id contact_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE assignment ADD CONSTRAINT FK_30C544BAE7A1254A FOREIGN KEY (contact_id) REFERENCES user (id)');
$this->addSql('CREATE INDEX IDX_30C544BAE7A1254A ON assignment (contact_id)');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE assignment DROP FOREIGN KEY FK_30C544BAE7A1254A');
$this->addSql('DROP INDEX IDX_30C544BAE7A1254A ON assignment');
$this->addSql('ALTER TABLE assignment CHANGE contact_id owner_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE assignment ADD CONSTRAINT FK_30C544BA7E3C61F9 FOREIGN KEY (owner_id) REFERENCES user (id)');
$this->addSql('CREATE INDEX IDX_30C544BA7E3C61F9 ON assignment (owner_id)');
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20231005101119 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user ADD first_name VARCHAR(255) NOT NULL, ADD last_name VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE user DROP first_name, DROP last_name');
}
}
+2
View File
@@ -52,6 +52,8 @@ class UserDataHandler
{ {
$user = new User(); $user = new User();
$user $user
->setFirstName($profileResponse->getFirstName())
->setLastName($profileResponse->getName())
->setEmail($profileResponse->getCommunication()->getEmail()) ->setEmail($profileResponse->getCommunication()->getEmail())
->setBusProPersonId($profileResponse->getPersonId()) ->setBusProPersonId($profileResponse->getPersonId())
->setBusProAddressId($profileResponse->getAddressId()) ->setBusProAddressId($profileResponse->getAddressId())
@@ -4,14 +4,24 @@ namespace App\Controller\Admin\Assignment;
use App\Entity\Assignment; use App\Entity\Assignment;
use App\Form\AssignmentType; use App\Form\AssignmentType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class CreateController extends AbstractController class CreateController extends AbstractController
{ {
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/assignment/create', name: 'app_admin_assignment_create')] #[Route('/admin/assignment/create', name: 'app_admin_assignment_create')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Request $request): Response public function index(Request $request): Response
{ {
$assignment = new Assignment(); $assignment = new Assignment();
@@ -19,6 +29,15 @@ class CreateController extends AbstractController
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->persist($assignment);
$this->entityManager->flush();
$this->addFlash('success', 'Der Einsatz wurde angelegt');
$this->logger->info('Create assignment', [
'assignment' => $assignment->getUuid(),
]);
return $this->redirectToRoute('app_admin_assignment_index'); return $this->redirectToRoute('app_admin_assignment_index');
} }
@@ -0,0 +1,46 @@
<?php
namespace App\Controller\Admin\Assignment;
use App\Entity\Assignment;
use App\Form\AssignmentType;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class EditController extends AbstractController
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly LoggerInterface $logger
) {
}
#[Route('/admin/assignment/edit/{uuid}', name: 'app_admin_assignment_edit')]
#[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Assignment $assignment, Request $request): Response
{
$form = $this->createForm(AssignmentType::class, $assignment);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->entityManager->flush();
$this->addFlash('success', 'Der Einsatz wurde aktualisiert');
$this->logger->info('Edit assignment', [
'assignment' => $assignment->getUuid(),
]);
return $this->redirectToRoute('app_admin_assignment_index');
}
return $this->render('admin/assignment/edit.html.twig', [
'form' => $form,
]);
}
}
@@ -2,15 +2,43 @@
namespace App\Controller\Admin\Assignment; namespace App\Controller\Admin\Assignment;
use App\Repository\AssignmentRepository;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class IndexController extends AbstractController class IndexController extends AbstractController
{ {
public function __construct(
private readonly AssignmentRepository $assignmentRepository,
private readonly PaginatorInterface $paginator
) {
}
#[Route('/admin/assignment', name: 'app_admin_assignment_index')] #[Route('/admin/assignment', name: 'app_admin_assignment_index')]
public function index(): Response #[IsGranted('ROLE_ADMINISTRATIVE')]
public function index(Request $request): Response
{ {
return $this->render('admin/assignment/index.html.twig'); $query = $this
->assignmentRepository
->getListQuery()
;
$pagination = $this->paginator->paginate(
$query,
$request->query->getInt('page', 1),
10,
[
'defaultSortFieldName' => 'assignment.dateFrom',
'defaultSortDirection' => 'asc',
]
);
return $this->render('admin/assignment/index.html.twig', [
'pagination' => $pagination,
]);
} }
} }
@@ -32,7 +32,7 @@ class HotelController extends AbstractController
$name = $hotel->getName(); $name = $hotel->getName();
if (1 === preg_match('/'.preg_quote($queryString, '/').'/i', $name)) { if (1 === preg_match('/'.preg_quote($queryString, '/').'/i', $name)) {
$data[] = [ $data[] = [
'value' => $hotel->getId(), 'value' => $hotel->getBusProId(),
'text' => sprintf('%s (%s)', $name, $hotel->getCode()), 'text' => sprintf('%s (%s)', $name, $hotel->getCode()),
]; ];
} }
+26 -49
View File
@@ -4,12 +4,14 @@ namespace App\Entity;
use App\Entity\Traits\BlameableEntity; use App\Entity\Traits\BlameableEntity;
use App\Entity\Traits\TimestampableEntity; use App\Entity\Traits\TimestampableEntity;
use App\Model\BenefitsDto;
use App\Repository\AssignmentRepository; use App\Repository\AssignmentRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types; use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\Uuid;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity(repositoryClass: AssignmentRepository::class)] #[ORM\Entity(repositoryClass: AssignmentRepository::class)]
class Assignment implements BlameableEntityInterface, TimestampableEntityInterface class Assignment implements BlameableEntityInterface, TimestampableEntityInterface
@@ -26,36 +28,41 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
private string $uuid; private string $uuid;
#[ORM\Column(nullable: true)] #[ORM\Column(nullable: true)]
#[Assert\NotNull(message: 'Bitte gib die Destination an')]
private ?int $destinationBusProId = null; private ?int $destinationBusProId = null;
#[ORM\ManyToOne] #[ORM\ManyToOne]
#[Assert\NotNull(message: 'Bitte gib das Jobprofil an')]
private ?JobProfile $jobProfile = null; private ?JobProfile $jobProfile = null;
#[ORM\Column(nullable: true)] #[ORM\Column(nullable: true)]
private ?int $available = null; #[Assert\Range(min: 1, minMessage: 'Die Mindestanzahl ist 1')]
private ?int $available = 1;
#[ORM\Column(type: Types::DATE_IMMUTABLE)] #[ORM\Column(type: Types::DATE_IMMUTABLE)]
#[Assert\NotNull(message: 'Bitte gib das Beginndatum an')]
private ?\DateTimeImmutable $dateFrom = null; private ?\DateTimeImmutable $dateFrom = null;
#[ORM\Column(type: Types::DATE_IMMUTABLE)] #[ORM\Column(type: Types::DATE_IMMUTABLE)]
#[Assert\NotNull(message: 'Bitte gib das Enddatum an')]
#[Assert\GreaterThan(propertyPath: 'dateFrom', message: 'Das Enddatum muss nach dem Beginndatum liegen')]
private ?\DateTimeImmutable $dateTo = null; private ?\DateTimeImmutable $dateTo = null;
#[ORM\Column(type: Types::DATE_IMMUTABLE)] #[ORM\Column(type: Types::DATE_IMMUTABLE)]
#[Assert\GreaterThanOrEqual(propertyPath: 'dateFrom', message: 'Die Busabfahrt muss am oder nach dem Beginndatum liegen')]
private ?\DateTimeImmutable $pickupDate = null; private ?\DateTimeImmutable $pickupDate = null;
#[ORM\Column(nullable: true)] #[ORM\Column(nullable: true)]
private ?int $pickup = null; private ?int $pickup = null;
#[ORM\Column(type: Types::TEXT, nullable: true)] #[ORM\Column]
private ?string $benefits = null; private array $benefits;
#[ORM\Column(type: Types::TEXT, nullable: true)] #[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $remarks = null; private ?string $remarks = null;
#[ORM\ManyToOne]
private ?User $owner = null;
#[ORM\ManyToMany(targetEntity: Fee::class)] #[ORM\ManyToMany(targetEntity: Fee::class)]
#[Assert\Count(min: 1, minMessage: 'Bitte triff mindestens eine Auswahl')]
private Collection $fees; private Collection $fees;
#[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Application::class)] #[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Application::class)]
@@ -64,8 +71,8 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
#[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Disposition::class)] #[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Disposition::class)]
private Collection $dispositions; private Collection $dispositions;
#[ORM\OneToMany(mappedBy: 'assignment', targetEntity: DispositionRequirement::class)] #[ORM\ManyToOne]
private Collection $requirements; private ?User $contact = null;
public function __construct() public function __construct()
{ {
@@ -73,7 +80,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
$this->fees = new ArrayCollection(); $this->fees = new ArrayCollection();
$this->applications = new ArrayCollection(); $this->applications = new ArrayCollection();
$this->dispositions = new ArrayCollection(); $this->dispositions = new ArrayCollection();
$this->requirements = new ArrayCollection(); $this->benefits = BenefitsDto::$defaults;
} }
public function getId(): ?int public function getId(): ?int
@@ -127,7 +134,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this->dateFrom; return $this->dateFrom;
} }
public function setDateFrom(\DateTimeImmutable $dateFrom): static public function setDateFrom(?\DateTimeImmutable $dateFrom): static
{ {
$this->dateFrom = $dateFrom; $this->dateFrom = $dateFrom;
@@ -139,7 +146,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this->dateTo; return $this->dateTo;
} }
public function setDateTo(\DateTimeImmutable $dateTo): static public function setDateTo(?\DateTimeImmutable $dateTo): static
{ {
$this->dateTo = $dateTo; $this->dateTo = $dateTo;
@@ -163,19 +170,19 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this->pickup; return $this->pickup;
} }
public function setPickup(?int $pickup): static public function setPickup(null|int|string $pickup): static
{ {
$this->pickup = $pickup; $this->pickup = (int) $pickup;
return $this; return $this;
} }
public function getBenefits(): ?string public function getBenefits(): array
{ {
return $this->benefits; return $this->benefits;
} }
public function setBenefits(string $benefits): static public function setBenefits(array $benefits): static
{ {
$this->benefits = $benefits; $this->benefits = $benefits;
@@ -194,18 +201,6 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this; return $this;
} }
public function getOwner(): ?User
{
return $this->owner;
}
public function setOwner(?User $owner): static
{
$this->owner = $owner;
return $this;
}
/** /**
* @return Collection<int, Fee> * @return Collection<int, Fee>
*/ */
@@ -290,32 +285,14 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
return $this; return $this;
} }
/** public function getContact(): ?User
* @return Collection<int, DispositionRequirement>
*/
public function getRequirements(): Collection
{ {
return $this->requirements; return $this->contact;
} }
public function addRequirement(DispositionRequirement $requirement): static public function setContact(?User $contact): static
{ {
if (!$this->requirements->contains($requirement)) { $this->contact = $contact;
$this->requirements->add($requirement);
$requirement->setAssignment($this);
}
return $this;
}
public function removeRequirement(DispositionRequirement $requirement): static
{
if ($this->requirements->removeElement($requirement)) {
// set the owning side to null (unless already changed)
if ($requirement->getAssignment() === $this) {
$requirement->setAssignment(null);
}
}
return $this; return $this;
} }
+44
View File
@@ -27,6 +27,12 @@ class User implements UserInterface, TimestampableEntityInterface
#[ORM\Column] #[ORM\Column]
private ?int $busProPersonId = null; private ?int $busProPersonId = null;
#[ORM\Column(length: 255)]
private ?string $firstName = null;
#[ORM\Column(length: 255)]
private ?string $lastName = null;
#[ORM\Column(length: 255)] #[ORM\Column(length: 255)]
private ?string $email = null; private ?string $email = null;
@@ -44,6 +50,11 @@ class User implements UserInterface, TimestampableEntityInterface
$this->uuid = Uuid::v4(); $this->uuid = Uuid::v4();
} }
public function __toString()
{
return $this->getFullName();
}
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@@ -78,6 +89,39 @@ class User implements UserInterface, TimestampableEntityInterface
return $this; return $this;
} }
public function getFirstName(): ?string
{
return $this->firstName;
}
public function setFirstName(?string $firstName): static
{
$this->firstName = $firstName;
return $this;
}
public function getLastName(): ?string
{
return $this->lastName;
}
public function setLastName(?string $lastName): static
{
$this->lastName = $lastName;
return $this;
}
public function getFullName(bool $formal = false): string
{
if (true === $formal) {
return sprintf('%s, %s', $this->getLastName(), $this->getFirstName());
}
return sprintf('%s %s', $this->getFirstName(), $this->getLastName());
}
public function getEmail(): ?string public function getEmail(): ?string
{ {
return $this->email; return $this->email;
+29 -2
View File
@@ -5,8 +5,12 @@ namespace App\Form;
use App\Entity\Assignment; use App\Entity\Assignment;
use App\Entity\Fee; use App\Entity\Fee;
use App\Entity\JobProfile; use App\Entity\JobProfile;
use App\Entity\User;
use App\Model\BenefitsDto;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
@@ -33,7 +37,6 @@ class AssignmentType extends AbstractType
]) ])
->add('dateFrom', DatepickerType::class, [ ->add('dateFrom', DatepickerType::class, [
'label' => 'Einsatztermin von', 'label' => 'Einsatztermin von',
'mode' => 'range',
]) ])
->add('dateTo', DatepickerType::class, [ ->add('dateTo', DatepickerType::class, [
'label' => 'Einsatztermin bis', 'label' => 'Einsatztermin bis',
@@ -47,9 +50,12 @@ class AssignmentType extends AbstractType
'required' => false, 'required' => false,
'placeholder' => 'Keine Busbegleitung', 'placeholder' => 'Keine Busbegleitung',
]) ])
->add('benefits', TextareaType::class, [ ->add('benefits', ChoiceType::class, [
'label' => 'Benefits', 'label' => 'Benefits',
'required' => false, 'required' => false,
'multiple' => true,
'expanded' => true,
'choices' => array_flip(BenefitsDto::$values),
]) ])
->add('fees', EntityType::class, [ ->add('fees', EntityType::class, [
'label' => 'Honorar(e)', 'label' => 'Honorar(e)',
@@ -58,6 +64,27 @@ class AssignmentType extends AbstractType
'multiple' => true, 'multiple' => true,
'expanded' => true, 'expanded' => true,
]) ])
->add('contact', EntityType::class, [
'label' => 'Ansprechpartner RM',
'class' => User::class,
'choice_label' => 'fullName',
'query_builder' => function (EntityRepository $repository) {
$qb = $repository->createQueryBuilder('user');
return $qb
->where($qb->expr()->like('user.roles', ':role'))
->setParameter('role','%ROLE_MANAGER%')
->orderBy('user.firstName', 'ASC')
;
},
])
->add('remarks', TextareaType::class, [
'label' => 'Anmerkungen',
'required' => false,
'attr' => [
'rows' => 3,
],
])
; ;
} }
-4
View File
@@ -19,13 +19,10 @@ class DatepickerType extends AbstractType
'min_date' => null, 'min_date' => null,
'max_date' => null, 'max_date' => null,
'disable_weekends' => false, 'disable_weekends' => false,
'mode' => 'single', // 'single', 'multiple' or 'range'
]); ]);
$resolver->setAllowedTypes('min_date', ['null', \DateTimeImmutable::class]); $resolver->setAllowedTypes('min_date', ['null', \DateTimeImmutable::class]);
$resolver->setAllowedTypes('max_date', ['null', \DateTimeImmutable::class]); $resolver->setAllowedTypes('max_date', ['null', \DateTimeImmutable::class]);
$resolver->setAllowedTypes('disable_weekends', 'bool'); $resolver->setAllowedTypes('disable_weekends', 'bool');
$resolver->setAllowedTypes('mode', 'string');
$resolver->setAllowedValues('mode', ['single', 'multiple', 'range']);
} }
public function buildView(FormView $view, FormInterface $form, array $options): void public function buildView(FormView $view, FormInterface $form, array $options): void
@@ -33,7 +30,6 @@ class DatepickerType extends AbstractType
$view->vars['min_date'] = $options['min_date']; $view->vars['min_date'] = $options['min_date'];
$view->vars['max_date'] = $options['max_date']; $view->vars['max_date'] = $options['max_date'];
$view->vars['disable_weekends'] = $options['disable_weekends']; $view->vars['disable_weekends'] = $options['disable_weekends'];
$view->vars['mode'] = $options['mode'];
} }
public function getParent(): string public function getParent(): string
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace App\Model;
class BenefitsDto
{
public static array $defaults = [
'anreise',
'unterkunft',
'verpflegung',
'skipass',
];
public static array $values = [
'anreise' => 'Anreise im E&P Reisebus',
'unterkunft' => 'Unterkunft',
'verpflegung' => 'Verpflegung',
'skipass' => 'Skipass',
];
}
+6 -40
View File
@@ -4,6 +4,7 @@ namespace App\Repository;
use App\Entity\Assignment; use App\Entity\Assignment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Query;
use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ManagerRegistry;
/** /**
@@ -21,46 +22,11 @@ class AssignmentRepository extends ServiceEntityRepository
parent::__construct($registry, Assignment::class); parent::__construct($registry, Assignment::class);
} }
public function save(Assignment $entity, bool $flush = false): void public function getListQuery(): Query
{ {
$this->getEntityManager()->persist($entity); return $this
->createQueryBuilder('assignment')
if ($flush) { ->getQuery()
$this->getEntityManager()->flush(); ;
}
} }
public function remove(Assignment $entity, bool $flush = false): void
{
$this->getEntityManager()->remove($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
// /**
// * @return Assignment[] Returns an array of Assignment objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('a')
// ->andWhere('a.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('a.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }
// public function findOneBySomeField($value): ?Assignment
// {
// return $this->createQueryBuilder('a')
// ->andWhere('a.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
} }
+1
View File
@@ -19,6 +19,7 @@ class AppExtension extends AbstractExtension
new TwigFilter('teamer_status_label', [AppRuntime::class, 'teamerStatusLabel']), new TwigFilter('teamer_status_label', [AppRuntime::class, 'teamerStatusLabel']),
new TwigFilter('bpn_country_label', [AppRuntime::class, 'bpnCountryLabel']), new TwigFilter('bpn_country_label', [AppRuntime::class, 'bpnCountryLabel']),
new TwigFilter('bpn_pickup_label', [AppRuntime::class, 'bpnPickupLabel']), new TwigFilter('bpn_pickup_label', [AppRuntime::class, 'bpnPickupLabel']),
new TwigFilter('bpn_destination_label', [AppRuntime::class, 'bpnDestinationLabel']),
]; ];
} }
+13
View File
@@ -3,6 +3,7 @@
namespace App\Twig; namespace App\Twig;
use App\BusProNet\DataProvider\CountryDataProvider; use App\BusProNet\DataProvider\CountryDataProvider;
use App\BusProNet\DataProvider\HotelDataProvider;
use App\BusProNet\DataProvider\PickupDataProvider; use App\BusProNet\DataProvider\PickupDataProvider;
use App\BusProNet\Model\Country; use App\BusProNet\Model\Country;
use App\Entity\Teamer; use App\Entity\Teamer;
@@ -19,6 +20,7 @@ class AppRuntime implements RuntimeExtensionInterface
private readonly IntlExtension $intlExtension, private readonly IntlExtension $intlExtension,
private readonly CountryDataProvider $countries, private readonly CountryDataProvider $countries,
private readonly PickupDataProvider $pickups, private readonly PickupDataProvider $pickups,
private readonly HotelDataProvider $hotels,
private readonly string $environment private readonly string $environment
) { ) {
} }
@@ -59,6 +61,17 @@ class AppRuntime implements RuntimeExtensionInterface
return $pickup->getCity(); return $pickup->getCity();
} }
public function bpnDestinationLabel(int $id): string
{
$hotel = $this->hotels->get($id);
if (null === $hotel) {
return 'unbekannt';
}
return sprintf('%s, %s', $hotel->getName(), $hotel->getCity() ?? '-');
}
public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string public function fileIconFilter(Environment $environment, string $mimeType, ?string $classes = 'w-4 h-4'): string
{ {
$icon = match ($mimeType) { $icon = match ($mimeType) {
@@ -0,0 +1,32 @@
{{ form_start(form) }}
<div class="flex flex-col space-y-4 pb-8">
{{ form_row(form.available) }}
{{ form_row(form.jobProfile) }}
{{ form_row(form.destinationBusProId) }}
<div class="grid lg:grid-cols-2 gap-4">
{{ form_row(form.dateFrom) }}
{{ form_row(form.dateTo) }}
</div>
<div class="grid lg:grid-cols-2 gap-4">
{{ form_row(form.pickupDate) }}
{{ form_row(form.pickup) }}
</div>
<div class="grid lg:grid-cols-2 gap-4">
{{ form_row(form.benefits) }}
{{ form_row(form.fees) }}
</div>
<div class="grid lg:grid-cols-2 gap-4">
{{ form_row(form.contact) }}
{{ form_row(form.remarks) }}
</div>
</div>
<div class="flex items-center space-x-2">
<button type="submit" class="btn">
Speichern
</button>
<a href="{{ path('app_admin_assignment_index') }}" class="btn btn--secondary">
Abbrechen
</a>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
+1 -3
View File
@@ -6,7 +6,5 @@
<h1 class="text-2xl font-bold pb-8"> <h1 class="text-2xl font-bold pb-8">
Einsatz anlegen Einsatz anlegen
</h1> </h1>
{{ form_start(form) }} {% include 'admin/assignment/_form.html.twig' %}
{{ form_rest(form) }}
{{ form_end(form) }}
{% endblock %} {% endblock %}
+10
View File
@@ -0,0 +1,10 @@
{% extends 'admin/layout.html.twig' %}
{% block title %}Einsatz bearbeiten{% endblock %}
{% block content %}
<h1 class="text-2xl font-bold pb-8">
Einsatz bearbeiten
</h1>
{% include 'admin/assignment/_form.html.twig' %}
{% endblock %}
+59 -12
View File
@@ -3,19 +3,66 @@
{% block title %}Einsatzübersicht{% endblock %} {% block title %}Einsatzübersicht{% endblock %}
{% block content %} {% block content %}
<h1 class="text-2xl font-bold pb-8"> <h1 class="text-2xl font-bold pb-8">
Einsatzübersicht Einsatzübersicht
</h1> </h1>
<div class="data-table-wrapper"> <div class="data-table-wrapper">
<div class="data-table-wrapper__inner"> <div class="data-table-wrapper__inner">
<table class="data-table"> <table class="data-table">
<thead> <thead>
<tr>
<th>
{{ knp_pagination_sortable(pagination, 'Einsatz&shy;beginn', 'assignment.dateFrom') }}
</th>
<th>
{{ knp_pagination_sortable(pagination, 'Einsatz&shy;ende', 'assignment.dateTo') }}
</th>
<th>
{{ knp_pagination_sortable(pagination, 'Jobprofil', 'assignment.jobProfile') }}
</th>
<th>
{{ knp_pagination_sortable(pagination, 'Destination', 'assignment.destinationBusProId') }}
</th>
<th>
{{ knp_pagination_sortable(pagination, 'Busabfahrt', 'assignment.pickupDate') }}
</th>
<th>
{{ knp_pagination_sortable(pagination, 'Busbegleitung ab', 'assignment.pickup') }}
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for assignment in pagination %}
<tr> <tr>
<td>
{{ assignment.dateFrom|date('d.m.Y') }}
</td>
<td>
{{ assignment.dateTo|date('d.m.Y') }}
</td>
<td>
{{ assignment.jobProfile.name }}
</td>
<td>
{{ assignment.destinationBusProId|bpn_destination_label }}
</td>
<td>
{{ assignment.pickupDate|date('d.m.Y') }}
</td>
<td>
{{ assignment.pickup|bpn_pickup_label|default('-') }}
</td>
<td>
<a href="{{ path('app_admin_assignment_edit', { 'uuid': assignment.uuid}) }}">
{{ icon('edit', 'w-5 h-5') }}
</a>
</td>
</tr> </tr>
</thead> {% endfor %}
<tbody> </tbody>
</tbody> </table>
</table> {{ knp_pagination_render(pagination) }}
</div>
</div> </div>
</div>
{% endblock %} {% endblock %}
+1 -1
View File
@@ -161,7 +161,7 @@
{%- if disabled is defined and disabled == true -%} {%- if disabled is defined and disabled == true -%}
{%- set attr = attr|merge({'class': attr.class|default('') ~ ' cursor-not-allowed' }) -%} {%- set attr = attr|merge({'class': attr.class|default('') ~ ' cursor-not-allowed' }) -%}
{%- endif -%} {%- endif -%}
<div {{ stimulus_controller('datepicker', { 'minDate': minDate, 'maxDate': maxDate, 'disableWeekends': form.vars.disable_weekends, 'mode': form.vars.mode }) }}> <div {{ stimulus_controller('datepicker', { 'minDate': minDate, 'maxDate': maxDate, 'disableWeekends': form.vars.disable_weekends }) }}>
<input type="text" name="{{ form.vars.full_name }}" value="{{ value }}" {{ block('widget_attributes') }} <input type="text" name="{{ form.vars.full_name }}" value="{{ value }}" {{ block('widget_attributes') }}
{{ stimulus_target('datepicker', 'field') }} /> {{ stimulus_target('datepicker', 'field') }} />
</div> </div>
+1 -1
View File
@@ -1,5 +1,5 @@
<a href="{{ options.href }}" class="flex items-center space-x-2"> <a href="{{ options.href }}" class="flex items-center space-x-2">
<span>{{ title }}</span> <span>{{ title|raw }}</span>
{%- if sorted -%} {%- if sorted -%}
{%- if direction == 'desc' -%} {%- if direction == 'desc' -%}
<svg class="w-4 h-4 shrink-0" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor"> <svg class="w-4 h-4 shrink-0" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor">