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

Modorders 1022 2 #836

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
cc02c81
Improve validation and reject inconsistent order lines
yuntianhu Jan 31, 2024
7d7f740
Merge branch 'master' into MODORDERS-585
yuntianhu Jan 31, 2024
ceffec2
Delete src/main/resources/postgres-conf.json
yuntianhu Jan 31, 2024
845eeb4
Improve validation and reject inconsistent order lines
yuntianhu Jan 31, 2024
1e5a2e4
Merge remote-tracking branch 'origin/MODORDERS-585' into MODORDERS-585
yuntianhu Jan 31, 2024
c7d90b2
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Jan 31, 2024
6cc0396
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 1, 2024
cdace76
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
4ade17e
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
ee636f3
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
8e86441
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
6e0c64c
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
639a533
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
875f67a
Merge branch 'master' into MODORDERS-585
yuntianhu Feb 2, 2024
4e75ef4
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 2, 2024
1815bac
Merge remote-tracking branch 'origin/MODORDERS-585' into MODORDERS-585
yuntianhu Feb 2, 2024
89c49df
Merge branch 'master' into MODORDERS-585
yuntianhu Feb 5, 2024
531ca1b
MODORDERS-585 Improve validation and reject inconsistent order lines
yuntianhu Feb 5, 2024
088c56e
Merge remote-tracking branch 'origin/MODORDERS-585' into MODORDERS-585
yuntianhu Feb 5, 2024
85a6263
Merge branch 'master' of https://github.com/folio-org/mod-orders
SerhiiNosko Feb 8, 2024
5251d57
MODORDERS-1022. Add receipt Date to the CheckIng Piece schema
SerhiiNosko Feb 8, 2024
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
6 changes: 5 additions & 1 deletion src/main/java/org/folio/rest/core/exceptions/ErrorCodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,11 @@ public enum ErrorCodes {
FUND_LOCATION_RESTRICTION_VIOLATION("fundLocationRestrictionViolation", "One of the locations is restricted to be used by all funds."),
ENCUMBRANCES_FOR_RE_ENCUMBER_NOT_FOUND("encumbrancesForReEncumberNotFound", "The encumbrances were correctly created during the rollover or have already been updated."),
CLAIMING_CONFIG_INVALID("claimingConfigInvalid", "Claiming interval should be set and greater than 0 if claiming is active"),
TEMPLATE_NAME_ALREADY_EXISTS("templateNameNotUnique", "Template name already exists");
TEMPLATE_NAME_ALREADY_EXISTS("templateNameNotUnique", "Template name already exists"),
INVALID_PHYSICAL_POL("physicalPOLShouldContainOnlyPhysicalElement", "Physical order format should contain only physical resource"),
INVALID_ELECTRONIC_POL("electronicPOLShouldContainOnlyElectronicElement", "Electronic order format should contain only electronic resource"),
INVALID_PEMIX_POL("peMixPOLShouldContainPhysicalAndElectronicElement", "PE mix order format should contain both of physical and electronic resource"),
INVALID_OTHER_POL("otherPOLShouldContainPhysicalElement", "Other order format should contain only physical resource");


private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

import io.vertx.core.Future;


public class CompositePoLineValidationService extends BaseValidationService {

private final ExpenseClassValidationService expenseClassValidationService;
Expand All @@ -55,6 +54,7 @@ public Future<List<Error>> validatePoLine(CompositePoLine compPOL, RequestContex
return expenseClassValidationService.validateExpenseClasses(List.of(compPOL), false, requestContext)
.onSuccess(v -> errors.addAll(validatePoLineFormats(compPOL)))
.onSuccess(v -> errors.addAll(validateLocations(compPOL)))
.onSuccess(v -> errors.addAll(validatePoLineMaterial(compPOL)))
.map(v -> {
errors.addAll(validateCostPrices(compPOL));
return errors;
Expand All @@ -76,6 +76,58 @@ private List<Error> validatePoLineFormats(CompositePoLine compPOL) {
return Collections.emptyList();
}

public List<Error> validatePoLineMaterial(CompositePoLine compPOL) {
CompositePoLine.OrderFormat orderFormat = compPOL.getOrderFormat();

return switch (orderFormat) {
case P_E_MIX -> checkPEMix(compPOL);
case ELECTRONIC_RESOURCE -> checkElectronicResource(compPOL);
case PHYSICAL_RESOURCE -> checkPhysicalResource(compPOL);
case OTHER -> checkOtherResource(compPOL);
default -> Collections.emptyList();
};
}

private List<Error> checkPEMix(CompositePoLine compPOL) {
List<ErrorCodes> errors = new ArrayList<>();

if ((compPOL.getPhysical() == null) || (compPOL.getEresource() == null) || (getElectronicCostQuantity(compPOL) == 0) || (getPhysicalCostQuantity(compPOL) == 0)) {
errors.add(ErrorCodes.INVALID_PEMIX_POL);
}

return convertErrorCodesToErrors(compPOL, errors);
}

private List<Error> checkElectronicResource(CompositePoLine compPOL) {
List<ErrorCodes> errors = new ArrayList<>();

if ((compPOL.getPhysical() != null) && (getPhysicalCostQuantity(compPOL) != 0)) {
errors.add(ErrorCodes.INVALID_ELECTRONIC_POL);
}

return convertErrorCodesToErrors(compPOL, errors);
}

private List<Error> checkPhysicalResource(CompositePoLine compPOL) {
List<ErrorCodes> errors = new ArrayList<>();

if ((compPOL.getEresource() != null) && (getElectronicCostQuantity(compPOL) != 0)) {
errors.add(ErrorCodes.INVALID_PHYSICAL_POL);
}

return convertErrorCodesToErrors(compPOL, errors);
}

private List<Error> checkOtherResource(CompositePoLine compPOL) {
List<ErrorCodes> errors = new ArrayList<>();

if ((compPOL.getEresource() != null) && (getElectronicCostQuantity(compPOL) != 0)) {
errors.add(ErrorCodes.INVALID_OTHER_POL);
}

return convertErrorCodesToErrors(compPOL, errors);
}

private List<Error> validatePoLineWithMixedFormat(CompositePoLine compPOL) {

List<ErrorCodes> errors = new ArrayList<>();
Expand Down
10 changes: 6 additions & 4 deletions src/test/java/org/folio/rest/impl/PurchaseOrderLinesApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import static org.folio.rest.core.exceptions.ErrorCodes.ELECTRONIC_COST_LOC_QTY_MISMATCH;
import static org.folio.rest.core.exceptions.ErrorCodes.INACTIVE_EXPENSE_CLASS;
import static org.folio.rest.core.exceptions.ErrorCodes.INSTANCE_ID_NOT_ALLOWED_FOR_PACKAGE_POLINE;
import static org.folio.rest.core.exceptions.ErrorCodes.INVALID_ELECTRONIC_POL;
import static org.folio.rest.core.exceptions.ErrorCodes.ISBN_NOT_VALID;
import static org.folio.rest.core.exceptions.ErrorCodes.LOCATION_CAN_NOT_BE_MODIFIER_AFTER_OPEN;
import static org.folio.rest.core.exceptions.ErrorCodes.NON_ZERO_COST_ELECTRONIC_QTY;
Expand Down Expand Up @@ -448,7 +449,7 @@ void testPutOrderLineElectronicFormatIncorrectQuantityAndPrice() {
final Errors response = verifyPut(String.format(LINE_BY_ID_PATH, reqData.getId()), JsonObject.mapFrom(reqData),
APPLICATION_JSON, 422).as(Errors.class);

assertThat(response.getErrors(), hasSize(8));
assertThat(response.getErrors(), hasSize(9));
List<String> errorCodes = response.getErrors()
.stream()
.map(Error::getCode)
Expand All @@ -461,7 +462,8 @@ void testPutOrderLineElectronicFormatIncorrectQuantityAndPrice() {
COST_ADDITIONAL_COST_INVALID.getCode(),
COST_DISCOUNT_INVALID.getCode(),
ELECTRONIC_COST_LOC_QTY_MISMATCH.getCode(),
PHYSICAL_COST_LOC_QTY_MISMATCH.getCode()));
PHYSICAL_COST_LOC_QTY_MISMATCH.getCode(),
INVALID_ELECTRONIC_POL.getCode()));


// Check that no any calls made by the business logic to other services
Expand Down Expand Up @@ -1682,7 +1684,7 @@ public void testFundDistributionValidationWhenZeroPriceAndDifferentDistributionT
void testPutPhysicalOrderLineByIdWhenSpecificElementIsPresentAndProtectedFieldsChanged(CompositePoLine.OrderFormat orderFormat) {
logger.info("=== Test PUT Order Line By Id - Protected fields changed ===");

String lineId = "0009662b-8b80-4001-b704-ca10971f222d";
String lineId = "0009662b-8b80-4001-b704-ca10971f222e";
JsonObject body = getMockAsJson(PO_LINES_MOCK_DATA_PATH, lineId);
Object[] expected = new Object[]{ POLineFieldNames.ACQUISITION_METHOD.getFieldName()};
if (CompositePoLine.OrderFormat.ELECTRONIC_RESOURCE == orderFormat) {
Expand Down Expand Up @@ -1750,7 +1752,7 @@ void testPutElecOrderLineByIdWhenSpecificElementIsPresentAndProtectedFieldsChang
void testPutMixedOrderLineByIdWhenSpecificElementIsPresentAndProtectedFieldsChanged(CompositePoLine.OrderFormat orderFormat) {
logger.info("=== Test PUT Order Line By Id - Protected fields changed ===");

String lineId = "0009662b-8b80-4001-b704-ca10971f222d";
String lineId = "0009662b-8b80-4001-b704-ca10971f222f";
JsonObject body = getMockAsJson(PO_LINES_MOCK_DATA_PATH, lineId);
Object[] expected = new Object[]{ POLineFieldNames.ACQUISITION_METHOD.getFieldName()};

Expand Down
15 changes: 11 additions & 4 deletions src/test/java/org/folio/rest/impl/PurchaseOrdersApiTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
import static org.folio.rest.core.exceptions.ErrorCodes.INACTIVE_EXPENSE_CLASS;
import static org.folio.rest.core.exceptions.ErrorCodes.INCORRECT_FUND_DISTRIBUTION_TOTAL;
import static org.folio.rest.core.exceptions.ErrorCodes.INSTANCE_ID_NOT_ALLOWED_FOR_PACKAGE_POLINE;
import static org.folio.rest.core.exceptions.ErrorCodes.INVALID_OTHER_POL;
import static org.folio.rest.core.exceptions.ErrorCodes.INVALID_PEMIX_POL;
import static org.folio.rest.core.exceptions.ErrorCodes.INVALID_PHYSICAL_POL;
import static org.folio.rest.core.exceptions.ErrorCodes.ISBN_NOT_VALID;
import static org.folio.rest.core.exceptions.ErrorCodes.MISMATCH_BETWEEN_ID_IN_PATH_AND_BODY;
import static org.folio.rest.core.exceptions.ErrorCodes.MISSING_MATERIAL_TYPE;
Expand Down Expand Up @@ -600,7 +603,7 @@ void testPostOrderWithIncorrectCost() throws Exception {

final Errors response = verifyPostResponse(COMPOSITE_ORDERS_PATH, JsonObject.mapFrom(reqData).encode(),
prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10), APPLICATION_JSON, 422).as(Errors.class);
assertThat(response.getErrors(), hasSize(10));
assertThat(response.getErrors(), hasSize(12));
Set<String> errorCodes = response.getErrors()
.stream()
.map(Error::getCode)
Expand All @@ -612,7 +615,9 @@ void testPostOrderWithIncorrectCost() throws Exception {
PHYSICAL_COST_LOC_QTY_MISMATCH.getCode(),
ELECTRONIC_COST_LOC_QTY_MISMATCH.getCode(),
COST_UNIT_PRICE_ELECTRONIC_INVALID.getCode(),
COST_UNIT_PRICE_INVALID.getCode()));
COST_UNIT_PRICE_INVALID.getCode(),
INVALID_OTHER_POL.getCode(),
INVALID_PEMIX_POL.getCode()));
}

@Test
Expand Down Expand Up @@ -726,7 +731,7 @@ void testPutOrderWithIncorrectQuantities() throws Exception {

APPLICATION_JSON, 422).as(Errors.class);

assertThat(response.getErrors(), hasSize(5));
assertThat(response.getErrors(), hasSize(6));
Set<String> errorCodes = response.getErrors()
.stream()
.map(Error::getCode)
Expand All @@ -736,7 +741,8 @@ void testPutOrderWithIncorrectQuantities() throws Exception {
ZERO_COST_PHYSICAL_QTY.getCode(),
ELECTRONIC_COST_LOC_QTY_MISMATCH.getCode(),
PHYSICAL_COST_LOC_QTY_MISMATCH.getCode(),
ZERO_LOCATION_QTY.getCode()));
ZERO_LOCATION_QTY.getCode(),
INVALID_PEMIX_POL.getCode()));
}

@Test
Expand Down Expand Up @@ -2340,6 +2346,7 @@ void testPostOrdersCreateInventoryPhysicalNone() throws Exception {
reqData.getCompositePoLines().get(0).getCost().setListUnitPriceElectronic(0d);
reqData.getCompositePoLines().get(0).getLocations().get(0).setQuantityElectronic(0);


verifyPostResponse(COMPOSITE_ORDERS_PATH, JsonObject.mapFrom(reqData).toString(),
prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), APPLICATION_JSON, 201).as(CompositePurchaseOrder.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import java.util.List;
import java.util.UUID;

import com.github.tomakehurst.wiremock.http.ssl.TrustEverythingStrategy;

import org.folio.rest.core.exceptions.ErrorCodes;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.Cost;
import org.folio.rest.jaxrs.model.Eresource;
import org.folio.rest.jaxrs.model.Error;
import org.folio.rest.jaxrs.model.Location;
import org.folio.rest.jaxrs.model.Physical;
Expand All @@ -23,7 +26,7 @@ public class CompositePoLineValidationServiceTest {
private CompositePoLineValidationService compositePoLineValidationService;

@BeforeEach
public void initMocks(){
public void initMocks() {
MockitoAnnotations.openMocks(this);
}

Expand Down Expand Up @@ -112,4 +115,68 @@ void shouldReturnErrorIfClaimingIntervalIsNegativeWhenClaimingActive() {
assertEquals(1, errors.size());
assertEquals(ErrorCodes.CLAIMING_CONFIG_INVALID.getCode(), errors.get(0).getCode());
}

@Test
@DisplayName("Should return error if physical order format contains Electronic resources.")
void shouldReturnErrorIfPhysicalContainsElectronicSource() {
Eresource eresource = new Eresource();
CompositePoLine.OrderFormat format = CompositePoLine.OrderFormat.PHYSICAL_RESOURCE;
Cost cost = new Cost().withQuantityElectronic(1);
CompositePoLine compositePoLine = new CompositePoLine().withOrderFormat(format).withEresource(eresource).withCost(cost);
List<Error> errors = compositePoLineValidationService.validatePoLineMaterial(compositePoLine);

assertEquals(1, errors.size());
assertEquals(ErrorCodes.INVALID_PHYSICAL_POL.getCode(), errors.get(0).getCode());
}

@Test
@DisplayName("Should return error if electronic order format contains physical resources.")
void shouldReturnErrorIfElectronicContainsPhysicalSource() {
Physical physical = new Physical();
CompositePoLine.OrderFormat format = CompositePoLine.OrderFormat.ELECTRONIC_RESOURCE;
Cost cost = new Cost().withQuantityPhysical(1);
CompositePoLine compositePoLine = new CompositePoLine().withOrderFormat(format).withPhysical(physical).withCost(cost);
List<Error> errors = compositePoLineValidationService.validatePoLineMaterial(compositePoLine);

assertEquals(1, errors.size());
assertEquals(ErrorCodes.INVALID_ELECTRONIC_POL.getCode(), errors.get(0).getCode());
}

@Test
@DisplayName("Should return error if p/e mix order format does not contains physical resources.")
void shouldReturnErrorIfMixedDoesNotContainsPhysicalSource() {
Eresource eresource = new Eresource();
CompositePoLine.OrderFormat format = CompositePoLine.OrderFormat.P_E_MIX;
CompositePoLine compositePoLine = new CompositePoLine().withOrderFormat(format).withEresource(eresource);
List<Error> errors = compositePoLineValidationService.validatePoLineMaterial(compositePoLine);

assertEquals(1, errors.size());
assertEquals(ErrorCodes.INVALID_PEMIX_POL.getCode(), errors.get(0).getCode());
}

@Test
@DisplayName("Should return error if p/e mix order format does not contains electronic resources.")
void shouldReturnErrorIfMixedDoesNotContainsESource() {
Physical physical = new Physical();
CompositePoLine.OrderFormat format = CompositePoLine.OrderFormat.P_E_MIX;
CompositePoLine compositePoLine = new CompositePoLine().withOrderFormat(format).withPhysical(physical);
List<Error> errors = compositePoLineValidationService.validatePoLineMaterial(compositePoLine);

assertEquals(1, errors.size());
assertEquals(ErrorCodes.INVALID_PEMIX_POL.getCode(), errors.get(0).getCode());
}

@Test
@DisplayName("Should return error if other order format contains Electronic resources.")
void shouldReturnErrorIfOtherContainsElectronicSource() {
Eresource eresource = new Eresource();
CompositePoLine.OrderFormat format = CompositePoLine.OrderFormat.OTHER;
Cost cost = new Cost().withQuantityElectronic(1);
CompositePoLine compositePoLine = new CompositePoLine().withOrderFormat(format).withEresource(eresource).withCost(cost);
List<Error> errors = compositePoLineValidationService.validatePoLineMaterial(compositePoLine);

assertEquals(1, errors.size());
assertEquals(ErrorCodes.INVALID_OTHER_POL.getCode(), errors.get(0).getCode());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"id" : "0009662b-8b80-4001-b704-ca10971f222e",
"acquisitionMethod" : "Purchase At Vendor System",
"alerts" : [ ],
"cancellationRestriction" : false,
"cancellationRestrictionNote" : "ABCDEFGHIJKLMNOPQRSTUVW",
"claims" : [ ],
"collection" : false,
"contributors" : [ {
"contributor" : "Ed Mashburn",
"contributorNameTypeId" : "fbdd42a8-e47d-4694-b448-cc571d1b44c3"
} ],
"cost": {
"currency": "USD",
"listUnitPrice": 900.00,
"quantityPhysical": 1
},
"description": "",
"details": {
"receivingNote": "start with v. 162",
"productIds": [
{
"productId": "0065-3438",
"productIdType": "913300b2-03ed-469a-8179-c1092c991227"
}
],
"subscriptionFrom": "2018-07-01T00:00:00.000Z",
"subscriptionInterval": 1095,
"subscriptionTo": "2021-06-30T00:00:00.000Z"
},
"donor": "",
"fundDistribution": [
{
"code": "STATE-SUBN",
"fundId": "e54b1f4d-7d05-4b1a-9368-3c36b75d8ac6",
"distributionType": "percentage",
"value": 100.0,
"encumbrance": "eb506834-6c70-4239-8d1a-6414a5b08011"
}
],
"locations": [
{
"locationId": "758258bc-ecc1-41b8-abca-f7b610822ffd",
"quantity": 1,
"quantityElectronic": 0,
"quantityPhysical": 1
}
],
"orderFormat": "Physical Resource",
"paymentStatus": "Pending",
"physical": {
"createInventory": "Instance, Holding, Item",
"materialSupplier": "6828d7cb-d84e-41e5-9db5-fc2e162f9ffb",
"materialType": "2fa93835-ea37-479d-b133-1d2a2279fcd8",
"receiptDue": "2018-07-31T00:00:00.000Z",
"volumes": []
},
"poLineDescription": "",
"poLineNumber": "1EFC97C6B7-1",
"publicationDate": "2018",
"publisher": "Plenum Press",
"purchaseOrderId": "11111111-dddd-4444-9999-ffffffffffff",
"receiptDate": null,
"receiptStatus": "Pending",
"reportingCodes": [],
"requester": "",
"rush": false,
"selector": "",
"source": "User",
"tags": {
"tagList": []
},
"titleOrPackage": "Advances in astronautical science",
"vendorDetail": {
"instructions": "",
"noteFromVendor": "",
"vendorAccount": ""
},
"metadata": {
"createdDate": "2010-10-08T03:53:00.000",
"createdByUserId": "ab18897b-0e40-4f31-896b-9c9adc979a88"
}
}
Loading
Loading