Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MODFIN-346] - Implement unrelease encumbrance endpoint #220

Merged
merged 6 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,16 @@
"finance-storage.transactions.item.put",
"finance-storage.order-transaction-summaries.item.put"
]
},
{
"method": ["POST"],
"pathPattern": "/finance/unrelease-encumbrance/{id}",
"permissionsRequired": ["finance.unrelease-encumbrance.item.post"],
SerhiiNosko marked this conversation as resolved.
Show resolved Hide resolved
"modulePermissions": [
"finance-storage.transactions.item.get",
"finance-storage.transactions.item.put",
"finance-storage.order-transaction-summaries.item.put"
]
}
]
},
Expand Down Expand Up @@ -1360,6 +1370,11 @@
"displayName" : "Release encumbrance",
"description" : "Release any remaining money encumbered back to the budget's available pool"
},
{
"permissionName" : "finance.unrelease-encumbrance.item.post",
"displayName" : "UnRelease encumbrance",
"description" : "Status of released encumbrance back to unreleased status"
imerabishvili marked this conversation as resolved.
Show resolved Hide resolved
},
{
"permissionName": "finance.group-fiscal-year-summaries.collection.get",
"displayName": "Finances - get group fiscal year summaries",
Expand Down
60 changes: 60 additions & 0 deletions ramls/unrelease-encumbrance.raml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#%RAML 1.0

title: Unreleased encumbrance
version: v1
protocols: [ HTTP, HTTPS ]
baseUri: https://github.com/folio-org/mod-finance

documentation:
- title: Unrelease encumbrance API
content: This documents the API calls that unrelease any remaining money encumbered back to the budget's available pool

types:
errors: !include raml-util/schemas/errors.schema
UUID:
type: string
pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$

traits:
validate: !include raml-util/traits/validation.raml

/finance/unrelease-encumbrance/{id}:
uriParameters:
id:
description: The UUID of an encumbrance
type: UUID
displayName: Finance unrelease encumbrance
description: Finance unrelease encumbrance APIs
post:
is: [validate]
description: Unrelease encumbrance
responses:
204:
description: "Encumbrance successfully unreleased"
400:
description: "Bad request, malformed query parameter. Details of the error (e.g. name of the parameter or line/character number with malformed data) provided in the response."
body:
text/plain:
example: "Transaction type is not encumbrance"
application/json:
example:
strict: false
value: !include raml-util/examples/errors.sample
404:
description: "Encumbrance with a given ID not found"
body:
text/plain:
example: "Encumbrance not found"
application/json:
example:
strict: false
value: !include raml-util/examples/errors.sample
500:
description: "Internal server error, e.g. due to misconfiguration"
body:
text/plain:
example: "internal server error, contact administrator"
application/json:
example:
strict: false
value: !include raml-util/examples/errors.sample
11 changes: 10 additions & 1 deletion src/main/java/org/folio/rest/impl/EncumbranceApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.folio.rest.annotations.Validate;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.resource.FinanceReleaseEncumbranceId;
import org.folio.rest.jaxrs.resource.FinanceUnreleaseEncumbranceId;
import org.folio.services.transactions.CommonTransactionService;
import org.folio.spring.SpringContextUtil;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -18,7 +19,7 @@
import io.vertx.core.Handler;
import io.vertx.core.Vertx;

public class EncumbranceApi extends BaseApi implements FinanceReleaseEncumbranceId {
public class EncumbranceApi extends BaseApi implements FinanceReleaseEncumbranceId, FinanceUnreleaseEncumbranceId {

@Autowired
private CommonTransactionService commonTransactionService;
Expand All @@ -36,4 +37,12 @@ public void postFinanceReleaseEncumbranceById(String id, Map<String, String> oka
.onFailure(fail -> handleErrorResponse(asyncResultHandler, fail));
}

@Override
@Validate
public void postFinanceUnreleaseEncumbranceById(String id, Map<String, String> okapiHeaders,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will repeated call throw an exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably no, I used approach from release encumbrance feature

Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
commonTransactionService.unreleaseTransaction(id, new RequestContext(vertxContext, okapiHeaders))
.onSuccess(v -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse())))
.onFailure(fail -> handleErrorResponse(asyncResultHandler, fail));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ public Future<Void> releaseTransaction(Transaction transaction, RequestContext r
.compose(summary -> updateTransaction(transaction, requestContext));
}

public Future<Void> unreleaseTransaction(String id, RequestContext requestContext) {
return retrieveTransactionById(id, requestContext)
.compose(transaction -> unreleaseTransaction(transaction, requestContext));
}

public Future<Void> unreleaseTransaction(Transaction transaction, RequestContext requestContext) {
logger.info("Start unreleasing transaction {}", transaction.getId()) ;

validateTransactionType(transaction, Transaction.TransactionType.ENCUMBRANCE);

if (transaction.getEncumbrance().getStatus() != Encumbrance.Status.RELEASED) {
return succeededFuture(null);
imerabishvili marked this conversation as resolved.
Show resolved Hide resolved
}

transaction.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED);
return createOrderTransactionSummary(transaction, 1, requestContext)
.compose(summary -> updateTransaction(transaction, requestContext));
}

public Future<Void> createOrderTransactionSummary(Transaction transaction, int number, RequestContext requestContext) {
String id = transaction.getEncumbrance().getSourcePurchaseOrderId();
OrderTransactionSummary summary = new OrderTransactionSummary().withId(id).withNumTransactions(number);
Expand Down
71 changes: 57 additions & 14 deletions src/test/java/org/folio/rest/impl/EncumbrancesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static javax.ws.rs.core.Response.Status.NO_CONTENT;
import static org.folio.rest.util.ErrorCodes.INVALID_TRANSACTION_TYPE;
import static org.folio.rest.util.MockServer.addMockEntry;
import static org.folio.rest.util.RestTestUtils.verifyPostResponse;
import static org.folio.rest.util.TestConfig.clearServiceInteractions;
import static org.folio.rest.util.TestConfig.initSpringContext;
import static org.folio.rest.util.TestConfig.isVerticleNotDeployed;
Expand All @@ -24,7 +25,6 @@
import org.folio.rest.jaxrs.model.Transaction;
import org.folio.rest.jaxrs.model.TransactionCollection;
import org.folio.rest.util.MockServer;
import org.folio.rest.util.RestTestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -65,7 +65,7 @@ void testPostReleaseEncumbrance() {

String encumbranceID = "5c9f769c-5fe2-4a6e-95fa-021f0d8834a0";

RestTestUtils.verifyPostResponse("/finance/release-encumbrance/" + encumbranceID , null, "", NO_CONTENT.getStatusCode());
verifyPostResponse("/finance/release-encumbrance/" + encumbranceID , null, "", NO_CONTENT.getStatusCode());

Transaction updatedEncumbrance = MockServer.getRqRsEntries(HttpMethod.PUT, TRANSACTIONS.name()).get(0).mapTo(Transaction.class);
assertEquals(Encumbrance.Status.RELEASED, updatedEncumbrance.getEncumbrance().getStatus());
Expand All @@ -79,12 +79,11 @@ void testPostReleaseNonEncumbrance() throws IOException {
Transaction allocation = new JsonObject(getMockData("mockdata/transactions/allocations.json")).mapTo(TransactionCollection.class).getTransactions().get(0);

addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(allocation));
Errors errors = RestTestUtils.verifyPostResponse("/finance/release-encumbrance/" + transactionID, null, "", 422).then()
Errors errors = verifyPostResponse("/finance/release-encumbrance/" + transactionID, null, "", 422).then()
.extract()
.as(Errors.class);

assertEquals(INVALID_TRANSACTION_TYPE.getCode(), errors.getErrors().get(0).getCode());

}

@Test
Expand All @@ -96,7 +95,7 @@ void testPostReleasedEncumbrance() throws IOException {
releasedEncumbrance.getEncumbrance().setStatus(Encumbrance.Status.RELEASED);
addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(releasedEncumbrance));

RestTestUtils.verifyPostResponse("/finance/release-encumbrance/" + transactionID , null, "", NO_CONTENT.getStatusCode());
verifyPostResponse("/finance/release-encumbrance/" + transactionID , null, "", NO_CONTENT.getStatusCode());

}

Expand All @@ -106,18 +105,62 @@ void testPostEncumbranceInvalidId() {

String transactionID = "bad-encumbrance-id";

RestTestUtils.verifyPostResponse("/finance/release-encumbrance/" + transactionID , null, "", BAD_REQUEST.getStatusCode());
verifyPostResponse("/finance/release-encumbrance/" + transactionID , null, "", BAD_REQUEST.getStatusCode());
}

@Test
void testPostUnreleaseEncumbrance() throws IOException {
logger.info("=== Test POST Unrelease Encumbrance ===");

String encumbranceID = "5c9f769c-5fe2-4a6e-95fa-021f0d8834a0";
Transaction releasedEncumbrance = new JsonObject(getMockData("mockdata/transactions/encumbrances.json")).mapTo(TransactionCollection.class).getTransactions().get(0);
releasedEncumbrance.getEncumbrance().setStatus(Encumbrance.Status.RELEASED);
addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(releasedEncumbrance));

verifyPostResponse("/finance/unrelease-encumbrance/" + encumbranceID , null, "", NO_CONTENT.getStatusCode());

Transaction updatedEncumbrance = MockServer.getRqRsEntries(HttpMethod.PUT, TRANSACTIONS.name()).get(0).mapTo(Transaction.class);
assertEquals(Encumbrance.Status.UNRELEASED, updatedEncumbrance.getEncumbrance().getStatus());
}

@Test
void testPostUnreleaseNonEncumbrance() throws IOException {
logger.info("=== Test POST Unrelease non Encumbrance transaction ===");

String transactionID = "a0b1e290-c42f-435a-b9d7-4ae7f77eb4ef";
Transaction allocation = new JsonObject(getMockData("mockdata/transactions/allocations.json"))
.mapTo(TransactionCollection.class).getTransactions().get(0);

addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(allocation));
Errors errors = verifyPostResponse("/finance/unrelease-encumbrance/" + transactionID, null, "", 422)
.then()
.extract()
.as(Errors.class);

assertEquals(INVALID_TRANSACTION_TYPE.getCode(), errors.getErrors().get(0).getCode());
}

private Transaction getTransactionMockById(String id) throws IOException {
return new JsonObject(getMockData("mockdata/transactions/transactions.json"))
.mapTo(TransactionCollection.class)
.getTransactions()
.stream()
.filter(tr -> tr.getId().equals(id))
.findFirst()
.get();
@Test
void testPostUnreleasedEncumbrance() throws IOException {
logger.info("=== Test POST Unreleased Encumbrance transaction ===");

String transactionID = "5c9f769c-5fe2-4a6e-95fa-021f0d8834a0";
Transaction releasedEncumbrance = new JsonObject(getMockData("mockdata/transactions/encumbrances.json"))
.mapTo(TransactionCollection.class).getTransactions().get(0);

releasedEncumbrance.getEncumbrance().setStatus(Encumbrance.Status.UNRELEASED);
addMockEntry(TRANSACTIONS.name(), JsonObject.mapFrom(releasedEncumbrance));

verifyPostResponse("/finance/unrelease-encumbrance/" + transactionID , null, "", NO_CONTENT.getStatusCode());
}

@Test
void testPostEncumbranceToUnreleaseInvalidId() {
logger.info("=== Test POST unrelease encumbrance bad ID ===");

String transactionID = "bad-encumbrance-id";

verifyPostResponse("/finance/unrelease-encumbrance/" + transactionID , null, "", BAD_REQUEST.getStatusCode());
}

}