From 5424649f36f008cda95d11a3cc6e52268c5a9749 Mon Sep 17 00:00:00 2001
From: "florian.azizian" <florian.azizian@maarch.org>
Date: Tue, 28 May 2019 16:49:23 +0100
Subject: [PATCH] FEAT #10623 TIME 5 explode notebook and signaturebook

---
 .../actions/sendToExternalNoteBook.php        | 200 ++++++++++++++++++
 .../actions/sendToExternalSignatureBook.php   |  92 ++++----
 core/xml/actions_pages.xml                    |  12 ++
 .../batch/process_mailsFromSignatoryBook.php  |  26 ++-
 .../visa/class/MaarchParapheurController.php  |  23 --
 rest/index.php                                |   1 +
 .../controllers/ActionMethodController.php    |  60 +++++-
 .../ExternalSignatoryBookTrait.php            |   6 +-
 .../PreProcessActionController.php            | 119 +++++++++--
 src/core/lang/lang-en.php                     |   1 +
 src/core/lang/lang-fr.php                     |   1 +
 src/core/lang/lang-nl.php                     |   2 +
 .../app/actions/actions-list.component.ts     |  23 ++
 ...d-external-note-book-action.component.html |  55 +++++
 ...d-external-note-book-action.component.scss | 128 +++++++++++
 ...end-external-note-book-action.component.ts |  77 +++++++
 .../maarch-paraph.component.html              |  34 +--
 .../maarch-paraph/maarch-paraph.component.ts  |  12 +-
 ...xternal-signatory-book-action.component.ts |   7 +-
 src/frontend/app/app.module.ts                |   3 +
 20 files changed, 722 insertions(+), 160 deletions(-)
 create mode 100755 apps/maarch_entreprise/actions/sendToExternalNoteBook.php
 create mode 100644 src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.html
 create mode 100644 src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.scss
 create mode 100644 src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.ts

diff --git a/apps/maarch_entreprise/actions/sendToExternalNoteBook.php b/apps/maarch_entreprise/actions/sendToExternalNoteBook.php
new file mode 100755
index 00000000000..465ceb8e40c
--- /dev/null
+++ b/apps/maarch_entreprise/actions/sendToExternalNoteBook.php
@@ -0,0 +1,200 @@
+<?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   sendToExternalNote
+*
+* @author  dev <dev@maarch.org>
+* @ingroup visa
+*/
+
+$confirm    = true;
+$frm_width  = '400px';
+$frm_height = 'auto';
+$warnMsg    = '';
+
+$etapes = ['form'];
+
+function get_form_txt($values, $path_manage_action, $id_action, $table, $module, $coll_id, $mode)
+{
+    $db = new Database();
+    $values_str = '';
+    if (empty($_SESSION['stockCheckbox'])) {
+        for ($i=0; $i<count($values); $i++) {
+            $values_str .= $values[$i].', ';
+        }
+    } else {
+        for ($i=0; $i<count($_SESSION['stockCheckbox']); $i++) {
+            $values_str .= $_SESSION['stockCheckbox'][$i].', ';
+        }
+    }
+    $values_str = preg_replace('/, $/', '', $values_str);
+
+    $config = getXml();
+
+    $labelAction = '';
+    if ($id_action <> '') {
+        $stmt = $db->query("SELECT label_action FROM actions WHERE id = ?", array($id_action));
+        $resAction = $stmt->fetchObject();
+        $labelAction = functions::show_string($resAction->label_action);
+    }
+
+    $html = '<div id="frm_error_'.$id_action.'" class="error"></div>';
+    $html .= '<h2 class="title">' . $labelAction . '</h2>';
+
+    $html .= '<form name="sendToExternalSB" id="sendToExternalSB" method="post" class="forms" action="#">';
+    $html .= '<input type="hidden" name="chosen_action" id="chosen_action" value="end_action" />';
+
+    if (!empty($config)) {
+        include_once 'modules/visa/class/MaarchParapheurController.php';
+
+        $initializeDatas = MaarchParapheurController::getInitializeDatas($config);
+        if (!empty($initializeDatas['error'])) {
+            $error = $initializeDatas['error'];
+        } else {
+            $html .= '<label for="processingUser">' . _USER_MAARCH_PARAPHEUR . '</label><select name="processingUser" id="processingUser">';
+            if (!empty($initializeDatas['users'])) {
+                foreach ($initializeDatas['users'] as $value) {
+                    $html .= '<option value="';
+                    $html .= $value['id'];
+                    $html .= '">';
+                    $html .= $value['firstname'] . ' ' . $value['lastname'];
+                    $html .= '</option>';
+                }
+            }
+            $html .= '</select><br /><br /><br /><br />';
+        }
+    } else {
+        $error = _FILE . ' modules/visa/xml/remoteSignatoryBooks.xml' . ' ' . _NOT_EXISTS;
+    }
+
+    $html .='<div align="center">';
+    if (empty($error)) {
+        $html .=' <input type="button" name="validate" id="validate" value="'._VALIDATE.'" class="button" ' .
+                'onclick="valid_action_form(\'sendToExternalSB\', \'' . $path_manage_action .
+                '\', \'' . $id_action . '\', \'' . $values_str . '\', \'res_letterbox\', \'null\', \'letterbox_coll\', \'' .
+                $mode . '\');" />&nbsp;';
+    } else {
+        $html .= '<br>' . $error . '<br><br>';
+    }
+    $html .='<input type="button" name="cancel" id="cancel" class="button" value="'._CANCEL.'" onclick="pile_actions.action_pop();destroyModal(\'modal_'.$id_action.'\');"/>';
+
+    $html .='</div>';
+    $html .='</form>';
+
+    return addslashes($html);
+}
+
+function check_form($form_id, $values)
+{
+    $_SESSION['action_error'] = '';
+
+    if (!empty($_SESSION['stockCheckbox'])) {
+        $aResources = $_SESSION['stockCheckbox'];
+    } else {
+        $aResources = [$_SESSION['doc_id']];
+    }
+
+    foreach ($aResources as $resId) {
+        $adrMainInfo = \Convert\controllers\ConvertPdfController::getConvertedPdfById(['resId' => $resId, 'collId' => 'letterbox_coll']);
+        $docserverMainInfo = \Docserver\models\DocserverModel::getByDocserverId(['docserverId' => $adrMainInfo['docserver_id']]);
+        $filePath = $docserverMainInfo['path_template'] . str_replace('#', '/', $adrMainInfo['path']) . $adrMainInfo['filename'];
+        if (!is_file($filePath)) {
+            $_SESSION['action_error'] = _FILE_MISSING . ' : ' . $filePath;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+function manage_form($arr_id, $history, $id_action, $label_action, $status, $coll_id, $table, $values_form)
+{
+    $result = '';
+    $config = getXml();
+
+    $coll_id = $_SESSION['current_basket']['coll_id'];
+    $message = '';
+
+    foreach ($arr_id as $res_id) {
+        $result .= $res_id.'#';
+        
+        if (!empty($config)) {
+            $processingUser     = get_value_fields($values_form, 'processingUser');
+            $processingUserInfo = \ExternalSignatoryBook\controllers\MaarchParapheurController::getUserById(['config' => $config, 'id' => $processingUser]);
+            $sendedInfo         = \ExternalSignatoryBook\controllers\MaarchParapheurController::sendDatas([
+                'config'             => $config,
+                'resIdMaster'        => $res_id,
+                'processingUser'     => $processingUserInfo['login'],
+                'objectSent'         => 'mail',
+                'userId'             => $_SESSION['user']['UserId']
+            ]);
+
+            if (!empty($sendedInfo['error'])) {
+                var_dump($sendedInfo['error']);
+                exit;
+            } else {
+                $attachmentToFreeze = $sendedInfo['sended'];
+            }
+
+            $message = ' (à ' . $processingUserInfo['firstname'] . ' ' . $processingUserInfo['lastname'] . ')';
+        }
+
+        if (!empty($attachmentToFreeze)) {
+            if (!empty($attachmentToFreeze['letterbox_coll'])) {
+                \Resource\models\ResModel::update([
+                    'set' => ['external_signatory_book_id' => $attachmentToFreeze['letterbox_coll'][$res_id]],
+                    'where' => ['res_id = ?'],
+                    'data' => [$res_id]
+                ]);
+            }
+        }
+    }
+
+    return ['result' => $result, 'history_msg' => $message];
+}
+
+function getXml()
+{
+    if (file_exists("custom/{$_SESSION['custom_override_id']}/modules/visa/xml/remoteSignatoryBooks.xml")) {
+        $path = "custom/{$_SESSION['custom_override_id']}/modules/visa/xml/remoteSignatoryBooks.xml";
+    } else {
+        $path = 'modules/visa/xml/remoteSignatoryBooks.xml';
+    }
+
+    $config = [];
+    if (file_exists($path)) {
+        $loadedXml = simplexml_load_file($path);
+        if ($loadedXml) {
+            $config['id'] = 'maarchParapheur';
+            foreach ($loadedXml->signatoryBook as $value) {
+                if ($value->id == $config['id']) {
+                    $config['data'] = (array)$value;
+                }
+            }
+        }
+    }
+
+    return $config;
+}
+
+ /**
+ * Get the value of a given field in the values returned by the form
+ *
+ * @param $values Array Values of the form to check
+ * @param $field String the field
+ * @return String the value, false if the field is not found
+ **/
+function get_value_fields($values, $field)
+{
+    for ($i=0; $i<count($values); $i++) {
+        if ($values[$i]['ID'] == $field) {
+            return  $values[$i]['VALUE'];
+        }
+    }
+    return false;
+}
diff --git a/apps/maarch_entreprise/actions/sendToExternalSignatureBook.php b/apps/maarch_entreprise/actions/sendToExternalSignatureBook.php
index 2580a690bf0..56f6ea14798 100755
--- a/apps/maarch_entreprise/actions/sendToExternalSignatureBook.php
+++ b/apps/maarch_entreprise/actions/sendToExternalSignatureBook.php
@@ -71,7 +71,30 @@ function get_form_txt($values, $path_manage_action, $id_action, $table, $module,
         } elseif ($config['id'] == 'maarchParapheur') {
             include_once 'modules/visa/class/MaarchParapheurController.php';
 
-            $htmlModal = MaarchParapheurController::getModal($config);
+            $htmlModal = MaarchParapheurController::getInitializeDatas($config);
+
+            if (empty($htmlModal['error'])) {
+                $aUsersInMP = [];
+                foreach ($htmlModal['users'] as $value) {
+                    $aUsersInMP[] = $value['id'];
+                }
+                $documentIds = explode(", ", $values_str);
+                foreach ($documentIds as $resId) {
+                    $listinstances = \Entity\models\ListInstanceModel::getVisaCircuitByResId(['select' => ['external_id', 'firstname', 'lastname'], 'id' => $resId]);
+                    if (empty($listinstances)) {
+                        $htmlModal['error'] = _EMPTY_VISA_WORKFLOW;
+                        break;
+                    }
+    
+                    foreach ($listinstances as $user) {
+                        $externalId = json_decode($user['external_id'], true);
+                        if (!in_array($externalId['maarchParapheur'], $aUsersInMP)) {
+                            $htmlModal['error'] = _EMPTY_VISA_WORKFLOW;
+                            break 2;
+                        }
+                    }
+                }
+            }
         }
 
         if (!empty($htmlModal['error'])) {
@@ -122,8 +145,6 @@ function check_form($form_id, $values)
             }
         }
         if ($config['id'] == 'maarchParapheur') {
-            $objectSentSign = get_value_fields($values, 'objectSentSign');
-            $objectSentNote  = get_value_fields($values, 'objectSentNote');
             $hasAttachmentError = hasAttachmentError();
             if (!empty($_SESSION['stockCheckbox'])) {
                 $aResources = $_SESSION['stockCheckbox'];
@@ -131,14 +152,14 @@ function check_form($form_id, $values)
                 $aResources = [$_SESSION['doc_id']];
             }
 
-            if ($objectSentSign == 'attachment' && $hasAttachmentError['error']) {
+            if ($hasAttachmentError['error']) {
                 if (!empty($_SESSION['stockCheckbox'])) {
                     $_SESSION['action_error'] = _MAIL_HAS_NO_RESPONSE_PROJECT . ' : ' . implode(",", $hasAttachmentError['resList']);
                 } else {
                     $_SESSION['action_error'] = _NO_RESPONSE_PROJECT_VISA;
                 }
                 return false;
-            } elseif ($objectSentSign == 'attachment') {
+            } else {
                 foreach ($aResources as $resId) {
                     $attachments = \Attachment\models\AttachmentModel::getOnView([
                         'select'    => [
@@ -170,16 +191,6 @@ function check_form($form_id, $values)
                         }
                     }
                 }
-            } elseif ($objectSentNote == 'mail') {
-                foreach ($aResources as $resId) {
-                    $adrMainInfo = \Convert\controllers\ConvertPdfController::getConvertedPdfById(['resId' => $resId, 'collId' => 'letterbox_coll']);
-                    $docserverMainInfo = \Docserver\models\DocserverModel::getByDocserverId(['docserverId' => $adrMainInfo['docserver_id']]);
-                    $filePath = $docserverMainInfo['path_template'] . str_replace('#', '/', $adrMainInfo['path']) . $adrMainInfo['filename'];
-                    if (!is_file($filePath)) {
-                        $_SESSION['action_error'] = _FILE_MISSING . ' : ' . $filePath;
-                        return false;
-                    }
-                }
             }
         }
     }
@@ -227,21 +238,10 @@ function manage_form($arr_id, $history, $id_action, $label_action, $status, $col
                 $attachmentToFreeze = FastParapheurController::sendDatas(['config' => $config, 'resIdMaster' => $res_id]);
             } elseif ($config['id'] == 'maarchParapheur') {
 
-                $processingUser  = get_value_fields($values_form, 'processingUser');
-                $objectSentNote  = get_value_fields($values_form, 'objectSentNote');
-                $objectSentSign  = get_value_fields($values_form, 'objectSentSign');
-
-                if (!empty($objectSentNote)) {
-                    $objectSent = $objectSentNote;
-                } else {
-                    $objectSent = $objectSentSign;
-                }
-                $processingUserInfo = \ExternalSignatoryBook\controllers\MaarchParapheurController::getUserById(['config' => $config, 'id' => $processingUser]);
                 $sendedInfo = \ExternalSignatoryBook\controllers\MaarchParapheurController::sendDatas([
                     'config'             => $config,
                     'resIdMaster'        => $res_id,
-                    'processingUser'     => $processingUserInfo['login'],
-                    'objectSent'         => $objectSent,
+                    'objectSent'         => 'attachment',
                     'userId'             => $_SESSION['user']['UserId']
                 ]);
                 if (!empty($sendedInfo['error'])) {
@@ -256,30 +256,22 @@ function manage_form($arr_id, $history, $id_action, $label_action, $status, $col
         }
 
         if (!empty($attachmentToFreeze)) {
-            if (!empty($attachmentToFreeze['letterbox_coll'])) {
-                \Resource\models\ResModel::update([
-                    'set' => ['external_signatory_book_id' => $attachmentToFreeze['letterbox_coll'][$res_id]],
-                    'where' => ['res_id = ?'],
-                    'data' => [$res_id]
-                ]);
-            } else {
-                if (!empty($attachmentToFreeze['attachments_coll'])) {
-                    foreach ($attachmentToFreeze['attachments_coll'] as $resId => $externalId) {
-                        \Attachment\models\AttachmentModel::freezeAttachment([
-                            'resId' => $resId,
-                            'table' => 'res_attachments',
-                            'externalId' => $externalId
-                        ]);
-                    }
+            if (!empty($attachmentToFreeze['attachments_coll'])) {
+                foreach ($attachmentToFreeze['attachments_coll'] as $resId => $externalId) {
+                    \Attachment\models\AttachmentModel::freezeAttachment([
+                        'resId' => $resId,
+                        'table' => 'res_attachments',
+                        'externalId' => $externalId
+                    ]);
                 }
-                if (!empty($attachmentToFreeze['attachments_version_coll'])) {
-                    foreach ($attachmentToFreeze['attachments_version_coll'] as $resId => $externalId) {
-                        \Attachment\models\AttachmentModel::freezeAttachment([
-                            'resId' => $resId,
-                            'table' => 'res_version_attachments',
-                            'externalId' => $externalId
-                        ]);
-                    }
+            }
+            if (!empty($attachmentToFreeze['attachments_version_coll'])) {
+                foreach ($attachmentToFreeze['attachments_version_coll'] as $resId => $externalId) {
+                    \Attachment\models\AttachmentModel::freezeAttachment([
+                        'resId' => $resId,
+                        'table' => 'res_version_attachments',
+                        'externalId' => $externalId
+                    ]);
                 }
             }
 
diff --git a/core/xml/actions_pages.xml b/core/xml/actions_pages.xml
index ba2fa09116d..d9252c157d3 100755
--- a/core/xml/actions_pages.xml
+++ b/core/xml/actions_pages.xml
@@ -226,6 +226,18 @@ An action page is described in a ACTIONPAGE tag :
             <COLL_ID>letterbox_coll</COLL_ID>
         </COLLECTIONS>
     </ACTIONPAGE>
+    <ACTIONPAGE>
+        <ID>sendToExternalNoteBook</ID>
+        <LABEL>_SEND_TO_EXTERNAL_NOTEBOOK</LABEL>
+        <NAME>sendToExternalNoteBook</NAME>
+        <component>sendExternalNoteBookAction</component>
+        <ORIGIN>apps</ORIGIN>
+        <MODULE></MODULE>
+        <FLAG_CREATE>false</FLAG_CREATE>
+        <COLLECTIONS>
+            <COLL_ID>letterbox_coll</COLL_ID>
+        </COLLECTIONS>
+    </ACTIONPAGE>
     <ACTIONPAGE>
         <ID>close_mail_and_index</ID>
         <LABEL>_CLOSE_MAIL_AND_INDEX</LABEL>
diff --git a/modules/visa/batch/process_mailsFromSignatoryBook.php b/modules/visa/batch/process_mailsFromSignatoryBook.php
index 41d94d5fd34..a22e4e88588 100755
--- a/modules/visa/batch/process_mailsFromSignatoryBook.php
+++ b/modules/visa/batch/process_mailsFromSignatoryBook.php
@@ -162,6 +162,7 @@ try {
     }
 
     $configRemoteSignatoryBook = [];
+    $configRemoteNoteBook = ['id' => 'maarchParapheur'];
     if (file_exists($path)) {
         $loadedXml = simplexml_load_file($path);
         if ($loadedXml) {
@@ -170,6 +171,9 @@ try {
                 if ($value->id == $configRemoteSignatoryBook['id']) {
                     $configRemoteSignatoryBook['data'] = (array)$value;
                 }
+                if ($value->id == $configRemoteNoteBook['id']) {
+                    $configRemoteNoteBook['data'] = (array)$value;
+                }
             }
         }
     } else {
@@ -244,15 +248,6 @@ while ($reqResult = $stmt->fetchObject()) {
     }
 }
 
-$GLOBALS['logger']->write('Retrieve mails sent to remote signatory book', 'INFO');
-$query = "SELECT res_id, external_signatory_book_id as external_id, subject, typist 
-        FROM res_letterbox WHERE external_signatory_book_id IS NOT NULL";
-$stmt = $GLOBALS['db']->query($query, []);
-
-while ($reqResult = $stmt->fetchObject()) {
-    $idsToRetrieve['resLetterbox'][$reqResult->res_id] = $reqResult;
-}
-
 // On récupère les pj signés dans le parapheur distant
 $GLOBALS['logger']->write('Retrieve signed/annotated documents from remote signatory book', 'INFO');
 if ($configRemoteSignatoryBook['id'] == 'ixbus') {
@@ -267,6 +262,19 @@ if ($configRemoteSignatoryBook['id'] == 'ixbus') {
     $retrievedMails = \ExternalSignatoryBook\controllers\XParaphController::retrieveSignedMails(['config' => $configRemoteSignatoryBook, 'idsToRetrieve' => $idsToRetrieve]);
 }
 
+$GLOBALS['logger']->write('Retrieve mails sent to remote signatory book', 'INFO');
+$query = "SELECT res_id, external_signatory_book_id as external_id, subject, typist 
+        FROM res_letterbox WHERE external_signatory_book_id IS NOT NULL";
+$stmt = $GLOBALS['db']->query($query, []);
+
+while ($reqResult = $stmt->fetchObject()) {
+    $idsToRetrieve['resLetterbox'][$reqResult->res_id] = $reqResult;
+}
+if (!empty($idsToRetrieve['resLetterbox'])) {
+    $retrievedLetterboxMails = \ExternalSignatoryBook\controllers\MaarchParapheurController::retrieveSignedMails(['config' => $configRemoteNoteBook, 'idsToRetrieve' => $idsToRetrieve]);
+    $retrievedMails['resLetterbox'] = $retrievedLetterboxMails['resLetterbox'];
+}
+
 if (!empty($retrievedMails['error'])) {
     $GLOBALS['logger']->write($retrievedMails['error'], 'ERROR');
     exit;
diff --git a/modules/visa/class/MaarchParapheurController.php b/modules/visa/class/MaarchParapheurController.php
index 5a51c216f11..44fc102d419 100755
--- a/modules/visa/class/MaarchParapheurController.php
+++ b/modules/visa/class/MaarchParapheurController.php
@@ -15,29 +15,6 @@
 
 class MaarchParapheurController
 {
-    public static function getModal($config)
-    {
-        $initializeDatas = MaarchParapheurController::getInitializeDatas($config);
-        if (!empty($initializeDatas['error'])) {
-            return ['error' => $initializeDatas['error']];
-        }
-        $html .= '<label for="processingUser">' . _USER_MAARCH_PARAPHEUR . '</label><select name="processingUser" id="processingUser">';
-        if (!empty($initializeDatas['users'])) {
-            foreach ($initializeDatas['users'] as $value) {
-                $html .= '<option value="';
-                $html .= $value['id'];
-                $html .= '">';
-                $html .= $value['firstname'] . ' ' . $value['lastname'];
-                $html .= '</option>';
-            }
-        }
-        $html .= '</select><br /><br /><br /><br />';
-        $html .= '<input type="radio" name="objectSent" id="objectSentNote" value="mail" checked="checked" /><label for="objectSentNote" style="float: none;display: unset;">' . _MAIL_NOTE . '</label><br/>';
-        $html .= '<input type="radio" name="objectSent" id="objectSentSign" value="attachment" /><label for="objectSentSign" style="float: none;display: unset;">' . _ATTACHMENT_SIGNATURE .'</label><br /><br />';
-
-        return $html;
-    }
-
     public static function getInitializeDatas($config)
     {
         $rawResponse['users'] = \ExternalSignatoryBook\controllers\MaarchParapheurController::getUsers(['config' => $config]);
diff --git a/rest/index.php b/rest/index.php
index e761b5f7b19..0730374032b 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -285,6 +285,7 @@ $app->post('/acknowledgementReceipt', \AcknowledgementReceipt\controllers\Acknow
 //PreProcess
 $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/checkAcknowledgementReceipt', \Action\controllers\PreProcessActionController::class . ':checkAcknowledgementReceipt');
 $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/checkExternalSignatoryBook', \Action\controllers\PreProcessActionController::class . ':checkExternalSignatoryBook');
+$app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/checkExternalNoteBook', \Action\controllers\PreProcessActionController::class . ':checkExternalNoteBook');
 $app->get('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions/{actionId}/getRedirect', \Action\controllers\PreProcessActionController::class . ':getRedirectInformations');
 $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions/{actionId}/checkShippings', \Action\controllers\PreProcessActionController::class . ':checkShippings');
 $app->get('/resources/{resId}/users/{userId}/isDestinationChanging', \Action\controllers\PreProcessActionController::class . ':isDestinationChanging');
diff --git a/src/app/action/controllers/ActionMethodController.php b/src/app/action/controllers/ActionMethodController.php
index 424d4ec211c..5732f8c4a2d 100644
--- a/src/app/action/controllers/ActionMethodController.php
+++ b/src/app/action/controllers/ActionMethodController.php
@@ -12,18 +12,20 @@
 
 namespace Action\controllers;
 
+use AcknowledgementReceipt\models\AcknowledgementReceiptModel;
+use Action\models\ActionModel;
+use Action\models\BasketPersistenceModel;
+use Action\models\ResMarkAsReadModel;
 use Entity\controllers\ListInstanceController;
 use Entity\models\ListInstanceModel;
+use ExternalSignatoryBook\controllers\MaarchParapheurController;
 use History\controllers\HistoryController;
+use MessageExchange\controllers\MessageExchangeReviewController;
 use Note\models\NoteModel;
 use Resource\models\ResModel;
-use Action\models\ResMarkAsReadModel;
-use Action\models\BasketPersistenceModel;
-use Action\models\ActionModel;
-use SrcCore\models\ValidatorModel;
+use SrcCore\models\CoreConfigModel;
 use SrcCore\models\CurlModel;
-use AcknowledgementReceipt\models\AcknowledgementReceiptModel;
-use MessageExchange\controllers\MessageExchangeReviewController;
+use SrcCore\models\ValidatorModel;
 use User\models\UserModel;
 
 class ActionMethodController
@@ -42,6 +44,7 @@ class ActionMethodController
         'disabledBasketPersistenceAction'       => 'disabledBasketPersistenceAction',
         'resMarkAsReadAction'                   => 'resMarkAsReadAction',
         'sendExternalSignatoryBookAction'       => 'sendExternalSignatoryBookAction',
+        'sendExternalNoteBookAction'            => 'sendExternalNoteBookAction',
         'createAcknowledgementReceiptsAction'   => 'createAcknowledgementReceipts',
         'updateAcknowledgementSendDateAction'   => 'updateAcknowledgementSendDateAction',
         'sendShippingAction'                    => 'createMailevaShippings'
@@ -264,4 +267,49 @@ class ActionMethodController
 
         return true;
     }
+
+    public static function sendExternalNoteBookAction(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['resId']);
+        ValidatorModel::intVal($args, ['resId']);
+
+        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'modules/visa/xml/remoteSignatoryBooks.xml']);
+        $config = [];
+
+        if (!empty($loadedXml)) {
+            $config['id'] = 'maarchParapheur';
+            foreach ($loadedXml->signatoryBook as $value) {
+                if ($value->id == $config['id']) {
+                    $config['data'] = (array)$value;
+                    break;
+                }
+            }
+
+            $processingUserInfo = MaarchParapheurController::getUserById(['config' => $config, 'id' => $args['data']['processingUser']]);
+            $sendedInfo = MaarchParapheurController::sendDatas([
+                'config'           => $config,
+                'resIdMaster'      => $args['resId'],
+                'processingUser'   => $processingUserInfo['login'],
+                'objectSent'       => 'mail',
+                'userId'           => $GLOBALS['userId']
+            ]);
+            if (!empty($sendedInfo['error'])) {
+                return ['errors' => [$sendedInfo['error']]];
+            } else {
+                $attachmentToFreeze = $sendedInfo['sended'];
+            }
+
+            $historyInfo = ' (à ' . $processingUserInfo['firstname'] . ' ' . $processingUserInfo['lastname'] . ')';
+        }
+
+        if (!empty($attachmentToFreeze)) {
+            ResModel::update([
+                'set' => ['external_signatory_book_id' => $attachmentToFreeze['letterbox_coll'][$args['resId']]],
+                'where' => ['res_id = ?'],
+                'data' => [$args['resId']]
+            ]);
+        }
+
+        return ['history' => $historyInfo];
+    }
 }
diff --git a/src/app/action/controllers/ExternalSignatoryBookTrait.php b/src/app/action/controllers/ExternalSignatoryBookTrait.php
index fc16db017f3..d189c1f358f 100644
--- a/src/app/action/controllers/ExternalSignatoryBookTrait.php
+++ b/src/app/action/controllers/ExternalSignatoryBookTrait.php
@@ -59,12 +59,10 @@ trait ExternalSignatoryBookTrait
                     return ['errors' => ['No attachment for this mail : ' . $noAttachmentsResource['alt_identifier']]];
                 }
 
-                $processingUserInfo = MaarchParapheurController::getUserById(['config' => $config, 'id' => $args['data']['processingUser']]);
                 $sendedInfo = MaarchParapheurController::sendDatas([
                     'config'           => $config,
                     'resIdMaster'      => $args['resId'],
-                    'processingUser'   => $processingUserInfo['login'],
-                    'objectSent'       => $args['data']['objectSent'],
+                    'objectSent'       => 'attachment',
                     'userId'           => $GLOBALS['userId']
                 ]);
                 if (!empty($sendedInfo['error'])) {
@@ -73,7 +71,7 @@ trait ExternalSignatoryBookTrait
                     $attachmentToFreeze = $sendedInfo['sended'];
                 }
 
-                $historyInfo = ' (à ' . $processingUserInfo['firstname'] . ' ' . $processingUserInfo['lastname'] . ')';
+                $historyInfo = '';
             } elseif ($config['id'] == 'xParaph') {
                 $attachments = AttachmentModel::getOnView([
                     'select'    => [
diff --git a/src/app/action/controllers/PreProcessActionController.php b/src/app/action/controllers/PreProcessActionController.php
index fbdea5cffef..42d07422480 100755
--- a/src/app/action/controllers/PreProcessActionController.php
+++ b/src/app/action/controllers/PreProcessActionController.php
@@ -418,9 +418,7 @@ class PreProcessActionController
             $signatureBookEnabled = $config['id'];
             $additionalsInfos = [
                 'attachments'   => [],
-                'noAttachment'  => [],
-                'mails'         => [],
-                'noMail'        => []
+                'noAttachment'  => []
             ];
             if ($signatureBookEnabled == 'ixbus') {
                 // TODO
@@ -444,29 +442,11 @@ class PreProcessActionController
                 }
 
                 foreach ($data['resources'] as $resId) {
-                    // Check Mail
                     $noAttachmentsResource = ResModel::getExtById(['resId' => $resId, 'select' => ['alt_identifier']]);
                     if (empty($noAttachmentsResource['alt_identifier'])) {
                         $noAttachmentsResource['alt_identifier'] = _UNDEFINED;
                     }
 
-                    $adrMainInfo = ConvertPdfController::getConvertedPdfById(['resId' => $resId, 'collId' => 'letterbox_coll']);
-                    if (empty($adrMainInfo['docserver_id'])) {
-                        $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'noMailConversion'];
-                        continue;
-                    }
-                    $docserverMainInfo = DocserverModel::getByDocserverId(['docserverId' => $adrMainInfo['docserver_id']]);
-                    if (empty($docserverMainInfo['path_template'])) {
-                        $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'docserverDoesNotExists'];
-                        continue;
-                    }
-                    $filePath = $docserverMainInfo['path_template'] . str_replace('#', '/', $adrMainInfo['path']) . $adrMainInfo['filename'];
-                    if (!is_file($filePath)) {
-                        $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'fileDoesNotExists'];
-                        continue;
-                    }
-                    $additionalsInfos['mails'][] = ['res_id' => $resId];
-
                     $listinstances = ListInstanceModel::getVisaCircuitByResId(['select' => ['external_id', 'firstname', 'lastname'], 'id' => $resId]);
                     if (empty($listinstances)) {
                         $additionalsInfos['visaWorkflowError'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'noVisaWorkflow'];
@@ -589,6 +569,103 @@ class PreProcessActionController
         return $response->withJson(['signatureBookEnabled' => $signatureBookEnabled, 'additionalsInfos' => $additionalsInfos, 'errors' => $errors]);
     }
 
+    public function checkExternalNoteBook(Request $request, Response $response, array $aArgs)
+    {
+        $currentUser = UserModel::getByLogin(['login' => $GLOBALS['userId'], 'select' => ['id']]);
+
+        $errors = ResourceListController::listControl(['groupId' => $aArgs['groupId'], 'userId' => $aArgs['userId'], 'basketId' => $aArgs['basketId'], 'currentUserId' => $currentUser['id']]);
+        if (!empty($errors['errors'])) {
+            return $response->withStatus($errors['code'])->withJson(['errors' => $errors['errors']]);
+        }
+
+        $data = $request->getParsedBody();
+
+        $data['resources'] = array_slice($data['resources'], 0, 500);
+        if (!ResController::hasRightByResId(['resId' => $data['resources'], 'userId' => $GLOBALS['userId']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+
+        $resources = ResModel::get([
+            'select' => ['res_id', 'locker_user_id', 'locker_time'],
+            'where'  => ['res_id in (?)'],
+            'data'   => [$data['resources']]
+        ]);
+
+        $resourcesForProcess = [];
+        foreach ($resources as $resource) {
+            $lock = true;
+            if (empty($resource['locker_user_id'] || empty($resource['locker_time']))) {
+                $lock = false;
+            } elseif ($resource['locker_user_id'] == $currentUser['id']) {
+                $lock = false;
+            } elseif (strtotime($resource['locker_time']) < time()) {
+                $lock = false;
+            }
+            if (!$lock) {
+                $resourcesForProcess[] = $resource['res_id'];
+            }
+        }
+        $data['resources'] = $resourcesForProcess;
+
+        $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'modules/visa/xml/remoteSignatoryBooks.xml']);
+
+        $errors = [];
+        if (!empty($loadedXml)) {
+            $config['id'] = 'maarchParapheur';
+            foreach ($loadedXml->signatoryBook as $value) {
+                if ($value->id == $config['id']) {
+                    $config['data'] = (array)$value;
+                    break;
+                }
+            }
+
+            $additionalsInfos = [
+                'mails'  => [],
+                'noMail' => []
+            ];
+
+            $userList = MaarchParapheurController::getInitializeDatas(['config' => $config]);
+            if (!empty($userList['users'])) {
+                $additionalsInfos['users'] = $userList['users'];
+                $aUsersInMP = [];
+                foreach ($userList['users'] as $value) {
+                    $aUsersInMP[] = $value['id'];
+                }
+            } else {
+                $additionalsInfos['users'] = [];
+            }
+            if (!empty($userList['errors'])) {
+                $errors[] = $userList['errors'];
+            }
+
+            foreach ($data['resources'] as $resId) {
+                $noAttachmentsResource = ResModel::getExtById(['resId' => $resId, 'select' => ['alt_identifier']]);
+                if (empty($noAttachmentsResource['alt_identifier'])) {
+                    $noAttachmentsResource['alt_identifier'] = _UNDEFINED;
+                }
+
+                $adrMainInfo = ConvertPdfController::getConvertedPdfById(['resId' => $resId, 'collId' => 'letterbox_coll']);
+                if (empty($adrMainInfo['docserver_id'])) {
+                    $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'noMailConversion'];
+                    continue;
+                }
+                $docserverMainInfo = DocserverModel::getByDocserverId(['docserverId' => $adrMainInfo['docserver_id']]);
+                if (empty($docserverMainInfo['path_template'])) {
+                    $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'docserverDoesNotExists'];
+                    continue;
+                }
+                $filePath = $docserverMainInfo['path_template'] . str_replace('#', '/', $adrMainInfo['path']) . $adrMainInfo['filename'];
+                if (!is_file($filePath)) {
+                    $additionalsInfos['noMail'][] = ['alt_identifier' => $noAttachmentsResource['alt_identifier'], 'res_id' => $resId, 'reason' => 'fileDoesNotExists'];
+                    continue;
+                }
+                $additionalsInfos['mails'][] = ['res_id' => $resId];
+            }
+        }
+
+        return $response->withJson(['additionalsInfos' => $additionalsInfos, 'errors' => $errors]);
+    }
+
     public function checkShippings(Request $request, Response $response)
     {
         $mailevaConfig = CoreConfigModel::getMailevaConfiguration();
diff --git a/src/core/lang/lang-en.php b/src/core/lang/lang-en.php
index 01bd3cc975f..e34f748dd45 100755
--- a/src/core/lang/lang-en.php
+++ b/src/core/lang/lang-en.php
@@ -320,6 +320,7 @@ define('_MARK_AS_READ_DESC', 'Mark the mail as \'read\' in the basket. Insert th
 define('_SEND_FILE_WS', 'Send file via Web Service');
 define('_SEND_DATA_WS', 'Send data via Web Service');
 define('_SEND_TO_EXTERNAL_SB', 'Send data to external signature book');
+define('_SEND_TO_EXTERNAL_NOTEBOOK', 'Send data to external note book');
 define('_CLOSE_MAIL_AND_INDEX', 'Close a mail and launch the indexation');
 define('_CLOSE_MAIL_AND_INDEX_DESC', 'Allows you to update the closing date of a mail (\'closing_date\' of the mlb_coll_ext table) AND opens the indexing page to save a new mail.');
 define('_CLOSE_MAIL_WITH_ATTACHMENT', 'Closing with attachment');
diff --git a/src/core/lang/lang-fr.php b/src/core/lang/lang-fr.php
index 976ea096551..2115ae889d9 100755
--- a/src/core/lang/lang-fr.php
+++ b/src/core/lang/lang-fr.php
@@ -320,6 +320,7 @@ define('_MARK_AS_READ_DESC', 'Marque le courrier comme \'lu\' dans la bannette.
 define('_SEND_FILE_WS', 'Envoyer le document via Web Service');
 define('_SEND_DATA_WS', 'Envoyer des données via Web Service');
 define('_SEND_TO_EXTERNAL_SB', 'Envoyer des données vers un parapheur externe');
+define('_SEND_TO_EXTERNAL_NOTEBOOK', 'Envoyer des données vers un annotateur externe');
 define('_CLOSE_MAIL_AND_INDEX', 'Clôturer un courrier et lancer l\'indexation');
 define('_CLOSE_MAIL_AND_INDEX_DESC', 'Permet de mettre à jour la date de clôture d\'un courrier (\'closing_date\' de la table mlb_coll_ext) ET ouvre la page d\'indexation afin d\'enregistrer un nouveau courrier.');
 define('_CLOSE_MAIL_WITH_ATTACHMENT', 'Clôturer un courrier avec pièce jointe');
diff --git a/src/core/lang/lang-nl.php b/src/core/lang/lang-nl.php
index a03bd75e123..40f2e8436d7 100755
--- a/src/core/lang/lang-nl.php
+++ b/src/core/lang/lang-nl.php
@@ -499,3 +499,5 @@ define("_FILE_NOT_ALLOWED_INFO_3", "is not allowed_TO_TRANSLATE");
 
 define("_ENTITY", "Entity_TO_TRANSLATE");
 define("_PRINT_SEP_TITLE", "Mail separator_TO_TRANSLATE");
+
+define('_SEND_TO_EXTERNAL_NOTEBOOK', 'Send data to external note book_TO_TRANSLATE');
\ No newline at end of file
diff --git a/src/frontend/app/actions/actions-list.component.ts b/src/frontend/app/actions/actions-list.component.ts
index 9c3685eabd1..d51221adcf8 100644
--- a/src/frontend/app/actions/actions-list.component.ts
+++ b/src/frontend/app/actions/actions-list.component.ts
@@ -14,6 +14,7 @@ import { CreateAcknowledgementReceiptActionComponent } from './create-acknowledg
 import { CloseAndIndexActionComponent } from './close-and-index-action/close-and-index-action.component';
 import { UpdateDepartureDateActionComponent } from './update-departure-date-action/update-departure-date-action.component';
 import { SendExternalSignatoryBookActionComponent } from './send-external-signatory-book-action/send-external-signatory-book-action.component';
+import { SendExternalNoteBookActionComponent } from './send-external-note-book-action/send-external-note-book-action.component';
 // import { ProcessActionComponent } from './process-action/process-action.component';
 import { Router } from '@angular/router';
 import { ViewDocActionComponent } from './view-doc-action/view-doc-action.component';
@@ -351,6 +352,28 @@ export class ActionsListComponent implements OnInit {
         });
     }
 
+    sendExternalNoteBookAction() {
+        const dialogRef = this.dialog.open(SendExternalNoteBookActionComponent, {
+            width: '500px',
+            data: {
+                contextMode: this.contextMode,
+                contextChrono: this.contextMenuTitle,
+                selectedRes: this.selectedRes,
+                action: this.currentAction,
+                currentBasketInfo: this.currentBasketInfo
+            }
+        });
+        dialogRef.afterClosed().subscribe(result => {
+            this.unlock();
+
+            if (result == 'success') {
+                this.endAction();
+            } else {
+                this.unlockRest();
+            }
+        });
+    }
+
     redirectAction() {
         const dialogRef = this.dialog.open(RedirectActionComponent, {
             data: {
diff --git a/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.html b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.html
new file mode 100644
index 00000000000..ba4f0ce8120
--- /dev/null
+++ b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.html
@@ -0,0 +1,55 @@
+<h1 mat-dialog-title>{{data.action.label_action}}</h1>
+<div mat-dialog-content>
+    <div *ngIf="loading" class="loading" style="display:flex;height:100%;">
+        <mat-spinner style="margin:auto;"></mat-spinner>
+    </div>
+    <mat-sidenav-container autosize style="height:100%;">
+        <mat-sidenav-content style="background: white;">
+            <div class="row" style="margin: 0;">
+                <div class="col-md-12">
+                    {{lang.makeActionOn}}
+                    <b *ngIf="data.selectedRes.length == 1 && data.contextChrono != ''" color="primary"
+                        class="highlight">{{data.contextChrono}}</b>
+                    <b *ngIf="!data.contextMode" color="primary" class="highlight">{{data.selectedRes.length}}
+                        {{lang.elements}}</b> ?
+                </div>
+                <div>
+                    <div class="col-md-12" style="padding-top: 10px;" *ngIf="additionalsInfos.users.length != 0">
+                        <mat-form-field>
+                            <mat-label>{{lang.userMaarchParapheur}}</mat-label>
+                            <mat-select name="processingUser" [(ngModel)]="externalSignatoryBookDatas.processingUser" required>
+                                <mat-option *ngFor="let user of additionalsInfos.users" [value]="user.id">
+                                    {{user.firstname}} {{user.lastname}} ({{user.email}})
+                                </mat-option>
+                            </mat-select>
+                        </mat-form-field>
+                    </div>
+                    <div class="col-md-12" *ngIf="additionalsInfos.users.length == 0">
+                        {{lang.noUserDefinedInMaarchParapheur}}
+                    </div>
+                    <div class="col-md-12" *ngIf="additionalsInfos.noMail.length != 0">
+                        <div>
+                            <div class="alert-message alert-message-danger mailList" role="alert">
+                                <p>
+                                    {{lang.canNotMakeAction}} :
+                                </p>
+                                <ul>
+                                    <li *ngFor="let mail of additionalsInfos.noMail">
+                                        <b>{{mail.alt_identifier}}</b> : {{lang[mail.reason]}}
+                                    </li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="col-md-12" style="padding-top: 10px;">
+                    <app-note-editor #noteEditor [resIds]="data.selectedRes"></app-note-editor>
+                </div>
+            </div>
+        </mat-sidenav-content>
+    </mat-sidenav-container>
+</div>
+<div mat-dialog-actions class="actions">
+    <button mat-raised-button mat-button color="primary" [disabled]="loading || checkValidAction()" (click)="onSubmit()">{{lang.validate}}</button>
+    <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.scss b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.scss
new file mode 100644
index 00000000000..9424211bb4a
--- /dev/null
+++ b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.scss
@@ -0,0 +1,128 @@
+@import '../../../css/vars.scss';
+
+.fullHeight {
+    height: 70vh;
+}
+
+.fullWidth {
+    width: 70vw;
+}
+
+.highlight {
+    font-size: 110%;
+}
+
+.loading {
+    display: flex;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: #ffffffb3;
+    z-index: 2;
+    overflow: hidden;
+}
+
+.mailList {
+    ul {
+        font-size: 12px;
+        max-height: 100px;
+        overflow: auto;
+        padding-left: 25px;
+        padding-right: 5px;
+        padding-bottom: 10px;
+        margin-top: 10px;
+    }
+
+    p {
+        //font-size: 18px;
+        margin: 0;
+        text-decoration: underline;
+    }
+
+    b {
+        font-size: 120%;
+    }
+}
+
+.formType {
+    align-items: center;
+    display: flex;
+    margin: 10px;
+    border-radius: 4px;
+    border: solid 1px #ccc;
+    position: relative;
+    padding: 10px;
+
+    &-title {
+        white-space: pre;
+        overflow: hidden;
+        max-width: 85%;
+        text-overflow: ellipsis;
+        z-index: 1;
+        font-size: 10px;
+        font-weight: bold;
+        background: white;
+        position: absolute;
+        top: -7px;
+        left: 10px;
+        padding: 0px;
+        margin: 0px;
+        color: #135f7f;
+    }
+
+    ::ng-deep.mat-form-field-suffix {
+        color: $secondary;
+        font-size: 15px;
+        top: 0;
+    }
+
+    ::ng-deep.mat-form-field-wrapper {
+        padding: 0;
+    }
+}
+
+.priceContent {
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    width: 100%;
+
+    &-label {
+        text-align: right;
+        color: $primary;
+        flex: 1;
+        justify-content: flex-end;
+        display: flex;
+        padding-right: 10px;
+    }
+
+    .mat-form-field {
+        width: 90px !important;
+
+        input {
+            font-weight: bold;
+            user-select: none;
+        }
+    }
+}
+
+.priceInfo {
+    padding-right: 20px;
+    font-size: 10px;
+    opacity: 0.5;
+    width: 100%;
+}
+
+.pjList {
+    display: flex;
+    width: 100%;
+    overflow: auto;
+    flex-direction: column;
+    background: #666;
+
+    img {
+        margin: 10px;
+    }
+}
\ No newline at end of file
diff --git a/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.ts b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.ts
new file mode 100644
index 00000000000..374ca4dd394
--- /dev/null
+++ b/src/frontend/app/actions/send-external-note-book-action/send-external-note-book-action.component.ts
@@ -0,0 +1,77 @@
+import { Component, OnInit, Inject, ViewChild } from '@angular/core';
+import { LANG } from '../../translate.component';
+import { NotificationService } from '../../notification.service';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
+import { HttpClient } from '@angular/common/http';
+import { NoteEditorComponent } from '../../notes/note-editor.component';
+
+@Component({
+    templateUrl: "send-external-note-book-action.component.html",
+    styleUrls: ['send-external-note-book-action.component.scss'],
+    providers: [NotificationService],
+})
+export class SendExternalNoteBookActionComponent implements OnInit {
+
+    lang: any = LANG;
+    loading: boolean = false;
+    additionalsInfos: any = {
+        users: [],
+        mails: [],
+        noMail: []
+    };
+
+    externalSignatoryBookDatas: any = {
+        processingUser: ''
+    };
+    errors: any;
+
+    @ViewChild('noteEditor') noteEditor: NoteEditorComponent;
+
+    constructor(public http: HttpClient, private notify: NotificationService, public dialogRef: MatDialogRef<SendExternalNoteBookActionComponent>, @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+    ngOnInit(): void {
+        this.loading = true;
+
+        this.http.post('../../rest/resourcesList/users/' + this.data.currentBasketInfo.ownerId + '/groups/' + this.data.currentBasketInfo.groupId + '/baskets/' + this.data.currentBasketInfo.basketId + '/checkExternalNoteBook', { resources: this.data.selectedRes })
+            .subscribe((data: any) => {
+                this.additionalsInfos = data.additionalsInfos;
+                this.errors = data.errors;
+                this.loading = false;
+            }, (err: any) => {
+                this.notify.handleErrors(err);
+                this.loading = false;
+            });
+    }
+
+    onSubmit(): void {
+        this.loading = true;
+
+        let realResSelected: string[];
+        let datas: any;
+
+        realResSelected = this.additionalsInfos.mails.map((e: any) => { return e.res_id; });
+        datas = this.externalSignatoryBookDatas;
+
+        this.http.put('../../rest/resourcesList/users/' + this.data.currentBasketInfo.ownerId + '/groups/' + this.data.currentBasketInfo.groupId + '/baskets/' + this.data.currentBasketInfo.basketId + '/actions/' + this.data.action.id, { resources: realResSelected, note: this.noteEditor.getNoteContent(), data: datas })
+            .subscribe((data: any) => {
+                if (!data) {
+                    this.dialogRef.close('success');
+                }
+                if (data && data.errors != null) {
+                    this.notify.error(data.errors);
+                }
+                this.loading = false;
+            }, (err: any) => {
+                this.notify.handleErrors(err);
+                this.loading = false;
+            });
+    }
+
+    checkValidAction() {
+        if (this.additionalsInfos.mails.length == 0 || !this.externalSignatoryBookDatas.processingUser || this.additionalsInfos.users.length == 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.html b/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.html
index 1f3d8c70f44..b6e21b2219e 100644
--- a/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.html
+++ b/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.html
@@ -1,20 +1,10 @@
-<div class="col-md-12" style="padding-top: 10px;" *ngIf="additionalsInfos.users.length != 0 && externalSignatoryBookDatas.objectSent == 'mail'">
-    <mat-form-field>
-        <mat-label>{{lang.userMaarchParapheur}}</mat-label>
-        <mat-select name="processingUser" [(ngModel)]="externalSignatoryBookDatas.processingUser" required>
-            <mat-option *ngFor="let user of additionalsInfos.users" [value]="user.id">
-                {{user.firstname}} {{user.lastname}} ({{user.email}})
-            </mat-option>
-        </mat-select>
-    </mat-form-field>
-</div>
 <div class="col-md-12" *ngIf="additionalsInfos.users.length == 0">
     {{lang.noUserDefinedInMaarchParapheur}}
 </div>
-<div class="col-md-12" *ngIf="externalSignatoryBookDatas.objectSent == 'attachment'">
+<div class="col-md-12">
     <div class="alert-message alert-message-info" role="alert">{{lang.visaWorkflowWillBeSend}}</div>
 </div>
-<div class="col-md-12" *ngIf="additionalsInfos.visaWorkflowError && externalSignatoryBookDatas.objectSent == 'attachment'">
+<div class="col-md-12" *ngIf="additionalsInfos.visaWorkflowError">
     <div>
         <div class="alert-message alert-message-danger mailList" role="alert">
             <p>
@@ -27,24 +17,4 @@
             </ul>
         </div>
     </div>
-</div>
-<div class="col-sm-12" *ngIf="additionalsInfos.users.length != 0">
-    <mat-radio-group required name="objectSent" [(ngModel)]="externalSignatoryBookDatas.objectSent">
-        <mat-radio-button color="primary" name="objectSent" checked value="mail">{{lang.mailNote}}</mat-radio-button>
-        <mat-radio-button color="primary" name="objectSent" value="attachment">{{lang.attachmentSignature}}</mat-radio-button><br><br>
-    </mat-radio-group>
-</div>
-<div class="col-md-12" *ngIf="additionalsInfos.noMail.length != 0 && externalSignatoryBookDatas.objectSent == 'mail'">
-    <div>
-        <div class="alert-message alert-message-danger mailList" role="alert">
-            <p>
-                {{lang.canNotMakeAction}} :
-            </p>
-            <ul>
-                <li *ngFor="let mail of additionalsInfos.noMail">
-                    <b>{{mail.alt_identifier}}</b> : {{lang[mail.reason]}}
-                </li>
-            </ul>
-        </div>
-    </div>
 </div>
\ No newline at end of file
diff --git a/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.ts b/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.ts
index 7f9d4270d16..c3dce09c9d6 100644
--- a/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.ts
+++ b/src/frontend/app/actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component.ts
@@ -27,11 +27,7 @@ export class MaarchParaphComponent implements OnInit {
     ngOnInit(): void { }
 
     checkValidParaph() {
-        if ((this.externalSignatoryBookDatas.objectSent == 'attachment' && this.additionalsInfos.attachments.length == 0) || 
-            (this.externalSignatoryBookDatas.objectSent == 'mail' && 
-                (this.additionalsInfos.mails.length == 0 || !this.externalSignatoryBookDatas.processingUser || this.additionalsInfos.users.length == 0)
-            )
-            ) {
+        if (this.additionalsInfos.attachments.length == 0) {
             return true;
         } else {
             return false;
@@ -39,11 +35,7 @@ export class MaarchParaphComponent implements OnInit {
     }
 
     getRessources() {
-        if (this.externalSignatoryBookDatas.objectSent == 'attachment') {
-            return this.additionalsInfos.attachments.map((e: any) => { return e.res_id; });
-        } else if (this.externalSignatoryBookDatas.objectSent == 'mail') {
-            return this.additionalsInfos.mails.map((e: any) => { return e.res_id; });
-        }
+        return this.additionalsInfos.attachments.map((e: any) => { return e.res_id; });
     }
 
     getDatas() {
diff --git a/src/frontend/app/actions/send-external-signatory-book-action/send-external-signatory-book-action.component.ts b/src/frontend/app/actions/send-external-signatory-book-action/send-external-signatory-book-action.component.ts
index 51d3f1e095e..6bf55a63a27 100644
--- a/src/frontend/app/actions/send-external-signatory-book-action/send-external-signatory-book-action.component.ts
+++ b/src/frontend/app/actions/send-external-signatory-book-action/send-external-signatory-book-action.component.ts
@@ -19,15 +19,12 @@ export class SendExternalSignatoryBookActionComponent implements OnInit {
     additionalsInfos: any = {
         users: [],
         attachments: [],
-        noAttachment: [],
-        mails: [],
-        noMail: []
+        noAttachment: []
     };
     signatoryBookEnabled: string = 'maarchParapheur';
 
     externalSignatoryBookDatas: any = {
-        objectSent: 'attachment',
-        processingUser: ''
+        objectSent: 'attachment'
     };
     errors: any;
 
diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index e67fbcfb46d..7cb8d3e77ae 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -33,6 +33,7 @@ import { CreateAcknowledgementReceiptActionComponent }             from './actio
 import { CloseAndIndexActionComponent }             from './actions/close-and-index-action/close-and-index-action.component';
 import { UpdateDepartureDateActionComponent }   from './actions/update-departure-date-action/update-departure-date-action.component';
 import { SendExternalSignatoryBookActionComponent }   from './actions/send-external-signatory-book-action/send-external-signatory-book-action.component';
+import { SendExternalNoteBookActionComponent }   from './actions/send-external-note-book-action/send-external-note-book-action.component';
 import { XParaphComponent }                         from './actions/send-external-signatory-book-action/x-paraph/x-paraph.component';
 import { MaarchParaphComponent }                         from './actions/send-external-signatory-book-action/maarch-paraph/maarch-paraph.component';
 import { ProcessActionComponent }               from './actions/process-action/process-action.component';
@@ -99,6 +100,7 @@ import { PrintSeparatorComponent }                        from './separator/prin
         CloseMailActionComponent,
         UpdateDepartureDateActionComponent,
         SendExternalSignatoryBookActionComponent,
+        SendExternalNoteBookActionComponent,
         XParaphComponent,
         MaarchParaphComponent,
         ProcessActionComponent,
@@ -125,6 +127,7 @@ import { PrintSeparatorComponent }                        from './separator/prin
         CloseMailActionComponent,
         UpdateDepartureDateActionComponent,
         SendExternalSignatoryBookActionComponent,
+        SendExternalNoteBookActionComponent,
         ProcessActionComponent,
         RedirectActionComponent,
         SendShippingActionComponent,
-- 
GitLab