diff --git a/migrations/Version20251216135542.php b/migrations/Version20251216135542.php new file mode 100644 index 0000000..f985d7a --- /dev/null +++ b/migrations/Version20251216135542.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE feedback ADD assignment_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE feedback ADD CONSTRAINT FK_D2294458D19302F8 FOREIGN KEY (assignment_id) REFERENCES assignment (id)'); + $this->addSql('CREATE INDEX IDX_D2294458D19302F8 ON feedback (assignment_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE feedback DROP FOREIGN KEY FK_D2294458D19302F8'); + $this->addSql('DROP INDEX IDX_D2294458D19302F8 ON feedback'); + $this->addSql('ALTER TABLE feedback DROP assignment_id'); + } +} diff --git a/migrations/Version20251216162601.php b/migrations/Version20251216162601.php new file mode 100644 index 0000000..29f10c8 --- /dev/null +++ b/migrations/Version20251216162601.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE feedback ADD job_profile_category VARCHAR(32) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE feedback DROP job_profile_category'); + } +} diff --git a/migrations/Version20251218100000.php b/migrations/Version20251218100000.php new file mode 100644 index 0000000..570ee7b --- /dev/null +++ b/migrations/Version20251218100000.php @@ -0,0 +1,59 @@ +addSql(" + UPDATE job_profile + SET category = 'course_ski' + WHERE category = 'course' + AND name LIKE '%Ski%' + "); + + // Split course category: profiles with "Board" or "Snowboard" in name become course_board + $this->addSql(" + UPDATE job_profile + SET category = 'course_board' + WHERE category = 'course' + AND (name LIKE '%Board%' OR name LIKE '%Snowboard%') + "); + + // New event_team category for profiles containing "Event" in name + $this->addSql(" + UPDATE job_profile + SET category = 'event_team' + WHERE name LIKE '%Event%' + "); + } + + public function down(Schema $schema): void + { + // Revert course_ski and course_board back to course + $this->addSql(" + UPDATE job_profile + SET category = 'course' + WHERE category IN ('course_ski', 'course_board') + "); + + // Note: Cannot reliably revert event_team as we don't know original category + $this->addSql(" + UPDATE job_profile + SET category = 'service' + WHERE category = 'event_team' + "); + } +} \ No newline at end of file diff --git a/migrations/Version20251218100001.php b/migrations/Version20251218100001.php new file mode 100644 index 0000000..d762f3e --- /dev/null +++ b/migrations/Version20251218100001.php @@ -0,0 +1,43 @@ +addSql(' + UPDATE feedback f + INNER JOIN disposition d ON d.feedback_id = f.id + SET f.assignment_id = d.assignment_id + WHERE f.assignment_id IS NULL + '); + + // Backfill job_profile_category from assignment's job profile + $this->addSql(' + UPDATE feedback f + INNER JOIN assignment a ON a.id = f.assignment_id + INNER JOIN job_profile jp ON jp.id = a.job_profile_id + SET f.job_profile_category = jp.category + WHERE f.job_profile_category IS NULL + AND f.assignment_id IS NOT NULL + '); + } + + public function down(Schema $schema): void + { + // Data migration - setting to NULL on rollback + $this->addSql('UPDATE feedback SET assignment_id = NULL, job_profile_category = NULL'); + } +} diff --git a/src/Entity/Assignment.php b/src/Entity/Assignment.php index eecaa25..b74473d 100644 --- a/src/Entity/Assignment.php +++ b/src/Entity/Assignment.php @@ -91,6 +91,9 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa #[ORM\ManyToMany(targetEntity: Teamer::class, mappedBy: 'bookmarks')] private Collection $teamers; + #[ORM\OneToMany(mappedBy: 'assignment', targetEntity: Feedback::class)] + private Collection $feedback; + #[ORM\ManyToOne] private ?User $owner = null; @@ -109,6 +112,7 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa $this->applications = new ArrayCollection(); $this->dispositions = new ArrayCollection(); $this->teamers = new ArrayCollection(); + $this->feedback = new ArrayCollection(); $this->benefits = "Anreise im E&P Reisebus\nUnterkunft\nVerpflegung\nSkipass\n"; } @@ -537,6 +541,30 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa return $this; } + /** + * @return Collection + */ + public function getFeedback(): Collection + { + return $this->feedback; + } + + public function addFeedback(Feedback $feedback): static + { + if (!$this->feedback->contains($feedback)) { + $this->feedback->add($feedback); + } + + return $this; + } + + public function removeFeedback(Feedback $feedback): static + { + $this->feedback->removeElement($feedback); + + return $this; + } + public function getOwner(): ?User { return $this->owner; diff --git a/src/Entity/Feedback.php b/src/Entity/Feedback.php index f2c0a6d..bbe3289 100644 --- a/src/Entity/Feedback.php +++ b/src/Entity/Feedback.php @@ -35,12 +35,18 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface #[Assert\NotNull(message: 'Bitte auswählen', groups: ['admin'])] private ?Teamer $teamer = null; + #[ORM\ManyToOne(inversedBy: 'feedback')] + private ?Assignment $assignment = null; + #[ORM\Column(length: 255, nullable: true)] private ?string $destinationName = null; #[ORM\Column(length: 255, nullable: true)] private ?string $jobProfileName = null; + #[ORM\Column(length: 32, nullable: true)] + private ?string $jobProfileCategory = null; + #[ORM\Column(length: 255, nullable: true)] private ?string $hotel = null; @@ -90,6 +96,7 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface $jobProfile = $assignment->getJobProfile(); $instance + ->setAssignment($assignment) ->setAssignmentDateFrom($assignment->getEffectiveDateFrom()) ->setAssignmentDateTo($assignment->getEffectiveDateTo()) ->setDestinationName($destination->getProduct()) @@ -97,6 +104,7 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface ->setHotelCode($destination->getHotelCode()) ->setHotelBusProId($destination->getHotelBusProId()) ->setJobProfileName($jobProfile->getName()) + ->setJobProfileCategory($jobProfile->getCategory()) ; return $instance; @@ -124,6 +132,18 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface return $this; } + public function getAssignment(): ?Assignment + { + return $this->assignment; + } + + public function setAssignment(?Assignment $assignment): static + { + $this->assignment = $assignment; + + return $this; + } + public function getTeamer(): ?Teamer { return $this->teamer; @@ -184,6 +204,18 @@ class Feedback implements BlameableEntityInterface, TimestampableEntityInterface return $this; } + public function getJobProfileCategory(): ?string + { + return $this->jobProfileCategory; + } + + public function setJobProfileCategory(?string $jobProfileCategory): static + { + $this->jobProfileCategory = $jobProfileCategory; + + return $this; + } + public function getHotel(): ?string { return $this->hotel; diff --git a/src/Entity/JobProfile.php b/src/Entity/JobProfile.php index 1b0f44c..caee5a6 100644 --- a/src/Entity/JobProfile.php +++ b/src/Entity/JobProfile.php @@ -22,7 +22,10 @@ class JobProfile implements BlameableEntityInterface, TimestampableEntityInterfa public const CATEGORY_GUIDE = 'guide'; public const CATEGORY_COURSE = 'course'; + public const CATEGORY_COURSE_SKI = 'course_ski'; + public const CATEGORY_COURSE_BOARD = 'course_board'; public const CATEGORY_SERVICE = 'service'; + public const CATEGORY_EVENT_TEAM = 'event_team'; #[ORM\Id] #[ORM\GeneratedValue] @@ -99,7 +102,10 @@ class JobProfile implements BlameableEntityInterface, TimestampableEntityInterfa return match ($this->category) { static::CATEGORY_GUIDE => 'Reiseleitung', static::CATEGORY_COURSE => 'Kursleitung', + static::CATEGORY_COURSE_SKI => 'Kursleitung Ski', + static::CATEGORY_COURSE_BOARD => 'Kursleitung Board', static::CATEGORY_SERVICE => 'Serviceteam', + static::CATEGORY_EVENT_TEAM => 'Eventteam', default => null, }; } diff --git a/src/Form/JobProfileType.php b/src/Form/JobProfileType.php index 52a8fe7..57e2a8d 100644 --- a/src/Form/JobProfileType.php +++ b/src/Form/JobProfileType.php @@ -27,8 +27,10 @@ class JobProfileType extends AbstractType 'placeholder' => 'bitte zuordnen...', 'choices' => [ 'Reiseleitung' => JobProfile::CATEGORY_GUIDE, - 'Kursleitung' => JobProfile::CATEGORY_COURSE, + 'Kursleitung Ski' => JobProfile::CATEGORY_COURSE_SKI, + 'Kursleitung Board' => JobProfile::CATEGORY_COURSE_BOARD, 'Serviceteam' => JobProfile::CATEGORY_SERVICE, + 'Eventteam' => JobProfile::CATEGORY_EVENT_TEAM, ], ]) ->add('requiredTrainings', EntityType::class, [