Merge branch '364-tel2-third-party' into 'master'

Adding a second phone number to thirdparty entity

Closes #364

See merge request Chill-Projet/chill-bundles!810
This commit is contained in:
Julien Fastré 2025-04-15 12:59:58 +00:00
commit 3aa4fac80d
22 changed files with 168 additions and 15 deletions

View File

@ -0,0 +1,7 @@
kind: Feature
body: Added a second phone number "telephone2" to the thirdParty entity. Adapted twig
templates and vuejs apps to handle this phone number
time: 2025-03-25T16:43:01.003712495+01:00
custom:
Issue: "364"
SchemaChange: Add columns or tables

View File

@ -0,0 +1,9 @@
kind: Fixed
body: |-
FIXED wrong translations in the on-the-fly for creation of thirdParty
FIXED update of phone number in on-the-fly edition of thirdParty
FIXED closing of modal when editing thirdParty in accompanying course works
time: 2025-03-25T16:43:27.437038378+01:00
custom:
Issue: ""
SchemaChange: No schema change

View File

@ -26,9 +26,9 @@
trans(THIRDPARTY_CONTACT_OF) trans(THIRDPARTY_CONTACT_OF)
}}</span> }}</span>
<span v-else-if="props.entity.kind === 'company'">{{ <span v-else-if="props.entity.kind === 'company'">{{
trans(THIRDPARTY_A_CONTACT) trans(THIRDPARTY_A_COMPANY)
}}</span> }}</span>
<span v-else>{{ $t("thirdparty.contact") }}</span> <span v-else>{{ trans(THIRDPARTY_A_CONTACT) }}</span>
</template> </template>
</span> </span>
@ -54,6 +54,7 @@ import {
ACCEPTED_USERS, ACCEPTED_USERS,
THIRDPARTY_A_CONTACT, THIRDPARTY_A_CONTACT,
THIRDPARTY_CONTACT_OF, THIRDPARTY_CONTACT_OF,
THIRDPARTY_A_COMPANY,
PERSON, PERSON,
THIRDPARTY, THIRDPARTY,
} from "translator"; } from "translator";

View File

@ -204,7 +204,8 @@ export default {
} else if (payload.type === "thirdparty") { } else if (payload.type === "thirdparty") {
body.name = payload.data.text; body.name = payload.data.text;
body.email = payload.data.email; body.email = payload.data.email;
body.telephone = payload.data.phonenumber; body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = { id: payload.data.address.address_id }; body.address = { id: payload.data.address.address_id };
makeFetch( makeFetch(

View File

@ -385,7 +385,8 @@ export default {
} else if (payload.type === "thirdparty") { } else if (payload.type === "thirdparty") {
body.name = payload.data.text; body.name = payload.data.text;
body.email = payload.data.email; body.email = payload.data.email;
body.telephone = payload.data.phonenumber; body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
if (payload.data.address) { if (payload.data.address) {
body.address = { id: payload.data.address.address_id }; body.address = { id: payload.data.address.address_id };
} }

View File

@ -194,6 +194,7 @@ export default {
body.name = payload.data.name; body.name = payload.data.name;
body.email = payload.data.email; body.email = payload.data.email;
body.telephone = payload.data.telephone; body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = payload.data.address body.address = payload.data.address
? { id: payload.data.address.address_id } ? { id: payload.data.address.address_id }
: null; : null;

View File

@ -745,7 +745,8 @@ export default {
let body = { type: payload.type }; let body = { type: payload.type };
body.name = payload.data.text; body.name = payload.data.text;
body.email = payload.data.email; body.email = payload.data.email;
body.telephone = payload.data.phonenumber; body.telephone = payload.data.telephone;
body.telephone2 = payload.data.telephone2;
body.address = { id: payload.data.address.address_id }; body.address = { id: payload.data.address.address_id };
makeFetch( makeFetch(
@ -755,7 +756,9 @@ export default {
) )
.then((response) => { .then((response) => {
this.$store.dispatch("updateThirdParty", response); this.$store.dispatch("updateThirdParty", response);
this.$refs.onTheFly.closeModal(); for (let otf of this.$refs.onTheFly) {
otf.closeModal();
}
}) })
.catch((error) => { .catch((error) => {
if (error.name === "ValidationException") { if (error.name === "ValidationException") {

View File

@ -65,6 +65,7 @@ class ThirdpartyCSVExportController extends AbstractController
'Name', 'Name',
'Profession', 'Profession',
'Telephone', 'Telephone',
'Telephone2',
'Email', 'Email',
'Address', 'Address',
'Comment', 'Comment',
@ -76,6 +77,7 @@ class ThirdpartyCSVExportController extends AbstractController
'Contact name', 'Contact name',
'Contact firstname', 'Contact firstname',
'Contact phone', 'Contact phone',
'Contact phone2',
'Contact email', 'Contact email',
'Contact address', 'Contact address',
'Contact profession', 'Contact profession',

View File

@ -209,6 +209,11 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
#[PhonenumberConstraint(type: 'any')] #[PhonenumberConstraint(type: 'any')]
private ?PhoneNumber $telephone = null; private ?PhoneNumber $telephone = null;
#[Groups(['read', 'write', 'docgen:read', 'docgen:read:3party:parent'])]
#[ORM\Column(name: 'telephone2', type: 'phone_number', nullable: true)]
#[PhonenumberConstraint(type: 'any')]
private ?PhoneNumber $telephone2 = null;
#[ORM\Column(name: 'types', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)] #[ORM\Column(name: 'types', type: \Doctrine\DBAL\Types\Types::JSON, nullable: true)]
private ?array $thirdPartyTypes = []; private ?array $thirdPartyTypes = [];
@ -429,6 +434,11 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
return $this->telephone; return $this->telephone;
} }
public function getTelephone2(): ?PhoneNumber
{
return $this->telephone2;
}
/** /**
* Get type. * Get type.
*/ */
@ -712,6 +722,13 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface, \Strin
return $this; return $this;
} }
public function setTelephone2(?PhoneNumber $telephone2 = null): self
{
$this->telephone2 = $telephone2;
return $this;
}
/** /**
* Set type. * Set type.
* *

View File

@ -59,6 +59,10 @@ class ThirdPartyType extends AbstractType
'label' => 'Phonenumber', 'label' => 'Phonenumber',
'required' => false, 'required' => false,
]) ])
->add('telephone2', ChillPhoneNumberType::class, [
'label' => 'telephone2',
'required' => false,
])
->add('email', EmailType::class, [ ->add('email', EmailType::class, [
'required' => false, 'required' => false,
]) ])

View File

@ -42,6 +42,7 @@ class ThirdPartyRepository implements ObjectRepository
parent.name AS name, parent.name AS name,
parent.profession AS profession, parent.profession AS profession,
parent.telephone AS telephone, parent.telephone AS telephone,
parent.telephone2 AS telephone2,
parent.email AS email, parent.email AS email,
CONCAT_WS(' ', parent_address.street, parent_address.streetnumber, parent_postal.code, parent_postal.label) AS address, CONCAT_WS(' ', parent_address.street, parent_address.streetnumber, parent_postal.code, parent_postal.label) AS address,
parent.comment AS comment, parent.comment AS comment,
@ -55,6 +56,7 @@ class ThirdPartyRepository implements ObjectRepository
contact.name AS contact_name, contact.name AS contact_name,
contact.firstname AS contact_firstname, contact.firstname AS contact_firstname,
contact.telephone AS contact_phone, contact.telephone AS contact_phone,
contact.telephone2 AS contact_phone2,
contact.email AS contact_email, contact.email AS contact_email,
contact.profession AS contact_profession, contact.profession AS contact_profession,
CONCAT_WS(' ', contact_address.street, contact_address.streetnumber, contact_postal.code, contact_postal.label) AS contact_address CONCAT_WS(' ', contact_address.street, contact_address.streetnumber, contact_postal.code, contact_postal.label) AS contact_address

View File

@ -91,6 +91,18 @@
}}</a }}</a
> >
</li> </li>
<li v-if="thirdparty.telephone2">
<i class="fa fa-li fa-mobile" />
<a
:href="
'tel: ' +
thirdparty.telephone2
"
>{{
thirdparty.telephone2
}}</a
>
</li>
<li v-if="thirdparty.email"> <li v-if="thirdparty.email">
<i <i
class="fa fa-li fa-envelope-o" class="fa fa-li fa-envelope-o"
@ -121,6 +133,12 @@
thirdparty.telephone thirdparty.telephone
}}</a> }}</a>
</li> </li>
<li v-if="thirdparty.telephone2">
<i class="fa fa-li fa-mobile" />
<a :href="'tel: ' + thirdparty.telephone2"
>{{ thirdparty.telephone2 }}
</a>
</li>
<li v-if="thirdparty.email"> <li v-if="thirdparty.email">
<i class="fa fa-li fa-envelope-o" /> <i class="fa fa-li fa-envelope-o" />
<a :href="'mailto: ' + thirdparty.email">{{ <a :href="'mailto: ' + thirdparty.email">{{

View File

@ -223,6 +223,19 @@
/> />
</div> </div>
<div class="input-group mb-3">
<span class="input-group-text" id="phonenumber2"
><i class="fa fa-fw fa-phone"
/></span>
<input
class="form-control form-control-lg"
v-model="thirdparty.telephone2"
:placeholder="$t('thirdparty.phonenumber2')"
:aria-label="$t('thirdparty.phonenumber2')"
aria-describedby="phonenumber2"
/>
</div>
<div v-if="parent"> <div v-if="parent">
<div class="input-group mb-3"> <div class="input-group mb-3">
<span class="input-group-text" id="comment" <span class="input-group-text" id="comment"
@ -263,6 +276,7 @@ export default {
firstname: "", firstname: "",
name: "", name: "",
telephone: "", telephone: "",
telephone2: "",
civility: null, civility: null,
profession: "", profession: "",
}, },
@ -368,9 +382,11 @@ export default {
addQueryItem(field, queryItem) { addQueryItem(field, queryItem) {
switch (field) { switch (field) {
case "name": case "name":
this.thirdparty.name if (this.thirdparty.name) {
? (this.thirdparty.name += ` ${queryItem}`) this.thirdparty.name += ` ${queryItem}`;
: (this.thirdparty.name = queryItem); } else {
this.thirdparty.name = queryItem;
}
break; break;
case "firstName": case "firstName":
this.thirdparty.firstname = queryItem; this.thirdparty.firstname = queryItem;

View File

@ -6,6 +6,7 @@ const thirdpartyMessages = {
name: "Dénomination", name: "Dénomination",
email: "Courriel", email: "Courriel",
phonenumber: "Téléphone", phonenumber: "Téléphone",
phonenumber2: "Autre numéro de téléphone",
comment: "Commentaire", comment: "Commentaire",
profession: "Qualité", profession: "Qualité",
civility: "Civilité", civility: "Civilité",

View File

@ -115,6 +115,10 @@
{% else %} {% else %}
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span> <span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
{% endif %} {% endif %}
{% if thirdparty.telephone2 is not null %}
{% if thirdparty.telephone is not null %}, {% endif %}
<a href="{{ 'tel:' ~ thirdparty.telephone2|phone_number_format('E164') }}">{{ thirdparty.telephone2|chill_format_phonenumber }}</a>
{% endif %}
</li> </li>
<li><i class="fa fa-li fa-envelope-o"></i> <li><i class="fa fa-li fa-envelope-o"></i>
<a href="{{ 'mailto:' ~ thirdparty.email }}"> <a href="{{ 'mailto:' ~ thirdparty.email }}">
@ -135,8 +139,14 @@
}) }} }) }}
</li> </li>
<li><i class="fa fa-li fa-phone"></i> <li><i class="fa fa-li fa-phone"></i>
{% if thirdparty.telephone %} {% if thirdparty.telephone or thirdparty.telephone2 %}
<a href="{{ 'tel:' ~ thirdparty.telephone|phone_number_format('E164') }}">{{ thirdparty.telephone|chill_format_phonenumber }}</a> {% if thirdparty.telephone is not null %}
<a href="{{ 'tel:' ~ thirdparty.telephone|phone_number_format('E164') }}">{{ thirdparty.telephone|chill_format_phonenumber }}</a>
{% endif %}
{% if thirdparty.telephone2 is not null %}
{% if thirdparty.telephone is not null %}, {% endif %}
<a href="{{ 'tel:' ~ thirdparty.telephone2|phone_number_format('E164') }}">{{ thirdparty.telephone2|chill_format_phonenumber }}</a>
{% endif %}
{% else %} {% else %}
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span> <span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
{% endif %} {% endif %}

View File

@ -22,6 +22,7 @@
{{ form_row(form.typesAndCategories) }} {{ form_row(form.typesAndCategories) }}
{{ form_row(form.telephone) }} {{ form_row(form.telephone) }}
{{ form_row(form.telephone2) }}
{{ form_row(form.email) }} {{ form_row(form.email) }}
{% if form.contactDataAnonymous is defined %} {% if form.contactDataAnonymous is defined %}

View File

@ -24,17 +24,24 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="form-group col-md-5 mb-3"> <div class="form-group col-md-6 mb-3">
{{ form_widget(form.telephone) }} {{ form_widget(form.telephone) }}
{{ form_errors(form.telephone) }} {{ form_errors(form.telephone) }}
{{ form_label(form.telephone) }} {{ form_label(form.telephone) }}
</div> </div>
<div class="form-group col-md-5 mb-3"> <div class="form-group col-md-6 mb-3">
{{ form_widget(form.telephone2) }}
{{ form_errors(form.telephone2) }}
{{ form_label(form.telephone2) }}
</div>
</div>
<div class="row">
<div class="form-group col-md-6 mb-3">
{{ form_widget(form.email) }} {{ form_widget(form.email) }}
{{ form_errors(form.email) }} {{ form_errors(form.email) }}
{{ form_label(form.email) }} {{ form_label(form.email) }}
</div> </div>
<div class="form-group col-md-2 mb-3"> <div class="form-group col-md-6 mb-3">
{{ form_widget(form.contactDataAnonymous) }} {{ form_widget(form.contactDataAnonymous) }}
{{ form_label(form.contactDataAnonymous) }} {{ form_label(form.contactDataAnonymous) }}
{{ form_errors(form.contactDataAnonymous) }} {{ form_errors(form.contactDataAnonymous) }}

View File

@ -76,6 +76,18 @@
{% endif %} {% endif %}
</dd> </dd>
<dt>{{ 'Phonenumber2'|trans }}</dt>
<dd>
{% if thirdParty.telephone2 == null %}
<span class="chill-no-data-statement">{{ 'thirdparty.No_phonenumber'|trans }}</span>
{% else %}
<a href="{{ 'tel:' ~ thirdParty.telephone2|phone_number_format('E164') }}">
{{ thirdParty.telephone2|chill_format_phonenumber }}
</a>
{% endif %}
</dd>
<dt>{{ 'email'|trans }}<dt> <dt>{{ 'email'|trans }}<dt>
<dd> <dd>
{% if thirdParty.email == null %} {% if thirdParty.email == null %}

View File

@ -55,6 +55,7 @@ class ThirdPartyNormalizer implements NormalizerAwareInterface, NormalizerInterf
'profession' => $this->normalizer->normalize($thirdParty->getProfession(), $format, $context), 'profession' => $this->normalizer->normalize($thirdParty->getProfession(), $format, $context),
'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']), 'address' => $this->normalizer->normalize($thirdParty->getAddress(), $format, ['address_rendering' => 'short']),
'telephone' => $this->normalizer->normalize($thirdParty->getTelephone(), $format, $context), 'telephone' => $this->normalizer->normalize($thirdParty->getTelephone(), $format, $context),
'telephone2' => $this->normalizer->normalize($thirdParty->getTelephone2(), $format, $context),
'email' => $thirdParty->getEmail(), 'email' => $thirdParty->getEmail(),
'isChild' => $thirdParty->isChild(), 'isChild' => $thirdParty->isChild(),
'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context), 'parent' => $this->normalizer->normalize($thirdParty->getParent(), $format, $context),

View File

@ -28,6 +28,8 @@ components:
type: string type: string
telephone: telephone:
type: string type: string
telephone2:
type: string
address: address:
$ref: "#/components/schemas/Address" $ref: "#/components/schemas/Address"
Address: Address:

View File

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\ThirdParty;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20250325085950 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add a second telephone number to ThirdParty';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_3party.third_party ADD telephone2 VARCHAR(35) DEFAULT NULL');
$this->addSql('COMMENT ON COLUMN chill_3party.third_party.telephone2 IS \'(DC2Type:phone_number)\'');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_3party.third_party DROP telephone2');
}
}

View File

@ -4,6 +4,7 @@ third parties: tiers
firstname: Prénom firstname: Prénom
name: Nom name: Nom
telephone: Téléphone telephone: Téléphone
telephone2: Autre numéro de téléphone
adress: Adresse adress: Adresse
email: Courriel email: Courriel
comment: Commentaire comment: Commentaire
@ -39,7 +40,7 @@ thirdparty.A contact: Une personne physique
thirdparty.contact: Personne physique thirdparty.contact: Personne physique
thirdparty.Contact of: Contact de thirdparty.Contact of: Contact de
thirdparty.a_company_explanation: >- thirdparty.a_company_explanation: >-
Les personnes morales 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'institution. Il est également possible de
leur associer un acronyme, et le nom d'un service. leur associer un acronyme, et le nom d'un service.
thirdparty.a_contact_explanation: >- thirdparty.a_contact_explanation: >-
Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. Il est possible de leur Les personnes physiques ne disposent pas d'acronyme, de service, ou de contacts sous-jacents. Il est possible de leur
@ -149,6 +150,8 @@ Contact id: Identifiant du contact
Contact name: Nom du contact Contact name: Nom du contact
Contact firstname: Prénom du contact Contact firstname: Prénom du contact
Contact phone: Téléphone du contact Contact phone: Téléphone du contact
Contact phone2: Autre téléphone du contact
Telephone2: Autre téléphone
Contact email: Courrier électronique du contact Contact email: Courrier électronique du contact
Contact address: Adresse du contact Contact address: Adresse du contact
Contact profession: Profession du contact Contact profession: Profession du contact