in applications/order/src/main/java/org/apache/ofbiz/order/order/OrderServices.java [1212:1476]
public static void reserveInventory(Delegator delegator, LocalDispatcher dispatcher, GenericValue userLogin, Locale locale,
List<GenericValue> orderItemShipGroupInfo, List<String> dropShipGroupIds, Map<String, GenericValue> itemValuesBySeqId,
String orderTypeId, String productStoreId, List<String> resErrorMessages) throws GeneralException {
boolean isImmediatelyFulfilled = false;
GenericValue productStore = null;
if (UtilValidate.isNotEmpty(productStoreId)) {
try {
productStore = EntityQuery.use(delegator).from("ProductStore").where("productStoreId", productStoreId).cache().queryOne();
} catch (GenericEntityException e) {
throw new GeneralException(UtilProperties.getMessage(RES_ERROR,
"OrderErrorCouldNotFindProductStoreWithID",
UtilMisc.toMap("productStoreId", productStoreId), locale) + e.toString());
}
}
if (productStore != null) {
isImmediatelyFulfilled = "Y".equals(productStore.getString("isImmediatelyFulfilled"));
}
boolean reserveInventory = ("SALES_ORDER".equals(orderTypeId));
if (reserveInventory && isImmediatelyFulfilled) {
// don't reserve inventory if the product store has isImmediatelyFulfilled set, ie don't if in this store things are immediately fulfilled
reserveInventory = false;
}
// START inventory reservation
// decrement inventory available for each OrderItemShipGroupAssoc, within the same transaction
if (UtilValidate.isNotEmpty(orderItemShipGroupInfo)) {
for (GenericValue orderItemShipGroupAssoc : orderItemShipGroupInfo) {
if ("OrderItemShipGroupAssoc".equals(orderItemShipGroupAssoc.getEntityName())) {
if (dropShipGroupIds != null && dropShipGroupIds.contains(orderItemShipGroupAssoc.getString("shipGroupSeqId"))) {
// the items in the drop ship groups are not reserved
continue;
}
GenericValue orderItem = itemValuesBySeqId.get(orderItemShipGroupAssoc.get("orderItemSeqId"));
if (orderItem != null) {
if ("SALES_ORDER".equals(orderTypeId) && productStore != null && "Y".equals(productStore.getString(
"allocateInventory"))) {
//If the 'autoReserve' flag is not set for the order item, don't reserve the inventory
String autoReserve = OrderReadHelper.getOrderItemAttribute(orderItem, "autoReserve");
if (autoReserve == null || !"true".equals(autoReserve)) {
continue;
}
}
if ("SALES_ORDER".equals(orderTypeId)) {
//If the 'reserveAfterDate' is not yet come don't reserve the inventory
Timestamp reserveAfterDate = orderItem.getTimestamp("reserveAfterDate");
if (UtilValidate.isNotEmpty(reserveAfterDate) && reserveAfterDate.after(UtilDateTime.nowTimestamp())) {
continue;
}
}
GenericValue orderItemShipGroup = orderItemShipGroupAssoc.getRelatedOne("OrderItemShipGroup", false);
String shipGroupFacilityId = orderItemShipGroup.getString("facilityId");
String itemStatus = null;
itemStatus = orderItem.getString("statusId");
if ("ITEM_REJECTED".equals(itemStatus)
|| "ITEM_CANCELLED".equals(itemStatus)
|| "ITEM_COMPLETED".equals(itemStatus)) {
Debug.logInfo("Order item [" + orderItem.getString("orderId") + " / " + orderItem.getString("orderItemSeqId")
+ "] is not in a proper status for reservation", MODULE);
continue;
}
if (UtilValidate.isNotEmpty(orderItem.getString("productId"))
// only reserve product items, ignore non-product items
&& !"RENTAL_ORDER_ITEM".equals(orderItem.getString("orderItemTypeId"))) { // ignore for rental
try {
// get the product of the order item
GenericValue product = orderItem.getRelatedOne("Product", false);
if (product == null) {
Debug.logError("Error when looking up product in reserveInventory service", MODULE);
resErrorMessages.add("Error when looking up product in reserveInventory service");
continue;
}
if (reserveInventory) {
// for MARKETING_PKG_PICK reserve the components
if (EntityTypeUtil.hasParentType(delegator, "ProductType", "productTypeId", product.getString("productTypeId"),
"parentTypeId", "MARKETING_PKG_PICK")) {
Map<String, Object> componentsRes = dispatcher.runSync("getAssociatedProducts", UtilMisc.toMap("productId",
orderItem.getString("productId"), "type", "PRODUCT_COMPONENT"));
if (ServiceUtil.isError(componentsRes)) {
resErrorMessages.add(ServiceUtil.getErrorMessage(componentsRes));
continue;
}
List<GenericValue> assocProducts = UtilGenerics.cast(componentsRes.get("assocProducts"));
for (GenericValue productAssoc : assocProducts) {
BigDecimal quantityOrd = productAssoc.getBigDecimal("quantity");
BigDecimal quantityKit = orderItemShipGroupAssoc.getBigDecimal("quantity");
BigDecimal quantity = quantityOrd.multiply(quantityKit);
Map<String, Object> reserveInput = new HashMap<>();
reserveInput.put("productStoreId", productStoreId);
reserveInput.put("productId", productAssoc.getString("productIdTo"));
reserveInput.put("orderId", orderItem.getString("orderId"));
reserveInput.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
reserveInput.put("shipGroupSeqId", orderItemShipGroupAssoc.getString("shipGroupSeqId"));
reserveInput.put("quantity", quantity);
reserveInput.put("userLogin", userLogin);
reserveInput.put("facilityId", shipGroupFacilityId);
Map<String, Object> reserveResult = dispatcher.runSync("reserveStoreInventory", reserveInput);
if (ServiceUtil.isError(reserveResult)) {
String invErrMsg = "The product ";
invErrMsg += getProductName(product, orderItem);
invErrMsg += " with ID " + orderItem.getString("productId") + " is no longer in stock. Please try "
+ "reducing the quantity or removing the product from this order.";
resErrorMessages.add(invErrMsg);
}
}
} else {
// reserve the product
Map<String, Object> reserveInput = new HashMap<>();
reserveInput.put("productStoreId", productStoreId);
reserveInput.put("productId", orderItem.getString("productId"));
reserveInput.put("orderId", orderItem.getString("orderId"));
reserveInput.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
reserveInput.put("shipGroupSeqId", orderItemShipGroupAssoc.getString("shipGroupSeqId"));
reserveInput.put("facilityId", shipGroupFacilityId);
// use the qty from the orderItemShipGroupAssoc, NOT the orderItem, these are reserved by item-group assoc
reserveInput.put("quantity", orderItemShipGroupAssoc.getBigDecimal("quantity"));
reserveInput.put("userLogin", userLogin);
Map<String, Object> reserveResult = dispatcher.runSync("reserveStoreInventory", reserveInput);
if (ServiceUtil.isError(reserveResult)) {
String invErrMsg = "The product ";
invErrMsg += getProductName(product, orderItem);
invErrMsg += " with ID " + orderItem.getString("productId")
+ " is no longer in stock. Please try reducing "
+ "the quantity or removing the product from this order.";
resErrorMessages.add(invErrMsg);
}
}
}
// Reserving inventory or not we still need to create a marketing package
// If the product is a marketing package auto, attempt to create enough packages to bring ATP back to 0, won't
// necessarily create enough to cover this order.
if (EntityTypeUtil.hasParentType(delegator, "ProductType", "productTypeId", product.getString("productTypeId"),
"parentTypeId", "MARKETING_PKG_AUTO")) {
// do something tricky here: run as the "system" user
// that can actually create and run a production run
GenericValue permUserLogin =
EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").cache().queryOne();
Map<String, Object> inputMap = new HashMap<>();
if (UtilValidate.isNotEmpty(shipGroupFacilityId)) {
inputMap.put("facilityId", shipGroupFacilityId);
} else {
inputMap.put("facilityId", productStore.getString("inventoryFacilityId"));
}
inputMap.put("orderId", orderItem.getString("orderId"));
inputMap.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
inputMap.put("userLogin", permUserLogin);
Map<String, Object> prunResult = dispatcher.runSync("createProductionRunForMktgPkg", inputMap);
if (ServiceUtil.isError(prunResult)) {
Debug.logError(ServiceUtil.getErrorMessage(prunResult) + " for input:" + inputMap, MODULE);
}
}
} catch (GenericServiceException e) {
String errMsg = "Fatal error calling reserveStoreInventory service: " + e.toString();
Debug.logError(e, errMsg, MODULE);
resErrorMessages.add(errMsg);
}
}
// rent item
if (UtilValidate.isNotEmpty(orderItem.getString("productId"))
&& "RENTAL_ORDER_ITEM".equals(orderItem.getString("orderItemTypeId"))) {
try {
// get the product of the order item
GenericValue product = orderItem.getRelatedOne("Product", false);
if (product == null) {
Debug.logError("Error when looking up product in reserveInventory service", MODULE);
resErrorMessages.add("Error when looking up product in reserveInventory service");
continue;
}
// check product type for rent
String productType = (String) product.get("productTypeId");
if ("ASSET_USAGE_OUT_IN".equals(productType)) {
if (reserveInventory) {
// for MARKETING_PKG_PICK reserve the components
if (EntityTypeUtil.hasParentType(delegator, "ProductType", "productTypeId",
product.getString("productTypeId"), "parentTypeId", "MARKETING_PKG_PICK")) {
Map<String, Object> componentsRes = dispatcher.runSync("getAssociatedProducts",
UtilMisc.toMap("productId", orderItem.getString("productId"),
"type", "PRODUCT_COMPONENT"));
if (ServiceUtil.isError(componentsRes)) {
resErrorMessages.add((String) componentsRes.get(ModelService.ERROR_MESSAGE));
continue;
}
List<GenericValue> assocProducts = UtilGenerics.cast(componentsRes.get("assocProducts"));
for (GenericValue productAssoc : assocProducts) {
BigDecimal quantityOrd = productAssoc.getBigDecimal("quantity");
BigDecimal quantityKit = orderItemShipGroupAssoc.getBigDecimal("quantity");
BigDecimal quantity = quantityOrd.multiply(quantityKit);
Map<String, Object> reserveInput = new HashMap<>();
reserveInput.put("productStoreId", productStoreId);
reserveInput.put("productId", productAssoc.getString("productIdTo"));
reserveInput.put("orderId", orderItem.getString("orderId"));
reserveInput.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
reserveInput.put("shipGroupSeqId", orderItemShipGroupAssoc.getString("shipGroupSeqId"));
reserveInput.put("quantity", quantity);
reserveInput.put("userLogin", userLogin);
reserveInput.put("facilityId", shipGroupFacilityId);
Map<String, Object> reserveResult = dispatcher.runSync("reserveStoreInventory", reserveInput);
if (ServiceUtil.isError(reserveResult)) {
String invErrMsg = "The product ";
invErrMsg += getProductName(product, orderItem);
invErrMsg += " with ID " + orderItem.getString("productId")
+ " is no longer in stock. Please try "
+ "reducing the quantity or removing the product from this order.";
resErrorMessages.add(invErrMsg);
}
}
} else {
// reserve the product
Map<String, Object> reserveInput = new HashMap<>();
reserveInput.put("productStoreId", productStoreId);
reserveInput.put("productId", orderItem.getString("productId"));
reserveInput.put("orderId", orderItem.getString("orderId"));
reserveInput.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
reserveInput.put("shipGroupSeqId", orderItemShipGroupAssoc.getString("shipGroupSeqId"));
reserveInput.put("facilityId", shipGroupFacilityId);
// use the quantity from the orderItemShipGroupAssoc, NOT the orderItem, these are reserved by item-group
// assoc
reserveInput.put("quantity", orderItemShipGroupAssoc.getBigDecimal("quantity"));
reserveInput.put("userLogin", userLogin);
Map<String, Object> reserveResult = dispatcher.runSync("reserveStoreInventory", reserveInput);
if (ServiceUtil.isError(reserveResult)) {
String invErrMsg = "The product ";
invErrMsg += getProductName(product, orderItem);
invErrMsg += " with ID " + orderItem.getString("productId") + " is no longer in stock. Please try "
+ "reducing the quantity or removing the product from this order.";
resErrorMessages.add(invErrMsg);
}
}
}
if (EntityTypeUtil.hasParentType(delegator, "ProductType", "productTypeId",
product.getString("productTypeId"), "parentTypeId", "MARKETING_PKG_AUTO")) {
GenericValue permUserLogin =
EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").cache().queryOne();
Map<String, Object> inputMap = new HashMap<>();
if (UtilValidate.isNotEmpty(shipGroupFacilityId)) {
inputMap.put("facilityId", shipGroupFacilityId);
} else {
inputMap.put("facilityId", productStore.getString("inventoryFacilityId"));
}
inputMap.put("orderId", orderItem.getString("orderId"));
inputMap.put("orderItemSeqId", orderItem.getString("orderItemSeqId"));
inputMap.put("userLogin", permUserLogin);
Map<String, Object> prunResult = dispatcher.runSync("createProductionRunForMktgPkg", inputMap);
if (ServiceUtil.isError(prunResult)) {
Debug.logError(ServiceUtil.getErrorMessage(prunResult) + " for input:" + inputMap, MODULE);
}
}
}
} catch (GenericServiceException e) {
String errMsg = "Fatal error calling reserveStoreInventory service: " + e.toString();
Debug.logError(e, errMsg, MODULE);
resErrorMessages.add(errMsg);
}
}
}
}
}
}
}