From 78f66d4f143b90c92521890115c59185afc10de5 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 8 Oct 2021 12:36:48 +0200 Subject: [PATCH 01/28] Address: Assign origin = 3 for postalCode created by users --- .../public/vuejs/Address/components/AddAddress.vue | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue index 55d8a93d1..959c68c14 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress.vue @@ -606,7 +606,7 @@ export default { let newPostcode = this.entity.selected.postcode; newPostcode = Object.assign(newPostcode, { 'country': {'id': this.entity.selected.country.id }, - }); + });//TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ? console.log('writeNew postcode is true! newPostcode: ', newPostcode); newAddress = Object.assign(newAddress, { 'newPostcode': newPostcode @@ -638,9 +638,7 @@ export default { if ('newPostcode' in payload) { let postcodeBody = payload.newPostcode; - if (this.context.target.name === 'person') { // !!! maintain here ? - postcodeBody = Object.assign(postcodeBody, {'origin': 3}); - } + postcodeBody = Object.assign(postcodeBody, {'origin': 3}); console.log('juste before post new postcode', postcodeBody); return postPostalCode(postcodeBody) .then(postalCode => { From cae3defedbfb6c53b8b93147723b253772fa1e51 Mon Sep 17 00:00:00 2001 From: nobohan Date: Fri, 8 Oct 2021 14:50:09 +0200 Subject: [PATCH 02/28] address: zoom to postal code --- .../vuejs/Address/components/AddAddress/CitySelection.vue | 4 +++- .../Resources/public/vuejs/Address/components/EditPane.vue | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) 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 9b6a7b87f..ef3683ec4 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 @@ -50,7 +50,7 @@ import VueMultiselect from 'vue-multiselect'; export default { name: 'CitySelection', components: { VueMultiselect }, - props: ['entity', 'focusOnAddress'], + props: ['entity', 'focusOnAddress', 'updateMapCenter'], emits: ['getReferenceAddresses'], data() { return { @@ -95,6 +95,7 @@ export default { return (value.code && value.name) ? `${value.code}-${value.name}` : ''; }, selectCity(value) { + console.log(value) this.entity.selected.city = value; this.entity.selected.postcode.name = value.name; this.entity.selected.postcode.code = value.code; @@ -102,6 +103,7 @@ export default { console.log('writeNew.postcode false, in selectCity'); this.$emit('getReferenceAddresses', value); this.focusOnAddress(); + this.updateMapCenter(value.center); }, listenInputSearch(query) { //console.log('listenInputSearch', query, this.isCitySelectorOpen); diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/EditPane.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/EditPane.vue index 9e257fe4a..2129a69d1 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/EditPane.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/EditPane.vue @@ -31,6 +31,7 @@ @@ -135,7 +136,7 @@ export default { } }, updateMapCenter(point) { - //console.log('point', point); + console.log('point', point); this.addressMap.center[0] = point.coordinates[1]; // TODO use reverse() this.addressMap.center[1] = point.coordinates[0]; this.$refs.addressMap.update(); // cast child methods From acbb33918f06935eeae777375b7b7fb78493b9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Oct 2021 17:09:38 +0200 Subject: [PATCH 03/28] improve translation --- .../public/vuejs/_components/OnTheFly/ThirdParty.vue | 4 ++-- src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue index 401cf1fa8..2710cd58e 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue @@ -77,8 +77,8 @@ const i18n = { messages: { fr: { tparty: { - contact: "Contact", - company: "Institution" + contact: "Personne physique", + company: "Personne morale" } } } diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index 604eafbad..cee39297b 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -29,8 +29,8 @@ thirdparty.UpdateBy.short: ' par ' thirdparty.CreatedAt.long: Date de création thirdparty.UpdatedAt.long: Date de la dernière modification thirdparty.UpdateBy.long: Utilisateur qui a effectué la dernière modification -thirdparty.A company: Une institution -thirdparty.company: Institution +thirdparty.A company: Une personne morale +thirdparty.company: Personne morale thirdparty.A contact: Une personne physique thirdparty.contact: Personne physique thirdparty.a_company_explanation: >- From 313c17826e5e83a7e87d7383f7a4a748f89be1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Oct 2021 17:34:52 +0200 Subject: [PATCH 04/28] translation of company & contact and show parent in list --- .../_components/AddPersons/TypeThirdParty.vue | 8 ++++---- .../ChillThirdPartyBundle/Entity/ThirdParty.php | 4 ++++ .../Resources/views/Entity/thirdparty.html.twig | 14 +++++++++++++- .../Templating/Entity/ThirdPartyRender.php | 3 ++- .../translations/messages.fr.yml | 6 ++++-- 5 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue index 4bb2e2d1e..2dbb7c8d0 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue @@ -19,8 +19,8 @@
- - {{ $t('thirdparty.contact')}} + + {{ $t('thirdparty.child')}} {{ $t('thirdparty.company')}} @@ -49,8 +49,8 @@ const i18n = { messages: { fr: { thirdparty: { - contact: "Contact", - company: "Institution", + contact: "Personne physique", + company: "Personne morale", child: "Personne de contact" } } diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php index b309c4542..38124b645 100644 --- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php +++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php @@ -460,6 +460,10 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface */ public function getAddress(): ?Address { + if ($this->isChild()) { + return $this->getParent()->getAddress(); + } + return $this->address; } diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig index f7dcf3bc5..558062271 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig @@ -84,7 +84,7 @@ {% if thirdparty.kind == 'company' %} {{ 'thirdparty.company'|trans }} {% elseif thirdparty.kind == 'child' %} - {{ 'thirdparty.Child'|trans }} + {{ 'thirdparty.Child'|trans }} {% elseif thirdparty.kind == 'contact' %} {{ 'thirdparty.contact'|trans }} {% endif %} @@ -144,4 +144,16 @@ {% endfor %}
{% endif %} + {% if options['showParent'] and thirdparty.isChild %} +
+ {{ 'thirdparty.Contact of'|trans }} : + {% include '@ChillMain/OnTheFly/_insert_vue_onthefly.html.twig' with { + targetEntity: { name: 'thirdparty', id: thirdparty.parent.id }, + action: 'show', + displayBadge: true, + buttonText: thirdparty.parent|chill_entity_render_string + } %} +
+ {% endif %} + {%- endif -%} diff --git a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php index db53108d4..e239c4a76 100644 --- a/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php +++ b/src/Bundle/ChillThirdPartyBundle/Templating/Entity/ThirdPartyRender.php @@ -61,7 +61,8 @@ class ThirdPartyRender extends AbstractChillEntityRender 'hLevel' => $options['hLevel'] ?? 3, 'customButtons' => $options['customButtons'] ?? [], 'customArea' => $options['customArea'] ?? [], - 'showContacts' => $options['showContacts'] ?? [], + 'showContacts' => $options['showContacts'] ?? false, + 'showParent' => $options['showParent'] ?? true, ]; return diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index cee39297b..e6167840d 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -33,11 +33,13 @@ thirdparty.A company: Une personne morale thirdparty.company: Personne morale thirdparty.A contact: Une personne physique thirdparty.contact: Personne physique +thirdparty.Contact of: Contact de thirdparty.a_company_explanation: >- - Les institutions peuvent compter un ou plusieurs contacts, interne à l'instution. Il est également possible de + Les personnes morales peuvent compter un ou plusieurs contacts, interne à l'instution. Il est également possible de leur associer un acronyme, et le nom d'un service. thirdparty.a_contact_explanation: >- - Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. + Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. Il est possible de leur + indiquer une civilité et un métier. thirdparty.Which kind of third party ?: Quel type de tiers souhaitez-vous créer ? thirdparty.Contact data are confidential: Données de contact confidentielles From bc608832c2425326ee294fc148ace9b63fd8afa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Oct 2021 17:37:58 +0200 Subject: [PATCH 05/28] fill changelog [ci-skip] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 118b75fda..991df9605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to ## Unreleased +* [3party]: french translation of contact and company +* [3party]: show parent in list +* [3party]: change color for badge "child" + ## Test releases From f4369553e12f91c4045d65abe695d48e1223c93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 11 Oct 2021 17:40:31 +0200 Subject: [PATCH 06/28] fix layout for address --- .../Resources/views/Entity/thirdparty.html.twig | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig index 558062271..5700acc0b 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig @@ -91,12 +91,14 @@
    - {{ thirdparty.getAddress|chill_entity_render_box({ - 'render': 'list', - 'with_picto': true, - 'multiline': false, - 'with_valid_from': false - }) }} +
  • + {{ thirdparty.getAddress|chill_entity_render_box({ + 'render': 'list', + 'with_picto': true, + 'multiline': false, + 'with_valid_from': false + }) }} +
  • {% if thirdparty.telephone %} {{ thirdparty.telephone|chill_format_phonenumber }} From e9192c5011fdfadc326bdb44cd689acd9eabaf7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 12 Oct 2021 09:28:53 +0200 Subject: [PATCH 07/28] adaptations for third party search --- .../Search/Entity/SearchUserApiProvider.php | 2 +- .../ChillMainBundle/Search/SearchApiQuery.php | 37 +++++++-- .../Tests/Search/SearchApiQueryTest.php | 40 ++++++++++ .../Search/SearchPersonApiProvider.php | 2 +- .../Search/ThirdPartyApiSearch.php | 76 ++++++++++++++++--- 5 files changed, 138 insertions(+), 19 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php diff --git a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php index e4061cea1..6b8139419 100644 --- a/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php +++ b/src/Bundle/ChillMainBundle/Search/Entity/SearchUserApiProvider.php @@ -27,7 +27,7 @@ class SearchUserApiProvider implements SearchApiInterface ->setSelectPertinence("GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical), SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical))", [ $pattern, $pattern ]) ->setFromClause("users AS u") - ->setWhereClause("SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15 + ->setWhereClauses("SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15 OR SIMILARITY(LOWER(UNACCENT(?)), u.emailcanonical) > 0.15 ", [ $pattern, $pattern ]); diff --git a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php index 2c986ee6c..9188c0b5c 100644 --- a/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php +++ b/src/Bundle/ChillMainBundle/Search/SearchApiQuery.php @@ -12,8 +12,8 @@ class SearchApiQuery private array $pertinenceParams = []; private ?string $fromClause = null; private array $fromClauseParams = []; - private ?string $whereClause = null; - private array $whereClauseParams = []; + private array $whereClauses = []; + private array $whereClausesParams = []; public function setSelectKey(string $selectKey, array $params = []): self { @@ -47,16 +47,39 @@ class SearchApiQuery return $this; } - public function setWhereClause(string $whereClause, array $params = []): self + /** + * Set the where clause and replace all existing ones. + * + */ + public function setWhereClauses(string $whereClause, array $params = []): self { - $this->whereClause = $whereClause; - $this->whereClauseParams = $params; + $this->whereClauses = [$whereClause]; + $this->whereClausesParams = [$params]; + + return $this; + } + + /** + * Add a where clause. + * + * This will add to previous where clauses with and `AND` join + * + * @param string $whereClause + * @param array $params + * @return $this + */ + public function andWhereClause(string $whereClause, array $params = []): self + { + $this->whereClauses[] = $whereClause; + $this->whereClausesParams[] = $params; return $this; } public function buildQuery(): string { + $where = \implode(' AND ', $this->whereClauses); + return \strtr("SELECT '{key}' AS key, {metadata} AS metadata, @@ -68,7 +91,7 @@ class SearchApiQuery '{metadata}' => $this->jsonbMetadata, '{pertinence}' => $this->pertinence, '{from}' => $this->fromClause, - '{where}' => $this->whereClause, + '{where}' => $where, ]); } @@ -79,7 +102,7 @@ class SearchApiQuery $this->jsonbMetadataParams, $this->pertinenceParams, $this->fromClauseParams, - $this->whereClauseParams, + \array_merge([], ...$this->whereClausesParams), ); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php new file mode 100644 index 000000000..2e63f24e0 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Search/SearchApiQueryTest.php @@ -0,0 +1,40 @@ +setSelectJsonbMetadata('boum') + ->setSelectKey('bim') + ->setSelectPertinence('1') + ->setFromClause('badaboum') + ->andWhereClause('foo', [ 'alpha' ]) + ->andWhereClause('bar', [ 'beta' ]) + ; + + $query = $q->buildQuery(); + + $this->assertStringContainsString('foo AND bar', $query); + $this->assertEquals(['alpha', 'beta'], $q->buildParameters()); + } + + public function testWithoutWhereClause() + { + $q = new SearchApiQuery(); + $q->setSelectJsonbMetadata('boum') + ->setSelectKey('bim') + ->setSelectPertinence('1') + ->setFromClause('badaboum') + ; + + $this->assertTrue(\is_string($q->buildQuery())); + $this->assertEquals([], $q->buildParameters()); + } + +} diff --git a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php index 4d1b720db..dd0ae67c7 100644 --- a/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php +++ b/src/Bundle/ChillPersonBundle/Search/SearchPersonApiProvider.php @@ -26,7 +26,7 @@ class SearchPersonApiProvider implements SearchApiInterface "(person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%')::int". ")", [ $pattern, $pattern ]) ->setFromClause("chill_person_person AS person") - ->setWhereClause("LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ". + ->setWhereClauses("LOWER(UNACCENT(?)) <<% person.fullnamecanonical OR ". "person.fullnamecanonical LIKE '%' || LOWER(UNACCENT(?)) || '%' ", [ $pattern, $pattern ]) ; diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php index 47d5cc6b9..d25b6ac8f 100644 --- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php +++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php @@ -5,7 +5,36 @@ namespace Chill\ThirdPartyBundle\Search; use Chill\MainBundle\Search\SearchApiInterface; use Chill\MainBundle\Search\SearchApiQuery; use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository; +use function explode; + +/* + * Internal note: test query for parametrizing / testing: + * +WITH rows AS ( + SELECT 'aide a domicile en milieu rural admr' AS c, 'la roche sur yon' AS l + UNION + SELECT 'aide a domicile en milieu rural admr' AS c, 'fontenay-le-comte' AS l +), searches AS ( + SELECT 'admr roche' AS s, 'admr' AS s1, 'roche' As s2 + UNION + SELECT 'admr font' AS s, 'admr' AS s1, 'font' AS s2 +) +SELECT + c, l, s, s1, s2, + strict_word_similarity(s, c) + + (c LIKE '%' || s1 || '%')::int + + (c LIKE '%' || s2 || '%')::int + + (l LIKE '%' || s1 || '%')::int + + (l LIKE '%' || s2 || '%')::int, + l LIKE '%' || s1 || '%', + l LIKE '%' || s2 || '%' +FROM rows, searches + */ + +/** + * Generate query for searching amongst third parties + */ class ThirdPartyApiSearch implements SearchApiInterface { private ThirdPartyRepository $thirdPartyRepository; @@ -17,18 +46,45 @@ class ThirdPartyApiSearch implements SearchApiInterface public function provideQuery(string $pattern, array $parameters): SearchApiQuery { - return (new SearchApiQuery) + $query = (new SearchApiQuery) ->setSelectKey('tparty') ->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)") - ->setSelectPertinence("GREATEST(". - "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized),". - "(tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')::int". - ")", [ $pattern, $pattern ]) - ->setFromClause('chill_3party.third_party AS tparty') - ->setWhereClause("tparty.active IS TRUE ". - "AND (LOWER(UNACCENT(?)) <<% tparty.canonicalized OR ". - "tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')", [ $pattern, $pattern ]) - ; + ->setFromClause('chill_3party.third_party AS tparty + LEFT JOIN chill_main_address cma ON cma.id = tparty.address_id + LEFT JOIN chill_main_postal_code cmpc ON cma.postcode_id = cmpc.id + LEFT JOIN chill_3party.third_party AS parent ON tparty.parent_id = parent.id + LEFT JOIN chill_main_address cma_p ON parent.address_id = cma_p.id + LEFT JOIN chill_main_postal_code cmpc_p ON cma_p.postcode_id = cmpc.id') + ->andWhereClause("tparty.active IS TRUE") + ; + + $strs = explode(' ', $pattern); + $wheres = []; + $whereArgs = []; + $pertinence = []; + $pertinenceArgs = []; + + foreach ($strs as $str) { + if (!empty($str)) { + $wheres[] = "(LOWER(UNACCENT(?)) <<% tparty.canonicalized OR + tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')"; + $whereArgs[] = [$str, $str]; + $pertinence[] = "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized) + ". + "(tparty.canonicalized LIKE '%s' || LOWER(UNACCENT(?)) || '%')::int + ". + // take postcode label into account, but lower than the canonicalized field + "COALESCE((LOWER(UNACCENT(cmpc.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0) + ". + "COALESCE((LOWER(UNACCENT(cmpc_p.label)) LIKE '%' || LOWER(UNACCENT(?)) || '%')::int * 0.3, 0)"; + $pertinenceArgs[] = [$str, $str, $str, $str]; + } + } + + $query + ->setSelectPertinence(\implode(' + ', $pertinence), \array_merge([], + ...$pertinenceArgs)) + ->andWhereClause(\implode(' OR ', $wheres), \array_merge([], + ...$whereArgs)); + + return $query; } public function supportsTypes(string $pattern, array $types, array $parameters): bool From 9eec15873eb9684f31894e191330296308da273a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 12 Oct 2021 09:44:51 +0200 Subject: [PATCH 08/28] fixtures for civility: add abbreviations --- .../DataFixtures/ORM/LoadCivility.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php index 07f824cd1..b26b5b991 100644 --- a/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php +++ b/src/Bundle/ChillMainBundle/DataFixtures/ORM/LoadCivility.php @@ -17,20 +17,21 @@ class LoadCivility extends Fixture implements FixtureGroupInterface public function load(ObjectManager $manager): void { $civilities = [ - ['name' => ['fr' => "Monsieur" ]], - ['name' => ['fr' => "Madame" ]], - ['name' => ['fr' => "Docteur" ]], - ['name' => ['fr' => "Professeur" ]], - ['name' => ['fr' => "Madame la Directrice" ]], - ['name' => ['fr' => "Monsieur le Directeur" ]], + ['name' => ['fr' => "Monsieur" ], 'abbrev' => ['fr' => 'M.']], + ['name' => ['fr' => "Madame" ], 'abbrev' => ['fr' => 'Mme']], + ['name' => ['fr' => "Docteur" ], 'abbrev' => ['fr' => 'Dr']], + ['name' => ['fr' => "Professeur" ], 'abbrev' => ['fr' => 'Pr']], + ['name' => ['fr' => "Madame la Directrice" ], 'abbrev' => ['fr' => 'Mme']], + ['name' => ['fr' => "Monsieur le Directeur" ], 'abbrev' => ['fr' => 'M.']], ['name' => ['fr' => "Madame la Maire" ]], ['name' => ['fr' => "Monsieur le Maire" ]], - ['name' => ['fr' => "Maître" ]], + ['name' => ['fr' => "Maître" ], 'abbrev' => ['fr' => 'Me']], ]; foreach ( $civilities as $val) { $civility = (new Civility()) ->setName($val['name']) + ->setAbbreviation($val['abbrev'] ?? []) ->setActive(true); $manager->persist($civility); } From 88d073b9a97e738f6905d2244fe45ebb555cd36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 12 Oct 2021 15:52:06 +0200 Subject: [PATCH 09/28] handle types and categories in a single select input --- .../ChillThirdPartyBundle.php | 3 + .../Controller/ThirdPartyController.php | 2 + .../Entity/ThirdParty.php | 106 +++++++++++++++++- .../Form/ThirdPartyType.php | 61 ++-------- .../Type/PickThirdPartyTypeCategoryType.php | 100 +++++++++++++++++ .../views/ThirdParty/_form.html.twig | 3 +- .../Resources/views/ThirdParty/view.html.twig | 11 +- .../Tests/Entity/ThirdPartyTest.php | 92 +++++++++++++++ .../config/services/form.yaml | 22 +--- .../translations/messages.fr.yml | 1 + 10 files changed, 323 insertions(+), 78 deletions(-) create mode 100644 src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php create mode 100644 src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php diff --git a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php index ba184292a..6c6ff08c9 100644 --- a/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php +++ b/src/Bundle/ChillThirdPartyBundle/ChillThirdPartyBundle.php @@ -2,6 +2,7 @@ namespace Chill\ThirdPartyBundle; +use Chill\ThirdPartyBundle\ThirdPartyType\ThirdPartyTypeProviderInterface; use Symfony\Component\HttpKernel\Bundle\Bundle; use Chill\ThirdPartyBundle\DependencyInjection\CompilerPass\ThirdPartyTypeCompilerPass; @@ -10,6 +11,8 @@ class ChillThirdPartyBundle extends Bundle public function build(\Symfony\Component\DependencyInjection\ContainerBuilder $container) { parent::build($container); + $container->registerForAutoconfiguration(ThirdPartyTypeProviderInterface::class) + ->addTag('chill_3party.provider'); $container->addCompilerPass(new ThirdPartyTypeCompilerPass()); } diff --git a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php index d6e4c0046..f7d47a32d 100644 --- a/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php +++ b/src/Bundle/ChillThirdPartyBundle/Controller/ThirdPartyController.php @@ -127,6 +127,8 @@ final class ThirdPartyController extends CRUDController return $this->getFilterOrderHelperFactory() ->create(self::class) ->addSearchBox(['name', 'company_name', 'acronym']) + //->addToggle('only-active', []) + // ->addOrderBy() ->build(); } } diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php index 38124b645..69da6cf50 100644 --- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php +++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php @@ -368,7 +368,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface public function setTypes(array $type = null) { // remove all keys from the input data - $this->type = \array_values($type); + $this->types = \array_values($type); foreach ($this->children as $child) { $child->setTypes($type); @@ -387,6 +387,40 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->types; } + public function addType(?string $type): self + { + if (NULL === $type) { + return $this; + } + + if (!\in_array($type, $this->types ?? [])) { + $this->types[] = $type; + } + + foreach ($this->children as $child) { + $child->addType($type); + } + + return $this; + } + + public function removeType(?string $type): self + { + if (NULL === $type) { + return $this; + } + + if (\in_array($type, $this->types ?? [])) { + $this->types = \array_filter($this->types, fn($e) => !\in_array($e, $this->types)); + } + + foreach ($this->children as $child) { + $child->removeType($type); + } + + return $this; + } + /** * @return bool */ @@ -541,7 +575,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface } foreach ($this->children as $child) { - $child->addCategory($child); + $child->addCategory($category); } return $this; @@ -556,7 +590,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface $this->categories->removeElement($category); foreach ($this->children as $child) { - $child->removeCategory($child); + $child->removeCategory($category); } return $this; @@ -631,6 +665,72 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this; } + public function addTypesAndCategories($typeAndCategory): self + { + if ($typeAndCategory instanceof ThirdPartyCategory) { + $this->addCategory($typeAndCategory); + return $this; + } + + if (is_string($typeAndCategory)) { + $this->addType($typeAndCategory); + return $this; + } + + throw new \UnexpectedValueException(sprintf( + "typeAndCategory should be a string or a %s", ThirdPartyCategory::class)); + } + + public function removeTypesAndCategories($typeAndCategory): self + { + if ($typeAndCategory instanceof ThirdPartyCategory) { + $this->removeCategory($typeAndCategory); + return $this; + } + + if (is_string($typeAndCategory)) { + $this->removeType($typeAndCategory); + return $this; + } + + throw new \UnexpectedValueException(sprintf( + "typeAndCategory should be a string or a %s", ThirdPartyCategory::class)); + } + + public function getTypesAndCategories(): array + { + return \array_merge( + $this->getCategories()->toArray(), + $this->getTypes() ?? [] + ); + } + + public function setTypesAndCategories(array $typesAndCategories): self + { + $types = \array_filter($typesAndCategories, fn($item) => !$item instanceof ThirdPartyCategory); + $this->setTypes($types); + + // handle categories + foreach ($typesAndCategories as $t) { + $this->addTypesAndCategories($t); + } + + $categories = \array_filter($typesAndCategories, fn($item) => $item instanceof ThirdPartyCategory); + $categoriesHashes = \array_map(fn(ThirdPartyCategory $c) => \spl_object_hash($c), $categories); + + foreach ($categories as $c) { + $this->addCategory($c); + } + + foreach ($this->getCategories() as $t) { + if (!\in_array(\spl_object_hash($t), $categoriesHashes)) { + $this->removeCategory($t); + } + } + + return $this; + } + /** * @param ThirdParty $child diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php index 057f848cb..3d30b9e81 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -11,9 +11,12 @@ use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\ThirdPartyBundle\Entity\ThirdPartyCategory; use Chill\ThirdPartyBundle\Entity\ThirdPartyProfession; +use Chill\ThirdPartyBundle\Form\Type\PickThirdPartyType; +use Chill\ThirdPartyBundle\Form\Type\PickThirdPartyTypeCategoryType; +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; -use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; @@ -40,14 +43,14 @@ class ThirdPartyType extends AbstractType protected TranslatableStringHelper $translatableStringHelper; - protected ObjectManager $om; + protected EntityManagerInterface $om; public function __construct( AuthorizationHelper $authorizationHelper, TokenStorageInterface $tokenStorage, ThirdPartyTypeManager $typesManager, TranslatableStringHelper $translatableStringHelper, - ObjectManager $om + EntityManagerInterface $om ) { $this->authorizationHelper = $authorizationHelper; $this->tokenStorage = $tokenStorage; @@ -171,21 +174,9 @@ class ThirdPartyType extends AbstractType } if (ThirdParty::KIND_CHILD !== $options['kind']) { - $builder - ->add('categories', EntityType::class, [ - 'label' => 'thirdparty.Categories', - 'class' => ThirdPartyCategory::class, - 'choice_label' => function (ThirdPartyCategory $category): string { - return $this->translatableStringHelper->localize($category->getName()); - }, - 'query_builder' => function (EntityRepository $er): QueryBuilder { - return $er->createQueryBuilder('c') - ->where('c.active = true'); - }, - 'required' => true, - 'multiple' => true, - 'attr' => ['class' => 'select2'] + ->add('typesAndCategories', PickThirdPartyTypeCategoryType::class, [ + 'label' => 'thirdparty.Categories' ]) ->add('active', ChoiceType::class, [ 'label' => 'thirdparty.Status', @@ -196,42 +187,6 @@ class ThirdPartyType extends AbstractType 'expanded' => true, 'multiple' => false ]); - - // add the types - $types = []; - foreach ($this->typesManager->getProviders() as $key => $provider) { - $types['chill_3party.key_label.'.$key] = $key; - } - if (count($types) === 1) { - $builder - ->add('types', HiddenType::class, [ - 'data' => array_values($types) - ]) - ->get('types') - ->addModelTransformer(new CallbackTransformer( - function (?array $typeArray): ?string { - if (null === $typeArray) { - return null; - } - return implode(',', $typeArray); - }, - function (?string $typeStr): ?array { - if (null === $typeStr) { - return null; - } - return explode(',', $typeStr); - } - )) - ; - } else { - $builder - ->add('types', ChoiceType::class, [ - 'choices' => $types, - 'expanded' => true, - 'multiple' => true, - 'label' => 'thirdparty.Type' - ]); - } } } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php new file mode 100644 index 000000000..2af962895 --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Form/Type/PickThirdPartyTypeCategoryType.php @@ -0,0 +1,100 @@ +thirdPartyCategoryRepository = $thirdPartyCategoryRepository; + $this->thirdPartyTypeManager = $thirdPartyTypeManager; + $this->translatableStringHelper = $translatableStringHelper; + $this->translator = $translator; + } + + public function getParent() + { + return ChoiceType::class; + } + + public function configureOptions(OptionsResolver $resolver) + { + $choices = \array_merge( + $this->thirdPartyCategoryRepository->findBy(['active' => true]), + $this->thirdPartyTypeManager->getTypes() + ); + + \uasort($choices, function ($itemA, $itemB) { + $strA = $itemA instanceof ThirdPartyCategory ? $this->translatableStringHelper + ->localize($itemA->getName()) : $this->translator->trans(self::PREFIX_TYPE.$itemA); + $strB = $itemB instanceof ThirdPartyCategory ? $this->translatableStringHelper + ->localize($itemB->getName()) : $this->translator->trans(self::PREFIX_TYPE.$itemB); + + return $strA <=> $strB; + }); + + + $resolver->setDefaults([ + 'choices' => $choices, + 'attr' => [ 'class' => 'select2' ], + 'multiple' => true, + 'choice_label' => function($item) { + if ($item instanceof ThirdPartyCategory) { + return $this->translatableStringHelper->localize($item->getName()); + } + return self::PREFIX_TYPE.$item; + }, + 'choice_value' => function($item) { + return $this->reverseTransform($item); + } + ]); + } + + public function reverseTransform($value) + { + if ($value === null) { + return null; + } + if (is_array($value)){ + $r = []; + + foreach ($value as $v) { + $r[] = $this->transform($v); + } + + return $r; + } + + if ($value instanceof ThirdPartyCategory) { + return 'category:'.$value->getId(); + } + + if (is_string($value)) { + return 'type:'.$value; + } + + throw new UnexpectedTypeException($value, \implode(' or ', ['array', 'string', ThirdPartyCategory::class])); + } +} diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig index ef347eb6d..87d26cc22 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig @@ -14,8 +14,7 @@ {{ form_row(form.profession) }} {% endif %} -{{ form_row(form.types) }} -{{ form_row(form.categories) }} +{{ form_row(form.typesAndCategories) }} {{ form_row(form.telephone) }} {{ form_row(form.email) }} diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/view.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/view.html.twig index 460468e98..6b6395b19 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/view.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/view.html.twig @@ -48,13 +48,20 @@ {% endif %} -
    {{ 'Type'|trans }}
    +
    {{ 'thirdparty.Categories'|trans }}
    {% set types = [] %} {% for t in thirdParty.types %} {% set types = types|merge( [ ('chill_3party.key_label.'~t)|trans ] ) %} {% endfor %} + {% for c in thirdParty.categories %} + {% set types = types|merge([ c.name|localize_translatable_string ]) %} + {% endfor %}
    - {{ types|join(', ') }} + {% if types|length > 0 %} + {{ types|join(', ') }} + {% else %} +

    {{ 'thirdParty.Any categories' }}

    + {% endif %}
    {{ 'Phonenumber'|trans }}
    diff --git a/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php b/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php new file mode 100644 index 000000000..ac1758030 --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Tests/Entity/ThirdPartyTest.php @@ -0,0 +1,92 @@ +addTypesAndCategories('type'); + $tp->addTypesAndCategories($cat1); + $tp->addTypesAndCategories($cat2); + + $this->assertTrue($tp->getCategories()->contains($cat1)); + $this->assertTrue($tp->getCategories()->contains($cat2)); + $this->assertCount(2, $tp->getCategories()); + + $this->assertCount(1, $tp->getTypes()); + $this->assertContains('type', $tp->getTypes()); + + $this->assertCount(3, $tp->getTypesAndCategories()); + $this->assertContains($cat1, $tp->getTypesAndCategories()); + $this->assertContains($cat2, $tp->getTypesAndCategories()); + $this->assertContains('type', $tp->getTypesAndCategories()); + + // remove type + $tp->removeTypesAndCategories('type'); + $tp->removeTypesAndCategories($cat2); + + $this->assertTrue($tp->getCategories()->contains($cat1), + "test that cat1 is still present"); + $this->assertFalse($tp->getCategories()->contains($cat2)); + $this->assertCount(1, $tp->getCategories()); + + $this->assertCount(0, $tp->getTypes()); + $this->assertNotContains('type', $tp->getTypes()); + + $this->assertCount(1, $tp->getTypesAndCategories()); + $this->assertContains($cat1, $tp->getTypesAndCategories()); + $this->assertNotContains($cat2, $tp->getTypesAndCategories()); + $this->assertNotContains('type', $tp->getTypesAndCategories()); + } + + public function testSyncingActivityTypes() + { + $tp = new ThirdParty(); + $tp->setTypesAndCategories([ + 'type1', + 'type2', + $cat1 = new ThirdPartyCategory(), + $cat2 = new ThirdPartyCategory() + ]); + + $this->assertTrue($tp->getCategories()->contains($cat1)); + $this->assertTrue($tp->getCategories()->contains($cat2)); + $this->assertCount(2, $tp->getCategories()); + + $this->assertCount(2, $tp->getTypes()); + $this->assertContains('type1', $tp->getTypes()); + $this->assertContains('type2', $tp->getTypes()); + + $this->assertCount(4, $tp->getTypesAndCategories()); + $this->assertContains($cat1, $tp->getTypesAndCategories()); + $this->assertContains($cat2, $tp->getTypesAndCategories()); + $this->assertContains('type1', $tp->getTypesAndCategories()); + $this->assertContains('type2', $tp->getTypesAndCategories()); + + $tp->setTypesAndCategories([$cat1, 'type1']); + + $this->assertTrue($tp->getCategories()->contains($cat1)); + $this->assertFalse($tp->getCategories()->contains($cat2)); + $this->assertCount(1, $tp->getCategories()); + + $this->assertCount(1, $tp->getTypes()); + $this->assertContains('type1', $tp->getTypes()); + $this->assertNotContains('type2', $tp->getTypes()); + + $this->assertCount(2, $tp->getTypesAndCategories()); + $this->assertContains($cat1, $tp->getTypesAndCategories()); + $this->assertNotContains($cat2, $tp->getTypesAndCategories()); + $this->assertContains('type1', $tp->getTypesAndCategories()); + $this->assertNotContains('type2', $tp->getTypesAndCategories()); + } + +} diff --git a/src/Bundle/ChillThirdPartyBundle/config/services/form.yaml b/src/Bundle/ChillThirdPartyBundle/config/services/form.yaml index 8ff604769..0ed703e86 100644 --- a/src/Bundle/ChillThirdPartyBundle/config/services/form.yaml +++ b/src/Bundle/ChillThirdPartyBundle/config/services/form.yaml @@ -1,19 +1,5 @@ services: - Chill\ThirdPartyBundle\Form\ThirdPartyType: - arguments: - $authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper' - $tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface' - $typesManager: '@Chill\ThirdPartyBundle\ThirdPartyType\ThirdPartyTypeManager' - $translatableStringHelper: '@Chill\MainBundle\Templating\TranslatableStringHelper' - $om: '@doctrine.orm.entity_manager' - tags: - - { name: form.type } - - Chill\ThirdPartyBundle\Form\Type\PickThirdPartyType: - arguments: - $em: '@Doctrine\ORM\EntityManagerInterface' - $urlGenerator: '@Symfony\Component\Routing\Generator\UrlGeneratorInterface' - $translator: '@Symfony\Component\Translation\TranslatorInterface' - $typesManager: '@Chill\ThirdPartyBundle\ThirdPartyType\ThirdPartyTypeManager' - tags: - - { name: form.type } + Chill\ThirdPartyBundle\Form\: + resource: '../../Form/' + autowire: true + autoconfigure: true diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index e6167840d..ba5847c0b 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -67,6 +67,7 @@ No nameCompany given: Aucune raison sociale renseignée No acronym given: Aucun sigle renseigné No phone given: Aucun téléphone renseigné No email given: Aucune adresse courriel renseignée +thirdparty.Any categories: Aucune catégorie The party is visible in those centers: Le tiers est visible dans ces centres The party is not visible in any center: Le tiers n'est associé à aucun centre From b84d0100e0e38213bdbb0c6c61663afeaaec954a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 12 Oct 2021 17:32:17 +0200 Subject: [PATCH 10/28] create style for badge 3party and introduce in ThirdPartyRenderBox.vue --- .../_components/AddPersons/TypeThirdParty.vue | 6 ++--- .../public/chill/chillthirdparty.scss | 16 ++++++++++++++ .../Resources/public/chill/index.js | 1 + .../Resources/public/chill/thirdparty.scss | 0 .../Resources/public/page/index/index.js | 2 +- ...chillthirdparty.scss => index_3party.scss} | 0 .../Entity/ThirdPartyRenderBox.vue | 22 +++++++++++++++++++ .../vuejs/_components/OnTheFly/ThirdParty.vue | 8 +++++-- .../views/Entity/thirdparty.html.twig | 8 +------ .../chill.webpack.config.js | 2 ++ .../translations/messages.fr.yml | 2 ++ 11 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 src/Bundle/ChillThirdPartyBundle/Resources/public/chill/chillthirdparty.scss create mode 100644 src/Bundle/ChillThirdPartyBundle/Resources/public/chill/index.js delete mode 100644 src/Bundle/ChillThirdPartyBundle/Resources/public/chill/thirdparty.scss rename src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/{chillthirdparty.scss => index_3party.scss} (100%) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue index 2dbb7c8d0..c68587ed9 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue @@ -19,13 +19,13 @@
- + {{ $t('thirdparty.child')}} - + {{ $t('thirdparty.company')}} - + {{ $t('thirdparty.contact')}} diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/chillthirdparty.scss b/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/chillthirdparty.scss new file mode 100644 index 000000000..9762a898a --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/chillthirdparty.scss @@ -0,0 +1,16 @@ +@import 'ChillMainAssets/module/bootstrap/shared'; + +.badge { + &.bg-thirdparty-company { + //@extend .bg-info; + background-color: $yellow; + } + &.bg-thirdparty-child { + //@extend .bg-chill-blue; + background-color: $chill-blue; + } + &.bg-thirdparty-contact { + //@extedn .bg-secondary; + background-color: $secondary; + } +} diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/index.js b/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/index.js new file mode 100644 index 000000000..34dd4f71e --- /dev/null +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/index.js @@ -0,0 +1 @@ +require('./chillthirdparty.scss'); diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/thirdparty.scss b/src/Bundle/ChillThirdPartyBundle/Resources/public/chill/thirdparty.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index.js b/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index.js index d85b125aa..10b9e8383 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index.js +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index.js @@ -1,2 +1,2 @@ -require('./chillthirdparty.scss'); +require('./index_3party.scss'); diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/chillthirdparty.scss b/src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index_3party.scss similarity index 100% rename from src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/chillthirdparty.scss rename to src/Bundle/ChillThirdPartyBundle/Resources/public/page/index/index_3party.scss diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue index c2714126a..3ef941c02 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue @@ -13,6 +13,16 @@ {{ thirdparty.text }} + + {{ $t('thirdparty.child')}} + + + {{ $t('thirdparty.company')}} + + + {{ $t('thirdparty.contact')}} + + {{ thirdparty.id }} {{ $t('renderbox.type.thirdparty') }} @@ -57,11 +67,23 @@ import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue'; import {dateToISO} from 'ChillMainAssets/chill/js/date.js'; +const i18n = { + messages: { + fr: { + tparty: { + contact: "Personne physique", + company: "Personne morale" + } + } + } +}; + export default { name: "ThirdPartyRenderBox", components: { AddressRenderBox }, + i18n, props: ['thirdparty', 'options'], computed: { isMultiline: function() { diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue index 2710cd58e..1cb03ec85 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/OnTheFly/ThirdParty.vue @@ -24,13 +24,17 @@
diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig index 5700acc0b..af71b9643 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/Entity/thirdparty.html.twig @@ -81,13 +81,7 @@
{{ _self.label(thirdparty, options) }} - {% if thirdparty.kind == 'company' %} - {{ 'thirdparty.company'|trans }} - {% elseif thirdparty.kind == 'child' %} - {{ 'thirdparty.Child'|trans }} - {% elseif thirdparty.kind == 'contact' %} - {{ 'thirdparty.contact'|trans }} - {% endif %} + {{ ('thirdparty.' ~ thirdparty.kind)|trans }}
    diff --git a/src/Bundle/ChillThirdPartyBundle/chill.webpack.config.js b/src/Bundle/ChillThirdPartyBundle/chill.webpack.config.js index c508cbc0c..8fbeb35a2 100644 --- a/src/Bundle/ChillThirdPartyBundle/chill.webpack.config.js +++ b/src/Bundle/ChillThirdPartyBundle/chill.webpack.config.js @@ -5,6 +5,8 @@ module.exports = function(encore, entries) ChillThirdPartyAssets: __dirname + '/Resources/public' }); + entries.push(__dirname + '/Resources/public/chill/index.js'); + encore.addEntry( 'page_3party_3party_index', __dirname + '/Resources/public/page/index/index.js' diff --git a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml index ba5847c0b..135ef9b47 100644 --- a/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillThirdPartyBundle/translations/messages.fr.yml @@ -16,7 +16,9 @@ thirdparty.NameCompany: Service/Département thirdparty.Acronym: Sigle thirdparty.Categories: Catégories thirdparty.Child: Personne de contact +thirdparty.child: Personne de contact thirdparty.Children: Personnes de contact +thirdparty.children: Personnes de contact thirdparty.Parent: Tiers institutionnel thirdparty.Parents: Tiers institutionnels thirdparty.Civility: Civilité From 01ff88074b526346e8da0d21fa2ebf9d9be50d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Tue, 12 Oct 2021 17:50:32 +0200 Subject: [PATCH 11/28] add parent in thirdpartyrenderbox.vue --- .../_components/AddPersons/TypeThirdParty.vue | 2 +- .../_components/Entity/ThirdPartyRenderBox.vue | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue index c68587ed9..de24c6fbf 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeThirdParty.vue @@ -13,7 +13,7 @@
- {{ item.result.parent.text }} + > {{ item.result.parent.text }}
diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue index 3ef941c02..8b8fc6449 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue +++ b/src/Bundle/ChillThirdPartyBundle/Resources/public/vuejs/_components/Entity/ThirdPartyRenderBox.vue @@ -28,11 +28,18 @@ +
+ + > {{ thirdparty.parent.text }} + +
+

+
@@ -87,11 +94,14 @@ export default { props: ['thirdparty', 'options'], computed: { isMultiline: function() { - if(this.options.isMultiline){ + if (this.options.isMultiline){ return this.options.isMultiline } else { return false } + }, + hasParent() { + return !(this.$props.thirdparty.parent === null || this.$props.thirdparty.parent === undefined); } } } @@ -102,6 +112,10 @@ export default { &:before{ content: " " } + &.tparty-parent { + font-weight: bold; + font-variant: all-small-caps; + } } From 13b96637bbaf0ecaf78beb5e9c46bd3fc1583718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 13 Oct 2021 22:58:54 +0200 Subject: [PATCH 12/28] Refactor address vue app and create a PickAddressType --- .../Resources/views/Form/fields.html.twig | 22 +++-- .../AddressToIdDataTransformer.php | 45 ++++++++++ .../Form/Type/PickAddressType.php | 52 +++++++++++ .../Resources/public/vuejs/Address/App.vue | 6 +- .../vuejs/Address/mod_input_address_index.js | 87 ++++++++++++++++++ .../ChillMainBundle/chill.webpack.config.js | 1 + .../ChillMainBundle/config/services/form.yaml | 9 ++ .../Entity/ThirdParty.php | 4 +- .../Form/ThirdPartyType.php | 9 +- .../vuejs/_components/OnTheFly/ThirdParty.vue | 49 +++++++--- .../views/ThirdParty/_form.html.twig | 11 ++- .../Resources/views/ThirdParty/new.html.twig | 8 ++ .../views/ThirdParty/update.html.twig | 89 ++----------------- 13 files changed, 282 insertions(+), 110 deletions(-) create mode 100644 src/Bundle/ChillMainBundle/Form/Type/DataTransformer/AddressToIdDataTransformer.php create mode 100644 src/Bundle/ChillMainBundle/Form/Type/PickAddressType.php create mode 100644 src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/mod_input_address_index.js diff --git a/src/Bundle/ChillCustomFieldsBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillCustomFieldsBundle/Resources/views/Form/fields.html.twig index a19f22e6f..e4e611b8d 100644 --- a/src/Bundle/ChillCustomFieldsBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillCustomFieldsBundle/Resources/views/Form/fields.html.twig @@ -1,16 +1,16 @@ {# * Copyright (C) 2014, Champs Libres Cooperative SCRLFS, - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . #} @@ -33,7 +33,7 @@ {# CFChoice : render the different elements in a choice list #} {% block cf_choices_row %}

{{ 'Choices'|trans }}

- +
@@ -47,8 +47,8 @@ {% endfor %}
- - + + {# we use javascrit to add an additional element. All functions are personnalized with the id ( = form.vars.id) #} diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue new file mode 100644 index 000000000..01667eab7 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue index be332523d..c40cc9cbc 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/Dates.vue @@ -1,5 +1,8 @@ From 9cbac89cae9245eb43a7dd94e5364cf8239909e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Fri, 15 Oct 2021 17:43:28 +0200 Subject: [PATCH 27/28] handle leaving household --- .../vuejs/HouseholdMembersEditor/App.vue | 27 +++++++- .../components/CurrentHousehold.vue | 25 +++++++- .../components/Household.vue | 62 +++++++++++++++---- .../vuejs/HouseholdMembersEditor/js/i18n.js | 4 +- 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue index c2112007f..52eac5ea6 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/App.vue @@ -15,7 +15,7 @@
    -
  • +
  • @@ -77,6 +77,11 @@ export default { return s; }, + hasReturnPath() { + let params = new URLSearchParams(window.location.search); + + return params.has('returnPath'); + }, // return true if the next step is allowed isNextAllowed() { switch (this.$data.step) { @@ -105,6 +110,9 @@ export default { if (this.$store.getters.isHouseholdNew) { this.$data.step = 'household_address'; break; + } else if (this.$store.getters.isModeLeave) { + this.$data.step = 'confirm'; + break; } else { this.$data.step = 'positioning'; break; @@ -118,7 +126,22 @@ export default { } }, goToPrevious() { - this.$data.step = 'concerned'; + if (this.$data.step === 'concerned') { + let params = new URLSearchParams(window.location.search); + if (params.has('returnPath')) { + window.location.replace(params.get('returnPath')); + } else { + return; + } + } + + let s = this.steps; + let index = s.indexOf(this.$data.step); + if (s[index - 1] === undefined) { + throw Error("step not found"); + } + + this.$data.step = s[index - 1]; }, confirm() { this.$store.dispatch('confirm'); diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue index 01667eab7..1f76c8a5b 100644 --- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue +++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/HouseholdMembersEditor/components/CurrentHousehold.vue @@ -4,10 +4,30 @@
+
+
+
+
+
+
+ + + + + {{ $t('household_members_editor.household.leave_without_household') }} +
+
+
+
+ {{ $t('household_members_editor.household.will_leave_any_household_explanation')}} +
+
+
+