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

OAM-48: Added event validation and assignments filter for Wards/Services #51

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import static org.openlmis.stockmanagement.i18n.MessageKeys.ERROR_REASON_ASSIGNMENT_NOT_FOUND;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ public abstract class MessageKeys {
EVENT_ERROR_PREFIX + ".reasonFreeText.notAllowed";
public static final String ERROR_STOCK_EVENT_ORDERABLE_DISABLED_VVM =
EVENT_ERROR_PREFIX + ".orderable.disabled.vvm";
public static final String ERROR_DESTINATION_MUST_BE_WARD_SERVICE_OF_FACILITY =
EVENT_ERROR_PREFIX + ".destination.must.be.wardService.of.facility";
//stock events creation: mandatory fields
public static final String ERROR_EVENT_OCCURRED_DATE_INVALID = EVENT_ERROR_PREFIX
+ ".occurredDate.invalid";
Expand Down Expand Up @@ -249,7 +251,10 @@ public abstract class MessageKeys {
PHYSICAL_INVENTORY_ERROR_PREFIX + ".draft.exists";
public static final String ERROR_PHYSICAL_INVENTORY_DRAFT_SUBMIT =
PHYSICAL_INVENTORY_ERROR_PREFIX + ".draft.submit";

private static final String NODE_ERROR_PREFIX = ERROR_PREFIX + ".node";
//node
public static final String ERROR_NODE_NOT_FOUND =
NODE_ERROR_PREFIX + ".notFound";
public static final String ERROR_SIZE_NULL
= ERROR_PREFIX + ".pageable.size.null";
public static final String ERROR_SIZE_NOT_POSITIVE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,21 @@ private List<ValidSourceDestinationDto> createAssignmentDto(
return true;
}
})
.filter(assignment -> {
// check if assignment facility is type Ward/Service AND is in the same zone as facility
if (assignment.getNode().isRefDataFacility()) {
FacilityDto assignmentFacility =
facilitiesById.get(assignment.getNode().getReferenceId());
if (assignmentFacility.getType().getCode().equals("WS")) {
return assignmentFacility.getGeographicZone().getId()
.equals(facility.getGeographicZone().getId());
} else {
return true;
}
} else {
return true;
}
})
.filter(assignment -> !assignment.getNode().isRefDataFacility()
|| hasGeoAffinity(assignment, facility, facilitiesById))
.collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.openlmis.stockmanagement.extension.point.FreeTextValidator;
import org.openlmis.stockmanagement.extension.point.UnpackKitValidator;
import org.openlmis.stockmanagement.validators.ApprovedOrderableValidator;
import org.openlmis.stockmanagement.validators.FacilityValidator;
import org.openlmis.stockmanagement.validators.LotValidator;
import org.openlmis.stockmanagement.validators.MandatoryFieldsValidator;
import org.openlmis.stockmanagement.validators.OrderableLotUnitDuplicationValidator;
Expand Down Expand Up @@ -83,6 +84,9 @@ public class StockEventValidationsService {
@Autowired
private UnitOfOrderableValidator unitOfOrderableValidator;

@Autowired
private FacilityValidator facilityValidator;

/**
* Validate stock event with permission service and all validators.
*
Expand All @@ -101,6 +105,7 @@ public void validate(StockEventDto stockEventDto) {
destinationGeoLevelAffinityValidator.validate(stockEventDto);
stockEventVvmValidator.validate(stockEventDto);
unitOfOrderableValidator.validate(stockEventDto);
facilityValidator.validate(stockEventDto);

AdjustmentReasonValidator adjustmentReasonValidator = extensionManager.getExtension(
ExtensionPointId.ADJUSTMENT_REASON_POINT_ID, AdjustmentReasonValidator.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* This program is part of the OpenLMIS logistics management information system platform software.
* Copyright © 2017 VillageReach
*
* This program is free software: you can redistribute it and/or modify it under the terms
* of the GNU Affero General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details. You should have received a copy of
* the GNU Affero General Public License along with this program. If not, see
* http://www.gnu.org/licenses.  For additional information contact [email protected].
*/

package org.openlmis.stockmanagement.validators;

import static org.openlmis.stockmanagement.i18n.MessageKeys.ERROR_DESTINATION_MUST_BE_WARD_SERVICE_OF_FACILITY;
import static org.openlmis.stockmanagement.i18n.MessageKeys.ERROR_NODE_NOT_FOUND;

import org.openlmis.stockmanagement.domain.sourcedestination.Node;
import org.openlmis.stockmanagement.dto.StockEventDto;
import org.openlmis.stockmanagement.dto.StockEventLineItemDto;
import org.openlmis.stockmanagement.dto.referencedata.FacilityDto;
import org.openlmis.stockmanagement.exception.ResourceNotFoundException;
import org.openlmis.stockmanagement.exception.ValidationMessageException;
import org.openlmis.stockmanagement.repository.NodeRepository;
import org.openlmis.stockmanagement.service.referencedata.FacilityReferenceDataService;
import org.openlmis.stockmanagement.util.Message;
import org.slf4j.profiler.Profiler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component(value = "FacilityValidator")
public class FacilityValidator implements StockEventValidator {

@Autowired
private FacilityReferenceDataService facilityService;

@Autowired
private NodeRepository nodeRepository;

@Override
public void validate(StockEventDto stockEventDto) {
XLOGGER.entry(stockEventDto);

Profiler profiler = new Profiler("FACILITY_VALIDATOR");
profiler.setLogger(XLOGGER);

if (stockEventDto.isPhysicalInventory() || stockEventDto.getLineItems().isEmpty()) {
return;
}

FacilityDto facility = facilityService.findOne(stockEventDto.getFacilityId());
for (StockEventLineItemDto lineItem : stockEventDto.getLineItems()) {
if (lineItem.getDestinationId() != null) {
Node node = nodeRepository.findById(lineItem.getDestinationId())
.orElseThrow(() -> new ResourceNotFoundException(
new Message(ERROR_NODE_NOT_FOUND, lineItem.getDestinationId())));
if (node.isRefDataFacility()) {
FacilityDto destinationFacility = facilityService.findOne(node.getReferenceId());
if (destinationFacility.getType().getCode().equals("WS")
&& !destinationFacility.getGeographicZone().getId()
.equals(facility.getGeographicZone().getId())) {
throw new ValidationMessageException(
new Message(ERROR_DESTINATION_MUST_BE_WARD_SERVICE_OF_FACILITY));
}
}
}
}

profiler.stop().log();
XLOGGER.exit(stockEventDto);
}

}
2 changes: 2 additions & 0 deletions src/main/resources/api-definition.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ traits:

403:
description: User does not have permission to create stock events for given facility and program.
headers:
Keep-Alive:
body:
application/json:
schema: localizedMessage
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ stockmanagement.error.event.no.lineItems=No line items were provided. {0}
stockmanagement.error.event.sourceAndDestination.bothPresent=Source {0} and destination {1} should not both be present.
stockmanagement.error.event.source.not.in.validList=Source {0} is not in the valid sources list.
stockmanagement.error.event.destination.not.in.validList=Destination {0} is not in the valid destinations list.
stockmanagement.error.event.destination.must.be.wardService.of.facility=Products can only be issued between wards/services of a given facility.
#stock event creation: adjustment reason
stockmanagement.error.event.adjustment.quantity.invalid=Stock Adjustment quantity must not be negative.
stockmanagement.error.event.adjustment.reason.type.invalid=Reason type {0} is not valid for this adjustment event.
Expand Down Expand Up @@ -121,6 +122,8 @@ stockmanagement.error.reporting.file.empty=Empty file
stockmanagement.reason.physicalInventory.credit=Overstock
stockmanagement.reason.physicalInventory.debit=Understock
stockmanagement.reason.physicalInventory.balance_adjustment=Balance adjustment
#node
stockmanagement.error.node.notFound=Node not found for id: {0}
#notification
stockmanagement.email.stockout.subject=STOCKOUT Action Required: ${facilityName}, ${orderableName}
stockmanagement.email.stockout.content=Dear ${username}:\n\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ private GeographicZoneDto generateGeographicZone(UUID districtLevelId, UUID regi
private FacilityDto createFacilityDtoWithFacilityType(UUID facilityId, UUID facilityTypeId) {
FacilityTypeDto facilityDto = new FacilityTypeDto();
facilityDto.setId(facilityTypeId);
facilityDto.setCode("TEST");
return FacilityDto.builder()
.id(facilityId)
.type(facilityDto)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.openlmis.stockmanagement.validators.DefaultAdjustmentReasonValidator;
import org.openlmis.stockmanagement.validators.DefaultFreeTextValidator;
import org.openlmis.stockmanagement.validators.DefaultUnpackKitValidator;
import org.openlmis.stockmanagement.validators.FacilityValidator;
import org.openlmis.stockmanagement.validators.LotValidator;
import org.openlmis.stockmanagement.validators.MandatoryFieldsValidator;
import org.openlmis.stockmanagement.validators.OrderableLotUnitDuplicationValidator;
Expand Down Expand Up @@ -108,6 +109,9 @@ public class StockEventValidationsServiceTest {
@Mock
private UnitOfOrderableValidator unitOfOrderableValidator;

@Mock
private FacilityValidator facilityValidator;

@Before
public void setUp() throws Exception {
//make real validators do nothing because
Expand All @@ -127,6 +131,7 @@ public void setUp() throws Exception {
doNothing().when(physicalInventoryReasonsValidator).validate(any(StockEventDto.class));
doNothing().when(unpackKitValidator).validate(any(StockEventDto.class));
doNothing().when(unitOfOrderableValidator).validate(any(StockEventDto.class));
doNothing().when(facilityValidator).validate(any(StockEventDto.class));
when(extensionManager
.getExtension(ExtensionPointId.ADJUSTMENT_REASON_POINT_ID, AdjustmentReasonValidator.class))
.thenReturn(adjustmentReasonValidator);
Expand Down Expand Up @@ -182,4 +187,4 @@ public void shouldNotRunNextValidatorIfPreviousValidatorFailed() throws Exceptio
}
}

}
}
Loading
Loading