mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-12 13:24:25 +00:00
Merge branch 'features/add-suggestion-household-member-editor' into 'master'
Add suggestion household member editor See merge request Chill-Projet/chill-bundles!97
This commit is contained in:
commit
741ef7b40d
@ -4,15 +4,50 @@ namespace Chill\PersonBundle\Controller;
|
|||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
use Chill\MainBundle\Entity\Address;
|
use Chill\MainBundle\Entity\Address;
|
||||||
|
use Chill\MainBundle\Serializer\Model\Collection;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Repository\Household\HouseholdRepository;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||||
|
|
||||||
class HouseholdApiController extends ApiController
|
class HouseholdApiController extends ApiController
|
||||||
{
|
{
|
||||||
|
private HouseholdRepository $householdRepository;
|
||||||
|
|
||||||
|
public function __construct(HouseholdRepository $householdRepository)
|
||||||
|
{
|
||||||
|
$this->householdRepository = $householdRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function householdAddressApi($id, Request $request, string $_format): Response
|
public function householdAddressApi($id, Request $request, string $_format): Response
|
||||||
{
|
{
|
||||||
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]);
|
return $this->addRemoveSomething('address', $id, $request, $_format, 'address', Address::class, [ 'groups' => [ 'read' ] ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find Household of people participating to the same AccompanyingPeriod
|
||||||
|
*
|
||||||
|
* @ParamConverter("person", options={"id" = "person_id"})
|
||||||
|
*/
|
||||||
|
public function suggestHouseholdByAccompanyingPeriodParticipationApi(Person $person, string $_format)
|
||||||
|
{
|
||||||
|
// TODO add acl
|
||||||
|
|
||||||
|
$count = $this->householdRepository->countByAccompanyingPeriodParticipation($person);
|
||||||
|
$paginator = $this->getPaginatorFactory()->create($count);
|
||||||
|
|
||||||
|
if ($count === 0) {
|
||||||
|
$households = [];
|
||||||
|
} else {
|
||||||
|
$households = $this->householdRepository->findByAccompanyingPeriodParticipation($person,
|
||||||
|
$paginator->getItemsPerPage(), $paginator->getCurrentPageFirstItemNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
$collection = new Collection($households, $paginator);
|
||||||
|
|
||||||
|
return $this->json($collection, Response::HTTP_OK, [],
|
||||||
|
[ "groups" => ["read"]]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace Chill\PersonBundle\Controller;
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
use Chill\PersonBundle\Entity\Household\Position;
|
use Chill\PersonBundle\Entity\Household\Position;
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\PersonBundle\Entity\Household\Household;
|
use Chill\PersonBundle\Entity\Household\Household;
|
||||||
@ -25,11 +26,17 @@ class HouseholdMemberController extends ApiController
|
|||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
|
private AccompanyingPeriodRepository $periodRepository;
|
||||||
|
|
||||||
public function __construct(UrlGeneratorInterface $generator, TranslatorInterface $translator)
|
public function __construct(
|
||||||
|
UrlGeneratorInterface $generator,
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
AccompanyingPeriodRepository $periodRepository
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$this->generator = $generator;
|
$this->generator = $generator;
|
||||||
$this->translator = $translator;
|
$this->translator = $translator;
|
||||||
|
$this->periodRepository = $periodRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,8 +151,23 @@ class HouseholdMemberController extends ApiController
|
|||||||
'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'),
|
'allowLeaveWithoutHousehold' => $allowLeaveWithoutHousehold ?? $request->query->has('allow_leave_without_household'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// context
|
||||||
|
if ($request->query->has('accompanying_period_id')) {
|
||||||
|
$period = $this->periodRepository->find(
|
||||||
|
$request->query->getInt('accompanying_period_id')
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($period === null) {
|
||||||
|
throw $this->createNotFoundException('period not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add acl on accompanying Course
|
||||||
|
}
|
||||||
|
|
||||||
return $this->render('@ChillPerson/Household/members_editor.html.twig', [
|
return $this->render('@ChillPerson/Household/members_editor.html.twig', [
|
||||||
'data' => $data
|
'data' => $data,
|
||||||
|
'expandSuggestions' => (int) $request->query->getBoolean('expand_suggestions', false),
|
||||||
|
'accompanyingCourse' => $period ?? null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,6 +565,13 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
],
|
],
|
||||||
'controller_action' => 'householdAddressApi'
|
'controller_action' => 'householdAddressApi'
|
||||||
],
|
],
|
||||||
|
'suggestHouseholdByAccompanyingPeriodParticipation' => [
|
||||||
|
'path' => '/suggest/by-person/{person_id}/through-accompanying-period-participation.{_format}',
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
Request::METHOD_HEAD => true,
|
||||||
|
]
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -25,8 +25,9 @@ namespace Chill\PersonBundle\Repository;
|
|||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
final class AccompanyingPeriodRepository
|
final class AccompanyingPeriodRepository implements ObjectRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
|
||||||
@ -34,4 +35,32 @@ final class AccompanyingPeriodRepository
|
|||||||
{
|
{
|
||||||
$this->repository = $entityManager->getRepository(AccompanyingPeriod::class);
|
$this->repository = $entityManager->getRepository(AccompanyingPeriod::class);
|
||||||
}
|
}
|
||||||
|
public function find($id): ?AccompanyingPeriod
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AccompanyingPeriod[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null): ?AccompanyingPeriod
|
||||||
|
{
|
||||||
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria): ?AccompanyingPeriod
|
||||||
|
{
|
||||||
|
return $this->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName()
|
||||||
|
{
|
||||||
|
return AccompanyingPeriod::class;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,102 @@
|
|||||||
namespace Chill\PersonBundle\Repository\Household;
|
namespace Chill\PersonBundle\Repository\Household;
|
||||||
|
|
||||||
use Chill\PersonBundle\Entity\Household\Household;
|
use Chill\PersonBundle\Entity\Household\Household;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\Query\ResultSetMappingBuilder;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
final class HouseholdRepository
|
final class HouseholdRepository implements ObjectRepository
|
||||||
{
|
{
|
||||||
private EntityRepository $repository;
|
private EntityRepository $repository;
|
||||||
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
public function __construct(EntityManagerInterface $entityManager)
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
{
|
{
|
||||||
$this->repository = $entityManager->getRepository(Household::class);
|
$this->repository = $entityManager->getRepository(Household::class);
|
||||||
|
$this->em = $entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id)
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findAll()
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
{
|
||||||
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria)
|
||||||
|
{
|
||||||
|
return $this->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName()
|
||||||
|
{
|
||||||
|
return Household::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function countByAccompanyingPeriodParticipation(Person $person)
|
||||||
|
{
|
||||||
|
return $this->buildQueryByAccompanyingPeriodParticipation($person, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByAccompanyingPeriodParticipation(Person $person, int $limit, int $offset)
|
||||||
|
{
|
||||||
|
return $this->buildQueryByAccompanyingPeriodParticipation($person, false, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildQueryByAccompanyingPeriodParticipation(Person $person, bool $isCount = false, int $limit = 50, int $offset = 0)
|
||||||
|
{
|
||||||
|
$rsm = new ResultSetMappingBuilder($this->em);
|
||||||
|
$rsm->addRootEntityFromClassMetadata(Household::class, 'h');
|
||||||
|
|
||||||
|
if ($isCount) {
|
||||||
|
$rsm->addScalarResult('count', 'count');
|
||||||
|
$sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [
|
||||||
|
'{select}' => 'COUNT(households.*) AS count',
|
||||||
|
'{limits}' => ''
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$sql = \strtr(self::SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION, [
|
||||||
|
'{select}' => $rsm->generateSelectClause(['h' => 'households']),
|
||||||
|
'{limits}' => "OFFSET {$offset} LIMIT {$limit}"
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$native = $this->em->createNativeQuery($sql, $rsm);
|
||||||
|
$native->setParameters([0 => $person->getId(), 1 => $person->getId()]);
|
||||||
|
|
||||||
|
if ($isCount) {
|
||||||
|
return $native->getSingleScalarResult();
|
||||||
|
} else {
|
||||||
|
return $native->getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CONST SQL_BY_ACCOMPANYING_PERIOD_PARTICIPATION = <<<SQL
|
||||||
|
WITH participations AS (
|
||||||
|
SELECT DISTINCT part.accompanyingperiod_id
|
||||||
|
FROM chill_person_accompanying_period_participation AS part
|
||||||
|
WHERE person_id = ?),
|
||||||
|
other_participants AS (
|
||||||
|
SELECT person_id, startDate, endDate
|
||||||
|
FROM chill_person_accompanying_period_participation
|
||||||
|
JOIN participations USING (accompanyingperiod_id)
|
||||||
|
WHERE person_id != ?
|
||||||
|
),
|
||||||
|
households AS (SELECT DISTINCT household.*
|
||||||
|
FROM chill_person_household_members AS hmembers
|
||||||
|
JOIN other_participants AS op USING (person_id)
|
||||||
|
JOIN chill_person_household AS household ON hmembers.household_id = household.id
|
||||||
|
WHERE daterange(op.startDate, op.endDate) && daterange(hmembers.startDate, hmembers.endDate)
|
||||||
|
)
|
||||||
|
SELECT {select} FROM households {limits}
|
||||||
|
SQL;
|
||||||
|
}
|
||||||
|
@ -23,6 +23,21 @@ const householdMove = (payload) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchHouseholdSuggestionByAccompanyingPeriod = (personId) => {
|
||||||
|
const url = `/api/1.0/person/household/suggest/by-person/${personId}/through-accompanying-period-participation.json`;
|
||||||
|
return window.fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Error ({m: 'Error while fetching household suggestion', status: response.status});
|
||||||
|
}).then(data => Promise.resolve(data.results))
|
||||||
|
.catch(e => console.err(e));
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
householdMove,
|
householdMove,
|
||||||
|
fetchHouseholdSuggestionByAccompanyingPeriod,
|
||||||
};
|
};
|
||||||
|
@ -14,6 +14,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul v-if="allowChangeHousehold" class="record_actions">
|
<ul v-if="allowChangeHousehold" class="record_actions">
|
||||||
|
<li v-if="!showHouseholdSuggestion">
|
||||||
|
<button
|
||||||
|
class="sc-button"
|
||||||
|
@click="toggleHouseholdSuggestion"
|
||||||
|
>
|
||||||
|
{{ $tc('household_members_editor.show_household_suggestion',
|
||||||
|
countHouseholdSuggestion) }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li v-if="showHouseholdSuggestion">
|
||||||
|
<button
|
||||||
|
class="sc-button"
|
||||||
|
@click="toggleHouseholdSuggestion"
|
||||||
|
>
|
||||||
|
{{ $t('household_members_editor.hide_household_suggestion') }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
<li v-if="allowHouseholdCreate">
|
<li v-if="allowHouseholdCreate">
|
||||||
<button class="sc-button bt-create" @click="createHousehold">
|
<button class="sc-button bt-create" @click="createHousehold">
|
||||||
{{ $t('household_members_editor.household.create_household') }}
|
{{ $t('household_members_editor.household.create_household') }}
|
||||||
@ -31,11 +48,55 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div class="householdSuggestions">
|
||||||
|
<div v-if="showHouseholdSuggestion">
|
||||||
|
<p>{{ $t('household_members_editor.household_for_participants_accompanying_period') }}:</p>
|
||||||
|
<div class="householdSuggestionList">
|
||||||
|
<div
|
||||||
|
v-for="h in filterHouseholdSuggestionByAccompanyingPeriod"
|
||||||
|
class="item"
|
||||||
|
>
|
||||||
|
<household-viewer :household="h"></household-viewer>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button class="sc-button" @click="selectHousehold(h)">
|
||||||
|
{{ $t('household_members_editor.select_household') }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
.householdSuggestionList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
& > .item {
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
width: calc(50% - 1rem);
|
||||||
|
border: 1px solid var(--chill-light-gray);
|
||||||
|
padding: 0.5rem 0.5rem 0 0.5rem;
|
||||||
|
|
||||||
|
ul.record_actions {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters, mapState } from 'vuex';
|
||||||
import HouseholdViewer from 'ChillPersonAssets/vuejs/_components/Household/Household.vue';
|
import HouseholdViewer from 'ChillPersonAssets/vuejs/_components/Household/Household.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -47,6 +108,12 @@ export default {
|
|||||||
...mapGetters([
|
...mapGetters([
|
||||||
'hasHousehold',
|
'hasHousehold',
|
||||||
'isHouseholdNew',
|
'isHouseholdNew',
|
||||||
|
'hasHouseholdSuggestion',
|
||||||
|
'countHouseholdSuggestion',
|
||||||
|
'filterHouseholdSuggestionByAccompanyingPeriod',
|
||||||
|
]),
|
||||||
|
...mapState([
|
||||||
|
'showHouseholdSuggestion',
|
||||||
]),
|
]),
|
||||||
household() {
|
household() {
|
||||||
return this.$store.state.household;
|
return this.$store.state.household;
|
||||||
@ -74,6 +141,12 @@ export default {
|
|||||||
},
|
},
|
||||||
forceLeaveWithoutHousehold() {
|
forceLeaveWithoutHousehold() {
|
||||||
this.$store.dispatch('forceLeaveWithoutHousehold');
|
this.$store.dispatch('forceLeaveWithoutHousehold');
|
||||||
|
},
|
||||||
|
toggleHouseholdSuggestion() {
|
||||||
|
this.$store.commit('toggleHouseholdSuggestion');
|
||||||
|
},
|
||||||
|
selectHousehold(h) {
|
||||||
|
this.$store.dispatch('selectHousehold', h);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -5,7 +5,7 @@ const appMessages = {
|
|||||||
fr: {
|
fr: {
|
||||||
household_members_editor: {
|
household_members_editor: {
|
||||||
household: {
|
household: {
|
||||||
no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage.",
|
no_household_choose_one: "Aucun ménage de destination. Choisissez un ménage. Les usagers concernés par la modification apparaitront ensuite.",
|
||||||
new_household: "Nouveau ménage",
|
new_household: "Nouveau ménage",
|
||||||
create_household: "Créer un ménage",
|
create_household: "Créer un ménage",
|
||||||
search_household: "Chercher un ménage",
|
search_household: "Chercher un ménage",
|
||||||
@ -13,7 +13,7 @@ const appMessages = {
|
|||||||
leave_without_household: "Sans nouveau ménage"
|
leave_without_household: "Sans nouveau ménage"
|
||||||
},
|
},
|
||||||
concerned: {
|
concerned: {
|
||||||
title: "Usagers concernés",
|
title: "Nouveaux membres du ménage",
|
||||||
add_persons: "Ajouter d'autres usagers",
|
add_persons: "Ajouter d'autres usagers",
|
||||||
search: "Rechercher des usagers",
|
search: "Rechercher des usagers",
|
||||||
move_to: "Déplacer vers",
|
move_to: "Déplacer vers",
|
||||||
@ -29,6 +29,10 @@ const appMessages = {
|
|||||||
remove_position: "Retirer des {position}",
|
remove_position: "Retirer des {position}",
|
||||||
remove_concerned: "Ne plus transférer",
|
remove_concerned: "Ne plus transférer",
|
||||||
household_part: "Ménage de destination",
|
household_part: "Ménage de destination",
|
||||||
|
hide_household_suggestion: "Masquer les suggestions",
|
||||||
|
show_household_suggestion: 'Aucune suggestion | Afficher une suggestion | Afficher {count} suggestions',
|
||||||
|
household_for_participants_accompanying_period: "Ces ménages partagent le même parcours",
|
||||||
|
select_household: "Choisir ce ménage",
|
||||||
dates_title: "Période de validité",
|
dates_title: "Période de validité",
|
||||||
dates: {
|
dates: {
|
||||||
start_date: "Début de validité",
|
start_date: "Début de validité",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import { householdMove, householdMoveTest } from './../api.js';
|
import { householdMove, fetchHouseholdSuggestionByAccompanyingPeriod } from './../api.js';
|
||||||
import { datetimeToISO } from 'ChillMainAssets/js/date.js';
|
import { datetimeToISO } from 'ChillMainAssets/js/date.js';
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
@ -14,6 +14,8 @@ const concerned = window.household_members_editor_data.persons.map(p => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('expand suggestions', window.household_members_editor_expand_suggestions === 1);
|
||||||
|
|
||||||
const store = createStore({
|
const store = createStore({
|
||||||
strict: debug,
|
strict: debug,
|
||||||
state: {
|
state: {
|
||||||
@ -33,11 +35,16 @@ const store = createStore({
|
|||||||
allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch,
|
allowHouseholdSearch: window.household_members_editor_data.allowHouseholdSearch,
|
||||||
allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold,
|
allowLeaveWithoutHousehold: window.household_members_editor_data.allowLeaveWithoutHousehold,
|
||||||
forceLeaveWithoutHousehold: false,
|
forceLeaveWithoutHousehold: false,
|
||||||
|
householdSuggestionByAccompanyingPeriod: [],
|
||||||
|
showHouseholdSuggestion: window.household_members_editor_expand_suggestions === 1,
|
||||||
warnings: [],
|
warnings: [],
|
||||||
errors: []
|
errors: []
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
isHouseholdNew(state) {
|
isHouseholdNew(state) {
|
||||||
|
if (state.household === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return !Number.isInteger(state.household.id);
|
return !Number.isInteger(state.household.id);
|
||||||
},
|
},
|
||||||
hasHousehold(state) {
|
hasHousehold(state) {
|
||||||
@ -46,6 +53,21 @@ const store = createStore({
|
|||||||
hasHouseholdOrLeave(state) {
|
hasHouseholdOrLeave(state) {
|
||||||
return state.household !== null || state.forceLeaveWithoutHousehold;
|
return state.household !== null || state.forceLeaveWithoutHousehold;
|
||||||
},
|
},
|
||||||
|
hasHouseholdSuggestion(state, getters) {
|
||||||
|
return getters.filterHouseholdSuggestionByAccompanyingPeriod.length > 0;
|
||||||
|
},
|
||||||
|
countHouseholdSuggestion(state, getters) {
|
||||||
|
return getters.filterHouseholdSuggestionByAccompanyingPeriod.length;
|
||||||
|
},
|
||||||
|
filterHouseholdSuggestionByAccompanyingPeriod(state) {
|
||||||
|
if (state.household === null) {
|
||||||
|
return state.householdSuggestionByAccompanyingPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
return state.householdSuggestionByAccompanyingPeriod
|
||||||
|
.filter(h => h.id !== state.household.id)
|
||||||
|
;
|
||||||
|
},
|
||||||
hasPersonsWellPositionnated(state, getters) {
|
hasPersonsWellPositionnated(state, getters) {
|
||||||
return getters.needsPositionning === false
|
return getters.needsPositionning === false
|
||||||
|| (getters.persons.length > 0 && getters.concUnpositionned.length === 0);
|
|| (getters.persons.length > 0 && getters.concUnpositionned.length === 0);
|
||||||
@ -172,9 +194,25 @@ const store = createStore({
|
|||||||
state.household = null;
|
state.household = null;
|
||||||
state.forceLeaveWithoutHousehold = true;
|
state.forceLeaveWithoutHousehold = true;
|
||||||
},
|
},
|
||||||
|
selectHousehold(state, household) {
|
||||||
|
state.household = household;
|
||||||
|
state.forceLeaveWithoutHousehold = false;
|
||||||
|
},
|
||||||
|
setHouseholdSuggestionByAccompanyingPeriod(state, households) {
|
||||||
|
let existingIds = state.householdSuggestionByAccompanyingPeriod
|
||||||
|
.map(h => h.id);
|
||||||
|
for (let i in households) {
|
||||||
|
if (!existingIds.includes(households[i].id)) {
|
||||||
|
state.householdSuggestionByAccompanyingPeriod.push(households[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
setStartDate(state, dateI) {
|
setStartDate(state, dateI) {
|
||||||
state.startDate = dateI;
|
state.startDate = dateI;
|
||||||
},
|
},
|
||||||
|
toggleHouseholdSuggestion(state) {
|
||||||
|
state.showHouseholdSuggestion = !state.showHouseholdSuggestion;
|
||||||
|
},
|
||||||
setWarnings(state, warnings) {
|
setWarnings(state, warnings) {
|
||||||
state.warnings = warnings;
|
state.warnings = warnings;
|
||||||
// reset errors, which should come from servers
|
// reset errors, which should come from servers
|
||||||
@ -213,6 +251,10 @@ const store = createStore({
|
|||||||
commit('forceLeaveWithoutHousehold');
|
commit('forceLeaveWithoutHousehold');
|
||||||
dispatch('computeWarnings');
|
dispatch('computeWarnings');
|
||||||
},
|
},
|
||||||
|
selectHousehold({ commit }, h) {
|
||||||
|
commit('selectHousehold', h);
|
||||||
|
dispatch('computeWarnings');
|
||||||
|
},
|
||||||
setStartDate({ commit, dispatch }, date) {
|
setStartDate({ commit, dispatch }, date) {
|
||||||
commit('setStartDate', date);
|
commit('setStartDate', date);
|
||||||
dispatch('computeWarnings');
|
dispatch('computeWarnings');
|
||||||
@ -220,6 +262,12 @@ const store = createStore({
|
|||||||
setComment({ commit }, payload) {
|
setComment({ commit }, payload) {
|
||||||
commit('setComment', payload);
|
commit('setComment', payload);
|
||||||
},
|
},
|
||||||
|
fetchHouseholdSuggestionForConcerned({ commit, state }, person) {
|
||||||
|
fetchHouseholdSuggestionByAccompanyingPeriod(person.id)
|
||||||
|
.then(households => {
|
||||||
|
commit('setHouseholdSuggestionByAccompanyingPeriod', households);
|
||||||
|
});
|
||||||
|
},
|
||||||
computeWarnings({ commit, state, getters }) {
|
computeWarnings({ commit, state, getters }) {
|
||||||
let warnings = [],
|
let warnings = [],
|
||||||
payload;
|
payload;
|
||||||
@ -255,7 +303,7 @@ const store = createStore({
|
|||||||
if (household.type === 'household') {
|
if (household.type === 'household') {
|
||||||
household_id = household.id;
|
household_id = household.id;
|
||||||
// nothing to do anymore here, bye-bye !
|
// nothing to do anymore here, bye-bye !
|
||||||
window.location.replace(`/fr/person/household/${household_id}/members`);
|
window.location.replace(`/fr/person/household/${household_id}/summary`);
|
||||||
} else {
|
} else {
|
||||||
// we assume the answer was 422...
|
// we assume the answer was 422...
|
||||||
error = household;
|
error = household;
|
||||||
@ -274,4 +322,10 @@ const store = createStore({
|
|||||||
|
|
||||||
store.dispatch('computeWarnings');
|
store.dispatch('computeWarnings');
|
||||||
|
|
||||||
|
if (concerned.length > 0) {
|
||||||
|
concerned.forEach(c => {
|
||||||
|
store.dispatch('fetchHouseholdSuggestionForConcerned', c.person);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export { store };
|
export { store };
|
||||||
|
@ -39,12 +39,15 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{% for p in withoutHousehold %}
|
{% for p in withoutHousehold %}
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" name="persons[]" value="{{ p.id }}" />
|
<input type="checkbox" name="persons[]" value="{{ p.id }}" checked />
|
||||||
{{ p|chill_entity_render_box }}
|
{{ p|chill_entity_render_box }}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<input type="hidden" name="expand_suggestions" value="true" />
|
||||||
|
<input type="hidden" name="accompanying_period_id", value="{{ accompanyingCourse.id }}" />
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<button type="submit" class="sc-button bt-edit">
|
<button type="submit" class="sc-button bt-edit">
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{% extends '@ChillMain/layout.html.twig' %}
|
{% extends accompanyingCourse != null ? '@ChillPerson/AccompanyingCourse/layout.html.twig'
|
||||||
|
: '@ChillMain/layout.html.twig' %}
|
||||||
|
|
||||||
{% block title 'household.Edit household members'|trans %}
|
{% block title 'household.Edit household members'|trans %}
|
||||||
|
|
||||||
@ -14,6 +15,7 @@
|
|||||||
{% block js %}
|
{% block js %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.household_members_editor_data = {{ data|json_encode|raw }};
|
window.household_members_editor_data = {{ data|json_encode|raw }};
|
||||||
|
window.household_members_editor_expand_suggestions = {{ expandSuggestions }};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('household_members_editor') }}
|
{{ encore_entry_script_tags('household_members_editor') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
|
||||||
|
class HouseholdApiControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider generatePersonId
|
||||||
|
*/
|
||||||
|
public function testSuggestByAccompanyingPeriodParticipation(int $personId)
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(
|
||||||
|
Request::METHOD_GET,
|
||||||
|
"/api/1.0/person/household/suggest/by-person/{$personId}/through-accompanying-period-participation.json"
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generatePersonId()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$qb = self::$container->get(EntityManagerInterface::class)
|
||||||
|
->createQueryBuilder();
|
||||||
|
|
||||||
|
$period = $qb
|
||||||
|
->select('ap')
|
||||||
|
->from(AccompanyingPeriod::class, 'ap')
|
||||||
|
->where(
|
||||||
|
$qb->expr()->gte('SIZE(ap.participations)', 2)
|
||||||
|
)
|
||||||
|
->getQuery()
|
||||||
|
->setMaxResults(1)
|
||||||
|
->getSingleResult()
|
||||||
|
;
|
||||||
|
|
||||||
|
$person = $period->getParticipations()
|
||||||
|
->first()->getPerson();
|
||||||
|
|
||||||
|
yield [ $person->getId() ];
|
||||||
|
}
|
||||||
|
}
|
@ -967,6 +967,36 @@ paths:
|
|||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
/1.0/person/household/suggest/by-person/{person_id}/through-accompanying-period-participation.json:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- household
|
||||||
|
summary: Return households associated with the given person through accompanying periods
|
||||||
|
description: |
|
||||||
|
Return households associated with the given person throught accompanying periods participation.
|
||||||
|
|
||||||
|
The current household of the given person is excluded.
|
||||||
|
parameters:
|
||||||
|
- name: person_id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The person's id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: integer
|
||||||
|
minimum: 1
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Household'
|
||||||
|
404:
|
||||||
|
description: "not found"
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
|
||||||
/1.0/person/household/members/move.json:
|
/1.0/person/household/members/move.json:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user