diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e42392a9..8e610ebd8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to
* [3party]: show parent in list
* [3party]: change color for badge "child"
* [3party]: fix address creation
+* [household members editor] finalisation of editor
@@ -40,10 +41,14 @@ and this project adheres to
* [FilterOrder]: add development kit for generating filter and ordering in list
* [Capitalization of names] person names are capitalized on creation, on prePersist event
+* [On-The-Fly] modale works for showing, editing and creating person or thirdparty ;
+* [AccompanyingCourse Resume page] associated persons list, can see household when hover, and with show on-the-fly modale when clicking person ;
### test release 2021-10-04
* [Household editor][UI] Update how household suggestion and addresses are picked;
+
+ See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/80
* [AddAddress] Handle address suggestion;
* [CenterType][Create a person] when overriding the ACL rules, allow to show a PickCenterType
when no centers are reachable by the default ACL.
@@ -62,8 +67,30 @@ and this project adheres to
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
-* [On-The-Fly] modale works for showing, editing and creating person or thirdparty ;
-* [AccompanyingCourse Resume page] associated persons list, can see household when hover, and with show on-the-fly modale when clicking person ;
+* [Household editor] suggest only temporarily addresses;
+ See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/82
+* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
+* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;
+* [AddAddress] Handle address suggestion;
+* [AddAddress][Entity address]: add a link between address and address reference;
+* [Household editor] suggest household by comparing the temporary addresses from courses;
-## Test release yyyy-mm-dd
+ See https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/81
+* On-The-Fly modale works for showing, editing and creating person and thirdparty
+
+## Test released
+
+
+
+## Stable releases
+
+No stable releases for v2+
+
+>>>>>>> 107b8131 (update changelog)
diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php
index 4cc5c37ba..06839ec99 100644
--- a/src/Bundle/ChillMainBundle/Entity/Address.php
+++ b/src/Bundle/ChillMainBundle/Entity/Address.php
@@ -23,7 +23,7 @@ class Address
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $id;
@@ -31,7 +31,7 @@ class Address
* @var string
*
* @ORM\Column(type="string", length=255)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $street = '';
@@ -39,7 +39,7 @@ class Address
* @var string
*
* @ORM\Column(type="string", length=255)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $streetNumber = '';
@@ -47,7 +47,7 @@ class Address
* @var PostalCode
*
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $postcode;
@@ -55,7 +55,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=16, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $floor;
@@ -63,7 +63,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=16, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $corridor;
@@ -71,7 +71,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=16, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $steps;
@@ -79,7 +79,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=255, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $buildingName;
@@ -87,7 +87,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=16, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $flat;
@@ -95,7 +95,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=255, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $distribution;
@@ -103,7 +103,7 @@ class Address
* @var string|null
*
* @ORM\Column(type="string", length=255, nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $extra;
@@ -114,7 +114,7 @@ class Address
* @var \DateTime
*
* @ORM\Column(type="date")
- * @groups({"write"})
+ * @Groups({"write"})
*/
private \DateTime $validFrom;
@@ -125,13 +125,13 @@ class Address
* @var \DateTime|null
*
* @ORM\Column(type="date", nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private ?\DateTime $validTo = null;
/**
* True if the address is a "no address", aka homeless person, ...
- * @groups({"write"})
+ * @Groups({"write"})
* @ORM\Column(type="boolean")
*
* @var bool
@@ -144,7 +144,7 @@ class Address
* @var Point|null
*
* @ORM\Column(type="point", nullable=true)
- * @groups({"write"})
+ * @Groups({"write"})
*/
private $point;
@@ -154,7 +154,7 @@ class Address
* @var ThirdParty|null
*
* @ORM\ManyToOne(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty")
- * @groups({"write"})
+ * @Groups({"write"})
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $linkedToThirdParty;
@@ -166,6 +166,12 @@ class Address
*/
private $customs = [];
+ /**
+ * @ORM\ManyToOne(targetEntity=AddressReference::class)
+ * @Groups({"write"})
+ */
+ private ?AddressReference $addressReference = null;
+
public function __construct()
{
$this->validFrom = new \DateTime();
@@ -376,6 +382,7 @@ class Address
public static function createFromAddress(Address $original) : Address
{
return (new Address())
+ ->setAddressReference($original->getAddressReference())
->setBuildingName($original->getBuildingName())
->setCorridor($original->getCorridor())
->setCustoms($original->getCustoms())
@@ -402,6 +409,7 @@ class Address
->setPostcode($original->getPostcode())
->setStreet($original->getStreet())
->setStreetNumber($original->getStreetNumber())
+ ->setAddressReference($original)
;
}
@@ -549,5 +557,22 @@ class Address
return $this;
}
+ /**
+ * @return AddressReference|null
+ */
+ public function getAddressReference(): ?AddressReference
+ {
+ return $this->addressReference;
+ }
+
+ /**
+ * @param AddressReference|null $addressReference
+ * @return Address
+ */
+ public function setAddressReference(?AddressReference $addressReference = null): Address
+ {
+ $this->addressReference = $addressReference;
+ return $this;
+ }
}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/api/download.js b/src/Bundle/ChillMainBundle/Resources/public/lib/api/download.js
new file mode 100644
index 000000000..625103ebe
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/lib/api/download.js
@@ -0,0 +1,39 @@
+
+const _fetchAction = (page, uri, params) => {
+ const item_per_page = 50;
+ if (params === undefined) {
+ params = {};
+ }
+ let url = uri + '?' + new URLSearchParams({ item_per_page, page, ...params });
+
+ return fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json;charset=utf-8'
+ },
+ }).then(response => {
+ if (response.ok) { return response.json(); }
+ throw Error({ m: response.statusText });
+ });
+};
+
+const fetchResults = async (uri, params) => {
+ let promises = [],
+ page = 1;
+ let firstData = await _fetchAction(page, uri, params);
+
+ promises.push(Promise.resolve(firstData.results));
+
+ if (firstData.pagination.more) {
+ do {
+ page = ++page;
+ promises.push(_fetchAction(page, uri, params).then(r => Promise.resolve(r.results)));
+ } while (page * firstData.pagination.items_per_page < firstData.count)
+ }
+
+ return Promise.all(promises).then(values => values.flat());
+};
+
+export {
+ fetchResults
+};
diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js b/src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
index 9073822bb..4c4223d77 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
+++ b/src/Bundle/ChillMainBundle/Resources/public/lib/api/scope.js
@@ -1,15 +1,7 @@
+import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
+
const fetchScopes = () => {
- return window.fetch('/api/1.0/main/scope.json').then(response => {
- if (response.ok) {
- return response.json();
- }
- }).then(data => {
- //console.log(data);
- return new Promise((resolve, reject) => {
- //console.log(data);
- resolve(data.results);
- });
- });
+ return fetchResults('/api/1.0/main/scope.json');
};
export {
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue
index 5616ce0be..7160d7cec 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue
@@ -589,6 +589,14 @@ export default {
'point': this.entity.selected.address.point.coordinates
});
}
+
+ // add the address reference, if any
+ if (this.entity.selected.address.addressReference !== undefined) {
+ newAddress = Object.assign(newAddress, {
+ 'addressReference': this.entity.selected.address.addressReference
+ });
+ }
+
if (this.validFrom) {
console.log('add validFrom in fetch body', this.entity.selected.valid.from);
newAddress = Object.assign(newAddress, {
@@ -733,6 +741,9 @@ export default {
},
/**
+ *
+ * Called when the event pick-address is emitted, which is, by the way,
+ * called when an address suggestion is picked.
*
* @param address the address selected
*/
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue
index 50a1bd8c1..ca2f5d634 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue
@@ -95,6 +95,9 @@ export default {
},
selectAddress(value) {
this.entity.selected.address = value;
+ this.entity.selected.address.addressReference = {
+ id: value.id
+ };
this.entity.selected.address.street = value.street;
this.entity.selected.address.streetNumber = value.streetNumber;
this.entity.selected.writeNew.address = false;
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php
index 2b39c07c3..ee628e014 100644
--- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php
@@ -3,6 +3,7 @@
namespace Chill\MainBundle\Serializer\Normalizer;
use Chill\MainBundle\Entity\Address;
+use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
@@ -33,6 +34,9 @@ class AddressNormalizer implements NormalizerAwareInterface, NormalizerInterface
$data['extra'] = $address->getExtra();
$data['validFrom'] = $address->getValidFrom();
$data['validTo'] = $address->getValidTo();
+ $data['addressReference'] = $this->normalizer->normalize($address->getAddressReference(), $format, [
+ AbstractNormalizer::GROUPS => ['read']
+ ]);
return $data;
}
diff --git a/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php b/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php
new file mode 100644
index 000000000..a2fbefa69
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/migrations/Version20210929192242.php
@@ -0,0 +1,31 @@
+addSql('ALTER TABLE chill_main_address ADD addressReference_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F647069464 FOREIGN KEY (addressReference_id) REFERENCES chill_main_address_reference (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX IDX_165051F647069464 ON chill_main_address (addressReference_id)');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE chill_main_address DROP addressReference_id');
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php
index 0bb804689..11e41ba29 100644
--- a/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php
+++ b/src/Bundle/ChillPersonBundle/Controller/HouseholdApiController.php
@@ -4,24 +4,31 @@ namespace Chill\PersonBundle\Controller;
use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\Entity\Address;
+use Chill\MainBundle\Entity\AddressReference;
use Chill\MainBundle\Serializer\Model\Collection;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\Household\Household;
+use Chill\PersonBundle\Repository\Household\HouseholdACLAwareRepositoryInterface;
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Routing\Annotation\Route;
+use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
class HouseholdApiController extends ApiController
{
private HouseholdRepository $householdRepository;
- public function __construct(HouseholdRepository $householdRepository)
- {
+ private HouseholdACLAwareRepositoryInterface $householdACLAwareRepository;
+
+ public function __construct(
+ HouseholdRepository $householdRepository,
+ HouseholdACLAwareRepositoryInterface $householdACLAwareRepository
+ ) {
$this->householdRepository = $householdRepository;
+ $this->householdACLAwareRepository = $householdACLAwareRepository;
}
-
public function householdAddressApi($id, Request $request, string $_format): Response
{
@@ -37,7 +44,7 @@ class HouseholdApiController extends ApiController
{
// TODO add acl
- $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
+ $count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
$paginator = $this->getPaginatorFactory()->create($count);
if ($count === 0) {
@@ -93,4 +100,27 @@ class HouseholdApiController extends ApiController
return $this->json(\array_values($addresses), Response::HTTP_OK, [],
[ 'groups' => [ 'read' ] ]);
}
+
+ /**
+ *
+ * @Route("/api/1.0/person/household/by-address-reference/{id}.json",
+ * name="chill_api_person_household_by_address_reference")
+ * @param AddressReference $addressReference
+ * @return \Symfony\Component\HttpFoundation\JsonResponse
+ */
+ public function getHouseholdByAddressReference(AddressReference $addressReference): Response
+ {
+ // TODO ACL
+ $this->denyAccessUnlessGranted('ROLE_USER');
+
+ $total = $this->householdACLAwareRepository->countByAddressReference($addressReference);
+ $paginator = $this->getPaginatorFactory()->create($total);
+ $households = $this->householdACLAwareRepository->findByAddressReference($addressReference,
+ $paginator->getCurrentPageFirstItemNumber(), $paginator->getItemsPerPage());
+ $collection = new Collection($households, $paginator);
+
+ return $this->json($collection, Response::HTTP_OK, [], [
+ AbstractNormalizer::GROUPS => ['read']
+ ]);
+ }
}
diff --git a/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php b/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php
index 17635a8fa..ab39c13bb 100644
--- a/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php
+++ b/src/Bundle/ChillPersonBundle/Controller/PersonApiController.php
@@ -77,13 +77,6 @@ class PersonApiController extends ApiController
$a = $participation->getAccompanyingPeriod()->getAddressLocation();
$addresses[$a->getId()] = $a;
}
- if (null !== $personLocation = $participation
- ->getAccompanyingPeriod()->getPersonLocation()) {
- $a = $personLocation->getCurrentHouseholdAddress();
- if (null !== $a) {
- $addresses[$a->getId()] = $a;
- }
- }
}
// remove the actual address
diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php
new file mode 100644
index 000000000..38236df14
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepository.php
@@ -0,0 +1,103 @@
+em = $em;
+ $this->authorizationHelper = $authorizationHelper;
+ $this->security = $security;
+ }
+
+ public function countByAddressReference(AddressReference $addressReference): int
+ {
+ $qb = $this->buildQueryByAddressReference($addressReference);
+ $qb = $this->addACL($qb);
+
+ return $qb->select('COUNT(h)')
+ ->getQuery()
+ ->getSingleScalarResult();
+ }
+
+ public function findByAddressReference(
+ AddressReference $addressReference,
+ ?int $firstResult = 0,
+ ?int $maxResult = 50
+ ): array {
+ $qb = $this->buildQueryByAddressReference($addressReference);
+ $qb = $this->addACL($qb);
+
+ return $qb
+ ->select('h')
+ ->setFirstResult($firstResult)
+ ->setMaxResults($maxResult)
+ ->getQuery()
+ ->getResult();
+ }
+
+ public function buildQueryByAddressReference(AddressReference $addressReference): QueryBuilder
+ {
+ $qb = $this->em->createQueryBuilder();
+ $qb
+ ->select('h')
+ ->from(Household::class, 'h')
+ ->join('h.addresses', 'address')
+ ->where(
+ $qb->expr()->eq('address.addressReference', ':reference')
+ )
+ ->setParameter(':reference', $addressReference)
+ ->andWhere(
+ $qb->expr()->andX(
+ $qb->expr()->lte('address.validFrom', ':today'),
+ $qb->expr()->orX(
+ $qb->expr()->isNull('address.validTo'),
+ $qb->expr()->gt('address.validTo', ':today')
+ )
+ )
+ )
+ ->setParameter('today', new \DateTime('today'))
+ ;
+
+ return $qb;
+ }
+
+ public function addACL(QueryBuilder $qb, string $alias = 'h'): QueryBuilder
+ {
+ $centers = $this->authorizationHelper->getReachableCenters(
+ $this->security->getUser(),
+ HouseholdVoter::SHOW
+ );
+
+ if ([] === $centers) {
+ return $qb
+ ->andWhere("'FALSE' = 'TRUE'");
+ }
+
+ $qb
+ ->join($alias.'.members', 'members')
+ ->join('members.person', 'person')
+ ->andWhere(
+ $qb->expr()->in('person.center', ':centers')
+ )
+ ->setParameter('centers', $centers);
+
+ return $qb;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php
new file mode 100644
index 000000000..56a927ae5
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Repository/Household/HouseholdACLAwareRepositoryInterface.php
@@ -0,0 +1,23 @@
+ {
+ const url = `/api/1.0/person/household/by-address-reference/${reference.id}.json`
+ return fetchResults(url);
+};
+
+export {
+ fetchHouseholdByAddressReference
+};
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue
index ff1cab206..52eac5ea6 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue
@@ -1,34 +1,150 @@
-
{{ $t('household_members_editor.dates_title') }}
+
+ {{ $t('household_members_editor.dates.dates_title') }}