Commit 76fe802a authored by Christian BUFFIN's avatar Christian BUFFIN
Browse files

Corrections et améliorations du paramétrage des responsables (cf. issue 362)

parent d0c2e660
This diff is collapsed.
......@@ -147,7 +147,6 @@ class SoustraitantsController extends AppController {
if ($success === true) {
$this->Soustraitant->SoustraitantOrganisation->Organisation->commit();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flashsuccessSousTraitantAffecterEnregistrer'), 'flashsuccess');
$this->redirect(['action' => 'index']);
} else {
$this->Soustraitant->SoustraitantOrganisation->Organisation->rollback();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flasherrorErreurEnregistrementSousTraitantAffecter'), 'flasherror');
......@@ -172,7 +171,7 @@ class SoustraitantsController extends AppController {
]
);
return($mesOrganisations);
return $mesOrganisations;
}
/**
......@@ -183,10 +182,10 @@ class SoustraitantsController extends AppController {
*/
protected function _optionsFiltre($organisation_id = null) {
$options = [
'ape' => $this->Soustraitant->getStringOptionList('ape', $organisation_id),
'organisations' => $this->Soustraitant->Organisation->find('list', ['order' => ['Organisation.raisonsociale ASC']]),
'raisonsociale' => $this->Soustraitant->getStringOptionList('raisonsociale', $organisation_id),
'siret' => $this->Soustraitant->getStringOptionList('siret', $organisation_id),
'ape' => $this->Soustraitant->getStringOptionList('ape', $organisation_id)
];
return $options;
......
......@@ -22,13 +22,13 @@ msgid "responsable.titreGestionResponsableEntitee"
msgstr "Liste des responsables présents dans l'entité"
msgid "responsable.titreAjouterResponsable"
msgstr "Ajouter un responsable"
msgstr "Ajout d'un responsable"
msgid "responsable.titreModifierResponsable"
msgstr "Modifier un responsable"
msgstr "Modification d'un responsable"
msgid "responsable.titreVisualiserResponsable"
msgstr "Visualiser un responsable"
msgstr "Visualisation d'un responsable"
###############################################################################
......@@ -36,11 +36,14 @@ msgstr "Visualiser un responsable"
#### SUCCESS ####
msgid "responsable.flashsuccessSaveResponsable"
msgstr "Le responsable a bien été enregistré"
msgid "responsable.flashsuccessDissocierResponsableEntite"
msgstr "La dissociation du responsable de l'entité a été enregistée"
msgstr "La dissociation du responsable de l'entité a été enregistrée"
msgid "responsable.flashsuccessSuppressionResponsableEntite"
msgstr "La suppression du responsable pour l'entité a été enregistée"
msgstr "La suppression du responsable a été enregistrée"
msgid "responsable.flashsuccessSousTraitantAffecterEnregistrer"
msgstr "Le responsable a été associé dans l'entité"
......@@ -49,6 +52,9 @@ msgstr "Le responsable a été associé dans l'entité"
#### ERREUR ####
msgid "responsable.flasherrorSaveResponsable"
msgstr "Une erreur est survenue lors de l'enregistrement du responsable"
msgid "responsable.flasherrorErreurDissocierResponsableEntite"
msgstr "Une erreur est survenue lors de la dissociation du responsable de l'entité"
......@@ -73,6 +79,12 @@ msgstr " Filtrer les responsables"
msgid "responsable.champFiltreEntite"
msgstr "Filtrer par entité"
msgid "responsable.champFiltreEntiteAssociee"
msgstr "Filtrer par entité associée"
msgid "responsable.champFiltreEntiteCreatrice"
msgstr "Filtrer par entité créatrice"
msgid "responsable.placeholderChoisirEntite"
msgstr "Choisir une entité"
......@@ -209,6 +221,9 @@ msgstr "La structure du co-responsable"
msgid "responsable.champRaisonsocialestructure"
msgstr "Raison sociale"
msgid "responsable.titreTableauEntiteResponsable"
msgstr "Entité(s) associée(s)"
msgid "responsable.placeholderChampRaisonsocialestructure"
msgstr "Raison sociale (requis)"
......
<?php
App::uses('LinkedOrganisationInterface', 'Model/Interface');
class FieldAsFilterOptionBehavior extends ModelBehavior
{
/**
* @param Model $model
* @param array $config
*/
public function setup( Model $model, $config = [] )
{
if (is_a($model, 'LinkedOrganisationInterface') === false) {
$message = 'La classe %s doit implémenter LinkedOrganisationInterface pour pouvoir être utilisée';
throw new RuntimeException(sprintf($message, get_class($model)));
}
}
/**
* Retourne une liste (en clé et en valeur) uniques et triées pour un champ particulier.
*
* @param string $fieldName
* @param int $organisation_id
* @return array
*/
public function getStringOptionList(Model $model, $fieldName, $organisation_id) {
$query = [
'fields' => [
"{$model->alias}.{$fieldName}",
"{$model->alias}.{$fieldName}",
],
'conditions' => [],
'group' => [
"{$model->alias}.{$fieldName}",
],
'order' => ["{$model->alias}.{$fieldName} ASC"]
];
if ($organisation_id !== null) {
$query['conditions'][] = $model->getConditionOrganisation($organisation_id);
}
return $model->find('list', $query);
}
}
......@@ -21,8 +21,9 @@
*/
App::uses('AppModel', 'Model');
App::uses('LinkedOrganisationInterface', 'Model/Interface');
class Responsable extends AppModel {
class Responsable extends AppModel implements LinkedOrganisationInterface {
public $name = 'Responsable';
......@@ -43,12 +44,22 @@ class Responsable extends AppModel {
'formatStripNotAlnum' => '/^(telephoneresponsable|telephonestructure|faxstructure|siretstructure)$/'
]
],
'FieldAsFilterOption',
'LettercaseFormattable' => [
'upper_noaccents' => ['nomresponsable'],
'title' => ['prenomresponsable']
]
];
/**
* Champs virtuels du modèle
*
* @var array
*/
public $virtualFields = [
'nom_complet' => '( COALESCE( "Responsable"."prenomresponsable", \'\' ) || \' \' || COALESCE( "Responsable"."nomresponsable", \'\' ))',
];
/**
* validate associations
*
......@@ -119,4 +130,41 @@ class Responsable extends AppModel {
'with' => 'ResponsableOrganisation'
]
];
/**
* Retourne les id des organisations liées au responsable.
*
* @param int $id
* @return array
*/
public function getLinkedOrganisationsIds($id) {
$query = [
'fields' => ['organisation_id'],
'conditions' => ['responsable_id' => $id],
];
return Hash::extract(
$this->ResponsableOrganisation->find('all', $query),
'{n}.ResponsableOrganisation.organisation_id'
);
}
/**
* Retourne une condition permettant de limiter aux sous-traitants liés à une ou plusieurs entités.
*
* @param array|int $organisation_id
* @return string
*/
public function getConditionOrganisation($organisation_id) {
$query = [
'alias' => 'responsables_organisations',
'fields' => [
'responsables_organisations.responsable_id'
],
'conditions' => [
'responsables_organisations.organisation_id' => $organisation_id
]
];
$sql = $this->ResponsableOrganisation->sql($query);
return "{$this->alias}.{$this->primaryKey} IN ( {$sql} )";
}
}
......@@ -43,7 +43,8 @@ class Soustraitant extends AppModel implements LinkedOrganisationInterface {
'formatSuffix' => '/_id$/',
'formatStripNotAlnum' => '/^(telephone|fax|siret)$/'
]
]
],
'FieldAsFilterOption',
];
/**
......@@ -147,34 +148,4 @@ class Soustraitant extends AppModel implements LinkedOrganisationInterface {
$sql = $this->SoustraitantOrganisation->sql($query);
return "{$this->alias}.{$this->primaryKey} IN ( {$sql} )";
}
/**
* Retourne une liste (en clé et en valeur) uniques et triées pour un champ particulier.
*
* @todo: dans un behavior ?
*
* @param string $fieldName
* @param int $organisation_id
* @return array
*/
public function getStringOptionList($fieldName, $organisation_id) {
$query = [
'fields' => [
"{$this->alias}.{$fieldName}",
"{$this->alias}.{$fieldName}",
],
'conditions' => [],
'group' => [
"{$this->alias}.{$fieldName}",
],
'order' => ["{$this->alias}.{$fieldName} ASC"]
];
if ($organisation_id !== null) {
$query['conditions'][] = $this->getConditionOrganisation($organisation_id);
}
return $this->find('list', $query);
}
}
<?php
App::uses('AppController', 'Controller');
App::uses( 'ControllerTestCaseAccessTrait', 'Test/Trait/Controller' );
/**
* Tests d'intégration de la classe ResponsablesController.
*
* ./cake_utils.sh tests app Controller/ResponsablesController
*
* @package app.Test.Case.Controller
*/
class ResponsablesControllerTest extends ControllerTestCase
{
use ControllerTestCaseAccessTrait;
public $fixtures = [
'app.Fiche',
'app.ListeDroit',
'app.Notification',
'app.Organisation',
'app.OrganisationUser',
'app.OrganisationUserRole',
'app.Responsable',
'app.ResponsableOrganisation',
'app.Role',
'app.RoleDroit',
'app.User',
'app.Valeur',
];
public function setUp() {
parent::setUp();
$this->controller = $this->generate('Responsables');
}
public function dataAccessAdd() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
[200, 'Superadministrateur.superadmin', '/responsables/add'],
[200, 'Administrateur.ibleu', '/responsables/add'],
[200, 'DPO.nroux', '/responsables/add'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
[403, 'Rédacteur.rjaune', '/responsables/add'],
[403, 'Valideur.cnoir', '/responsables/add'],
[403, 'Consultant.mrose', '/responsables/add'],
];
}
/**
* @dataProvider dataAccessAdd
*/
public function testAccessAdd($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessDelete() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
// 1.1. Enregistrement existant
[302, 'Superadministrateur.superadmin', '/responsables/delete/1'],
[302, 'Administrateur.ibleu', '/responsables/delete/1'],
[302, 'DPO.nroux', '/responsables/delete/1'],
// Un utilisateur mono-collectivité ne peut pas accéder à l'enregistrement d'une autre collectivité
[403, 'Administrateur.findigo', '/responsables/delete/1'],
[403, 'DPO.hvermeil', '/responsables/delete/1'],
// 1.2. Enregistrement inexistant
[404, 'Superadministrateur.superadmin', '/responsables/delete/666'],
[404, 'Administrateur.ibleu', '/responsables/delete/666'],
[404, 'DPO.nroux', '/responsables/delete/666'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
// 1.1. Enregistrement existant
[403, 'Rédacteur.rjaune', '/responsables/delete/1'],
[403, 'Valideur.cnoir', '/responsables/delete/1'],
[403, 'Consultant.mrose', '/responsables/delete/1'],
// 2.2. Enregistrement inexistant
[403, 'Rédacteur.rjaune', '/responsables/delete/666'],
[403, 'Valideur.cnoir', '/responsables/delete/666'],
[403, 'Consultant.mrose', '/responsables/delete/666'],
];
}
/**
* @dataProvider dataAccessDelete
*/
public function testAccessDelete($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessDissocierResponsable() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
// 1.1. Enregistrement existant et associé
[302, 'Superadministrateur.superadmin', '/responsables/dissocierResponsable/8'],
[302, 'Administrateur.ibleu', '/responsables/dissocierResponsable/8'],
[302, 'DPO.nroux', '/responsables/dissocierResponsable/8'],
// Un utilisateur mono-collectivité ne peut pas accéder à l'enregistrement d'une autre collectivité
[403, 'Administrateur.findigo', '/responsables/dissocierResponsable/8'],
[403, 'DPO.hvermeil', '/responsables/dissocierResponsable/8'],
// 1.2. Enregistrement inexistant
[404, 'Superadministrateur.superadmin', '/responsables/dissocierResponsable/666'],
[404, 'Administrateur.ibleu', '/responsables/dissocierResponsable/666'],
[404, 'DPO.nroux', '/responsables/dissocierResponsable/666'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
// 1.1. Enregistrement existant
[403, 'Rédacteur.rjaune', '/responsables/dissocierResponsable/8'],
[403, 'Valideur.cnoir', '/responsables/dissocierResponsable/8'],
[403, 'Consultant.mrose', '/responsables/dissocierResponsable/8'],
// 2.2. Enregistrement inexistant
[403, 'Rédacteur.rjaune', '/responsables/dissocierResponsable/666'],
[403, 'Valideur.cnoir', '/responsables/dissocierResponsable/666'],
[403, 'Consultant.mrose', '/responsables/dissocierResponsable/666'],
];
}
/**
* @dataProvider dataAccessDissocierResponsable
*/
public function testAccessDissocierResponsable($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessEdit() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
// 1.1. Enregistrement existant
[200, 'Superadministrateur.superadmin', '/responsables/edit/1'],
[200, 'Administrateur.ibleu', '/responsables/edit/1'],
[200, 'DPO.nroux', '/responsables/edit/1'],
// Un utilisateur mono-collectivité ne peut pas accéder à l'enregistrement d'une autre collectivité
[403, 'Administrateur.findigo', '/responsables/edit/1'],
[403, 'DPO.hvermeil', '/responsables/edit/1'],
// 1.2. Enregistrement inexistant
[404, 'Superadministrateur.superadmin', '/responsables/edit/666'],
[404, 'Administrateur.ibleu', '/responsables/edit/666'],
[404, 'DPO.nroux', '/responsables/edit/666'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
// 1.1. Enregistrement existant
[403, 'Rédacteur.rjaune', '/responsables/edit/1'],
[403, 'Valideur.cnoir', '/responsables/edit/1'],
[403, 'Consultant.mrose', '/responsables/edit/1'],
// 2.2. Enregistrement inexistant
[403, 'Rédacteur.rjaune', '/responsables/edit/666'],
[403, 'Valideur.cnoir', '/responsables/edit/666'],
[403, 'Consultant.mrose', '/responsables/edit/666'],
];
}
/**
* @dataProvider dataAccessEdit
*/
public function testAccessEdit($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessEntite() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
[200, 'Superadministrateur.superadmin', '/responsables/entite'],
[200, 'Administrateur.ibleu', '/responsables/entite'],
[200, 'DPO.nroux', '/responsables/entite'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
[403, 'Rédacteur.rjaune', '/responsables/entite'],
[403, 'Valideur.cnoir', '/responsables/entite'],
[403, 'Consultant.mrose', '/responsables/entite'],
];
}
/**
* @dataProvider dataAccessEntite
*/
public function testAccessEntite($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessIndex() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
[200, 'Superadministrateur.superadmin', '/responsables/index'],
[200, 'Administrateur.ibleu', '/responsables/index'],
[200, 'DPO.nroux', '/responsables/index'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
[403, 'Rédacteur.rjaune', '/responsables/index'],
[403, 'Valideur.cnoir', '/responsables/index'],
[403, 'Consultant.mrose', '/responsables/index'],
];
}
/**
* @dataProvider dataAccessIndex
*/
public function testAccessIndex($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
public function dataAccessShow() {
return [
// 1. Utilisateurs pouvant accéder à la fonctionnalité
// 1.1. Enregistrement existant
[200, 'Superadministrateur.superadmin', '/responsables/show/1'],
[200, 'Administrateur.ibleu', '/responsables/show/1'],
[200, 'DPO.nroux', '/responsables/show/1'],
// 1.2. Enregistrement inexistant
[404, 'Superadministrateur.superadmin', '/responsables/show/666'],
[404, 'Administrateur.ibleu', '/responsables/show/666'],
[404, 'DPO.nroux', '/responsables/show/666'],
// 2. Utilisateurs ne pouvant pas accéder à la fonctionnalité
// 1.1. Enregistrement existant
[403, 'Rédacteur.rjaune', '/responsables/show/1'],
[403, 'Valideur.cnoir', '/responsables/show/1'],
[403, 'Consultant.mrose', '/responsables/show/1'],
// 2.2. Enregistrement inexistant
[403, 'Rédacteur.rjaune', '/responsables/show/666'],
[403, 'Valideur.cnoir', '/responsables/show/666'],
[403, 'Consultant.mrose', '/responsables/show/666'],
];
}
/**
* @dataProvider dataAccessShow
*/
public function testAccessShow($expectedStatus, $user, $url, $options = []) {
$this->assertActionAccess($expectedStatus, $user, $url, $options);
}
}
<?php
echo $this->Html->script('jquery-mask-plugin/dist/jquery.mask.min.js');
echo $this->Html->script('responsables.js');
if (isset($this->validationErrors['Responsable']) && !empty($this->validationErrors['Responsable'])) {
?>
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"><!----></span>
<span class="sr-only">Error:</span>
Ces erreurs se sont produites:
<ul>
<?php
foreach ($this->validationErrors as $donnees) {
foreach ($donnees as $champ) {
foreach ($champ as $error) {
echo '<li>' . $error . '</li>';
}
}
}
?>
</ul>
</div>
<?php
}
?>
<?php
echo $this->WebcilForm->create('Responsable',[
'url' => 'add',
'type' => 'file',
'autocomplete' => 'off',
'inputDefaults' => ['div' => false],
'class' => 'form-horizontal',
'novalidate' => 'novalidate'
]);
?>
<div class="users form">
<h2>
<?php
// Texte : "Le co-responsable :"
echo __d('responsable', 'responsable.titreResponsable');
?>
</h2>
<div class="row">
<!-- Colonne de gauche -->
<div class="col-md-6">
<?php
echo $this->WebcilForm->inputs([
'nomresponsable' => [
'id' => 'nomresponsable',
'required' => true
],
'prenomresponsable' => [
'id' => 'prenomresponsable',
'required' => true
],
'fonctionresponsable' => [
'id' => 'fonctionresponsable',
'required' => true
]
]);
?>
</div>
<!-- Colonne de droite -->
<div class="col-md-6">
<?php
echo $this->WebcilForm->inputs([
'emailresponsable' => [
'id' => 'emailresponsable',
'required' => true
],
'telephoneresponsable' => [
'id' => 'telephoneresponsable',
'required' => true
]
]);
?>
</div>
</div>
<!--Information sur la structure du co-responsable -->
<h2>
<?php
echo __d('responsable', 'responsable.titreStructureResponsable');
?>
</h2>
<div class="row">
<!-- Colonne de gauche -->
<div class="col-md-6">
<?php
echo $this->WebcilForm->inputs([
'raisonsocialestructure' => [
'id' => 'raisonsocialestructure',
'required' => true
],
'siretstructure' => [
'id' => 'siretstructure',
'required' => true
],
'apestructure' => [
'id' => 'apestructure',
'required' => true
]
]);
?>
</div>
<!-- Colonne de droite -->
<div class="col-md-6">
<?php
echo $this->WebcilForm->inputs([
'telephonestructure' => [
'id' => 'telephonestructure'
],
'faxstructure' => [
'id' => 'faxstructure'