mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 14:43:49 +00:00
Merge remote-tracking branch 'origin/master' into issue707_docgen_filter_activity_by_user
This commit is contained in:
@@ -195,7 +195,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\User")
|
||||
* @Groups({"docgen:read"})
|
||||
*/
|
||||
private User $user;
|
||||
private ?User $user;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity="Chill\MainBundle\Entity\User")
|
||||
@@ -494,7 +494,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
return $this->activityType;
|
||||
}
|
||||
|
||||
public function getUser(): User
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
@@ -681,14 +681,14 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUser(UserInterface $user): self
|
||||
public function setUser(?User $user): self
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUsers(?Collection $users): self
|
||||
public function setUsers(Collection $users): self
|
||||
{
|
||||
$this->users = $users;
|
||||
|
||||
|
@@ -20,13 +20,6 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class LocationFilter implements FilterInterface
|
||||
{
|
||||
private TranslatableStringHelper $translatableStringHelper;
|
||||
|
||||
public function __construct(TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
|
@@ -225,6 +225,7 @@ class ActivityType extends AbstractType
|
||||
$builder->add('user', PickUserDynamicType::class, [
|
||||
'label' => $activityType->getLabel('user'),
|
||||
'required' => $activityType->isRequired('user'),
|
||||
'multiple' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -48,7 +48,7 @@ final class PersonMenuBuilder implements LocalMenuBuilderInterface
|
||||
|
||||
if ($this->authorizationChecker->isGranted(ActivityVoter::SEE, $person)) {
|
||||
$menu->addChild(
|
||||
$this->translator->trans('Activity list'),
|
||||
$this->translator->trans('Activities'),
|
||||
[
|
||||
'route' => 'chill_activity_activity_list',
|
||||
'routeParameters' => ['person_id' => $person->getId()],
|
||||
|
@@ -63,7 +63,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if activity.user and t.userVisible %}
|
||||
{% if activity.user is not null and t.userVisible %}
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title"><h3>{{ 'Referrer'|trans }}</h3></div>
|
||||
<div class="wl-col list">
|
||||
|
@@ -5,7 +5,7 @@
|
||||
|
||||
Maybe should we think about abstracting this file a bit more ? Moving it to PersonBundle ?
|
||||
#}
|
||||
{% if context == 'calendar_accompanyingCourse' %}
|
||||
{% if context == 'calendar_accompanyingCourse' or context == 'calendar_person' %}
|
||||
{% import "@ChillCalendar/_invite.html.twig" as invite %}
|
||||
{% endif %}
|
||||
|
||||
|
@@ -34,10 +34,12 @@
|
||||
|
||||
<div class="item-row separator">
|
||||
<dl class="chill_view_data">
|
||||
<dt class="inline">{{ 'Referrer'|trans|capitalize }}</dt>
|
||||
<dd>
|
||||
<span class="badge-user">{{ entity.user|chill_entity_render_box }}</span>
|
||||
</dd>
|
||||
{%- if entity.user is not null %}
|
||||
<dt class="inline">{{ 'Referrer'|trans|capitalize }}</dt>
|
||||
<dd>
|
||||
<span class="badge-user">{{ entity.user|chill_entity_render_box }}</span>
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
||||
{%- if entity.scope -%}
|
||||
<dt class="inline">{{ 'Scope'|trans }}</dt>
|
||||
|
@@ -121,14 +121,14 @@ final class ActivityControllerTest extends WebTestCase
|
||||
$client->getResponse()->getStatusCode(),
|
||||
'Unexpected HTTP status code for GET /activity/'
|
||||
);
|
||||
$crawler = $client->click($crawler->selectLink('Ajouter une nouvelle activité')
|
||||
$crawler = $client->click($crawler->selectLink('Ajouter un nouvel échange')
|
||||
->link());
|
||||
|
||||
$reason1 = $this->getRandomActivityReason();
|
||||
$reason2 = $this->getRandomActivityReason([$reason1->getId()]);
|
||||
|
||||
// Fill in the form and submit it
|
||||
$form = $crawler->selectButton('Ajouter une nouvelle activité')->form([
|
||||
$form = $crawler->selectButton('Ajouter un nouvel échange')->form([
|
||||
'chill_activitybundle_activity' => [
|
||||
'date' => '15-01-2015',
|
||||
'durationTime' => 600,
|
||||
@@ -152,9 +152,9 @@ final class ActivityControllerTest extends WebTestCase
|
||||
);
|
||||
|
||||
// Edit the entity
|
||||
$crawler = $client->click($crawler->selectLink("Modifier l'activité")->link());
|
||||
$crawler = $client->click($crawler->selectLink("Modifier l'échange")->link());
|
||||
|
||||
$form = $crawler->selectButton("Sauver l'activité")->form([
|
||||
$form = $crawler->selectButton("Sauver l'échange")->form([
|
||||
'chill_activitybundle_activity' => [
|
||||
'date' => '25-01-2015',
|
||||
// 'remark' => 'Foo'
|
||||
|
@@ -112,9 +112,9 @@ final class ActivityTypeTest extends KernelTestCase
|
||||
'attendee' => true,
|
||||
]]);
|
||||
|
||||
// var_dump($form->getErrors()->count()); var_dump($form->isValid());
|
||||
// foreach($form->getErrors() as $e) { fwrite(STDOUT, var_dump($e->getMessage())); }
|
||||
// var_dump($form->getErrors());
|
||||
// var_dump($form->getErrors()->count()); var_dump($form->isValid());
|
||||
// foreach($form->getErrors() as $e) { fwrite(STDOUT, var_dump($e->getMessage())); }
|
||||
// var_dump($form->getErrors());
|
||||
|
||||
$this->assertTrue($form->isSynchronized(), 'Test the form is synchronized');
|
||||
$this->assertTrue($form->isValid(), 'test the form is valid');
|
||||
|
@@ -1,41 +1,41 @@
|
||||
#general
|
||||
Show the activity: Voir l'activité
|
||||
Edit the activity: Modifier l'activité
|
||||
Activity: Activité
|
||||
Show the activity: Voir l'échange
|
||||
Edit the activity: Modifier l'échange
|
||||
Activity: Échange
|
||||
Duration time: Durée
|
||||
Duration Time: Durée
|
||||
durationTime: durée
|
||||
Travel time: Durée de déplacement
|
||||
Attendee: Présence de la personne
|
||||
attendee: présence de la personne
|
||||
Attendee: Présence de l'usager
|
||||
attendee: présence de l'usager
|
||||
list_reasons: liste des sujets
|
||||
user_username: nom de l'utilisateur
|
||||
circle_name: nom du cercle
|
||||
Remark: Commentaire
|
||||
No comments: Aucun commentaire
|
||||
Add a new activity: Ajouter une nouvelle activité
|
||||
Activity list: Liste des activités
|
||||
Add a new activity: Ajouter une nouvel échange
|
||||
Activity list: Liste des échanges
|
||||
present: présent
|
||||
not present: absent
|
||||
Delete: Supprimer
|
||||
Update: Mettre à jour
|
||||
Update activity: Modifier l'activité
|
||||
Update activity: Modifier l'échange
|
||||
Scope: Cercle
|
||||
Activity data: Données de l'activité
|
||||
Activity location: Localisation de l'activité
|
||||
Activity data: Données de l'échange
|
||||
Activity location: Localisation de l'échange
|
||||
No reason associated: Aucun sujet
|
||||
No social issues associated: Aucune problématique sociale
|
||||
No social actions associated: Aucune action d'accompagnement
|
||||
There isn't any activities.: Aucune activité enregistrée.
|
||||
type_name: type de l'activité
|
||||
There isn't any activities.: Aucun échange enregistré.
|
||||
type_name: type de l'échange
|
||||
person_firstname: prénom
|
||||
person_lastname: nom de famille
|
||||
person_id: identifiant de la personne
|
||||
person_id: identifiant de l'usager
|
||||
Type: Type
|
||||
Invisible: Invisible
|
||||
Optional: Optionnel
|
||||
Required: Obligatoire
|
||||
Persons: Personnes
|
||||
Persons: Usagers
|
||||
Users: Utilisateurs
|
||||
Emergency: Urgent
|
||||
Sent received: Entrant / Sortant
|
||||
@@ -50,10 +50,10 @@ received: Reçu
|
||||
|
||||
|
||||
#forms
|
||||
Activity creation: Nouvelle activité
|
||||
Activity creation: Nouvel échange
|
||||
Create: Créer
|
||||
Back to the list: Retour à la liste
|
||||
Save activity: Sauver l'activité
|
||||
Save activity: Sauver l'échange
|
||||
Reset form: Remise à zéro du formulaire
|
||||
Choose the duration: Choisir la durée
|
||||
Choose a type: Choisir un type
|
||||
@@ -90,40 +90,40 @@ activity:
|
||||
No documents: Aucun document
|
||||
|
||||
#timeline
|
||||
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'
|
||||
'%user% has done an %activity_type%': '%user% a effectué un échange de type "%activity_type%"'
|
||||
|
||||
#controller
|
||||
'Success : activity created!': L'activité a été créée.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'activité n'a pas été créée.
|
||||
'Success : activity updated!': L'activité a été mise à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'activité n'a pas été mise à jour.
|
||||
'Success : activity created!': L'échange a été créé.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'échange n'a pas été créé.
|
||||
'Success : activity updated!': L'échange a été mis à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'échange n'a pas été mise à jour.
|
||||
|
||||
# ROLES
|
||||
CHILL_ACTIVITY_CREATE: Créer une activité
|
||||
CHILL_ACTIVITY_UPDATE: Modifier une activité
|
||||
CHILL_ACTIVITY_SEE: Voir une activité
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des activités
|
||||
CHILL_ACTIVITY_DELETE: Supprimer une activité
|
||||
CHILL_ACTIVITY_STATS: Statistique des activités
|
||||
CHILL_ACTIVITY_LIST: Liste des activités
|
||||
CHILL_ACTIVITY_CREATE: Créer un échange
|
||||
CHILL_ACTIVITY_UPDATE: Modifier un échange
|
||||
CHILL_ACTIVITY_SEE: Voir un échange
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des échanges
|
||||
CHILL_ACTIVITY_DELETE: Supprimer un échange
|
||||
CHILL_ACTIVITY_STATS: Statistique des échanges
|
||||
CHILL_ACTIVITY_LIST: Liste des échanges
|
||||
|
||||
# admin
|
||||
Activities: Activités
|
||||
Activity configuration: Configuration des activités
|
||||
Activity configuration menu: Configuration des activités
|
||||
Activity types: Types d'activité
|
||||
Activity type configuration: Configuration des categories d'activités
|
||||
Activity Reasons: Sujets d'une activité
|
||||
Activity Reasons Category: Catégories de sujet d'activités
|
||||
Activity Types Categories: Catégories des types d'activité
|
||||
Activity Presences: Presences aux activités
|
||||
Activities: Échanges
|
||||
Activity configuration: Configuration des échanges
|
||||
Activity configuration menu: Configuration des échanges
|
||||
Activity types: Types d'échange
|
||||
Activity type configuration: Configuration des catégories d'échanges
|
||||
Activity Reasons: Sujets d'un échange
|
||||
Activity Reasons Category: Catégories de sujet d'échanges
|
||||
Activity Types Categories: Catégories des types d'échange
|
||||
Activity Presences: Presences aux échanges
|
||||
Associated activity reason category is inactive: La catégorie de sujet attachée est inactive
|
||||
|
||||
|
||||
# Crud
|
||||
crud:
|
||||
activity_type:
|
||||
title_new: Nouveau type d'activité
|
||||
title_new: Nouveau type d'échange
|
||||
title_edit: Edition d'un type d'activité
|
||||
activity_type_category:
|
||||
title_new: Nouvelle catégorie de type d'activité
|
||||
@@ -159,8 +159,8 @@ Create a new activity presence: Créer une nouvelle "Présence aux activités"
|
||||
# activity type type admin
|
||||
ActivityType list: Types d'activités
|
||||
Create a new activity type: Créer un nouveau type d'activité
|
||||
Persons visible: Visibilité du champ Personnes
|
||||
Persons label: Libellé du champ Personnes
|
||||
Persons visible: Visibilité du champ Usagers
|
||||
Persons label: Libellé du champ Usagers
|
||||
User visible: Visibilité du champ Utilisateur
|
||||
User label: Libellé du champ Utilisateur
|
||||
Date visible: Visibilité du champ Date
|
||||
@@ -183,8 +183,8 @@ Private comment visible: Visibilité du champ Commentaire Privé
|
||||
Private comment label: Libellé du champ Commentaire Privé
|
||||
Emergency visible: Visibilité du champ Urgent
|
||||
Emergency label: Libellé du champ Urgent
|
||||
Accompanying period visible: Visibilité du champ Période d'accompagnement
|
||||
Accompanying period label: Libellé du champ Période d'accompagnement
|
||||
Accompanying period visible: Visibilité du champ parcours d'accompagnement
|
||||
Accompanying period label: Libellé du champ parcours d'accompagnement
|
||||
Social issues visible: Visibilité du champ Problématiques sociales
|
||||
Social issues label: Libellé du champ Problématiques sociales
|
||||
Social actions visible: Visibilité du champ Action sociale
|
||||
@@ -206,10 +206,10 @@ Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr d
|
||||
The activity has been successfully removed.: L'activité a été supprimée.
|
||||
|
||||
# exports
|
||||
Exports of activities linked to a person: Exports des activités liées à une personne
|
||||
Number of activities linked to a person: Nombre d'activités liées à une personne
|
||||
Exports of activities linked to a person: Exports des activités liées à un usager
|
||||
Number of activities linked to a person: Nombre d'activités liées à un usager
|
||||
Count activities linked to a person: Nombre d'activités
|
||||
Count activities linked to a person by various parameters.: Compte le nombre d'activités enregistrées et liées à une personne en fonction de différents paramètres.
|
||||
Count activities linked to a person by various parameters.: Compte le nombre d'activités enregistrées et liées à un usager en fonction de différents paramètres.
|
||||
Sum activity linked to a person duration: Durée des activités
|
||||
Sum activities linked to a person duration: Durée des activités liés à un usager
|
||||
Sum activities linked to a person duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
@@ -244,10 +244,10 @@ Activities before this date: Activités avant cette date
|
||||
"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'activité: uniquement entre %date_from% et %date_to%"
|
||||
This date should be after the date given in "Implied in an activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités après cette date"
|
||||
|
||||
Filtered by person having an activity in a period: Uniquement les personnes ayant eu une activité dans la période donnée
|
||||
Filtered by person having an activity in a period: Uniquement les usagers ayant eu une activité dans la période donnée
|
||||
Implied in an activity after this date: Impliqué dans une activité après cette date
|
||||
Implied in an activity before this date: Impliqué dans une activité avant cette date
|
||||
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name%
|
||||
Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par usager associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name%
|
||||
Activity reasons for those activities: Sujets de ces activités
|
||||
|
||||
Filter by activity type: Filtrer les activités par type
|
||||
@@ -338,8 +338,8 @@ export:
|
||||
users name: Nom des utilisateurs
|
||||
users ids: Identifiant des utilisateurs
|
||||
third parties ids: Identifiant des tiers
|
||||
persons ids: Identifiant des personnes
|
||||
persons name: Nom des personnes
|
||||
persons ids: Identifiant des usagers
|
||||
persons name: Nom des usagers
|
||||
thirds parties: Tiers
|
||||
date: Date de l'activité
|
||||
locationName: Localisation
|
||||
|
@@ -47,10 +47,10 @@ Reasons: Onderwerpen
|
||||
|
||||
|
||||
#forms
|
||||
Activity creation: Nouvelle activité
|
||||
Activity creation: Nouvel échange
|
||||
Create: Créer
|
||||
Back to the list: Retour à la liste
|
||||
Save activity: Sauver l'activité
|
||||
Save activity: Sauver l'échange
|
||||
Reset form: Remise à zéro du formulaire
|
||||
Choose the duration: Choisir la durée
|
||||
Choose a type: Choisir un type
|
||||
@@ -79,43 +79,43 @@ activity:
|
||||
No documents: Aucun document
|
||||
|
||||
#timeline
|
||||
'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"'
|
||||
'%user% has done an %activity_type%': '%user% a effectué un échange de type "%activity_type%"'
|
||||
|
||||
#controller
|
||||
'Success : activity created!': L'activité a été créée.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'activité n'a pas été créée.
|
||||
'Success : activity updated!': L'activité a été mise à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'activité n'a pas été mise à jour.
|
||||
'Success : activity created!': L'échange a été créé.
|
||||
'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'échange n'a pas été créé.
|
||||
'Success : activity updated!': L'échange a été mis à jour.
|
||||
'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'échange n'a pas été mis à jour.
|
||||
|
||||
# ROLES
|
||||
CHILL_ACTIVITY_CREATE: Créer une activité
|
||||
CHILL_ACTIVITY_UPDATE: Modifier une activité
|
||||
CHILL_ACTIVITY_SEE: Voir une activité
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des activités
|
||||
CHILL_ACTIVITY_DELETE: Supprimer une activité
|
||||
CHILL_ACTIVITY_STATS: Statistique des activités
|
||||
CHILL_ACTIVITY_LIST: Liste des activités
|
||||
CHILL_ACTIVITY_CREATE: Créer un échange
|
||||
CHILL_ACTIVITY_UPDATE: Modifier un échange
|
||||
CHILL_ACTIVITY_SEE: Voir un échange
|
||||
CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des échanges
|
||||
CHILL_ACTIVITY_DELETE: Supprimer un échange
|
||||
CHILL_ACTIVITY_STATS: Statistique des échanges
|
||||
CHILL_ACTIVITY_LIST: Liste des échanges
|
||||
|
||||
# admin
|
||||
Activities: Activités
|
||||
Activity configuration: Configuration des activités
|
||||
Activity configuration menu: Configuration des activités
|
||||
Activity types: Types d'activité
|
||||
Activity type configuration: Configuration des categories d'activités
|
||||
Activity Reasons: Sujets d'une activité
|
||||
Activity Reasons Category: Catégories de sujet d'activités
|
||||
Activity Types Categories: Catégories des types d'activité
|
||||
Activity Presences: Presences des activités
|
||||
Activities: Échanges
|
||||
Activity configuration: Configuration des échanges
|
||||
Activity configuration menu: Configuration des échanges
|
||||
Activity types: Types d'échange
|
||||
Activity type configuration: Configuration des categories d'échanges
|
||||
Activity Reasons: Sujets d'un échange
|
||||
Activity Reasons Category: Catégories de sujet d'échanges
|
||||
Activity Types Categories: Catégories des types d'échanges
|
||||
Activity Presences: Presences des échanges
|
||||
|
||||
|
||||
# Crud
|
||||
crud:
|
||||
activity_type:
|
||||
title_new: Nouveau type d'activité
|
||||
title_edit: Edition d'un type d'activité
|
||||
title_new: Nouveau type d'échange
|
||||
title_edit: Edition d'un type d'échange
|
||||
activity_type_category:
|
||||
title_new: Nouvelle catégorie de type d'activité
|
||||
title_edit: Edition d'une catégorie de type d'activité
|
||||
title_new: Nouvelle catégorie de type d'échange
|
||||
title_edit: Edition d'une catégorie de type d'échange
|
||||
|
||||
# activity reason admin
|
||||
ActivityReason list: Liste des sujets
|
||||
@@ -124,7 +124,7 @@ Active: Actif
|
||||
Category: Catégorie
|
||||
ActivityReason creation: Nouveau sujet
|
||||
ActivityReason edit: Modification d'un sujet
|
||||
ActivityReason: Sujet d'activité
|
||||
ActivityReason: Sujet d'échange
|
||||
The entity is inactive and won't be proposed: Le sujet est inactif et ne sera pas proposé
|
||||
The entity is active and will be proposed: Le sujet est actif et sera proposé
|
||||
|
||||
@@ -133,13 +133,13 @@ ActivityReasonCategory list: Catégories de sujets
|
||||
Create a new activity category reason: Créer une nouvelle catégorie
|
||||
ActivityReasonCategory creation: Nouvelle catégorie de sujet
|
||||
ActivityReasonCategory edit: Modification d'une catégorie de sujet
|
||||
ActivityReasonCategory: Catégorie de sujet d'activité
|
||||
ActivityReasonCategory: Catégorie de sujet d'échange
|
||||
ActivityReasonCategory is active and will be proposed: La catégorie est active et sera proposée
|
||||
ActivityReasonCategory is inactive and won't be proposed: La catégorie est inactive et ne sera pas proposée
|
||||
|
||||
# activity type type admin
|
||||
ActivityType list: Types d'activités
|
||||
Create a new activity type: Créer un nouveau type d'activité
|
||||
ActivityType list: Types d'échanges
|
||||
Create a new activity type: Créer un nouveau type d'échange
|
||||
Persons visible: Visibilité du champ Personnes
|
||||
Persons label: Libellé du champ Personnes
|
||||
User visible: Visibilité du champ Utilisateur
|
||||
@@ -177,20 +177,20 @@ Documents label: Libellé du champ Documents
|
||||
|
||||
# activity type category admin
|
||||
ActivityTypeCategory list: Liste des catégories des types d'activité
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'activité
|
||||
Create a new activity type category: Créer une nouvelle catégorie de type d'échange
|
||||
|
||||
# activity delete
|
||||
Remove activity: Supprimer une activité
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'activité a été supprimée.
|
||||
Remove activity: Supprimer un échange
|
||||
Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer un échange qui concerne "%name%" ?
|
||||
The activity has been successfully removed.: L'échange a été supprimée.
|
||||
|
||||
# exports
|
||||
Count activities: Nombre d'activités
|
||||
Count activities by various parameters.: Compte le nombre d'activités enregistrées en fonction de différents paramètres.
|
||||
Sum activity duration: Total de la durée des activités
|
||||
Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres.
|
||||
List activities: Liste les activités
|
||||
Number of activities: Nombre d'activités
|
||||
Count activities: Nombre d'échanges
|
||||
Count activities by various parameters.: Compte le nombre d'échanges enregistrées en fonction de différents paramètres.
|
||||
Sum activity duration: Total de la durée des échanges
|
||||
Sum activities duration by various parameters.: Additionne la durée des échanges en fonction de différents paramètres.
|
||||
List activities: Liste les échanges
|
||||
Number of activities: Nombre d'échanges
|
||||
|
||||
#filters
|
||||
Filter by reason: Filtrer par sujet d'activité
|
||||
|
@@ -1,22 +1,22 @@
|
||||
The reasons's level should not be empty: Le niveau du sujet ne peut pas être vide
|
||||
At least one reason must be choosen: Au moins un sujet doit être choisi
|
||||
For this type of activity, you must add at least one person: Pour ce type d'activité, vous devez ajouter au moins un usager
|
||||
For this type of activity, you must add at least one user: Pour ce type d'activité, vous devez ajouter au moins un utilisateur
|
||||
For this type of activity, you must add at least one third party: Pour ce type d'activité, vous devez ajouter au moins un tiers
|
||||
For this type of activity, user is required: Pour ce type d'activité, l'utilisateur est requis
|
||||
For this type of activity, date is required: Pour ce type d'activité, la date est requise
|
||||
For this type of activity, location is required: Pour ce type d'activité, la localisation est requise
|
||||
For this type of activity, attendee is required: Pour ce type d'activité, le champ "Présence de la personne" est requis
|
||||
For this type of activity, duration time is required: Pour ce type d'activité, la durée est requise
|
||||
For this type of activity, travel time is required: Pour ce type d'activité, la durée du trajet est requise
|
||||
For this type of activity, reasons is required: Pour ce type d'activité, le champ "sujet" est requis
|
||||
For this type of activity, comment is required: Pour ce type d'activité, un commentaire est requis
|
||||
For this type of activity, sent/received is required: Pour ce type d'activité, le champ Entrant/Sortant est requis
|
||||
For this type of activity, document is required: Pour ce type d'activité, un document est requis
|
||||
For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" est requis
|
||||
For this type of activity, accompanying period is required: Pour ce type d'activité, le parcours d'accompagnement est requis
|
||||
For this type of activity, you must add at least one social issue: Pour ce type d'activité, vous devez ajouter au moins une problématique sociale
|
||||
For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquer au moins une action sociale
|
||||
For this type of activity, you must add at least one person: Pour ce type d'échange, vous devez ajouter au moins un usager
|
||||
For this type of activity, you must add at least one user: Pour ce type d'échange, vous devez ajouter au moins un utilisateur
|
||||
For this type of activity, you must add at least one third party: Pour ce type d'échange, vous devez ajouter au moins un tiers
|
||||
For this type of activity, user is required: Pour ce type d'échange, l'utilisateur est requis
|
||||
For this type of activity, date is required: Pour ce type d'échange, la date est requise
|
||||
For this type of activity, location is required: Pour ce type d'échange, la localisation est requise
|
||||
For this type of activity, attendee is required: Pour ce type d'échange, le champ "Présence de l'usager" est requis
|
||||
For this type of activity, duration time is required: Pour ce type d'échange, la durée est requise
|
||||
For this type of activity, travel time is required: Pour ce type d'échange, la durée du trajet est requise
|
||||
For this type of activity, reasons is required: Pour ce type d'échange, le champ "sujet" est requis
|
||||
For this type of activity, comment is required: Pour ce type d'échange, un commentaire est requis
|
||||
For this type of activity, sent/received is required: Pour ce type d'échange, le champ Entrant/Sortant est requis
|
||||
For this type of activity, document is required: Pour ce type d'échange, un document est requis
|
||||
For this type of activity, emergency is required: Pour ce type d'échange, le champ "Urgent" est requis
|
||||
For this type of activity, accompanying period is required: Pour ce type d'échange, le parcours d'accompagnement est requis
|
||||
For this type of activity, you must add at least one social issue: Pour ce type d'échange, vous devez ajouter au moins une problématique sociale
|
||||
For this type of activity, you must add at least one social action: Pour ce type d'échange, vous devez indiquer au moins une action sociale
|
||||
|
||||
# admin
|
||||
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
||||
|
@@ -160,8 +160,8 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||
return 'export.aside_activity.main_center';
|
||||
}
|
||||
|
||||
/** @var Center $c */
|
||||
if (null === $value || '' === $value || null === $c = $this->centerRepository->find($value)) {
|
||||
/** @var Center $c */
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -190,10 +190,6 @@ final class ListAsideActivity implements ListInterface, GroupedExportInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param QueryBuilder $query
|
||||
* @param array $data
|
||||
*/
|
||||
public function getResult($query, $data): array
|
||||
{
|
||||
return $query->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
@@ -28,22 +28,17 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
|
||||
use function in_array;
|
||||
|
||||
final class AsideActivityFormType extends AbstractType
|
||||
{
|
||||
private TokenStorageInterface $storage;
|
||||
|
||||
private array $timeChoices;
|
||||
|
||||
public function __construct(
|
||||
ParameterBagInterface $parameterBag,
|
||||
TokenStorageInterface $storage
|
||||
) {
|
||||
$this->timeChoices = $parameterBag->get('chill_aside_activity.form.time_duration');
|
||||
$this->storage = $storage;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
|
@@ -44,17 +44,6 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
||||
'order' => 11,
|
||||
'icons' => ['plus'],
|
||||
]);
|
||||
$menu->addChild($this->translator->trans('Phonecall'), [
|
||||
'route' => 'chill_crud_aside_activity_new',
|
||||
'routeParameters' => [
|
||||
'type' => 1,
|
||||
'duration' => 900,
|
||||
],
|
||||
])
|
||||
->setExtras([
|
||||
'order' => 12,
|
||||
'icons' => ['plus'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -21,7 +21,7 @@ Type: Type
|
||||
Invisible: Invisible
|
||||
Optional: Optionnel
|
||||
Required: Obligatoire
|
||||
Persons: Personnes
|
||||
Persons: Usagers
|
||||
Users: Utilisateurs
|
||||
Emergency: Urgent
|
||||
by: "Par "
|
||||
@@ -50,7 +50,7 @@ For agent: Pour l'utilisateur
|
||||
date: Date
|
||||
Duration: Durée
|
||||
Note: Note
|
||||
Choose the agent for whom this activity is created: Choisissez l'agent pour qui l'activité est créée
|
||||
Choose the agent for whom this activity is created: Choisissez l'agent pour qui l'échange est créé
|
||||
Choose the activity category: Choisir la catégorie
|
||||
|
||||
#Duration
|
||||
|
@@ -33,27 +33,15 @@ class ElementController extends AbstractController
|
||||
{
|
||||
private CalculatorManager $calculator;
|
||||
|
||||
private LoggerInterface $chillMainLogger;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private ResourceRepository $resourceRepository;
|
||||
|
||||
private ChargeRepository $chargeRepository;
|
||||
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
TranslatorInterface $translator,
|
||||
LoggerInterface $chillMainLogger,
|
||||
CalculatorManager $calculator,
|
||||
ResourceRepository $resourceRepository,
|
||||
ChargeRepository $chargeRepository,
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->translator = $translator;
|
||||
$this->chillMainLogger = $chillMainLogger;
|
||||
$this->calculator = $calculator;
|
||||
$this->resourceRepository = $resourceRepository;
|
||||
$this->chargeRepository = $chargeRepository;
|
||||
|
@@ -30,7 +30,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
@@ -38,7 +38,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllActive(): array
|
||||
{
|
||||
@@ -53,7 +53,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array
|
||||
{
|
||||
@@ -64,7 +64,7 @@ final class ChargeKindRepository implements ChargeKindRepositoryInterface
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
*
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
|
@@ -19,25 +19,25 @@ interface ChargeKindRepositoryInterface extends ObjectRepository
|
||||
public function find($id): ?ChargeKind;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllActive(): array;
|
||||
|
||||
/**
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array;
|
||||
|
||||
/**
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return ChargeType[]
|
||||
* @return array<ChargeKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||
|
||||
|
@@ -30,7 +30,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAll(): array
|
||||
{
|
||||
@@ -38,7 +38,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllActive(): array
|
||||
{
|
||||
@@ -58,7 +58,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array
|
||||
{
|
||||
@@ -69,7 +69,7 @@ final class ResourceKindRepository implements ResourceKindRepositoryInterface
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
*
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
|
@@ -19,25 +19,25 @@ interface ResourceKindRepositoryInterface extends ObjectRepository
|
||||
public function find($id): ?ResourceKind;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAll(): array;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllActive(): array;
|
||||
|
||||
/**
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findAllByType(string $type): array;
|
||||
|
||||
/**
|
||||
* @param mixed|null $limit
|
||||
* @param mixed|null $offset
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
*
|
||||
* @return ResourceType[]
|
||||
* @return list<ResourceKind>
|
||||
*/
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array;
|
||||
|
||||
|
@@ -29,7 +29,7 @@ End of validity period: Fin de la période de validité
|
||||
Total: Total
|
||||
Create new resource: Créer une nouvelle ressource
|
||||
Create new charge: Créer une nouvelle charge
|
||||
See person: Voir personne
|
||||
See person: Voir usagers
|
||||
|
||||
There isn't any element recorded: Aucun élément enregistré
|
||||
No resources registered: Aucune ressource enregistrée
|
||||
|
@@ -207,6 +207,7 @@ class CalendarController extends AbstractController
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
'template' => $template->getId(),
|
||||
'returnPath' => $request->getRequestUri(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -377,7 +378,9 @@ class CalendarController extends AbstractController
|
||||
$this->addFlash('success', $this->translator->trans('Success : calendar item created!'));
|
||||
|
||||
if ($form->get('save_and_upload_doc')->isClicked()) {
|
||||
return $this->redirectToRoute('chill_calendar_calendardoc_new', ['id' => $entity->getId()]);
|
||||
return $this->redirectToRoute('chill_calendar_calendardoc_new', [
|
||||
'id' => $entity->getId()
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($templates as $template) {
|
||||
@@ -386,6 +389,7 @@ class CalendarController extends AbstractController
|
||||
'entityClassName' => Calendar::class,
|
||||
'entityId' => $entity->getId(),
|
||||
'template' => $template->getId(),
|
||||
'returnPath' => $this->generateUrl('chill_calendar_calendar_edit', ['id' => $entity->getId()]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -526,14 +530,20 @@ class CalendarController extends AbstractController
|
||||
'comment' => $calendar->getComment()->getComment(),
|
||||
];
|
||||
|
||||
return $this->redirectToRoute(
|
||||
'chill_activity_activity_new',
|
||||
[
|
||||
'accompanying_period_id' => $calendar->getAccompanyingPeriod()->getId(),
|
||||
'activityData' => $activityData,
|
||||
'returnPath' => $request->query->get('returnPath', null),
|
||||
]
|
||||
);
|
||||
$routeParams = [
|
||||
'activityData' => $activityData,
|
||||
'returnPath' => $request->query->get('returnPath', null),
|
||||
];
|
||||
|
||||
if ($calendar->getContext() === 'accompanying_period') {
|
||||
$routeParams['accompanying_period_id'] = $calendar->getAccompanyingPeriod()->getId();
|
||||
} elseif ($calendar->getContext() === 'person') {
|
||||
$routeParams['person_id'] = $calendar->getPerson()->getId();
|
||||
} else {
|
||||
throw new RuntimeException('context not found for this calendar');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('chill_activity_activity_new', $routeParams);
|
||||
}
|
||||
|
||||
private function buildListFilterOrder(): FilterOrderHelper
|
||||
@@ -544,21 +554,6 @@ class CalendarController extends AbstractController
|
||||
return $filterOrder->build();
|
||||
}
|
||||
|
||||
private function buildParamsToUrl(?User $user, ?AccompanyingPeriod $accompanyingPeriod): array
|
||||
{
|
||||
$params = [];
|
||||
|
||||
if (null !== $user) {
|
||||
$params['user_id'] = $user->getId();
|
||||
}
|
||||
|
||||
if (null !== $accompanyingPeriod) {
|
||||
$params['id'] = $accompanyingPeriod->getId();
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form to delete a Calendar entity by id.
|
||||
*/
|
||||
|
@@ -29,6 +29,7 @@ use DateTimeImmutable;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\Common\Collections\ReadableCollection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use LogicException;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
@@ -92,6 +93,7 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\PersonBundle\Entity\AccompanyingPeriod", inversedBy="calendars")
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
private ?AccompanyingPeriod $accompanyingPeriod = null;
|
||||
|
||||
@@ -507,10 +509,10 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface, HasCente
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|User[]
|
||||
* @return ReadableCollection<(int|string), User>
|
||||
* @Serializer\Groups({"calendar:read", "read"})
|
||||
*/
|
||||
public function getUsers(): Collection
|
||||
public function getUsers(): ReadableCollection
|
||||
{
|
||||
return $this->getInvites()->map(static function (Invite $i) {
|
||||
return $i->getUser();
|
||||
|
@@ -52,7 +52,7 @@ class CountCalendars implements ExportInterface, GroupedExportInterface
|
||||
return 'Exports of calendar';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): Closure
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_result' !== $key) {
|
||||
throw new LogicException("the key {$key} is not used by this export");
|
||||
|
@@ -26,9 +26,6 @@ class CalendarDocEditType extends AbstractType
|
||||
->add('title', TextType::class, [
|
||||
'label' => 'chill_calendar.Document title',
|
||||
'required' => true,
|
||||
])
|
||||
->add('doc', StoredObjectType::class, [
|
||||
'label' => 'chill_calendar.Document object',
|
||||
]);
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
:picked="null !== this.$store.getters.getMainUser ? [this.$store.getters.getMainUser] : []"
|
||||
:removableIfSet="false"
|
||||
:displayPicked="false"
|
||||
:suggested="this.suggestedUsers"
|
||||
@addNewEntity="setMainUser"
|
||||
></pick-entity>
|
||||
</div>
|
||||
@@ -143,6 +144,7 @@ export default {
|
||||
slotMinTime: '09:00:00',
|
||||
slotMaxTime: '18:00:00',
|
||||
hideWeekEnds: true,
|
||||
previousUser: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -188,11 +190,23 @@ export default {
|
||||
users.push(this.$store.getters.getUserDataById(id).user);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
},
|
||||
suggestedUsers() {
|
||||
const suggested = [];
|
||||
|
||||
this.$data.previousUser.forEach(u => {
|
||||
if (u.id !== this.$store.getters.getMainUser.id) {
|
||||
suggested.push(u)
|
||||
}
|
||||
});
|
||||
|
||||
return suggested;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setMainUser(user) {
|
||||
console.log('setMainUser APP', user);
|
||||
setMainUser({entity}) {
|
||||
const user = entity;
|
||||
console.log('setMainUser APP', entity);
|
||||
|
||||
if (user.id !== this.$store.getters.getMainUser && (
|
||||
this.$store.state.activity.calendarRange !== null
|
||||
@@ -205,6 +219,14 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// add the previous user, if any, in the previous user list (in use for suggestion)
|
||||
if (null !== this.$store.getters.getMainUser) {
|
||||
const suggestedUids = new Set(this.$data.previousUser.map(u => u.id));
|
||||
if (!suggestedUids.has(this.$store.getters.getMainUser.id)){
|
||||
this.$data.previousUser.push(this.$store.getters.getMainUser);
|
||||
}
|
||||
}
|
||||
|
||||
this.$store.dispatch('setMainUser', user);
|
||||
this.$store.commit('showUserOnCalendar', {user, ranges: true, remotes: true});
|
||||
},
|
||||
|
@@ -202,6 +202,8 @@ export default {
|
||||
|
||||
return dispatch('associateCalendarToRange', { range: null }).then(() => {
|
||||
commit('setMainUser', mainUser);
|
||||
|
||||
return dispatch('fetchCalendarEvents');
|
||||
});
|
||||
},
|
||||
|
||||
|
@@ -54,7 +54,7 @@ export const mapEntity = (entity: EventInput): EventInput => {
|
||||
|
||||
export const createUserData = (user: User, colorIndex: number): UserData => {
|
||||
const colorId = colorIndex % COLORS.length;
|
||||
console.log('colorId', colorId);
|
||||
|
||||
return {
|
||||
user: user,
|
||||
calendarRanges: [],
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<label class="form-label">Lieu des plages de disponibilités créées</label>
|
||||
<label class="form-label">{{ $t('created_availabilities') }}</label>
|
||||
<vue-multiselect
|
||||
v-model="pickedLocation"
|
||||
:options="locations"
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const appMessages = {
|
||||
fr: {
|
||||
created_availabilities: "Lieu des plages de disponibilités créées",
|
||||
edit_your_calendar_range: "Planifiez vos plages de disponibilités",
|
||||
show_my_calendar: "Afficher mon calendrier",
|
||||
show_weekends: "Afficher les week-ends",
|
||||
|
@@ -20,15 +20,24 @@
|
||||
<div class="row">
|
||||
<div class="col text-start">
|
||||
{{ d.storedObject.title }}
|
||||
{% if d.dateTimeVersion < d.calendar.dateTimeVersion %}
|
||||
</div>
|
||||
{% if d.dateTimeVersion < d.calendar.dateTimeVersion %}
|
||||
<div class="col text-start">
|
||||
<span class="badge bg-danger">{{ 'chill_calendar.Document outdated'|trans }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-auto text-center">
|
||||
{{ mm.mimeIcon(d.storedObject.type) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col col-lg-4 text-end">
|
||||
{{ d.storedObject|chill_document_button_group(d.storedObject.title, is_granted('CHILL_CALENDAR_DOC_EDIT', d), {'small': true}) }}
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
{{ d.storedObject|chill_document_button_group(d.storedObject.title, is_granted('CHILL_CALENDAR_DOC_EDIT', d), {'small': true}) }}
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendardoc_edit', {id: d.id}) }}" class="btn btn-sm btn-edit"></a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendardoc_delete', {id: d.id}) }}" class="btn btn-sm btn-delete"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
|
@@ -110,7 +110,46 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item-row">
|
||||
{% if calendar.activity is not null %}
|
||||
<div class="item-row separator">
|
||||
<div class="item-col">
|
||||
<div class="wrap-list">
|
||||
<div class="wl-row">
|
||||
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
||||
<div class="wl-col list activity-linked">
|
||||
<h2 class="badge-title">
|
||||
<span class="title_label"></span>
|
||||
<span class="title_action">
|
||||
{{ calendar.activity.type.name | localize_translatable_string }}
|
||||
|
||||
{% if calendar.activity.emergency %}
|
||||
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li class="cancel">
|
||||
<span class="createdBy">
|
||||
{{ 'Created by'|trans }}
|
||||
<b>{{ calendar.activity.createdBy|chill_entity_render_string }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
||||
</span>
|
||||
</li>
|
||||
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
||||
<li>
|
||||
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="item-row separator">
|
||||
<ul class="record_actions">
|
||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_SEE', calendar) %}
|
||||
{% if templates|length == 0 %}
|
||||
@@ -147,7 +186,12 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if accompanyingCourse is defined and is_granted('CHILL_ACTIVITY_CREATE', accompanyingCourse) and calendar.activity is null %}
|
||||
{% if calendar.activity is null and (
|
||||
(calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod))
|
||||
or
|
||||
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
||||
)
|
||||
%}
|
||||
<li>
|
||||
<a class="btn btn-create"
|
||||
href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}">
|
||||
|
@@ -9,13 +9,13 @@
|
||||
{% block js %}
|
||||
{{ parent() }}
|
||||
{{ encore_entry_script_tags('mod_answer') }}
|
||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
{{ parent() }}
|
||||
{{ encore_entry_link_tags('mod_answer') }}
|
||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@@ -24,7 +24,6 @@
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.doc) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
|
@@ -23,7 +23,6 @@
|
||||
{{ form_start(form) }}
|
||||
|
||||
{{ form_row(form.title) }}
|
||||
{{ form_row(form.doc) }}
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
|
@@ -28,7 +28,7 @@
|
||||
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li class="cancel">
|
||||
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_calendar_calendar_list_by_accompanying_period', {'id': accompanyingCourse.id }) }}">{{ 'Cancel'|trans|chill_return_path_label }}</a>
|
||||
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_calendar_calendar_edit', {'id': calendar_doc.calendar.id }) }}">{{ 'Cancel'|trans|chill_return_path_label }}</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
|
@@ -132,8 +132,8 @@ docgen:
|
||||
Base context for calendar: 'Rendez-vous: contexte de base'
|
||||
A base context for generating document on calendar: Contexte pour générer des documents à partir des rendez-vous
|
||||
Track changes on datetime and warn user if date time is updated after the doc generation: Suivre les changements sur le document et prévenir les utilisateurs que la date et l'heure ont été modifiée après la génération du document
|
||||
Ask main person: Demander de choisir une personne parmi les participants aux rendez-vous
|
||||
Main person label: Label pour choisir la personne
|
||||
Ask main person: Demander de choisir un usager parmi les participants aux rendez-vous
|
||||
Main person label: Label pour choisir l'usager
|
||||
Ask third party: Demander de choisir un tiers parmi les participants aux rendez-vous
|
||||
Third party label: Label pour choisir le tiers
|
||||
Destinee: Destinataire
|
||||
|
@@ -1,5 +1,5 @@
|
||||
calendar:
|
||||
At least {{ limit }} person is required.: Au moins {{ limit }} personne doit être associée à ce rendez-vous
|
||||
At least {{ limit }} person is required.: Au moins {{ limit }} usager doit être associée à ce rendez-vous
|
||||
An end date is required: Indiquez une date et heure de fin
|
||||
A start date is required: Indiquez une date et heure de début
|
||||
A location is required: Indiquez un lieu
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\DocStoreBundle\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\HasCentersInterface;
|
||||
use Chill\MainBundle\Entity\HasScopesInterface;
|
||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
@@ -19,7 +20,7 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
* @ORM\Entity
|
||||
* @ORM\Table("chill_doc.accompanyingcourse_document")
|
||||
*/
|
||||
class AccompanyingCourseDocument extends Document implements HasScopesInterface
|
||||
class AccompanyingCourseDocument extends Document implements HasScopesInterface, HasCentersInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||
@@ -27,6 +28,11 @@ class AccompanyingCourseDocument extends Document implements HasScopesInterface
|
||||
*/
|
||||
private ?AccompanyingPeriod $course = null;
|
||||
|
||||
public function getCenters(): ?iterable
|
||||
{
|
||||
return $this->course->getCenters();
|
||||
}
|
||||
|
||||
public function getCourse(): ?AccompanyingPeriod
|
||||
{
|
||||
return $this->course;
|
||||
|
@@ -51,16 +51,9 @@
|
||||
</div>
|
||||
<ul class="item-col record_actions flex-shrink-1">
|
||||
{% if document.course is defined %}
|
||||
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
|
||||
<li class="delete">
|
||||
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
|
||||
<li>
|
||||
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
{{ chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) }}
|
||||
</li>
|
||||
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
|
||||
<li>
|
||||
{{ document.object|chill_document_button_group(document.title, is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document)) }}
|
||||
@@ -69,20 +62,17 @@
|
||||
<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
{{ chill_entity_workflow_list('Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument', document.id) }}
|
||||
</li>
|
||||
{% else %}
|
||||
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
|
||||
<li class="delete">
|
||||
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
|
||||
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
|
||||
<li>
|
||||
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
|
||||
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
|
||||
<li class="delete">
|
||||
<a href="{{ chill_return_path_or('chill_docstore_accompanying_course_document_delete', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-delete"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
|
||||
<li>
|
||||
{{ document.object|chill_document_button_group(document.title, is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document)) }}
|
||||
@@ -91,6 +81,16 @@
|
||||
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
|
||||
<li>
|
||||
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if is_granted('CHILL_PERSON_DOCUMENT_DELETE', document) %}
|
||||
<li class="delete">
|
||||
<a href="{{ chill_return_path_or('chill_docstore_person_document_delete', {'person': person.id, 'id': document.id}) }}" class="btn btn-delete"></a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
|
@@ -78,12 +78,12 @@ class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements Prov
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function supports($attribute, $subject)
|
||||
protected function supports($attribute, $subject): bool
|
||||
{
|
||||
return $this->voterHelper->supports($attribute, $subject);
|
||||
}
|
||||
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
|
||||
{
|
||||
if (!$token->getUser() instanceof User) {
|
||||
return false;
|
||||
|
@@ -113,27 +113,23 @@ class EventSearch extends AbstractSearch
|
||||
]
|
||||
);
|
||||
}
|
||||
// format is "json"
|
||||
$results = [];
|
||||
$search = $this->search($terms, $start, $limit, $options);
|
||||
|
||||
if ('json' === $format) {
|
||||
$results = [];
|
||||
$search = $this->search($terms, $start, $limit, $options);
|
||||
|
||||
foreach ($search as $item) {
|
||||
$results[] = [
|
||||
'id' => $item->getId(),
|
||||
'text' => $item->getDate()->format('d/m/Y, H:i') . ' → ' .
|
||||
// $item->getType()->getName()['fr'] . ': ' . // display the type of event
|
||||
$item->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'results' => $results,
|
||||
'pagination' => [
|
||||
'more' => $paginator->hasNextPage(),
|
||||
],
|
||||
foreach ($search as $item) {
|
||||
$results[] = [
|
||||
'id' => $item->getId(),
|
||||
'text' => $item->getDate()->format('d/m/Y, H:i') . ' → ' .
|
||||
// $item->getType()->getName()['fr'] . ': ' . // display the type of event
|
||||
$item->getName(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'results' => $results,
|
||||
'more' => $paginator->hasNextPage(),
|
||||
];
|
||||
}
|
||||
|
||||
public function supports($domain, $format)
|
||||
|
@@ -34,7 +34,7 @@ Edit the participation: Modifier la participation
|
||||
Participation Edit: Modifier une participation
|
||||
Add a participation: Ajouter un participant
|
||||
Participation creation: Ajouter une participation
|
||||
Associated person: Personne associée
|
||||
Associated person: Usager associé
|
||||
Associated event: Événement associé
|
||||
Back to the event: Retour à l'événement
|
||||
The participation was created: La participation a été créée
|
||||
@@ -108,4 +108,4 @@ csv: csv
|
||||
|
||||
Create a new role: Créer un nouveau rôle
|
||||
Create a new type: Créer un nouveau type
|
||||
Create a new status: Créer un nouveau statut
|
||||
Create a new status: Créer un nouveau statut
|
||||
|
@@ -101,7 +101,7 @@ class CRUDRoutesLoader extends Loader
|
||||
$singleCollection = $action['single_collection'] ?? '_entity' === $name ? 'single' : null;
|
||||
|
||||
if ('collection' === $singleCollection) {
|
||||
// continue;
|
||||
// continue;
|
||||
}
|
||||
|
||||
// compute default action
|
||||
|
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
class AddressToReferenceMatcherController
|
||||
{
|
||||
private Security $security;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private SerializerInterface $serializer;
|
||||
|
||||
public function __construct(
|
||||
Security $security,
|
||||
EntityManagerInterface $entityManager,
|
||||
SerializerInterface $serializer
|
||||
) {
|
||||
$this->security = $security;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/api/1.0/main/address/reference-match/{id}/set/reviewed", methods={"POST"})
|
||||
*/
|
||||
public function markAddressAsReviewed(Address $address): JsonResponse
|
||||
{
|
||||
if (!$this->security->isGranted('ROLE_USER')) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
$address->setRefStatus(Address::ADDR_REFERENCE_STATUS_REVIEWED);
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new JsonResponse(
|
||||
$this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]),
|
||||
JsonResponse::HTTP_OK,
|
||||
[],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an address back to "to review". Only if the address is in "reviewed" state.
|
||||
*
|
||||
* @Route("/api/1.0/main/address/reference-match/{id}/set/to_review", methods={"POST"})
|
||||
*/
|
||||
public function markAddressAsToReview(Address $address): JsonResponse
|
||||
{
|
||||
if (!$this->security->isGranted('ROLE_USER')) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
if (Address::ADDR_REFERENCE_STATUS_REVIEWED !== $address->getRefStatus()) {
|
||||
throw new AccessDeniedHttpException("forbidden to mark a matching address to 'to review'");
|
||||
}
|
||||
|
||||
$address->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW);
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new JsonResponse(
|
||||
$this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]),
|
||||
JsonResponse::HTTP_OK,
|
||||
[],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/api/1.0/main/address/reference-match/{id}/sync-with-reference", methods={"POST"})
|
||||
*/
|
||||
public function syncAddressWithReference(Address $address): JsonResponse
|
||||
{
|
||||
if (null === $address->getAddressReference()) {
|
||||
throw new BadRequestHttpException('this address does not have any address reference');
|
||||
}
|
||||
|
||||
$address->syncWithReference($address->getAddressReference());
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new JsonResponse(
|
||||
$this->serializer->serialize($address, 'json', [AbstractNormalizer::GROUPS => ['read']]),
|
||||
JsonResponse::HTTP_OK,
|
||||
[],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Repository\GeographicalUnitRepositoryInterface;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
class GeographicalUnitByAddressApiController
|
||||
{
|
||||
private PaginatorFactory $paginatorFactory;
|
||||
|
||||
private GeographicalUnitRepositoryInterface $geographicalUnitRepository;
|
||||
|
||||
private Security $security;
|
||||
|
||||
private SerializerInterface $serializer;
|
||||
|
||||
/**
|
||||
* @param PaginatorFactory $paginatorFactory
|
||||
* @param GeographicalUnitRepositoryInterface $geographicalUnitRepository
|
||||
* @param Security $security
|
||||
* @param SerializerInterface $serializer
|
||||
*/
|
||||
public function __construct(
|
||||
PaginatorFactory $paginatorFactory,
|
||||
GeographicalUnitRepositoryInterface $geographicalUnitRepository,
|
||||
Security $security,
|
||||
SerializerInterface $serializer
|
||||
) {
|
||||
$this->paginatorFactory = $paginatorFactory;
|
||||
$this->geographicalUnitRepository = $geographicalUnitRepository;
|
||||
$this->security = $security;
|
||||
$this->serializer = $serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/api/1.0/main/geographical-unit/by-address/{id}.{_format}", requirements={"_format": "json"})
|
||||
*/
|
||||
public function getGeographicalUnitCoveringAddress(Address $address): JsonResponse
|
||||
{
|
||||
if (!$this->security->isGranted('ROLE_USER')) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
$count = $this->geographicalUnitRepository->countGeographicalUnitContainingAddress($address);
|
||||
$pagination = $this->paginatorFactory->create($count);
|
||||
$units = $this->geographicalUnitRepository->findGeographicalUnitContainingAddress($address, $pagination->getCurrentPageFirstItemNumber(), $pagination->getItemsPerPage());
|
||||
|
||||
$collection = new Collection($units, $pagination);
|
||||
|
||||
return new JsonResponse(
|
||||
$this->serializer->serialize($collection, 'json', [AbstractNormalizer::GROUPS => ['read']]),
|
||||
JsonResponse::HTTP_OK,
|
||||
[],
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
@@ -46,6 +46,7 @@ use Chill\MainBundle\Doctrine\Type\NativeDateIntervalType;
|
||||
use Chill\MainBundle\Doctrine\Type\PointType;
|
||||
use Chill\MainBundle\Entity\Civility;
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Chill\MainBundle\Entity\GeographicalUnitLayer;
|
||||
use Chill\MainBundle\Entity\Language;
|
||||
use Chill\MainBundle\Entity\Location;
|
||||
use Chill\MainBundle\Entity\LocationType;
|
||||
@@ -732,6 +733,20 @@ class ChillMainExtension extends Extension implements
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'class' => GeographicalUnitLayer::class,
|
||||
'name' => 'geographical-unit-layer',
|
||||
'base_path' => '/api/1.0/main/geographical-unit-layer',
|
||||
'base_role' => 'ROLE_USER',
|
||||
'actions' => [
|
||||
'_index' => [
|
||||
'methods' => [
|
||||
Request::METHOD_GET => true,
|
||||
Request::METHOD_HEAD => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
@@ -211,7 +211,7 @@ trait AddWidgetConfigurationTrait
|
||||
*
|
||||
* @throws InvalidConfigurationException if a service's tag does not have the "alias" key
|
||||
*
|
||||
* @return type
|
||||
* @return array
|
||||
*/
|
||||
protected function getWidgetAliasesbyPlace($place, ContainerBuilder $containerBuilder)
|
||||
{
|
||||
|
@@ -31,9 +31,6 @@ class NativeDateIntervalType extends DateIntervalType
|
||||
{
|
||||
public const FORMAT = '%rP%YY%MM%DDT%HH%IM%SS';
|
||||
|
||||
/**
|
||||
* @param DateInterval|null $value
|
||||
*/
|
||||
public function convertToDatabaseValue($value, AbstractPlatform $platform)
|
||||
{
|
||||
if (null === $value) {
|
||||
|
@@ -12,6 +12,10 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Entity;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
||||
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
|
||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
@@ -28,8 +32,28 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
* @ORM\Table(name="chill_main_address")
|
||||
* @ORM\HasLifecycleCallbacks
|
||||
*/
|
||||
class Address
|
||||
class Address implements TrackCreationInterface, TrackUpdateInterface
|
||||
{
|
||||
use TrackCreationTrait;
|
||||
use TrackUpdateTrait;
|
||||
|
||||
/**
|
||||
* When an Address does match with the AddressReference
|
||||
*/
|
||||
public const ADDR_REFERENCE_STATUS_MATCH = 'match';
|
||||
|
||||
/**
|
||||
* When an Address does not match with the AddressReference, and
|
||||
* is pending for a review
|
||||
*/
|
||||
public const ADDR_REFERENCE_STATUS_TO_REVIEW = 'to_review';
|
||||
|
||||
/**
|
||||
* When an Address does not match with the AddressReference, but
|
||||
* is reviewed
|
||||
*/
|
||||
public const ADDR_REFERENCE_STATUS_REVIEWED = 'reviewed';
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=AddressReference::class)
|
||||
* @Groups({"write"})
|
||||
@@ -37,67 +61,48 @@ class Address
|
||||
private ?AddressReference $addressReference = null;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $buildingName;
|
||||
private string $buildingName = '';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="boolean")
|
||||
* @ORM\Column(type="boolean", options={"default": false})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private bool $confidential = false;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $corridor;
|
||||
private string $corridor = '';
|
||||
|
||||
/**
|
||||
* A list of metadata, added by customizable fields.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $customs = [];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* used for the CEDEX information
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $distribution;
|
||||
private string $distribution = '';
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $extra;
|
||||
private string $extra = '';
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $flat;
|
||||
private string $flat = '';
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $floor;
|
||||
private string $floor = '';
|
||||
|
||||
/**
|
||||
* List of geographical units and addresses.
|
||||
@@ -131,11 +136,9 @@ class Address
|
||||
* True if the address is a "no address", aka homeless person, ...
|
||||
*
|
||||
* @Groups({"write"})
|
||||
* @ORM\Column(type="boolean")
|
||||
*
|
||||
* @var bool
|
||||
* @ORM\Column(type="boolean", options={"default": false})
|
||||
*/
|
||||
private $isNoAddress = false;
|
||||
private bool $isNoAddress = false;
|
||||
|
||||
/**
|
||||
* A ThirdParty reference for person's addresses that are linked to a third party.
|
||||
@@ -146,7 +149,7 @@ class Address
|
||||
* @Groups({"write"})
|
||||
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
|
||||
*/
|
||||
private $linkedToThirdParty;
|
||||
private ?ThirdParty $linkedToThirdParty;
|
||||
|
||||
/**
|
||||
* A geospatial field storing the coordinates of the Address.
|
||||
@@ -156,7 +159,7 @@ class Address
|
||||
* @ORM\Column(type="point", nullable=true)
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $point;
|
||||
private ?Point $point = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
|
||||
@@ -166,28 +169,36 @@ class Address
|
||||
private ?PostalCode $postcode = null;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @Groups({"write"})
|
||||
* @var self::ADDR_REFERENCE_STATUS_*
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": self::ADDR_REFERENCE_STATUS_MATCH})
|
||||
*/
|
||||
private $steps;
|
||||
private string $refStatus = self::ADDR_REFERENCE_STATUS_MATCH;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", length=255)
|
||||
* @Groups({"write"})
|
||||
* @ORM\Column(type="datetime_immutable", nullable=false, options={"default": "CURRENT_TIMESTAMP"})
|
||||
*/
|
||||
private $street = '';
|
||||
private \DateTimeImmutable $refStatusLastUpdate;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(type="string", length=255)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private $streetNumber = '';
|
||||
private string $steps = '';
|
||||
|
||||
/**
|
||||
*
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private string $street = '';
|
||||
|
||||
/**
|
||||
*
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private string $streetNumber = '';
|
||||
|
||||
/**
|
||||
* Indicates when the address starts validation. Used to build an history
|
||||
@@ -210,6 +221,7 @@ class Address
|
||||
public function __construct()
|
||||
{
|
||||
$this->validFrom = new DateTime();
|
||||
$this->refStatusLastUpdate = new \DateTimeImmutable('now');
|
||||
$this->geographicalUnits = new ArrayCollection();
|
||||
}
|
||||
|
||||
@@ -220,7 +232,6 @@ class Address
|
||||
->setBuildingName($original->getBuildingName())
|
||||
->setConfidential($original->getConfidential())
|
||||
->setCorridor($original->getCorridor())
|
||||
->setCustoms($original->getCustoms())
|
||||
->setDistribution($original->getDistribution())
|
||||
->setExtra($original->getExtra())
|
||||
->setFlat($original->getFlat())
|
||||
@@ -239,11 +250,20 @@ class Address
|
||||
public static function createFromAddressReference(AddressReference $original): Address
|
||||
{
|
||||
return (new Address())
|
||||
->setPoint($original->getPoint())
|
||||
->setPostcode($original->getPostcode())
|
||||
->setStreet($original->getStreet())
|
||||
->setStreetNumber($original->getStreetNumber())
|
||||
->setAddressReference($original);
|
||||
->syncWithReference($original);
|
||||
}
|
||||
|
||||
public function syncWithReference(AddressReference $addressReference): Address
|
||||
{
|
||||
$this
|
||||
->setPoint($addressReference->getPoint())
|
||||
->setPostcode($addressReference->getPostcode())
|
||||
->setStreet($addressReference->getStreet())
|
||||
->setStreetNumber($addressReference->getStreetNumber())
|
||||
->setRefStatus(self::ADDR_REFERENCE_STATUS_MATCH)
|
||||
->setAddressReference($addressReference);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAddressReference(): ?AddressReference
|
||||
@@ -251,7 +271,7 @@ class Address
|
||||
return $this->addressReference;
|
||||
}
|
||||
|
||||
public function getBuildingName(): ?string
|
||||
public function getBuildingName(): string
|
||||
{
|
||||
return $this->buildingName;
|
||||
}
|
||||
@@ -261,35 +281,27 @@ class Address
|
||||
return $this->confidential;
|
||||
}
|
||||
|
||||
public function getCorridor(): ?string
|
||||
public function getCorridor(): string
|
||||
{
|
||||
return $this->corridor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get customs informations in the address.
|
||||
*/
|
||||
public function getCustoms(): array
|
||||
{
|
||||
return $this->customs;
|
||||
}
|
||||
|
||||
public function getDistribution(): ?string
|
||||
public function getDistribution(): string
|
||||
{
|
||||
return $this->distribution;
|
||||
}
|
||||
|
||||
public function getExtra(): ?string
|
||||
public function getExtra(): string
|
||||
{
|
||||
return $this->extra;
|
||||
}
|
||||
|
||||
public function getFlat(): ?string
|
||||
public function getFlat(): string
|
||||
{
|
||||
return $this->flat;
|
||||
}
|
||||
|
||||
public function getFloor(): ?string
|
||||
public function getFloor(): string
|
||||
{
|
||||
return $this->floor;
|
||||
}
|
||||
@@ -340,12 +352,22 @@ class Address
|
||||
return $this->postcode;
|
||||
}
|
||||
|
||||
public function getSteps(): ?string
|
||||
public function getRefStatus(): string
|
||||
{
|
||||
return $this->refStatus;
|
||||
}
|
||||
|
||||
public function getRefStatusLastUpdate(): \DateTimeImmutable
|
||||
{
|
||||
return $this->refStatusLastUpdate;
|
||||
}
|
||||
|
||||
public function getSteps(): string
|
||||
{
|
||||
return $this->steps;
|
||||
}
|
||||
|
||||
public function getStreet(): ?string
|
||||
public function getStreet(): string
|
||||
{
|
||||
return $this->street;
|
||||
}
|
||||
@@ -354,6 +376,7 @@ class Address
|
||||
* Get streetAddress1 (legacy function).
|
||||
*
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function getStreetAddress1()
|
||||
{
|
||||
@@ -364,13 +387,14 @@ class Address
|
||||
* Get streetAddress2 (legacy function).
|
||||
*
|
||||
* @return string
|
||||
* @deprecated
|
||||
*/
|
||||
public function getStreetAddress2()
|
||||
{
|
||||
return $this->streetNumber;
|
||||
}
|
||||
|
||||
public function getStreetNumber(): ?string
|
||||
public function getStreetNumber(): string
|
||||
{
|
||||
return $this->streetNumber;
|
||||
}
|
||||
@@ -378,7 +402,7 @@ class Address
|
||||
/**
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getValidFrom()
|
||||
public function getValidFrom(): DateTime
|
||||
{
|
||||
return $this->validFrom;
|
||||
}
|
||||
@@ -407,7 +431,7 @@ class Address
|
||||
|
||||
public function setBuildingName(?string $buildingName): self
|
||||
{
|
||||
$this->buildingName = $buildingName;
|
||||
$this->buildingName = (string) $buildingName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -421,47 +445,35 @@ class Address
|
||||
|
||||
public function setCorridor(?string $corridor): self
|
||||
{
|
||||
$this->corridor = $corridor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store custom informations in the address.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCustoms(array $customs): self
|
||||
{
|
||||
$this->customs = $customs;
|
||||
$this->corridor = (string) $corridor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDistribution(?string $distribution): self
|
||||
{
|
||||
$this->distribution = $distribution;
|
||||
$this->distribution = (string) $distribution;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setExtra(?string $extra): self
|
||||
{
|
||||
$this->extra = $extra;
|
||||
$this->extra = (string) $extra;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFlat(?string $flat): self
|
||||
{
|
||||
$this->flat = $flat;
|
||||
$this->flat = (string) $flat;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFloor(?string $floor): self
|
||||
{
|
||||
$this->floor = $floor;
|
||||
$this->floor = (string) $floor;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -508,19 +520,44 @@ class Address
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the ref status
|
||||
*
|
||||
* <<<<<<< HEAD
|
||||
* @param Address::ADDR_REFERENCE_STATUS_* $refStatus
|
||||
* @param bool|null $updateLastUpdate Also update the "refStatusLastUpdate"
|
||||
* =======
|
||||
* The refstatuslast update is also updated
|
||||
* >>>>>>> 31152616d (Feature: Provide api endpoint for reviewing addresses)
|
||||
*/
|
||||
public function setRefStatus(string $refStatus, ?bool $updateLastUpdate = true): self
|
||||
{
|
||||
$this->refStatus = $refStatus;
|
||||
|
||||
if ($updateLastUpdate) {
|
||||
$this->setRefStatusLastUpdate(new \DateTimeImmutable('now'));
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setRefStatusLastUpdate(\DateTimeImmutable $refStatusLastUpdate): self
|
||||
{
|
||||
$this->refStatusLastUpdate = $refStatusLastUpdate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSteps(?string $steps): self
|
||||
{
|
||||
$this->steps = $steps;
|
||||
$this->steps = (string) $steps;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStreet(?string $street): self
|
||||
{
|
||||
if (null === $street) {
|
||||
$street = '';
|
||||
}
|
||||
$this->street = $street;
|
||||
$this->street = (string) $street;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -531,6 +568,7 @@ class Address
|
||||
* @param string $streetAddress1
|
||||
*
|
||||
* @return Address
|
||||
* @deprecated
|
||||
*/
|
||||
public function setStreetAddress1($streetAddress1)
|
||||
{
|
||||
@@ -543,7 +581,7 @@ class Address
|
||||
* Set streetAddress2 (legacy function).
|
||||
*
|
||||
* @param string $streetAddress2
|
||||
*
|
||||
* @deprecated
|
||||
* @return Address
|
||||
*/
|
||||
public function setStreetAddress2($streetAddress2)
|
||||
@@ -555,10 +593,7 @@ class Address
|
||||
|
||||
public function setStreetNumber(?string $streetNumber): self
|
||||
{
|
||||
if (null === $streetNumber) {
|
||||
$streetNumber = '';
|
||||
}
|
||||
$this->streetNumber = $streetNumber;
|
||||
$this->streetNumber = (string) $streetNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -605,7 +640,7 @@ class Address
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->getStreetAddress1())) {
|
||||
if ('' === $this->getStreet()) {
|
||||
$context
|
||||
->buildViolation('address.street1-should-be-set')
|
||||
->atPath('streetAddress1')
|
||||
|
@@ -55,13 +55,13 @@ class AddressReference
|
||||
* @ORM\Column(type="integer")
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $id;
|
||||
private ?int $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $municipalityCode;
|
||||
private string $municipalityCode = '';
|
||||
|
||||
/**
|
||||
* A geospatial field storing the coordinates of the Address.
|
||||
@@ -71,7 +71,7 @@ class AddressReference
|
||||
* @ORM\Column(type="point")
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $point;
|
||||
private ?Point $point = null;
|
||||
|
||||
/**
|
||||
* @var PostalCode
|
||||
@@ -79,31 +79,31 @@ class AddressReference
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $postcode;
|
||||
private ?PostalCode $postcode;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $refId;
|
||||
private string $refId = '';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $source;
|
||||
private string $source = '';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $street;
|
||||
private string $street = '';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=255, nullable=true)
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @groups({"read"})
|
||||
*/
|
||||
private $streetNumber;
|
||||
private string $streetNumber = '';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=true)
|
||||
@@ -126,7 +126,7 @@ class AddressReference
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getMunicipalityCode(): ?string
|
||||
public function getMunicipalityCode(): string
|
||||
{
|
||||
return $this->municipalityCode;
|
||||
}
|
||||
@@ -141,27 +141,27 @@ class AddressReference
|
||||
*
|
||||
* @return PostalCode
|
||||
*/
|
||||
public function getPostcode()
|
||||
public function getPostcode(): ?PostalCode
|
||||
{
|
||||
return $this->postcode;
|
||||
}
|
||||
|
||||
public function getRefId(): ?string
|
||||
public function getRefId(): string
|
||||
{
|
||||
return $this->refId;
|
||||
}
|
||||
|
||||
public function getSource(): ?string
|
||||
public function getSource(): string
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
public function getStreet(): ?string
|
||||
public function getStreet(): string
|
||||
{
|
||||
return $this->street;
|
||||
}
|
||||
|
||||
public function getStreetNumber(): ?string
|
||||
public function getStreetNumber(): string
|
||||
{
|
||||
return $this->streetNumber;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ class AddressReference
|
||||
|
||||
public function setMunicipalityCode(?string $municipalityCode): self
|
||||
{
|
||||
$this->municipalityCode = $municipalityCode;
|
||||
$this->municipalityCode = (string) $municipalityCode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -227,21 +227,21 @@ class AddressReference
|
||||
|
||||
public function setSource(?string $source): self
|
||||
{
|
||||
$this->source = $source;
|
||||
$this->source = (string) $source;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStreet(?string $street): self
|
||||
{
|
||||
$this->street = $street;
|
||||
$this->street = (string) $street;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStreetNumber(?string $streetNumber): self
|
||||
{
|
||||
$this->streetNumber = $streetNumber;
|
||||
$this->streetNumber = (string) $streetNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -11,6 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Entity\GeographicalUnit;
|
||||
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
/**
|
||||
* Simple GeographialUnit Data Transfer Object.
|
||||
*
|
||||
@@ -21,24 +23,28 @@ class SimpleGeographicalUnitDTO
|
||||
/**
|
||||
* @readonly
|
||||
* @psalm-readonly
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public int $id;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @psalm-readonly
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public int $layerId;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @psalm-readonly
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $unitName;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @psalm-readonly
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
public string $unitRefId;
|
||||
|
||||
|
@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Entity;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="chill_main_geographical_unit_layer", uniqueConstraints={
|
||||
@@ -27,16 +28,19 @@ class GeographicalUnitLayer
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
* @ORM\Column(type="integer")
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private ?int $id = null;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="json", nullable=false, options={"default": "[]"})
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private array $name = [];
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=false, options={"default": ""})
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private string $refId = '';
|
||||
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Export;
|
||||
|
||||
use Doctrine\ORM\NativeQuery;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ use Doctrine\ORM\QueryBuilder;
|
||||
* aggregation, use `ListInterface`.
|
||||
*
|
||||
* @example Chill\PersonBundle\Export\CountPerson an example of implementation
|
||||
* @template Q of QueryBuilder|NativeQuery
|
||||
*/
|
||||
interface ExportInterface extends ExportElementInterface
|
||||
{
|
||||
@@ -84,7 +86,7 @@ interface ExportInterface extends ExportElementInterface
|
||||
* @param mixed[] $values The values from the result. if there are duplicates, those might be given twice. Example: array('FR', 'BE', 'CZ', 'FR', 'BE', 'FR')
|
||||
* @param mixed $data The data from the export's form (as defined in `buildForm`)
|
||||
*
|
||||
* @return pure-callable(null|string|int|float|'_header' $value):string|int|\DateTimeInterface where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
|
||||
* @return callable(null|string|int|float|'_header' $value): string|int|\DateTimeInterface where the first argument is the value, and the function should return the label to show in the formatted file. Example : `function($countryCode) use ($countries) { return $countries[$countryCode]->getName(); }`
|
||||
*/
|
||||
public function getLabels($key, array $values, $data);
|
||||
|
||||
@@ -102,7 +104,7 @@ interface ExportInterface extends ExportElementInterface
|
||||
/**
|
||||
* Return the results of the query builder.
|
||||
*
|
||||
* @param \Doctrine\ORM\NativeQuery|QueryBuilder $query
|
||||
* @param Q $query
|
||||
* @param mixed[] $data the data from the export's fomr (added by self::buildForm)
|
||||
*
|
||||
* @return mixed[] an array of results
|
||||
@@ -132,7 +134,7 @@ interface ExportInterface extends ExportElementInterface
|
||||
* @param array $acl an array where each row has a `center` key containing the Chill\MainBundle\Entity\Center, and `circles` keys containing the reachable circles. Example: `array( array('center' => $centerA, 'circles' => array($circleA, $circleB) ) )`
|
||||
* @param array $data the data from the form, if any
|
||||
*
|
||||
* @return \Doctrine\ORM\NativeQuery|QueryBuilder the query to execute.
|
||||
* @return Q the query to execute.
|
||||
*/
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = []);
|
||||
|
||||
|
@@ -43,11 +43,13 @@ class AddressDataMapper implements DataMapperInterface
|
||||
/** @var FormInterface $form */
|
||||
switch ($key) {
|
||||
case 'streetAddress1':
|
||||
/** @phpstan-ignore-next-line */
|
||||
$form->setData($address->getStreetAddress1());
|
||||
|
||||
break;
|
||||
|
||||
case 'streetAddress2':
|
||||
/** @phpstan-ignore-next-line */
|
||||
$form->setData($address->getStreetAddress2());
|
||||
|
||||
break;
|
||||
@@ -110,11 +112,13 @@ class AddressDataMapper implements DataMapperInterface
|
||||
|
||||
return;
|
||||
}
|
||||
/** @phpstan-ignore-next-line */
|
||||
$address->setStreetAddress1($form->getData());
|
||||
|
||||
break;
|
||||
|
||||
case 'streetAddress2':
|
||||
/** @phpstan-ignore-next-line */
|
||||
$address->setStreetAddress2($form->getData());
|
||||
|
||||
break;
|
||||
|
@@ -24,15 +24,7 @@ class ExportPickCenterDataMapper implements DataMapperInterface
|
||||
{
|
||||
protected RegroupmentRepository $regroupmentRepository;
|
||||
|
||||
/**
|
||||
* @param array|Center[] $data
|
||||
* @param $forms
|
||||
*
|
||||
* @throws Exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mapDataToForms($data, $forms)
|
||||
public function mapDataToForms($data, $forms): void
|
||||
{
|
||||
if (null === $data) {
|
||||
return;
|
||||
@@ -44,7 +36,9 @@ class ExportPickCenterDataMapper implements DataMapperInterface
|
||||
$pickedRegroupment = [];
|
||||
|
||||
foreach ($this->regroupmentRepository->findAll() as $regroupment) {
|
||||
[$contained, $notContained] = $regroupment->getCenters()->partition(static function (Center $center) {
|
||||
/** @phpstan-ignore-next-line */
|
||||
[$contained, $notContained] = $regroupment->getCenters()->partition(static function (Center $center): bool {
|
||||
return false;
|
||||
});
|
||||
|
||||
if (0 === count($notContained)) {
|
||||
@@ -56,13 +50,7 @@ class ExportPickCenterDataMapper implements DataMapperInterface
|
||||
$form['centers']->setData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable $forms
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mapFormsToData($forms, &$data)
|
||||
public function mapFormsToData($forms, &$data): void
|
||||
{
|
||||
/** @var array<string, FormInterface> $forms */
|
||||
$forms = iterator_to_array($forms);
|
||||
@@ -74,8 +62,8 @@ class ExportPickCenterDataMapper implements DataMapperInterface
|
||||
}
|
||||
|
||||
if (array_key_exists('regroupment', $forms)) {
|
||||
/** @var Regroupment $regroupment */
|
||||
foreach ($forms['regroupment']->getData() as $regroupment) {
|
||||
/** @var Regroupment $regroupment */
|
||||
foreach ($regroupment->getCenters() as $center) {
|
||||
$centers[spl_object_hash($center)] = $center;
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ class RollingDateDataMapper implements DataMapperInterface
|
||||
$forms = iterator_to_array($forms);
|
||||
|
||||
$viewData = new RollingDate(
|
||||
$forms['roll']->getData(),
|
||||
($forms['roll']->getData() ?? RollingDate::T_TODAY),
|
||||
$forms['fixedDate']->getData()
|
||||
);
|
||||
}
|
||||
|
@@ -31,8 +31,6 @@ class MultipleObjectsToIdTransformer implements DataTransformerInterface
|
||||
* Transforms a string (id) to an object (item).
|
||||
*
|
||||
* @param mixed $array
|
||||
*
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function reverseTransform($array)
|
||||
{
|
||||
@@ -53,10 +51,8 @@ class MultipleObjectsToIdTransformer implements DataTransformerInterface
|
||||
* Transforms an object (use) to a string (id).
|
||||
*
|
||||
* @param array $array
|
||||
*
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function transform($array)
|
||||
public function transform($array): array
|
||||
{
|
||||
$ret = [];
|
||||
|
||||
|
@@ -11,20 +11,58 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\GeographicalUnit;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface
|
||||
final class GeographicalUnitRepository implements GeographicalUnitRepositoryInterface
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->repository = $em->getRepository($this->getClassName());
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
|
||||
public function countGeographicalUnitContainingAddress(Address $address): int
|
||||
{
|
||||
$qb = $this->buildQueryGeographicalUnitContainingAddress($address);
|
||||
|
||||
return $qb
|
||||
->select('COUNT(gu)')
|
||||
->getQuery()
|
||||
->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function findGeographicalUnitContainingAddress(Address $address, int $offset = 0, int $limit = 50): array
|
||||
{
|
||||
$qb = $this->buildQueryGeographicalUnitContainingAddress($address);
|
||||
|
||||
return $qb
|
||||
->select(sprintf('NEW %s(gu.id, gu.unitName, gu.unitRefId, IDENTITY(gu.layer))', GeographicalUnit\SimpleGeographicalUnitDTO::class))
|
||||
->addOrderBy('IDENTITY(gu.layer)')
|
||||
->addOrderBy(('gu.unitName'))
|
||||
->getQuery()
|
||||
->setFirstResult($offset)
|
||||
->setMaxResults($limit)
|
||||
->getResult();
|
||||
}
|
||||
|
||||
private function buildQueryGeographicalUnitContainingAddress(Address $address): QueryBuilder
|
||||
{
|
||||
$qb = $this->repository
|
||||
->createQueryBuilder('gu')
|
||||
;
|
||||
return $qb
|
||||
->select(sprintf('NEW %s(gu.id, gu.unitName, gu.unitRefId, IDENTITY(gu.layer))', GeographicalUnit\SimpleGeographicalUnitDTO::class))
|
||||
->innerJoin(Address::class, 'address', Join::WITH, 'ST_CONTAINS(gu.geom, address.point) = TRUE')
|
||||
->where($qb->expr()->eq('address', ':address'))
|
||||
->setParameter('address', $address)
|
||||
;
|
||||
}
|
||||
|
||||
public function find($id): ?GeographicalUnit
|
||||
|
@@ -11,8 +11,23 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Repository;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\GeographicalUnit\SimpleGeographicalUnitDTO;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
interface GeographicalUnitRepositoryInterface extends ObjectRepository
|
||||
{
|
||||
/**
|
||||
* Return the geographical units as @link{SimpleGeographicalUnitDTO} whithin the address is contained.
|
||||
*
|
||||
* This query is executed in real time (without the refresh of the materialized view which load the addresses).
|
||||
*
|
||||
* @param Address $address
|
||||
* @param int $offset
|
||||
* @param int $limit
|
||||
* @return SimpleGeographicalUnitDTO[]
|
||||
*/
|
||||
public function findGeographicalUnitContainingAddress(Address $address, int $offset = 0, int $limit = 50): array;
|
||||
|
||||
public function countGeographicalUnitContainingAddress(Address $address): int;
|
||||
}
|
||||
|
@@ -0,0 +1,35 @@
|
||||
import {Address, GeographicalUnitLayer, SimpleGeographicalUnit} from "../../types";
|
||||
import {fetchResults, makeFetch} from "./apiMethods";
|
||||
|
||||
export const getAddressById = async (address_id: number): Promise<Address> =>
|
||||
{
|
||||
const url = `/api/1.0/main/address/${address_id}.json`;
|
||||
|
||||
const response = await fetch(url);
|
||||
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
throw Error('Error with request resource response');
|
||||
};
|
||||
|
||||
export const getGeographicalUnitsByAddress = async (address: Address): Promise<SimpleGeographicalUnit[]> => {
|
||||
return fetchResults<SimpleGeographicalUnit>(`/api/1.0/main/geographical-unit/by-address/${address.address_id}.json`);
|
||||
}
|
||||
|
||||
export const getAllGeographicalUnitLayers = async (): Promise<GeographicalUnitLayer[]> => {
|
||||
return fetchResults<GeographicalUnitLayer>(`/api/1.0/main/geographical-unit-layer.json`);
|
||||
}
|
||||
|
||||
export const syncAddressWithReference = async (address: Address): Promise<Address> => {
|
||||
return makeFetch<null, Address>("POST", `/api/1.0/main/address/reference-match/${address.address_id}/sync-with-reference`);
|
||||
}
|
||||
|
||||
export const markAddressReviewed = async (address: Address): Promise<Address> => {
|
||||
return makeFetch<null, Address>("POST", `/api/1.0/main/address/reference-match/${address.address_id}/set/reviewed`);
|
||||
}
|
||||
|
||||
export const markAddressToReview = async (address: Address): Promise<Address> => {
|
||||
return makeFetch<null, Address>("POST", `/api/1.0/main/address/reference-match/${address.address_id}/set/to_review`);
|
||||
}
|
@@ -67,9 +67,6 @@ export const makeFetch = <Input, Output>(method: 'POST'|'GET'|'PUT'|'PATCH'|'DEL
|
||||
},
|
||||
};
|
||||
|
||||
console.log('for url '+url, body);
|
||||
console.log('for url '+url, body !== null);
|
||||
|
||||
if (body !== null && typeof body !== 'undefined') {
|
||||
Object.assign(opts, {body: JSON.stringify(body)})
|
||||
}
|
||||
@@ -77,9 +74,6 @@ export const makeFetch = <Input, Output>(method: 'POST'|'GET'|'PUT'|'PATCH'|'DEL
|
||||
if (typeof options !== 'undefined') {
|
||||
opts = Object.assign(opts, options);
|
||||
}
|
||||
console.log('will fetch', url);
|
||||
console.log('content for ' + url, opts);
|
||||
|
||||
return fetch(url, opts)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
|
@@ -0,0 +1,39 @@
|
||||
import AddressDetailsButton from "../../vuejs/_components/AddressDetails/AddressDetailsButton.vue";
|
||||
import {createApp} from "vue";
|
||||
import {createI18n} from "vue-i18n";
|
||||
import {_createI18n} from "../../vuejs/_js/i18n";
|
||||
import {Address} from "../../types";
|
||||
|
||||
const i18n = _createI18n({});
|
||||
|
||||
document.querySelectorAll<HTMLSpanElement>('span[data-address-details]').forEach((el) => {
|
||||
const dataset = el.dataset as {
|
||||
addressId: string,
|
||||
addressRefStatus: string,
|
||||
};
|
||||
|
||||
const app = createApp({
|
||||
components: {AddressDetailsButton},
|
||||
data() {
|
||||
return {
|
||||
addressId: Number.parseInt(dataset.addressId),
|
||||
addressRefStatus: dataset.addressRefStatus,
|
||||
}
|
||||
},
|
||||
template: '<address-details-button :address_id="addressId" :address_ref_status="addressRefStatus" @update-address="onUpdateAddress"></address-details-button>',
|
||||
methods: {
|
||||
onUpdateAddress: (address: Address): void => {
|
||||
if (address.refStatus === 'to_review' || address.refStatus === 'reviewed') {
|
||||
// in this two case, the address content do not change
|
||||
return;
|
||||
}
|
||||
if (window.confirm("L'adresse a été modifiée. Vous pouvez continuer votre travail. Cependant, pour afficher les données immédiatement, veuillez recharger la page. \n\n Voulez-vous recharger la page immédiatement ?")) {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.use(i18n);
|
||||
app.mount(el);
|
||||
});
|
@@ -18,6 +18,7 @@ function loadDynamicPicker(element) {
|
||||
isMultiple = parseInt(el.dataset.multiple) === 1,
|
||||
uniqId = el.dataset.uniqid,
|
||||
input = element.querySelector('[data-input-uniqid="'+ el.dataset.uniqid +'"]'),
|
||||
// the "picked" will always be an array, even if multiple is false
|
||||
picked = isMultiple ?
|
||||
JSON.parse(input.value) : (
|
||||
(input.value === '[]' || input.value === '') ?
|
||||
@@ -54,15 +55,11 @@ function loadDynamicPicker(element) {
|
||||
},
|
||||
computed: {
|
||||
notPickedSuggested() {
|
||||
if (this.multiple) {
|
||||
const pickedIds = new Set();
|
||||
for (const p of this.picked) {
|
||||
pickedIds.add(`${p.type}${p.id}`);
|
||||
}
|
||||
return this.suggested.filter(e => !pickedIds.has(`${e.type}${e.id}`))
|
||||
const pickedIds = new Set();
|
||||
for (const p of this.picked) {
|
||||
pickedIds.add(`${p.type}${p.id}`);
|
||||
}
|
||||
|
||||
return this.suggested.filter(e => e.type !== this.picked.type && e.id !== e.picked.id);
|
||||
return this.suggested.filter(e => !pickedIds.has(`${e.type}${e.id}`))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -90,7 +87,11 @@ function loadDynamicPicker(element) {
|
||||
this.suggested.push(entity);
|
||||
}
|
||||
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
|
||||
input.value = JSON.stringify(this.picked);
|
||||
if (this.multiple) {
|
||||
input.value = JSON.stringify(this.picked);
|
||||
} else {
|
||||
input.value = "";
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
@@ -70,6 +70,8 @@ export interface Country {
|
||||
code: string;
|
||||
}
|
||||
|
||||
export type AddressRefStatus = 'match'|'to_review'|'reviewed';
|
||||
|
||||
export interface Address {
|
||||
type: "address";
|
||||
address_id: number;
|
||||
@@ -90,6 +92,13 @@ export interface Address {
|
||||
addressReference: AddressReference | null;
|
||||
validFrom: DateTime;
|
||||
validTo: DateTime | null;
|
||||
point: Point | null;
|
||||
refStatus: AddressRefStatus;
|
||||
isNoAddress: boolean;
|
||||
}
|
||||
|
||||
export interface AddressWithPoint extends Address {
|
||||
point: Point
|
||||
}
|
||||
|
||||
export interface AddressReference {
|
||||
@@ -106,6 +115,19 @@ export interface AddressReference {
|
||||
updatedAt: DateTime | null;
|
||||
}
|
||||
|
||||
export interface SimpleGeographicalUnit {
|
||||
id: number;
|
||||
layerId: number;
|
||||
unitName: string;
|
||||
unitRefId: string;
|
||||
}
|
||||
|
||||
export interface GeographicalUnitLayer {
|
||||
id: number;
|
||||
name: TranslatableString;
|
||||
refId: string;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
type: "location";
|
||||
id: number;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import {getAddressById} from 'ChillMainAssets/lib/api/address';
|
||||
|
||||
/**
|
||||
* Endpoint chill_api_single_country__index
|
||||
* method GET, get Country Object
|
||||
@@ -188,13 +190,7 @@ const postPostalCode = (postalCode) => { //<--
|
||||
* @returns {Promise} a promise containing a Address object
|
||||
*/
|
||||
const getAddress = (id) => {
|
||||
//console.log('<< get address');
|
||||
const url = `/api/1.0/main/address/${id}.json`;
|
||||
return fetch(url)
|
||||
.then(response => {
|
||||
if (response.ok) { return response.json(); }
|
||||
throw Error('Error with request resource response');
|
||||
});
|
||||
return getAddressById(id);
|
||||
};
|
||||
|
||||
export {
|
||||
|
@@ -59,7 +59,7 @@
|
||||
v-bind:insideModal="false"
|
||||
@pick-address="this.pickAddress"
|
||||
ref="suggestAddress">
|
||||
|
||||
|
||||
<template v-slot:before v-if="!bypassFirstStep">
|
||||
<a class="btn btn-cancel" @click="resetPane">
|
||||
{{ $t('action.cancel') }}
|
||||
@@ -73,7 +73,7 @@
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
||||
</suggest-pane>
|
||||
</div>
|
||||
</template>
|
||||
@@ -133,7 +133,7 @@
|
||||
v-bind:insideModal="false"
|
||||
@getCities="getCities"
|
||||
@getReferenceAddresses="getReferenceAddresses">
|
||||
|
||||
|
||||
<template v-slot:before>
|
||||
<a class="btn btn-cancel" @click="resetPane">
|
||||
{{ $t('action.cancel') }}
|
||||
@@ -152,7 +152,7 @@
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
||||
</edit-pane>
|
||||
</div>
|
||||
</template>
|
||||
@@ -206,7 +206,7 @@
|
||||
v-bind:flag="this.flag"
|
||||
v-bind:insideModal="false"
|
||||
ref="dateAddress">
|
||||
|
||||
|
||||
<template v-slot:before>
|
||||
<button class="btn btn-misc" @click="openEditPane">
|
||||
<i class="fa fa-fw fa-arrow-left"></i>
|
||||
@@ -220,7 +220,7 @@
|
||||
</button>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
|
||||
</date-pane>
|
||||
</div>
|
||||
</template>
|
||||
@@ -580,15 +580,15 @@ export default {
|
||||
this.entity.selected.city = this.context.edit ? this.entity.address.postcode : {};
|
||||
|
||||
this.entity.selected.address = {};
|
||||
this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null;
|
||||
this.entity.selected.address.streetNumber = this.context.edit ? this.entity.address.streetNumber: null;
|
||||
this.entity.selected.address.floor = this.context.edit ? this.entity.address.floor: null;
|
||||
this.entity.selected.address.corridor = this.context.edit ? this.entity.address.corridor: null;
|
||||
this.entity.selected.address.steps = this.context.edit ? this.entity.address.steps: null;
|
||||
this.entity.selected.address.flat = this.context.edit ? this.entity.address.flat: null;
|
||||
this.entity.selected.address.buildingName = this.context.edit ? this.entity.address.buildingName: null;
|
||||
this.entity.selected.address.distribution = this.context.edit ? this.entity.address.distribution: null;
|
||||
this.entity.selected.address.extra = this.context.edit ? this.entity.address.extra: null;
|
||||
this.entity.selected.address.street = this.context.edit ? this.entity.address.street: '';
|
||||
this.entity.selected.address.streetNumber = this.context.edit ? this.entity.address.streetNumber: '';
|
||||
this.entity.selected.address.floor = this.context.edit ? this.entity.address.floor: '';
|
||||
this.entity.selected.address.corridor = this.context.edit ? this.entity.address.corridor: '';
|
||||
this.entity.selected.address.steps = this.context.edit ? this.entity.address.steps: '';
|
||||
this.entity.selected.address.flat = this.context.edit ? this.entity.address.flat: '';
|
||||
this.entity.selected.address.buildingName = this.context.edit ? this.entity.address.buildingName: '';
|
||||
this.entity.selected.address.distribution = this.context.edit ? this.entity.address.distribution: '';
|
||||
this.entity.selected.address.extra = this.context.edit ? this.entity.address.extra: '';
|
||||
|
||||
this.entity.selected.writeNew.address = this.context.edit && this.entity.address.addressReference === null && this.entity.address.street.length > 0
|
||||
this.entity.selected.writeNew.postcode = false // NB: this used to be this.context.edit, but think it was erroneous;
|
||||
|
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<span v-if="data.working_ref_status === 'to_review'" class="badge bg-danger address-details-button-warning">L'adresse de référence a été modifiée</span>
|
||||
<a v-if="data.loading === false" @click.prevent="clickOrOpen" class="btn btn-sm btn-misc">
|
||||
<span class="fa fa-map address-details-button"></span>
|
||||
</a>
|
||||
<span v-if="data.loading" class="fa fa-spin fa-spinner "></span>
|
||||
<AddressModal :address="data.working_address" @update-address="onUpdateAddress" ref="address_modal"></AddressModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {Address, AddressRefStatus} from "../../../types";
|
||||
import {onMounted, reactive, ref} from "vue";
|
||||
import {getAddressById} from "../../../lib/api/address";
|
||||
import AddressModal from "./AddressModal.vue";
|
||||
|
||||
export interface AddressModalContentProps {
|
||||
address_id: number;
|
||||
address_ref_status: AddressRefStatus | null;
|
||||
}
|
||||
|
||||
const data = reactive<{
|
||||
loading: boolean,
|
||||
working_address: Address | null,
|
||||
working_ref_status: AddressRefStatus | null,
|
||||
}>({
|
||||
loading: false,
|
||||
working_address: null,
|
||||
working_ref_status: null,
|
||||
});
|
||||
|
||||
const props = defineProps<AddressModalContentProps>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update-address', value: Address): void
|
||||
}>();
|
||||
|
||||
const address_modal = ref<InstanceType<typeof AddressModal> | null>(null);
|
||||
|
||||
onMounted(() => {
|
||||
data.working_ref_status = props.address_ref_status;
|
||||
});
|
||||
|
||||
async function clickOrOpen(): Promise<void> {
|
||||
if (data.working_address === null) {
|
||||
data.loading = true;
|
||||
data.working_address = await getAddressById(props.address_id);
|
||||
data.working_ref_status = data.working_address.refStatus;
|
||||
data.loading = false;
|
||||
}
|
||||
|
||||
// open the modal
|
||||
address_modal.value?.open();
|
||||
}
|
||||
|
||||
const onUpdateAddress = (address: Address): void => {
|
||||
data.working_address = address;
|
||||
data.working_ref_status = address.refStatus;
|
||||
emit('update-address', address);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.address-details-button-warning {
|
||||
display: inline-block;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<address-render-box :address="props.address" :show-button-details="false"></address-render-box>
|
||||
<address-details-ref-matching :address="props.address" @update-address="onUpdateAddress"></address-details-ref-matching>
|
||||
<address-details-map :address="props.address"></address-details-map>
|
||||
<address-details-geographical-layers :address="props.address"></address-details-geographical-layers>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {Address} from "../../../types";
|
||||
import AddressDetailsMap from "./Parts/AddressDetailsMap.vue";
|
||||
import AddressRenderBox from "../Entity/AddressRenderBox.vue";
|
||||
import AddressDetailsGeographicalLayers from "./Parts/AddressDetailsGeographicalLayers.vue";
|
||||
import AddressDetailsRefMatching from "./Parts/AddressDetailsRefMatching.vue";
|
||||
|
||||
interface AddressModalContentProps {
|
||||
address: Address,
|
||||
}
|
||||
|
||||
const props = defineProps<AddressModalContentProps>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update-address', value: Address): void
|
||||
}>();
|
||||
|
||||
const onUpdateAddress = (address: Address): void => {
|
||||
emit('update-address', address);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<teleport to="body">
|
||||
<modal v-if="state.show_modal" @close="close">
|
||||
<template v-slot:header>
|
||||
<h2>Détails d'une adresse</h2>
|
||||
</template>
|
||||
<template v-slot:body>
|
||||
<address-details-content :address="props.address" @update-address="onUpdateAddress"></address-details-content>
|
||||
</template>
|
||||
</modal>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {reactive, ref} from "vue";
|
||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
||||
import {Address} from "../../../types";
|
||||
import AddressDetailsContent from "./AddressDetailsContent.vue";
|
||||
|
||||
interface AddressModalProps {
|
||||
address: Address
|
||||
}
|
||||
|
||||
interface AddressModalState {
|
||||
show_modal: boolean,
|
||||
}
|
||||
|
||||
const props = defineProps<AddressModalProps>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update-address', value: Address): void
|
||||
}>();
|
||||
|
||||
const state: AddressModalState = reactive({show_modal: false});
|
||||
|
||||
const open = (): void => {
|
||||
state.show_modal = true;
|
||||
}
|
||||
|
||||
const close = (): void => {
|
||||
state.show_modal = false;
|
||||
}
|
||||
|
||||
const onUpdateAddress = (address: Address): void => {
|
||||
emit('update-address', address);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
close,
|
||||
open,
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<template v-for="container in data.containers">
|
||||
<h4>{{ container.layer.name.fr }}</h4>
|
||||
<ul>
|
||||
<li v-for="unit in container.units">{{ unit.unitName }} ({{ unit.unitRefId }})</li>
|
||||
</ul>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {Address, GeographicalUnitLayer, SimpleGeographicalUnit} from "../../../../types";
|
||||
import {getGeographicalUnitsByAddress, getAllGeographicalUnitLayers} from "../../../../lib/api/address";
|
||||
import {onMounted, reactive} from "vue";
|
||||
|
||||
export interface AddressDetailsGeographicalLayersProp {
|
||||
address: Address
|
||||
};
|
||||
|
||||
interface GeographicalUnitContainer {
|
||||
layer: GeographicalUnitLayer;
|
||||
units: SimpleGeographicalUnit[];
|
||||
}
|
||||
|
||||
const props = defineProps<AddressDetailsGeographicalLayersProp>();
|
||||
|
||||
const data: {
|
||||
containers: GeographicalUnitContainer[]
|
||||
} = reactive({
|
||||
containers: []
|
||||
});
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
const [units, layers] = await Promise.all([
|
||||
getGeographicalUnitsByAddress(props.address),
|
||||
getAllGeographicalUnitLayers()
|
||||
]) as [SimpleGeographicalUnit[], GeographicalUnitLayer[]];
|
||||
|
||||
for (let layer of layers) {
|
||||
let us = units.filter((u) => u.layerId === layer.id);
|
||||
if (us.length > 0) {
|
||||
data.containers.push({
|
||||
layer,
|
||||
units: us
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div v-if="props.address.isNoAddress" class="alert alert-info">
|
||||
Cette adresse est incomplète. La position géographique est approximative.
|
||||
</div>
|
||||
<div v-if="props.address.point !== null" class="address_details_map" ref="map_div"></div>
|
||||
<p>Voir sur <a :href="makeUrlGoogleMap(props.address)" target="_blank">Google Maps</a> <a :href="makeUrlOsm(props.address)" target="_blank">OSM</a></p>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {onMounted, ref} from "vue";
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import markerIconPng from "leaflet/dist/images/marker-icon.png";
|
||||
import L, {LatLngExpression, LatLngTuple} from "leaflet";
|
||||
import {Address, Point} from "../../../../types";
|
||||
|
||||
const lonLatForLeaflet = (point: Point): LatLngTuple => {
|
||||
return [point.coordinates[1], point.coordinates[0]];
|
||||
}
|
||||
|
||||
export interface MapProps {
|
||||
address: Address,
|
||||
}
|
||||
|
||||
const props = defineProps<MapProps>();
|
||||
|
||||
const map_div = ref<HTMLDivElement | null>(null)
|
||||
let map: L.Map|null = null;
|
||||
let marker: L.Marker|null = null;
|
||||
|
||||
onMounted(() => {
|
||||
if (map_div.value === null) {
|
||||
// there is no map div when the address does not have any Point
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.address.point !== null) {
|
||||
map = L.map(map_div.value);
|
||||
map.setView(lonLatForLeaflet(props.address.point), 18);
|
||||
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
|
||||
|
||||
const markerIcon = L.icon({
|
||||
iconUrl: markerIconPng,
|
||||
iconAnchor: [12, 41],
|
||||
});
|
||||
|
||||
marker = L.marker(lonLatForLeaflet(props.address.point), {icon: markerIcon});
|
||||
marker.addTo(map);
|
||||
}
|
||||
});
|
||||
|
||||
const makeUrlGoogleMap = (address: Address): string => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('api', '1');
|
||||
if (address.point !== null && address.addressReference !== null) {
|
||||
params.append('query', `${address.point.coordinates[1]} ${address.point.coordinates[0]}`);
|
||||
} else {
|
||||
params.append('query', address.lines.join(', '));
|
||||
}
|
||||
|
||||
return `https://www.google.com/maps/search/?${params.toString()}`;
|
||||
}
|
||||
|
||||
const makeUrlOsm = (address: Address): string => {
|
||||
if (address.point !== null && address.addressReference !== null) {
|
||||
const params = new URLSearchParams();
|
||||
params.append('mlat', `${address.point.coordinates[1]}`);
|
||||
params.append('mlon', `${address.point.coordinates[0]}`);
|
||||
const hashParams = new URLSearchParams();
|
||||
hashParams.append('map', `18/${address.point.coordinates[1]}/${address.point.coordinates[0]}`);
|
||||
|
||||
return `https://www.openstreetmap.org/?${params.toString()}#${hashParams.toString()}`;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.append('query', address.lines.join(', '));
|
||||
|
||||
return `https://www.openstreetmap.org/search?${params.toString()}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
div.address_details_map {
|
||||
height: 250px;
|
||||
}
|
||||
</style>
|
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<template v-if="props.address.refStatus !== 'match'">
|
||||
<div v-if="props.address.refStatus === 'to_review' || props.address.refStatus === 'reviewed'" :class="{alert: true, 'alert-danger': props.address.refStatus === 'to_review', 'alert-warning': props.address.refStatus === 'reviewed'}">
|
||||
<p v-if="props.address.refStatus === 'to_review'"><i class="fa fa-warning"></i> L'adresse de référence a été modifiée.</p>
|
||||
<p v-if="props.address.refStatus === 'reviewed'">L'adresse est conservée, mais diffère de l'adresse de référence.</p>
|
||||
|
||||
<template v-if="props.address.addressReference.street !== props.address.street || props.address.addressReference.streetNumber !== props.address.streetNumber">
|
||||
<template v-if="props.address.country.code === 'BE'">
|
||||
<div class="difference">
|
||||
<span class="old">{{ props.address.street }} {{props.address.streetNumber}}</span>
|
||||
<span class="new">{{ props.address.addressReference.street }} {{ props.address.addressReference.streetNumber }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="difference">
|
||||
<span class="old">{{props.address.streetNumber}} {{ props.address.street }}</span>
|
||||
<span class="new">{{ props.address.addressReference.streetNumber }} {{ props.address.addressReference.street }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template v-if="props.address.addressReference.postcode.id !== props.address.postcode.id">
|
||||
<div class="difference">
|
||||
<span class="old">{{ props.address.postcode.code }} {{props.address.postcode.name }}</span>
|
||||
<span class="new">{{ props.address.addressReference.postcode.code }} {{ props.address.addressReference.postcode.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="props.address.point !== null && (props.address.point.coordinates[0] !== props.address.addressReference.point.coordinates[0] || props.address.point.coordinates[1] !== props.address.addressReference.point.coordinates[1])">
|
||||
<div class="difference">
|
||||
<span class="old">{{ props.address.point.coordinates[0] }} {{ props.address.point.coordinates[1]}}</span>
|
||||
<span class="new">{{ props.address.addressReference.point.coordinates[0] }} {{ props.address.addressReference.point.coordinates[1]}}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ul class="record_actions">
|
||||
<li v-if="props.address.refStatus === 'to_review'"><button class="btn btn-sm btn-update" @click="applyUpdate">Appliquer les modifications</button></li>
|
||||
<li v-if="props.address.refStatus === 'to_review'"><button class="btn btn-sm btn-primary" @click="keepCurrentAddress">Conserver</button></li>
|
||||
<li v-if="props.address.refStatus === 'reviewed'"><button class="btn btn-sm btn-primary" @click="backToReview">Ré-examiner</button></li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {Address} from "../../../../types";
|
||||
import {markAddressReviewed, markAddressToReview, syncAddressWithReference} from "../../../../lib/api/address";
|
||||
|
||||
export interface AddressDetailsRefMatchingProps {
|
||||
address: Address;
|
||||
}
|
||||
|
||||
const props = defineProps<AddressDetailsRefMatchingProps>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update-address', value: Address): void
|
||||
}>();
|
||||
|
||||
const applyUpdate = async () => {
|
||||
const new_address = await syncAddressWithReference(props.address);
|
||||
|
||||
emit('update-address', new_address);
|
||||
}
|
||||
|
||||
const keepCurrentAddress = async () => {
|
||||
const new_address = await markAddressReviewed(props.address);
|
||||
|
||||
emit("update-address", new_address);
|
||||
}
|
||||
|
||||
const backToReview = async () => {
|
||||
const new_address = await markAddressToReview(props.address);
|
||||
|
||||
emit("update-address", new_address);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.difference {
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.old {
|
||||
text-decoration: red line-through;
|
||||
}
|
||||
.new {
|
||||
font-weight: bold;
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
</style>
|
@@ -11,17 +11,18 @@
|
||||
<p v-for="(l, i) in address.lines" :key="`line-${i}`">
|
||||
{{ l }}
|
||||
</p>
|
||||
<p v-if="showButtonDetails"><address-details-button :address_id="address.address_id" :address_ref_status="address.refStatus"></address-details-button></p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p v-if="address.text"
|
||||
<p v-if="'' !== address.text"
|
||||
class="street">
|
||||
{{ address.text }}
|
||||
</p>
|
||||
<p v-if="address.postcode"
|
||||
<p v-if="null !== address.postcode"
|
||||
class="postcode">
|
||||
{{ address.postcode.code }} {{ address.postcode.name }}
|
||||
</p>
|
||||
<p v-if="address.country"
|
||||
<p v-if="null !== address.country"
|
||||
class="country">
|
||||
{{ address.country.name.fr }}
|
||||
</p>
|
||||
@@ -35,11 +36,12 @@
|
||||
<p v-for="(l, i) in address.lines" :key="`line-${i}`">
|
||||
{{ l }}
|
||||
</p>
|
||||
<p v-if="showButtonDetails"><address-details-button :address_id="address.address_id" :address_ref_status="address.refStatus"></address-details-button></p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p v-if="address.text"
|
||||
class="street">
|
||||
{{ address.text }}
|
||||
{{ address.text }} <template v-if="showButtonDetails"><address-details-button :address_id="address.address_id" :address_ref_status="address.refStatus"></address-details-button></template>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -65,11 +67,13 @@
|
||||
<script>
|
||||
|
||||
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
||||
import AddressDetailsButton from "ChillMainAssets/vuejs/_components/AddressDetails/AddressDetailsButton.vue";
|
||||
|
||||
export default {
|
||||
name: 'AddressRenderBox',
|
||||
components: {
|
||||
Confidential
|
||||
Confidential,
|
||||
AddressDetailsButton,
|
||||
},
|
||||
props: {
|
||||
address: {
|
||||
@@ -82,6 +86,10 @@ export default {
|
||||
useDatePane: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
showButtonDetails: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@@ -69,6 +69,7 @@
|
||||
<i class="fa fa-li fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.inline(address, options, streetLine, lines) }}
|
||||
<span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}" ></span>
|
||||
</li>
|
||||
{%- endif -%}
|
||||
|
||||
@@ -78,6 +79,7 @@
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.inline(address, options, streetLine, lines) }}
|
||||
<span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}"></span>
|
||||
</span>
|
||||
{%- endif -%}
|
||||
|
||||
@@ -102,6 +104,7 @@
|
||||
<div class="noaddress">
|
||||
{{ 'address.consider homeless'|trans }}
|
||||
</div>
|
||||
<p><span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}" ></span></p>
|
||||
|
||||
{% else %}
|
||||
<div class="address{% if options['multiline'] %} multiline{% endif %}{% if options['with_delimiter'] %} delimiter{% endif %}">
|
||||
@@ -109,6 +112,7 @@
|
||||
<i class="fa fa-fw fa-map-marker"></i>
|
||||
{% endif %}
|
||||
{{ _self.raw(lines) }}
|
||||
<p><span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}"></span></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ _self.validity(address, options) }}
|
||||
|
@@ -66,6 +66,7 @@
|
||||
{{ form_row(transition_form.future_dest_users) }}
|
||||
|
||||
{{ form_row(transition_form.future_dest_emails) }}
|
||||
{{ form_errors(transition_form.future_dest_users) }}
|
||||
</div>
|
||||
|
||||
<p>{{ form_label(transition_form.comment) }}</p>
|
||||
|
@@ -20,6 +20,7 @@
|
||||
{{ encore_entry_link_tags('chill') }}
|
||||
{{ encore_entry_link_tags('mod_blur') }}
|
||||
{{ encore_entry_link_tags('vue_onthefly') }}
|
||||
{{ encore_entry_link_tags('mod_address_details') }}
|
||||
{% block css %}<!-- nothing added to css -->{% endblock %}
|
||||
</head>
|
||||
|
||||
@@ -112,6 +113,7 @@
|
||||
{{ encore_entry_script_tags('mod_blur') }}
|
||||
{{ encore_entry_script_tags('chill') }}
|
||||
{{ encore_entry_script_tags('vue_onthefly') }}
|
||||
{{ encore_entry_script_tags('mod_address_details') }}
|
||||
|
||||
<script type="text/javascript">
|
||||
window.addEventListener('DOMContentLoaded', function(e) {
|
||||
|
@@ -11,8 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Search;
|
||||
|
||||
use Chill\MainBundle\Pagination\Paginator;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -30,7 +30,7 @@ class SearchApi
|
||||
|
||||
private PaginatorFactory $paginator;
|
||||
|
||||
private iterable $providers = [];
|
||||
private iterable $providers;
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
@@ -42,9 +42,6 @@ class SearchApi
|
||||
$this->paginator = $paginator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Model/Result[]
|
||||
*/
|
||||
public function getResults(string $pattern, array $types, array $parameters): Collection
|
||||
{
|
||||
$queries = $this->findQueries($pattern, $types, $parameters);
|
||||
@@ -53,10 +50,10 @@ class SearchApi
|
||||
throw new SearchApiNoQueryException($pattern, $types, $parameters);
|
||||
}
|
||||
|
||||
$total = $this->countItems($queries, $types, $parameters);
|
||||
$total = $this->countItems($queries);
|
||||
$paginator = $this->paginator->create($total);
|
||||
|
||||
$rawResults = $this->fetchRawResult($queries, $types, $parameters, $paginator);
|
||||
$rawResults = $this->fetchRawResult($queries, $types, $paginator);
|
||||
|
||||
$this->prepareProviders($rawResults);
|
||||
$results = $this->buildResults($rawResults);
|
||||
@@ -64,7 +61,7 @@ class SearchApi
|
||||
return new Collection($results, $paginator);
|
||||
}
|
||||
|
||||
private function buildCountQuery(array $queries, $types, $parameters)
|
||||
private function buildCountQuery(array $queries): array
|
||||
{
|
||||
$query = 'SELECT SUM(c) AS count FROM ({union_unordered}) AS sq';
|
||||
$unions = [];
|
||||
@@ -88,7 +85,7 @@ class SearchApi
|
||||
$items = [];
|
||||
|
||||
foreach ($rawResults as $r) {
|
||||
foreach ($this->providers as $k => $p) {
|
||||
foreach ($this->providers as $p) {
|
||||
if ($p->supportsResult($r['key'], $r['metadata'])) {
|
||||
$items[] = (new SearchApiResult($r['pertinence']))
|
||||
->setResult(
|
||||
@@ -103,7 +100,7 @@ class SearchApi
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function buildUnionQuery(array $queries, $types, $parameters, Paginator $paginator)
|
||||
private function buildUnionQuery(array $queries, PaginatorInterface $paginator): array
|
||||
{
|
||||
$query = '{unions} ORDER BY pertinence DESC LIMIT ? OFFSET ?';
|
||||
$unions = [];
|
||||
@@ -126,9 +123,9 @@ class SearchApi
|
||||
];
|
||||
}
|
||||
|
||||
private function countItems($providers, $types, $parameters): int
|
||||
private function countItems($providers): int
|
||||
{
|
||||
[$countQuery, $parameters] = $this->buildCountQuery($providers, $types, $parameters);
|
||||
[$countQuery, $parameters] = $this->buildCountQuery($providers);
|
||||
$rsmCount = new ResultSetMappingBuilder($this->em);
|
||||
$rsmCount->addScalarResult('count', 'count');
|
||||
$countNq = $this->em->createNativeQuery($countQuery, $rsmCount);
|
||||
@@ -137,9 +134,9 @@ class SearchApi
|
||||
return (int) $countNq->getSingleScalarResult();
|
||||
}
|
||||
|
||||
private function fetchRawResult($queries, $types, $parameters, Paginator $paginator): array
|
||||
private function fetchRawResult($queries, $types, PaginatorInterface $paginator): array
|
||||
{
|
||||
[$union, $parameters] = $this->buildUnionQuery($queries, $types, $parameters, $paginator);
|
||||
[$union, $parameters] = $this->buildUnionQuery($queries, $paginator);
|
||||
$rsm = new ResultSetMappingBuilder($this->em);
|
||||
$rsm->addScalarResult('key', 'key', Types::STRING)
|
||||
->addScalarResult('metadata', 'metadata', Types::JSON)
|
||||
@@ -172,7 +169,7 @@ class SearchApi
|
||||
);
|
||||
}
|
||||
|
||||
private function prepareProviders(array $rawResults)
|
||||
private function prepareProviders(array $rawResults): void
|
||||
{
|
||||
$metadatas = [];
|
||||
$providers = [];
|
||||
|
@@ -16,6 +16,18 @@ use function count;
|
||||
use function implode;
|
||||
use function strtr;
|
||||
|
||||
/**
|
||||
* This create a query optimized for searching for the api response.
|
||||
*
|
||||
* When build, this class generate a SQL string and a list of a parameters which is suitable for running
|
||||
* a native SQL query. This have usually the form of
|
||||
*
|
||||
* `SELECT '<key>' as key, <metadata> as metadata, <pertinence> as pertinence FROM <from clause> WHERE <where clause>`.
|
||||
*
|
||||
* The clause between `<>` are provided through the dedicated method in this class (@link{self::setSelectKey},
|
||||
* @link{self::setFromClause}), etc.).
|
||||
*
|
||||
*/
|
||||
class SearchApiQuery
|
||||
{
|
||||
private ?string $fromClause = null;
|
||||
|
@@ -71,9 +71,9 @@ interface SearchInterface
|
||||
* @param array $terms the string to search
|
||||
* @param int $start the first result (for pagination)
|
||||
* @param int $limit the number of result (for pagination)
|
||||
* @param string $format The format for result
|
||||
* @param "html"|"json" $format The format for result
|
||||
*
|
||||
* @return string, an HTML string
|
||||
* @return string|array a string if format is html, an array if format is json
|
||||
*/
|
||||
public function renderResult(array $terms, $start = 0, $limit = 50, array $options = [], $format = 'html');
|
||||
|
||||
|
@@ -16,7 +16,7 @@ use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Repository\UserACLAwareRepositoryInterface;
|
||||
use Chill\MainBundle\Security\ParentRoleHelper;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
||||
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||
use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
@@ -34,7 +34,7 @@ use function get_class;
|
||||
*/
|
||||
class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
{
|
||||
private CenterResolverDispatcherInterface $centerResolverDispatcher;
|
||||
private CenterResolverManagerInterface $centerResolverManager;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
@@ -45,13 +45,13 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
private UserACLAwareRepositoryInterface $userACLAwareRepository;
|
||||
|
||||
public function __construct(
|
||||
CenterResolverDispatcherInterface $centerResolverDispatcher,
|
||||
CenterResolverManagerInterface $centerResolverManager,
|
||||
LoggerInterface $logger,
|
||||
ScopeResolverDispatcher $scopeResolverDispatcher,
|
||||
UserACLAwareRepositoryInterface $userACLAwareRepository,
|
||||
ParentRoleHelper $parentRoleHelper
|
||||
) {
|
||||
$this->centerResolverDispatcher = $centerResolverDispatcher;
|
||||
$this->centerResolverManager = $centerResolverManager;
|
||||
$this->logger = $logger;
|
||||
$this->scopeResolverDispatcher = $scopeResolverDispatcher;
|
||||
$this->userACLAwareRepository = $userACLAwareRepository;
|
||||
@@ -63,7 +63,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
*
|
||||
* @param User $user The user
|
||||
* @param array $centers a list of centers which are going to be filtered
|
||||
* @param Center|string $role
|
||||
* @param mixed $role
|
||||
*/
|
||||
public function filterReachableCenters(User $user, array $centers, $role): array
|
||||
{
|
||||
@@ -113,13 +113,14 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
* Get reachable Centers for the given user, role,
|
||||
* and optionally Scope.
|
||||
*
|
||||
* @return array|Center[]
|
||||
* @return list<Center>
|
||||
*/
|
||||
public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array
|
||||
{
|
||||
if ($role instanceof Role) {
|
||||
$role = $role->getRole();
|
||||
}
|
||||
/** @var array<string, Center> $centers */
|
||||
$centers = [];
|
||||
|
||||
foreach ($user->getGroupCenters() as $groupCenter) {
|
||||
@@ -129,13 +130,13 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
//check that the role is in the reachable roles
|
||||
if ($this->isRoleReached($role, $roleScope->getRole())) {
|
||||
if (null === $scope) {
|
||||
$centers[] = $groupCenter->getCenter();
|
||||
$centers[spl_object_hash($groupCenter->getCenter())] = $groupCenter->getCenter();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ($scope->getId() === $roleScope->getScope()->getId()) {
|
||||
$centers[] = $groupCenter->getCenter();
|
||||
$centers[spl_object_hash($groupCenter->getCenter())] = $groupCenter->getCenter();
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -143,7 +144,7 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
}
|
||||
}
|
||||
|
||||
return $centers;
|
||||
return array_values($centers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,12 +195,8 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
*
|
||||
* @return array|Scope[]
|
||||
*/
|
||||
public function getReachableScopes(UserInterface $user, string $role, $center): array
|
||||
public function getReachableScopes(UserInterface $user, string $role, Center|array $center): array
|
||||
{
|
||||
if ($role instanceof Role) {
|
||||
$role = $role->getRole();
|
||||
}
|
||||
|
||||
return $this->getReachableCircles($user, $role, $center);
|
||||
}
|
||||
|
||||
@@ -252,27 +249,15 @@ class AuthorizationHelper implements AuthorizationHelperInterface
|
||||
*/
|
||||
public function userHasAccess(User $user, $entity, $attribute)
|
||||
{
|
||||
$center = $this->centerResolverDispatcher->resolveCenter($entity);
|
||||
$centers = $this->centerResolverManager->resolveCenters($entity);
|
||||
|
||||
if (is_iterable($center)) {
|
||||
foreach ($center as $c) {
|
||||
if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) {
|
||||
return true;
|
||||
}
|
||||
foreach ($centers as $c) {
|
||||
if ($this->userHasAccessForCenter($user, $c, $entity, $attribute)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($center instanceof Center) {
|
||||
return $this->userHasAccessForCenter($user, $center, $entity, $attribute);
|
||||
}
|
||||
|
||||
if (null === $center) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException('could not resolver a center');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -21,12 +21,12 @@ interface AuthorizationHelperInterface
|
||||
* Get reachable Centers for the given user, role,
|
||||
* and optionnaly Scope.
|
||||
*
|
||||
* @return Center[]
|
||||
* @return list<Center>
|
||||
*/
|
||||
public function getReachableCenters(UserInterface $user, string $role, ?Scope $scope = null): array;
|
||||
|
||||
/**
|
||||
* @param array|Center|Center[] $center
|
||||
* @param Center|list<Center> $center
|
||||
*/
|
||||
public function getReachableScopes(UserInterface $user, string $role, $center): array;
|
||||
public function getReachableScopes(UserInterface $user, string $role, Center|array $center): array;
|
||||
}
|
||||
|
@@ -97,6 +97,13 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw
|
||||
);
|
||||
$data['validFrom'] = $address->getValidFrom();
|
||||
$data['validTo'] = $address->getValidTo();
|
||||
$data['refStatus'] = $address->getRefStatus();
|
||||
$data['point'] = $this->normalizer->normalize(
|
||||
$address->getPoint(),
|
||||
$format,
|
||||
[AbstractNormalizer::GROUPS => ['read']]
|
||||
);
|
||||
$data['isNoAddress'] = $address->isNoAddress();
|
||||
} elseif ('docgen' === $format) {
|
||||
$dateContext = array_merge($context, ['docgen:expects' => DateTimeInterface::class]);
|
||||
$data['validFrom'] = $this->normalizer->normalize($address->getValidFrom(), $format, $dateContext);
|
||||
|
@@ -24,12 +24,18 @@ class AddressReferenceBEFromBestAddress
|
||||
|
||||
private AddressReferenceBaseImporter $baseImporter;
|
||||
|
||||
private AddressToReferenceMatcher $addressToReferenceMatcher;
|
||||
|
||||
private HttpClientInterface $client;
|
||||
|
||||
public function __construct(HttpClientInterface $client, AddressReferenceBaseImporter $baseImporter)
|
||||
{
|
||||
public function __construct(
|
||||
HttpClientInterface $client,
|
||||
AddressReferenceBaseImporter $baseImporter,
|
||||
AddressToReferenceMatcher $addressToReferenceMatcher
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->baseImporter = $baseImporter;
|
||||
$this->addressToReferenceMatcher = $addressToReferenceMatcher;
|
||||
}
|
||||
|
||||
public function import(string $lang, array $lists): void
|
||||
@@ -89,16 +95,18 @@ class AddressReferenceBEFromBestAddress
|
||||
$record['municipality_objectid'],
|
||||
$record['postal_info_objectid'],
|
||||
$record['streetname'],
|
||||
$record['housenumber'] . $record['boxnumber'],
|
||||
$record['housenumber'] .($record['boxnumber'] !== '' ? ' bte '. $record['boxnumber'] : ''),
|
||||
'bestaddress.' . $list,
|
||||
(float) $record['X'],
|
||||
(float) $record['Y'],
|
||||
(float) $record['X'],
|
||||
3812
|
||||
);
|
||||
}
|
||||
|
||||
$this->baseImporter->finalize();
|
||||
|
||||
$this->addressToReferenceMatcher->checkAddressesMatchingReferences();
|
||||
|
||||
gzclose($uncompressedStream);
|
||||
}
|
||||
}
|
||||
|
@@ -22,12 +22,15 @@ class AddressReferenceFromBano
|
||||
{
|
||||
private AddressReferenceBaseImporter $baseImporter;
|
||||
|
||||
private AddressToReferenceMatcher $addressToReferenceMatcher;
|
||||
|
||||
private HttpClientInterface $client;
|
||||
|
||||
public function __construct(HttpClientInterface $client, AddressReferenceBaseImporter $baseImporter)
|
||||
public function __construct(HttpClientInterface $client, AddressReferenceBaseImporter $baseImporter, AddressToReferenceMatcher $addressToReferenceMatcher)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->baseImporter = $baseImporter;
|
||||
$this->addressToReferenceMatcher = $addressToReferenceMatcher;
|
||||
}
|
||||
|
||||
public function import(string $departementNo): void
|
||||
@@ -82,6 +85,8 @@ class AddressReferenceFromBano
|
||||
|
||||
$this->baseImporter->finalize();
|
||||
|
||||
$this->addressToReferenceMatcher->checkAddressesMatchingReferences();
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Service\Import;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Mark existing addresses as to be reviewed regarding the
|
||||
* address reference
|
||||
*/
|
||||
final class AddressToReferenceMatcher
|
||||
{
|
||||
private Connection $connection;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private const LOG_PREFIX = '[address_to_reference_matcher] ';
|
||||
|
||||
private const SQL_MARK_TO_REVIEW_ADDRESS_UNMATCHING = <<<'SQL'
|
||||
UPDATE chill_main_address a SET refstatus = '{{ to_review }}', refstatuslastupdate = NOW()
|
||||
FROM chill_main_address_reference ar
|
||||
WHERE
|
||||
a.addressreference_id = ar.id
|
||||
-- restrict only on active addresses
|
||||
AND (a.validto IS NULL OR a.validto >= NOW())
|
||||
-- only addresses that are marked matching or "to review", but before the update
|
||||
AND
|
||||
(a.refstatus LIKE '{{ matching }}'
|
||||
OR (a.refstatus LIKE '{{ reviewed }}' AND a.refstatuslastupdate < ar.updatedat))
|
||||
AND (
|
||||
a.postcode_id != ar.postcode_id
|
||||
OR a.street != ar.street
|
||||
OR a.streetnumber != ar.streetnumber
|
||||
OR ROUND(ST_X(a.point) * 1000000) <> ROUND(ST_X(ar.point) * 1000000)
|
||||
OR ROUND(ST_Y(a.point) * 1000000) <> ROUND(ST_Y(ar.point) * 1000000)
|
||||
)
|
||||
SQL;
|
||||
|
||||
private const SQL_MARK_MATCHING_ADDRESSES_REVIEWED_OR_TO_REVIEW = <<<'SQL'
|
||||
UPDATE chill_main_address a SET refstatus = '{{ matching }}', refstatuslastupdate = NOW()
|
||||
FROM chill_main_address_reference ar
|
||||
WHERE
|
||||
a.addressreference_id = ar.id
|
||||
-- restrict only on active addresses
|
||||
AND (a.validto IS NULL OR a.validto >= NOW())
|
||||
AND a.refstatus IN ('{{ to_review }}', '{{ reviewed }}')
|
||||
AND a.postcode_id = ar.postcode_id
|
||||
AND a.street = ar.street
|
||||
AND a.streetnumber = ar.streetnumber
|
||||
AND ROUND(ST_X(a.point) * 1000000) = ROUND(ST_X(ar.point) * 1000000)
|
||||
AND ROUND(ST_Y(a.point) * 1000000) = ROUND(ST_Y(ar.point) * 1000000)
|
||||
SQL;
|
||||
|
||||
private const SUBSTITUTES = [
|
||||
'{{ to_review }}' => Address::ADDR_REFERENCE_STATUS_TO_REVIEW,
|
||||
'{{ matching }}' => Address::ADDR_REFERENCE_STATUS_MATCH,
|
||||
'{{ reviewed }}' => Address::ADDR_REFERENCE_STATUS_REVIEWED
|
||||
];
|
||||
|
||||
public function __construct(Connection $connection, LoggerInterface $logger)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function checkAddressesMatchingReferences(): void
|
||||
{
|
||||
$this->logger->notice(self::LOG_PREFIX.'Starting addresses matching');
|
||||
|
||||
$this->connection->transactional(function () {
|
||||
$markedAsMatching = $this->connection->executeStatement(
|
||||
strtr(self::SQL_MARK_MATCHING_ADDRESSES_REVIEWED_OR_TO_REVIEW, self::SUBSTITUTES)
|
||||
);
|
||||
|
||||
$markedAsToReview = $this->connection->executeStatement(
|
||||
strtr(self::SQL_MARK_TO_REVIEW_ADDRESS_UNMATCHING, self::SUBSTITUTES)
|
||||
);
|
||||
|
||||
$this->logger->info(self::LOG_PREFIX.'Executed address matching', [
|
||||
'marked_as_matching' => $markedAsMatching,
|
||||
'marked_as_to_review' => $markedAsToReview,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
@@ -13,6 +13,8 @@ namespace Chill\MainBundle\Templating\Entity;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
use function array_merge;
|
||||
@@ -38,8 +40,10 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
|
||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||
|
||||
public function __construct(EngineInterface $templating, TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
public function __construct(
|
||||
EngineInterface $templating,
|
||||
TranslatableStringHelperInterface $translatableStringHelper
|
||||
) {
|
||||
$this->templating = $templating;
|
||||
$this->translatableStringHelper = $translatableStringHelper;
|
||||
}
|
||||
@@ -58,6 +62,9 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function renderLines(Address $addr, bool $includeCityLine = true, bool $includeCountry = true): array
|
||||
{
|
||||
$lines = [];
|
||||
@@ -91,18 +98,18 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_filter($lines, static fn ($l) => null !== $l));
|
||||
return array_values(array_filter($lines, static fn ($l) => '' !== (string) $l));
|
||||
}
|
||||
|
||||
public function renderStreetLine(Address $addr): ?string
|
||||
{
|
||||
if (null !== $addr->getStreet() && $addr->getStreet() !== '') {
|
||||
if ('' !== $addr->getStreet()) {
|
||||
$street = $addr->getStreet();
|
||||
} else {
|
||||
$street = '';
|
||||
}
|
||||
|
||||
if (null !== $addr->getStreetNumber() && $addr->getStreetNumber() !== '') {
|
||||
if ('' !== $addr->getStreetNumber()) {
|
||||
$streetNumber = $addr->getStreetNumber();
|
||||
} else {
|
||||
$streetNumber = '';
|
||||
@@ -133,7 +140,7 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
|
||||
private function renderBuildingLine(Address $addr): ?string
|
||||
{
|
||||
if (null !== $addr->getBuildingName() && $addr->getBuildingName() !== '') {
|
||||
if ($addr->getBuildingName() !== '') {
|
||||
$building = $addr->getBuildingName();
|
||||
} else {
|
||||
$building = '';
|
||||
@@ -157,7 +164,7 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
return $res;
|
||||
}
|
||||
|
||||
private function renderCityLine($addr): string
|
||||
private function renderCityLine(Address $addr): string
|
||||
{
|
||||
if (null !== $addr->getPostcode()) {
|
||||
$res = strtr('{postcode} {label}', [
|
||||
@@ -165,11 +172,9 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
'{label}' => $addr->getPostcode()->getName(),
|
||||
]);
|
||||
|
||||
if (null !== $addr->getPostCode()->getCountry()->getCountryCode()) {
|
||||
if ($addr->getPostCode()->getCountry()->getCountryCode() === 'FR') {
|
||||
if ($addr->getDistribution()) {
|
||||
$res = $res . ' ' . $addr->getDistribution();
|
||||
}
|
||||
if ($addr->getPostcode()->getCountry()->getCountryCode() === 'FR') {
|
||||
if ('' !== $addr->getDistribution()) {
|
||||
$res = $res . ' ' . $addr->getDistribution();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,35 +182,35 @@ class AddressRender implements ChillEntityRenderInterface
|
||||
return $res ?? '';
|
||||
}
|
||||
|
||||
private function renderCountryLine($addr): ?string
|
||||
private function renderCountryLine(Address $addr): ?string
|
||||
{
|
||||
return $this->translatableStringHelper->localize(
|
||||
$addr->getPostCode()->getCountry()->getName()
|
||||
$addr->getPostcode()->getCountry()->getName()
|
||||
);
|
||||
}
|
||||
|
||||
private function renderDeliveryLine($addr): ?string
|
||||
private function renderDeliveryLine(Address $addr): string
|
||||
{
|
||||
return $addr->getExtra();
|
||||
}
|
||||
|
||||
private function renderIntraBuildingLine($addr): ?string
|
||||
private function renderIntraBuildingLine(Address $addr): ?string
|
||||
{
|
||||
$arr = [];
|
||||
|
||||
if ($addr->getFlat()) {
|
||||
if ('' !== $addr->getFlat()) {
|
||||
$arr[] = 'appart ' . $addr->getFlat();
|
||||
}
|
||||
|
||||
if ($addr->getFloor()) {
|
||||
if ('' !== $addr->getFloor()) {
|
||||
$arr[] = 'ét ' . $addr->getFloor();
|
||||
}
|
||||
|
||||
if ($addr->getCorridor()) {
|
||||
if ('' !== $addr->getCorridor()) {
|
||||
$arr[] = 'coul ' . $addr->getCorridor();
|
||||
}
|
||||
|
||||
if ($addr->getSteps()) {
|
||||
if ('' !== $addr->getSteps()) {
|
||||
$arr[] = 'esc ' . $addr->getSteps();
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Controller;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Repository\AddressRepository;
|
||||
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class AddressToReferenceMatcherControllerTest extends WebTestCase
|
||||
{
|
||||
use PrepareClientTrait;
|
||||
|
||||
private AddressRepository $addressRepository;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->addressRepository = self::$container->get(AddressRepository::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider addressToReviewProvider
|
||||
*/
|
||||
public function testMarkAddressAsReviewed(int $addressId): void
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request('POST', "/api/1.0/main/address/reference-match/${addressId}/set/reviewed");
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
||||
$address = $this->addressRepository->find($addressId);
|
||||
|
||||
$this->assertEquals(Address::ADDR_REFERENCE_STATUS_REVIEWED, $address->getRefStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider addressUnsyncedProvider
|
||||
*/
|
||||
public function testSyncAddressWithReference(int $addressId): void
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request('POST', "/api/1.0/main/address/reference-match/${addressId}/sync-with-reference");
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
|
||||
$address = $this->addressRepository->find($addressId);
|
||||
|
||||
$this->assertEquals(Address::ADDR_REFERENCE_STATUS_MATCH, $address->getRefStatus());
|
||||
$this->assertEquals($address->getAddressReference()->getStreet(), $address->getStreet());
|
||||
$this->assertEquals($address->getAddressReference()->getStreetNumber(), $address->getStreetNumber());
|
||||
$this->assertEquals($address->getAddressReference()->getPoint()->toWKT(), $address->getPoint()->toWKT());
|
||||
}
|
||||
|
||||
public static function addressToReviewProvider(): iterable
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$nb = $em->createQuery('SELECT count(a) FROM '.Address::class.' a')
|
||||
->getSingleScalarResult();
|
||||
|
||||
if (0 === $nb) {
|
||||
throw new \RuntimeException("There aren't any address with a ref status 'matched'");
|
||||
}
|
||||
|
||||
/** @var Address $address */
|
||||
$address = $em->createQuery('SELECT a FROM '.Address::class.' a')
|
||||
->setFirstResult(rand(0, $nb))
|
||||
->setMaxResults(1)
|
||||
->getSingleResult();
|
||||
|
||||
$address->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW);
|
||||
$em->flush();
|
||||
|
||||
yield [$address->getId()];
|
||||
}
|
||||
|
||||
public static function addressUnsyncedProvider(): iterable
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$nb = $em->createQuery('SELECT count(a) FROM '.AddressReference::class.' a')
|
||||
->getSingleScalarResult();
|
||||
|
||||
if (0 === $nb) {
|
||||
throw new \RuntimeException("There isn't any address reference");
|
||||
}
|
||||
|
||||
$ref = $em->createQuery('SELECT a FROM '.AddressReference::class.' a')
|
||||
->setMaxResults(1)
|
||||
->setFirstResult(rand(0, $nb))
|
||||
->getSingleResult();
|
||||
|
||||
$address = Address::createFromAddressReference($ref);
|
||||
|
||||
// make the address dirty
|
||||
$address->setStreet('tagada')
|
||||
->setStreetNumber('-250')
|
||||
->setPoint(Point::fromLonLat(0, 0))
|
||||
->setRefStatus(Address::ADDR_REFERENCE_STATUS_TO_REVIEW);
|
||||
|
||||
$em->persist($address);
|
||||
$em->flush();
|
||||
|
||||
yield [$address->getId()];
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\MainBundle\Tests\Controller;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class GeographicalUnitByAddressApiControllerTest extends WebTestCase
|
||||
{
|
||||
use PrepareClientTrait;
|
||||
|
||||
/**
|
||||
* @dataProvider generateRandomAddress
|
||||
*/
|
||||
public function testGetGeographicalUnitCoveringAddress(int $addressId): void
|
||||
{
|
||||
$client = $this->getClientAuthenticated();
|
||||
|
||||
$client->request('GET', '/api/1.0/main/geographical-unit/by-address/'.$addressId.'.json');
|
||||
|
||||
$this->assertResponseIsSuccessful();
|
||||
}
|
||||
|
||||
public static function generateRandomAddress(): iterable
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$nb = $em->createQuery('SELECT COUNT(a) FROM '.Address::class.' a')->getSingleScalarResult();
|
||||
/** @var \Chill\MainBundle\Entity\Address $random */
|
||||
$random = $em->createQuery('SELECT a FROM '.Address::class.' a')
|
||||
->setFirstResult(rand(0, $nb))
|
||||
->setMaxResults(1)
|
||||
->getSingleResult();
|
||||
|
||||
yield [$random->getId()];
|
||||
}
|
||||
}
|
@@ -99,7 +99,7 @@ final class AddressReferenceBaseImporterTest extends KernelTestCase
|
||||
'abcc guessed fixed'
|
||||
);
|
||||
|
||||
$this->assertCount('1', $addresses);
|
||||
$this->assertCount(1, $addresses);
|
||||
$this->assertEquals('Rue test abccc guessed fixed', $addresses[0]->getStreet());
|
||||
$this->assertEquals($previousAddressId, $addresses[0]->getId());
|
||||
}
|
||||
|
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Services\Import;
|
||||
|
||||
use Chill\MainBundle\Doctrine\Model\Point;
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Chill\MainBundle\Entity\AddressReference;
|
||||
use Chill\MainBundle\Entity\PostalCode;
|
||||
use Chill\MainBundle\Repository\AddressReferenceRepository;
|
||||
use Chill\MainBundle\Repository\CountryRepository;
|
||||
use Chill\MainBundle\Service\Import\AddressReferenceBaseImporter;
|
||||
use Chill\MainBundle\Service\Import\AddressToReferenceMatcher;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
class AddressToReferenceMatcherTest extends KernelTestCase
|
||||
{
|
||||
private AddressToReferenceMatcher $addressToReferenceMatcher;
|
||||
|
||||
private AddressReferenceRepository $addressReferenceRepository;
|
||||
|
||||
private CountryRepository $countryRepository;
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private AddressReferenceBaseImporter $addressReferenceBaseImporter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
|
||||
$this->addressToReferenceMatcher = self::$container->get(AddressToReferenceMatcher::class);
|
||||
$this->addressReferenceRepository = self::$container->get(AddressReferenceRepository::class);
|
||||
$this->countryRepository = self::$container->get(CountryRepository::class);
|
||||
$this->addressReferenceBaseImporter = self::$container->get(AddressReferenceBaseImporter::class);
|
||||
$this->entityManager = self::$container->get(EntityManagerInterface::class);
|
||||
}
|
||||
|
||||
public function testCheckAddressesMatchingReferences(): void
|
||||
{
|
||||
if (null === $belgium = $this->countryRepository->findOneBy(['countryCode' => 'BE'])) {
|
||||
throw new \RuntimeException('Belgium not found');
|
||||
}
|
||||
|
||||
$postalCode = (new PostalCode())
|
||||
->setName('test for matcher')
|
||||
->setPostalCodeSource('test for matcher')
|
||||
->setCode('78910')
|
||||
->setRefPostalCodeId($refPostalCodeId = '78910'.uniqid())
|
||||
->setCountry($belgium)
|
||||
;
|
||||
$this->entityManager->persist($postalCode);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addressReferenceBaseImporter->importAddress(
|
||||
$refAddress = '010203_test'.uniqid(),
|
||||
$refPostalCodeId,
|
||||
'78910',
|
||||
$street = 'Rue Poulet',
|
||||
$streetNumber = '14',
|
||||
'test_matcher',
|
||||
$lat = 50.0123456789,
|
||||
$lon = 5.0123456789,
|
||||
4326
|
||||
);
|
||||
$this->addressReferenceBaseImporter->finalize();
|
||||
|
||||
if (null === $addressReference = $this->addressReferenceRepository->findOneBy(['refId' => $refAddress])) {
|
||||
throw new \RuntimeException('address reference not created');
|
||||
}
|
||||
|
||||
$address = Address::createFromAddressReference($addressReference);
|
||||
|
||||
$this->assertEquals('Rue Poulet', $address->getStreet());
|
||||
|
||||
$this->entityManager->persist($address);
|
||||
$this->entityManager->flush();
|
||||
|
||||
// we update the address
|
||||
$this->addressReferenceBaseImporter->importAddress(
|
||||
$refAddress,
|
||||
$refPostalCodeId,
|
||||
'78910',
|
||||
'Rue Poulet aux amandes',
|
||||
'14',
|
||||
'test_matcher',
|
||||
50.01234456789,
|
||||
5.0123456789,
|
||||
4326
|
||||
);
|
||||
$this->addressReferenceBaseImporter->finalize();
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->addressToReferenceMatcher->checkAddressesMatchingReferences();
|
||||
|
||||
$this->entityManager->refresh($address);
|
||||
|
||||
$this->assertEquals('to_review', $address->getRefStatus());
|
||||
|
||||
// we update the address
|
||||
$this->addressReferenceBaseImporter->importAddress(
|
||||
$refAddress,
|
||||
$refPostalCodeId,
|
||||
'78910',
|
||||
$street,
|
||||
$streetNumber,
|
||||
'test_matcher',
|
||||
$lat,
|
||||
$lon,
|
||||
4326
|
||||
);
|
||||
$this->addressReferenceBaseImporter->finalize();
|
||||
|
||||
$this->addressToReferenceMatcher->checkAddressesMatchingReferences();
|
||||
|
||||
$this->entityManager->refresh($address);
|
||||
|
||||
$this->assertEquals('Rue Poulet', $address->getStreet());
|
||||
$this->assertEquals('match', $address->getRefStatus());
|
||||
}
|
||||
}
|
@@ -18,6 +18,7 @@ use Chill\MainBundle\Templating\Entity\AddressRender;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Iterator;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||
use Symfony\Component\Templating\EngineInterface;
|
||||
|
||||
/**
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Workflow;
|
||||
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||
|
||||
interface EntityWorkflowHandlerInterface
|
||||
|
@@ -75,6 +75,7 @@ module.exports = function(encore, entries)
|
||||
encore.addEntry('mod_wopi_link', __dirname + '/Resources/public/module/wopi-link/index.js');
|
||||
encore.addEntry('mod_pick_postal_code', __dirname + '/Resources/public/module/pick-postal-code/index.js');
|
||||
encore.addEntry('mod_pick_rolling_date', __dirname + '/Resources/public/module/pick-rolling-date/index.js');
|
||||
encore.addEntry('mod_address_details', __dirname + '/Resources/public/module/address-details/index');
|
||||
|
||||
// Vue entrypoints
|
||||
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
|
||||
|
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230306142148 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add columns refStatus and refStatusLastUpdate to Address';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD refStatus TEXT DEFAULT \'match\' NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD refStatusLastUpdate TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL');
|
||||
|
||||
// we must set the last status update to the address reference date to avoid inconsistencies
|
||||
$this->addSql('UPDATE chill_main_address a SET refStatusLastUpdate = COALESCE(r.updatedat, r.createdat, \'1970-01-01\'::timestamp) FROM chill_main_address_reference r WHERE a.addressreference_id = r.id');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP refStatus');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP refStatusLastUpdate');
|
||||
}
|
||||
}
|
116
src/Bundle/ChillMainBundle/migrations/Version20230306145728.php
Normal file
116
src/Bundle/ChillMainBundle/migrations/Version20230306145728.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230306145728 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'fix inconsistencies in chill_main_address table';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD createdBy_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD updatedBy_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER street TYPE TEXT');
|
||||
$this->addSql('UPDATE chill_main_address SET street=\'\' WHERE street IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER street SET DEFAULT \'\'');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER streetnumber TYPE TEXT');
|
||||
$this->addSql('UPDATE chill_main_address SET streetnumber=\'\' WHERE streetnumber IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER streetnumber SET DEFAULT \'\'');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER floor SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET floor=\'\' WHERE floor IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER floor SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER corridor SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET corridor=\'\' WHERE corridor IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER corridor SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER steps SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET steps=\'\' WHERE steps IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER steps SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingname TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingname SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET buildingname=\'\' WHERE buildingname IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingname SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER flat SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET flat=\'\' WHERE flat IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER flat SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET distribution=\'\' WHERE distribution IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address SET extra=\'\' WHERE extra IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra SET NOT NULL');
|
||||
$this->addSql('UPDATE chill_main_address SET confidential=FALSE WHERE confidential IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER confidential SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER refstatuslastupdate TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address.point IS \'(DC2Type:point)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address.createdAt IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address.updatedAt IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address.refStatusLastUpdate IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F63174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT FK_165051F665FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_165051F63174800F ON chill_main_address (createdBy_id)');
|
||||
$this->addSql('CREATE INDEX IDX_165051F665FF1AEC ON chill_main_address (updatedBy_id)');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address_reference.point IS \'(DC2Type:point)\'');
|
||||
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->throwIrreversibleMigrationException('down method is not double-checked');
|
||||
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F63174800F');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT FK_165051F665FF1AEC');
|
||||
$this->addSql('DROP INDEX IDX_165051F63174800F');
|
||||
$this->addSql('DROP INDEX IDX_165051F665FF1AEC');
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD customs JSONB DEFAULT \'[]\'');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP createdAt');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP updatedAt');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP createdBy_id');
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP updatedBy_id');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingName TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingName DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER buildingName DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER confidential SET DEFAULT false');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER confidential DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER corridor DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER corridor DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER distribution DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER extra DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER flat DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER flat DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER floor DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER floor DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER isNoAddress SET DEFAULT false');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER point TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER refStatusLastUpdate TYPE TIMESTAMP(0) WITHOUT TIME ZONE');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER steps DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER steps DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER street TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER street DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER streetNumber TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER streetNumber DROP DEFAULT');
|
||||
$this->addSql('COMMENT ON COLUMN chill_main_address.refstatuslastupdate IS NULL');
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20230306151218 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'fix inconsistencies in chill_main_address_reference table';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER refid TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER refid SET DEFAULT \'\'');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address_reference SET street = \'\' WHERE street IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetnumber TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetnumber SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address_reference SET streetnumber = \'\' WHERE streetnumber IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetnumber SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalitycode TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalitycode SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address_reference SET municipalitycode = \'\' WHERE municipalitycode IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalitycode SET NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source TYPE TEXT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source SET DEFAULT \'\'');
|
||||
$this->addSql('UPDATE chill_main_address_reference SET source = \'\' WHERE source IS NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source SET NOT NULL');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->throwIrreversibleMigrationException('not double-checked');
|
||||
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalityCode TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalityCode DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER municipalityCode DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER refId TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER refId DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER source DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER street DROP NOT NULL');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetNumber TYPE VARCHAR(255)');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetNumber DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_address_reference ALTER streetNumber DROP NOT NULL');
|
||||
}
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
"This program is free software: you can redistribute it and/or modify it under the terms of the <strong>GNU Affero General Public License</strong>": "Ce programme est un logiciel libre: vous pouvez le redistribuer et/ou le modifier selon les termes de la licence <strong>GNU Affero GPL</strong>"
|
||||
User manual: Manuel d'utilisation
|
||||
Search: Rechercher
|
||||
"Search persons, ...": "Recherche des personnes, ..."
|
||||
Person name: Nom / Prénom de la personne
|
||||
"Search persons, ...": "Recherche des usagers, ..."
|
||||
Person name: Nom / Prénom de l'usager
|
||||
Login: Connexion
|
||||
Logout: Se déconnecter
|
||||
Bad credentials.: Le mot de passe et le nom d'utilisateur ne correspondent pas.
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user