public static void reserveInventory()

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);
                            }
                        }
                    }
                }
            }
        }
    }