diff --git a/README.md b/README.md index a401d212..d1ad3c90 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ Version 2.0. See the file "[LICENSE](LICENSE)" for more information. ## Goal -FOLIO compatible title-level requests functionality. +FOLIO compatible title level requests functionality. ## Further information ### Issue tracker -Project [MODTLR](https://issues.folio.org/browse/MODTLR). \ No newline at end of file +Project [MODTLR](https://issues.folio.org/browse/MODTLR). diff --git a/descriptors/ModuleDescriptor-template.json b/descriptors/ModuleDescriptor-template.json index 94d6d14e..3607b834 100644 --- a/descriptors/ModuleDescriptor-template.json +++ b/descriptors/ModuleDescriptor-template.json @@ -19,6 +19,18 @@ "modulePermissions": [ "circulation.requests.item.post" ] + }, + { + "methods": ["PUT"], + "pathPattern": "/tlr/ecs-tlr/{requestId}", + "permissionsRequired": ["tlr.ecs-tlr.item.put"], + "modulePermissions": [] + }, + { + "methods": ["DELETE"], + "pathPattern": "/tlr/ecs-tlr/{requestId}", + "permissionsRequired": ["tlr.ecs-tlr.item.delete"], + "modulePermissions": [] } ] }, @@ -60,6 +72,16 @@ "permissionName": "tlr.ecs-tlr.post", "displayName": "ecs-tlr - create ECS TLR", "description": "Create ECS TLR" + }, + { + "permissionName": "tlr.ecs-tlr.put", + "displayName": "ecs-tlr - update ECS TLR", + "description": "Update ECS TLR" + }, + { + "permissionName": "tlr.ecs-tlr.delete", + "displayName": "ecs-tlr - remove ECS TLR", + "description": "Remove ECS TLR" } ], "requires": [], diff --git a/src/main/java/org/folio/controller/EcsTlrController.java b/src/main/java/org/folio/controller/EcsTlrController.java index 9fe5e947..800910e0 100644 --- a/src/main/java/org/folio/controller/EcsTlrController.java +++ b/src/main/java/org/folio/controller/EcsTlrController.java @@ -1,6 +1,8 @@ package org.folio.controller; import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.http.HttpStatus.OK; import java.util.UUID; @@ -8,6 +10,7 @@ import org.folio.domain.dto.EcsTlr; import org.folio.rest.resource.TlrApi; import org.folio.service.EcsTlrService; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; @@ -23,7 +26,7 @@ public class EcsTlrController implements TlrApi { @Override public ResponseEntity getEcsTlrById(UUID requestId) { - log.debug("getEcsTlrById:: parameters id: {}", requestId); + log.debug("getEcsTlrById:: parameters requestId: {}", requestId); return ecsTlrService.get(requestId) .map(ResponseEntity.status(OK)::body) @@ -32,8 +35,26 @@ public ResponseEntity getEcsTlrById(UUID requestId) { @Override public ResponseEntity postEcsTlr(EcsTlr ecsTlr) { - log.debug("postEcsTlr:: parameters ecsTlr: {}", ecsTlr); + log.debug("postEcsTlr:: parameters ecsTlr: {}", () -> ecsTlr); - return ResponseEntity.status(CREATED).body(ecsTlrService.post(ecsTlr)); + return ResponseEntity.status(CREATED).body(ecsTlrService.create(ecsTlr)); + } + + @Override + public ResponseEntity putEcsTlrById(UUID requestId, EcsTlr ecsTlr) { + log.debug("putEcsTlrById:: parameters requestId: {}, ecsTlr: {}", () -> requestId, () -> ecsTlr); + boolean requestUpdated = ecsTlrService.update(requestId, ecsTlr); + HttpStatus httpStatus = requestUpdated ? NO_CONTENT : NOT_FOUND; + + return ResponseEntity.status(httpStatus).build(); + } + + @Override + public ResponseEntity deleteEcsTlrById(UUID requestId) { + log.debug("deleteEcsTlrById:: parameters requestId: {}", requestId); + boolean requestDeleted = ecsTlrService.delete(requestId); + HttpStatus httpStatus = requestDeleted ? NO_CONTENT : NOT_FOUND; + + return ResponseEntity.status(httpStatus).build(); } } diff --git a/src/main/java/org/folio/service/EcsTlrService.java b/src/main/java/org/folio/service/EcsTlrService.java index 125f9930..c7c5dd83 100644 --- a/src/main/java/org/folio/service/EcsTlrService.java +++ b/src/main/java/org/folio/service/EcsTlrService.java @@ -7,6 +7,8 @@ public interface EcsTlrService { Optional get(UUID requestId); - EcsTlr post(EcsTlr ecsTlr); + EcsTlr create(EcsTlr ecsTlr); + boolean update(UUID requestId, EcsTlr ecsTlr); + boolean delete(UUID requestId); void updateRequestItem(UUID tlrRequestId, UUID itemId); } diff --git a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java index 2db6c012..b7a7068a 100644 --- a/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java +++ b/src/main/java/org/folio/service/impl/EcsTlrServiceImpl.java @@ -34,14 +34,36 @@ public Optional get(UUID id) { } @Override - public EcsTlr post(EcsTlr ecsTlr) { - log.debug("post:: parameters ecsTlr: {}", () -> ecsTlr); + public EcsTlr create(EcsTlr ecsTlr) { + log.debug("create:: parameters ecsTlr: {}", () -> ecsTlr); createRemoteRequest(ecsTlr, "university"); // TODO: replace with real tenantId return requestsMapper.mapEntityToDto(ecsTlrRepository.save( requestsMapper.mapDtoToEntity(ecsTlr))); } + @Override + public boolean update(UUID requestId, EcsTlr ecsTlr) { + log.debug("update:: parameters requestId: {}, ecsTlr: {}", () -> requestId, () -> ecsTlr); + + if (ecsTlrRepository.existsById(requestId)) { + ecsTlrRepository.save(requestsMapper.mapDtoToEntity(ecsTlr)); + return true; + } + return false; + } + + @Override + public boolean delete(UUID requestId) { + log.debug("delete:: parameters requestId: {}", () -> requestId); + + if (ecsTlrRepository.existsById(requestId)) { + ecsTlrRepository.deleteById(requestId); + return true; + } + return false; + } + @Override public void updateRequestItem(UUID tlrRequestId, UUID itemId) { log.debug("updateRequestItem:: parameters tlrRequestId: {}, itemId: {}", tlrRequestId, itemId); diff --git a/src/main/resources/swagger.api/ecs-tlr.yaml b/src/main/resources/swagger.api/ecs-tlr.yaml index 657e0354..3d5bf10b 100644 --- a/src/main/resources/swagger.api/ecs-tlr.yaml +++ b/src/main/resources/swagger.api/ecs-tlr.yaml @@ -32,12 +32,41 @@ paths: '400': $ref: '#/components/responses/badRequestResponse' '404': - description: Not found - content: - text/plain: - schema: - type: string - example: Not found + $ref: '#/components/responses/notFoundResponse' + '500': + $ref: '#/components/responses/internalServerErrorResponse' + put: + description: Update ECS TLR by ID + operationId: putEcsTlrById + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ecs-tlr" + required: true + parameters: + - $ref: '#/components/parameters/requestId' + responses: + '204': + description: Request successfully updated + '400': + $ref: '#/components/responses/badRequestResponse' + '404': + $ref: '#/components/responses/notFoundResponse' + '500': + $ref: '#/components/responses/internalServerErrorResponse' + delete: + description: Remove ECS TLR by ID + operationId: deleteEcsTlrById + parameters: + - $ref: '#/components/parameters/requestId' + responses: + '204': + description: Request successfully removed + '400': + $ref: '#/components/responses/badRequestResponse' + '404': + $ref: '#/components/responses/notFoundResponse' '500': $ref: '#/components/responses/internalServerErrorResponse' components: @@ -70,7 +99,16 @@ components: example: errors: - message: Request is invalid - code: invalid.request + total_records: 1 + schema: + $ref: "#/components/schemas/errorResponse" + notFoundResponse: + description: Not found + content: + application/json: + example: + errors: + - message: Request not found total_records: 1 schema: $ref: "#/components/schemas/errorResponse" @@ -81,7 +119,6 @@ components: example: errors: - message: Unexpected error - code: unexpected.error total_records: 1 schema: $ref: "#/components/schemas/errorResponse" diff --git a/src/main/resources/swagger.api/examples/EcsTlr.sample b/src/main/resources/swagger.api/examples/EcsTlr.sample new file mode 100644 index 00000000..61123530 --- /dev/null +++ b/src/main/resources/swagger.api/examples/EcsTlr.sample @@ -0,0 +1,12 @@ +{ + "id": "58e3b64b-c634-4afc-aba7-4d2a3ddef63d", + "instanceId": "2835ba05-fc4b-4ff2-972b-6ff7faaedd6e", + "requesterId": "4565999e-1994-4aab-9282-185731b4ce66", + "requestType": "Hold", + "requestLevel": "Title", + "requestExpirationDate": "2024-01-01T23:11:00+00:00", + "requestDate": "2024-01-01T00:12:00+00:00" + "patronComments": "test comment", + "fulfillmentPreference": "Hold Shelf", + "pickupServicePointId": "71ff4b72-70a0-40f6-9f73-6db29ced80a3" +} diff --git a/src/main/resources/swagger.api/schemas/EcsTlr.yaml b/src/main/resources/swagger.api/schemas/EcsTlr.yaml index 3405bf5e..78b52440 100644 --- a/src/main/resources/swagger.api/schemas/EcsTlr.yaml +++ b/src/main/resources/swagger.api/schemas/EcsTlr.yaml @@ -1,5 +1,5 @@ EcsTlr: - description: ECS TLR - title-level requests in a multi-tenant environment with Сonsortia support enabled + description: ECS TLR - title level requests in a multi-tenant environment with Сonsortia support enabled type: "object" properties: id: diff --git a/src/test/java/org/folio/controller/EcsTlrControllerTest.java b/src/test/java/org/folio/controller/EcsTlrControllerTest.java index 5d99b86e..e85fe1e8 100644 --- a/src/test/java/org/folio/controller/EcsTlrControllerTest.java +++ b/src/test/java/org/folio/controller/EcsTlrControllerTest.java @@ -5,8 +5,11 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.http.HttpStatus.CREATED; +import static org.springframework.http.HttpStatus.NOT_FOUND; +import static org.springframework.http.HttpStatus.NO_CONTENT; import java.util.Optional; +import java.util.UUID; import org.folio.domain.dto.EcsTlr; import org.folio.service.EcsTlrService; @@ -43,11 +46,43 @@ void getById() { @Test void ecsTlrShouldSuccessfullyBeCreated() { var mockRequest = new EcsTlr(); - when(requestsService.post(any(EcsTlr.class))).thenReturn(mockRequest); + when(requestsService.create(any(EcsTlr.class))).thenReturn(mockRequest); var response = requestsController.postEcsTlr(new EcsTlr()); assertEquals(CREATED, response.getStatusCode()); assertEquals(mockRequest, response.getBody()); } + + @Test + void ecsTlrShouldSuccessfullyBeUpdated() { + var id = UUID.randomUUID(); + var mockRequest = new EcsTlr(); + mockRequest.setId(id.toString()); + when(requestsService.update(any(UUID.class), any(EcsTlr.class))).thenReturn(true); + + var response = requestsController.putEcsTlrById(id, mockRequest); + assertEquals(NO_CONTENT, response.getStatusCode()); + } + + @Test + void ecsTlrShouldSuccessfullyBeDeleted() { + when(requestsService.delete(any(UUID.class))).thenReturn(true); + assertEquals(NO_CONTENT, requestsController.deleteEcsTlrById(UUID.randomUUID()).getStatusCode()); + } + + @Test + void ecsTlrShouldNotBeFound() { + var id = UUID.randomUUID(); + var mockRequest = new EcsTlr(); + mockRequest.setId(UUID.randomUUID().toString()); + + when(requestsService.update(any(UUID.class), any(EcsTlr.class))).thenReturn(false); + var putResponse = requestsController.putEcsTlrById(id, mockRequest); + assertEquals(NOT_FOUND, putResponse.getStatusCode()); + + when(requestsService.delete(any(UUID.class))).thenReturn(false); + var deleteResponse = requestsController.deleteEcsTlrById(id); + assertEquals(NOT_FOUND, deleteResponse.getStatusCode()); + } } diff --git a/src/test/java/org/folio/service/EcsTlrServiceTest.java b/src/test/java/org/folio/service/EcsTlrServiceTest.java index f2904003..395f724e 100644 --- a/src/test/java/org/folio/service/EcsTlrServiceTest.java +++ b/src/test/java/org/folio/service/EcsTlrServiceTest.java @@ -1,10 +1,13 @@ package org.folio.service; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.Optional; import java.util.UUID; import org.folio.domain.dto.EcsTlr; @@ -41,7 +44,7 @@ void getById() { } @Test - void postEcsTlr() { + void ecsTlrShouldBeCreatedThenUpdatedAndDeleted() { var id = UUID.randomUUID(); var instanceId = UUID.randomUUID(); var requesterId = UUID.randomUUID(); @@ -80,7 +83,7 @@ void postEcsTlr() { when(ecsTlrRepository.save(any(EcsTlrEntity.class))).thenReturn(mockEcsTlrEntity); when(tenantScopedExecutionService.execute(any(String.class), any())) .thenReturn(new Request().id(UUID.randomUUID().toString())); - var postEcsTlr = ecsTlrService.post(ecsTlr); + var postEcsTlr = ecsTlrService.create(ecsTlr); assertEquals(id.toString(), postEcsTlr.getId()); assertEquals(instanceId.toString(), postEcsTlr.getInstanceId()); @@ -91,5 +94,13 @@ void postEcsTlr() { assertEquals(patronComments, postEcsTlr.getPatronComments()); assertEquals(fulfillmentPreference, postEcsTlr.getFulfillmentPreference()); assertEquals(pickupServicePointId.toString(), postEcsTlr.getPickupServicePointId()); + + when(ecsTlrRepository.existsById(any(UUID.class))).thenReturn(true); + assertTrue(ecsTlrService.update(id, ecsTlr)); + assertTrue(ecsTlrService.delete(id)); + + when(ecsTlrRepository.existsById(any(UUID.class))).thenReturn(false); + assertFalse(ecsTlrService.update(id, ecsTlr)); + assertFalse(ecsTlrService.delete(id)); } }