diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56b958bb6..d80038b97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,9 +11,15 @@ and this project adheres to
## Unreleased
+* [parcours] Display of interlocuteurs changed to flex-table in parcours edit page to prevent cut-off of information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/535)
+
+## Test releases
+
+### continuous release in February and March
+
+* Creation of PickCivilityType, and implementation in PersonType and ThirdpartyType
* [person] Accompanying course evaluation documents: disable the WOPI edit link if mimetype not supported and if no keyInfos
(https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/585)
-
* [activity] display error messages above the form in creating a new location (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/481)
* [activity] show required field in activity edit/new by an asterix in the vuejs fields (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/494)
* [ACL] fix allow to see the course, event if the scope'course does not contains the scope's user
@@ -77,8 +83,7 @@ and this project adheres to
* [parcours] Create document buttons made sticky (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/532)
* [person] Trailing guillemet removed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/530)
* [notification] Display of social action within workflow notification set to display block (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/537)
-
-## Test releases
+* [onthefly] trim trailing whitespace in email of person and thirdparty (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/542)
### test release 2022-02-21
@@ -106,8 +111,6 @@ and this project adheres to
* [bug]: fix confidential toggle of address in thirdpartyrenderbox (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/460)
-## Test releases
-* Creation of PickCivilityType, and implementation in PersonType and ThirdpartyType
### test release 2022-02-14
diff --git a/phpstan-types.neon b/phpstan-types.neon
index 9671c05a5..d43fd8944 100644
--- a/phpstan-types.neon
+++ b/phpstan-types.neon
@@ -460,8 +460,3 @@ parameters:
count: 1
path: src/Bundle/ChillThirdPartyBundle/Search/ThirdPartySearch.php
- -
- message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
- count: 1
- path: src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php
-
diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php
index 08a0fec77..8e46feb7b 100644
--- a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php
+++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudget.php
@@ -23,7 +23,7 @@ use function count;
/**
* Helps to find a summary of the budget: the sum of resources and charges.
*/
-class SummaryBudget
+class SummaryBudget implements SummaryBudgetInterface
{
private const QUERY_CHARGE_BY_HOUSEHOLD = 'select SUM(amount) AS sum, type FROM chill_budget.charge WHERE (person_id IN (_ids_) OR household_id = ?) AND NOW() BETWEEN startdate AND COALESCE(enddate, \'infinity\'::timestamp) GROUP BY type';
@@ -52,26 +52,6 @@ class SummaryBudget
$this->translatableStringHelper = $translatableStringHelper;
}
- public function getEmptyChargeArray(): array
- {
- $keys = $this->configRepository->getChargesKeys();
- $labels = $this->chargeLabels;
-
- return array_combine($keys, array_map(function ($i) use ($labels) {
- return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
- }, $keys));
- }
-
- public function getEmptyResourceArray(): array
- {
- $keys = $this->configRepository->getResourcesKeys();
- $labels = $this->resourcesLabels;
-
- return array_combine($keys, array_map(function ($i) use ($labels) {
- return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
- }, $keys));
- }
-
public function getSummaryForHousehold(?Household $household): array
{
if (null === $household) {
@@ -101,8 +81,15 @@ class SummaryBudget
];
}
- public function getSummaryForPerson(Person $person): array
+ public function getSummaryForPerson(?Person $person): array
{
+ if (null === $person) {
+ return [
+ 'resources' => $this->getEmptyResourceArray(),
+ 'charges' => $this->getEmptyChargeArray(),
+ ];
+ }
+
$rsm = $this->buildRsm();
$resources = $this->em->createNativeQuery(self::QUERY_RESOURCE_BY_PERSON, $rsm)
@@ -128,6 +115,26 @@ class SummaryBudget
return $rsm;
}
+ private function getEmptyChargeArray(): array
+ {
+ $keys = $this->configRepository->getChargesKeys();
+ $labels = $this->chargeLabels;
+
+ return array_combine($keys, array_map(function ($i) use ($labels) {
+ return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
+ }, $keys));
+ }
+
+ private function getEmptyResourceArray(): array
+ {
+ $keys = $this->configRepository->getResourcesKeys();
+ $labels = $this->resourcesLabels;
+
+ return array_combine($keys, array_map(function ($i) use ($labels) {
+ return ['sum' => 0.0, 'label' => $this->translatableStringHelper->localize($labels[$i])];
+ }, $keys));
+ }
+
private function rowToArray(array $rows, string $kind): array
{
switch ($kind) {
diff --git a/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php
new file mode 100644
index 000000000..528c4626e
--- /dev/null
+++ b/src/Bundle/ChillBudgetBundle/Service/Summary/SummaryBudgetInterface.php
@@ -0,0 +1,25 @@
+getMethod()) {
case Request::METHOD_GET:
diff --git a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php
index 32c0a3b43..56470c78b 100644
--- a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php
+++ b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php
@@ -45,7 +45,7 @@ class SearchUserApiProvider implements SearchApiInterface
$query
->setSelectKey('user')
->setSelectJsonbMetadata("jsonb_build_object('id', u.id)")
- ->setSelectPertinence('GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.label),
+ ->setSelectPertinence('3 + GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.label),
SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical))', [$pattern, $pattern])
->setFromClause('users AS u')
->setWhereClauses('
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php
index 70958d5a9..81e953267 100644
--- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/DateNormalizer.php
@@ -44,13 +44,21 @@ class DateNormalizer implements ContextAwareNormalizerInterface, DenormalizerInt
switch ($type) {
case DateTime::class:
- return DateTime::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
+ $result = DateTime::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
+ break;
case DateTimeInterface::class:
case DateTimeImmutable::class:
- return DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
+ $result = DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
+ break;
}
+ if (false === $result) {
+ return null;
+ }
+
+ return $result;
+
throw new UnexpectedValueException();
}
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/PhonenumberNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/PhonenumberNormalizer.php
index 7eb323754..f76b1e5c8 100644
--- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/PhonenumberNormalizer.php
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/PhonenumberNormalizer.php
@@ -32,7 +32,7 @@ class PhonenumberNormalizer implements ContextAwareNormalizerInterface, Denormal
}
/**
- * @param mixed $data
+ * @param string|null $data
* @param mixed $type
* @param null|mixed $format
*
@@ -40,7 +40,7 @@ class PhonenumberNormalizer implements ContextAwareNormalizerInterface, Denormal
*/
public function denormalize($data, $type, $format = null, array $context = [])
{
- if ('' === trim($data)) {
+ if ('' === trim((string) $data)) {
return null;
}
diff --git a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php
index 2620ed19a..fed9f0af0 100644
--- a/src/Bundle/ChillPersonBundle/Entity/Household/Household.php
+++ b/src/Bundle/ChillPersonBundle/Entity/Household/Household.php
@@ -514,6 +514,8 @@ class Household
if ($iterator->valid()) {
$current->setValidTo($iterator->current()->getValidFrom());
+ } else {
+ $current->setValidTo(null);
}
}
}
diff --git a/src/Bundle/ChillPersonBundle/Entity/Person.php b/src/Bundle/ChillPersonBundle/Entity/Person.php
index 880c2bd11..ef522f068 100644
--- a/src/Bundle/ChillPersonBundle/Entity/Person.php
+++ b/src/Bundle/ChillPersonBundle/Entity/Person.php
@@ -276,25 +276,21 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* The person's first name.
*
- * @var string
- *
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="The firstname cannot be empty")
* @Assert\Length(
* max=255,
* )
*/
- private $firstName;
+ private string $firstName = '';
/**
* fullname canonical. Read-only field, which is calculated by
* the database.
*
- * @var string
- *
* @ORM\Column(type="text", nullable=true)
*/
- private $fullnameCanonical;
+ private string $fullnameCanonical = '';
/**
* The person's gender.
@@ -328,6 +324,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* targetEntity=HouseholdMember::class,
* mappedBy="person"
* )
+ *
+ * @var Collection|HouseholdMember[]
*/
private Collection $householdParticipations;
@@ -343,15 +341,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* The person's last name.
*
- * @var string
- *
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank(message="The lastname cannot be empty")
* @Assert\Length(
* max=255,
* )
*/
- private $lastName;
+ private string $lastName = '';
/**
* The marital status of the person.
@@ -1117,6 +1113,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this->householdAddresses;
}
+ /**
+ * @return Collection|HouseholdMember[]
+ */
public function getHouseholdParticipations(): Collection
{
return $this->householdParticipations;
@@ -1126,6 +1125,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* Get participation where the person does not share the household.
*
* Order by startDate, desc
+ *
+ * @return HouseholdMember[]
*/
public function getHouseholdParticipationsNotShareHousehold(): Collection
{
@@ -1146,6 +1147,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* Get participation where the person does share the household.
*
* Order by startDate, desc
+ *
+ * @return Collection|HouseholdMember[]
*/
public function getHouseholdParticipationsShareHousehold(): Collection
{
@@ -1565,18 +1568,14 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
public function setEmail(?string $email): self
{
- if (null === $email) {
- $email = '';
- }
-
- $this->email = $email;
+ $this->email = trim((string) $email);
return $this;
}
- public function setFirstName(string $firstName): self
+ public function setFirstName(?string $firstName): self
{
- $this->firstName = $firstName;
+ $this->firstName = (string) $firstName;
return $this;
}
@@ -1602,9 +1601,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
return $this;
}
- public function setLastName(string $lastName): self
+ public function setLastName(?string $lastName): self
{
- $this->lastName = $lastName;
+ $this->lastName = (string) $lastName;
return $this;
}
diff --git a/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php b/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php
index aeab09fea..31af0a649 100644
--- a/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php
+++ b/src/Bundle/ChillPersonBundle/Form/PersonResourceType.php
@@ -29,8 +29,12 @@ use Symfony\Contracts\Translation\TranslatorInterface;
final class PersonResourceType extends AbstractType
{
+ private PersonRenderInterface $personRender;
+
private ResourceKindRender $resourceKindRender;
+ private ThirdPartyRender $thirdPartyRender;
+
private TranslatorInterface $translator;
public function __construct(ResourceKindRender $resourceKindRender, PersonRenderInterface $personRender, ThirdPartyRender $thirdPartyRender, TranslatorInterface $translator)
diff --git a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php
index e327efbab..1c7cbb538 100644
--- a/src/Bundle/ChillPersonBundle/Household/MembersEditor.php
+++ b/src/Bundle/ChillPersonBundle/Household/MembersEditor.php
@@ -61,8 +61,6 @@ class MembersEditor
throw new LogicException('You must define a household first');
}
- $event = new PersonAddressMoveEvent($person);
-
$membership = (new HouseholdMember())
->setStartDate($date)
->setPerson($person)
@@ -70,9 +68,15 @@ class MembersEditor
->setHolder($holder)
->setComment($comment);
$this->household->addMember($membership);
- $event->setNextMembership($membership);
if ($position->getShareHousehold()) {
+ // launch event only if moving to a "share household" position,
+ // and if the destination household is different than the previous one
+ $event = new PersonAddressMoveEvent($person);
+ $event->setNextMembership($membership);
+
+ $counter = 0;
+
foreach ($person->getHouseholdParticipationsShareHousehold() as $participation) {
if ($participation === $membership) {
continue;
@@ -82,14 +86,25 @@ class MembersEditor
continue;
}
+ ++$counter;
+
if ($participation->getEndDate() === null || $participation->getEndDate() > $date) {
- $event->setPreviousMembership($participation);
$participation->setEndDate($date);
$this->membershipsAffected[] = $participation;
$this->oldMembershipsHashes[] = spl_object_hash($participation);
+
+ if ($participation->getHousehold() !== $this->household) {
+ $event->setPreviousMembership($participation);
+ $this->events[] = $event;
+ }
}
}
+ // send also the event if there was no participation before
+ if (0 === $counter) {
+ $this->events[] = $event;
+ }
+
foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
if ($participation->getHousehold() === $this->household
&& $participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate()
@@ -98,11 +113,30 @@ class MembersEditor
$participation->setEndDate($membership->getStartDate());
}
}
+ } else {
+ // if a members is moved to the same household than the one he belongs to,
+ // we should make it leave the household
+ if ($person->getCurrentHousehold($date) === $this->household) {
+ $this->leaveMovement($date, $person);
+ }
+
+ // if there are multiple belongings not sharing household, close the others
+ foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
+ if ($participation === $membership) {
+ continue;
+ }
+
+ if ($participation->getHousehold() === $this->household
+ && ($participation->getEndDate() === null || $participation->getEndDate() > $membership->getStartDate())
+ && $participation->getStartDate() <= $membership->getStartDate()
+ ) {
+ $participation->setEndDate($membership->getStartDate());
+ }
+ }
}
$this->membershipsAffected[] = $membership;
$this->persistables[] = $membership;
- $this->events[] = $event;
return $this;
}
diff --git a/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php b/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php
index 80da956c4..103fd2b88 100644
--- a/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php
+++ b/src/Bundle/ChillPersonBundle/Menu/PersonMenuBuilder.php
@@ -88,7 +88,7 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface
->setExtras([
'order' => 99999,
]);
-
+ /*
$menu->addChild($this->translator->trans('Person duplicate'), [
'route' => 'chill_person_duplicate_view',
'routeParameters' => [
@@ -98,7 +98,7 @@ class PersonMenuBuilder implements LocalMenuBuilderInterface
->setExtras([
'order' => 99999,
]);
-
+ */
if (
'visible' === $this->showAccompanyingPeriod
&& $this->security->isGranted(AccompanyingPeriodVoter::SEE, $parameters['person'])
diff --git a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php
index 78745af1d..5ed9762c8 100644
--- a/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php
+++ b/src/Bundle/ChillPersonBundle/Repository/PersonACLAwareRepository.php
@@ -133,8 +133,8 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
$pertinence = [];
$pertinenceArgs = [];
- $orWhereSearchClause = [];
- $orWhereSearchClauseArgs = [];
+ $andWhereSearchClause = [];
+ $andWhereSearchClauseArgs = [];
if ('' !== $default) {
foreach (explode(' ', $default) as $str) {
@@ -145,15 +145,15 @@ final class PersonACLAwareRepository implements PersonACLAwareRepositoryInterfac
'(starts_with(LOWER(UNACCENT(lastname)), UNACCENT(LOWER(?))))::int';
array_push($pertinenceArgs, $str, $str, $str, $str);
- $orWhereSearchClause[] =
+ $andWhereSearchClause[] =
'(LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ' .
"person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' )";
- array_push($orWhereSearchClauseArgs, $str, $str);
+ array_push($andWhereSearchClauseArgs, $str, $str);
}
$query->andWhereClause(
- implode(' OR ', $orWhereSearchClause),
- $orWhereSearchClauseArgs
+ implode(' AND ', $andWhereSearchClause),
+ $andWhereSearchClauseArgs
);
} else {
$pertinence = ['1'];
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Resources.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Resources.vue
index e9b9695ab..7287437a3 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Resources.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Resources.vue
@@ -10,7 +10,7 @@
-
+
personRender = $personRender;
$this->relationshipRepository = $relationshipRepository;
@@ -214,6 +214,14 @@ class PersonDocGenNormalizer implements
$data['relations'] = [];
}
+ if ($context['docgen:person:with-budget'] ?? false) {
+ $data['budget']['person'] = $this->summaryBudget->getSummaryForPerson(null);
+
+ if ($context['docgen:person:with-household'] ?? false) {
+ $data['budget']['household'] = $this->summaryBudget->getSummaryForHousehold(null);
+ }
+ }
+
return $data;
}
}
diff --git a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php
index ae95c9321..41c06e9ec 100644
--- a/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php
+++ b/src/Bundle/ChillPersonBundle/Serializer/Normalizer/PersonJsonNormalizer.php
@@ -208,8 +208,8 @@ class PersonJsonNormalizer implements DenormalizerAwareInterface, NormalizerAwar
'birthdate' => $this->normalizer->normalize($person->getBirthdate(), $format, $context),
'deathdate' => $this->normalizer->normalize($person->getDeathdate(), $format, $context),
'age' => $this->normalizer->normalize($person->getAge(), $format, $context),
- 'phonenumber' => $this->normalizer->normalize($person->getPhonenumber()),
- 'mobilenumber' => $this->normalizer->normalize($person->getMobilenumber()),
+ 'phonenumber' => $this->normalizer->normalize($person->getPhonenumber(), $format, $context),
+ 'mobilenumber' => $this->normalizer->normalize($person->getMobilenumber(), $format, $context),
'email' => $person->getEmail(),
'gender' => $person->getGender(),
];
diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php
index 08034978e..94a0ac243 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Controller/HouseholdApiControllerTest.php
@@ -65,7 +65,7 @@ final class HouseholdApiControllerTest extends WebTestCase
}
$reference = $em->createQueryBuilder()->select('ar')->from(AddressReference::class, 'ar')
- ->setFirstResult(random_int(0, $nbReference))
+ ->setFirstResult(random_int(0, $nbReference - 1))
->setMaxResults(1)
->getQuery()->getSingleResult();
diff --git a/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php
index 6799f882b..7cf8af3e5 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Entity/Household/HouseholdTest.php
@@ -75,6 +75,7 @@ final class HouseholdTest extends TestCase
$lastAddress = new Address();
$lastAddress->setValidFrom($yesterday = new DateTime('yesterday'));
+ $lastAddress->setValidTo(new DateTime('tomorrow'));
$household->addAddress($lastAddress);
$this->assertNull($lastAddress->getValidTo());
@@ -82,6 +83,7 @@ final class HouseholdTest extends TestCase
$previousAddress = new Address();
$previousAddress->setValidFrom($oneMonthAgo = new DateTime('1 month ago'));
+ $previousAddress->setValidTo(new DateTime('now'));
$household->addAddress($previousAddress);
$addresses = $household->getAddressesOrdered();
@@ -95,6 +97,7 @@ final class HouseholdTest extends TestCase
$futureAddress = new Address();
$futureAddress->setValidFrom($tomorrow = new DateTime('tomorrow'));
+ $futureAddress->setValidTo(new DateTime('2150-01-01'));
$household->addAddress($futureAddress);
$addresses = $household->getAddressesOrdered();
diff --git a/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php
index 65199dabf..77eeed387 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Household/MembersEditorTest.php
@@ -12,6 +12,7 @@ declare(strict_types=1);
namespace Chill\PersonBundle\Tests\Household;
use Chill\PersonBundle\Entity\Household\Household;
+use Chill\PersonBundle\Entity\Household\HouseholdMember;
use Chill\PersonBundle\Entity\Household\Position;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Event\Person\PersonAddressMoveEvent;
@@ -39,6 +40,122 @@ final class MembersEditorTest extends TestCase
$this->factory = $this->buildMembersEditorFactory();
}
+ public function testAddingParticipationNotSharingHouseholdCloseTheOldOnes()
+ {
+ $person = new Person();
+ $position = (new Position())->setShareHousehold(false);
+ $household = new Household();
+
+ // set a first time the person in position
+ $factory = $this->buildMembersEditorFactory();
+ $editor = $factory->createEditor($household);
+
+ $editor->addMovement($aMonthAgo = new DateTimeImmutable('1 month ago'), $person, $position);
+
+ // set a second time the person in position
+ $factory = $this->buildMembersEditorFactory();
+ $editor = $factory->createEditor($household);
+
+ $editor->addMovement($yesterday = new DateTimeImmutable('yesterday'), $person, $position);
+
+ $this->assertCount(2, $person->getHouseholdParticipationsNotShareHousehold());
+
+ $startDates = [];
+ $endDates = [];
+
+ foreach ($person->getHouseholdParticipationsNotShareHousehold() as $participation) {
+ $startDates[] = $participation->getStartDate();
+ $endDates[] = $participation->getEndDate();
+ }
+
+ $this->assertContains($aMonthAgo, $startDates);
+ $this->assertContains($yesterday, $startDates);
+ $this->assertContains($yesterday, $endDates);
+ $this->assertContains(null, $endDates);
+ }
+
+ /**
+ * We test here a move for a person:.
+ *
+ * * which was in a position "sharing household"
+ * * which move to the another household, in a position "not sharing household"
+ *
+ * The person should stays in the two households
+ */
+ public function testMoveFromSharingHouseholdToNotSharingHousehouldInDifferentHousehold()
+ {
+ $person = new Person();
+ $household = new Household();
+ $positionSharing = (new Position())->setShareHousehold(true);
+ $positionNotSharing = (new Position())->setShareHousehold(false);
+ $factory = $this->buildMembersEditorFactory();
+ $editor = $factory->createEditor($household);
+
+ // we add the member to the household
+ $editor->addMovement(new DateTimeImmutable('1 month ago'), $person, $positionSharing);
+
+ // double check that the person is in the household
+ $this->assertContains($person, $household->getCurrentPersons());
+
+ // we do the move to the position not sharing household
+ $editor = $factory->createEditor($household2 = new Household());
+ $editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
+
+ $sharings = $household->getCurrentMembers()->filter(static function (HouseholdMember $m) {
+ return $m->getShareHousehold();
+ });
+ $notSharing = $household2->getCurrentMembers()->filter(static function (HouseholdMember $m) {
+ return !$m->getShareHousehold();
+ });
+
+ $this->assertCount(1, $notSharing);
+ $this->assertCount(1, $sharings);
+
+ $getPerson = static function (HouseholdMember $m) { return $m->getPerson(); };
+
+ $this->assertContains($person, $notSharing->map($getPerson));
+ }
+
+ /**
+ * We test here a move for a person:.
+ *
+ * * which was in a position "sharing household"
+ * * which move to the same household, in a position "not sharing household"
+ */
+ public function testMoveFromSharingHouseholdToNotSharingHousehouldInSamehousehold()
+ {
+ $person = new Person();
+ $household = new Household();
+ $positionSharing = (new Position())->setShareHousehold(true);
+ $positionNotSharing = (new Position())->setShareHousehold(false);
+ $factory = $this->buildMembersEditorFactory();
+ $editor = $factory->createEditor($household);
+
+ // we add the member to the household
+ $editor->addMovement(new DateTimeImmutable('1 month ago'), $person, $positionSharing);
+
+ // double check that the person is in the household
+ $this->assertContains($person, $household->getCurrentPersons());
+
+ // we do the move to the position not sharing household
+ $editor = $factory->createEditor($household);
+ $editor->addMovement(new DateTimeImmutable('yesterday'), $person, $positionNotSharing);
+
+ $sharings = $household->getCurrentMembers()->filter(static function (HouseholdMember $m) {
+ return $m->getShareHousehold();
+ });
+ $notSharing = $household->getCurrentMembers()->filter(static function (HouseholdMember $m) {
+ return !$m->getShareHousehold();
+ });
+
+ $this->assertCount(1, $notSharing);
+ $this->assertCount(0, $sharings);
+
+ $getPerson = static function (HouseholdMember $m) { return $m->getPerson(); };
+
+ $this->assertContains($person, $notSharing->map($getPerson));
+ }
+
public function testMovePersonWithoutSharedHousehold()
{
$person = new Person();
@@ -126,7 +243,7 @@ final class MembersEditorTest extends TestCase
$this->assertEquals($date, $membership1->getEndDate());
}
- public function testPostMove()
+ public function testPostMoveToAPositionNotSharingHousehold()
{
$person = new Person();
$position = (new Position())
@@ -134,6 +251,86 @@ final class MembersEditorTest extends TestCase
$household1 = new Household();
$household2 = new Household();
$eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher
+ ->dispatch(Argument::type(PersonAddressMoveEvent::class))
+ ->shouldNotBeCalled();
+ $factory = $this->buildMembersEditorFactory(
+ $eventDispatcher->reveal(),
+ null
+ );
+ $editor = $factory->createEditor($household1);
+
+ $editor->addMovement(new DateTimeImmutable('now'), $person, $position);
+
+ $editor->postMove();
+ }
+
+ public function testPostMoveToAPositionSharingHouseholdAndSameHousehold()
+ {
+ $person = new Person();
+ $position = (new Position())
+ ->setShareHousehold(true);
+ $position2 = (new Position())
+ ->setShareHousehold(true);
+ $household1 = new Household();
+
+ // set into the first household
+ $editor = $this->buildMembersEditorFactory()
+ ->createEditor($household1);
+ $editor->addMovement(new DateTimeImmutable('1 year ago'), $person, $position);
+
+ // prepare for next move
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher
+ ->dispatch(Argument::type(PersonAddressMoveEvent::class))
+ ->shouldNotBeCalled();
+ $factory = $this->buildMembersEditorFactory(
+ $eventDispatcher->reveal(),
+ null
+ );
+ $editor = $factory->createEditor($household1);
+
+ $editor->addMovement(new DateTimeImmutable('now'), $person, $position2);
+
+ $editor->postMove();
+ }
+
+ public function testPostMoveToAPositionSharingHouseholdFromDifferentHousehold()
+ {
+ $person = new Person();
+ $position = (new Position())
+ ->setShareHousehold(true);
+ $household1 = new Household();
+ $household2 = new Household();
+
+ // set into the first household
+ $editor = $this->buildMembersEditorFactory()
+ ->createEditor($household1);
+ $editor->addMovement(new DateTimeImmutable('1 year ago'), $person, $position);
+
+ // perform now the movement
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
+ $eventDispatcher
+ ->dispatch(Argument::type(PersonAddressMoveEvent::class))
+ ->shouldBeCalled();
+ $factory = $this->buildMembersEditorFactory(
+ $eventDispatcher->reveal(),
+ null
+ );
+ $editor = $factory->createEditor($household2);
+
+ $editor->addMovement(new DateTimeImmutable('now'), $person, $position);
+
+ $editor->postMove();
+ }
+
+ public function testPostMoveToAPositionSharingHouseholdFromNoHousehold()
+ {
+ $person = new Person();
+ $position = (new Position())
+ ->setShareHousehold(true);
+ $household1 = new Household();
+ $eventDispatcher = $this->prophesize(EventDispatcherInterface::class);
$eventDispatcher
->dispatch(Argument::type(PersonAddressMoveEvent::class))
->shouldBeCalled();
diff --git a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php
index c19533e08..deef94525 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Serializer/Normalizer/PersonDocGenNormalizerTest.php
@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Serializer\Normalizer;
+use Chill\BudgetBundle\Service\Summary\SummaryBudgetInterface;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\PersonBundle\Entity\Household\Household;
@@ -72,6 +73,17 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
$this->normalizer = self::$container->get(NormalizerInterface::class);
}
+ public function dataGeneratorNormalizationNullOrNotNullHaveSameKeys(): iterable
+ {
+ yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read']]];
+
+ yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-household' => true]];
+
+ yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-relations' => true]];
+
+ yield [['docgen:expects' => Person::class, 'groups' => ['docgen:read'], 'docgen:person:with-budget' => true]];
+ }
+
public function generateData()
{
$person = new Person();
@@ -90,12 +102,16 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
yield [null, self::BLANK, 'normalization for a null person'];
}
- public function testNormalizationNullOrNotNullHaveSameKeys()
+ /**
+ * @dataProvider dataGeneratorNormalizationNullOrNotNullHaveSameKeys
+ *
+ * @param mixed $context
+ */
+ public function testNormalizationNullOrNotNullHaveSameKeys($context)
{
- $this->markTestSkipped();
$period = new Person();
- $notNullData = $this->buildPersonNormalizer()->normalize($period, 'docgen', ['docgen:expects' => Person::class]);
- $nullData = $this->buildPersonNormalizer()->normalize(null, 'docgen', ['docgen:expects' => Person::class]);
+ $notNullData = $this->buildPersonNormalizer()->normalize($period, 'docgen', $context);
+ $nullData = $this->buildPersonNormalizer()->normalize(null, 'docgen', $context);
$this->assertEqualsCanonicalizing(
array_keys($notNullData),
@@ -131,7 +147,6 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
public function testNormalizePersonWithHousehold()
{
- $this->markTestSkipped();
$household = new Household();
$person = new Person();
$person
@@ -172,7 +187,6 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
public function testNormalizePersonWithRelationships()
{
- $this->markTestSkipped();
$person = (new Person())->setFirstName('Renaud')->setLastName('megane');
$father = (new Person())->setFirstName('Clément')->setLastName('megane');
$mother = (new Person())->setFirstName('Mireille')->setLastName('Mathieu');
@@ -235,13 +249,25 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
?RelationshipRepository $relationshipRepository = null,
?TranslatorInterface $translator = null,
?TranslatableStringHelper $translatableStringHelper = null,
- ?NormalizerInterface $normalizer = null
+ ?NormalizerInterface $normalizer = null,
+ ?SummaryBudgetInterface $summaryBudget = null
): PersonDocGenNormalizer {
+ if (null === $summaryBudget) {
+ $summaryBudget = $this->prophesize(SummaryBudgetInterface::class);
+ $summaryBudget->getSummaryForHousehold(Argument::any())->willReturn(
+ ['resources' => [], 'charges' => []]
+ );
+ $summaryBudget->getSummaryForPerson(Argument::any())->willReturn(
+ ['resources' => [], 'charges' => []]
+ );
+ }
+
$personDocGenNormalizer = new PersonDocGenNormalizer(
$personRender ?? self::$container->get(PersonRender::class),
$relationshipRepository ?? self::$container->get(RelationshipRepository::class),
$translator ?? self::$container->get(TranslatorInterface::class),
- $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class)
+ $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class),
+ $summaryBudget->reveal(),
);
if (null === $normalizer) {
@@ -259,13 +285,31 @@ final class PersonDocGenNormalizerTest extends KernelTestCase
?PersonRender $personRender = null,
?RelationshipRepository $relationshipRepository = null,
?TranslatorInterface $translator = null,
- ?TranslatableStringHelper $translatableStringHelper = null
+ ?TranslatableStringHelper $translatableStringHelper = null,
+ ?SummaryBudgetInterface $summaryBudget = null
): PersonDocGenNormalizer {
+ if (null === $relationshipRepository) {
+ $relationshipRepository = $this->prophesize(RelationshipRepository::class);
+ $relationshipRepository->findByPerson(Argument::type(Person::class))->willReturn([]);
+ $relationshipRepository = $relationshipRepository->reveal();
+ }
+
+ if (null === $summaryBudget) {
+ $summaryBudget = $this->prophesize(SummaryBudgetInterface::class);
+ $summaryBudget->getSummaryForHousehold(Argument::any())->willReturn(
+ ['resources' => [], 'charges' => []]
+ );
+ $summaryBudget->getSummaryForPerson(Argument::any())->willReturn(
+ ['resources' => [], 'charges' => []]
+ );
+ }
+
$normalizer = new PersonDocGenNormalizer(
$personRender ?? self::$container->get(PersonRender::class),
- $relationshipRepository ?? self::$container->get(RelationshipRepository::class),
+ $relationshipRepository,
$translator ?? self::$container->get(TranslatorInterface::class),
- $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class)
+ $translatableStringHelper ?? self::$container->get(TranslatableStringHelperInterface::class),
+ $summaryBudget->reveal()
);
$normalizerManager = $this->prophesize(NormalizerInterface::class);
$normalizerManager->supportsNormalization(Argument::any(), 'docgen', Argument::any())->willReturn(true);
diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php
index 16260ec97..f060c4bfb 100644
--- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php
+++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php
@@ -762,7 +762,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface
*/
public function setEmail($email = null)
{
- $this->email = $email;
+ $this->email = trim((string) $email);
return $this;
}
diff --git a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php
index 2a57a2f55..f67417767 100644
--- a/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php
+++ b/src/Bundle/ChillThirdPartyBundle/Repository/ThirdPartyACLAwareRepository.php
@@ -34,6 +34,12 @@ final class ThirdPartyACLAwareRepository implements ThirdPartyACLAwareRepository
{
$qb = $this->thirdPartyRepository->createQueryBuilder('tp');
+ $qb->leftJoin('tp.parent', 'parent')
+ ->andWhere($qb->expr()->andX(
+ 'tp.active = \'TRUE\'',
+ $qb->expr()->orX($qb->expr()->isNull('parent'), 'parent.active = \'TRUE\'')
+ ));
+
if (null !== $filterString) {
$qb->andWhere($qb->expr()->like('tp.canonicalized', 'LOWER(UNACCENT(:filterString))'))
->setParameter('filterString', '%' . $filterString . '%');
diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
index e4b7f43af..f43a6eda2 100644
--- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
+++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php
@@ -109,14 +109,15 @@ class ThirdPartyApiSearch implements SearchApiInterface
}
$query
- ->setSelectPertinence(implode(' + ', $pertinence), array_merge(
+ ->setSelectPertinence(implode(' + ', $pertinence) . ' + 1', array_merge(
[],
...$pertinenceArgs
))
- ->andWhereClause(implode(' OR ', $wheres), array_merge(
- [],
- ...$whereArgs
- ));
+ ->andWhereClause(implode(' AND ', $wheres)
+ . ' AND tparty.active IS TRUE and (parent.active IS TRUE OR parent IS NULL)', array_merge(
+ [],
+ ...$whereArgs
+ ));
return $query;
}
diff --git a/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php b/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php
index 87bfb6995..5eb8895b3 100644
--- a/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php
+++ b/src/Bundle/ChillThirdPartyBundle/Serializer/Normalizer/ThirdPartyNormalizer.php
@@ -63,7 +63,7 @@ class ThirdPartyNormalizer implements NormalizerAwareInterface, NormalizerInterf
}, $thirdParty->getTypesAndCategories()),
'profession' => $this->normalizer->normalize($thirdParty->getProfession(), $format, $context),
'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']),
- 'telephone' => $this->normalizer->normalize($thirdParty->getTelephone()),
+ 'telephone' => $this->normalizer->normalize($thirdParty->getTelephone(), $format, $context),
'email' => $thirdParty->getEmail(),
'isChild' => $thirdParty->isChild(),
'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context),
diff --git a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php
index cec9dee7d..4fe3da927 100644
--- a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php
+++ b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php
@@ -71,13 +71,13 @@ class ThirdPartyRender extends AbstractChillEntityRender
$civility = '';
}
- if (!empty($entity->getAcronym())) {
+ if ('' !== (string) $entity->getAcronym()) {
$acronym = ' (' . $entity->getAcronym() . ')';
} else {
$acronym = '';
}
- $firstname = empty($entity->getFirstname()) ? '' : $entity->getFirstname();
+ $firstname = ('' === $entity->getFirstname()) ? '' : $entity->getFirstname();
return $civility . $firstname . ' ' . $entity->getName() . $acronym;
}