Skip to content

Commit

Permalink
Release v5.8.1 (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
Abdulkhakimov authored Apr 1, 2024
1 parent c0e3453 commit 057cbf9
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 11 deletions.
10 changes: 10 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
## 5.9.0 - Unreleased

## 5.8.1 - Released (Quesnelia R1 2024)
The focus of this release was to fix acquisition check behaviour and improve consistency between invoice and encumbrance

[Full Changelog](https://github.com/folio-org/mod-invoice/compare/v5.8.0...v5.8.1)

### Bug Fixes
* [MODORDERS-1073](https://folio-org.atlassian.net/browse/MODORDERS-1073) - Invoice encumbrance link not removed because of acquisition unit
* [MODINVOICE-540](https://folio-org.atlassian.net/browse/MODINVOICE-540) - Mod-invoice tries to release encumbrances that are already released
* [MODINVOICE-516](https://folio-org.atlassian.net/browse/MODINVOICE-516) - Invoice transactions should not be changed when acquisition check was failed

## 5.8.0 - Released (Quesnelia R1 2024)
The focus of this release was to fix bugs and make improvement in transaction call and error codes

Expand Down
24 changes: 23 additions & 1 deletion descriptors/ModuleDescriptor-template.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"methods": ["GET"],
"pathPattern": "/invoice/invoices",
"permissionsRequired": ["invoice.invoices.collection.get"],
"permissionsDesired": [
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"invoice-storage.invoices.collection.get",
"invoice-storage.invoice-lines.collection.get",
Expand All @@ -36,6 +39,9 @@
"permissionsRequired": [
"invoice.invoices.item.get"
],
"permissionsDesired": [
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"invoice-storage.invoices.item.get",
"invoice-storage.invoice-lines.collection.get",
Expand All @@ -52,14 +58,16 @@
"invoices.fiscal-year.update",
"invoice.item.approve",
"invoice.item.pay",
"invoice.item.cancel"
"invoice.item.cancel",
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"configuration.entries.collection.get",
"invoice-storage.invoices.item.put",
"invoice-storage.invoices.item.get",
"invoice-storage.invoice-lines.item.put",
"invoice-storage.invoice-lines.collection.get",
"orders.bypass-acquisition-units",
"orders.collection.get",
"orders.po-lines.collection.get",
"orders.po-lines.item.put",
Expand Down Expand Up @@ -108,6 +116,9 @@
"methods": ["GET"],
"pathPattern": "/invoice/invoice-lines",
"permissionsRequired": ["invoice.invoice-lines.collection.get"],
"permissionsDesired": [
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"invoice-storage.invoice-lines.collection.get",
"acquisitions-units-storage.units.collection.get",
Expand Down Expand Up @@ -147,6 +158,9 @@
"methods": ["GET"],
"pathPattern": "/invoice/invoice-lines/{id}",
"permissionsRequired": ["invoice.invoice-lines.item.get"],
"permissionsDesired": [
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"invoice-storage.invoice-lines.item.get",
"invoice-storage.invoice-lines.item.put",
Expand All @@ -162,6 +176,9 @@
"methods": ["PUT"],
"pathPattern": "/invoice/invoice-lines/{id}",
"permissionsRequired": ["invoice.invoice-lines.item.put"],
"permissionsDesired": [
"invoices.bypass-acquisition-units"
],
"modulePermissions": [
"invoice-storage.invoice-lines.item.put",
"invoice-storage.invoice-lines.item.get",
Expand Down Expand Up @@ -896,6 +913,11 @@
"batch-voucher.export-configurations.credentials.test"
]
},
{
"permissionName": "invoices.bypass-acquisition-units",
"displayName": "Bypass acquisition units checks",
"description": "Backend internal permission to bypass invoice acquisition units checks"
},
{
"permissionName": "invoices.acquisitions-units-assignments.assign",
"displayName": "Acquisitions unit assignment - create unit assignment",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public enum AcqDesiredPermissions {
APPROVE("invoice.item.approve"),
PAY("invoice.item.pay"),
CANCEL("invoice.item.cancel"),
FISCAL_YEAR_UPDATE("invoices.fiscal-year.update");
FISCAL_YEAR_UPDATE("invoices.fiscal-year.update"),
BYPASS_ACQ_UNITS("invoices.bypass-acquisition-units");

private String permission;
private static final List<String> values;
Expand All @@ -32,4 +33,8 @@ public String getPermission() {
public static List<String> getValues() {
return values;
}

public static List<String> getValuesExceptBypass() {
return values.stream().filter(v -> !BYPASS_ACQ_UNITS.getPermission().equals(v)).toList();
}
}
8 changes: 8 additions & 0 deletions src/main/java/org/folio/rest/impl/InvoiceHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static javax.money.Monetary.getDefaultRounding;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.folio.invoices.utils.AcqDesiredPermissions.BYPASS_ACQ_UNITS;
import static org.folio.invoices.utils.ErrorCodes.CANNOT_RESET_INVOICE_FISCAL_YEAR;
import static org.folio.invoices.utils.ErrorCodes.INVALID_INVOICE_TRANSITION_ON_PAID_STATUS;
import static org.folio.invoices.utils.ErrorCodes.MULTIPLE_ADJUSTMENTS_FISCAL_YEARS;
Expand All @@ -22,6 +23,7 @@
import static org.folio.invoices.utils.ProtectedOperationType.UPDATE;
import static org.folio.invoices.utils.ResourcePathResolver.INVOICES;
import static org.folio.services.voucher.VoucherCommandService.VOUCHER_NUMBER_PREFIX_CONFIG_QUERY;
import static org.folio.utils.UserPermissionsUtil.userHasDesiredPermission;
import static org.folio.utils.UserPermissionsUtil.verifyUserHasAssignPermission;
import static org.folio.utils.UserPermissionsUtil.verifyUserHasFiscalYearUpdatePermission;
import static org.folio.utils.UserPermissionsUtil.verifyUserHasInvoiceApprovePermission;
Expand Down Expand Up @@ -262,6 +264,9 @@ public Future<InvoiceCollection> getInvoices(int limit, int offset, String query
}

private Future<String> buildGetInvoicesQuery(String query) {
if (userHasDesiredPermission(BYPASS_ACQ_UNITS, okapiHeaders)) {
return succeededFuture(query);
}
return protectionHelper.buildAcqUnitsCqlExprToSearchRecords(INVOICES)
.map(acqUnitsCqlExpr -> {
if (isEmpty(query)) {
Expand Down Expand Up @@ -384,6 +389,9 @@ private List<InvoiceLine> filterUpdatedLines(List<InvoiceLine> invoiceLines, Lis
* acquisitions units
*/
private Future<Void> validateAcqUnitsOnUpdate(Invoice updatedInvoice, Invoice persistedInvoice) {
if (userHasDesiredPermission(BYPASS_ACQ_UNITS, okapiHeaders)) {
return Future.succeededFuture();
}
List<String> updatedAcqUnitIds = updatedInvoice.getAcqUnitIds();
List<String> currentAcqUnitIds = persistedInvoice.getAcqUnitIds();
verifyUserHasManagePermission(updatedAcqUnitIds, currentAcqUnitIds, okapiHeaders);
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/org/folio/rest/impl/InvoiceLineHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.vertx.core.Future.succeededFuture;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.folio.invoices.utils.AcqDesiredPermissions.BYPASS_ACQ_UNITS;
import static org.folio.invoices.utils.ErrorCodes.CANNOT_DELETE_INVOICE_LINE;
import static org.folio.invoices.utils.ErrorCodes.FAILED_TO_UPDATE_INVOICE_AND_OTHER_LINES;
import static org.folio.invoices.utils.ErrorCodes.FAILED_TO_UPDATE_PONUMBERS;
Expand All @@ -18,6 +19,7 @@
import static org.folio.invoices.utils.ProtectedOperationType.UPDATE;
import static org.folio.invoices.utils.ResourcePathResolver.INVOICE_LINES;
import static org.folio.invoices.utils.ResourcePathResolver.resourcesPath;
import static org.folio.utils.UserPermissionsUtil.userHasDesiredPermission;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -86,6 +88,15 @@ public InvoiceLineHelper(Map<String, String> okapiHeaders, Context ctx) {
}

public Future<InvoiceLineCollection> getInvoiceLines(int limit, int offset, String query) {
if (userHasDesiredPermission(BYPASS_ACQ_UNITS, okapiHeaders)) {
String endpoint;
if (isEmpty(query)) {
endpoint = resourcesPath(INVOICE_LINES);
} else {
endpoint = String.format(GET_INVOICE_LINES_BY_QUERY, limit, offset, getEndpointWithQuery(query));
}
return invoiceLineService.getInvoiceLines(endpoint, buildRequestContext());
}
return protectionHelper.buildAcqUnitsCqlExprToSearchRecords(INVOICE_LINES)
.compose(acqUnitsCqlExpr -> {
String queryParam;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/folio/rest/impl/ProtectionHelper.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package org.folio.rest.impl;

import static io.vertx.core.Future.succeededFuture;
import static org.folio.invoices.utils.AcqDesiredPermissions.BYPASS_ACQ_UNITS;
import static org.folio.invoices.utils.ErrorCodes.ACQ_UNITS_NOT_FOUND;
import static org.folio.invoices.utils.ErrorCodes.USER_HAS_NO_PERMISSIONS;
import static org.folio.invoices.utils.HelperUtils.ALL_UNITS_CQL;
import static org.folio.invoices.utils.HelperUtils.convertIdsToCqlQuery;
import static org.folio.services.AcquisitionsUnitsService.ACQUISITIONS_UNIT_ID;
import static org.folio.utils.UserPermissionsUtil.userHasDesiredPermission;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -56,6 +58,9 @@ public ProtectionHelper(Map<String, String> okapiHeaders, Context ctx) {
* exist; successfully otherwise
*/
public Future<Void> isOperationRestricted(List<String> unitIds, ProtectedOperationType operation) {
if (userHasDesiredPermission(BYPASS_ACQ_UNITS, okapiHeaders)) {
return Future.succeededFuture();
}
if (CollectionUtils.isNotEmpty(unitIds)) {
return getUnitsByIds(unitIds).compose(units -> {
if (unitIds.size() == units.size()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.folio.invoices.utils.ErrorCodes.PENDING_PAYMENT_ERROR;
import static org.folio.invoices.utils.HelperUtils.convertToDoubleWithRounding;
import static org.folio.invoices.utils.HelperUtils.getFundDistributionAmount;
import static org.folio.rest.acq.model.finance.Encumbrance.Status.RELEASED;
import static org.folio.services.FundsDistributionService.distributeFunds;

import javax.money.MonetaryAmount;
Expand Down Expand Up @@ -94,7 +95,8 @@ private Future<Void> cleanupOldEncumbrances(List<Transaction> poLineTransactions
RequestContext requestContext) {
// Release encumbrances that are no longer relevant
List<Transaction> transactionsToRelease = poLineTransactions.stream()
.filter(tr -> holders.stream().noneMatch(holder -> sameFundAndPoLine(tr, holder)))
.filter(tr -> !RELEASED.equals(tr.getEncumbrance().getStatus()) &&
holders.stream().noneMatch(holder -> sameFundAndPoLine(tr, holder)))
.toList();
if (transactionsToRelease.isEmpty()) {
return Future.succeededFuture();
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/folio/utils/UserPermissionsUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public static void verifyUserHasAssignPermission(List<String> acqUnitIds, Map<St
}
}

public static boolean userHasDesiredPermission(AcqDesiredPermissions acqPerm, Map<String, String> okapiHeaders) {
return getProvidedPermissions(okapiHeaders).contains(acqPerm.getPermission());
}

public static boolean isUserDoesNotHaveDesiredPermission(AcqDesiredPermissions acqPerm, Map<String, String> okapiHeaders) {
return !getProvidedPermissions(okapiHeaders).contains(acqPerm.getPermission());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static io.vertx.core.json.Json.encodePrettily;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.folio.invoices.utils.AcqDesiredPermissions.BYPASS_ACQ_UNITS;
import static org.folio.invoices.utils.ErrorCodes.ACQ_UNITS_NOT_FOUND;
import static org.folio.invoices.utils.ErrorCodes.USER_HAS_NO_ACQ_PERMISSIONS;
import static org.folio.invoices.utils.ErrorCodes.USER_HAS_NO_PERMISSIONS;
Expand All @@ -10,6 +11,7 @@
import static org.folio.rest.impl.MockServer.addMockEntry;
import static org.folio.rest.impl.ProtectionHelper.ACQUISITIONS_UNIT_IDS;
import static org.folio.rest.impl.protection.ProtectedOperations.UPDATE;
import static org.folio.utils.UserPermissionsUtil.OKAPI_HEADER_PERMISSIONS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
Expand All @@ -18,6 +20,8 @@
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.core.IsEqual.equalTo;

import io.restassured.http.Header;
import io.vertx.core.json.JsonArray;
import io.vertx.junit5.VertxExtension;
import java.util.Arrays;
import java.util.Collections;
Expand Down Expand Up @@ -211,4 +215,19 @@ public void testGetInvoiceWithAssignedSoftDeletedUnit() {
assertThat(acquisitionsUnits, hasSize(1));
assertThat(acquisitionsUnits.get(0).getIsDeleted(), is(true));
}

@ParameterizedTest
@ValueSource(strings = {
"READ"
})
void testBypassAcqUnitChecks(ProtectedOperations operation) {
Header permissionHeader = new Header(OKAPI_HEADER_PERMISSIONS,
new JsonArray(List.of(BYPASS_ACQ_UNITS.getPermission())).encode());
Headers headers = new Headers(X_OKAPI_TENANT, permissionHeader, X_OKAPI_USER_WITH_UNITS_NOT_ASSIGNED_TO_RECORD);
Invoice invoice = prepareInvoice(Collections.emptyList());
operation.process(INVOICE_PATH, encodePrettily(invoice.withAcqUnitIds(PROTECTED_UNITS)),
headers, operation.getContentType(), operation.getCode());

validateNumberOfRequests(0, 0);
}
}
Loading

0 comments on commit 057cbf9

Please sign in to comment.