mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-11-04 03:08:25 +00:00 
			
		
		
		
	Merge branch 'features/household' into 'master'
Manage household See merge request Chill-Projet/chill-bundles!70
This commit is contained in:
		@@ -0,0 +1,29 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\Migrations\Main;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add extension btree_gist
 | 
			
		||||
 */
 | 
			
		||||
final class Version20210528090000 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'add extension btree_gist';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('CREATE EXTENSION IF NOT EXISTS btree_gist');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('DROP EXTENSION btree_gist');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Controller;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\Serializer\Exception;
 | 
			
		||||
use Symfony\Component\Routing\Annotation\Route;
 | 
			
		||||
use Chill\MainBundle\CRUD\Controller\ApiController;
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditor;
 | 
			
		||||
 | 
			
		||||
class HouseholdMemberController extends ApiController
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @Route(
 | 
			
		||||
     *      "/api/1.0/person/household/members/move.{_format}",
 | 
			
		||||
     *      name="chill_person_household_members_move"
 | 
			
		||||
     *  )
 | 
			
		||||
     */
 | 
			
		||||
    public function move(Request $request, $_format): Response
 | 
			
		||||
    {
 | 
			
		||||
        try {
 | 
			
		||||
            $editor = $this->getSerializer()
 | 
			
		||||
                ->deserialize($request->getContent(), MembersEditor::class,
 | 
			
		||||
                    $_format, ['groups' => [ "read" ]]);
 | 
			
		||||
        } catch (Exception\InvalidArgumentException | Exception\UnexpectedValueException $e) {
 | 
			
		||||
            throw new BadRequestException("Deserialization error: {$e->getMessage()}", 45896, $e);
 | 
			
		||||
        }
 | 
			
		||||
        dump($editor);
 | 
			
		||||
        // TODO ACL
 | 
			
		||||
        //
 | 
			
		||||
        // TODO validation
 | 
			
		||||
        //
 | 
			
		||||
        $em = $this->getDoctrine()->getManager();
 | 
			
		||||
 | 
			
		||||
        // to ensure closing membership before creating one, we must manually open a transaction
 | 
			
		||||
        $em->beginTransaction();
 | 
			
		||||
 | 
			
		||||
        foreach ($editor->getPersistable() as $el) {
 | 
			
		||||
           $em->persist($el); 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $em->flush();
 | 
			
		||||
        $em->commit();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return $this->json($editor->getHousehold(), Response::HTTP_OK, ["groups" => ["read"]]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHousehold.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/Bundle/ChillPersonBundle/DataFixtures/ORM/LoadHousehold.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\DataFixtures\ORM;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditorFactory;
 | 
			
		||||
use Doctrine\Bundle\FixturesBundle\Fixture;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
use Doctrine\Common\DataFixtures\DependentFixtureInterface;
 | 
			
		||||
 | 
			
		||||
class LoadHousehold extends Fixture implements DependentFixtureInterface
 | 
			
		||||
{
 | 
			
		||||
    private MembersEditorFactory $editorFactory;
 | 
			
		||||
 | 
			
		||||
    private EntityManagerInterface $em;
 | 
			
		||||
 | 
			
		||||
    private CONST NUMBER_OF_HOUSEHOLD = 10;
 | 
			
		||||
 | 
			
		||||
    public function __construct(MembersEditorFactory $editorFactory, EntityManagerInterface $em)
 | 
			
		||||
    {
 | 
			
		||||
        $this->editorFactory = $editorFactory;
 | 
			
		||||
        $this->em = $em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function load(ObjectManager $manager)
 | 
			
		||||
    {
 | 
			
		||||
        // generate two times the participation. This will lead to 
 | 
			
		||||
        // some movement in participation (same people in two differents
 | 
			
		||||
        // households)
 | 
			
		||||
 | 
			
		||||
        $this->preparePersonIds();
 | 
			
		||||
 | 
			
		||||
        $this->generateHousehold(
 | 
			
		||||
            $manager,
 | 
			
		||||
            \DateTimeImmutable::createFromFormat('Y-m-d', '2010-01-01')
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $this->preparePersonIds();
 | 
			
		||||
 | 
			
		||||
        $this->generateHousehold(
 | 
			
		||||
            $manager,
 | 
			
		||||
            \DateTimeImmutable::createFromFormat('Y-m-d', '2015-01-01')
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $manager->flush();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function generateHousehold(ObjectManager $manager, \DateTimeImmutable $startDate)
 | 
			
		||||
    {
 | 
			
		||||
        for ($i=0; $i < self::NUMBER_OF_HOUSEHOLD; $i++) {
 | 
			
		||||
            $household = new Household();
 | 
			
		||||
            $manager->persist($household);
 | 
			
		||||
 | 
			
		||||
            $movement = $this->editorFactory->createEditor($household);
 | 
			
		||||
 | 
			
		||||
            // load adults
 | 
			
		||||
            $k = 0;
 | 
			
		||||
            foreach ($this->getRandomPersons(1, 3) as $person) {
 | 
			
		||||
                $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W'));
 | 
			
		||||
                $position = $this->getReference(LoadHouseholdPosition::ADULT);
 | 
			
		||||
 | 
			
		||||
                $movement->addMovement($date, $person, $position, $k === 0, "self generated");
 | 
			
		||||
                $k++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // load children
 | 
			
		||||
            foreach ($this->getRandomPersons(0, 3) as $person) {
 | 
			
		||||
                $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W'));
 | 
			
		||||
                $position = $this->getReference(LoadHouseholdPosition::CHILD);
 | 
			
		||||
 | 
			
		||||
                $movement->addMovement($date, $person, $position, $k === 0, "self generated");
 | 
			
		||||
                $k++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // load children out
 | 
			
		||||
            foreach ($this->getRandomPersons(0, 2) as $person) {
 | 
			
		||||
                $date = $startDate->add(new \DateInterval('P'.\random_int(1, 200).'W'));
 | 
			
		||||
                $position = $this->getReference(LoadHouseholdPosition::CHILD_OUT);
 | 
			
		||||
 | 
			
		||||
                $movement->addMovement($date, $person, $position, $k === 0, "self generated");
 | 
			
		||||
                $k++;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach ($movement->getPersistable() as $obj) {
 | 
			
		||||
                $manager->persist($obj);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function preparePersonIds()
 | 
			
		||||
    {
 | 
			
		||||
        $this->personIds = $this->em
 | 
			
		||||
            ->createQuery('SELECT p.id FROM '.Person::class.' p '.
 | 
			
		||||
                'JOIN p.center c '.
 | 
			
		||||
                'WHERE c.name = :center '
 | 
			
		||||
            )
 | 
			
		||||
            ->setParameter('center', 'Center A')
 | 
			
		||||
            ->getScalarResult()
 | 
			
		||||
            ;
 | 
			
		||||
        \shuffle($this->personIds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getRandomPersons(int $min, int $max)
 | 
			
		||||
    {
 | 
			
		||||
        $nb = \random_int($min, $max);
 | 
			
		||||
 | 
			
		||||
        for ($i=0; $i < $nb; $i++) {
 | 
			
		||||
            $personId = \array_pop($this->personIds)['id'];
 | 
			
		||||
            $persons[] = $this->em->getRepository(Person::class)
 | 
			
		||||
                ->find($personId)
 | 
			
		||||
                ;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $persons ?? [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getDependencies()
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            LoadPeople::class,
 | 
			
		||||
            LoadHouseholdPosition::class
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\DataFixtures\ORM;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Doctrine\Bundle\FixturesBundle\Fixture;
 | 
			
		||||
use Doctrine\Persistence\ObjectManager;
 | 
			
		||||
 | 
			
		||||
class LoadHouseholdPosition extends Fixture
 | 
			
		||||
{
 | 
			
		||||
    const POSITIONS_DATA = [
 | 
			
		||||
        ["Adulte", true, true, 1.0, self::ADULT ],
 | 
			
		||||
        ["Enfants", true, false, 2.0, self::CHILD ],
 | 
			
		||||
        ["Enfants hors ménage", false, false, 3.0, self::CHILD_OUT ]
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const ADULT = "position_adulte";
 | 
			
		||||
    const CHILD = "position_enfant";
 | 
			
		||||
    const CHILD_OUT = "position_enfant_hors";
 | 
			
		||||
 | 
			
		||||
    public function load(ObjectManager $manager)
 | 
			
		||||
    {
 | 
			
		||||
        foreach (self::POSITIONS_DATA as list($name, $share, $allowHolder, 
 | 
			
		||||
            $ordering, $ref)) {
 | 
			
		||||
            $position = (new Position())
 | 
			
		||||
                ->setLabel([ "fr" => $name ])
 | 
			
		||||
                ->setAllowHolder($allowHolder)
 | 
			
		||||
                ->setShareHousehold($share)
 | 
			
		||||
                ->setOrdering($ordering)
 | 
			
		||||
                ;
 | 
			
		||||
 | 
			
		||||
            $manager->persist($position);
 | 
			
		||||
            $this->addReference($ref, $position);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $manager->flush();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -74,6 +74,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
 | 
			
		||||
        $loader->load('services/form.yaml');
 | 
			
		||||
        $loader->load('services/templating.yaml');
 | 
			
		||||
        $loader->load('services/alt_names.yaml');
 | 
			
		||||
        $loader->load('services/household.yaml');
 | 
			
		||||
        // We can get rid of this file when the service 'chill.person.repository.person' is no more used.
 | 
			
		||||
        // We should use the PersonRepository service instead of a custom service name.
 | 
			
		||||
        $loader->load('services/repository.yaml');
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,16 @@ namespace Chill\PersonBundle\Entity\Household;
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Doctrine\Common\Collections\Collection;
 | 
			
		||||
use Chill\MainBundle\Entity\Address;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation as Serializer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity
 | 
			
		||||
 * @ORM\Table(
 | 
			
		||||
 *      name="chill_person_household"
 | 
			
		||||
 *  )
 | 
			
		||||
 * @Serializer\DiscriminatorMap(typeProperty="type", mapping={
 | 
			
		||||
 *    "household"=Household::class
 | 
			
		||||
 * })
 | 
			
		||||
 */
 | 
			
		||||
class Household
 | 
			
		||||
{
 | 
			
		||||
@@ -15,6 +22,7 @@ class Household
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\GeneratedValue
 | 
			
		||||
     * @ORM\Column(type="integer")
 | 
			
		||||
     * @Serializer\Groups({"read"})
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,186 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Entity\Household;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity
 | 
			
		||||
 * @ORM\Table(
 | 
			
		||||
 *      name="chill_person_household_members"
 | 
			
		||||
 *  )
 | 
			
		||||
 */
 | 
			
		||||
class HouseholdMember
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\GeneratedValue
 | 
			
		||||
     * @ORM\Column(type="integer")
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\ManyToOne(targetEntity=Position::class)
 | 
			
		||||
     */
 | 
			
		||||
    private ?Position $position = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
 | 
			
		||||
     */
 | 
			
		||||
    private ?\DateTimeImmutable $startDate = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="date_immutable", nullable= true, options={"default": null})
 | 
			
		||||
     */
 | 
			
		||||
    private ?\DateTimeImmutable $endDate = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     */
 | 
			
		||||
    private ?string $comment = NULL;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="boolean")
 | 
			
		||||
     */
 | 
			
		||||
    private bool $sharedHousehold = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="boolean", options={"default": false})
 | 
			
		||||
     */
 | 
			
		||||
    private bool $holder = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var Person
 | 
			
		||||
     * @ORM\ManyToOne(
 | 
			
		||||
     *  targetEntity="\Chill\PersonBundle\Entity\Person"
 | 
			
		||||
     * )
 | 
			
		||||
     */
 | 
			
		||||
    private ?Person $person = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var Household
 | 
			
		||||
     * @ORM\ManyToOne(
 | 
			
		||||
     *  targetEntity="\Chill\PersonBundle\Entity\Household\Household"
 | 
			
		||||
     * )
 | 
			
		||||
     */
 | 
			
		||||
    private ?Household $household = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function getId(): ?int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPosition(): ?Position
 | 
			
		||||
    {
 | 
			
		||||
        return $this->position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPosition(Position $position): self
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->position instanceof Position) {
 | 
			
		||||
            throw new \LogicException("The position is already set. You cannot change ".
 | 
			
		||||
                "a position of a membership");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->position = $position;
 | 
			
		||||
        $this->sharedHousehold = $position->getShareHousehold();
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStartDate(): ?\DateTimeImmutable
 | 
			
		||||
    {
 | 
			
		||||
        return $this->startDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStartDate(\DateTimeImmutable $startDate): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->startDate = $startDate;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getEndDate(): ?\DateTimeImmutable
 | 
			
		||||
    {
 | 
			
		||||
        return $this->endDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setEndDate(\DateTimeImmutable $endDate): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->endDate = $endDate;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getComment(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->comment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setComment(?string $comment): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->comment = $comment;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getShareHousehold(): ?bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->sharedHousehold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function getPerson(): ?Person
 | 
			
		||||
    {
 | 
			
		||||
        return $this->person;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPerson(?Person $person): self
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->person instanceof Person) {
 | 
			
		||||
            throw new \LogicException("You cannot change person ".
 | 
			
		||||
                "on a membership");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->person = $person;
 | 
			
		||||
        $this->person->addHouseholdParticipation($this);
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHousehold(): ?Household
 | 
			
		||||
    {
 | 
			
		||||
        return $this->household;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setHousehold(?Household $household): self
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->household instanceof Household) {
 | 
			
		||||
            throw new \LogicException("You cannot change household ".
 | 
			
		||||
                "on a membership");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->household = $household;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setHolder(bool $holder): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->holder = $holder;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isHolder(): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->holder;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,152 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Entity\Household;
 | 
			
		||||
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity
 | 
			
		||||
 */
 | 
			
		||||
class HouseholdMembers
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\GeneratedValue
 | 
			
		||||
     * @ORM\Column(type="integer")
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     */
 | 
			
		||||
    private $position;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="date")
 | 
			
		||||
     */
 | 
			
		||||
    private $startDate;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="date")
 | 
			
		||||
     */
 | 
			
		||||
    private $endDate;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="string", length=255, nullable=true)
 | 
			
		||||
     */
 | 
			
		||||
    private $comment;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="boolean")
 | 
			
		||||
     */
 | 
			
		||||
    private $sharedHousehold;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var Person
 | 
			
		||||
     * @ORM\ManyToOne(
 | 
			
		||||
     *  targetEntity="\Chill\PersonBundle\Entity\Person"
 | 
			
		||||
     * )
 | 
			
		||||
     */
 | 
			
		||||
    private $person;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @var Household
 | 
			
		||||
     * @ORM\ManyToOne(
 | 
			
		||||
     *  targetEntity="\Chill\PersonBundle\Entity\Household\Household"
 | 
			
		||||
     * )
 | 
			
		||||
     */
 | 
			
		||||
    private $household;
 | 
			
		||||
 | 
			
		||||
    public function getId(): ?int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPosition(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->position;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPosition(?string $position): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->position = $position;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getStartDate(): ?\DateTimeInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->startDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStartDate(\DateTimeInterface $startDate): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->startDate = $startDate;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getEndDate(): ?\DateTimeInterface
 | 
			
		||||
    {
 | 
			
		||||
        return $this->endDate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setEndDate(\DateTimeInterface $endDate): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->endDate = $endDate;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getComment(): ?string
 | 
			
		||||
    {
 | 
			
		||||
        return $this->comment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setComment(?string $comment): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->comment = $comment;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getSharedHousehold(): ?bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->sharedHousehold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setSharedHousehold(bool $sharedHousehold): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->sharedHousehold = $sharedHousehold;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPerson(): ?Person
 | 
			
		||||
    {
 | 
			
		||||
        return $this->person;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setPerson(?Person $person): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->person = $person;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHousehold(): ?Household
 | 
			
		||||
    {
 | 
			
		||||
        return $this->household;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setHousehold(?Household $household): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->household = $household;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								src/Bundle/ChillPersonBundle/Entity/Household/Position.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/Bundle/ChillPersonBundle/Entity/Household/Position.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Entity\Household;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Repository\Household\PositionRepository;
 | 
			
		||||
use Doctrine\ORM\Mapping as ORM;
 | 
			
		||||
use Symfony\Component\Serializer\Annotation as Serializer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ORM\Entity(repositoryClass=PositionRepository::class)
 | 
			
		||||
 * @ORM\Table(name="chill_person_household_position")
 | 
			
		||||
 * @Serializer\DiscriminatorMap(typeProperty="type", mapping={
 | 
			
		||||
 *   "household_position"=Position::class
 | 
			
		||||
 *   })
 | 
			
		||||
 */
 | 
			
		||||
class Position
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Id
 | 
			
		||||
     * @ORM\GeneratedValue
 | 
			
		||||
     * @ORM\Column(type="integer")
 | 
			
		||||
     * @Serializer\Groups({ "read" })
 | 
			
		||||
     */
 | 
			
		||||
    private $id;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="json")
 | 
			
		||||
     */
 | 
			
		||||
    private $label = [];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="boolean")
 | 
			
		||||
     */
 | 
			
		||||
    private $shareHouseHold;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="boolean")
 | 
			
		||||
     */
 | 
			
		||||
    private $allowHolder;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\Column(type="float")
 | 
			
		||||
     */
 | 
			
		||||
    private $ordering;
 | 
			
		||||
 | 
			
		||||
    public function getId(): ?int
 | 
			
		||||
    {
 | 
			
		||||
        return $this->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getLabel(): ?array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->label;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setLabel(array $label): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->label = $label;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getShareHousehold(): ?bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->shareHouseHold;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setShareHousehold(bool $shareHouseHold): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->shareHouseHold = $shareHouseHold;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getAllowHolder(): ?bool
 | 
			
		||||
    {
 | 
			
		||||
        return $this->allowHolder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setAllowHolder(bool $allowHolder): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->allowHolder = $allowHolder;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getOrdering(): ?float
 | 
			
		||||
    {
 | 
			
		||||
        return $this->ordering;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setOrdering(float $ordering): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->ordering = $ordering;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,6 +26,7 @@ use ArrayIterator;
 | 
			
		||||
use Chill\MainBundle\Entity\Center;
 | 
			
		||||
use Chill\MainBundle\Entity\Country;
 | 
			
		||||
use Chill\PersonBundle\Entity\MaritalStatus;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
 | 
			
		||||
use Chill\MainBundle\Entity\HasCenterInterface;
 | 
			
		||||
use Chill\MainBundle\Entity\Address;
 | 
			
		||||
use DateTime;
 | 
			
		||||
@@ -272,6 +273,14 @@ class Person implements HasCenterInterface
 | 
			
		||||
     */
 | 
			
		||||
    private $fullnameCanonical;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @ORM\OneToMany(
 | 
			
		||||
     *  targetEntity=HouseholdMember::class,
 | 
			
		||||
     *  mappedBy="person"
 | 
			
		||||
     * )
 | 
			
		||||
     */
 | 
			
		||||
    private Collection $householdParticipations;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Person constructor.
 | 
			
		||||
     *
 | 
			
		||||
@@ -284,6 +293,7 @@ class Person implements HasCenterInterface
 | 
			
		||||
        $this->addresses = new ArrayCollection();
 | 
			
		||||
        $this->altNames = new ArrayCollection();
 | 
			
		||||
        $this->otherPhoneNumbers = new ArrayCollection();
 | 
			
		||||
        $this->householdParticipations = new ArrayCollection();
 | 
			
		||||
 | 
			
		||||
        if ($opening === null) {
 | 
			
		||||
            $opening = new \DateTime();
 | 
			
		||||
@@ -1180,4 +1190,16 @@ class Person implements HasCenterInterface
 | 
			
		||||
        $this->fullnameCanonical = $fullnameCanonical;
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addHouseholdParticipation(HouseholdMember $member): self
 | 
			
		||||
    {
 | 
			
		||||
        $this->householdParticipations[] = $member;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHouseholdParticipations(): Collection
 | 
			
		||||
    {
 | 
			
		||||
        return $this->householdParticipations;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								src/Bundle/ChillPersonBundle/Household/MembersEditor.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/Bundle/ChillPersonBundle/Household/MembersEditor.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Household;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MembersEditor
 | 
			
		||||
{
 | 
			
		||||
    private ValidatorInterface $validator;
 | 
			
		||||
    private Household $household;
 | 
			
		||||
 | 
			
		||||
    private array $persistables = [];
 | 
			
		||||
    private array $membershipsAffected = [];
 | 
			
		||||
 | 
			
		||||
    public function __construct(ValidatorInterface $validator, Household $household)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validation = $validator;
 | 
			
		||||
        $this->household = $household;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public function addMovement(\DateTimeImmutable $date, Person $person, Position $position, ?bool $holder = false, ?string $comment = null): self
 | 
			
		||||
    {
 | 
			
		||||
        if (NULL === $this->household) {
 | 
			
		||||
            throw new \LogicException("You must define a household first");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $membership = (new HouseholdMember())
 | 
			
		||||
            ->setStartDate($date)
 | 
			
		||||
            ->setPerson($person)
 | 
			
		||||
            ->setPosition($position)
 | 
			
		||||
            ->setHolder($holder)
 | 
			
		||||
            ->setHousehold($this->household)
 | 
			
		||||
            ->setComment($comment)
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        if ($position->getShareHousehold()) {
 | 
			
		||||
            foreach ($person->getHouseholdParticipations() as $participation) {
 | 
			
		||||
                if (FALSE === $participation->getShareHousehold()) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($participation === $membership) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($participation->getEndDate() === NULL || $participation->getEndDate() > $date) {
 | 
			
		||||
                    $participation->setEndDate($date);
 | 
			
		||||
                    $this->membershipsAffected[] = $participation;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->membershipsAffected[] = $membership;
 | 
			
		||||
        $this->persistables[] = $membership;
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function validate(): ConstraintViolationListInterface
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getPersistable(): array
 | 
			
		||||
    {
 | 
			
		||||
        return $this->persistables;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getHousehold(): Household
 | 
			
		||||
    {
 | 
			
		||||
        return $this->household;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Household;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditor;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MembersEditorFactory
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(ValidatorInterface $validator)
 | 
			
		||||
    {
 | 
			
		||||
        $this->validator = $validator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function createEditor(Household $household): MembersEditor
 | 
			
		||||
    {
 | 
			
		||||
        return new MembersEditor($this->validator, $household);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Repository\Household;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
 | 
			
		||||
use Doctrine\Persistence\ManagerRegistry;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @method Position|null find($id, $lockMode = null, $lockVersion = null)
 | 
			
		||||
 * @method Position|null findOneBy(array $criteria, array $orderBy = null)
 | 
			
		||||
 * @method Position[]    findAll()
 | 
			
		||||
 * @method Position[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 | 
			
		||||
 */
 | 
			
		||||
class PositionRepository extends ServiceEntityRepository
 | 
			
		||||
{
 | 
			
		||||
    public function __construct(ManagerRegistry $registry)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct($registry, Position::class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Serializer\Normalizer;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
 | 
			
		||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
 | 
			
		||||
use Symfony\Component\Serializer\Exception;
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditorFactory;
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditor;
 | 
			
		||||
 | 
			
		||||
class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwareInterface
 | 
			
		||||
{
 | 
			
		||||
    private MembersEditorFactory $factory;
 | 
			
		||||
 | 
			
		||||
    use DenormalizerAwareTrait;
 | 
			
		||||
 | 
			
		||||
    public function __construct(MembersEditorFactory $factory)
 | 
			
		||||
    {
 | 
			
		||||
        $this->factory = $factory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function denormalize($data, string $type, string $format = null, array $context = [])
 | 
			
		||||
    {
 | 
			
		||||
        $household = $this->denormalizer->denormalize($data['destination'], Household::class, 
 | 
			
		||||
            $format, $context);
 | 
			
		||||
 | 
			
		||||
        if (NULL === $household) {
 | 
			
		||||
           throw new Exception\InvalidArgumentException("household could not be denormalized. Impossible to process"); 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $editor = $this->factory->createEditor($household);
 | 
			
		||||
 | 
			
		||||
        if (NULL == $data['concerned'] ?? [] 
 | 
			
		||||
            && FALSE === ·\is_array('concerned')) {
 | 
			
		||||
            throw new Exception\UnexpectedValueException("The schema does not have any key 'concerned'");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($data['concerned'] as $key => $concerned) {
 | 
			
		||||
            $person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class, 
 | 
			
		||||
                $format, $context); 
 | 
			
		||||
            $position = $this->denormalizer->denormalize($concerned['position'] ?? null, Position::class,
 | 
			
		||||
                $format, $context);
 | 
			
		||||
            $startDate = $this->denormalizer->denormalize($concerned['start_date'] ?? null, \DateTimeImmutable::class,
 | 
			
		||||
                $format, $context);
 | 
			
		||||
 | 
			
		||||
            $holder = (bool) $concerned['holder'] ?? false;
 | 
			
		||||
            $comment = (string) $concerned['comment'] ?? false;
 | 
			
		||||
 | 
			
		||||
            if (
 | 
			
		||||
                NULL === $person
 | 
			
		||||
                && NULL === $position
 | 
			
		||||
                && NULL === $startDate
 | 
			
		||||
            ) {
 | 
			
		||||
                throw new Exception\InvalidArgumentException("position with ".
 | 
			
		||||
                    "key $key could not be denormalized: missing ".
 | 
			
		||||
                    "person, position or start_date.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $editor->addMovement($startDate, $person, $position, $holder, 
 | 
			
		||||
                $comment);
 | 
			
		||||
 | 
			
		||||
            return $editor;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function supportsDenormalization($data, string $type, string $format = null)
 | 
			
		||||
    {
 | 
			
		||||
        return $type === MembersEditor::class;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,98 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Bundle\ChillPersonBundle\Tests\Controller;
 | 
			
		||||
 | 
			
		||||
use Symfony\Component\HttpFoundation\Response;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
use Chill\MainBundle\Test\PrepareClientTrait;
 | 
			
		||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Doctrine\ORM\EntityManagerInterface;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HouseholdMemberControllerTest extends WebTestCase
 | 
			
		||||
{
 | 
			
		||||
    use PrepareClientTrait;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @dataProvider provideValidData
 | 
			
		||||
     */
 | 
			
		||||
    public function testMoveMember($personId, $householdId, $positionId, \DateTimeInterface $date)
 | 
			
		||||
    {
 | 
			
		||||
        $client = $this->getClientAuthenticated();
 | 
			
		||||
 | 
			
		||||
        $client->request(
 | 
			
		||||
            Request::METHOD_POST,
 | 
			
		||||
            '/api/1.0/person/household/members/move.json',
 | 
			
		||||
            [], // parameters
 | 
			
		||||
            [], // files
 | 
			
		||||
            [], // server
 | 
			
		||||
            \json_encode(
 | 
			
		||||
                [
 | 
			
		||||
                    'concerned' => 
 | 
			
		||||
                    [
 | 
			
		||||
                        [ 
 | 
			
		||||
                            'person' => 
 | 
			
		||||
                            [ 
 | 
			
		||||
                                'type' => 'person',
 | 
			
		||||
                                'id' => $personId
 | 
			
		||||
                            ],
 | 
			
		||||
                            'start_date' => 
 | 
			
		||||
                            [
 | 
			
		||||
                                'datetime' => $date->format(\DateTimeInterface::RFC3339)
 | 
			
		||||
                            ],
 | 
			
		||||
                            'position' =>
 | 
			
		||||
                            [
 | 
			
		||||
                                'type' => 'household_position',
 | 
			
		||||
                                'id' => $positionId
 | 
			
		||||
                            ],
 | 
			
		||||
                            'holder' => false,
 | 
			
		||||
                            'comment' => "Introduced by automated test",
 | 
			
		||||
                        ],
 | 
			
		||||
                    ],
 | 
			
		||||
                    'destination' => 
 | 
			
		||||
                    [
 | 
			
		||||
                        'type' => 'household',
 | 
			
		||||
                        'id' => $householdId
 | 
			
		||||
                    ]
 | 
			
		||||
                ],
 | 
			
		||||
            true)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $this->assertEquals(Response::HTTP_OK, 
 | 
			
		||||
            $client->getResponse()->getStatusCode()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function provideValidData(): \Iterator
 | 
			
		||||
    {
 | 
			
		||||
        self::bootKernel();
 | 
			
		||||
        $em = self::$container->get(EntityManagerInterface::class);
 | 
			
		||||
 | 
			
		||||
        $personIds = $em->createQuery("SELECT p.id FROM ".Person::class." p ".
 | 
			
		||||
            "JOIN p.center c WHERE c.name = :center")
 | 
			
		||||
            ->setParameter('center', "Center A")
 | 
			
		||||
            ->setMaxResults(100)
 | 
			
		||||
            ->getScalarResult()
 | 
			
		||||
            ;
 | 
			
		||||
        \shuffle($personIds);
 | 
			
		||||
 | 
			
		||||
        $household = new Household();
 | 
			
		||||
        $em->persist($household);
 | 
			
		||||
        $em->flush();
 | 
			
		||||
 | 
			
		||||
        $positions = $em->createQuery("SELECT pos.id FROM ".Position::class." pos ".
 | 
			
		||||
            "WHERE pos.shareHouseHold = TRUE")
 | 
			
		||||
            ->getResult()
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        yield [ 
 | 
			
		||||
            \array_pop($personIds)['id'],
 | 
			
		||||
            $household->getId(), 
 | 
			
		||||
            $positions[\random_int(0, count($positions) - 1)]['id'],
 | 
			
		||||
            new \DateTimeImmutable('today')
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Bundle\ChillPersonBundle\Tests\Entity\Household;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
class HouseholdMemberTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    public function testPositionSharehousehold()
 | 
			
		||||
    {
 | 
			
		||||
        $position = (new Position())
 | 
			
		||||
            ->setShareHousehold(true)
 | 
			
		||||
            ;
 | 
			
		||||
        $membership = (new HouseholdMember())
 | 
			
		||||
            ->setPosition($position)
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($membership->getShareHousehold());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPositionDoNotSharehousehold()
 | 
			
		||||
    {
 | 
			
		||||
        $position = (new Position())
 | 
			
		||||
            ->setShareHousehold(false)
 | 
			
		||||
            ;
 | 
			
		||||
        $membership = (new HouseholdMember())
 | 
			
		||||
            ->setPosition($position)
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
        $this->assertFalse($membership->getShareHousehold());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,105 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Chill\PersonBundle\Tests\Household;
 | 
			
		||||
 | 
			
		||||
use Chill\PersonBundle\Entity\Person;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Household;
 | 
			
		||||
use Chill\PersonBundle\Entity\Household\Position;
 | 
			
		||||
use Chill\PersonBundle\Household\MembersEditorFactory;
 | 
			
		||||
use Doctrine\Common\Collections\Collection;
 | 
			
		||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
 | 
			
		||||
use PHPUnit\Framework\TestCase;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MembersEditorTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private MembersEditorFactory $factory;
 | 
			
		||||
 | 
			
		||||
    protected function setUp()
 | 
			
		||||
    {
 | 
			
		||||
        $validator = $this->createMock(ValidatorInterface::class);
 | 
			
		||||
 | 
			
		||||
        $this->factory = new MembersEditorFactory($validator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testMovePersonWithSharedHousehold()
 | 
			
		||||
    {
 | 
			
		||||
        $person = new Person();
 | 
			
		||||
        $position = (new Position())
 | 
			
		||||
            ->setShareHousehold(true)
 | 
			
		||||
            ;
 | 
			
		||||
        $household1 = new Household();
 | 
			
		||||
        $household2 = new Household();
 | 
			
		||||
        $editor = $this->factory->createEditor($household1);
 | 
			
		||||
 | 
			
		||||
        $editor->addMovement(
 | 
			
		||||
            \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'),
 | 
			
		||||
            $person,
 | 
			
		||||
            $position);
 | 
			
		||||
 | 
			
		||||
        $persistables = $editor->getPersistable();
 | 
			
		||||
        $this->assertEquals(\count($persistables), 1);
 | 
			
		||||
 | 
			
		||||
        $membership1 = $persistables[0];
 | 
			
		||||
        $this->assertSame($household1, $membership1->getHousehold());
 | 
			
		||||
        $this->assertNull($membership1->getEndDate());
 | 
			
		||||
 | 
			
		||||
        // move to another household
 | 
			
		||||
        $date = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01');
 | 
			
		||||
        $editor = $this->factory->createEditor($household2);
 | 
			
		||||
        $editor->addMovement(
 | 
			
		||||
            $date,
 | 
			
		||||
            $person,
 | 
			
		||||
            $position);
 | 
			
		||||
 | 
			
		||||
        $persistables = $editor->getPersistable();
 | 
			
		||||
        $this->assertEquals(1, count($persistables));
 | 
			
		||||
 | 
			
		||||
        $membership2 = $persistables[0];
 | 
			
		||||
        $this->assertSame($household2, $membership2->getHousehold());
 | 
			
		||||
        $this->assertNull($membership2->getEndDate());
 | 
			
		||||
        $this->assertNotNull($membership1->getEndDate(),
 | 
			
		||||
            "assert that the membership1 is closed");
 | 
			
		||||
        $this->assertEquals($date, $membership1->getEndDate());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testMovePersonWithoutSharedHousehold()
 | 
			
		||||
    {
 | 
			
		||||
        $person = new Person();
 | 
			
		||||
        $position = (new Position())
 | 
			
		||||
            ->setShareHousehold(false)
 | 
			
		||||
            ;
 | 
			
		||||
        $household1 = new Household();
 | 
			
		||||
        $household2 = new Household();
 | 
			
		||||
        $editor = $this->factory->createEditor($household1);
 | 
			
		||||
 | 
			
		||||
        $editor->addMovement(
 | 
			
		||||
            \DateTimeImmutable::createFromFormat('Y-m-d', '2020-01-01'),
 | 
			
		||||
            $person,
 | 
			
		||||
            $position);
 | 
			
		||||
 | 
			
		||||
        $persistables = $editor->getPersistable();
 | 
			
		||||
        $this->assertEquals(1, count($persistables));
 | 
			
		||||
 | 
			
		||||
        $membership1 = $person->getHouseholdParticipations()->first();
 | 
			
		||||
        $this->assertSame($household1, $membership1->getHousehold());
 | 
			
		||||
        $this->assertNull($membership1->getEndDate());
 | 
			
		||||
 | 
			
		||||
        // move to another household
 | 
			
		||||
        $date = \DateTimeImmutable::createFromFormat('Y-m-d', '2021-01-01');
 | 
			
		||||
        $editor = $this->factory->createEditor($household2);
 | 
			
		||||
        $editor->addMovement(
 | 
			
		||||
            $date,
 | 
			
		||||
            $person,
 | 
			
		||||
            $position);
 | 
			
		||||
 | 
			
		||||
        $persistables = $editor->getPersistable();
 | 
			
		||||
        $this->assertEquals(1, count($persistables));
 | 
			
		||||
 | 
			
		||||
        $membership2 = $person->getHouseholdParticipations()->last();
 | 
			
		||||
        $this->assertNull($membership2->getEndDate());
 | 
			
		||||
        $this->assertSame($household2, $membership2->getHousehold());
 | 
			
		||||
        $this->assertNull($membership1->getEndDate(),
 | 
			
		||||
            "assert that the membership1 is not closed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -192,6 +192,25 @@ components:
 | 
			
		||||
        text:
 | 
			
		||||
          type: string
 | 
			
		||||
          readOnly: true
 | 
			
		||||
    Household:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
          id:
 | 
			
		||||
            type: integer
 | 
			
		||||
          type:
 | 
			
		||||
            type: string
 | 
			
		||||
            enum:
 | 
			
		||||
              - 'household'
 | 
			
		||||
    HouseholdPosition:
 | 
			
		||||
      type: object
 | 
			
		||||
      properties:
 | 
			
		||||
        id:
 | 
			
		||||
          type: integer
 | 
			
		||||
        type:
 | 
			
		||||
          type: string
 | 
			
		||||
          enum:
 | 
			
		||||
            - 'household_position'
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
paths:
 | 
			
		||||
  /1.0/person/person/{id}.json:
 | 
			
		||||
@@ -764,3 +783,46 @@ paths:
 | 
			
		||||
          description: "OK"
 | 
			
		||||
        400:
 | 
			
		||||
          description: "transition cannot be applyed"
 | 
			
		||||
 | 
			
		||||
  /1.0/person/household/members/move.json:
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - household
 | 
			
		||||
      summary: move one or multiple person from a household to another
 | 
			
		||||
      requestBody:
 | 
			
		||||
        required: true
 | 
			
		||||
        content:
 | 
			
		||||
          application/json:
 | 
			
		||||
            schema:
 | 
			
		||||
              type: object
 | 
			
		||||
              properties:
 | 
			
		||||
                concerned:
 | 
			
		||||
                  type: array
 | 
			
		||||
                  items:
 | 
			
		||||
                    type: object
 | 
			
		||||
                    properties:
 | 
			
		||||
                      person:
 | 
			
		||||
                          $ref: '#/components/schemas/PersonById'
 | 
			
		||||
                      start_date:
 | 
			
		||||
                          $ref: '#/components/schemas/Date'
 | 
			
		||||
                      position:
 | 
			
		||||
                          $ref: '#/components/schemas/HouseholdPosition'
 | 
			
		||||
                      holder:
 | 
			
		||||
                        type: boolean
 | 
			
		||||
                      comment:
 | 
			
		||||
                        type: string
 | 
			
		||||
                destination:
 | 
			
		||||
                  oneOf:
 | 
			
		||||
                    - $ref: '#/components/schemas/Household'
 | 
			
		||||
      responses:
 | 
			
		||||
        401:
 | 
			
		||||
          description: "Unauthorized"
 | 
			
		||||
        404:
 | 
			
		||||
          description: "Not found"
 | 
			
		||||
        200:
 | 
			
		||||
          description: "OK"
 | 
			
		||||
        422:
 | 
			
		||||
          description: "Unprocessable entity (validation errors)"
 | 
			
		||||
        400:
 | 
			
		||||
          description: "transition cannot be applyed"
 | 
			
		||||
                    
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
services:
 | 
			
		||||
    Chill\PersonBundle\DataFixtures\ORM\:
 | 
			
		||||
        autowire: true
 | 
			
		||||
        resource: ../../DataFixtures/ORM
 | 
			
		||||
        tags: [ 'doctrine.fixture.orm' ]
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
services:
 | 
			
		||||
    Chill\PersonBundle\Household\MembersEditorFactory:
 | 
			
		||||
        autowire: true
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\Migrations\Person;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * prefix table concerning household with 'chill_person' and add constraints
 | 
			
		||||
 */
 | 
			
		||||
final class Version20210528092625 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'prefix table concerning household with \'chill_person\' and add constraints';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        // we need to rename constraint, drop them first, recreate them after
 | 
			
		||||
        $this->addSql('ALTER TABLE householdmembers DROP CONSTRAINT fk_4d1fb288e79ff843');
 | 
			
		||||
        $this->addSql('ALTER TABLE householdmembers DROP CONSTRAINT fk_4d1fb288217bbb47');
 | 
			
		||||
 | 
			
		||||
        // rename tables
 | 
			
		||||
        $this->addSql('ALTER TABLE householdmembers RENAME TO chill_person_household_members');
 | 
			
		||||
        $this->addSql('ALTER TABLE household RENAME TO chill_person_household');
 | 
			
		||||
 | 
			
		||||
        // rename sequences
 | 
			
		||||
        $this->addSql('ALTER SEQUENCE household_id_seq RENAME TO chill_person_household_id_seq');
 | 
			
		||||
        $this->addSql('ALTER SEQUENCE householdmembers_id_seq RENAME TO chill_person_household_members_id_seq');
 | 
			
		||||
 | 
			
		||||
        // recreate constraints
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT FK_EEF5DED7217BBB47 FOREIGN KEY (person_id) REFERENCES chill_person_person (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT FK_EEF5DED7E79FF843 FOREIGN KEY (household_id) REFERENCES chill_person_household (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
 | 
			
		||||
        // create constraint 'householdmembers not overlaps'
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD CHECK (startdate < enddate)');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT '.
 | 
			
		||||
            "household_members_not_overlaps EXCLUDE USING GIST(
 | 
			
		||||
              -- extension btree_gist required to include comparaison with integer
 | 
			
		||||
              person_id WITH =,
 | 
			
		||||
              daterange(startdate, enddate) WITH &&
 | 
			
		||||
           ) WHERE (sharedhousehold IS TRUE)
 | 
			
		||||
           INITIALLY DEFERRED");
 | 
			
		||||
 | 
			
		||||
        // rename constraints
 | 
			
		||||
        $this->addSql('ALTER TABLE public.chill_person_household_to_addresses DROP CONSTRAINT fk_7109483e79ff843');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_to_addresses ADD CONSTRAINT FK_C28AF063E79FF843 FOREIGN KEY (household_id) REFERENCES chill_person_household (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
 | 
			
		||||
        // rename indexes
 | 
			
		||||
        $this->addSql('ALTER INDEX idx_7109483e79ff843 RENAME TO IDX_C28AF063E79FF843');
 | 
			
		||||
        $this->addSql('ALTER INDEX idx_7109483f5b7af75 RENAME TO IDX_C28AF063F5B7AF75');
 | 
			
		||||
        $this->addSql('ALTER INDEX idx_4d1fb288e79ff843 RENAME TO IDX_EEF5DED7E79FF843');
 | 
			
		||||
        $this->addSql('ALTER INDEX idx_4d1fb288217bbb47 RENAME TO IDX_EEF5DED7217BBB47');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {   
 | 
			
		||||
        $this->throwIrreversibleMigrationException("the down method is not implemented");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\Migrations\Person;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add position to househould_member
 | 
			
		||||
 */
 | 
			
		||||
final class Version20210528111624 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'Add position to househould_member';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('CREATE SEQUENCE chill_person_household_position_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
 | 
			
		||||
        $this->addSql('CREATE TABLE chill_person_household_position (id INT NOT NULL, label JSON NOT NULL, shareHouseHold BOOLEAN NOT NULL, allowHolder BOOLEAN NOT NULL, ordering DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))');
 | 
			
		||||
        
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD position_id INT DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members DROP "position"');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD CONSTRAINT FK_EEF5DED7DD842E46 FOREIGN KEY (position_id) REFERENCES chill_person_household_position (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
 | 
			
		||||
        $this->addSql('CREATE INDEX IDX_EEF5DED7DD842E46 ON chill_person_household_members (position_id)');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members DROP CONSTRAINT FK_EEF5DED7DD842E46');
 | 
			
		||||
        $this->addSql('DROP SEQUENCE chill_person_household_position_id_seq CASCADE');
 | 
			
		||||
        $this->addSql('DROP TABLE chill_person_household_position');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD "position" VARCHAR(255) DEFAULT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members DROP position_id');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,31 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\Migrations\Person;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Household members: allow startdate and enddate to be null
 | 
			
		||||
 */
 | 
			
		||||
final class Version20210528132405 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'Household members: allow startdate and enddate to be null';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ALTER startdate DROP NOT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ALTER enddate DROP NOT NULL');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ALTER startDate SET NOT NULL');
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ALTER endDate SET NOT NULL');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Chill\Migrations\Person;
 | 
			
		||||
 | 
			
		||||
use Doctrine\DBAL\Schema\Schema;
 | 
			
		||||
use Doctrine\Migrations\AbstractMigration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add house holder on membership
 | 
			
		||||
 */
 | 
			
		||||
final class Version20210528142121 extends AbstractMigration
 | 
			
		||||
{
 | 
			
		||||
    public function getDescription(): string
 | 
			
		||||
    {
 | 
			
		||||
        return 'Add house holder on membership';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function up(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members ADD holder BOOLEAN DEFAULT FALSE  NOT NULL');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function down(Schema $schema): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->addSql('ALTER TABLE chill_person_household_members DROP COLUMN holder');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user