Add event budget element entity, forms and event property

This commit is contained in:
Julie Lenaerts 2025-05-06 14:03:25 +02:00
parent 9baf15221f
commit b024eef493
10 changed files with 322 additions and 6 deletions

View File

@ -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<int, EventBudgetElement>
*/
#[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<int, EventBudgetElement>
*/
public function getBudgetElements(): Collection
{
return $this->budgetElements;
}
/**
* @return Collection<int, Participation>
*/
@ -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.
*/

View File

@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\EventBundle\Entity;
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ORM\Table(name: 'chill_event_budget_element')]
class EventBudgetElement
{
#[ORM\Column(name: 'id', type: Types::INTEGER)]
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'AUTO')]
private ?int $id = null;
#[Assert\GreaterThan(value: 0)]
#[Assert\NotNull(message: 'The amount cannot be empty')]
#[ORM\Column(name: 'amount', type: Types::DECIMAL, precision: 10, scale: 2)]
private string $amount;
#[ORM\Embedded(class: CommentEmbeddable::class, columnPrefix: 'comment_budget_element_')]
private ?CommentEmbeddable $comment = null;
#[ORM\ManyToOne(targetEntity: Event::class)]
private Event $event;
#[ORM\ManyToOne(targetEntity: EventBudgetKind::class, inversedBy: 'EventBudgetElement')]
#[ORM\JoinColumn]
private EventBudgetKind $kind;
/* Getters and Setters */
public function getId(): ?int
{
return $this->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;
}
}

View File

@ -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]

View File

@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\EventBundle\Form;
use Chill\EventBundle\Entity\BudgetTypeEnum;
use Chill\EventBundle\Entity\EventBudgetElement;
use Chill\EventBundle\Entity\EventBudgetKind;
use Chill\EventBundle\Repository\EventBudgetKindRepository;
use Chill\MainBundle\Form\Type\CommentType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AddEventBudgetElementType extends AbstractType
{
public function __construct(private EventBudgetKindRepository $kindRepository, private readonly TranslatableStringHelperInterface $translatableStringHelper) {}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$charges = $this->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,
]);
}
}

View File

@ -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,

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\EventBundle\Repository;
use Chill\EventBundle\Entity\EventBudgetKind;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<EventBudgetKind>
*/
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();
}
}

View File

@ -23,6 +23,7 @@
{{ form_row(form.location) }}
<div id="location"></div>
{{ form_row(form.organizationCost) }}
{{ form_row(form.budgetElements) }}
{{ form_row(form.comment) }}
{{ form_row(form.documents) }}

View File

@ -44,4 +44,8 @@ services:
tags:
- { name: form.type }
Chill\EventBundle\Form\AddEventBudgetElementType:
tags:
- { name: form.type }

View File

@ -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);
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Event;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250506114531 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
$this->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);
}
}