From 38f082dde54c8b8ba7c91c7340bee4d8021654d8 Mon Sep 17 00:00:00 2001
From: Guillaume Heurtier <guillaume.heurtier@maarch.org>
Date: Fri, 23 Oct 2020 17:53:25 +0200
Subject: [PATCH] FEAT #12018 TIME 7:00 show delegate in visa/opinion circuit

---
 migration/20.10/2010.sql                      |  2 +
 .../controllers/ActionMethodController.php    | 30 +++++++----
 .../controllers/ListInstanceController.php    | 51 +++++++++++++++----
 .../models/ListInstanceModelAbstract.php      |  3 +-
 .../controllers/SummarySheetController.php    | 30 ++++++++---
 .../app/avis/avis-workflow.component.html     |  5 ++
 .../app/visa/visa-workflow.component.html     |  5 ++
 src/lang/lang-en.json                         |  3 +-
 src/lang/lang-fr.json                         |  4 +-
 9 files changed, 102 insertions(+), 31 deletions(-)

diff --git a/migration/20.10/2010.sql b/migration/20.10/2010.sql
index 1a78526a13c..0b0b50e6109 100755
--- a/migration/20.10/2010.sql
+++ b/migration/20.10/2010.sql
@@ -310,6 +310,8 @@ DROP TYPE IF EXISTS custom_fields_modes;
 CREATE TYPE custom_fields_modes AS ENUM ('form', 'technical');
 ALTER TABLE custom_fields ADD COLUMN mode custom_fields_modes NOT NULL DEFAULT 'form';
 
+ALTER TABLE listinstance ADD COLUMN delegate INTEGER;
+
 /* RE CREATE VIEWS */
 CREATE OR REPLACE VIEW res_view_letterbox AS
 SELECT r.res_id,
diff --git a/src/app/action/controllers/ActionMethodController.php b/src/app/action/controllers/ActionMethodController.php
index 6b472990c17..389526557de 100644
--- a/src/app/action/controllers/ActionMethodController.php
+++ b/src/app/action/controllers/ActionMethodController.php
@@ -381,7 +381,7 @@ class ActionMethodController
         ValidatorModel::intVal($args, ['resId']);
 
         $listInstance = ListInstanceModel::get([
-            'select'    => ['listinstance_id'],
+            'select'    => ['listinstance_id', 'item_id'],
             'where'     => ['res_id = ?', 'difflist_type = ?', 'process_date is null'],
             'data'      => [$args['resId'], 'VISA_CIRCUIT'],
             'orderBy'   => ['listinstance_id'],
@@ -391,10 +391,13 @@ class ActionMethodController
             return ['errors' => ['No available circuit']];
         }
 
+        $set = ['process_date' => 'CURRENT_TIMESTAMP'];
+        if ($listInstance[0]['item_id'] != $GLOBALS['id']) {
+            $set['delegate'] = $GLOBALS['id'];
+        }
+
         ListInstanceModel::update([
-            'set'   => [
-                'process_date' => 'CURRENT_TIMESTAMP'
-            ],
+            'set'   => $set,
             'where' => ['listinstance_id = ?'],
             'data'  => [$listInstance[0]['listinstance_id']]
         ]);
@@ -724,6 +727,8 @@ class ActionMethodController
         }
         $currentStep = $currentStep[0];
 
+        $set = ['process_date' => 'CURRENT_TIMESTAMP'];
+
         $message = null;
         if ($currentStep['item_id'] != $GLOBALS['id']) {
             $currentUser = UserModel::getById(['select' => ['firstname', 'lastname'], 'id' => $GLOBALS['id']]);
@@ -738,12 +743,12 @@ class ActionMethodController
                 . $currentUser['firstname'] . ' ' . $currentUser['lastname']
                 . " " . _INSTEAD_OF . " "
                 . $stepUser['firstname'] . ' ' . $stepUser['lastname'];
+
+            $set['delegate'] = $GLOBALS['id'];
         }
 
         ListInstanceModel::update([
-            'set'   => [
-                'process_date' => 'CURRENT_TIMESTAMP'
-            ],
+            'set'   => $set,
             'where' => ['listinstance_id = ?'],
             'data'  => [$currentStep['listinstance_id']]
         ]);
@@ -761,7 +766,7 @@ class ActionMethodController
         ValidatorModel::intVal($args, ['resId']);
 
         $currentStep = ListInstanceModel::get([
-            'select'  => ['listinstance_id'],
+            'select'  => ['listinstance_id', 'item_id'],
             'where'   => ['res_id = ?', 'difflist_type = ?', 'item_id = ?', 'item_mode in (?)'],
             'data'    => [$args['resId'], 'entity_id', $GLOBALS['id'], ['avis', 'avis_copy', 'avis_info']],
             'limit'   => 1
@@ -772,10 +777,13 @@ class ActionMethodController
         }
         $currentStep = $currentStep[0];
 
+        $set = ['process_date' => 'CURRENT_TIMESTAMP'];
+        if ($currentStep['item_id'] != $GLOBALS['id']) {
+            $set['delegate'] = $GLOBALS['id'];
+        }
+
         ListInstanceModel::update([
-            'set'   => [
-                'process_date' => 'CURRENT_TIMESTAMP'
-            ],
+            'set'   => $set,
             'where' => ['listinstance_id = ?'],
             'data'  => [$currentStep['listinstance_id']]
         ]);
diff --git a/src/app/entity/controllers/ListInstanceController.php b/src/app/entity/controllers/ListInstanceController.php
index 84429c09f80..aadc007c2fa 100755
--- a/src/app/entity/controllers/ListInstanceController.php
+++ b/src/app/entity/controllers/ListInstanceController.php
@@ -69,10 +69,20 @@ class ListInstanceController
             return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
         }
 
-        $listInstances = ListInstanceModel::getVisaCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'signatory', 'requested_signature'], 'id' => $aArgs['resId']]);
+        $listInstances = ListInstanceModel::getVisaCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'signatory', 'requested_signature', 'delegate'], 'id' => $aArgs['resId']]);
         foreach ($listInstances as $key => $value) {
+            $user = UserModel::getById(['id' => $value['item_id'], 'select' => ['status']]);
+            $listInstances[$key]['isValid'] = !empty($user) && !in_array($user['status'], ['SPD', 'DEL']);
+
             $listInstances[$key]['item_type'] = 'user';
-            $listInstances[$key]['labelToDisplay'] = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+            $itemLabel = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+
+            $listInstances[$key]['labelToDisplay'] = $itemLabel;
+            $listInstances[$key]['delegatedBy'] = null;
+            if (!empty($listInstances[$key]['delegate'])) {
+                $listInstances[$key]['labelToDisplay'] = UserModel::getLabelledUserById(['id' => $listInstances[$key]['delegate']]);
+                $listInstances[$key]['delegatedBy'] = $itemLabel;
+            }
 
             $listInstances[$key]['hasPrivilege'] = true;
             if (empty($value['process_date']) && !PrivilegeController::hasPrivilege(['privilegeId' => 'visa_documents', 'userId' => $value['item_id']]) && !PrivilegeController::hasPrivilege(['privilegeId' => 'sign_document', 'userId' => $value['item_id']])) {
@@ -89,10 +99,20 @@ class ListInstanceController
             return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
         }
 
-        $listInstances = ListInstanceModel::getAvisCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment'], 'id' => $aArgs['resId']]);
+        $listInstances = ListInstanceModel::getAvisCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'delegate'], 'id' => $aArgs['resId']]);
         foreach ($listInstances as $key => $value) {
+            $user = UserModel::getById(['id' => $value['item_id'], 'select' => ['status']]);
+            $listInstances[$key]['isValid'] = !empty($user) && !in_array($user['status'], ['SPD', 'DEL']);
+
             $listInstances[$key]['item_type'] = 'user';
-            $listInstances[$key]['labelToDisplay'] = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+            $itemLabel = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+
+            $listInstances[$key]['labelToDisplay'] = $itemLabel;
+            $listInstances[$key]['delegatedBy'] = null;
+            if (!empty($listInstances[$key]['delegate'])) {
+                $listInstances[$key]['labelToDisplay'] = UserModel::getLabelledUserById(['id' => $listInstances[$key]['delegate']]);
+                $listInstances[$key]['delegatedBy'] = $itemLabel;
+            }
 
             $listInstances[$key]['hasPrivilege'] = true;
             if (empty($value['process_date']) && !PrivilegeController::hasPrivilege(['privilegeId' => 'avis_documents', 'userId' => $value['item_id']])) {
@@ -109,10 +129,20 @@ class ListInstanceController
             return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
         }
 
-        $listInstances = ListInstanceModel::getParallelOpinionByResId(['select' => ['listinstance_id', 'sequence', 'item_mode', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment'], 'id' => $aArgs['resId']]);
+        $listInstances = ListInstanceModel::getParallelOpinionByResId(['select' => ['listinstance_id', 'sequence', 'item_mode', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'delegate'], 'id' => $aArgs['resId']]);
         foreach ($listInstances as $key => $value) {
+            $user = UserModel::getById(['id' => $value['item_id'], 'select' => ['status']]);
+            $listInstances[$key]['isValid'] = !empty($user) && !in_array($user['status'], ['SPD', 'DEL']);
+
             $listInstances[$key]['item_type'] = 'user';
-            $listInstances[$key]['labelToDisplay'] = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+            $itemLabel = $listInstances[$key]['item_firstname'].' '.$listInstances[$key]['item_lastname'];
+
+            $listInstances[$key]['labelToDisplay'] = $itemLabel;
+            $listInstances[$key]['delegatedBy'] = null;
+            if (!empty($listInstances[$key]['delegate'])) {
+                $listInstances[$key]['labelToDisplay'] = UserModel::getLabelledUserById(['id' => $listInstances[$key]['delegate']]);
+                $listInstances[$key]['delegatedBy'] = $itemLabel;
+            }
 
             $listInstances[$key]['hasPrivilege'] = true;
             if (empty($value['process_date']) && !PrivilegeController::hasPrivilege(['privilegeId' => 'avis_documents', 'userId' => $value['item_id']])) {
@@ -272,7 +302,8 @@ class ListInstanceController
                     'process_date'          => null,
                     'process_comment'       => null,
                     'requested_signature'   => false,
-                    'viewed'                => empty($instance['viewed']) ? 0 : $instance['viewed']
+                    'viewed'                => empty($instance['viewed']) ? 0 : $instance['viewed'],
+                    'delegate'              => $instance['delegate'] ?? null
                 ]);
 
                 if ($instance['item_mode'] == 'dest') {
@@ -417,7 +448,8 @@ class ListInstanceController
                     'item_mode'             => $listInstance['item_mode'],
                     'process_date'          => null,
                     'process_comment'       => $listInstance['process_comment'] ?? null,
-                    'requested_signature'   => $listInstance['requested_signature'] ?? false
+                    'requested_signature'   => $listInstance['requested_signature'] ?? false,
+                    'delegate'              => $listInstance['delegate'] ?? null
                 ];
             }
 
@@ -432,7 +464,8 @@ class ListInstanceController
                     'difflist_type'         => $args['type'] == 'visaCircuit' ? 'VISA_CIRCUIT' : 'AVIS_CIRCUIT',
                     'process_date'          => $listInstance['process_date'],
                     'process_comment'       => $listInstance['process_comment'],
-                    'requested_signature'   => $listInstance['requested_signature']
+                    'requested_signature'   => $listInstance['requested_signature'],
+                    'delegate'              => $listInstance['delegate']
                 ]);
             }
         }
diff --git a/src/app/entity/models/ListInstanceModelAbstract.php b/src/app/entity/models/ListInstanceModelAbstract.php
index 5941db189bb..921c870ae0f 100755
--- a/src/app/entity/models/ListInstanceModelAbstract.php
+++ b/src/app/entity/models/ListInstanceModelAbstract.php
@@ -57,7 +57,8 @@ abstract class ListInstanceModelAbstract
                 'difflist_type'             => $args['difflist_type'],
                 'process_date'              => $args['process_date'],
                 'process_comment'           => $args['process_comment'],
-                'requested_signature'       => empty($args['requested_signature']) ? 'false' : 'true'
+                'requested_signature'       => empty($args['requested_signature']) ? 'false' : 'true',
+                'delegate'                  => $args['delegate'] ?? null
             ]
         ]);
 
diff --git a/src/app/resource/controllers/SummarySheetController.php b/src/app/resource/controllers/SummarySheetController.php
index 07ab102f64b..2b7bd50cc7d 100755
--- a/src/app/resource/controllers/SummarySheetController.php
+++ b/src/app/resource/controllers/SummarySheetController.php
@@ -585,8 +585,16 @@ class SummarySheetController
                     if ($found && $listInstance['res_id'] != $resource['res_id']) {
                         break;
                     } elseif ($listInstance['res_id'] == $resource['res_id']) {
+                        $mode = $listInstance['requested_signature'] ? 'Signataire' : 'Viseur';
+                        $userLabel = UserModel::getLabelledUserById(['id' => $listInstance['item_id']]) . " ({$mode}) ";
+
+                        $delegate = !empty($listInstance['delegate']) ? UserModel::getLabelledUserById(['id' => $listInstance['delegate']]) : '';
+                        if (!empty($delegate)) {
+                            $userLabel = $delegate . ' ' . _INSTEAD_OF . ' ' . $userLabel;
+                        }
+
                         $users[] = [
-                            'user'  => UserModel::getLabelledUserById(['id' => $listInstance['item_id']]),
+                            'user'  => $userLabel,
                             'mode'  => $listInstance['requested_signature'] ? 'Signataire' : 'Viseur',
                             'date'  => TextFormatModel::formatDate($listInstance['process_date']),
                         ];
@@ -608,7 +616,7 @@ class SummarySheetController
                     $pdf->Cell($specialWidth * 3, 20, _USERS, 1, 0, 'L', false);
                     $pdf->Cell($specialWidth, 20, _ACTION_DATE, 1, 1, 'L', false);
                     foreach ($users as $keyUser => $user) {
-                        $pdf->Cell($specialWidth * 3, 20, $keyUser + 1 . ". {$user['user']} ({$user['mode']})", 1, 0, 'L', false);
+                        $pdf->Cell($specialWidth * 3, 20, $keyUser + 1 . ". {$user['user']}", 1, 0, 'L', false);
                         $pdf->Cell($specialWidth, 20, $user['date'], 1, 1, 'L', false);
                     }
                 }
@@ -619,13 +627,19 @@ class SummarySheetController
                     if ($found && $listInstance['res_id'] != $resource['res_id']) {
                         break;
                     } elseif ($listInstance['res_id'] == $resource['res_id']) {
-                        $user = UserModel::getById(['id' => $listInstance['item_id'], 'select' => ['id', 'firstname', 'lastname']]);
-                        $entity = UserModel::getPrimaryEntityById(['id' => $user['id'], 'select' => ['entities.entity_label']]);
+                        $user = UserModel::getLabelledUserById(['id' => $listInstance['item_id']]);
+                        $entity = UserModel::getPrimaryEntityById(['id' => $listInstance['item_id'], 'select' => ['entities.entity_label']]);
+
+                        $userLabel = $user . " (" . $entity['entity_label'] . ")";
+                        $delegate = !empty($listInstance['delegate']) ? UserModel::getLabelledUserById(['id' => $listInstance['delegate']]) : '';
+
+                        if (!empty($delegate)) {
+                            $userLabel = $delegate . ' ' .  _INSTEAD_OF . ' ' . $userLabel;
+                        }
 
-                        $userLabel = $user['firstname'] . ' ' .$user['lastname'] . " (" . $entity['entity_label'] . ")";
                         $users[] = [
                             'user'  => $userLabel,
-                            'date'  => TextFormatModel::formatDate($listInstance['process_date']),
+                            'date'  => TextFormatModel::formatDate($listInstance['process_date'])
                         ];
                         unset($args['data']['listInstancesOpinion'][$listKey]);
                         $found = true;
@@ -763,14 +777,14 @@ class SummarySheetController
                 }
             } elseif ($unit['unit'] == 'opinionWorkflow') {
                 $data['listInstancesOpinion'] = ListInstanceModel::get([
-                    'select'    => ['item_id', 'process_date', 'res_id'],
+                    'select'    => ['item_id', 'process_date', 'res_id', 'delegate'],
                     'where'     => ['difflist_type = ?', 'res_id in (?)'],
                     'data'      => ['AVIS_CIRCUIT', $tmpIds],
                     'orderBy'   => ['listinstance_id']
                 ]);
             } elseif ($unit['unit'] == 'visaWorkflow') {
                 $data['listInstancesVisa'] = ListInstanceModel::get([
-                    'select'    => ['item_id', 'requested_signature', 'process_date', 'res_id'],
+                    'select'    => ['item_id', 'requested_signature', 'process_date', 'res_id', 'delegate'],
                     'where'     => ['difflist_type = ?', 'res_id in (?)'],
                     'data'      => ['VISA_CIRCUIT', $tmpIds],
                     'orderBy'   => ['listinstance_id']
diff --git a/src/frontend/app/avis/avis-workflow.component.html b/src/frontend/app/avis/avis-workflow.component.html
index 3e8f03782b3..f4a8dc7f0cf 100644
--- a/src/frontend/app/avis/avis-workflow.component.html
+++ b/src/frontend/app/avis/avis-workflow.component.html
@@ -68,6 +68,11 @@
                 <div class="workflowLineContainer">
                     <div class="workflowLineLabel" [class.unauthorized]="!diffusion.hasPrivilege || !diffusion.isValid">
                         {{diffusion.labelToDisplay}}
+                        <ng-container *ngIf="diffusion.process_date != null && diffusion.delegatedBy !== null">
+                            <mat-icon mat-list-icon class="fas fa-exclamation-circle"
+                                      [title]="this.translate.instant('lang.insteadOf') + ' ' + diffusion.delegatedBy"
+                                      style="opacity:0.5;font-size: 125%;height: 15px"></mat-icon>
+                        </ng-container>
                     </div>
                     <div class="workflowLineSubLabel" [class.unauthorized]="!diffusion.hasPrivilege || !diffusion.isValid">
                         {{diffusion.item_entity}}
diff --git a/src/frontend/app/visa/visa-workflow.component.html b/src/frontend/app/visa/visa-workflow.component.html
index 2413157e94a..d1268ddcbe2 100755
--- a/src/frontend/app/visa/visa-workflow.component.html
+++ b/src/frontend/app/visa/visa-workflow.component.html
@@ -83,6 +83,11 @@
                 <div class="workflowLineContainer">
                     <div class="workflowLineLabel" [class.unauthorized]="!diffusion.hasPrivilege || !diffusion.isValid">
                         {{diffusion.labelToDisplay}}
+                        <ng-container *ngIf="diffusion.process_date != null && diffusion.delegatedBy !== null">
+                            <mat-icon mat-list-icon class="fas fa-exclamation-circle"
+                                      [title]="this.translate.instant('lang.insteadOf') + ' ' + diffusion.delegatedBy"
+                                      style="opacity:0.5;font-size: 125%;height: 15px"></mat-icon>
+                        </ng-container>
                     </div>
                     <div class="workflowLineSubLabel" [class.unauthorized]="!diffusion.hasPrivilege || !diffusion.isValid">
                         {{diffusion.item_entity}}
diff --git a/src/lang/lang-en.json b/src/lang/lang-en.json
index 1ec76ab1a1a..4fa681ef9c9 100644
--- a/src/lang/lang-en.json
+++ b/src/lang/lang-en.json
@@ -2078,5 +2078,6 @@
     "displayCriteria": "Show search criteria",
     "displaySelectedValues": "Show selected values",
     "quickSearch": "Quick search",
-    "contactInput": "Contact input"
+    "contactInput": "Contact input",
+    "insteadOf": "Instead of"
 }
diff --git a/src/lang/lang-fr.json b/src/lang/lang-fr.json
index efd31d6c07c..24a79b73d6b 100644
--- a/src/lang/lang-fr.json
+++ b/src/lang/lang-fr.json
@@ -2130,5 +2130,7 @@
     "installNewCustom": "Créer une nouvelle instance",
     "mustConnectToInstall" : "Veuillez vous connecter pour accéder à l'installeur",
     "mustPrivilegeToInstall" : "Vous n'avez pas le droit de créer une nouvelle instance",
-    "instancesList" : "Instances présentes"
+    "instancesList" : "Instances présentes",
+    "insteadOf": "À la place de"
+
 }
-- 
GitLab