diff --git a/rest/index.php b/rest/index.php
index 75c4cc81caad0ad96393755976bc3df6bd2a1175..8ce0c9050654cb1cafb15779538e0e9e8038a4ed 100755
--- a/rest/index.php
+++ b/rest/index.php
@@ -264,6 +264,7 @@ $app->get('/resources/{resId}/isAllowed', \Resource\controllers\ResController::c
 $app->get('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}', \Resource\controllers\ResourceListController::class . ':get');
 $app->get('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/actions', \Resource\controllers\ResourceListController::class . ':getActions');
 $app->put('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/lock', \Resource\controllers\ResourceListController::class . ':lock');
+$app->put('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/unlock', \Resource\controllers\ResourceListController::class . ':unlock');
 $app->get('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/filters', \Resource\controllers\ResourceListController::class . ':getFilters');
 $app->put('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/exports', \Resource\controllers\ExportController::class . ':updateExport');
 $app->post('/resourcesList/users/{userId}/groups/{groupId}/baskets/{basketId}/summarySheets', \Resource\controllers\SummarySheetController::class . ':createList');
diff --git a/sql/develop.sql b/sql/develop.sql
index 0f521e13ac2d32ac29f25e669d449c79698eb140..52dccb984a8bf2b0e49d221d372f1cc98311d15a 100755
--- a/sql/develop.sql
+++ b/sql/develop.sql
@@ -12,9 +12,9 @@ DROP VIEW IF EXISTS res_view_letterbox;
 ALTER TABLE res_letterbox DROP COLUMN IF EXISTS external_signatory_book_id;
 ALTER TABLE res_letterbox ADD COLUMN external_signatory_book_id integer;
 
+/* Acknowledgment receipt */
 ALTER TABLE res_letterbox DROP COLUMN IF EXISTS acknowledgment_creation_date;
 ALTER TABLE res_letterbox ADD COLUMN acknowledgment_creation_date timestamp without time zone;
-
 ALTER TABLE res_letterbox DROP COLUMN IF EXISTS acknowledgment_send_date;
 ALTER TABLE res_letterbox ADD COLUMN acknowledgment_send_date timestamp without time zone;
 
diff --git a/src/app/resource/controllers/ResourceListController.php b/src/app/resource/controllers/ResourceListController.php
index f93ec597f384cdcc7e5108aff97198fbc67c375d..82e95865f0993ccafec8b2ed21c7335b0d199acd 100644
--- a/src/app/resource/controllers/ResourceListController.php
+++ b/src/app/resource/controllers/ResourceListController.php
@@ -582,6 +582,14 @@ class ResourceListController
             return $response->withStatus(400)->withJson(['errors' => 'Action is not linked to this group basket']);
         }
 
+        $action = ActionModel::getById(['id' => $aArgs['actionId'], 'select' => ['component']]);
+        if (empty($action['component'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Action component does not exist']);
+        }
+        if (!array_key_exists($action['component'], ActionMethodController::COMPONENTS_ACTIONS)) {
+            return $response->withStatus(400)->withJson(['errors' => 'Action method does not exist']);
+        }
+
         $user   = UserModel::getById(['id' => $aArgs['userId'], 'select' => ['user_id']]);
         $whereClause = PreparedClauseController::getPreparedClause(['clause' => $basket['basket_clause'], 'login' => $user['user_id']]);
         $resources = ResModel::getOnView([
@@ -600,6 +608,7 @@ class ResourceListController
             }
         }
 
+        $resourcesForAction = [];
         foreach ($resources as $resource) {
             $lock = true;
             if (empty($resource['locker_user_id'] || empty($resource['locker_time']))) {
@@ -609,28 +618,23 @@ class ResourceListController
             } elseif (strtotime($resource['locker_time']) < time()) {
                 $lock = false;
             }
-            if ($lock) {
-                return $response->withStatus(403)->withJson(['errors' => 'One of resources is lock']);
+            if (!$lock) {
+                $resourcesForAction[] = $resource['res_id'];
             }
         }
 
-        $action = ActionModel::getById(['id' => $aArgs['actionId'], 'select' => ['component']]);
-        if (empty($action['component'])) {
-            return $response->withStatus(400)->withJson(['errors' => 'Action component does not exist']);
-        }
-
-        if (!array_key_exists($action['component'], ActionMethodController::COMPONENTS_ACTIONS)) {
-            return $response->withStatus(400)->withJson(['errors' => 'Action method does not exist']);
+        if (empty($resourcesForAction)) {
+            return $response->withJson(['success' => 'No resource to process']);
         }
 
-        foreach ($body['resources'] as $resId) {
+        foreach ($resourcesForAction as $resId) {
             $method = ActionMethodController::COMPONENTS_ACTIONS[$action['component']];
 
             if (!empty($method)) {
                 ActionMethodController::$method(['id' => $aArgs['actionId'], 'resId' => $resId]);
             }
         }
-        ActionMethodController::terminateAction(['id' => $aArgs['actionId'], 'resources' => $body['resources'], 'basketName' => $basket['basket_name']]);
+        ActionMethodController::terminateAction(['id' => $aArgs['actionId'], 'resources' => $resourcesForAction, 'basketName' => $basket['basket_name']]);
 
         return $response->withStatus(204);
     }
@@ -699,6 +703,58 @@ class ResourceListController
         return $response->withJson(['lockedResources' => $locked]);
     }
 
+    public function unlock(Request $request, Response $response, array $aArgs)
+    {
+        $body = $request->getParsedBody();
+        if (!Validator::arrayType()->notEmpty()->validate($body['resources'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Data resources is empty or not an array']);
+        }
+        $body['resources'] = array_slice($body['resources'], 0, 500);
+
+        $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']]);
+        }
+
+        $basket = BasketModel::getById(['id' => $aArgs['basketId'], 'select' => ['basket_clause']]);
+        $user   = UserModel::getById(['id' => $aArgs['userId'], 'select' => ['user_id']]);
+
+        $whereClause = PreparedClauseController::getPreparedClause(['clause' => $basket['basket_clause'], 'login' => $user['user_id']]);
+        $resources = ResModel::getOnView([
+            'select'    => ['res_id', 'locker_user_id', 'locker_time'],
+            'where'     => [$whereClause, 'res_view_letterbox.res_id in (?)'],
+            'data'      => [$body['resources']]
+        ]);
+        $resourcesInBasket = [];
+        foreach ($resources as $resource) {
+            $resourcesInBasket[] = $resource['res_id'];
+        }
+
+        foreach ($body['resources'] as $resId) {
+            if (!in_array($resId, $resourcesInBasket)) {
+                return $response->withStatus(403)->withJson(['errors' => 'Resources out of perimeter']);
+            }
+        }
+
+        $resourcesToUnlock = [];
+        foreach ($resources as $resource) {
+            if (!(!empty($resource['locker_user_id']) && $resource['locker_user_id'] != $currentUser['id'] && strtotime($resource['locker_time']) > time())) {
+                $resourcesToUnlock[] = $resource['res_id'];
+            }
+        }
+
+        if (!empty($resourcesToUnlock)) {
+            ResModel::update([
+                'set'   => ['locker_user_id' => null, 'locker_time' => null],
+                'where' => ['res_id in (?)'],
+                'data'  => [$resourcesToUnlock]
+            ]);
+        }
+
+        return $response->withStatus(204);
+    }
+
     public static function listControl(array $aArgs)
     {
         ValidatorModel::notEmpty($aArgs, ['groupId', 'userId', 'basketId', 'currentUserId']);
diff --git a/test/unitTests/app/resource/ResourceListControllerTest.php b/test/unitTests/app/resource/ResourceListControllerTest.php
index 39adf5cb223ade341b64371177fed9791e4a0ed7..77585c3529777808788b5c5e957d5f72c9ac1e8b 100644
--- a/test/unitTests/app/resource/ResourceListControllerTest.php
+++ b/test/unitTests/app/resource/ResourceListControllerTest.php
@@ -174,4 +174,23 @@ class ResourceListControllerTest extends TestCase
 
         $GLOBALS['userId'] = 'superadmin';
     }
+
+    public function testGetActions()
+    {
+        $GLOBALS['userId'] = 'bbain';
+
+        $resListController = new \Resource\controllers\ResourceListController();
+
+        //  GET
+        $environment    = \Slim\Http\Environment::mock(['REQUEST_METHOD' => 'GET']);
+        $request        = \Slim\Http\Request::createFromEnvironment($environment);
+
+        $response     = $resListController->getActions($request, new \Slim\Http\Response(), ['userId' => 19, 'groupId' => 2, 'basketId' => 10]);
+        $responseBody = json_decode((string)$response->getBody());
+
+        $this->assertInternalType('array', $responseBody->actions);
+        $this->assertNotNull($responseBody->actions);
+
+        $GLOBALS['userId'] = 'superadmin';
+    }
 }