mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 21:34:25 +00:00
backend: allow to remove people from household, or move to a new household
This commit is contained in:
parent
6fed008ff2
commit
89734c680c
@ -55,7 +55,11 @@ class HouseholdMemberController extends ApiController
|
|||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
// if new household, persist it
|
// if new household, persist it
|
||||||
if (FALSE === $em->contains($editor->getHousehold())) {
|
if (
|
||||||
|
$editor->hasHousehold()
|
||||||
|
&&
|
||||||
|
FALSE === $em->contains($editor->getHousehold())
|
||||||
|
) {
|
||||||
$em->persist($editor->getHousehold());
|
$em->persist($editor->getHousehold());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace Chill\PersonBundle\Household;
|
namespace Chill\PersonBundle\Household;
|
||||||
|
|
||||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||||
|
use Doctrine\Common\Collections\Criteria;
|
||||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||||
use Chill\PersonBundle\Entity\Household\Position;
|
use Chill\PersonBundle\Entity\Household\Position;
|
||||||
use Chill\PersonBundle\Entity\Household\Household;
|
use Chill\PersonBundle\Entity\Household\Household;
|
||||||
@ -13,12 +14,12 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|||||||
class MembersEditor
|
class MembersEditor
|
||||||
{
|
{
|
||||||
private ValidatorInterface $validator;
|
private ValidatorInterface $validator;
|
||||||
private Household $household;
|
private ?Household $household = null;
|
||||||
|
|
||||||
private array $persistables = [];
|
private array $persistables = [];
|
||||||
private array $membershipsAffected = [];
|
private array $membershipsAffected = [];
|
||||||
|
|
||||||
public function __construct(ValidatorInterface $validator, Household $household)
|
public function __construct(ValidatorInterface $validator, ?Household $household)
|
||||||
{
|
{
|
||||||
$this->validation = $validator;
|
$this->validation = $validator;
|
||||||
$this->household = $household;
|
$this->household = $household;
|
||||||
@ -62,6 +63,33 @@ class MembersEditor
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function leaveMovement(
|
||||||
|
\DateTimeImmutable $date,
|
||||||
|
Person $person
|
||||||
|
): self {
|
||||||
|
$criteria = new Criteria();
|
||||||
|
$expr = Criteria::expr();
|
||||||
|
|
||||||
|
$criteria->where(
|
||||||
|
$expr->andX(
|
||||||
|
$expr->lt('startDate', $date),
|
||||||
|
$expr->isNull('endDate', $date)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$participations = $person->getHouseholdParticipations()
|
||||||
|
->matching($criteria)
|
||||||
|
;
|
||||||
|
|
||||||
|
foreach ($participations as $participation) {
|
||||||
|
$participation->setEndDate($date);
|
||||||
|
$this->membershipsAffected[] = $participation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function validate(): ConstraintViolationListInterface
|
public function validate(): ConstraintViolationListInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -72,8 +100,13 @@ class MembersEditor
|
|||||||
return $this->persistables;
|
return $this->persistables;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHousehold(): Household
|
public function getHousehold(): ?Household
|
||||||
{
|
{
|
||||||
return $this->household;
|
return $this->household;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasHousehold(): bool
|
||||||
|
{
|
||||||
|
return $this->household !== null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class MembersEditorFactory
|
|||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createEditor(Household $household): MembersEditor
|
public function createEditor(?Household $household = null): MembersEditor
|
||||||
{
|
{
|
||||||
return new MembersEditor($this->validator, $household);
|
return new MembersEditor($this->validator, $household);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,58 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
|
{
|
||||||
|
// some test about schema first...
|
||||||
|
$this->performChecks($data);
|
||||||
|
|
||||||
|
// route to "leave movement" (all concerned leave household)
|
||||||
|
// or "move to another household" (all concerned go to another
|
||||||
|
// household)
|
||||||
|
if (NULL === $data['destination']) {
|
||||||
|
return $this->denormalizeLeave($data, $type, $format, $context);
|
||||||
|
} else {
|
||||||
|
return $this->denormalizeMove($data, $type, $format, $context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function performChecks($data): void
|
||||||
|
{
|
||||||
|
if (NULL == $data['concerned'] ?? NULL
|
||||||
|
&& FALSE === ·\is_array('concerned')) {
|
||||||
|
throw new Exception\UnexpectedValueException("The schema does not have any key 'concerned'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FALSE === \array_key_exists('destination', $data)) {
|
||||||
|
throw new Exception\UnexpectedValueException("The schema does not have any key 'destination'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function denormalizeLeave($data, string $type, string $format, array $context = [])
|
||||||
|
{
|
||||||
|
$editor = $this->factory->createEditor(null);
|
||||||
|
|
||||||
|
foreach ($data['concerned'] as $key => $concerned) {
|
||||||
|
$person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class,
|
||||||
|
$format, $context);
|
||||||
|
$startDate = $this->denormalizer->denormalize($concerned['start_date'] ?? null, \DateTimeImmutable::class,
|
||||||
|
$format, $context);
|
||||||
|
|
||||||
|
if (
|
||||||
|
NULL === $person
|
||||||
|
&& NULL === $startDate
|
||||||
|
) {
|
||||||
|
throw new Exception\InvalidArgumentException("position with ".
|
||||||
|
"key $key could not be denormalized: missing ".
|
||||||
|
"person or start_date.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$editor->leaveMovement($startDate, $person);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function denormalizeMove($data, string $type, string $format, array $context = [])
|
||||||
{
|
{
|
||||||
$household = $this->denormalizer->denormalize($data['destination'], Household::class,
|
$household = $this->denormalizer->denormalize($data['destination'], Household::class,
|
||||||
$format, $context);
|
$format, $context);
|
||||||
@ -34,11 +86,6 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar
|
|||||||
|
|
||||||
$editor = $this->factory->createEditor($household);
|
$editor = $this->factory->createEditor($household);
|
||||||
|
|
||||||
if (NULL == $data['concerned'] ?? NULL
|
|
||||||
&& FALSE === ·\is_array('concerned')) {
|
|
||||||
throw new Exception\UnexpectedValueException("The schema does not have any key 'concerned'");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($data['concerned'] as $key => $concerned) {
|
foreach ($data['concerned'] as $key => $concerned) {
|
||||||
$person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class,
|
$person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class,
|
||||||
$format, $context);
|
$format, $context);
|
||||||
@ -62,9 +109,9 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar
|
|||||||
|
|
||||||
$editor->addMovement($startDate, $person, $position, $holder,
|
$editor->addMovement($startDate, $person, $position, $holder,
|
||||||
$comment);
|
$comment);
|
||||||
|
|
||||||
return $editor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supportsDenormalization($data, string $type, string $format = null)
|
public function supportsDenormalization($data, string $type, string $format = null)
|
||||||
|
@ -67,6 +67,116 @@ class HouseholdMemberControllerTest extends WebTestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideValidDataMove
|
||||||
|
*/
|
||||||
|
public function testMoveMemberToNewHousehold($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',
|
||||||
|
]
|
||||||
|
],
|
||||||
|
true)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(Response::HTTP_OK,
|
||||||
|
$client->getResponse()->getStatusCode()
|
||||||
|
);
|
||||||
|
|
||||||
|
$data = \json_decode($client->getResponse()->getContent(), true);
|
||||||
|
|
||||||
|
$this->assertIsArray($data);
|
||||||
|
$this->assertArrayHasKey('members', $data);
|
||||||
|
$this->assertIsArray($data['members']);
|
||||||
|
$this->assertEquals(1, count($data['members']),
|
||||||
|
"assert new household count one member");
|
||||||
|
$this->assertArrayHasKey('person', $data['members'][0]);
|
||||||
|
$this->assertArrayHasKey('id', $data['members'][0]['person']);
|
||||||
|
$this->assertEquals($personId, $data['members'][0]['person']['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideValidDataMove
|
||||||
|
*/
|
||||||
|
public function testLeaveWithoutHousehold($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' => null
|
||||||
|
],
|
||||||
|
true)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(Response::HTTP_OK,
|
||||||
|
$client->getResponse()->getStatusCode()
|
||||||
|
);
|
||||||
|
|
||||||
|
$data = \json_decode($client->getResponse()->getContent(), true);
|
||||||
|
|
||||||
|
$this->assertEquals(null, $data);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideValidDataEditMember
|
* @dataProvider provideValidDataEditMember
|
||||||
*/
|
*/
|
||||||
@ -97,7 +207,13 @@ class HouseholdMemberControllerTest extends WebTestCase
|
|||||||
$em = self::$container->get(EntityManagerInterface::class);
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
$personIds = $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
$personIds = $em->createQuery("SELECT p.id FROM ".Person::class." p ".
|
||||||
"JOIN p.center c WHERE c.name = :center")
|
"JOIN p.center c ".
|
||||||
|
"JOIN p.householdParticipations hp ".
|
||||||
|
"WHERE ".
|
||||||
|
"c.name = :center ".
|
||||||
|
"AND hp.startDate < CURRENT_DATE() ".
|
||||||
|
"AND hp.endDate IS NULL "
|
||||||
|
)
|
||||||
->setParameter('center', "Center A")
|
->setParameter('center', "Center A")
|
||||||
->setMaxResults(100)
|
->setMaxResults(100)
|
||||||
->getScalarResult()
|
->getScalarResult()
|
||||||
|
@ -802,18 +802,61 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
person:
|
person:
|
||||||
$ref: '#/components/schemas/PersonById'
|
$ref: '#/components/schemas/PersonById'
|
||||||
start_date:
|
start_date:
|
||||||
$ref: '#/components/schemas/Date'
|
$ref: '#/components/schemas/Date'
|
||||||
position:
|
position:
|
||||||
$ref: '#/components/schemas/HouseholdPosition'
|
$ref: '#/components/schemas/HouseholdPosition'
|
||||||
holder:
|
holder:
|
||||||
type: boolean
|
type: boolean
|
||||||
comment:
|
comment:
|
||||||
type: string
|
type: string
|
||||||
destination:
|
destination:
|
||||||
oneOf:
|
$ref: '#/components/schemas/Household'
|
||||||
- $ref: '#/components/schemas/Household'
|
examples:
|
||||||
|
Moving person to a new household:
|
||||||
|
value:
|
||||||
|
concerned:
|
||||||
|
-
|
||||||
|
person:
|
||||||
|
id: 0
|
||||||
|
type: person
|
||||||
|
position:
|
||||||
|
type: position
|
||||||
|
id: 1
|
||||||
|
start_date:
|
||||||
|
datetime: 2021-06-01T00:00:00+02:00
|
||||||
|
comment: "This is my comment for moving"
|
||||||
|
holder: false
|
||||||
|
destination:
|
||||||
|
type: household
|
||||||
|
Moving person to an existing household:
|
||||||
|
value:
|
||||||
|
concerned:
|
||||||
|
-
|
||||||
|
person:
|
||||||
|
id: 0
|
||||||
|
type: person
|
||||||
|
position:
|
||||||
|
type: position
|
||||||
|
id: 1
|
||||||
|
start_date:
|
||||||
|
datetime: 2021-06-01T00:00:00+02:00
|
||||||
|
comment: "This is my comment for moving"
|
||||||
|
holder: false
|
||||||
|
destination:
|
||||||
|
type: household
|
||||||
|
id: 54
|
||||||
|
Removing a person from any household:
|
||||||
|
value:
|
||||||
|
concerned:
|
||||||
|
-
|
||||||
|
person:
|
||||||
|
id: 0
|
||||||
|
type: person
|
||||||
|
start_date:
|
||||||
|
datetime: 2021-06-01T00:00:00+02:00
|
||||||
|
destination: null
|
||||||
responses:
|
responses:
|
||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user