diff --git a/src/app/contentManagement/controllers/MergeController.php b/src/app/contentManagement/controllers/MergeController.php
index 236011607c330552205345fd1725480fecbdce75..ff84d809cd9a3486bb9c84b3d732c8df25ad4d48 100644
--- a/src/app/contentManagement/controllers/MergeController.php
+++ b/src/app/contentManagement/controllers/MergeController.php
@@ -14,9 +14,14 @@
 
 namespace ContentManagement\controllers;
 
+use Attachment\models\AttachmentModel;
 use Contact\controllers\ContactController;
 use Contact\models\ContactModel;
+use Convert\controllers\ConvertPdfController;
+use Convert\models\AdrModel;
 use CustomField\models\CustomFieldModel;
+use Docserver\controllers\DocserverController;
+use Docserver\models\DocserverModel;
 use Doctype\models\DoctypeModel;
 use Endroid\QrCode\QrCode;
 use Entity\models\EntityModel;
@@ -504,6 +509,167 @@ class MergeController
         return $myContent;
     }
 
+    public static function mergeAction(array $args)
+    {
+        ValidatorModel::notEmpty($args, ['resId', 'type']);
+        ValidatorModel::intVal($args, ['resId']);
+        ValidatorModel::stringType($args, ['type']);
+
+        $mergeData = [
+            'date'   => date('d/m/Y'),
+            'user'   => UserModel::getLabelledUserById(['id' => $GLOBALS['id']]),
+            'entity' => UserModel::getPrimaryEntityById(['id' => $GLOBALS['id'], 'select' => ['*']])
+        ];
+
+        if ($args['type'] == 'attachment') {
+            $document = AttachmentModel::get([
+                'select' => ['res_id', 'docserver_id', 'path', 'filename', 'res_id_master', 'title', 'fingerprint', 'format', 'identifier', 'attachment_type'],
+                'where'  => ['res_id = ?', 'status not in (?)'],
+                'data'   => [$args['resId'], ['DEL']]
+            ]);
+            $document = $document[0];
+
+            $docserver = DocserverModel::getByDocserverId(['docserverId' => $document['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]);
+            if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+                return ['errors' => 'Docserver does not exist'];
+            }
+
+            $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $document['path']) . $document['filename'];
+
+            if (!file_exists($pathToDocument)) {
+                return ['errors' => 'Document not found on docserver'];
+            }
+        } else {
+            $document = ResModel::getById(['select' => ['docserver_id', 'path', 'filename', 'category_id', 'version', 'fingerprint', 'format', 'version'], 'resId' => $args['resId']]);
+            if (empty($document['filename'])) {
+                return ['errors' => 'Document does not exist'];
+            }
+
+            $convertedDocument = AdrModel::getDocuments([
+                'select' => ['docserver_id', 'path', 'filename', 'fingerprint'],
+                'where'  => ['res_id = ?', 'type = ?', 'version = ?'],
+                'data'   => [$args['resId'], 'SIGN', $document['version']],
+                'limit'  => 1
+            ]);
+            $document = $convertedDocument[0] ?? $document;
+
+            $docserver = DocserverModel::getByDocserverId(['docserverId' => $document['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]);
+            if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) {
+                return ['errors' => 'Docserver does not exist'];
+            }
+
+            $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $document['path']) . $document['filename'];
+        }
+
+        $tbs = new \clsTinyButStrong();
+        $tbs->NoErr = true;
+        $tbs->PlugIn(TBS_INSTALL, OPENTBS_PLUGIN);
+
+        $pathInfo = pathinfo($pathToDocument);
+        $extension = $pathInfo['extension'];
+        $filename = $pathInfo['fullFilename'];
+
+        if ($extension == 'odt') {
+            $tbs->LoadTemplate($pathToDocument, OPENTBS_ALREADY_UTF8);
+        } elseif ($extension == 'docx') {
+            $tbs->LoadTemplate($pathToDocument, OPENTBS_ALREADY_UTF8);
+            $templates = ['word/header1.xml', 'word/header2.xml', 'word/header3.xml', 'word/footer1.xml', 'word/footer2.xml', 'word/footer3.xml'];
+            foreach ($templates as $template) {
+                if ($tbs->Plugin(OPENTBS_FILEEXISTS, $template)) {
+                    $tbs->LoadTemplate("#{$template}", OPENTBS_ALREADY_UTF8);
+                    $tbs->MergeField('signature', $mergeData);
+                }
+            }
+            $tbs->PlugIn(OPENTBS_SELECT_MAIN);
+        } else {
+            $tbs->LoadTemplate($pathToDocument, OPENTBS_ALREADY_UTF8);
+        }
+
+        $tbs->MergeField('signature', $mergeData);
+
+        if (in_array($extension, MergeController::OFFICE_EXTENSIONS)) {
+            $tbs->Show(OPENTBS_STRING);
+        } else {
+            $tbs->Show(TBS_NOTHING);
+        }
+
+        if ($args['type'] == 'attachment') {
+            $tmpPath = CoreConfigModel::getTmpPath();
+            $fileNameOnTmp = rand() . $filename;
+            file_put_contents($tmpPath . $fileNameOnTmp . '.' . $extension, $tbs->Source);
+
+            ConvertPdfController::convertInPdf(['fullFilename' => $tmpPath.$fileNameOnTmp.'.'.$extension]);
+
+            if (!file_exists($tmpPath.$fileNameOnTmp.'.pdf')) {
+                return ['errors' => 'Merged document conversion failed'];
+            }
+
+            $content = file_get_contents($tmpPath.$fileNameOnTmp.'.pdf');
+
+            $storeResult = DocserverController::storeResourceOnDocServer([
+                'collId'          => 'attachments_coll',
+                'docserverTypeId' => 'CONVERT',
+                'encodedResource' => base64_encode($content),
+                'format'          => 'pdf'
+            ]);
+
+            if (!empty($storeResult['errors'])) {
+                return ['errors' => $storeResult['errors']];
+            }
+
+            unlink($tmpPath.$fileNameOnTmp.'.'.$extension);
+            unlink($tmpPath.$fileNameOnTmp.'.pdf');
+
+            AdrModel::createAttachAdr([
+                'resId'       => $args['resId'],
+                'type'        => 'TMP',
+                'docserverId' => $storeResult['docserver_id'],
+                'path'        => $storeResult['destination_dir'],
+                'filename'    => $storeResult['file_destination_name'],
+                'fingerprint' => $storeResult['fingerPrint']
+            ]);
+        } else {
+            $tmpPath = CoreConfigModel::getTmpPath();
+            $fileNameOnTmp = rand() . $document['filename'];
+
+            file_put_contents($tmpPath . $fileNameOnTmp . '.' . $extension, $tbs->Source);
+
+            ConvertPdfController::convertInPdf(['fullFilename' => $tmpPath.$fileNameOnTmp.'.'.$extension]);
+
+            if (!file_exists($tmpPath.$fileNameOnTmp.'.pdf')) {
+                return ['errors' => 'Merged document conversion failed'];
+            }
+
+            $content = file_get_contents($tmpPath.$fileNameOnTmp.'.pdf');
+
+            $storeResult = DocserverController::storeResourceOnDocServer([
+                'collId'          => 'letterbox_coll',
+                'docserverTypeId' => 'CONVERT',
+                'encodedResource' => base64_encode($content),
+                'format'          => 'pdf'
+            ]);
+
+            if (!empty($storeResult['errors'])) {
+                return ['errors' => $storeResult['errors']];
+            }
+
+            unlink($tmpPath.$fileNameOnTmp.'.'.$extension);
+            unlink($tmpPath.$fileNameOnTmp.'.pdf');
+
+            AdrModel::createDocumentAdr([
+                'resId'       => $args['resId'],
+                'type'        => 'TMP',
+                'docserverId' => $storeResult['docserver_id'],
+                'path'        => $storeResult['destination_dir'],
+                'filename'    => $storeResult['file_destination_name'],
+                'version'     => $document['version'] + 1,
+                'fingerprint' => $storeResult['fingerPrint']
+            ]);
+        }
+
+        return true;
+    }
+
     private static function formatPerson(array $args)
     {
         $person = [];
diff --git a/src/app/signatureBook/controllers/SignatureBookController.php b/src/app/signatureBook/controllers/SignatureBookController.php
index 46ce954eb884928f6d5e19929a37cc4c444200b8..5cddee93fabb7a7390074f1feea268c354466fda 100755
--- a/src/app/signatureBook/controllers/SignatureBookController.php
+++ b/src/app/signatureBook/controllers/SignatureBookController.php
@@ -21,6 +21,7 @@ use Basket\models\GroupBasketModel;
 use Basket\models\RedirectBasketModel;
 use Contact\controllers\ContactController;
 use Contact\models\ContactModel;
+use ContentManagement\controllers\MergeController;
 use Convert\controllers\ConvertPdfController;
 use Convert\models\AdrModel;
 use Docserver\controllers\DocserverController;
@@ -413,13 +414,28 @@ class SignatureBookController
             return $response->withStatus(404)->withJson(['errors' => 'Signature not found on docserver']);
         }
 
-        $convertedDocument = AdrModel::getDocuments([
-            'select'    => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
-            'where'     => ['res_id = ?', 'type in (?)'],
-            'data'      => [$args['resId'], ['PDF', 'SIGN']],
-            'orderBy'   => ["type='SIGN' DESC", 'version DESC'],
-            'limit'     => 1
-        ]);
+        $document = ResModel::getById(['select' => ['format'], 'resId' => $args['resId']]);
+        if (in_array($document['format'], MergeController::OFFICE_EXTENSIONS)) {
+            $result = MergeController::mergeAction(['resId' => $args['resId'], 'type' => 'resource']);
+            if (!empty($result['errors'])) {
+                return $response->withStatus(400)->withJson(['errors' => $result['errors']]);
+            }
+            $convertedDocument = AdrModel::getDocuments([
+                'select' => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
+                'where'  => ['res_id = ?', 'type = ?'],
+                'data'   => [$args['resId'], 'TMP'],
+                'limit'  => 1
+            ]);
+        } else {
+            $convertedDocument = AdrModel::getDocuments([
+                'select'  => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
+                'where'   => ['res_id = ?', 'type in (?)'],
+                'data'    => [$args['resId'], ['PDF', 'SIGN']],
+                'orderBy' => ["type='SIGN' DESC", 'version DESC'],
+                'limit'   => 1
+            ]);
+        }
+
         if (empty($convertedDocument[0])) {
             return $response->withStatus(400)->withJson(['errors' => 'Converted document does not exist']);
         } elseif ($convertedDocument[0]['type'] == 'SIGN') {
@@ -455,6 +471,11 @@ class SignatureBookController
         }
         unlink($tmpPath.$convertedDocument['filename']);
 
+        if (in_array($document['format'], MergeController::OFFICE_EXTENSIONS)) {
+            unlink($pathToDocument);
+            AdrModel::deleteDocumentAdr(['where' => ['res_id = ?', 'type = ?'], 'data' => [$args['resId'], 'TMP']]);
+        }
+
         $storeResult = DocserverController::storeResourceOnDocServer([
             'collId'            => 'letterbox_coll',
             'docserverTypeId'   => 'DOC',
@@ -550,7 +571,7 @@ class SignatureBookController
             return $response->withStatus(400)->withJson(['errors' => 'Route id is not an integer']);
         }
 
-        $attachment = AttachmentModel::getById(['id' => $args['id'], 'select' => ['res_id_master', 'title', 'typist', 'identifier', 'recipient_id', 'recipient_type']]);
+        $attachment = AttachmentModel::getById(['id' => $args['id'], 'select' => ['res_id_master', 'title', 'typist', 'identifier', 'recipient_id', 'recipient_type', 'format']]);
         if (empty($attachment)) {
             return $response->withStatus(403)->withJson(['errors' => 'Attachment out of perimeter']);
         } elseif (!SignatureBookController::isResourceInSignatureBook(['resId' => $attachment['res_id_master'], 'userId' => $GLOBALS['id']])) {
@@ -580,11 +601,24 @@ class SignatureBookController
             return $response->withStatus(404)->withJson(['errors' => 'Signature not found on docserver']);
         }
 
-        $convertedDocument = AdrModel::getAttachments([
-            'select'    => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
-            'where'     => ['res_id = ?', 'type = ?'],
-            'data'      => [$args['id'], 'PDF']
-        ]);
+        if (in_array($attachment['format'], MergeController::OFFICE_EXTENSIONS)) {
+            $result = MergeController::mergeAction(['resId' => $args['id'], 'type' => 'attachment']);
+            if (!empty($result['errors'])) {
+                return $response->withStatus(400)->withJson(['errors' => $result['errors']]);
+            }
+            $convertedDocument = AdrModel::getAttachments([
+                'select' => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
+                'where'  => ['res_id = ?', 'type = ?'],
+                'data'   => [$args['id'], 'TMP']
+            ]);
+        } else {
+            $convertedDocument = AdrModel::getAttachments([
+                'select' => ['docserver_id', 'path', 'filename', 'type', 'fingerprint'],
+                'where'  => ['res_id = ?', 'type = ?'],
+                'data'   => [$args['id'], 'PDF']
+            ]);
+        }
+
         if (empty($convertedDocument[0])) {
             return $response->withStatus(400)->withJson(['errors' => 'Converted document does not exist']);
         }
@@ -619,6 +653,11 @@ class SignatureBookController
         }
         unlink($tmpPath.$convertedDocument['filename']);
 
+        if (in_array($attachment['format'], MergeController::OFFICE_EXTENSIONS)) {
+            unlink($pathToDocument);
+            AdrModel::deleteAttachmentAdr(['where' => ['res_id = ?', 'type = ?'], 'data' => [$args['id'], 'TMP']]);
+        }
+
         $data = [
             'title'                    => $attachment['title'],
             'encodedFile'              => base64_encode($signedDocument),