diff --git a/src/Bundle/ChillEventBundle/Entity/Event.php b/src/Bundle/ChillEventBundle/Entity/Event.php index c45c68159..ba4337205 100644 --- a/src/Bundle/ChillEventBundle/Entity/Event.php +++ b/src/Bundle/ChillEventBundle/Entity/Event.php @@ -25,6 +25,7 @@ use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Serializer\Annotation as Serializer; @@ -98,9 +99,16 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter #[ORM\JoinTable('chill_event_event_documents')] private Collection $documents; - #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DECIMAL, precision: 10, scale: 4, nullable: true, options: ['default' => '0.0'])] + #[ORM\Column(type: Types::DECIMAL, precision: 10, scale: 4, nullable: true, options: ['default' => '0.0'])] private string $organizationCost = '0.0'; + /** + * @var Collection + */ + #[ORM\OneToMany(mappedBy: 'event', targetEntity: EventBudgetElement::class, cascade: ['persist'])] + #[Serializer\Groups(['read'])] + private Collection $budgetElements; + /** * Event constructor. */ @@ -110,6 +118,17 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter $this->documents = new ArrayCollection(); $this->comment = new CommentEmbeddable(); $this->themes = new ArrayCollection(); + $this->budgetElements = new ArrayCollection(); + } + + public function addBudgetElement(EventBudgetElement $budgetElement) + { + if (!$this->budgetElements->contains($budgetElement)) { + $this->budgetElements[] = $budgetElement; + $budgetElement->setEvent($this); + } + + return $this; } /** @@ -208,6 +227,14 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter return $this->name; } + /** + * @return Collection + */ + public function getBudgetElements(): Collection + { + return $this->budgetElements; + } + /** * @return Collection */ @@ -246,6 +273,11 @@ class Event implements HasCenterInterface, HasScopeInterface, TrackCreationInter return $this->type; } + public function removeBudgetElement(EventBudgetElement $budgetElement): void + { + $this->budgetElements->removeElement($budgetElement); + } + /** * Remove participation. */ diff --git a/src/Bundle/ChillEventBundle/Entity/EventBudgetElement.php b/src/Bundle/ChillEventBundle/Entity/EventBudgetElement.php new file mode 100644 index 000000000..40109d568 --- /dev/null +++ b/src/Bundle/ChillEventBundle/Entity/EventBudgetElement.php @@ -0,0 +1,101 @@ +id; + } + + public function setId(?int $id): void + { + $this->id = $id; + } + public function getAmount(): float + { + return (float) $this->amount; + } + + public function getComment(): ?CommentEmbeddable + { + return $this->comment; + } + + public function getEvent(): Event + { + return $this->event; + } + + public function getKind(): EventBudgetKind + { + return $this->kind; + } + + public function setAmount(string $amount): self + { + $this->amount = $amount; + + return $this; + } + + public function setComment(?CommentEmbeddable $comment = null): self + { + $this->comment = $comment; + + return $this; + } + + public function setEvent(Event $event): self + { + $this->event = $event; + + return $this; + } + + public function setKind(EventBudgetKind $kind): self + { + $this->kind = $kind; + + return $this; + } +} diff --git a/src/Bundle/ChillEventBundle/Entity/EventBudgetKind.php b/src/Bundle/ChillEventBundle/Entity/EventBudgetKind.php index 937f44051..b668ff5cc 100644 --- a/src/Bundle/ChillEventBundle/Entity/EventBudgetKind.php +++ b/src/Bundle/ChillEventBundle/Entity/EventBudgetKind.php @@ -18,7 +18,7 @@ use Doctrine\ORM\Mapping as ORM; * Type of event budget element. */ #[ORM\Entity] -#[ORM\Table(name: 'chill_event_budget_element_kind')] +#[ORM\Table(name: 'chill_event_budget_kind')] class EventBudgetKind { #[ORM\Id] diff --git a/src/Bundle/ChillEventBundle/Form/AddEventBudgetElementType.php b/src/Bundle/ChillEventBundle/Form/AddEventBudgetElementType.php new file mode 100644 index 000000000..94b7f2e69 --- /dev/null +++ b/src/Bundle/ChillEventBundle/Form/AddEventBudgetElementType.php @@ -0,0 +1,59 @@ +kindRepository->findByType(BudgetTypeEnum::CHARGE->value); + $resources = $this->kindRepository->findByType(BudgetTypeEnum::RESOURCE->value); + + $builder->add('kind', ChoiceType::class, [ + 'choices' => [ + 'Charges' => $charges, + 'Resources' => $resources, + ], + 'choice_label' => fn (EventBudgetKind $kind) => $this->translatableStringHelper->localize($kind->getName()), + 'choice_value' => fn (?EventBudgetKind $kind) => $kind?->getId(), + 'placeholder' => 'Select a budget element kind', + ]) + ->add('amount', NumberType::class, [ + 'required' => true, + ]) + ->add('comment', CommentType::class, [ + 'label' => 'Comment', + 'required' => false, + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'data_class' => EventBudgetElement::class, + ]); + } +} diff --git a/src/Bundle/ChillEventBundle/Form/EventType.php b/src/Bundle/ChillEventBundle/Form/EventType.php index 6bceed93f..23d83c6f0 100644 --- a/src/Bundle/ChillEventBundle/Form/EventType.php +++ b/src/Bundle/ChillEventBundle/Form/EventType.php @@ -13,9 +13,12 @@ namespace Chill\EventBundle\Form; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\DocStoreBundle\Form\StoredObjectType; +use Chill\EventBundle\Entity\BudgetTypeEnum; use Chill\EventBundle\Entity\Event; +use Chill\EventBundle\Form\Type\PickEventBudgetKindType; use Chill\EventBundle\Form\Type\PickEventThemeType; use Chill\EventBundle\Form\Type\PickEventTypeType; +use Chill\EventBundle\Repository\EventBudgetKindRepository; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer; use Chill\MainBundle\Form\Type\ChillCollectionType; @@ -23,6 +26,7 @@ use Chill\MainBundle\Form\Type\ChillDateTimeType; use Chill\MainBundle\Form\Type\CommentType; use Chill\MainBundle\Form\Type\PickUserDynamicType; use Chill\MainBundle\Form\Type\ScopePickerType; +use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\Core\Type\MoneyType; @@ -34,10 +38,15 @@ class EventType extends AbstractType { public function __construct( private readonly IdToLocationDataTransformer $idToLocationDataTransformer, + private readonly EventBudgetKindRepository $eventBudgetKindRepository, + private readonly TranslatableStringHelperInterface $translatableStringHelper, ) {} public function buildForm(FormBuilderInterface $builder, array $options) { + $chargeKinds = $this->eventBudgetKindRepository->findByType(BudgetTypeEnum::CHARGE->value); + $resourceKinds = $this->eventBudgetKindRepository->findByType(BudgetTypeEnum::RESOURCE->value); + $builder ->add('name', TextType::class, [ 'required' => true, @@ -61,6 +70,13 @@ class EventType extends AbstractType ->add('moderator', PickUserDynamicType::class, [ 'label' => 'Pick a moderator', ]) + ->add('budgetElements', ChillCollectionType::class, [ + 'entry_type' => AddEventBudgetElementType::class, + 'entry_options' => ['label' => false], + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + ]) ->add('comment', CommentType::class, [ 'label' => 'Comment', 'required' => false, diff --git a/src/Bundle/ChillEventBundle/Repository/EventBudgetKindRepository.php b/src/Bundle/ChillEventBundle/Repository/EventBudgetKindRepository.php new file mode 100644 index 000000000..0c40fce7d --- /dev/null +++ b/src/Bundle/ChillEventBundle/Repository/EventBudgetKindRepository.php @@ -0,0 +1,46 @@ + + */ +class EventBudgetKindRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, EventBudgetKind::class); + } + + public function findByActive(): array + { + return $this->createQueryBuilder('e') + ->select('e') + ->where('e.active = True') + ->getQuery() + ->getResult(); + } + + public function findByType(string $type): array + { + return $this->createQueryBuilder('e') + ->select('e') + ->where('e.type = :type') + ->setParameter('type', $type) + ->getQuery() + ->getResult(); + } +} diff --git a/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig b/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig index 279bf4588..1f7b58baf 100644 --- a/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig +++ b/src/Bundle/ChillEventBundle/Resources/views/Event/new.html.twig @@ -23,6 +23,7 @@ {{ form_row(form.location) }}
{{ form_row(form.organizationCost) }} + {{ form_row(form.budgetElements) }} {{ form_row(form.comment) }} {{ form_row(form.documents) }} diff --git a/src/Bundle/ChillEventBundle/config/services/forms.yaml b/src/Bundle/ChillEventBundle/config/services/forms.yaml index 93407204b..f8883ecb3 100644 --- a/src/Bundle/ChillEventBundle/config/services/forms.yaml +++ b/src/Bundle/ChillEventBundle/config/services/forms.yaml @@ -44,4 +44,8 @@ services: tags: - { name: form.type } + Chill\EventBundle\Form\AddEventBudgetElementType: + tags: + - { name: form.type } + diff --git a/src/Bundle/ChillEventBundle/migrations/Version20250505120818.php b/src/Bundle/ChillEventBundle/migrations/Version20250505120818.php index 52e219694..464fbbf91 100644 --- a/src/Bundle/ChillEventBundle/migrations/Version20250505120818.php +++ b/src/Bundle/ChillEventBundle/migrations/Version20250505120818.php @@ -17,20 +17,20 @@ final class Version20250505120818 extends AbstractMigration public function up(Schema $schema): void { $this->addSql(<<<'SQL' - CREATE SEQUENCE chill_event_budget_element_kind_id_seq INCREMENT BY 1 MINVALUE 1 START 1 + CREATE SEQUENCE chill_event_budget_kind_id_seq INCREMENT BY 1 MINVALUE 1 START 1 SQL); $this->addSql(<<<'SQL' - CREATE TABLE chill_event_budget_element_kind (id INT NOT NULL, isActive BOOLEAN DEFAULT true NOT NULL, type VARCHAR(255) NOT NULL, name JSONB DEFAULT '{}' NOT NULL, PRIMARY KEY(id)) + CREATE TABLE chill_event_budget_kind (id INT NOT NULL, isActive BOOLEAN DEFAULT true NOT NULL, type VARCHAR(255) NOT NULL, name JSONB DEFAULT '{}' NOT NULL, PRIMARY KEY(id)) SQL); } public function down(Schema $schema): void { $this->addSql(<<<'SQL' - DROP SEQUENCE chill_event_budget_element_kind_id_seq CASCADE + DROP SEQUENCE chill_event_budget_kind_id_seq CASCADE SQL); $this->addSql(<<<'SQL' - DROP TABLE chill_event_budget_element_kind + DROP TABLE chill_event_budget_kind SQL); } } diff --git a/src/Bundle/ChillEventBundle/migrations/Version20250506114531.php b/src/Bundle/ChillEventBundle/migrations/Version20250506114531.php new file mode 100644 index 000000000..0b28eb55c --- /dev/null +++ b/src/Bundle/ChillEventBundle/migrations/Version20250506114531.php @@ -0,0 +1,57 @@ +addSql(<<<'SQL' + CREATE SEQUENCE chill_event_budget_element_id_seq INCREMENT BY 1 MINVALUE 1 START 1 + SQL); + $this->addSql(<<<'SQL' + CREATE TABLE chill_event_budget_element (id INT NOT NULL, event_id INT DEFAULT NULL, kind_id INT DEFAULT NULL, amount NUMERIC(10, 2) NOT NULL, comment_budget_element_comment TEXT DEFAULT NULL, comment_budget_element_date TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, comment_budget_element_userId INT DEFAULT NULL, PRIMARY KEY(id)) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_BA25859071F7E88B ON chill_event_budget_element (event_id) + SQL); + $this->addSql(<<<'SQL' + CREATE INDEX IDX_BA25859030602CA9 ON chill_event_budget_element (kind_id) + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_event_budget_element ADD CONSTRAINT FK_BA25859071F7E88B FOREIGN KEY (event_id) REFERENCES chill_event_event (id) NOT DEFERRABLE INITIALLY IMMEDIATE + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_event_budget_element ADD CONSTRAINT FK_BA25859030602CA9 FOREIGN KEY (kind_id) REFERENCES chill_event_budget_kind (id) NOT DEFERRABLE INITIALLY IMMEDIATE + SQL); + } + + public function down(Schema $schema): void + { + $this->addSql(<<<'SQL' + DROP SEQUENCE chill_event_budget_element_id_seq CASCADE + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_event_budget_element DROP CONSTRAINT FK_BA25859071F7E88B + SQL); + $this->addSql(<<<'SQL' + ALTER TABLE chill_event_budget_element DROP CONSTRAINT FK_BA25859030602CA9 + SQL); + $this->addSql(<<<'SQL' + DROP TABLE chill_event_budget_element + SQL); + } +}