diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d587e43b..a0612475a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to ## Unreleased +* vuejs: translate in French all multiselect widgets +* [address] define address lines according postal standards for France and Belgium (default) and change AddressRender, chill_entity_render_box and AddressRenderBox.vue * [household] change translations (champs-libres/departement-de-la-vendee/accent-suivi-developpement#109) * [household] add address i18n in household component (champs-libres/departement-de-la-vendee/accent-suivi-developpement#158) * [household] add on the fly i18n in household component @@ -20,6 +22,9 @@ and this project adheres to * [household] household member editor: remove markNoAddress button (champs-libres/departement-de-la-vendee/accent-suivi-developpement#109) * [person]: ordering fields in add person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/61) * [person]: Add email and alt names in add person (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/61) +* [accompanyingCourse] Add a delete action and delete buttons to delete a accompanying course when step = DRAFT (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/64) +* [accompanyingCourse] Add a administrative location in the accompanying course, set the user current location as default, allow to select a location in a select field and do not allow to confirm the accompanying course if location is empty. +* [accompanyingCourse] Add the administrative location in the available variables for document generation * AddAddress: optimize loading: wait for the user finish typing; * UserPicker: fix bug with deprecated role * docgen: add base context + tests diff --git a/composer.json b/composer.json index 1cecf0852..75580b309 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,7 @@ "drupol/php-conventions": "^5", "fakerphp/faker": "^1.13", "nelmio/alice": "^3.8", + "phpspec/prophecy-phpunit": "^2.0", "phpstan/phpstan-strict-rules": "^1.0", "phpunit/phpunit": ">= 7.5", "symfony/debug-bundle": "^5.1", diff --git a/phpstan-types.neon b/phpstan-types.neon index 98d17b666..949ff774a 100644 --- a/phpstan-types.neon +++ b/phpstan-types.neon @@ -315,11 +315,6 @@ parameters: count: 1 path: src/Bundle/ChillMainBundle/Security/PasswordRecover/TokenManager.php - - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" - count: 3 - path: src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php - - message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#" count: 1 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 208c915ae..89cb80635 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,7 +6,6 @@ backupGlobals="false" colors="true" bootstrap="tests/app/tests/bootstrap.php" - stopOnFailure="true" > diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue index 49b53c8cb..f5057eb25 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue @@ -12,7 +12,7 @@
    -
  • +
  • {{ p.text }}
diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue index 50eb14799..b8249ccc5 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/Location.vue @@ -15,13 +15,15 @@ :searchable="true" :placeholder="$t('activity.choose_location')" :custom-label="customLabel" + :select-label="$t('multiselect.select_label')" + :deselect-label="$t('multiselect.deselect_label')" + :selected-label="$t('multiselect.selected_label')" :options="availableLocations" group-values="locations" group-label="locationGroup" v-model="location" > -
@@ -32,7 +34,6 @@ import { mapState, mapGetters } from "vuex"; import VueMultiselect from "vue-multiselect"; import NewLocation from "./Location/NewLocation.vue"; -import { getLocations, getLocationTypeByDefaultFor, getUserCurrentLocation } from "../api.js"; export default { name: "Location", diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue index 92aa7be0e..e585200c0 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue @@ -9,9 +9,9 @@ @@ -21,18 +21,18 @@ label="text" track-by="id" open-direction="bottom" - v-bind:close-on-select="true" - v-bind:preserve-search="false" - v-bind:reset-after="true" - v-bind:hide-selected="true" - v-bind:taggable="false" - v-bind:multiple="false" - v-bind:searchable="true" - v-bind:allow-empty="true" - v-bind:show-labels="false" - v-bind:loading="issueIsLoading" - v-bind:placeholder="$t('activity.choose_other_social_issue')" - v-bind:options="socialIssuesOther" + :close-on-select="true" + :preserve-search="false" + :reset-after="true" + :hide-selected="true" + :taggable="false" + :multiple="false" + :searchable="true" + :allow-empty="true" + :show-labels="false" + :loading="issueIsLoading" + :placeholder="$t('activity.choose_other_social_issue')" + :options="socialIssuesOther" @select="addIssueInList"> @@ -58,9 +58,9 @@ diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js index fa7da3203..509e3b0d9 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/i18n.js @@ -1,4 +1,5 @@ import { personMessages } from 'ChillPersonAssets/vuejs/_js/i18n' +import { multiSelectMessages } from 'ChillMainAssets/vuejs/_js/i18n' const activityMessages = { fr: { @@ -33,12 +34,11 @@ const activityMessages = { }, create_address: 'Créer une adresse', edit_address: "Modifier l'adresse" - } } } -Object.assign(activityMessages.fr, personMessages.fr); +Object.assign(activityMessages.fr, personMessages.fr, multiSelectMessages.fr); export { activityMessages diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/CalendarUserSelector.vue b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/CalendarUserSelector.vue index da9a9eaf8..494fde96c 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/CalendarUserSelector.vue +++ b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/CalendarUserSelector.vue @@ -13,6 +13,9 @@ :close-on-select="false" :allow-empty="true" :model-value="value" + :select-label="$t('multiselect.select_label')" + :deselect-label="$t('multiselect.deselect_label')" + :selected-label="$t('multiselect.selected_label')" @select="selectUsers" @remove="unSelectUsers" @close="coloriseSelectedValues" diff --git a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/js/i18n.js b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/js/i18n.js index f1aae5df1..2f7d15662 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/js/i18n.js +++ b/src/Bundle/ChillCalendarBundle/Resources/public/vuejs/_components/CalendarUserSelector/js/i18n.js @@ -1,13 +1,17 @@ +import { multiSelectMessages } from 'ChillMainAssets/vuejs/_js/i18n' + const calendarUserSelectorMessages = { - fr: { - choose_your_calendar_user: "Afficher les plages de disponibilités", - select_user: "Sélectionnez des calendriers", - show_my_calendar: "Afficher mon calendrier", - show_weekends: "Afficher les week-ends" - } - }; + fr: { + choose_your_calendar_user: "Afficher les plages de disponibilités", + select_user: "Sélectionnez des calendriers", + show_my_calendar: "Afficher mon calendrier", + show_weekends: "Afficher les week-ends" + } +}; - export { - calendarUserSelectorMessages - }; +Object.assign(calendarUserSelectorMessages.fr, multiSelectMessages.fr); + +export { + calendarUserSelectorMessages +}; \ No newline at end of file diff --git a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php index 66d475d89..2aff33af0 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php +++ b/src/Bundle/ChillDocGeneratorBundle/Controller/DocGeneratorTemplateController.php @@ -276,7 +276,6 @@ final class DocGeneratorTemplateController extends AbstractController fwrite($templateResource, $dataDecrypted); rewind($templateResource); } - $datas = $context->getData($template, $entity, $contextGenerationData); try { diff --git a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php index 7101e562d..7a3e4ac69 100644 --- a/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php +++ b/src/Bundle/ChillDocGeneratorBundle/GeneratorDriver/RelatorioDriver.php @@ -46,7 +46,6 @@ class RelatorioDriver implements DriverInterface 'template' => new DataPart($template, $templateName ?? uniqid('template_'), $resourceType), ]; $form = new FormDataPart($formFields); - dump(json_encode($data)); try { $response = $this->relatorioClient->request('POST', $this->url, [ diff --git a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig index 29050ce02..436f816c2 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig +++ b/src/Bundle/ChillDocGeneratorBundle/Resources/views/Admin/DocGeneratorTemplate/index.html.twig @@ -23,11 +23,7 @@ - + diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php index 91e8e6170..e70171234 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Helper/NormalizeNullValueHelper.php @@ -11,9 +11,11 @@ declare(strict_types=1); namespace Chill\DocGeneratorBundle\Serializer\Helper; +use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use function array_merge; +use function is_array; class NormalizeNullValueHelper { @@ -30,7 +32,7 @@ class NormalizeNullValueHelper $this->discriminatorValue = $discriminatorValue; } - public function normalize(array $attributes, string $format = 'docgen', ?array $context = []) + public function normalize(array $attributes, string $format = 'docgen', ?array $context = [], ?ClassMetadata $classMetadata = null) { $data = []; $data['isNull'] = true; @@ -58,7 +60,7 @@ class NormalizeNullValueHelper default: $data[$key] = $this->normalizer->normalize(null, $format, array_merge( - $context, + $this->getContextForAttribute($key, $context, $classMetadata), ['docgen:expects' => $class] )); @@ -69,4 +71,25 @@ class NormalizeNullValueHelper return $data; } + + private function getContextForAttribute(string $key, array $initialContext, ?ClassMetadata $classMetadata): array + { + if (null === $classMetadata) { + return $initialContext; + } + + $attributeMetadata = $classMetadata->getAttributesMetadata()[$key] ?? null; + + if (null !== $attributeMetadata) { + /** @var \Symfony\Component\Serializer\Mapping\AttributeMetadata $attributeMetadata */ + $initialContext = array_merge( + $initialContext, + $attributeMetadata->getNormalizationContextForGroups( + is_array($initialContext['groups']) ? $initialContext['groups'] : [$initialContext['groups']] + ) + ); + } + + return $initialContext; + } } diff --git a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php index 0a3f6e403..6851c7225 100644 --- a/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php +++ b/src/Bundle/ChillDocGeneratorBundle/Serializer/Normalizer/DocGenObjectNormalizer.php @@ -196,7 +196,7 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte $normalizer = new NormalizeNullValueHelper($this->normalizer, $typeKey, $typeValue); - return $normalizer->normalize($keys, $format, $context); + return $normalizer->normalize($keys, $format, $context, $metadata); } /** @@ -260,9 +260,13 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte /** @var AttributeMetadata $attribute */ $value = $this->propertyAccess->getValue($object, $attribute->getName()); $key = $attribute->getSerializedName() ?? $attribute->getName(); - $isTranslatable = $attribute->getNormalizationContextForGroups( - is_array($context['groups']) ? $context['groups'] : [$context['groups']] - )['is-translatable'] ?? false; + $objectContext = array_merge( + $context, + $attribute->getNormalizationContextForGroups( + is_array($context['groups']) ? $context['groups'] : [$context['groups']] + ) + ); + $isTranslatable = $objectContext['is-translatable'] ?? false; if ($isTranslatable) { $data[$key] = $this->translatableStringHelper @@ -273,7 +277,7 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte foreach ($value as $k => $v) { $arr[$k] = $this->normalizer->normalize($v, $format, array_merge( - $context, + $objectContext, $attribute->getNormalizationContextForGroups($expectedGroups) )); } @@ -281,11 +285,11 @@ class DocGenObjectNormalizer implements NormalizerAwareInterface, NormalizerInte } elseif (is_object($value)) { $data[$key] = $this->normalizer->normalize($value, $format, array_merge( - $context, + $objectContext, $attribute->getNormalizationContextForGroups($expectedGroups) )); } elseif (null === $value) { - $data[$key] = $this->normalizeNullOutputValue($format, $context, $attribute, $reflection); + $data[$key] = $this->normalizeNullOutputValue($format, $objectContext, $attribute, $reflection); } else { $data[$key] = $value; } diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php index ef7055048..178e9b183 100644 --- a/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php +++ b/src/Bundle/ChillDocGeneratorBundle/tests/Serializer/Normalizer/DocGenObjectNormalizerTest.php @@ -14,6 +14,7 @@ namespace Chill\DocGeneratorBundle\tests\Serializer\Normalizer; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Serializer\Annotation as Serializer; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -33,6 +34,49 @@ final class DocGenObjectNormalizerTest extends KernelTestCase $this->normalizer = self::$container->get(NormalizerInterface::class); } + public function testChangeContextOnAttribute() + { + $object = new TestableParentClass(); + $actual = $this->normalizer->normalize( + $object, + 'docgen', + ['groups' => 'docgen:read'] + ); + + $this->assertIsArray($actual); + $this->assertArrayHasKey('child', $actual); + $this->assertIsArray($actual['child']); + $this->assertArrayHasKey('foo', $actual['child']); + $this->assertEquals('bar', $actual['child']['foo']); + $this->assertArrayNotHasKey('baz', $actual['child']); + + // test with child = null + $object->child = null; + $actual = $this->normalizer->normalize( + $object, + 'docgen', + ['groups' => 'docgen:read'] + ); + $this->assertIsArray($actual); + $this->assertArrayHasKey('child', $actual); + $this->assertIsArray($actual['child']); + $this->assertArrayHasKey('foo', $actual['child']); + $this->assertEquals('', $actual['child']['foo']); + $this->assertArrayNotHasKey('baz', $actual['child']); + + $actual = $this->normalizer->normalize( + null, + 'docgen', + ['groups' => 'docgen:read', 'docgen:expects' => TestableParentClass::class], + ); + $this->assertIsArray($actual); + $this->assertArrayHasKey('child', $actual); + $this->assertIsArray($actual['child']); + $this->assertArrayHasKey('foo', $actual['child']); + $this->assertEquals('', $actual['child']['foo']); + $this->assertArrayNotHasKey('baz', $actual['child']); + } + public function testNormalizationBasic() { $scope = new Scope(); @@ -99,3 +143,30 @@ final class DocGenObjectNormalizerTest extends KernelTestCase $this->assertEquals($expected, $normalized, 'test normalization fo an user with null center'); } } + +class TestableParentClass +{ + /** + * @Serializer\Groups("docgen:read") + * @Serializer\Context(normalizationContext={"groups": "docgen:read:foo"}, groups={"docgen:read"}) + */ + public ?TestableChildClass $child; + + public function __construct() + { + $this->child = new TestableChildClass(); + } +} + +class TestableChildClass +{ + /** + * @Serializer\Groups("docgen:read") + */ + public string $baz = 'bloup'; + + /** + * @Serializer\Groups("docgen:read:foo") + */ + public string $foo = 'bar'; +} diff --git a/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/BaseContextDataTest.php b/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/BaseContextDataTest.php index e5a1c6d5f..feb9afd35 100644 --- a/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/BaseContextDataTest.php +++ b/src/Bundle/ChillDocGeneratorBundle/tests/Service/Context/BaseContextDataTest.php @@ -13,6 +13,7 @@ namespace Chill\DocGeneratorBundle\tests\Service\Context; use Chill\DocGeneratorBundle\Service\Context\BaseContextData; use Chill\MainBundle\Entity\User; +use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Security\Core\Security; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; @@ -23,6 +24,8 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface; */ final class BaseContextDataTest extends KernelTestCase { + use ProphecyTrait; + protected function setUp(): void { parent::setUp(); diff --git a/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml b/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml index af08cf1c8..214428bd4 100644 --- a/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillDocGeneratorBundle/translations/messages.fr.yml @@ -7,6 +7,7 @@ docgen: Context: Contexte New template: Nouveau gabarit Edit template: Modifier gabarit + test generate: Tester la génération With context: 'Avec le contexte :' diff --git a/src/Bundle/ChillMainBundle/Entity/Address.php b/src/Bundle/ChillMainBundle/Entity/Address.php index dcf0c5a96..070d40468 100644 --- a/src/Bundle/ChillMainBundle/Entity/Address.php +++ b/src/Bundle/ChillMainBundle/Entity/Address.php @@ -60,6 +60,8 @@ class Address /** * @var string|null * + * used for the CEDEX information + * * @ORM\Column(type="string", length=255, nullable=true) * @Groups({"write"}) */ diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue index c333961db..6d9c32524 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/AddressSelection.vue @@ -6,8 +6,9 @@ v-model="value" :placeholder="$t('select_address')" :tag-placeholder="$t('create_address')" - :select-label="$t('press_enter_to_select')" + :select-label="$t('multiselect.select_label')" :deselect-label="$t('create_address')" + :selected-label="$t('multiselect.selected_label')" @search-change="listenInputSearch" ref="addressSelector" @select="selectAddress" diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue index abd1cd8de..5191b3a31 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue @@ -12,8 +12,9 @@ label="value" :custom-label="transName" :placeholder="$t('select_city')" - :select-label="$t('press_enter_to_select')" + :select-label="$t('multiselect.select_label')" :deselect-label="$t('create_postal_code')" + :selected-label="$t('multiselect.selected_label')" :taggable="true" :multiple="false" @tag="addPostcode" diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CountrySelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CountrySelection.vue index c15db8d2a..c1b1d1b55 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CountrySelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CountrySelection.vue @@ -5,12 +5,13 @@ id="countrySelect" label="name" track-by="id" - v-bind:custom-label="transName" - v-bind:placeholder="$t('select_country')" - v-bind:options="sortedCountries" + :custom-label="transName" + :placeholder="$t('select_country')" + :options="sortedCountries" v-model="value" - :select-label="$t('press_enter_to_select')" - :deselect-label="$t('press_enter_to_remove')" + :select-label="$t('multiselect.select_label')" + :deselect-label="$t('multiselect.deselect_label')" + :selected-label="$t('multiselect.selected_label')" @select="selectCountry"> diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/SuggestPane.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/SuggestPane.vue index 15c77e414..798835a76 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/SuggestPane.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/SuggestPane.vue @@ -10,7 +10,7 @@

{{ $t('address_suggestions') }}

-
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js index ab0032de6..98f31cbd3 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js @@ -1,7 +1,7 @@ +import { multiSelectMessages } from 'ChillMainAssets/vuejs/_js/i18n' + const addressMessages = { fr: { - press_enter_to_select: 'Appuyer sur Entrée pour sélectionner', - press_enter_to_remove: 'Appuyer sur Entrée pour désélectionner', add_an_address_title: 'Créer une adresse', edit_an_address_title: 'Modifier une adresse', create_a_new_address: 'Créer une nouvelle adresse', @@ -48,6 +48,8 @@ const addressMessages = { } }; +Object.assign(addressMessages.fr, multiSelectMessages.fr); + export { addressMessages }; diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/AddressRenderBox.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/AddressRenderBox.vue index 475558d0c..8a069298a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/AddressRenderBox.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/AddressRenderBox.vue @@ -2,21 +2,28 @@ -

- {{ address.text }}, -

-

- {{ address.postcode.code }} {{ address.postcode.name }} -

-

- {{ address.country.name.fr }} -

+
+

+ {{ l }} +

+
+
+

+ {{ address.text }} +

+

+ {{ address.postcode.code }} {{ address.postcode.name }} +

+

+ {{ address.country.name.fr }} +

+
-
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js index 4b998f98a..1ab8eb29a 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_js/i18n.js @@ -84,3 +84,17 @@ const _createI18n = (appMessages) => { }; export { _createI18n } + +export const multiSelectMessages = { + fr: { + multiselect: { + placeholder: 'Choisir', + tag_placeholder: 'Créer un nouvel élément', + select_label: 'Appuyer sur "Entrée" pour sélectionner', + deselect_label: 'Appuyer sur "Entrée" pour désélectionner', + select_group_label: 'Appuyer sur "Entrée" pour sélectionner ce groupe', + deselect_group_label: 'Appuyer sur "Entrée" pour désélectionner ce groupe', + selected_label: 'Sélectionné' + } + } +}; \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig index 4d871404f..ea8f18fc0 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Entity/address.html.twig @@ -9,57 +9,23 @@ * with_delimiter bool add a delimiter between fragments * has_no_address bool * multiline bool multiline display - * extended_infos bool add extra informations (step, floor, etc.) + * extended_infos bool add extra informations (step, floor, etc.) DEPRECATED #} -{% macro raw(address, options, streetLine) %} - - {% if address.street is not empty %} -

{{ streetLine }}

- {% endif %} - {% if options['extended_infos'] %} - {{ _self.extended(address, options) }} - {% endif %} - {% if address.postCode is not empty %} -

- {{ address.postCode.code }} - {{ address.postCode.name }} -

-

{{ address.postCode.country.name|localize_translatable_string }}

- {% endif %} +{% macro raw(lines) %} + {% for l in lines %} +

{{ l }}

+ {% endfor %} {% endmacro %} -{% macro extended(address, options) %} - {% if address.floor is not empty %} - {{ 'address more.floor'|trans }} {{ address.floor }} - {% endif %} - {% if address.corridor is not empty %} - {{ 'address more.corridor'|trans }} {{ address.corridor }} - {% endif %} - {% if address.steps is not empty %} - {{ 'address more.steps'|trans }} {{ address.steps }} - {% endif %} - {% if address.buildingName is not empty %} - {{ 'address more.buildingName'|trans }} {{ address.buildingName }} - {% endif %} - {% if address.flat is not empty %} - {{ 'address more.flat'|trans }} {{ address.flat }} - {% endif %} - {% if address.extra is not empty %} - {{ 'address more.extra'|trans }} {{ address.extra }} - {% endif %} - {% if address.distribution is not empty %} - {{ 'address more.distribution'|trans }} {{ address.distribution }} - {% endif %} -{% endmacro %} - -{% macro inline(address, options, streetLine) %} +{% macro inline(address, options, streetLine, lines) %} {% if options['has_no_address'] == true and address.isNoAddress == true %} {% if address.postCode is not empty %}

{{ address.postCode.code }} {{ address.postCode.name }} + {{ address.distribution }}

{{ address.postCode.country.name|localize_translatable_string }}

{% endif %} @@ -68,7 +34,7 @@ {% else %} - {{ _self.raw(address, options, streetLine) }} + {{ _self.raw(lines) }} {% endif %} {{ _self.validity(address, options) }} @@ -97,7 +63,7 @@ {% if options['with_picto'] %} {% endif %} - {{ _self.inline(address, options, streetLine) }} + {{ _self.inline(address, options, streetLine, lines) }} {%- endif -%} @@ -106,7 +72,7 @@ {% if options['with_picto'] %} {% endif %} - {{ _self.inline(address, options, streetLine) }} + {{ _self.inline(address, options, streetLine, lines) }} {%- endif -%} @@ -118,20 +84,21 @@

{{ address.postCode.code }} {{ address.postCode.name }} + {{ address.distribution }}

{{ address.postCode.country.name|localize_translatable_string }}

-
+
{% endif %}
{{ 'address.consider homeless'|trans }}
- + {% else %}
{% if options['with_picto'] %} {% endif %} - {{ _self.raw(address, options, streetLine) }} + {{ _self.raw(lines) }}
{% endif %} {{ _self.validity(address, options) }} diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php index 119126a2e..0b46127b6 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/AddressNormalizer.php @@ -13,6 +13,7 @@ namespace Chill\MainBundle\Serializer\Normalizer; use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Templating\Entity\AddressRender; use DateTimeInterface; use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\AbstractNormalizer; @@ -46,6 +47,13 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw 'validTo' => DateTimeInterface::class, ]; + private AddressRender $addressRender; + + public function __construct(AddressRender $addressRender) + { + $this->addressRender = $addressRender; + } + /** * @param Address $address * @param string|null $format @@ -53,19 +61,9 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw public function normalize($address, $format = null, array $context = []) { if ($address instanceof Address) { - $text = $address->isNoAddress() ? '' : $address->getStreet() . ', ' . $address->getStreetNumber(); - - if (null !== $address->getPostCode()->getCountry()->getCountryCode()) { - if ($address->getPostCode()->getCountry()->getCountryCode() === 'FR') { - $text = $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet(); - } else { - $text = $address->isNoAddress() ? '' : $address->getStreetNumber() . ', ' . $address->getStreet(); - } - } - $data = [ 'address_id' => $address->getId(), - 'text' => $text, + 'text' => $address->isNoAddress() ? null : $this->addressRender->renderStreetLine($address, []), 'street' => $address->getStreet(), 'streetNumber' => $address->getStreetNumber(), 'postcode' => [ @@ -85,6 +83,7 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw 'buildingName' => $address->getBuildingName(), 'distribution' => $address->getDistribution(), 'extra' => $address->getExtra(), + 'lines' => $this->addressRender->renderLines($address), ]; if ('json' === $format) { diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php index 082491bd0..975a7c9f8 100644 --- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php +++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Serializer\Normalizer; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\UserJob; @@ -55,16 +56,21 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware $context, ['docgen:expects' => Center::class, 'groups' => 'docgen:read'] ); + $locationContext = array_merge( + $context, + ['docgen:expects' => Location::class, 'groups' => 'dogen:read'] + ); if (null === $user && 'docgen' === $format) { return array_merge(self::NULL_USER, [ 'user_job' => $this->normalizer->normalize(null, $format, $userJobContext), 'main_center' => $this->normalizer->normalize(null, $format, $centerContext), 'main_scope' => $this->normalizer->normalize(null, $format, $scopeContext), + 'current_location' => $this->normalizer->normalize(null, $format, $locationContext), ]); } - return [ + $data = [ 'type' => 'user', 'id' => $user->getId(), 'username' => $user->getUsername(), @@ -75,6 +81,12 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware 'main_center' => $this->normalizer->normalize($user->getMainCenter(), $format, $centerContext), 'main_scope' => $this->normalizer->normalize($user->getMainScope(), $format, $scopeContext), ]; + + if ('docgen' === $format) { + $data['current_location'] = $this->normalizer->normalize($user->getCurrentLocation(), $format, $locationContext); + } + + return $data; } public function supportsNormalization($data, $format = null, array $context = []): bool diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php index 1af5607c9..66d6e9e41 100644 --- a/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php +++ b/src/Bundle/ChillMainBundle/Templating/Entity/AddressRender.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Templating\Entity; use Chill\MainBundle\Entity\Address; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Symfony\Component\Templating\EngineInterface; use function array_merge; @@ -26,14 +27,18 @@ class AddressRender implements ChillEntityRenderInterface 'with_delimiter' => false, 'has_no_address' => false, 'multiline' => true, + /* deprecated */ 'extended_infos' => false, ]; private EngineInterface $templating; - public function __construct(EngineInterface $templating) + private TranslatableStringHelper $translatableStringHelper; + + public function __construct(EngineInterface $templating, TranslatableStringHelper $translatableStringHelper) { $this->templating = $templating; + $this->translatableStringHelper = $translatableStringHelper; } /** @@ -50,43 +55,49 @@ class AddressRender implements ChillEntityRenderInterface 'streetLine' => $this->renderStreetLine($addr), 'render' => $options['render'] ?? 'bloc', 'options' => $options, + 'lines' => $this->renderLines($addr), ]); } /** * @param Address addr * @param mixed $addr + * + * @return string[] */ - public function renderString($addr, array $options): string + public function renderLines($addr): array { $lines = []; - $lines[0] = $this->renderStreetLine($addr); - - if (!empty($addr->getPostcode())) { - $lines[1] = strtr('{postcode} {label}', [ - '{postcode}' => $addr->getPostcode()->getCode(), - '{label}' => $addr->getPostcode()->getName(), - ]); + if (null !== $addr->getPostCode()) { + if ($addr->getPostCode()->getCountry()->getCountryCode() === 'FR') { + $lines[] = $this->renderIntraBuildingLine($addr); + $lines[] = $this->renderBuildingLine($addr); + $lines[] = $this->renderStreetLine($addr); + $lines[] = $this->renderDeliveryLine($addr); + $lines[] = $this->renderCityLine($addr); + $lines[] = $this->renderCountryLine($addr); + } else { + $lines[] = $this->renderBuildingLine($addr); + $lines[] = $this->renderDeliveryLine($addr); + $lines[] = $this->renderStreetLine($addr); + $lines[] = $this->renderCityLine($addr); + $lines[] = $this->renderCountryLine($addr); + } } - return implode(' - ', $lines); + return array_values(array_filter($lines, static fn ($l) => null !== $l)); } - public function supports($entity, array $options): bool + public function renderStreetLine(Address $addr): ?string { - return $entity instanceof Address; - } - - private function renderStreetLine($addr): string - { - if (!empty($addr->getStreet())) { + if (null !== $addr->getStreet() && $addr->getStreet() !== '') { $street = $addr->getStreet(); } else { $street = ''; } - if (!empty($addr->getStreetNumber())) { + if (null !== $addr->getStreetNumber() && $addr->getStreetNumber() !== '') { $streetNumber = $addr->getStreetNumber(); } else { $streetNumber = ''; @@ -100,8 +111,111 @@ class AddressRender implements ChillEntityRenderInterface } } - if (',' === $res) { - $res = ''; + if ((',' === $res) || ('' === $res)) { + $res = null; + } + + return $res; + } + + /** + * @param Address addr + * @param mixed $addr + */ + public function renderString($addr, array $options): string + { + return implode(' - ', $this->renderLines($addr)); + } + + public function supports($entity, array $options): bool + { + return $entity instanceof Address; + } + + private function renderBuildingLine(Address $addr): ?string + { + if (null !== $addr->getBuildingName() && $addr->getBuildingName() !== '') { + $building = $addr->getBuildingName(); + } else { + $building = ''; + } + $intraBuilding = $this->renderIntraBuildingLine($addr); + + if (null === $intraBuilding) { + $intraBuilding = ''; + } + + $res = trim($building . ' - ' . $intraBuilding, ' - '); + + if ('' === $res) { + $res = null; + } + + if (null !== $addr->getPostCode()->getCountry()->getCountryCode()) { + if ($addr->getPostCode()->getCountry()->getCountryCode() === 'FR') { + $res = $addr->getBuildingName(); + } + } + + return $res; + } + + private function renderCityLine($addr): string + { + if (null !== $addr->getPostcode()) { + $res = strtr('{postcode} {label}', [ + '{postcode}' => $addr->getPostcode()->getCode(), + '{label}' => $addr->getPostcode()->getName(), + ]); + + if (null !== $addr->getPostCode()->getCountry()->getCountryCode()) { + if ($addr->getPostCode()->getCountry()->getCountryCode() === 'FR') { + if ($addr->getDistribution()) { + $res = $res . ' ' . $addr->getDistribution(); + } + } + } + } + + return $res ?? ''; + } + + private function renderCountryLine($addr): ?string + { + return $this->translatableStringHelper->localize( + $addr->getPostCode()->getCountry()->getName() + ); + } + + private function renderDeliveryLine($addr): ?string + { + return $addr->getExtra(); + } + + private function renderIntraBuildingLine($addr): ?string + { + $arr = []; + + if ($addr->getFlat()) { + $arr[] = 'appart ' . $addr->getFlat(); + } + + if ($addr->getFloor()) { + $arr[] = 'ét ' . $addr->getFloor(); + } + + if ($addr->getCorridor()) { + $arr[] = 'coul ' . $addr->getCorridor(); + } + + if ($addr->getSteps()) { + $arr[] = 'esc ' . $addr->getSteps(); + } + + $res = implode(' - ', $arr); + + if ('' === $res) { + $res = null; } return $res; diff --git a/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php b/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php index e577028ca..fcd7b374a 100644 --- a/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Templating/Entity/AddressRenderTest.php @@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Country; use Chill\MainBundle\Entity\PostalCode; use Chill\MainBundle\Templating\Entity\AddressRender; +use Chill\MainBundle\Templating\TranslatableStringHelper; use Iterator; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Templating\EngineInterface; @@ -30,11 +31,11 @@ final class AddressRenderTest extends KernelTestCase self::bootKernel(); } - public function addressDataProvider(): Iterator + public function addressDataProviderBEWithBuilding(): Iterator { $addr = new Address(); $country = (new Country()) - ->setName(['fr' => 'Pays']) + ->setName(['fr' => 'Belgium']) ->setCountryCode('BE'); $postCode = new PostalCode(); $postCode->setName('Locality') @@ -45,20 +46,279 @@ final class AddressRenderTest extends KernelTestCase ->setStreetNumber('5') ->setPostcode($postCode); - yield [$addr, 'Rue ABC, 5 - 012345 Locality']; + $addr->setBuildingName('Résidence "Les Bleuets"'); + + yield [$addr, 'Résidence "Les Bleuets" - Rue ABC, 5 - 012345 Locality - Belgium']; + } + + public function addressDataProviderBEWithSteps(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'Belgium']) + ->setCountryCode('BE'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + $addr->setSteps('4'); + + yield [$addr, 'esc 4 - Rue ABC, 5 - 012345 Locality - Belgium']; + } + + public function addressDataProviderFRWithBuilding(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'France']) + ->setCountryCode('FR'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + $addr->setBuildingName('Résidence "Les Bleuets"'); + + yield [$addr, 'Résidence "Les Bleuets" - 5, Rue ABC - 012345 Locality - France']; + } + + public function addressDataProviderFRWithSteps(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'France']) + ->setCountryCode('FR'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + $addr->setSteps('4'); + + yield [$addr, 'esc 4 - 5, Rue ABC - 012345 Locality - France']; + } + + public function complexAddressDataProviderBE(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'Belgium']) + ->setCountryCode('BE'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + $addr->setBuildingName('Résidence "Les Bleuets"'); + $addr->setFlat('1'); + $addr->setFloor('2'); + $addr->setCorridor('3'); + $addr->setSteps('4'); + + yield [$addr, 'Résidence "Les Bleuets" - appart 1 - ét 2 - coul 3 - esc 4 - Rue ABC, 5 - 012345 Locality - Belgium']; + } + + public function complexAddressDataProviderFR(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'France']) + ->setCountryCode('FR'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + $addr->setBuildingName('Résidence "Les Bleuets"'); + $addr->setFlat('1'); + $addr->setFloor('2'); + $addr->setCorridor('3'); + $addr->setSteps('4'); + $addr->setExtra('A droite de la porte'); + $addr->setDistribution('CEDEX'); + + yield [$addr, 'appart 1 - ét 2 - coul 3 - esc 4 - Résidence "Les Bleuets" - 5, Rue ABC - A droite de la porte - 012345 Locality CEDEX - France']; + } + + public function noFullAddressDataProviderBE(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'Belgium']) + ->setCountryCode('BE'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setPostcode($postCode) + ->setIsNoAddress(true); + + yield [$addr, '012345 Locality - Belgium']; + } + + public function simpleAddressDataProviderBE(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'Belgium']) + ->setCountryCode('BE'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + yield [$addr, 'Rue ABC, 5 - 012345 Locality - Belgium']; + } + + public function simpleAddressDataProviderFR(): Iterator + { + $addr = new Address(); + $country = (new Country()) + ->setName(['fr' => 'France']) + ->setCountryCode('FR'); + $postCode = new PostalCode(); + $postCode->setName('Locality') + ->setCode('012345') + ->setCountry($country); + + $addr->setStreet('Rue ABC') + ->setStreetNumber('5') + ->setPostcode($postCode); + + yield [$addr, '5, Rue ABC - 012345 Locality - France']; } /** - * @dataProvider addressDataProvider + * @dataProvider complexAddressDataProviderBE */ - public function testRenderString(Address $addr, string $expectedString): void + public function testRenderComplexAddressBE(Address $addr, string $expectedString): void { $engine = self::$container->get(EngineInterface::class); - $renderer = new AddressRender($engine); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } - return; - $this->assertIsString($renderer->renderBox($addr, [])); + /** + * @dataProvider complexAddressDataProviderFR + */ + public function testRenderComplexAddressFR(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider noFullAddressDataProviderBE + */ + public function testRenderNoFullAddressBE(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider simpleAddressDataProviderBE + */ + public function testRenderStringSimpleAddressBE(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider simpleAddressDataProviderFR + */ + public function testRenderStringSimpleAddressFR(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider addressDataProviderBEWithBuilding + */ + public function testRenderWithBuildingAddressBE(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider addressDataProviderFRWithBuilding + */ + public function testRenderWithBuildingAddressFR(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider addressDataProviderBEWithSteps + */ + public function testRenderWithStepsAddressBE(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); + } + + /** + * @dataProvider addressDataProviderFRWithSteps + */ + public function testRenderWithStepsAddressFR(Address $addr, string $expectedString): void + { + $engine = self::$container->get(EngineInterface::class); + $translatableStringHelper = self::$container->get(TranslatableStringHelper::class); + $renderer = new AddressRender($engine, $translatableStringHelper); + + $this->assertEquals($expectedString, $renderer->renderString($addr, [])); } } diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php index 5088b2381..9abd85f64 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php @@ -19,6 +19,7 @@ use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkRepos use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Exception\BadRequestException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -110,6 +111,60 @@ class AccompanyingCourseController extends Controller ]); } + /** + * Delete page of Accompanying Course section. + * + * @Route("/{_locale}/parcours/{accompanying_period_id}/delete", name="chill_person_accompanying_course_delete") + * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) + */ + public function deleteAction(Request $request, AccompanyingPeriod $accompanyingCourse) + { + $em = $this->getDoctrine()->getManager(); + + $person_id = $request->query->get('person_id'); + + $form = $this->createFormBuilder() + ->setAction($this->generateUrl('chill_person_accompanying_course_delete', [ + 'accompanying_period_id' => $accompanyingCourse->getId(), + 'person_id' => $person_id, + ])) + ->setMethod('DELETE') + ->add('submit', SubmitType::class, ['label' => 'Delete']) + ->getForm(); + + if ($request->getMethod() === Request::METHOD_DELETE) { + $form->handleRequest($request); + + if ($form->isValid()) { + $em->remove($accompanyingCourse); + $em->flush(); + + $this->addFlash('success', $this->get('translator') + ->trans('The accompanying course has been successfully removed.')); + + if (null !== $person_id) { + return $this->redirectToRoute('chill_person_accompanying_period_list', [ + 'person_id' => $person_id, + ]); + } + + return $this->redirectToRoute('chill_main_homepage'); + } + } + + if (null !== $person_id) { + $view = '@ChillPerson/AccompanyingCourse/confirm_delete_person.html.twig'; + } else { + $view = '@ChillPerson/AccompanyingCourse/confirm_delete_accompanying_course.html.twig'; + } + + return $this->render($view, [ + 'accompanyingCourse' => $accompanyingCourse, + 'person_id' => $person_id, + 'delete_form' => $form->createView(), + ]); + } + /** * Edit page of Accompanying Course section. * @@ -208,6 +263,9 @@ class AccompanyingCourseController extends Controller } } + $userLocation = $this->getUser()->getCurrentLocation(); + $period->setAdministrativeLocation($userLocation); + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CREATE, $period); $em->persist($period); diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 9628da187..06e4f0c8b 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -17,6 +17,7 @@ use Chill\MainBundle\Entity\Address; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\HasCentersInterface; use Chill\MainBundle\Entity\HasScopesInterface; +use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork; @@ -118,6 +119,13 @@ class AccompanyingPeriod implements */ private ?Address $addressLocation = null; + /** + * @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\Location") + * @Groups({"read", "write"}) + * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) + */ + private ?Location $administrativeLocation = null; + /** * @var DateTime * @@ -507,6 +515,11 @@ class AccompanyingPeriod implements return $this->addressLocation; } + public function getAdministrativeLocation(): ?Location + { + return $this->administrativeLocation; + } + /** * Get a list of person which have an adresse available for a valid location. * @@ -980,6 +993,13 @@ class AccompanyingPeriod implements return $this; } + public function setAdministrativeLocation(?Location $administrativeLocation): AccompanyingPeriod + { + $this->administrativeLocation = $administrativeLocation; + + return $this; + } + /** * Set closingDate. * diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php index 0c5517b71..4dc3d958c 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkGoal.php @@ -39,32 +39,32 @@ class AccompanyingPeriodWorkGoal /** * @ORM\ManyToOne(targetEntity=Goal::class) * @Serializer\Groups({"accompanying_period_work:edit"}) - * @Serializer\Groups({"read"}) + * @Serializer\Groups({"read", "docgen:read"}) */ - private $goal; + private ?Goal $goal = null; /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") - * @Serializer\Groups({"read"}) + * @Serializer\Groups({"read", "docgen:read"}) */ - private $id; + private ?int $id = null; /** * @ORM\Column(type="text") * @Serializer\Groups({"accompanying_period_work:edit"}) * @Serializer\Groups({"read"}) */ - private $note; + private ?string $note = null; /** * @ORM\ManyToMany(targetEntity=Result::class, inversedBy="accompanyingPeriodWorkGoals") * @ORM\JoinTable(name="chill_person_accompanying_period_work_goal_result") * @Serializer\Groups({"accompanying_period_work:edit"}) - * @Serializer\Groups({"read"}) + * @Serializer\Groups({"read", "docgen:read"}) */ - private $results; + private Collection $results; public function __construct() { diff --git a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php index c78e5df33..b2be55059 100644 --- a/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php +++ b/src/Bundle/ChillPersonBundle/Entity/Relationships/Relation.php @@ -28,7 +28,7 @@ class Relation * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") - * @Serializer\Groups({"read"}) + * @Serializer\Groups({"read", "docgen:read"}) */ private ?int $id = null; diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue index 30a8bbf2a..c0f279760 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/App.vue @@ -8,6 +8,7 @@ + @@ -28,6 +29,7 @@ import { mapGetters, mapState } from 'vuex' import Banner from './components/Banner.vue'; import StickyNav from './components/StickyNav.vue'; import OriginDemand from './components/OriginDemand.vue'; +import AdminLocation from './components/AdminLocation.vue'; import PersonsAssociated from './components/PersonsAssociated.vue'; import Requestor from './components/Requestor.vue'; import SocialIssue from './components/SocialIssue.vue'; @@ -44,6 +46,7 @@ export default { Banner, StickyNav, OriginDemand, + AdminLocation, PersonsAssociated, Requestor, SocialIssue, diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/AdminLocation.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/AdminLocation.vue new file mode 100644 index 000000000..201360a6e --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/AdminLocation.vue @@ -0,0 +1,103 @@ + + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue index 00dc73bd2..435dfe0c8 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner/PersonsAssociated.vue @@ -1,9 +1,9 @@