diff --git a/apps/maarch_entreprise/xml/entreprise.xml b/apps/maarch_entreprise/xml/entreprise.xml index 453d952a0fb527941913ab88a960600f63ef2680..35312670c260c6cbbd1615a9a43092e70a1bfa66 100755 --- a/apps/maarch_entreprise/xml/entreprise.xml +++ b/apps/maarch_entreprise/xml/entreprise.xml @@ -37,6 +37,14 @@ <id>summary_sheet</id> <label>_SUMMARY_SHEET</label> </type> + <type show="false" with_chrono="true" icon="" sign="false"> + <id>acknowledgement_record_management</id> + <label>_ACKNOWLEDGEMENT_RECORD_MANAGEMENT</label> + </type> + <type show="false" with_chrono="true" icon="" sign="false"> + <id>reply_record_management</id> + <label>_REPLY_RECORD_MANAGEMENT</label> + </type> </attachment_types> <contact_check> <check_days_before>5</check_days_before> <!-- 0 if you want to disabled --> diff --git a/rest/index.php b/rest/index.php index 6e21142eb868995f51a3ba01e53ce1deeea0453f..4b5498a1379ccc5542073ad12ce39a12bc0e1ba2 100755 --- a/rest/index.php +++ b/rest/index.php @@ -455,6 +455,8 @@ $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/ac $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions/{actionId}/checkReconcile', \Action\controllers\PreProcessActionController::class . ':checkReconcile'); $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions/{actionId}/checkSendAlfresco', \Action\controllers\PreProcessActionController::class . ':checkSendAlfresco'); $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions/{actionId}/checkPrintDepositList', \Action\controllers\PreProcessActionController::class . ':checkPrintDepositList'); +$app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/checkAcknowledgementRecordManagement', \Action\controllers\PreProcessActionController::class . ':checkAcknowledgementRecordManagement'); +$app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/checkReplyRecordManagement', \Action\controllers\PreProcessActionController::class . ':checkReplyRecordManagement'); //Search $app->post('/search', \Search\controllers\SearchController::class . ':get'); diff --git a/src/app/action/controllers/PreProcessActionController.php b/src/app/action/controllers/PreProcessActionController.php index 17a4b8f72e13402d7040fe1e0b03b40812a7e5b2..2a272d9b8991ddf7234964117a2b841d3cf412fc 100755 --- a/src/app/action/controllers/PreProcessActionController.php +++ b/src/app/action/controllers/PreProcessActionController.php @@ -50,9 +50,12 @@ use SrcCore\models\ValidatorModel; use Template\models\TemplateModel; use User\models\UserEntityModel; use User\models\UserModel; +use ExportSeda\controllers\PreProcessActionSEDATrait; class PreProcessActionController { + use PreProcessActionSEDATrait; + public static function getRedirectInformations(Request $request, Response $response, array $args) { $errors = ResourceListController::listControl(['groupId' => $args['groupId'], 'userId' => $args['userId'], 'basketId' => $args['basketId'], 'currentUserId' => $GLOBALS['id']]); diff --git a/src/app/external/exportSeda/controllers/PreProcessActionSEDATrait.php b/src/app/external/exportSeda/controllers/PreProcessActionSEDATrait.php new file mode 100644 index 0000000000000000000000000000000000000000..e3ada08628d5aaf1fab85573994898b18ced1f36 --- /dev/null +++ b/src/app/external/exportSeda/controllers/PreProcessActionSEDATrait.php @@ -0,0 +1,201 @@ +<?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 PreProcessActionSEDATrait +* @author dev <dev@maarch.org> +* @ingroup core +*/ + +namespace ExportSeda\controllers; + +use Respect\Validation\Validator; +use Action\controllers\PreProcessActionController; +use Attachment\models\AttachmentModel; +use Docserver\models\DocserverModel; +use Docserver\models\DocserverTypeModel; +use MessageExchange\models\MessageExchangeModel; +use Resource\controllers\ResController; +use Resource\controllers\ResourceListController; +use Resource\controllers\StoreController; +use Resource\models\ResModel; +use Slim\Http\Request; +use Slim\Http\Response; + +trait PreProcessActionSEDATrait +{ + public function checkAcknowledgementRecordManagement(Request $request, Response $response, array $args) + { + $body = $request->getParsedBody(); + + if (!Validator::arrayType()->notEmpty()->validate($body['resources'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body resources is empty or not an array']); + } + + $errors = ResourceListController::listControl(['groupId' => $args['groupId'], 'userId' => $args['userId'], 'basketId' => $args['basketId'], 'currentUserId' => $GLOBALS['id']]); + if (!empty($errors['errors'])) { + return $response->withStatus($errors['code'])->withJson(['errors' => $errors['errors']]); + } + + $body['resources'] = array_slice($body['resources'], 0, 500); + if (!ResController::hasRightByResId(['resId' => $body['resources'], 'userId' => $GLOBALS['id']])) { + return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']); + } + + $resourcesInformations = ['success' => [], 'errors' => []]; + $body['resources'] = PreProcessActionController::getNonLockedResources(['resources' => $body['resources'], 'userId' => $GLOBALS['id']]); + + $attachments = AttachmentModel::get([ + 'select' => ['res_id_master', 'path', 'filename', 'docserver_id', 'fingerprint'], + 'where' => ['res_id_master in (?)', 'attachment_type = ?', 'status = ?'], + 'data' => [$body['resources'], 'acknowledgement_record_management', 'TRA'] + ]); + $resourcesAcknowledgement = array_column($attachments, null, 'res_id_master'); + $resIdAcknowledgement = array_column($attachments, 'res_id_master'); + + $resourceAltIdentifier = ResModel::get(['select' => ['alt_identifier', 'res_id'], 'where' => ['res_id in (?)'], 'data' => [$body['resources']]]); + $altIdentifiers = array_column($resourceAltIdentifier, 'alt_identifier', 'res_id'); + + foreach ($body['resources'] as $resId) { + if (!in_array($resId, $resIdAcknowledgement)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_noAcknowledgement']; + continue; + } + $acknowledgement = $resourcesAcknowledgement[$resId]; + + $docserver = DocserverModel::getByDocserverId(['docserverId' => $acknowledgement['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]); + if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'docserverDoesNotExists']; + continue; + } + + $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $acknowledgement['path']) . $acknowledgement['filename']; + if (!file_exists($pathToDocument)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'fileDoesNotExists']; + continue; + } + + $docserverType = DocserverTypeModel::getById(['id' => $docserver['docserver_type_id'], 'select' => ['fingerprint_mode']]); + $fingerprint = StoreController::getFingerPrint(['filePath' => $pathToDocument, 'mode' => $docserverType['fingerprint_mode']]); + if (empty($acknowledgement['fingerprint'])) { + AttachmentModel::update(['set' => ['fingerprint' => $fingerprint], 'where' => ['res_id = ?'], 'data' => [$args['resId']]]); + $acknowledgement['fingerprint'] = $fingerprint; + } + if (!empty($acknowledgement['fingerprint']) && $acknowledgement['fingerprint'] != $fingerprint) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'fingerprintsDoNotMatch']; + continue; + } + + $acknowledgementXml = simplexml_load_file($pathToDocument); + if (empty($acknowledgementXml)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_acknowledgementNotReadable']; + continue; + } + + $messageExchange = MessageExchangeModel::getMessageByReference(['select' => ['message_id'], 'reference' => (string)$acknowledgementXml->MessageReceivedIdentifier]); + if (empty($messageExchange)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_noAcknowledgementReference']; + continue; + } + + $unitIdentifier = MessageExchangeModel::getUnitIdentifierByResId(['select' => ['message_id'], 'resId' => $resId]); + if ($unitIdentifier['message_id'] != $messageExchange['message_id']) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_wrongAcknowledgement']; + continue; + } + + $resourcesInformation['success'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId]; + } + + return $response->withJson(['resourcesInformations' => $resourcesInformations]); + } + + public function checkReplyRecordManagement(Request $request, Response $response, array $args) + { + $body = $request->getParsedBody(); + + if (!Validator::arrayType()->notEmpty()->validate($body['resources'])) { + return $response->withStatus(400)->withJson(['errors' => 'Body resources is empty or not an array']); + } + + $errors = ResourceListController::listControl(['groupId' => $args['groupId'], 'userId' => $args['userId'], 'basketId' => $args['basketId'], 'currentUserId' => $GLOBALS['id']]); + if (!empty($errors['errors'])) { + return $response->withStatus($errors['code'])->withJson(['errors' => $errors['errors']]); + } + + $body['resources'] = array_slice($body['resources'], 0, 500); + if (!ResController::hasRightByResId(['resId' => $body['resources'], 'userId' => $GLOBALS['id']])) { + return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']); + } + + $resourcesInformations = ['success' => [], 'errors' => []]; + $body['resources'] = PreProcessActionController::getNonLockedResources(['resources' => $body['resources'], 'userId' => $GLOBALS['id']]); + + $attachments = AttachmentModel::get([ + 'select' => ['res_id_master', 'path', 'filename', 'docserver_id', 'fingerprint'], + 'where' => ['res_id_master in (?)', 'attachment_type = ?', 'status = ?'], + 'data' => [$body['resources'], 'reply_record_management', 'TRA'] + ]); + $resourcesReply = array_column($attachments, null, 'res_id_master'); + $resIdReply = array_column($attachments, 'res_id_master'); + + $resourceAltIdentifier = ResModel::get(['select' => ['alt_identifier', 'res_id'], 'where' => ['res_id in (?)'], 'data' => [$body['resources']]]); + $altIdentifiers = array_column($resourceAltIdentifier, 'alt_identifier', 'res_id'); + + foreach ($body['resources'] as $resId) { + if (!in_array($resId, $resIdReply)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_noReply']; + continue; + } + $reply = $resourcesReply[$resId]; + + $docserver = DocserverModel::getByDocserverId(['docserverId' => $reply['docserver_id'], 'select' => ['path_template', 'docserver_type_id']]); + if (empty($docserver['path_template']) || !file_exists($docserver['path_template'])) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'docserverDoesNotExists']; + continue; + } + + $pathToDocument = $docserver['path_template'] . str_replace('#', DIRECTORY_SEPARATOR, $reply['path']) . $reply['filename']; + if (!file_exists($pathToDocument)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'fileDoesNotExists']; + continue; + } + + $docserverType = DocserverTypeModel::getById(['id' => $docserver['docserver_type_id'], 'select' => ['fingerprint_mode']]); + $fingerprint = StoreController::getFingerPrint(['filePath' => $pathToDocument, 'mode' => $docserverType['fingerprint_mode']]); + if (empty($reply['fingerprint'])) { + AttachmentModel::update(['set' => ['fingerprint' => $fingerprint], 'where' => ['res_id = ?'], 'data' => [$args['resId']]]); + $reply['fingerprint'] = $fingerprint; + } + if (!empty($reply['fingerprint']) && $reply['fingerprint'] != $fingerprint) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'fingerprintsDoNotMatch']; + continue; + } + + $replyXml = simplexml_load_file($pathToDocument); + if (empty($replyXml)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_replyNotReadable']; + continue; + } + + $messageExchange = MessageExchangeModel::getMessageByReference(['select' => ['message_id'], 'reference' => (string)$replyXml->MessageRequestIdentifier]); + if (empty($messageExchange)) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_noReplyReference']; + continue; + } + + $unitIdentifier = MessageExchangeModel::getUnitIdentifierByResId(['select' => ['message_id'], 'resId' => $resId]); + if ($unitIdentifier['message_id'] != $messageExchange['message_id']) { + $resourcesInformations['errors'][] = ['alt_identifier' => $altIdentifiers[$resId], 'res_id' => $resId, 'reason' => 'recordManagement_wrongReply']; + continue; + } + + $resourcesInformation['success'][] = ['alt_identifier' => $altIdentifiers[$resId]['alt_identifier'], 'res_id' => $resId]; + } + + return $response->withJson(['resourcesInformations' => $resourcesInformations]); + } +} diff --git a/src/app/external/messageExchange/models/MessageExchangeModelAbstract.php b/src/app/external/messageExchange/models/MessageExchangeModelAbstract.php index a740b3679c1b7bb0b595257ec34e90a46c3a23ab..e1a1b2ea9be34eba36d27a0ca5a8322ce9aede18 100755 --- a/src/app/external/messageExchange/models/MessageExchangeModelAbstract.php +++ b/src/app/external/messageExchange/models/MessageExchangeModelAbstract.php @@ -288,6 +288,21 @@ abstract class MessageExchangeModelAbstract return $messages; } + public static function getUnitIdentifierByResId(array $args) + { + ValidatorModel::notEmpty($args, ['resId']); + ValidatorModel::stringType($args, ['resId']); + + $messages = DatabaseModel::select([ + 'select' => empty($args['select']) ? ['*'] : $args['select'], + 'table' => ['unit_identifier'], + 'where' => ['res_id = ?'], + 'data' => [$args['resId']] + ]); + + return $messages; + } + public static function insertUnitIdentifier(array $args) { ValidatorModel::notEmpty($args, ['messageId', 'tableName', 'resId', 'disposition']); diff --git a/src/frontend/app/actions/check-acknowledgment-record-management-action/check-acknowledgment-record-management.component.ts b/src/frontend/app/actions/check-acknowledgment-record-management-action/check-acknowledgment-record-management.component.ts index 0033a9caad13751c0ca3cd8039fa2d0db9e5aedc..2c82cc1421c27f848e97f7a852bae45ca561ac3d 100644 --- a/src/frontend/app/actions/check-acknowledgment-record-management-action/check-acknowledgment-record-management.component.ts +++ b/src/frontend/app/actions/check-acknowledgment-record-management-action/check-acknowledgment-record-management.component.ts @@ -32,23 +32,16 @@ export class CheckAcknowledgmentRecordManagementComponent implements OnInit { ) { } ngOnInit(): void { - // this.checkReply(); - - // FOR TEST - setTimeout(() => { - this.checking = false; - this.selectedRes = this.data.resIds; - }, 2000); + this.checkAcknowledgement(); } - checkReply() { - this.http.post(`../rest/resourcesList/users/${this.data.userId}/groups/${this.data.groupId}/baskets/${this.data.basketId}/actions/${this.data.action.id}/checkCloseWithFieldsAction`, { resources: this.data.resIds }).pipe( + checkAcknowledgement() { + this.http.post(`../rest/resourcesList/users/${this.data.userId}/groups/${this.data.groupId}/baskets/${this.data.basketId}/checkAcknowledgementRecordManagement`, { resources: this.data.resIds }).pipe( tap((data: any) => { - // TO DO - this.resourcesErrors = data.errors; - this.selectedRes = data.success; + this.resourcesErrors = data.resourcesInformations.errors; + this.selectedRes = data.resourcesInformations.success; }), - finalize(() => this.loading = false), + finalize(() => this.checking = false), catchError((err: any) => { this.notify.handleSoftErrors(err); return of(false); @@ -58,12 +51,7 @@ export class CheckAcknowledgmentRecordManagementComponent implements OnInit { onSubmit() { this.loading = true; - // this.executeAction(); - - // FOR TEST - setTimeout(() => { - this.loading = false; - }, 3000); + this.executeAction(); } executeAction() { diff --git a/src/frontend/app/actions/check-reply-record-management-action/check-reply-record-management.component.ts b/src/frontend/app/actions/check-reply-record-management-action/check-reply-record-management.component.ts index 0fa4d1541e02fcbac9b3626afbfba3e81f847f91..6e4312c97a1e48c2b8b5e816d0da9bad03f20130 100644 --- a/src/frontend/app/actions/check-reply-record-management-action/check-reply-record-management.component.ts +++ b/src/frontend/app/actions/check-reply-record-management-action/check-reply-record-management.component.ts @@ -32,23 +32,16 @@ export class CheckReplyRecordManagementComponent implements OnInit { ) { } ngOnInit(): void { - // this.checkReply(); - - // FOR TEST - setTimeout(() => { - this.checking = false; - this.selectedRes = this.data.resIds; - }, 2000); + this.checkReply(); } checkReply() { - this.http.post(`../rest/resourcesList/users/${this.data.userId}/groups/${this.data.groupId}/baskets/${this.data.basketId}/actions/${this.data.action.id}/checkCloseWithFieldsAction`, { resources: this.data.resIds }).pipe( + this.http.post(`../rest/resourcesList/users/${this.data.userId}/groups/${this.data.groupId}/baskets/${this.data.basketId}/checkReplyRecordManagement`, { resources: this.data.resIds }).pipe( tap((data: any) => { - // TO DO - this.resourcesErrors = data.errors; - this.selectedRes = data.success; + this.resourcesErrors = data.resourcesInformations.errors; + this.selectedRes = data.resourcesInformations.success; }), - finalize(() => this.loading = false), + finalize(() => this.checking = false), catchError((err: any) => { this.notify.handleSoftErrors(err); return of(false); @@ -58,12 +51,7 @@ export class CheckReplyRecordManagementComponent implements OnInit { onSubmit() { this.loading = true; - // this.executeAction(); - - // FOR TEST - setTimeout(() => { - this.loading = false; - }, 3000); + this.executeAction(); } executeAction() { 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 index b9dca73169c9f1d134edea285c64357671981502..7c9217fb793584c1c448e69873f865a03271dbb3 100644 --- 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 @@ -13,7 +13,6 @@ import { of } from 'rxjs'; }) export class SendExternalNoteBookActionComponent implements OnInit { - loading: boolean = false; additionalsInfos: any = { users: [], diff --git a/src/lang/lang-fr.json b/src/lang/lang-fr.json index 41cbbb75438d1f83073631dd6b8802cd6e6f3bab..2edd78a724ec2452f7475a14b342e725a634b308 100644 --- a/src/lang/lang-fr.json +++ b/src/lang/lang-fr.json @@ -2070,6 +2070,14 @@ "checkReplyRecordManagementDesc": "Vérifie les <b>réponses</b> des paquets qui ont été transférés au <b>système d'archivage électronique</b>.", "checkAcknowledgmentRecordManagementDesc": "Vérifie si le <b>système d'archivage électronique</b> a bien reçu les <b>paquets</b>.", "checkInProgress": "Vérification en cours", + "recordManagement_noAcknowledgement": "Aucun accusé de réception trouvé pour ce courrier", + "recordManagement_acknowledgementNotReadable": "L'accusé de réception de ce courrier n'est pas correctement structuré", + "recordManagement_noAcknowledgementReference": "Aucun accusé de réception trouvé avec la référence de ce courrier", + "recordManagement_wrongAcknowledgement": "L'accusé de réception n'est pas lié au bon courrier", + "recordManagement_noReply": "Aucune réponse de transfert trouvé pour ce courrier", + "recordManagement_replyNotReadable": "La réponse de transfert de ce courrier n'est pas correctement structurée", + "recordManagement_noReplyReference": "Aucun bordereau correspond à la réponse de transfert", + "recordManagement_wrongReply": "La réponse de transfert n'est pas lié au bon courrier", "nextPage": "Page suivante", "prevPage": "Page précédente" }