From 8580e997f1256afd5e3d0374cee93be5e9b93eef Mon Sep 17 00:00:00 2001
From: "florian.azizian" <florian.azizian@maarch.org>
Date: Fri, 6 Dec 2019 11:37:00 +0100
Subject: [PATCH] FEAT #12510 TIME 3 admin contact parameters

---
 rest/index.php                                |   4 +-
 .../contact/controllers/ContactController.php |  48 ++++++--
 .../ContactCustomFieldController.php          |   2 +
 .../contact/models/ContactFillingModel.php    |   3 -
 .../contact/models/ContactParameterModel.php  | 104 ++++++++++++++++++
 ...acts-filling-administration.component.html |  40 ++++---
 ...ntacts-filling-administration.component.ts |  91 +++++----------
 src/frontend/lang/lang-fr.ts                  |  26 ++---
 8 files changed, 206 insertions(+), 112 deletions(-)
 create mode 100755 src/app/contact/models/ContactParameterModel.php

diff --git a/rest/index.php b/rest/index.php
index 1d89396000d..5bef194c4d8 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -127,8 +127,8 @@ $app->put('/contactsGroups/{id}', \Contact\controllers\ContactGroupController::c
 $app->delete('/contactsGroups/{id}', \Contact\controllers\ContactGroupController::class . ':delete');
 $app->post('/contactsGroups/{id}/contacts', \Contact\controllers\ContactGroupController::class . ':addContacts');
 $app->delete('/contactsGroups/{id}/contacts/{contactId}', \Contact\controllers\ContactGroupController::class . ':deleteContact');
-$app->get('/contactsFilling', \Contact\controllers\ContactController::class . ':getFilling');
-$app->put('/contactsFilling', \Contact\controllers\ContactController::class . ':updateFilling');
+$app->get('/contactsParameters', \Contact\controllers\ContactController::class . ':getContactsParameters');
+$app->put('/contactsParameters', \Contact\controllers\ContactController::class . ':updateContactsParameters');
 
 //Convert
 $app->post('/convertedFile', \Convert\controllers\ConvertPdfController::class . ':convertedFile');
diff --git a/src/app/contact/controllers/ContactController.php b/src/app/contact/controllers/ContactController.php
index 099f6568a3d..c7be64de672 100755
--- a/src/app/contact/controllers/ContactController.php
+++ b/src/app/contact/controllers/ContactController.php
@@ -17,6 +17,7 @@ use Contact\models\ContactCustomFieldListModel;
 use Contact\models\ContactCustomFieldModel;
 use Contact\models\ContactFillingModel;
 use Contact\models\ContactModel;
+use Contact\models\ContactParameterModel;
 use Entity\models\EntityModel;
 use Group\controllers\PrivilegeController;
 use History\controllers\HistoryController;
@@ -310,37 +311,60 @@ class ContactController
         return $response->withStatus(204);
     }
 
-    public function getFilling(Request $request, Response $response)
+    public function getContactsParameters(Request $request, Response $response)
     {
         if (!PrivilegeController::hasPrivilege(['privilegeId' => 'admin_contacts', 'userId' => $GLOBALS['id']])) {
             return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
         }
 
         $contactsFilling = ContactFillingModel::get();
-        $contactsFilling['rating_columns'] = json_decode($contactsFilling['rating_columns']);
+        $contactParameters = ContactParameterModel::get(['select' => ['*']]);
+        foreach ($contactParameters as $key => $parameter) {
+            if (strpos($parameter['identifier'], 'contactCustomField_') !== false) {
+                $contactCustomId = str_replace("contactCustomField_", "", $parameter['identifier']);
+                $customField = ContactCustomFieldListModel::getById(['select' => ['label'], 'id' => $contactCustomId]);
+                $contactParameters[$key]['label'] = $customField['label'];
+            } else {
+                $contactParameters[$key]['label'] = null;
+            }
+        }
 
-        return $response->withJson(['contactsFilling' => $contactsFilling]);
+        return $response->withJson(['contactsFilling' => $contactsFilling, 'contactsParameters' => $contactParameters]);
     }
 
-    public function updateFilling(Request $request, Response $response)
+    public function updateContactsParameters(Request $request, Response $response)
     {
         if (!PrivilegeController::hasPrivilege(['privilegeId' => 'admin_contacts', 'userId' => $GLOBALS['id']])) {
             return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
         }
 
         $data = $request->getParams();
-        $check = Validator::boolType()->validate($data['enable']);
-        $check = $check && Validator::arrayType()->validate($data['rating_columns']);
-        $check = $check && Validator::intVal()->notEmpty()->validate($data['first_threshold']) && $data['first_threshold'] > 0 && $data['first_threshold'] < 99;
-        $check = $check && Validator::intVal()->notEmpty()->validate($data['second_threshold']) && $data['second_threshold'] > 1 && $data['second_threshold'] < 100;
-        $check = $check && $data['first_threshold'] < $data['second_threshold'];
+        $check = Validator::arrayType()->validate($data['contactsParameters']);
+        $check = $check && Validator::arrayType()->validate($data['contactsFilling']);
+        $check = $check && Validator::boolType()->validate($data['contactsFilling']['enable']);
+        $check = $check && Validator::intVal()->notEmpty()->validate($data['contactsFilling']['first_threshold']) && $data['contactsFilling']['first_threshold'] > 0 && $data['contactsFilling']['first_threshold'] < 99;
+        $check = $check && Validator::intVal()->notEmpty()->validate($data['contactsFilling']['second_threshold']) && $data['contactsFilling']['second_threshold'] > 1 && $data['contactsFilling']['second_threshold'] < 100;
+        $check = $check && $data['contactsFilling']['first_threshold'] < $data['contactsFilling']['second_threshold'];
         if (!$check) {
             return $response->withStatus(400)->withJson(['errors' => 'Bad Request']);
         }
 
-        $data['rating_columns'] = json_encode($data['rating_columns']);
-
-        ContactFillingModel::update($data);
+        foreach ($data['contactsParameters'] as $contactParameter) {
+            unset($contactParameter['label']);
+            ContactParameterModel::update([
+                'set'   => [
+                    'id' => $contactParameter['id'],
+                    'mandatory'   => empty($contactParameter['mandatory']) ? 'false' : 'true',
+                    'filling'     => empty($contactParameter['filling']) ? 'false' : 'true',
+                    'searchable'  => empty($contactParameter['searchable']) ? 'false' : 'true',
+                    'displayable' => empty($contactParameter['displayable']) ? 'false' : 'true',
+                ],
+                'where' => ['id = ?'],
+                'data'  => [$contactParameter['id']]
+            ]);
+        }
+        
+        ContactFillingModel::update($data['contactsFilling']);
 
         return $response->withJson(['success' => 'success']);
     }
diff --git a/src/app/contact/controllers/ContactCustomFieldController.php b/src/app/contact/controllers/ContactCustomFieldController.php
index f27ede076cb..47a014010d4 100644
--- a/src/app/contact/controllers/ContactCustomFieldController.php
+++ b/src/app/contact/controllers/ContactCustomFieldController.php
@@ -15,6 +15,7 @@ namespace Contact\controllers;
 
 use Contact\models\ContactCustomFieldListModel;
 use Contact\models\ContactCustomFieldModel;
+use Contact\models\ContactParameterModel;
 use Group\controllers\PrivilegeController;
 use History\controllers\HistoryController;
 use Respect\Validation\Validator;
@@ -139,6 +140,7 @@ class ContactCustomFieldController
         $field = ContactCustomFieldListModel::getById(['select' => ['label'], 'id' => $args['id']]);
 
         ContactCustomFieldModel::delete(['where' => ['custom_field_id = ?'], 'data' => [$args['id']]]);
+        ContactParameterModel::delete(['where' => ['identifier = ?'], 'data' => ['contactCustomField_' . $args['id']]]);
 
         ContactCustomFieldListModel::delete([
             'where' => ['id = ?'],
diff --git a/src/app/contact/models/ContactFillingModel.php b/src/app/contact/models/ContactFillingModel.php
index 9d505538b3b..2fcf0570b55 100755
--- a/src/app/contact/models/ContactFillingModel.php
+++ b/src/app/contact/models/ContactFillingModel.php
@@ -34,9 +34,7 @@ class ContactFillingModel
 
     public static function update(array $aArgs)
     {
-        ValidatorModel::notEmpty($aArgs, ['rating_columns']);
         ValidatorModel::boolType($aArgs, ['enable']);
-        ValidatorModel::stringType($aArgs, ['rating_columns']);
         ValidatorModel::intVal($aArgs, ['first_threshold', 'second_threshold']);
 
         $aArgs['enable'] = $aArgs['enable'] ? 'true' : 'false';
@@ -45,7 +43,6 @@ class ContactFillingModel
             'table'     => 'contacts_filling',
             'set'       => [
                 'enable'            => $aArgs['enable'],
-                'rating_columns'    => $aArgs['rating_columns'],
                 'first_threshold'   => $aArgs['first_threshold'],
                 'second_threshold'  => $aArgs['second_threshold']
             ],
diff --git a/src/app/contact/models/ContactParameterModel.php b/src/app/contact/models/ContactParameterModel.php
new file mode 100755
index 00000000000..3f755c7e05d
--- /dev/null
+++ b/src/app/contact/models/ContactParameterModel.php
@@ -0,0 +1,104 @@
+<?php
+
+/**
+* Copyright Maarch since 2008 under licence GPLv3.
+* See LICENCE.txt file at the root folder for more details.
+* This file is part of Maarch software.
+*
+*/
+
+/**
+* @brief Contact Parameter Model
+* @author dev@maarch.org
+*/
+
+namespace Contact\models;
+
+use SrcCore\models\DatabaseModel;
+use SrcCore\models\ValidatorModel;
+
+class ContactParameterModel
+{
+    public static function get(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['select']);
+        ValidatorModel::arrayType($args, ['select', 'where', 'data', 'orderBy']);
+        ValidatorModel::intType($args, ['limit']);
+
+        $contacts = DatabaseModel::select([
+            'select'    => $args['select'],
+            'table'     => ['contacts_parameters'],
+            'where'     => empty($args['where']) ? [] : $args['where'],
+            'data'      => empty($args['data']) ? [] : $args['data'],
+            'order_by'  => empty($args['orderBy']) ? [] : $args['orderBy'],
+            'limit'     => empty($args['limit']) ? 0 : $args['limit']
+        ]);
+
+        return $contacts;
+    }
+
+    public static function getById(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['id', 'select']);
+        ValidatorModel::intVal($args, ['id']);
+        ValidatorModel::arrayType($args, ['select']);
+
+        $contact = DatabaseModel::select([
+            'select'    => $args['select'],
+            'table'     => ['contacts_parameters'],
+            'where'     => ['id = ?'],
+            'data'      => [$args['id']],
+        ]);
+
+        if (empty($contact[0])) {
+            return [];
+        }
+
+        return $contact[0];
+    }
+
+    public static function create(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['creator']);
+        ValidatorModel::intVal($args, ['creator']);
+
+        $nextSequenceId = DatabaseModel::getNextSequenceValue(['sequenceId' => 'contacts_parameters_id_seq']);
+        $args['id'] = $nextSequenceId;
+
+        DatabaseModel::insert([
+            'table'         => 'contacts_parameters',
+            'columnsValues' => $args
+        ]);
+
+        return $nextSequenceId;
+    }
+
+    public static function update(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['set', 'where', 'data']);
+        ValidatorModel::arrayType($args, ['set', 'where', 'data']);
+
+        DatabaseModel::update([
+            'table' => 'contacts_parameters',
+            'set'   => $args['set'],
+            'where' => $args['where'],
+            'data'  => $args['data']
+        ]);
+
+        return true;
+    }
+
+    public static function delete(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['where', 'data']);
+        ValidatorModel::arrayType($args, ['where', 'data']);
+
+        DatabaseModel::delete([
+            'table' => 'contacts_parameters',
+            'where' => $args['where'],
+            'data'  => $args['data']
+        ]);
+
+        return true;
+    }
+}
diff --git a/src/frontend/app/administration/contact/contacts-filling-administration.component.html b/src/frontend/app/administration/contact/contacts-filling-administration.component.html
index ef75c9f2f3d..78866c9805d 100755
--- a/src/frontend/app/administration/contact/contacts-filling-administration.component.html
+++ b/src/frontend/app/administration/contact/contacts-filling-administration.component.html
@@ -56,19 +56,33 @@
                         </mat-card>
                     </div>
                 </div>
-                <div class="row" style="margin-top:10px;">
-                    <div class="col-md-12 col-xs-12">
-                        <mat-tab-group>
-                            <mat-tab label="{{lang.contactsFillingCriteria}}">
-                                <div class="row" *ngFor="let fillingColumnSelected of fillingColumnsSelected">
-                                    <div class="col-md-3 col-sm-6 col-xs-12" *ngFor="let fillingColumn of fillingColumns;let i = index" style="padding-bottom: 5px;">
-                                        <mat-slide-toggle color="primary" name="{{fillingColumn}}" (change)="addCriteria($event,fillingColumn)" [checked]="fillingColumnsState[i]">{{lang['contactsFilling_'+fillingColumn]}}</mat-slide-toggle>
-                                    </div>
-                                </div>
-                            </mat-tab>
-                        </mat-tab-group>
-                    </div>
-                </div>
+                <mat-table #table [dataSource]="dataSource" matSort matSortActive="identifier" matSortDirection="asc">
+                        <ng-container matColumnDef="identifier">
+                            <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.label}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element">
+                                <div *ngIf="!element.label">{{lang['contactsFilling_'+element.identifier]}}</div>
+                                <div *ngIf="element.label">{{element.label}}</div>
+                            </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="mandatory">
+                            <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.mandatory}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element"><mat-slide-toggle style="margin-left:11px" color="primary" (change)="addCriteria($event, element, 'mandatory')" [checked]="element.mandatory"></mat-slide-toggle></mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="filling">
+                                <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.contactsFillingCriteria}}</mat-header-cell>
+                                <mat-cell *matCellDef="let element"> <mat-slide-toggle style="margin-left:11px" color="primary" (change)="addCriteria($event, element, 'filling')" [checked]="element.filling"></mat-slide-toggle> </mat-cell>
+                            </ng-container>
+                        <ng-container matColumnDef="displayable">
+                            <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.autocompletionSearchable}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element"> <mat-slide-toggle style="margin-left:11px" color="primary" (change)="addCriteria($event, element, 'searchable')" [checked]="element.searchable"></mat-slide-toggle> </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="searchable">
+                            <mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.autocompletionDisplayable}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element"> <mat-slide-toggle style="margin-left:11px" color="primary" (change)="addCriteria($event, element, 'displayable')" [checked]="element.displayable"></mat-slide-toggle> </mat-cell>
+                        </ng-container>
+                        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+                        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+                    </mat-table>
             </mat-card>
         </mat-sidenav-content>
     </mat-sidenav-container>
diff --git a/src/frontend/app/administration/contact/contacts-filling-administration.component.ts b/src/frontend/app/administration/contact/contacts-filling-administration.component.ts
index 4c9d261d19c..5327fc15a64 100755
--- a/src/frontend/app/administration/contact/contacts-filling-administration.component.ts
+++ b/src/frontend/app/administration/contact/contacts-filling-administration.component.ts
@@ -5,6 +5,7 @@ import { NotificationService } from '../../notification.service';
 import { HeaderService }        from '../../../service/header.service';
 import { MatSidenav } from '@angular/material/sidenav';
 import { AppService } from '../../../service/app.service';
+import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
 
 declare function $j(selector: any): any;
 
@@ -20,68 +21,28 @@ export class ContactsFillingAdministrationComponent implements OnInit {
     lang: any = LANG;
 
     contactsFilling: any = {
-        'rating_columns': [],
         'enable': false,
         'first_threshold': '33',
         'second_threshold': '66',
     };
 
+    contactsParameters: any = [];
+
     arrRatingColumns: String[] = [];
     fillingColor = {
         'first_threshold': '#ff9e9e',
         'second_threshold': '#f6cd81',
         'third_threshold': '#ccffcc',
     };
-    fillingColumns = [
-        'address_num',
-        'address_postal_code',
-        'title',
-        'function',
-        'address_street',
-        'address_town',
-        'lastname',
-        'departement',
-        'occupancy',
-        'address_country',
-        'firstname',
-        'phone',
-        'address_complement',
-        'society',
-        'society_short',
-        'email',
-    ];
-    fillingColumnsState = [
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-        false,
-    ];
-    fillingColumnsSelected = ['society'];
 
     loading: boolean = false;
 
+    dataSource = new MatTableDataSource(this.contactsParameters);
+    displayedColumns = ['identifier', 'mandatory', 'filling', 'displayable', 'searchable'];
+
+    @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
+    @ViewChild(MatSort, { static: false }) sort: MatSort;
+
     constructor(
         public http: HttpClient, 
         private notify: NotificationService, 
@@ -94,32 +55,30 @@ export class ContactsFillingAdministrationComponent implements OnInit {
 
         this.loading = true;
 
-        this.headerService.setHeader(this.lang.contactsFillingAdministration);
+        this.headerService.setHeader(this.lang.contactsParameters);
         window['MainHeaderComponent'].setSnav(this.sidenavLeft);
         window['MainHeaderComponent'].setSnavRight(null);
 
-        this.http.get('../../rest/contactsFilling')
+        this.http.get('../../rest/contactsParameters')
             .subscribe((data: any) => {
                 this.contactsFilling = data.contactsFilling;
-                if (this.contactsFilling.rating_columns.length > 0) {
-                    this.contactsFilling.rating_columns.forEach((col: any) => {
-                        let i = this.fillingColumns.indexOf(col);
-                        this.fillingColumnsState[i] = true;    
-                        this.arrRatingColumns.push(col);
-                    });
-                }  
+                this.contactsParameters = data.contactsParameters;
                 this.loading = false;
+                setTimeout(() => {
+                    this.dataSource = new MatTableDataSource(this.contactsParameters);
+                    this.dataSource.paginator = this.paginator;
+                    this.dataSource.sort = this.sort;
+                }, 0);
             });
     }
 
-    addCriteria(event: any, criteria: String) {
-        if (event.checked) {
-            this.arrRatingColumns.push(criteria);
-        } else {
-            this.arrRatingColumns.splice(this.arrRatingColumns.indexOf(criteria), 1);
-        }
-        this.contactsFilling.rating_columns = this.arrRatingColumns;
-        this.contactsFilling.rating_columns.length == 0 ? this.contactsFilling.enable = false : this.contactsFilling.enable = true;
+    addCriteria(event: any, criteria: any, type: string) {
+        this.contactsParameters.forEach((col: any, i: number) => {
+            if (col.id == criteria.id) {
+                this.contactsParameters[i][type] = event.checked;
+            }
+        });
+
         this.onSubmit();
     }
 
@@ -127,7 +86,7 @@ export class ContactsFillingAdministrationComponent implements OnInit {
         if (this.contactsFilling.first_threshold >= this.contactsFilling.second_threshold) {
             this.contactsFilling.second_threshold = this.contactsFilling.first_threshold + 1;
         }
-        this.http.put('../../rest/contactsFilling', this.contactsFilling)
+        this.http.put('../../rest/contactsParameters', {'contactsFilling': this.contactsFilling, 'contactsParameters': this.contactsParameters})
             .subscribe(() => {
                 this.notify.success(this.lang.contactsFillingUpdated);
 
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index c9dd9c62d68..063250a56d8 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -200,31 +200,22 @@ export const LANG_FR = {
     "contactGroupList"                      : "Liste des groupements",
     "contactInfo"                           : "Fiche contact",
     "contacts"                              : "Contact(s)",
-    "contactsFilling_address_complement"    : "Tour, bâtiment, immeuble, résidence",
+    "contactsFilling_address_additional1"    : "Tour, bâtiment, immeuble, résidence",
     "contactsFilling_address_country"       : "Pays",
-    "contactsFilling_address_num"           : "Numéro de rue",
-    "contactsFilling_address_postal_code"   : "Code postal",
+    "contactsFilling_address_number"           : "Numéro de rue",
+    "contactsFilling_address_postcode"   : "Code postal",
     "contactsFilling_address_street"        : "Voie",
     "contactsFilling_address_town"          : "Ville",
-    "contactsFilling_contact_firstname"     : "Prénom (contact physique)",
-    "contactsFilling_contact_function"      : "Fonction (contact physique)",
-    "contactsFilling_contact_lastname"      : "Nom (contact physique)",
-    "contactsFilling_contact_other_data"    : "Informations complémentaires (contact physique)",
-    "contactsFilling_contact_title"         : "Civilité (contact physique)",
-    "contactsFilling_departement"           : "Service",
+    "contactsFilling_department"           : "Service",
     "contactsFilling_email"                 : "Courriel",
     "contactsFilling_firstname"             : "Prénom",
     "contactsFilling_function"              : "Fonction",
     "contactsFilling_lastname"              : "Nom",
-    "contactsFilling_occupancy"             : "N° app, étage, escalier",
+    "contactsFilling_address_additional2"   : "N° app, étage, escalier",
     "contactsFilling_other_data"            : "Informations complémentaires",
     "contactsFilling_phone"                 : "Téléphone",
-    "contactsFilling_salutation_footer"     : "Formule de politesse (fin de courrier)",
-    "contactsFilling_salutation_header"     : "Formule de politesse (début de courrier)",
-    "contactsFilling_society_short"         : "Sigle de la structure",
-    "contactsFilling_society"               : "Structure",
-    "contactsFilling_title"                 : "Civilité",
-    "contactsFilling_website"               : "Site internet",
+    "contactsFilling_company"               : "Société",
+    "contactsFilling_civility"              : "Civilité",
     "contactsFillingAdministration"         : "Complétude des informations contacts",
     "contactsFillingCriteria"               : "Critères de complétude",
     "contactsFillingStep1"                  : "Premier palier",
@@ -1366,4 +1357,7 @@ export const LANG_FR = {
     "newVersion": "Nouvelle version",
     "information": "Information",
     "mustEditDocument": "Vous devez <b>éditer</b> votre document afin de pouvoir <b>valider</b> vos modifications.",
+    "autocompletionSearchable": "Recherchable dans l'autocomplétion",
+    "autocompletionDisplayable": "Affichable dans l'autocompletion",
+    "contactsParameters": "Paramétrage des contacts",
 };
-- 
GitLab