Commit 3025c8ad authored by Artem Hrybeniuk's avatar Artem Hrybeniuk Committed by Matija Obreza
Browse files

OrderRequestServiceImpl: Inventory quantityOnHand updates

- Inventory.quantityOnHand automatic deduction after the item of one order was shipped
- Withdrawn Inventory.quantityOnHand = OrderRequestItem.quantityShipped
- Updated unit tests
parent 99af17cd
......@@ -151,6 +151,7 @@ public abstract class CommunityCodeValues {
public static final CodeValueDef ORDER_REQUEST_ITEM_STATUS_PENDING = new CodeValueDef(ORDER_REQUEST_ITEM_STATUS, "PENDING", "Retrieve from storage", "Retrieve source inventory from storage for distribution.");
public static final CodeValueDef ORDER_REQUEST_ITEM_STATUS_SPLIT = new CodeValueDef(ORDER_REQUEST_ITEM_STATUS, "SPLIT", "Split out order item", null);
public static final CodeValueDef ORDER_REQUEST_ITEM_STATUS_CANCEL = new CodeValueDef(ORDER_REQUEST_ITEM_STATUS, "CANCEL", "Cancel or abort order item", null);
public static final CodeValueDef ORDER_REQUEST_ITEM_STATUS_SHIPPED = new CodeValueDef(ORDER_REQUEST_ITEM_STATUS, "SHIPPED", "Shipped order item", null);
public static final String ORDER_REQUEST_ITEM_ACTION = "ORDER_REQUEST_ITEM_ACTION";
public static final CodeValueDef ORDER_REQUEST_ITEM_ACTION_RETRIEVE = new CodeValueDef(ORDER_REQUEST_ITEM_ACTION, "RETRIEVE", "Retrieve from storage", "Retrieve source inventory from storage for distribution.");
......
......@@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
......@@ -459,6 +460,9 @@ public class OrderRequestServiceImpl extends FilteredCRUDServiceImpl<OrderReques
// not having selected status
.and(QOrderRequestItem.orderRequestItem.statusCode.ne(newStatus))));
var shippedItemsIds = orderItems.stream().filter(item -> CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_SHIPPED.is(item.getStatusCode()))
.map(OrderRequestItem::getId).collect(Collectors.toList());
// Updated items only
List<OrderRequestItem> updatedItems = orderItems.stream().map((orderItem) -> updateItemStatus(orderItem, newStatus))
// if updatedItem is null, the change is not permitted
......@@ -472,6 +476,35 @@ public class OrderRequestServiceImpl extends FilteredCRUDServiceImpl<OrderReques
itemRepository.saveAll(updatedItems);
Set<Inventory> updatedInventories = new HashSet<>();
if (CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_SHIPPED.is(newStatus)) {
// update inventory quantity if item status is updated to shipped
updatedInventories = updatedItems.stream().map(item -> {
var inventory = item.getInventory();
if (shouldAutoDeductInventory(item)) {
if (inventory.getQuantityOnHand() < item.getQuantityShipped()) {
throw new InvalidApiUsageException("Insufficient inventory quantity on hand");
}
inventory.setQuantityOnHand(inventory.getQuantityOnHand() - item.getQuantityShipped());
}
return inventory;
}).collect(Collectors.toSet());
} else if (!shippedItemsIds.isEmpty()) {
// update inventory quantity if item status is updated from shipped to something else
updatedInventories = updatedItems.stream().filter(updatedItem -> shippedItemsIds.contains(updatedItem.getId())).map(item -> {
var inventory = item.getInventory();
if (shouldAutoDeductInventory(item)) {
inventory.setQuantityOnHand(inventory.getQuantityOnHand() + item.getQuantityShipped());
}
return inventory;
}).collect(Collectors.toSet());
}
if (!updatedInventories.isEmpty()) {
inventoryRepository.saveAll(updatedInventories);
}
// Log change based on: "Order Request Item status_code changed by xxxxxx to
// SHIPPED for 11 items."
actionSupport.logAction(orderRequest, MessageFormat.format("Item status changed to {0} for {1} items.", newStatus, updatedItems.size()), updatedItems);
......@@ -484,6 +517,25 @@ public class OrderRequestServiceImpl extends FilteredCRUDServiceImpl<OrderReques
.and(QOrderRequestItem.orderRequestItem.in(orderItems))));
}
/**
* Determine if the inventory of order request item should be automatically deducted
* @param item order request item
* @return <code>true</code> if form and unit codes match, and inventory is auto-deductible
*/
private boolean shouldAutoDeductInventory(OrderRequestItem item) {
Inventory inventory = item.getInventory();
if (inventory == null)
return false;
return
// inventory is auto-deductible
StringUtils.equals(inventory.getIsAutoDeducted(), "Y")
// item form type code matches inventory distribtion form code
&& StringUtils.equals(item.getDistributionFormCode(), inventory.getFormTypeCode())
// item units match inventory units
&& StringUtils.equals(item.getQuantityShippedUnitCode(), inventory.getQuantityOnHandUnitCode())
;
}
@Override
@Transactional
public OrderRequest generateInventories(OrderRequest order) {
......@@ -525,7 +577,7 @@ public class OrderRequestServiceImpl extends FilteredCRUDServiceImpl<OrderReques
withdrawnInventory.setFormTypeCode(inventory.getFormTypeCode());
withdrawnInventory.setGeneration(inventory.getGeneration());
withdrawnInventory.setHundredSeedWeight(inventory.getHundredSeedWeight());
withdrawnInventory.setQuantityOnHand(null);
withdrawnInventory.setQuantityOnHand(item.getQuantityShipped());
withdrawnInventory.setPathogenStatusCode(inventory.getPathogenStatusCode());
withdrawnInventory.setPlantSexCode(inventory.getPlantSexCode());
withdrawnInventory.setRootstock(inventory.getRootstock());
......
......@@ -872,7 +872,7 @@ public class InventoryControllerTest extends AbstractApiV1Test {
Inventory savedInventory = addInventoryToDB(accession, "INV", -1L, null);
assertThat(savedInventory, is(notNullValue()));
assertThat(inventoryRepository.count(), equalTo(2L));
assertThat(savedInventory.getQuantityOnHandUnitCode(), nullValue());
assertThat(savedInventory.getQuantityOnHandUnitCode(), is("sd"));
InventoryService.InventoryQuantity quantity = new InventoryService.InventoryQuantity();
quantity.id = savedInventory.getId();
......@@ -901,7 +901,7 @@ public class InventoryControllerTest extends AbstractApiV1Test {
Inventory savedInventory = addInventoryToDB(accession, "INV", -1L, null);
assertThat(savedInventory, is(notNullValue()));
assertThat(inventoryRepository.count(), equalTo(2L));
assertThat(savedInventory.getQuantityOnHandUnitCode(), nullValue());
assertThat(savedInventory.getQuantityOnHandUnitCode(), is("sd"));
InventoryService.InventoryQuantity quantity = new InventoryService.InventoryQuantity();
quantity.id = savedInventory.getId();
......@@ -1081,7 +1081,7 @@ public class InventoryControllerTest extends AbstractApiV1Test {
InventoryService.InventoryQuantity quantity = new InventoryService.InventoryQuantity();
quantity.id = savedInventory.getId();
quantity.quantityOnHand = 300d;
quantity.quantityOnHandUnitCode = "g"; // invalid code
quantity.quantityOnHandUnitCode = "aliens"; // invalid code
/*@formatter:off*/
mockMvc
......@@ -1091,12 +1091,13 @@ public class InventoryControllerTest extends AbstractApiV1Test {
)
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.error", containsString("'inventoryQuantity' on field 'quantityOnHandUnitCode': rejected value [aliens]")))
;
/*@formatter:on*/
Inventory updated = inventoryService.get(quantity.id);
assertThat(updated.getQuantityOnHand(), is(savedInventory.getQuantityOnHand()));
assertThat(updated.getQuantityOnHandUnitCode(), nullValue());
assertThat(updated.getQuantityOnHandUnitCode(), is("sd"));
}
@Test
......@@ -1228,7 +1229,7 @@ public class InventoryControllerTest extends AbstractApiV1Test {
Inventory savedInventory = addInventoryToDB(accession, "INV", -1L, null);
assertThat(savedInventory, is(notNullValue()));
assertThat(inventoryRepository.count(), equalTo(2L));
assertThat(savedInventory.getQuantityOnHandUnitCode(), nullValue());
assertThat(savedInventory.getQuantityOnHandUnitCode(), is("sd"));
InventoryService.InventoryQuantity quantity = new InventoryService.InventoryQuantity();
quantity.id = savedInventory.getId();
......
......@@ -408,7 +408,7 @@ public class OrderRequestControllerTest extends AbstractApiV1Test {
assertThat(withdrawnInventory.getStorageLocationPart2(), is(inventory.getStorageLocationPart2()));
assertThat(withdrawnInventory.getStorageLocationPart3(), is(inventory.getStorageLocationPart3()));
assertThat(withdrawnInventory.getStorageLocationPart4(), is(inventory.getStorageLocationPart4()));
assertThat(withdrawnInventory.getQuantityOnHand(), is(nullValue()));
assertThat(withdrawnInventory.getQuantityOnHand(), is(1D));
assertThat(inventoryActionRepository.count(), is(2L));
var actions = inventoryActionRepository.findAll();
......@@ -1297,6 +1297,72 @@ public class OrderRequestControllerTest extends AbstractApiV1Test {
assertThat(orderRequestItemRepository.count(), is(4L));
}
@Test
public void updateItemStatusShippedTest() throws Exception {
OrderRequest orderRequest1 = addOrderRequestToDB();
assertThat(orderRequest1, is(notNullValue()));
assertThat(orderRequest1.getId(), is(notNullValue()));
assertThat(orderRequestRepository.findById(orderRequest1.getId()).isPresent(), is(true));
Inventory inventory = addInventoryToDB();
OrderRequestItem orderRequestItem1 = addOrderRequestItemToDB(inventory, orderRequest1, CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.value);
assertThat(orderRequestItem1, is(notNullValue()));
assertThat(orderRequestItem1.getId(), is(notNullValue()));
assertThat(orderRequestItem1.getQuantityShipped(), notNullValue());
assertThat(orderRequestItem1.getDistributionFormCode(), is(inventory.getFormTypeCode()));
assertThat(orderRequestItem1.getQuantityShippedUnitCode(), is(inventory.getQuantityOnHandUnitCode()));
assertThat(orderRequestItemRepository.findById(orderRequestItem1.getId()).isPresent(), is(true));
OrderRequestItem orderRequestItem2 = addOrderRequestItemToDB(inventory, orderRequest1, CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.value);
assertThat(orderRequestItem2, is(notNullValue()));
assertThat(orderRequestItem2.getId(), is(notNullValue()));
assertThat(orderRequestItem2.getQuantityShipped(), notNullValue());
assertThat(orderRequestItem2.getDistributionFormCode(), is(inventory.getFormTypeCode()));
assertThat(orderRequestItem2.getQuantityShippedUnitCode(), is(inventory.getQuantityOnHandUnitCode()));
assertThat(orderRequestItemRepository.findById(orderRequestItem2.getId()).isPresent(), is(true));
/*@formatter:off*/
mockMvc
.perform(post(OrderRequestController.API_URL.concat("/items/{id}/status/{newStatus}"), orderRequest1.getId(), CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_SHIPPED.value)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(verboseMapper.writeValueAsString(Set.of(orderRequestItem1.getId(), orderRequestItem2.getId())))
)
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", not(nullValue())))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$.[0].statusCode", equalTo(CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_SHIPPED.value)))
.andExpect(jsonPath("$.[1].statusCode", equalTo(CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_SHIPPED.value)))
;
/*@formatter:on*/
Inventory updatedInventory = inventoryService.load(inventory.getId());
assertThat(updatedInventory.getQuantityOnHand(), is(0D));
/*@formatter:off*/
mockMvc
.perform(post(OrderRequestController.API_URL.concat("/items/{id}/status/{newStatus}"), orderRequest1.getId(), CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.value)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.content(verboseMapper.writeValueAsString(Set.of(orderRequestItem1.getId(), orderRequestItem2.getId())))
)
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", not(nullValue())))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(2)))
.andExpect(jsonPath("$.[0].statusCode", equalTo(CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.value)))
.andExpect(jsonPath("$.[1].statusCode", equalTo(CommunityCodeValues.ORDER_REQUEST_ITEM_STATUS_PENDING.value)))
;
/*@formatter:on*/
updatedInventory = inventoryService.load(inventory.getId());
assertThat(updatedInventory.getQuantityOnHand(), is(2D));
}
@Test
public void completeItemActionTest() throws Exception {
OrderRequestItem orderRequestItem = addOrderRequestItemToDB();
......
......@@ -600,7 +600,7 @@ public class RepositoryControllerTest extends AbstractApiV1Test {
/*@formatter:off*/
mockMvc
.perform(get(RepositoryController.CONTROLLER_URL.concat("/folder/download/{folderUuid}"), saved.getFolder().getUuid()))
.andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType("application/zip"))
.andExpect(header().string("Content-Disposition", "attachment; filename=\"ccc.zip\""))
......@@ -617,7 +617,7 @@ public class RepositoryControllerTest extends AbstractApiV1Test {
/*@formatter:off*/
MvcResult result = mockMvc
.perform(get(RepositoryController.CONTROLLER_URL.concat("/folder/download/{folderUuid}"), saved.getFolder().getUuid()))
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType("application/zip"))
.andExpect(header().string("Content-Disposition", "attachment; filename=\"ccc.zip\""))
......@@ -630,7 +630,7 @@ public class RepositoryControllerTest extends AbstractApiV1Test {
/*@formatter:off*/
mockMvc
.perform(get(RepositoryController.CONTROLLER_URL.concat("/file/extract/{fileUuid}"), zipFile.getUuid()))
.andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
// .andDo(org.springframework.test.web.servlet.result.MockMvcResultHandlers.print())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$", not(nullValue())))
......
......@@ -232,7 +232,9 @@ public abstract class AbstractServicesTest extends AbstractServiceTest {
inventory.setInventoryMaintenancePolicy(inventoryMaintenancePolicy);
inventory.setSite(DEFAULT_SITE);
inventory.setQuantityOnHand(2.);
inventory.setQuantityOnHandUnitCode(UNIT_OF_QUANTITY_SEED.value);
inventory.setDistributionCriticalQuantity(1.);
inventory.setDistributionDefaultQuantity(1.);
return inventory;
}
......@@ -391,6 +393,9 @@ public abstract class AbstractServicesTest extends AbstractServiceTest {
item.setInventory(inventory);
item.setOrderRequest(orderRequest);
item.setStatusCode(status);
item.setQuantityShipped(1.);
item.setDistributionFormCode(GERMPLASM_CODE_SD);
item.setQuantityShippedUnitCode(UNIT_OF_QUANTITY_SEED.value);
return orderRequestItemRepository.save(item);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment