Skip to content

Commit

Permalink
Bugfix release 17.1.1 (#226)
Browse files Browse the repository at this point in the history
* MODFEE-243 implemented (#219)

(cherry picked from commit 1736520)

* MODFEE-243 - Prevent deleting/updating required FeeFines (#221)

* Fixed validation logic and refactored test

* Test is fixed

* Tests are optimized

* Tests are fixed

* MODFEE-243 Refactor

* MODFEE-243 Extend tests

* Tests are fixed

* refactored according to review

* refactored

* refactored

Co-authored-by: Alexander Kurash <[email protected]>
(cherry picked from commit e24143e)

* bugfix-release-17.1.1 cherry pick from MODFEE-247, MODFEE-243

* Update NEWS

* [maven-release-plugin] prepare release v17.1.1

* [maven-release-plugin] prepare for next development iteration

Co-authored-by: OleksandrVidinieiev <[email protected]>
  • Loading branch information
sherzodn and OleksandrVidinieiev authored Apr 12, 2022
1 parent d740c31 commit bf5ecec
Show file tree
Hide file tree
Showing 13 changed files with 188 additions and 26 deletions.
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 17.1.1 2022-04-12
Return remaining amount in response to refund (MODFEE-247)
Prevent deleting/updating required FeeFines (MODFEE-243)
Generate aged to lost fees and fines (MODFEE-239)

## 17.1.0 2022-02-22
Reopen a fee/fine on refund (MODFEE-229)
Upgrade to RMB 33.0.4 and Log4j 2.16.0 (MODFEE-232)
Expand Down
2 changes: 1 addition & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"provides":[
{
"id":"feesfines",
"version":"17.1",
"version":"17.2",
"handlers":[
{
"methods":[
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.folio</groupId>
<artifactId>mod-feesfines</artifactId>
<version>17.1.1-SNAPSHOT</version>
<version>17.1.2-SNAPSHOT</version>
<packaging>jar</packaging>

<licenses>
Expand Down
2 changes: 1 addition & 1 deletion ramls/accounts.raml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#%RAML 1.0
title: Accounts
version: v17.1
version: v17.2
baseUri: http://github.com/org/folio/mod-feesfines

documentation:
Expand Down
7 changes: 6 additions & 1 deletion ramls/actions/actionSuccessResponse.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"type": "string",
"description": "Action amount"
},
"remainingAmount": {
"type": "string",
"description": "Remaining fee/fine amount after action"
},
"feefineactions": {
"type": "array",
"description": "Fee/fine action records created as a result of an action",
Expand All @@ -24,6 +28,7 @@
"additionalProperties": false,
"required": [
"accountId",
"amount"
"amount",
"remainingAmount"
]
}
34 changes: 34 additions & 0 deletions src/main/java/org/folio/rest/domain/AutomaticFeeFineType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.folio.rest.domain;

import java.util.HashMap;
import java.util.Map;

public enum AutomaticFeeFineType {
// IDs come from /resources/templates/db_scripts/populate-feefines.sql

OVERDUE_FINE("9523cb96-e752-40c2-89da-60f3961a488d"),
REPLACEMENT_PROCESSING_FEE("d20df2fb-45fd-4184-b238-0d25747ffdd9"),
LOST_ITEM_FEE("cf238f9f-7018-47b7-b815-bb2db798e19f"),
LOST_ITEM_PROCESSING_FEE("c7dede15-aa48-45ed-860b-f996540180e0");

private final String id;
private static final Map<String, AutomaticFeeFineType> idIndex = new HashMap<>(AutomaticFeeFineType.values().length);

static {
for (AutomaticFeeFineType automaticFeeFineType : AutomaticFeeFineType.values()) {
idIndex.put(automaticFeeFineType.id, automaticFeeFineType);
}
}

AutomaticFeeFineType(String id) {
this.id = id;
}

public String getId() {
return id;
}

public static AutomaticFeeFineType getById(String id) {
return idIndex.get(id);
}
}
13 changes: 12 additions & 1 deletion src/main/java/org/folio/rest/impl/AccountsAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.folio.rest.client.InventoryClient;
import org.folio.rest.domain.Action;
import org.folio.rest.domain.ActionRequest;
import org.folio.rest.domain.MonetaryValue;
import org.folio.rest.exception.AccountNotFoundValidationException;
import org.folio.rest.exception.FailedValidationException;
import org.folio.rest.jaxrs.model.Account;
Expand Down Expand Up @@ -481,16 +482,26 @@ private void handleActionResult(ActionRequest request, AsyncResult<ActionContext

ActionResultAdapter resultAdapter = action.getActionResultAdapter();
if (resultAdapter == null) {
logger.error("Unprocessable action: " + action.name());
logger.error("Unprocessable action: {}", action.name());
return;
}

final String accountId = request.getAccountIds().get(0);

if (asyncResult.succeeded()) {
final ActionContext actionContext = asyncResult.result();

final String remainingAmount = actionContext.getAccounts()
.values()
.stream()
.findFirst()
.map(Account::getRemaining)
.map(MonetaryValue::toString)
.orElse(null);

ActionSuccessResponse response = new ActionSuccessResponse()
.withFeefineactions(actionContext.getFeeFineActions())
.withRemainingAmount(remainingAmount)
.withAccountId(accountId);
if (actionContext.getRequestedAmount() != null) {
response.withAmount(actionContext.getRequestedAmount().toString());
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/org/folio/rest/impl/FeeFinesAPI.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.folio.rest.impl;

import static io.vertx.core.Future.succeededFuture;
import static org.folio.rest.jaxrs.resource.Feefines.PostFeefinesResponse.respond422WithApplicationJson;
import static org.folio.rest.utils.ErrorHelper.createErrors;

import java.io.IOException;
import java.util.List;
import java.util.Map;
Expand All @@ -12,6 +16,8 @@
import org.folio.cql2pgjson.CQL2PgJSON;
import org.folio.cql2pgjson.exception.CQL2PgJSONException;
import org.folio.rest.annotations.Validate;
import org.folio.rest.domain.AutomaticFeeFineType;
import org.folio.rest.jaxrs.model.Error;
import org.folio.rest.jaxrs.model.Feefine;
import org.folio.rest.jaxrs.model.FeefinedataCollection;
import org.folio.rest.jaxrs.model.FeefinesGetOrder;
Expand Down Expand Up @@ -42,6 +48,7 @@ public class FeeFinesAPI implements Feefines {
private static final String FEEFINE_ID_FIELD = "'id'";
private static final String OKAPI_HEADER_TENANT = "x-okapi-tenant";
private final Logger logger = LogManager.getLogger(FeeFinesAPI.class);
private static final String VALIDATION_ERROR_MSG = "Attempt to change an automatic fee/fine type";

private CQLWrapper getCQL(String query, int limit, int offset) throws CQL2PgJSONException, IOException {
CQL2PgJSON cql2pgJson = new CQL2PgJSON(FEEFINES_TABLE + ".jsonb");
Expand Down Expand Up @@ -123,6 +130,11 @@ public void postFeefines(String lang, Feefine entity, Map<String, String> okapiH
}
try {
vertxContext.runOnContext(v -> {
// Automatic fee/fine types can't be created
if (refuseToChangeAutomaticFeeFineType(entity.getId(), asyncResultHandler)) {
return;
}

String tenantId = TenantTool.calculateTenantId(okapiHeaders.get(OKAPI_HEADER_TENANT));
PostgresClient postgresClient = PostgresClient.getInstance(vertxContext.owner(), tenantId);

Expand Down Expand Up @@ -229,6 +241,11 @@ public void deleteFeefinesByFeefineId(String feefineId,
Context vertxContext) {
try {
vertxContext.runOnContext(v -> {
// Automatic fee/fine types can't be deleted
if (refuseToChangeAutomaticFeeFineType(feefineId, asyncResultHandler)) {
return;
}

String tenantId = TenantTool.calculateTenantId(okapiHeaders.get(OKAPI_HEADER_TENANT));

Criteria idCrit = new Criteria();
Expand Down Expand Up @@ -294,6 +311,11 @@ public void putFeefinesByFeefineId(String feefineId,
asyncResultHandler.handle(Future.succeededFuture(PutFeefinesByFeefineIdResponse.respond400WithTextPlain("feefineId is missing")));
}

// Automatic fee/fine types can't be updated
if (refuseToChangeAutomaticFeeFineType(feefineId, asyncResultHandler)) {
return;
}

vertxContext.runOnContext(v -> {
String tenantId = TenantTool.calculateTenantId(okapiHeaders.get(OKAPI_HEADER_TENANT));

Expand Down Expand Up @@ -351,4 +373,15 @@ public void putFeefinesByFeefineId(String feefineId,
messages.getMessage(lang, MessageConsts.InternalServerError))));
}
}

private boolean refuseToChangeAutomaticFeeFineType(String feeFineId,
Handler<AsyncResult<Response>> asyncResultHandler) {

boolean automatic = AutomaticFeeFineType.getById(feeFineId) != null;
if (automatic) {
asyncResultHandler.handle(succeededFuture(respond422WithApplicationJson(createErrors(
new Error().withMessage(VALIDATION_ERROR_MSG)))));
}
return automatic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static io.restassured.http.ContentType.JSON;
import static java.lang.String.format;
import static org.folio.rest.domain.MonetaryValue.ZERO;
import static org.folio.rest.utils.LogEventUtils.fetchLogEventPayloads;
import static org.folio.rest.utils.ResourceClients.buildAccountBulkCancelClient;
import static org.folio.rest.utils.ResourceClients.buildAccountCancelClient;
Expand All @@ -26,6 +27,7 @@
import org.folio.rest.jaxrs.model.BulkActionSuccessResponse;
import org.folio.rest.jaxrs.model.CancelActionRequest;
import org.folio.rest.jaxrs.model.CancelBulkActionRequest;
import org.folio.rest.jaxrs.model.PaymentStatus;
import org.folio.rest.utils.ResourceClient;
import org.folio.test.support.ApiTests;
import org.folio.test.support.EntityBuilder;
Expand Down Expand Up @@ -58,6 +60,7 @@ public void cancelActionShouldCancelAccount() {
.then()
.statusCode(HttpStatus.SC_CREATED)
.body("accountId", is(ACCOUNT_ID))
.body("remainingAmount", is(ZERO.toString()))
.body(FEE_FINE_ACTIONS, hasSize(1));

accountsClient.getById(ACCOUNT_ID)
Expand Down Expand Up @@ -93,6 +96,7 @@ public void shouldUseCancellationReason() {
accountCancelClient.attemptCreate(cancelActionRequest)
.then()
.statusCode(HttpStatus.SC_CREATED)
.body("remainingAmount", is(ZERO.toString()))
.body("accountId", is(ACCOUNT_ID));

accountsClient.getById(ACCOUNT_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static org.folio.rest.domain.Action.PAY;
import static org.folio.rest.domain.Action.TRANSFER;
import static org.folio.rest.domain.Action.WAIVE;
import static org.folio.rest.domain.MonetaryValue.ZERO;
import static org.folio.rest.utils.LogEventUtils.fetchLogEventPayloads;
import static org.folio.rest.utils.ResourceClients.buildAccountPayClient;
import static org.folio.rest.utils.ResourceClients.buildAccountTransferClient;
Expand Down Expand Up @@ -182,6 +183,7 @@ public void longDecimalsAreHandledCorrectlyAndAccountIsClosed() {

String requestedAmountString = "1.004123456789";
String expectedPaymentStatus = action.getFullResult();
MonetaryValue expectedRemainingAmount = ZERO;

final DefaultActionRequest request = createRequest(requestedAmountString);

Expand All @@ -190,6 +192,7 @@ public void longDecimalsAreHandledCorrectlyAndAccountIsClosed() {
.statusCode(HttpStatus.SC_CREATED)
.contentType(JSON)
.body("amount", is("1.00"))
.body("remainingAmount", is(expectedRemainingAmount.toString()))
.body("accountId", is(ACCOUNT_ID));

actionsClient.getAll()
Expand All @@ -201,7 +204,8 @@ public void longDecimalsAreHandledCorrectlyAndAccountIsClosed() {
hasJsonPath("typeAction", is(expectedPaymentStatus))
)));

verifyAccountAndGet(accountsClient, ACCOUNT_ID, expectedPaymentStatus, MonetaryValue.ZERO, "Closed");
verifyAccountAndGet(accountsClient, ACCOUNT_ID, expectedPaymentStatus, expectedRemainingAmount,
"Closed");

assertThat(fetchLogEventPayloads(getOkapi()).get(0),
is(feeFineActionLogEventPayload(account, request, action.getFullResult(), 1.0,
Expand All @@ -215,6 +219,7 @@ public void longDecimalsAreHandledCorrectly() {

String requestedAmountString = "1.004987654321"; // should be rounded to 1.00
String expectedPaymentStatus = action.getPartialResult();
MonetaryValue expectedRemainingAmount = new MonetaryValue(0.24);

final DefaultActionRequest request = createRequest(requestedAmountString);

Expand All @@ -223,6 +228,7 @@ public void longDecimalsAreHandledCorrectly() {
.statusCode(HttpStatus.SC_CREATED)
.contentType(JSON)
.body("amount", is("1.00"))
.body("remainingAmount", is(expectedRemainingAmount.toString()))
.body("accountId", is(ACCOUNT_ID));

actionsClient.getAll()
Expand All @@ -234,7 +240,7 @@ public void longDecimalsAreHandledCorrectly() {
hasJsonPath("typeAction", is(expectedPaymentStatus))
)));

verifyAccountAndGet(accountsClient, ACCOUNT_ID, expectedPaymentStatus, new MonetaryValue(0.24),
verifyAccountAndGet(accountsClient, ACCOUNT_ID, expectedPaymentStatus, expectedRemainingAmount,
"Open");

assertThat(fetchLogEventPayloads(getOkapi()).get(0),
Expand Down Expand Up @@ -275,6 +281,7 @@ private void paymentCreatesActionAndUpdatesAccount(boolean terminalAction) {
.statusCode(HttpStatus.SC_CREATED)
.contentType(JSON)
.body("amount", is(requestedAmountString))
.body("remainingAmount", is(expectedAccountBalanceAfter.toString()))
.body("accountId", is(ACCOUNT_ID))
.body(FEE_FINE_ACTIONS, hasSize(1));

Expand Down
Loading

0 comments on commit bf5ecec

Please sign in to comment.