mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +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();
|
||||
|
||||
// if new household, persist it
|
||||
if (FALSE === $em->contains($editor->getHousehold())) {
|
||||
if (
|
||||
$editor->hasHousehold()
|
||||
&&
|
||||
FALSE === $em->contains($editor->getHousehold())
|
||||
) {
|
||||
$em->persist($editor->getHousehold());
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Chill\PersonBundle\Household;
|
||||
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||
use Chill\PersonBundle\Entity\Household\Position;
|
||||
use Chill\PersonBundle\Entity\Household\Household;
|
||||
@ -13,12 +14,12 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
class MembersEditor
|
||||
{
|
||||
private ValidatorInterface $validator;
|
||||
private Household $household;
|
||||
private ?Household $household = null;
|
||||
|
||||
private array $persistables = [];
|
||||
private array $membershipsAffected = [];
|
||||
|
||||
public function __construct(ValidatorInterface $validator, Household $household)
|
||||
public function __construct(ValidatorInterface $validator, ?Household $household)
|
||||
{
|
||||
$this->validation = $validator;
|
||||
$this->household = $household;
|
||||
@ -62,6 +63,33 @@ class MembersEditor
|
||||
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
|
||||
{
|
||||
|
||||
@ -72,8 +100,13 @@ class MembersEditor
|
||||
return $this->persistables;
|
||||
}
|
||||
|
||||
public function getHousehold(): Household
|
||||
public function getHousehold(): ?Household
|
||||
{
|
||||
return $this->household;
|
||||
}
|
||||
|
||||
public function hasHousehold(): bool
|
||||
{
|
||||
return $this->household !== null;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class MembersEditorFactory
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function createEditor(Household $household): MembersEditor
|
||||
public function createEditor(?Household $household = null): MembersEditor
|
||||
{
|
||||
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 = [])
|
||||
{
|
||||
// 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,
|
||||
$format, $context);
|
||||
@ -34,11 +86,6 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar
|
||||
|
||||
$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) {
|
||||
$person = $this->denormalizer->denormalize($concerned['person'] ?? null, Person::class,
|
||||
$format, $context);
|
||||
@ -62,9 +109,9 @@ class MembersEditorNormalizer implements DenormalizerInterface, DenormalizerAwar
|
||||
|
||||
$editor->addMovement($startDate, $person, $position, $holder,
|
||||
$comment);
|
||||
|
||||
return $editor;
|
||||
}
|
||||
|
||||
return $editor;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@ -97,7 +207,13 @@ class HouseholdMemberControllerTest extends WebTestCase
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$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")
|
||||
->setMaxResults(100)
|
||||
->getScalarResult()
|
||||
|
@ -802,18 +802,61 @@ paths:
|
||||
type: object
|
||||
properties:
|
||||
person:
|
||||
$ref: '#/components/schemas/PersonById'
|
||||
$ref: '#/components/schemas/PersonById'
|
||||
start_date:
|
||||
$ref: '#/components/schemas/Date'
|
||||
$ref: '#/components/schemas/Date'
|
||||
position:
|
||||
$ref: '#/components/schemas/HouseholdPosition'
|
||||
$ref: '#/components/schemas/HouseholdPosition'
|
||||
holder:
|
||||
type: boolean
|
||||
comment:
|
||||
type: string
|
||||
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:
|
||||
401:
|
||||
description: "Unauthorized"
|
||||
|
Loading…
x
Reference in New Issue
Block a user