diff --git a/src/app/attachment/controllers/AttachmentController.php b/src/app/attachment/controllers/AttachmentController.php
index 71c9dea5c14032ddfd72b07853c96a0f54ceeaff..8ee19a4eb5f55a1ec3e0dc90ac48c02fcfbd6d62 100755
--- a/src/app/attachment/controllers/AttachmentController.php
+++ b/src/app/attachment/controllers/AttachmentController.php
@@ -44,84 +44,35 @@ class AttachmentController
     {
         $body = $request->getParsedBody();
 
-        if (empty($body)) {
-            return $response->withStatus(400)->withJson(['errors' => 'Body is not set or empty']);
-        } elseif (!Validator::notEmpty()->validate($body['encodedFile'])) {
-            return $response->withStatus(400)->withJson(['errors' => 'Body encodedFile is empty']);
-        } elseif (!Validator::stringType()->notEmpty()->validate($body['format'])) {
-            return $response->withStatus(400)->withJson(['errors' => 'Body format is empty or not a string']);
-        }
-
-        $attachmentsTypes = AttachmentModel::getAttachmentsTypesByXML();
-        $generateChrono = false;
-        $mandatoryColumns = ['res_id_master', 'attachment_type'];
-        foreach ($body['data'] as $key => $value) {
-            foreach ($mandatoryColumns as $columnKey => $column) {
-                if ($column == $value['column'] && !empty($value['value'])) {
-                    if ($column == 'res_id_master') {
-                        if (!ResController::hasRightByResId(['resId' => [$value['value']], 'userId' => $GLOBALS['id']])) {
-                            return $response->withStatus(403)->withJson(['errors' => 'ResId master out of perimeter']);
-                        }
-                        $resId = $value['value'];
-                    } elseif ($column == 'attachment_type') {
-                        if (empty($attachmentsTypes[$value['value']])) {
-                            return $response->withStatus(400)->withJson(['errors' => 'Attachment Type does not exist']);
-                        } elseif ($attachmentsTypes[$value['value']]['chrono']) {
-                            $generateChrono = true;
-                        }
-                    }
-                    unset($mandatoryColumns[$columnKey]);
-                }
-            }
-            if (in_array($value['column'], ['identifier'])) {
-                unset($body['data'][$key]);
-            }
-        }
-        if (!empty($mandatoryColumns)) {
-            return $response->withStatus(400)->withJson(['errors' => 'Body data array needs column(s) [' . implode(', ', $mandatoryColumns) . ']']);
-        } elseif (empty($resId)) {
-            return $response->withStatus(400)->withJson(['errors' => 'ResId master is missing']);
-        }
-
-        if ($generateChrono) {
-            $resource = ResModel::getById(['select' => ['destination', 'type_id'], 'resId' => $resId]);
-            $chrono = ChronoModel::getChrono(['id' => 'outgoing', 'entityId' => $resource['destination'], 'typeId' => $resource['type_id'], 'resId' => $resId]);
-            $body['data'][] = ['column' => 'identifier', 'value' => $chrono];
+        $control = AttachmentController::controlAttachment(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return $response->withStatus(400)->withJson(['errors' => $control['errors']]);
         }
 
-        $body['status'] = 'A_TRA';
-        $body['collId'] = 'letterbox_coll';
-        $body['data'][] = ['column' => 'coll_id', 'value' => 'letterbox_coll'];
-        $body['data'][] = ['column' => 'type_id', 'value' => '0'];
-        $body['data'][] = ['column' => 'relation', 'value' => '1'];
-        $body['fileFormat'] = $body['format'];
-        $resId = StoreController::storeAttachment($body);
-
-        if (empty($resId) || !empty($resId['errors'])) {
-            return $response->withStatus(500)->withJson(['errors' => '[AttachmentController create] ' . $resId['errors']]);
+        $id = StoreController::storeAttachment($body);
+        if (empty($id) || !empty($id['errors'])) {
+            return $response->withStatus(500)->withJson(['errors' => '[AttachmentController create] ' . $id['errors']]);
         }
 
-        $collId = empty($body['version']) ? 'attachments_coll' : 'attachments_version_coll';
         ConvertPdfController::convert([
-            'resId'     => $resId,
-            'collId'    => $collId
+            'resId'     => $id,
+            'collId'    => 'attachments_coll'
         ]);
 
         $customId = CoreConfigModel::getCustomId();
         $customId = empty($customId) ? 'null' : $customId;
-        $user = UserModel::getByLogin(['select' => ['id'], 'login' => $GLOBALS['userId']]);
-        exec("php src/app/convert/scripts/FullTextScript.php --customId {$customId} --resId {$resId} --collId {$collId} --userId {$user['id']} > /dev/null &");
+        exec("php src/app/convert/scripts/FullTextScript.php --customId {$customId} --resId {$id} --collId attachments_coll --userId {$GLOBALS['id']} > /dev/null &");
 
         HistoryController::add([
             'tableName' => 'res_attachments',
-            'recordId'  => $resId,
+            'recordId'  => $id,
             'eventType' => 'ADD',
             'info'      => _DOC_ADDED,
             'moduleId'  => 'attachment',
             'eventId'   => 'attachmentAdd',
         ]);
 
-        return $response->withJson(['resId' => $resId]);
+        return $response->withJson(['id' => $id]);
     }
 
     public function getByResId(Request $request, Response $response, array $aArgs)
@@ -568,69 +519,6 @@ class AttachmentController
                 foreach ($contactsForMailing as $keyContact => $contactForMailing) {
                     $chronoPubli = $attachment['identifier'].'-'.($keyContact+1);
 
-                    $dataValue = [];
-
-                    $dataValue[] = [
-                        'column'    => 'coll_id',
-                        'value'     => 'letterbox_coll',
-                        'type'      => 'string'
-                    ];
-                    array_push($dataValue, [
-                        'column' => 'res_id_master',
-                        'value' => $aArgs['resIdMaster'],
-                        'type' => 'integer'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'attachment_type',
-                        'value' => $attachment['attachment_type'],
-                        'type' => 'string'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'identifier',
-                        'value' => $chronoPubli,
-                        'type' => 'string'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'title',
-                        'value' => $attachment['title'],
-                        'type' => 'string'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'type_id',
-                        'value' => $attachment['type_id'],
-                        'type' => 'integer'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'format',
-                        'value' => $attachment['format'],
-                        'type' => 'string'
-                    
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'typist',
-                        'value' => $attachment['typist'],
-                        'type' => 'string'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'relation',
-                        'value' => $attachment['relation'],
-                        'type' => 'integer'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'dest_contact_id',
-                        'value' => $contactForMailing['contact_id'],
-                        'type' => 'integer'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'dest_address_id',
-                        'value' => $contactForMailing['address_id'],
-                        'type' => 'integer'
-                    ]);
-                    array_push($dataValue, [
-                        'column' => 'in_signature_book',
-                        'value' => 'true',
-                    ]);
-
                     $params = [
                         'userId'           => $aArgs['userId'],
                         'res_id'           => $aArgs['resIdMaster'],
@@ -646,12 +534,13 @@ class AttachmentController
                     $filePathOnTmp = TemplateController::mergeDatasource($params);
 
                     $allDatas = [
-                        "encodedFile" => base64_encode(file_get_contents($filePathOnTmp)),
-                        "data"        => $dataValue,
-                        "collId"      => "letterbox_coll",
-                        "table"       => "res_attachments",
-                        "fileFormat"  => $attachment['format'],
-                        "status"      => 'A_TRA'
+                        "encodedFile"       => base64_encode(file_get_contents($filePathOnTmp)),
+                        "format"            => $attachment['format'],
+                        'resIdMaster'       => $aArgs['resIdMaster'],
+                        'type'              => $attachment['attachment_type'],
+                        'chrono'            => $chronoPubli,
+                        'title'             => $attachment['title'],
+                        'inSignatureBook'   => true,
                     ];
 
                     StoreController::storeAttachment($allDatas);
@@ -694,4 +583,93 @@ class AttachmentController
 
         return $return;
     }
+
+    private static function controlAttachment(array $args)
+    {
+        $body = $args['body'];
+
+        if (empty($body)) {
+            return ['errors' => 'Body is not set or empty'];
+        } elseif (!Validator::notEmpty()->validate($body['encodedFile'])) {
+            return ['errors' => 'Body encodedFile is empty'];
+        } elseif (!Validator::stringType()->notEmpty()->validate($body['format'])) {
+            return ['errors' => 'Body format is empty or not a string'];
+        } elseif (!Validator::intVal()->notEmpty()->validate($body['resIdMaster'])) {
+            return ['errors' => 'Body resIdMaster is empty or not an integer'];
+        } elseif (!Validator::stringType()->notEmpty()->validate($body['type'])) {
+            return ['errors' => 'Body type is empty or not a string'];
+        }
+
+        if (!ResController::hasRightByResId(['resId' => [$body['resIdMaster']], 'userId' => $GLOBALS['id']])) {
+            return ['errors' => 'Body resIdMaster is out of perimeter'];
+        }
+
+        $attachmentsTypes = AttachmentModel::getAttachmentsTypesByXML();
+        if (empty($attachmentsTypes[$body['type']])) {
+            return ['errors' => 'Body type does not exist'];
+        }
+
+        $control = AttachmentController::controlFileData(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        $control = AttachmentController::controlOrigin(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        $control = AttachmentController::controlDates(['body' => $body]);
+        if (!empty($control['errors'])) {
+            return ['errors' => $control['errors']];
+        }
+
+        return true;
+    }
+
+    private static function controlFileData(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['encodedFile'])) {
+            if (!Validator::stringType()->notEmpty()->validate($body['format'])) {
+                return ['errors' => 'Body format is empty or not a string'];
+            }
+
+            $file     = base64_decode($body['encodedFile']);
+            $finfo    = new \finfo(FILEINFO_MIME_TYPE);
+            $mimeType = $finfo->buffer($file);
+            if (!StoreController::isFileAllowed(['extension' => $body['format'], 'type' => $mimeType])) {
+                return ['errors' => "Format with this mimeType is not allowed : {$body['format']} {$mimeType}"];
+            }
+        }
+
+        return true;
+    }
+
+    private static function controlOrigin(array $args)
+    {
+        $body = $args['body'];
+
+        if (!empty($body['originId'])) {
+            if (!Validator::intVal()->notEmpty()->validate($body['originId'])) {
+                return ['errors' => 'Body originId is not an integer'];
+            }
+            $origin = AttachmentModel::getById(['id' => $body['originId'], 'select' => ['res_id_master']]);
+            if (empty($origin)) {
+                return ['errors' => 'Body originId does not exist'];
+            } elseif ($origin['res_id_master'] != $body['resIdMaster']) {
+                return ['errors' => 'Body resIdMaster is different from origin'];
+            }
+        }
+
+        return true;
+    }
+
+    private static function controlDates(array $args)
+    {
+        $body = $args['body'];
+
+        return true;
+    }
 }
diff --git a/src/app/attachment/models/AttachmentModelAbstract.php b/src/app/attachment/models/AttachmentModelAbstract.php
index b3790d7da553e9d4f8c1ad0a9ad94ed2d843d6ce..423b54ea38240e8aa2526754faffde37b4c42f9b 100755
--- a/src/app/attachment/models/AttachmentModelAbstract.php
+++ b/src/app/attachment/models/AttachmentModelAbstract.php
@@ -104,19 +104,16 @@ abstract class AttachmentModelAbstract
 
     public static function create(array $aArgs)
     {
-        ValidatorModel::notEmpty($aArgs, ['format', 'typist', 'creation_date', 'docserver_id', 'path', 'filename', 'fingerprint', 'filesize', 'status']);
+        ValidatorModel::notEmpty($aArgs, ['res_id', 'format', 'typist', 'creation_date', 'docserver_id', 'path', 'filename', 'fingerprint', 'filesize', 'status', 'relation']);
         ValidatorModel::stringType($aArgs, ['format', 'typist', 'creation_date', 'docserver_id', 'path', 'filename', 'fingerprint', 'status']);
-        ValidatorModel::intVal($aArgs, ['filesize']);
-
-        $nextSequenceId = DatabaseModel::getNextSequenceValue(['sequenceId' => 'res_attachment_res_id_seq']);
-        $aArgs['res_id'] = $nextSequenceId;
+        ValidatorModel::intVal($aArgs, ['res_id', 'filesize', 'relation']);
 
         DatabaseModel::insert([
             'table'         => 'res_attachments',
             'columnsValues' => $aArgs
         ]);
 
-        return $nextSequenceId;
+        return true;
     }
 
     public static function update(array $aArgs)
@@ -136,7 +133,13 @@ abstract class AttachmentModelAbstract
 
     public static function getAttachmentsTypesByXML()
     {
-        $attachmentTypes = [];
+        static $types;
+
+        if (!empty($types)) {
+            return $types;
+        }
+
+        $types = [];
 
         $loadedXml = CoreConfigModel::getXmlLoaded(['path' => 'apps/maarch_entreprise/xml/entreprise.xml']);
         if ($loadedXml) {
@@ -144,7 +147,7 @@ abstract class AttachmentModelAbstract
             if (count($attachmentTypesXML) > 0) {
                 foreach ($attachmentTypesXML->type as $value) {
                     $label = defined((string) $value->label) ? constant((string) $value->label) : (string) $value->label;
-                    $attachmentTypes[(string) $value->id] = [
+                    $types[(string) $value->id] = [
                         'label'     => $label,
                         'icon'      => (string)$value['icon'],
                         'sign'      => (empty($value['sign']) || (string)$value['sign'] == 'true') ? true : false,
@@ -155,7 +158,7 @@ abstract class AttachmentModelAbstract
             }
         }
 
-        return $attachmentTypes;
+        return $types;
     }
 
     public static function unsignAttachment(array $aArgs)
diff --git a/src/app/resource/controllers/ResController.php b/src/app/resource/controllers/ResController.php
index a8d4b4374e976fa66f98b01c9cd67e719b95e56f..86774bddebb672cf0ea1ae7a3908136a297a967f 100755
--- a/src/app/resource/controllers/ResController.php
+++ b/src/app/resource/controllers/ResController.php
@@ -91,7 +91,7 @@ class ResController
 
             $customId = CoreConfigModel::getCustomId();
             $customId = empty($customId) ? 'null' : $customId;
-            exec("php src/app/convert/scripts/FullTextScript.php --customId {$customId} --resId {$resId} --collId 'letterbox_coll' --userId {$GLOBALS['id']} > /dev/null &");
+            exec("php src/app/convert/scripts/FullTextScript.php --customId {$customId} --resId {$resId} --collId letterbox_coll --userId {$GLOBALS['id']} > /dev/null &");
         }
 
         HistoryController::add([
diff --git a/src/app/resource/controllers/StoreController.php b/src/app/resource/controllers/StoreController.php
index 6e0411f1d8bd41145370af6dceace0b6c28904f3..954d49c7f8bd88293e752ea2e20457377266dd81 100755
--- a/src/app/resource/controllers/StoreController.php
+++ b/src/app/resource/controllers/StoreController.php
@@ -24,6 +24,7 @@ use SrcCore\models\DatabaseModel;
 use SrcCore\models\ValidatorModel;
 use Resource\models\ResModel;
 use SrcCore\models\CoreConfigModel;
+use User\models\UserModel;
 
 class StoreController
 {
@@ -68,40 +69,43 @@ class StoreController
         }
     }
 
-    public static function storeAttachment(array $aArgs)
+    public static function storeAttachment(array $args)
     {
-        ValidatorModel::notEmpty($aArgs, ['encodedFile', 'data', 'fileFormat', 'status']);
-        ValidatorModel::stringType($aArgs, ['collId', 'fileFormat', 'status']);
+        ValidatorModel::notEmpty($args, ['encodedFile', 'format']);
+        ValidatorModel::stringType($args, ['format']);
 
         try {
-            $fileContent    = base64_decode(str_replace(['-', '_'], ['+', '/'], $aArgs['encodedFile']));
+            $id = DatabaseModel::getNextSequenceValue(['sequenceId' => 'res_attachment_res_id_seq']);
+
+            $fileContent    = base64_decode(str_replace(['-', '_'], ['+', '/'], $args['encodedFile']));
 
             $storeResult = DocserverController::storeResourceOnDocServer([
                 'collId'            => 'attachments_coll',
                 'docserverTypeId'   => 'DOC',
                 'encodedResource'   => base64_encode($fileContent),
-                'format'            => $aArgs['fileFormat']
+                'format'            => $args['format']
             ]);
             if (!empty($storeResult['errors'])) {
-                return ['errors' => '[storeResource] ' . $storeResult['errors']];
+                return ['errors' => '[storeAttachment] ' . $storeResult['errors']];
             }
 
-            $data = StoreController::prepareAttachmentStorage([
-                'data'          => $aArgs['data'],
-                'docserverId'   => $storeResult['docserver_id'],
-                'status'        => $aArgs['status'],
-                'fileName'      => $storeResult['file_destination_name'],
-                'fileFormat'    => $aArgs['fileFormat'],
-                'fileSize'      => $storeResult['fileSize'],
-                'path'          => $storeResult['destination_dir'],
-                'fingerPrint'   => $storeResult['fingerPrint']
-            ]);
+            $data = [
+                'res_id'        => $id,
+                'docserver_id'  => $storeResult['docserver_id'],
+                'filename'      => $storeResult['file_destination_name'],
+                'filesize'      => $storeResult['fileSize'],
+                'path'          => $storeResult['directory'],
+                'fingerprint'   => $storeResult['fingerPrint']
+            ];
+
+            $data = array_merge($args, $data);
+            $data = StoreController::prepareAttachmentStorage($data);
 
-            $id = AttachmentModel::create($data);
+            AttachmentModel::create($data);
 
             return $id;
         } catch (\Exception $e) {
-            return ['errors' => '[storeResource] ' . $e->getMessage()];
+            return ['errors' => '[storeAttachment] ' . $e->getMessage()];
         }
     }
 
@@ -171,59 +175,52 @@ class StoreController
         return $preparedData;
     }
 
-    public static function prepareAttachmentStorage(array $aArgs)
+    public static function prepareAttachmentStorage(array $args)
     {
-        ValidatorModel::notEmpty($aArgs, ['data', 'docserverId', 'fileName', 'fileFormat', 'fileSize', 'path', 'fingerPrint']);
-        ValidatorModel::stringType($aArgs, ['docserverId', 'status', 'fileName', 'fileFormat', 'path', 'fingerPrint']);
-        ValidatorModel::arrayType($aArgs, ['data']);
-        ValidatorModel::intVal($aArgs, ['fileSize']);
+        ValidatorModel::notEmpty($args, ['res_id', 'docserver_id', 'filename', 'format', 'path', 'fingerprint']);
+        ValidatorModel::stringType($args, ['docserver_id', 'filename', 'format', 'path', 'fingerprint']);
+        ValidatorModel::intVal($args, ['res_id', 'filesize']);
 
-        foreach ($aArgs['data'] as $key => $value) {
-            $aArgs['data'][$key]['column'] = strtolower($value['column']);
+        $attachmentsTypes = AttachmentModel::getAttachmentsTypesByXML();
+        if ($attachmentsTypes[$args['type']]['chrono'] && empty($args['chrono'])) {
+            $resource = ResModel::getById(['select' => ['destination', 'type_id'], 'resId' => $args['resIdMaster']]);
+            $args['chrono'] = ChronoModel::getChrono(['id' => 'outgoing', 'entityId' => $resource['destination'], 'typeId' => $resource['type_id'], 'resId' => $args['resIdMaster']]);
         }
 
-        $aArgs['data'][] = [
-            'column'    => 'docserver_id',
-            'value'     => $aArgs['docserverId'],
-            'type'      => 'string'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'creation_date',
-            'value'     => 'CURRENT_TIMESTAMP',
-            'type'      => 'function'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'path',
-            'value'     => $aArgs['path'],
-            'type'      => 'string'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'fingerprint',
-            'value'     => $aArgs['fingerPrint'],
-            'type'      => 'string'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'filename',
-            'value'     => $aArgs['fileName'],
-            'type'      => 'string'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'format',
-            'value'     => $aArgs['fileFormat'],
-            'type'      => 'string'
-        ];
-        $aArgs['data'][] = [
-            'column'    => 'filesize',
-            'value'     => $aArgs['fileSize'],
-            'type'      => 'int'
-        ];
+        $relation = 1;
+        if (!empty($args['originId'])) {
+            $relations = AttachmentModel::get(['select' => ['relation'], 'where' => ['origin_id = ?'], 'data' => [$args['originId']], 'orderBy' => ['relation DESC'], 'limit' => 1]);
+            $relation = $relations[0]['relation'] ?? 2;
+            AttachmentModel::update(['set' => ['status' => 'OBS'], 'where' => ['(origin_id = ? OR res_id = ?)'], 'data' => [$args['originId'], $args['originId']]]);
+        }
 
-        $formatedData = [];
-        foreach ($aArgs['data'] as $value) {
-            $formatedData[$value['column']] = $value['value'];
+        $externalId = '{}';
+        if (!empty($args['externalId']) && is_array($args['externalId'])) {
+            $externalId = json_encode($args['externalId']);
         }
 
-        return $formatedData;
+        $preparedData = [
+            'res_id'                => $args['res_id'],
+            'title'                 => $args['title'] ?? null,
+            'identifier'            => $args['chrono'] ?? null,
+            'typist'                => $GLOBALS['userId'],
+            'status'                => 'A_TRA',
+            'relation'              => $relation,
+            'origin_id'             => $args['originId'] ?? null,
+            'res_id_master'         => $args['resIdMaster'],
+            'attachment_type'       => $args['type'],
+            'in_signature_book'     => empty($args['inSignatureBook']) ? 'false' : 'true',
+            'external_id'           => $externalId,
+            'format'                => $args['format'],
+            'docserver_id'          => $args['docserver_id'],
+            'filename'              => $args['filename'],
+            'filesize'              => $args['filesize'],
+            'path'                  => $args['path'],
+            'fingerprint'           => $args['fingerprint'],
+            'creation_date'         => 'CURRENT_TIMESTAMP'
+        ];
+
+        return $preparedData;
     }
 
     public static function getFingerPrint(array $aArgs)
diff --git a/src/app/resource/models/ResModelAbstract.php b/src/app/resource/models/ResModelAbstract.php
index fc176610751acaa7a0479da55ef315fac7ae7acf..27275d424f3a4a315d908827cf590f6ec6a1ab0e 100755
--- a/src/app/resource/models/ResModelAbstract.php
+++ b/src/app/resource/models/ResModelAbstract.php
@@ -79,7 +79,7 @@ abstract class ResModelAbstract
     public static function create(array $args)
     {
         ValidatorModel::notEmpty($args, ['res_id', 'model_id', 'category_id', 'typist', 'creation_date']);
-        ValidatorModel::stringType($args, ['category_id', 'creation_date', 'format', 'docserver_id', 'path', 'filename', 'fingerprint', ]);
+        ValidatorModel::stringType($args, ['category_id', 'creation_date', 'format', 'docserver_id', 'path', 'filename', 'fingerprint']);
         ValidatorModel::intVal($args, ['res_id', 'model_id', 'typist', 'filesize']);
 
         DatabaseModel::insert([