Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/requirement/RequirementServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/requirement/RequirementServices.java?rev=1695126&r1=1695125&r2=1695126&view=diff ============================================================================== --- ofbiz/trunk/applications/order/src/org/ofbiz/order/requirement/RequirementServices.java (original) +++ ofbiz/trunk/applications/order/src/org/ofbiz/order/requirement/RequirementServices.java Mon Aug 10 16:15:37 2015 @@ -1,332 +1,332 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.ofbiz.order.requirement; - -import java.util.*; -import java.math.BigDecimal; -import java.sql.Timestamp; - -import org.ofbiz.base.util.*; -import org.ofbiz.entity.condition.*; -import org.ofbiz.entity.Delegator; -import org.ofbiz.entity.GenericEntityException; -import org.ofbiz.entity.GenericValue; -import org.ofbiz.entity.util.EntityQuery; -import org.ofbiz.entity.util.EntityUtil; -import org.ofbiz.service.DispatchContext; -import org.ofbiz.service.GenericServiceException; -import org.ofbiz.service.LocalDispatcher; -import org.ofbiz.service.ServiceUtil; - -/** - * Requirement Services - */ - -public class RequirementServices { - - public static final String module = RequirementServices.class.getName(); - public static final String resource_error = "OrderErrorUiLabels"; - - public static Map<String, Object> getRequirementsForSupplier(DispatchContext ctx, Map<String, ? extends Object> context) { - Delegator delegator = ctx.getDelegator(); - LocalDispatcher dispatcher = ctx.getDispatcher(); - Locale locale = (Locale) context.get("locale"); - - EntityCondition requirementConditions = (EntityCondition) context.get("requirementConditions"); - String partyId = (String) context.get("partyId"); - String unassignedRequirements = (String) context.get("unassignedRequirements"); - List<String> statusIds = UtilGenerics.checkList(context.get("statusIds")); - //TODO currencyUomId still not used - //String currencyUomId = (String) context.get("currencyUomId"); - try { - List<EntityCondition> conditions = UtilMisc.toList( - EntityCondition.makeCondition("requirementTypeId", EntityOperator.EQUALS, "PRODUCT_REQUIREMENT"), - EntityUtil.getFilterByDateExpr() - ); - if (UtilValidate.isNotEmpty(statusIds)) { - conditions.add(EntityCondition.makeCondition("statusId", EntityOperator.IN, statusIds)); - } else { - conditions.add(EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "REQ_APPROVED")); - } - if (requirementConditions != null) conditions.add(requirementConditions); - - // we're either getting the requirements for a given supplier, unassigned requirements, or requirements for all suppliers - if (UtilValidate.isNotEmpty(partyId)) { - conditions.add(EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, partyId)); - conditions.add(EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "SUPPLIER")); - } else if (UtilValidate.isNotEmpty(unassignedRequirements)) { - conditions.add(EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, null)); - } else { - conditions.add(EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "SUPPLIER")); - } - - List<GenericValue> requirementAndRoles = EntityQuery.use(delegator).from("RequirementAndRole") - .where(conditions) - .orderBy("partyId", "requirementId") - .queryList(); - - // maps to cache the associated suppliers and products data, so we don't do redundant DB and service requests - Map<String, GenericValue> suppliers = new HashMap<String, GenericValue>(); - Map<String, GenericValue> gids = new HashMap<String, GenericValue>(); - Map<String, Map<String, Object>> inventories = new HashMap<String, Map<String,Object>>(); - Map<String, BigDecimal> productsSold = new HashMap<String, BigDecimal>(); - - // to count quantity, running total, and distinct products in list - BigDecimal quantity = BigDecimal.ZERO; - BigDecimal amountTotal = BigDecimal.ZERO; - Set<String> products = new HashSet<String>(); - - // time period to count products ordered from, six months ago and the 1st of that month - Timestamp timePeriodStart = UtilDateTime.getMonthStart(UtilDateTime.nowTimestamp(), 0, -6); - - // join in fields with extra data about the suppliers and products - List<Map<String, Object>> requirements = new LinkedList<Map<String,Object>>(); - for (GenericValue requirement : requirementAndRoles) { - Map<String, Object> union = new HashMap<String, Object>(); - String productId = requirement.getString("productId"); - partyId = requirement.getString("partyId"); - String facilityId = requirement.getString("facilityId"); - BigDecimal requiredQuantity = requirement.getBigDecimal("quantity"); - - // get an available supplier product, preferably the one with the smallest minimum quantity to order, followed by price - String supplierKey = partyId + "^" + productId; - GenericValue supplierProduct = suppliers.get(supplierKey); - if (supplierProduct == null) { - // TODO: it is possible to restrict to quantity > minimumOrderQuantity, but then the entire requirement must be skipped - supplierProduct = EntityQuery.use(delegator).from("SupplierProduct") - .where("partyId", partyId, "productId", productId) - .orderBy("minimumOrderQuantity", "lastPrice") - .filterByDate("availableFromDate", "availableThruDate") - .queryFirst(); - suppliers.put(supplierKey, supplierProduct); - } - - // add our supplier product and cost of this line to the data - if (supplierProduct != null) { - union.putAll(supplierProduct.getAllFields()); - BigDecimal lastPrice = supplierProduct.getBigDecimal("lastPrice"); - amountTotal = amountTotal.add(lastPrice.multiply(requiredQuantity)); - } - - // for good identification, get the UPCA type (UPC code) - GenericValue gid = gids.get(productId); - if (gid == null) { - gid = EntityQuery.use(delegator).from("GoodIdentification").where("goodIdentificationTypeId", "UPCA", "productId", requirement.get("productId")).queryOne(); - gids.put(productId, gid); - } - if (gid != null) union.put("idValue", gid.get("idValue")); - - // the ATP and QOH quantities - if (UtilValidate.isNotEmpty(facilityId)) { - String inventoryKey = facilityId + "^" + productId; - Map<String, Object> inventory = inventories.get(inventoryKey); - if (inventory == null) { - inventory = dispatcher.runSync("getInventoryAvailableByFacility", UtilMisc.toMap("productId", productId, "facilityId", facilityId)); - if (ServiceUtil.isError(inventory)) { - return inventory; - } - inventories.put(inventoryKey, inventory); - } - if (inventory != null) { - union.put("qoh", inventory.get("quantityOnHandTotal")); - union.put("atp", inventory.get("availableToPromiseTotal")); - } - } - - // how many of the products were sold (note this is for a fixed time period across all product stores) - BigDecimal sold = productsSold.get(productId); - if (sold == null) { - EntityCondition prodConditions = EntityCondition.makeCondition(UtilMisc.toList( - EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId), - EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "SALES_ORDER"), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_IN, UtilMisc.toList("ORDER_REJECTED", "ORDER_CANCELLED")), - EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_IN, UtilMisc.toList("ITEM_REJECTED", "ITEM_CANCELLED")), - EntityCondition.makeCondition("orderDate", EntityOperator.GREATER_THAN_EQUAL_TO, timePeriodStart) - ), EntityOperator.AND); - GenericValue count = EntityQuery.use(delegator).select("quantityOrdered").from("OrderItemQuantityReportGroupByProduct").where(prodConditions).queryFirst(); - if (count != null) { - sold = count.getBigDecimal("quantityOrdered"); - if (sold != null) productsSold.put(productId, sold); - } - } - if (sold != null) { - union.put("qtySold", sold); - } - - // keep a running total of distinct products and quantity to order - if (requirement.getBigDecimal("quantity") == null) requirement.put("quantity", BigDecimal.ONE); // default quantity = 1 - quantity = quantity.add(requiredQuantity); - products.add(productId); - - // add all the requirement fields last, to overwrite any conflicting fields - union.putAll(requirement.getAllFields()); - requirements.add(union); - } - - Map<String, Object> results = ServiceUtil.returnSuccess(); - results.put("requirementsForSupplier", requirements); - results.put("distinctProductCount", Integer.valueOf(products.size())); - results.put("quantityTotal", quantity); - results.put("amountTotal", amountTotal); - return results; - } catch (GenericServiceException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderServiceExceptionSeeLogs", locale)); - } catch (GenericEntityException e) { - Debug.logError(e, module); - return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderEntityExceptionSeeLogs", locale)); - } - } - - // note that this service is designed to work only when a sales order status changes from CREATED -> APPROVED because HOLD -> APPROVED is too complex - public static Map<String, Object> createAutoRequirementsForOrder(DispatchContext ctx, Map<String, ? extends Object> context) { - Delegator delegator = ctx.getDelegator(); - LocalDispatcher dispatcher = ctx.getDispatcher(); - GenericValue userLogin = (GenericValue) context.get("userLogin"); - - String orderId = (String) context.get("orderId"); - try { - GenericValue order = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); - GenericValue productStore = order.getRelatedOne("ProductStore", true); - if (productStore == null) { - Debug.logInfo("ProductStore for order ID " + orderId + " not found, requirements not created", module); - return ServiceUtil.returnSuccess(); - } - String facilityId = productStore.getString("inventoryFacilityId"); - List<GenericValue> orderItems = order.getRelated("OrderItem", null, null, false); - for (GenericValue item : orderItems) { - GenericValue product = item.getRelatedOne("Product", false); - if (product == null) continue; - if ((!"PRODRQM_AUTO".equals(product.get("requirementMethodEnumId")) && - !"PRODRQM_AUTO".equals(productStore.get("requirementMethodEnumId"))) || - (product.get("requirementMethodEnumId") == null && - !"PRODRQM_AUTO".equals(productStore.get("requirementMethodEnumId")))) continue; - BigDecimal quantity = item.getBigDecimal("quantity"); - BigDecimal cancelQuantity = item.getBigDecimal("cancelQuantity"); - BigDecimal required = quantity.subtract(cancelQuantity == null ? BigDecimal.ZERO : cancelQuantity); - if (required.compareTo(BigDecimal.ZERO) <= 0) continue; - - Map<String, Object> input = UtilMisc.toMap("userLogin", userLogin, "facilityId", facilityId, "productId", product.get("productId"), "quantity", required, "requirementTypeId", "PRODUCT_REQUIREMENT"); - Map<String, Object> results = dispatcher.runSync("createRequirement", input); - if (ServiceUtil.isError(results)) return results; - String requirementId = (String) results.get("requirementId"); - - input = UtilMisc.toMap("userLogin", userLogin, "orderId", order.get("orderId"), "orderItemSeqId", item.get("orderItemSeqId"), "requirementId", requirementId, "quantity", required); - results = dispatcher.runSync("createOrderRequirementCommitment", input); - if (ServiceUtil.isError(results)) return results; - } - } catch (GenericEntityException e) { - Debug.logError(e, module); - } catch (GenericServiceException e) { - Debug.logError(e, module); - } - return ServiceUtil.returnSuccess(); - } - - // note that this service is designed to work only when a sales order status changes from CREATED -> APPROVED because HOLD -> APPROVED is too complex - public static Map<String, Object> createATPRequirementsForOrder(DispatchContext ctx, Map<String, ? extends Object> context) { - Delegator delegator = ctx.getDelegator(); - LocalDispatcher dispatcher = ctx.getDispatcher(); - GenericValue userLogin = (GenericValue) context.get("userLogin"); - - /* - * The strategy in this service is to begin making requirements when the product falls below the - * ProductFacility.minimumStock. Because the minimumStock is an upper bound, the quantity to be required - * is either that required to bring the ATP back up to the minimumStock level or the amount ordered, - * whichever is less. - * - * If there is a way to support reorderQuantity without losing the order item -> requirement association data, - * then this service should be updated. - * - * The result is that this service generates many small requirements when stock levels are low for a product, - * which is perfectly fine since the system is capable of creating POs in bulk from aggregate requirements. - * The only concern would be a UI to manage numerous requirements with ease, preferrably by aggregating - * on productId. - */ - String orderId = (String) context.get("orderId"); - try { - GenericValue order = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); - GenericValue productStore = order.getRelatedOne("ProductStore", true); - if (productStore == null) { - Debug.logInfo("ProductStore for order ID " + orderId + " not found, ATP requirements not created", module); - return ServiceUtil.returnSuccess(); - } - String facilityId = productStore.getString("inventoryFacilityId"); - List<GenericValue> orderItems = order.getRelated("OrderItem", null, null, false); - for (GenericValue item : orderItems) { - GenericValue product = item.getRelatedOne("Product", false); - if (product == null) continue; - - if (!("PRODRQM_ATP".equals(product.get("requirementMethodEnumId")) || - ("PRODRQM_ATP".equals(productStore.get("requirementMethodEnumId")) && product.get("requirementMethodEnumId") == null))) continue; - - BigDecimal quantity = item.getBigDecimal("quantity"); - BigDecimal cancelQuantity = item.getBigDecimal("cancelQuantity"); - BigDecimal ordered = quantity.subtract(cancelQuantity == null ? BigDecimal.ZERO : cancelQuantity); - if (ordered.compareTo(BigDecimal.ZERO) <= 0) continue; - - // get the minimum stock for this facility (if not configured assume a minimum of zero, ie create requirements when it goes into backorder) - GenericValue productFacility = EntityQuery.use(delegator).from("ProductFacility").where("facilityId", facilityId, "productId", product.get("productId")).queryOne(); - BigDecimal minimumStock = BigDecimal.ZERO; - if (productFacility != null && productFacility.get("minimumStock") != null) { - minimumStock = productFacility.getBigDecimal("minimumStock"); - } - - // get the facility ATP for product, which should be updated for this item's reservation - Map<String, Object> results = dispatcher.runSync("getInventoryAvailableByFacility", UtilMisc.toMap("userLogin", userLogin, "productId", product.get("productId"), "facilityId", facilityId)); - if (ServiceUtil.isError(results)) return results; - BigDecimal atp = ((BigDecimal) results.get("availableToPromiseTotal")); // safe since this is a required OUT param - - // count all current requirements for this product - BigDecimal pendingRequirements = BigDecimal.ZERO; - EntityConditionList<EntityExpr> ecl = EntityCondition.makeCondition(UtilMisc.toList( - EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, facilityId), - EntityCondition.makeCondition("productId", EntityOperator.EQUALS, product.get("productId")), - EntityCondition.makeCondition("requirementTypeId", EntityOperator.EQUALS, "PRODUCT_REQUIREMENT"), - EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "REQ_ORDERED"), - EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "REQ_REJECTED")), - EntityOperator.AND); - List<GenericValue> requirements = EntityQuery.use(delegator).from("Requirement").where(ecl).queryList(); - for (GenericValue requirement : requirements) { - pendingRequirements = pendingRequirements.add(requirement.get("quantity") == null ? BigDecimal.ZERO : requirement.getBigDecimal("quantity")); - } - - // the minimum stock is an upper bound, therefore we either require up to the minimum stock or the input required quantity, whichever is less - BigDecimal shortfall = minimumStock.subtract(atp).subtract(pendingRequirements); - BigDecimal required = ordered.compareTo(shortfall) < 0 ? ordered : shortfall; - if (required.compareTo(BigDecimal.ZERO) <= 0) continue; - - Map<String, Object> input = UtilMisc.toMap("userLogin", userLogin, "facilityId", facilityId, "productId", product.get("productId"), "quantity", required, "requirementTypeId", "PRODUCT_REQUIREMENT"); - results = dispatcher.runSync("createRequirement", input); - if (ServiceUtil.isError(results)) return results; - String requirementId = (String) results.get("requirementId"); - - input = UtilMisc.toMap("userLogin", userLogin, "orderId", order.get("orderId"), "orderItemSeqId", item.get("orderItemSeqId"), "requirementId", requirementId, "quantity", required); - results = dispatcher.runSync("createOrderRequirementCommitment", input); - if (ServiceUtil.isError(results)) return results; - } - } catch (GenericEntityException e) { - Debug.logError(e, module); - } catch (GenericServiceException e) { - Debug.logError(e, module); - } - return ServiceUtil.returnSuccess(); - } -} - +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.ofbiz.order.requirement; + +import java.util.*; +import java.math.BigDecimal; +import java.sql.Timestamp; + +import org.ofbiz.base.util.*; +import org.ofbiz.entity.condition.*; +import org.ofbiz.entity.Delegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.util.EntityQuery; +import org.ofbiz.entity.util.EntityUtil; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.GenericServiceException; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.service.ServiceUtil; + +/** + * Requirement Services + */ + +public class RequirementServices { + + public static final String module = RequirementServices.class.getName(); + public static final String resource_error = "OrderErrorUiLabels"; + + public static Map<String, Object> getRequirementsForSupplier(DispatchContext ctx, Map<String, ? extends Object> context) { + Delegator delegator = ctx.getDelegator(); + LocalDispatcher dispatcher = ctx.getDispatcher(); + Locale locale = (Locale) context.get("locale"); + + EntityCondition requirementConditions = (EntityCondition) context.get("requirementConditions"); + String partyId = (String) context.get("partyId"); + String unassignedRequirements = (String) context.get("unassignedRequirements"); + List<String> statusIds = UtilGenerics.checkList(context.get("statusIds")); + //TODO currencyUomId still not used + //String currencyUomId = (String) context.get("currencyUomId"); + try { + List<EntityCondition> conditions = UtilMisc.toList( + EntityCondition.makeCondition("requirementTypeId", EntityOperator.EQUALS, "PRODUCT_REQUIREMENT"), + EntityUtil.getFilterByDateExpr() + ); + if (UtilValidate.isNotEmpty(statusIds)) { + conditions.add(EntityCondition.makeCondition("statusId", EntityOperator.IN, statusIds)); + } else { + conditions.add(EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, "REQ_APPROVED")); + } + if (requirementConditions != null) conditions.add(requirementConditions); + + // we're either getting the requirements for a given supplier, unassigned requirements, or requirements for all suppliers + if (UtilValidate.isNotEmpty(partyId)) { + conditions.add(EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, partyId)); + conditions.add(EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "SUPPLIER")); + } else if (UtilValidate.isNotEmpty(unassignedRequirements)) { + conditions.add(EntityCondition.makeCondition("partyId", EntityOperator.EQUALS, null)); + } else { + conditions.add(EntityCondition.makeCondition("roleTypeId", EntityOperator.EQUALS, "SUPPLIER")); + } + + List<GenericValue> requirementAndRoles = EntityQuery.use(delegator).from("RequirementAndRole") + .where(conditions) + .orderBy("partyId", "requirementId") + .queryList(); + + // maps to cache the associated suppliers and products data, so we don't do redundant DB and service requests + Map<String, GenericValue> suppliers = new HashMap<String, GenericValue>(); + Map<String, GenericValue> gids = new HashMap<String, GenericValue>(); + Map<String, Map<String, Object>> inventories = new HashMap<String, Map<String,Object>>(); + Map<String, BigDecimal> productsSold = new HashMap<String, BigDecimal>(); + + // to count quantity, running total, and distinct products in list + BigDecimal quantity = BigDecimal.ZERO; + BigDecimal amountTotal = BigDecimal.ZERO; + Set<String> products = new HashSet<String>(); + + // time period to count products ordered from, six months ago and the 1st of that month + Timestamp timePeriodStart = UtilDateTime.getMonthStart(UtilDateTime.nowTimestamp(), 0, -6); + + // join in fields with extra data about the suppliers and products + List<Map<String, Object>> requirements = new LinkedList<Map<String,Object>>(); + for (GenericValue requirement : requirementAndRoles) { + Map<String, Object> union = new HashMap<String, Object>(); + String productId = requirement.getString("productId"); + partyId = requirement.getString("partyId"); + String facilityId = requirement.getString("facilityId"); + BigDecimal requiredQuantity = requirement.getBigDecimal("quantity"); + + // get an available supplier product, preferably the one with the smallest minimum quantity to order, followed by price + String supplierKey = partyId + "^" + productId; + GenericValue supplierProduct = suppliers.get(supplierKey); + if (supplierProduct == null) { + // TODO: it is possible to restrict to quantity > minimumOrderQuantity, but then the entire requirement must be skipped + supplierProduct = EntityQuery.use(delegator).from("SupplierProduct") + .where("partyId", partyId, "productId", productId) + .orderBy("minimumOrderQuantity", "lastPrice") + .filterByDate("availableFromDate", "availableThruDate") + .queryFirst(); + suppliers.put(supplierKey, supplierProduct); + } + + // add our supplier product and cost of this line to the data + if (supplierProduct != null) { + union.putAll(supplierProduct.getAllFields()); + BigDecimal lastPrice = supplierProduct.getBigDecimal("lastPrice"); + amountTotal = amountTotal.add(lastPrice.multiply(requiredQuantity)); + } + + // for good identification, get the UPCA type (UPC code) + GenericValue gid = gids.get(productId); + if (gid == null) { + gid = EntityQuery.use(delegator).from("GoodIdentification").where("goodIdentificationTypeId", "UPCA", "productId", requirement.get("productId")).queryOne(); + gids.put(productId, gid); + } + if (gid != null) union.put("idValue", gid.get("idValue")); + + // the ATP and QOH quantities + if (UtilValidate.isNotEmpty(facilityId)) { + String inventoryKey = facilityId + "^" + productId; + Map<String, Object> inventory = inventories.get(inventoryKey); + if (inventory == null) { + inventory = dispatcher.runSync("getInventoryAvailableByFacility", UtilMisc.toMap("productId", productId, "facilityId", facilityId)); + if (ServiceUtil.isError(inventory)) { + return inventory; + } + inventories.put(inventoryKey, inventory); + } + if (inventory != null) { + union.put("qoh", inventory.get("quantityOnHandTotal")); + union.put("atp", inventory.get("availableToPromiseTotal")); + } + } + + // how many of the products were sold (note this is for a fixed time period across all product stores) + BigDecimal sold = productsSold.get(productId); + if (sold == null) { + EntityCondition prodConditions = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId), + EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "SALES_ORDER"), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_IN, UtilMisc.toList("ORDER_REJECTED", "ORDER_CANCELLED")), + EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_IN, UtilMisc.toList("ITEM_REJECTED", "ITEM_CANCELLED")), + EntityCondition.makeCondition("orderDate", EntityOperator.GREATER_THAN_EQUAL_TO, timePeriodStart) + ), EntityOperator.AND); + GenericValue count = EntityQuery.use(delegator).select("quantityOrdered").from("OrderItemQuantityReportGroupByProduct").where(prodConditions).queryFirst(); + if (count != null) { + sold = count.getBigDecimal("quantityOrdered"); + if (sold != null) productsSold.put(productId, sold); + } + } + if (sold != null) { + union.put("qtySold", sold); + } + + // keep a running total of distinct products and quantity to order + if (requirement.getBigDecimal("quantity") == null) requirement.put("quantity", BigDecimal.ONE); // default quantity = 1 + quantity = quantity.add(requiredQuantity); + products.add(productId); + + // add all the requirement fields last, to overwrite any conflicting fields + union.putAll(requirement.getAllFields()); + requirements.add(union); + } + + Map<String, Object> results = ServiceUtil.returnSuccess(); + results.put("requirementsForSupplier", requirements); + results.put("distinctProductCount", Integer.valueOf(products.size())); + results.put("quantityTotal", quantity); + results.put("amountTotal", amountTotal); + return results; + } catch (GenericServiceException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderServiceExceptionSeeLogs", locale)); + } catch (GenericEntityException e) { + Debug.logError(e, module); + return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderEntityExceptionSeeLogs", locale)); + } + } + + // note that this service is designed to work only when a sales order status changes from CREATED -> APPROVED because HOLD -> APPROVED is too complex + public static Map<String, Object> createAutoRequirementsForOrder(DispatchContext ctx, Map<String, ? extends Object> context) { + Delegator delegator = ctx.getDelegator(); + LocalDispatcher dispatcher = ctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String orderId = (String) context.get("orderId"); + try { + GenericValue order = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); + GenericValue productStore = order.getRelatedOne("ProductStore", true); + if (productStore == null) { + Debug.logInfo("ProductStore for order ID " + orderId + " not found, requirements not created", module); + return ServiceUtil.returnSuccess(); + } + String facilityId = productStore.getString("inventoryFacilityId"); + List<GenericValue> orderItems = order.getRelated("OrderItem", null, null, false); + for (GenericValue item : orderItems) { + GenericValue product = item.getRelatedOne("Product", false); + if (product == null) continue; + if ((!"PRODRQM_AUTO".equals(product.get("requirementMethodEnumId")) && + !"PRODRQM_AUTO".equals(productStore.get("requirementMethodEnumId"))) || + (product.get("requirementMethodEnumId") == null && + !"PRODRQM_AUTO".equals(productStore.get("requirementMethodEnumId")))) continue; + BigDecimal quantity = item.getBigDecimal("quantity"); + BigDecimal cancelQuantity = item.getBigDecimal("cancelQuantity"); + BigDecimal required = quantity.subtract(cancelQuantity == null ? BigDecimal.ZERO : cancelQuantity); + if (required.compareTo(BigDecimal.ZERO) <= 0) continue; + + Map<String, Object> input = UtilMisc.toMap("userLogin", userLogin, "facilityId", facilityId, "productId", product.get("productId"), "quantity", required, "requirementTypeId", "PRODUCT_REQUIREMENT"); + Map<String, Object> results = dispatcher.runSync("createRequirement", input); + if (ServiceUtil.isError(results)) return results; + String requirementId = (String) results.get("requirementId"); + + input = UtilMisc.toMap("userLogin", userLogin, "orderId", order.get("orderId"), "orderItemSeqId", item.get("orderItemSeqId"), "requirementId", requirementId, "quantity", required); + results = dispatcher.runSync("createOrderRequirementCommitment", input); + if (ServiceUtil.isError(results)) return results; + } + } catch (GenericEntityException e) { + Debug.logError(e, module); + } catch (GenericServiceException e) { + Debug.logError(e, module); + } + return ServiceUtil.returnSuccess(); + } + + // note that this service is designed to work only when a sales order status changes from CREATED -> APPROVED because HOLD -> APPROVED is too complex + public static Map<String, Object> createATPRequirementsForOrder(DispatchContext ctx, Map<String, ? extends Object> context) { + Delegator delegator = ctx.getDelegator(); + LocalDispatcher dispatcher = ctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + /* + * The strategy in this service is to begin making requirements when the product falls below the + * ProductFacility.minimumStock. Because the minimumStock is an upper bound, the quantity to be required + * is either that required to bring the ATP back up to the minimumStock level or the amount ordered, + * whichever is less. + * + * If there is a way to support reorderQuantity without losing the order item -> requirement association data, + * then this service should be updated. + * + * The result is that this service generates many small requirements when stock levels are low for a product, + * which is perfectly fine since the system is capable of creating POs in bulk from aggregate requirements. + * The only concern would be a UI to manage numerous requirements with ease, preferrably by aggregating + * on productId. + */ + String orderId = (String) context.get("orderId"); + try { + GenericValue order = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); + GenericValue productStore = order.getRelatedOne("ProductStore", true); + if (productStore == null) { + Debug.logInfo("ProductStore for order ID " + orderId + " not found, ATP requirements not created", module); + return ServiceUtil.returnSuccess(); + } + String facilityId = productStore.getString("inventoryFacilityId"); + List<GenericValue> orderItems = order.getRelated("OrderItem", null, null, false); + for (GenericValue item : orderItems) { + GenericValue product = item.getRelatedOne("Product", false); + if (product == null) continue; + + if (!("PRODRQM_ATP".equals(product.get("requirementMethodEnumId")) || + ("PRODRQM_ATP".equals(productStore.get("requirementMethodEnumId")) && product.get("requirementMethodEnumId") == null))) continue; + + BigDecimal quantity = item.getBigDecimal("quantity"); + BigDecimal cancelQuantity = item.getBigDecimal("cancelQuantity"); + BigDecimal ordered = quantity.subtract(cancelQuantity == null ? BigDecimal.ZERO : cancelQuantity); + if (ordered.compareTo(BigDecimal.ZERO) <= 0) continue; + + // get the minimum stock for this facility (if not configured assume a minimum of zero, ie create requirements when it goes into backorder) + GenericValue productFacility = EntityQuery.use(delegator).from("ProductFacility").where("facilityId", facilityId, "productId", product.get("productId")).queryOne(); + BigDecimal minimumStock = BigDecimal.ZERO; + if (productFacility != null && productFacility.get("minimumStock") != null) { + minimumStock = productFacility.getBigDecimal("minimumStock"); + } + + // get the facility ATP for product, which should be updated for this item's reservation + Map<String, Object> results = dispatcher.runSync("getInventoryAvailableByFacility", UtilMisc.toMap("userLogin", userLogin, "productId", product.get("productId"), "facilityId", facilityId)); + if (ServiceUtil.isError(results)) return results; + BigDecimal atp = ((BigDecimal) results.get("availableToPromiseTotal")); // safe since this is a required OUT param + + // count all current requirements for this product + BigDecimal pendingRequirements = BigDecimal.ZERO; + EntityConditionList<EntityExpr> ecl = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, facilityId), + EntityCondition.makeCondition("productId", EntityOperator.EQUALS, product.get("productId")), + EntityCondition.makeCondition("requirementTypeId", EntityOperator.EQUALS, "PRODUCT_REQUIREMENT"), + EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "REQ_ORDERED"), + EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "REQ_REJECTED")), + EntityOperator.AND); + List<GenericValue> requirements = EntityQuery.use(delegator).from("Requirement").where(ecl).queryList(); + for (GenericValue requirement : requirements) { + pendingRequirements = pendingRequirements.add(requirement.get("quantity") == null ? BigDecimal.ZERO : requirement.getBigDecimal("quantity")); + } + + // the minimum stock is an upper bound, therefore we either require up to the minimum stock or the input required quantity, whichever is less + BigDecimal shortfall = minimumStock.subtract(atp).subtract(pendingRequirements); + BigDecimal required = ordered.compareTo(shortfall) < 0 ? ordered : shortfall; + if (required.compareTo(BigDecimal.ZERO) <= 0) continue; + + Map<String, Object> input = UtilMisc.toMap("userLogin", userLogin, "facilityId", facilityId, "productId", product.get("productId"), "quantity", required, "requirementTypeId", "PRODUCT_REQUIREMENT"); + results = dispatcher.runSync("createRequirement", input); + if (ServiceUtil.isError(results)) return results; + String requirementId = (String) results.get("requirementId"); + + input = UtilMisc.toMap("userLogin", userLogin, "orderId", order.get("orderId"), "orderItemSeqId", item.get("orderItemSeqId"), "requirementId", requirementId, "quantity", required); + results = dispatcher.runSync("createOrderRequirementCommitment", input); + if (ServiceUtil.isError(results)) return results; + } + } catch (GenericEntityException e) { + Debug.logError(e, module); + } catch (GenericServiceException e) { + Debug.logError(e, module); + } + return ServiceUtil.returnSuccess(); + } +} + Propchange: ofbiz/trunk/applications/order/src/org/ofbiz/order/requirement/RequirementServices.java ('svn:eol-style' removed) Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/inventory/InventoryWorker.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/inventory/InventoryWorker.java?rev=1695126&r1=1695125&r2=1695126&view=diff ============================================================================== --- ofbiz/trunk/applications/product/src/org/ofbiz/product/inventory/InventoryWorker.java (original) +++ ofbiz/trunk/applications/product/src/org/ofbiz/product/inventory/InventoryWorker.java Mon Aug 10 16:15:37 2015 @@ -1,147 +1,147 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.ofbiz.product.inventory; - -import java.math.BigDecimal; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.ofbiz.base.util.Debug; -import org.ofbiz.base.util.UtilMisc; -import org.ofbiz.base.util.UtilValidate; -import org.ofbiz.entity.Delegator; -import org.ofbiz.entity.GenericEntityException; -import org.ofbiz.entity.GenericValue; -import org.ofbiz.entity.condition.EntityCondition; -import org.ofbiz.entity.condition.EntityConditionList; -import org.ofbiz.entity.condition.EntityOperator; -import org.ofbiz.entity.util.EntityQuery; - -public class InventoryWorker { - - public final static String module = InventoryWorker.class.getName(); - - /** - * Finds all outstanding Purchase orders for a productId. The orders and the items cannot be completed, cancelled, or rejected - * @param productId the product id - * @param delegator the delegator - * @return returns all outstanding Purchase orders for a productId - */ - public static List<GenericValue> getOutstandingPurchaseOrders(String productId, Delegator delegator) { - try { - List<EntityCondition> purchaseOrderConditions = UtilMisc.<EntityCondition>toList(EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_COMPLETED"), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_CANCELLED"), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_REJECTED"), - EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_COMPLETED"), - EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_CANCELLED"), - EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_REJECTED")); - purchaseOrderConditions.add(EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "PURCHASE_ORDER")); - purchaseOrderConditions.add(EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId)); - List<GenericValue> purchaseOrders = EntityQuery.use(delegator).from("OrderHeaderAndItems") - .where(EntityCondition.makeCondition(purchaseOrderConditions, EntityOperator.AND)) - .orderBy("estimatedDeliveryDate DESC", "orderDate") - .queryList(); - return purchaseOrders; - } catch (GenericEntityException ex) { - Debug.logError("Unable to find outstanding purchase orders for product [" + productId + "] due to " + ex.getMessage() + " - returning null", module); - return null; - } - } - - /** - * Finds the net outstanding ordered quantity for a productId, netting quantity on outstanding purchase orders against cancelQuantity - * @param productId the product id - * @param delegator the delegator - * @return returns the net outstanding ordered quantity for a productId - */ - public static BigDecimal getOutstandingPurchasedQuantity(String productId, Delegator delegator) { - BigDecimal qty = BigDecimal.ZERO; - List<GenericValue> purchaseOrders = getOutstandingPurchaseOrders(productId, delegator); - if (UtilValidate.isEmpty(purchaseOrders)) { - return qty; - } else { - for (GenericValue nextOrder: purchaseOrders) { - if (nextOrder.get("quantity") != null) { - BigDecimal itemQuantity = nextOrder.getBigDecimal("quantity"); - BigDecimal cancelQuantity = BigDecimal.ZERO; - if (nextOrder.get("cancelQuantity") != null) { - cancelQuantity = nextOrder.getBigDecimal("cancelQuantity"); - } - itemQuantity = itemQuantity.subtract(cancelQuantity); - if (itemQuantity.compareTo(BigDecimal.ZERO) >= 0) { - qty = qty.add(itemQuantity); - } - } - } - } - - return qty; - } - - /** - * Gets the quanitty of each product in the order that is outstanding across all orders of the given input type. - * Uses the OrderItemQuantityReportGroupByProduct view entity. - * - * @param productIds Collection of disticnt productIds in an order. Use OrderReadHelper.getOrderProductIds() - * @param orderTypeId Either "SALES_ORDER" or "PURCHASE_ORDER" - * @param delegator The delegator to use - * @return Map of productIds to quantities outstanding. - */ - public static Map<String, BigDecimal> getOutstandingProductQuantities(Collection<String> productIds, String orderTypeId, Delegator delegator) { - Set<String> fieldsToSelect = UtilMisc.toSet("productId", "quantityOpen"); - List<EntityCondition> condList = UtilMisc.<EntityCondition>toList( - EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, orderTypeId), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_COMPLETED"), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_REJECTED"), - EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_CANCELLED") - ); - if (productIds.size() > 0) { - condList.add(EntityCondition.makeCondition("productId", EntityOperator.IN, productIds)); - } - condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_COMPLETED")); - condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_REJECTED")); - condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_CANCELLED")); - EntityConditionList<EntityCondition> conditions = EntityCondition.makeCondition(condList, EntityOperator.AND); - - Map<String, BigDecimal> results = new HashMap<String, BigDecimal>(); - try { - List<GenericValue> orderedProducts = EntityQuery.use(delegator).select(fieldsToSelect).from("OrderItemQuantityReportGroupByProduct").where(conditions).queryList(); - for (GenericValue value: orderedProducts) { - results.put(value.getString("productId"), value.getBigDecimal("quantityOpen")); - } - } catch (GenericEntityException e) { - Debug.logError(e, module); - } - return results; - } - - /** As above, but for sales orders */ - public static Map<String, BigDecimal> getOutstandingProductQuantitiesForSalesOrders(Collection<String> productIds, Delegator delegator) { - return getOutstandingProductQuantities(productIds, "SALES_ORDER", delegator); - } - - /** As above, but for purchase orders */ - public static Map<String, BigDecimal> getOutstandingProductQuantitiesForPurchaseOrders(Collection<String> productIds, Delegator delegator) { - return getOutstandingProductQuantities(productIds, "PURCHASE_ORDER", delegator); - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.ofbiz.product.inventory; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.ofbiz.base.util.Debug; +import org.ofbiz.base.util.UtilMisc; +import org.ofbiz.base.util.UtilValidate; +import org.ofbiz.entity.Delegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.condition.EntityCondition; +import org.ofbiz.entity.condition.EntityConditionList; +import org.ofbiz.entity.condition.EntityOperator; +import org.ofbiz.entity.util.EntityQuery; + +public class InventoryWorker { + + public final static String module = InventoryWorker.class.getName(); + + /** + * Finds all outstanding Purchase orders for a productId. The orders and the items cannot be completed, cancelled, or rejected + * @param productId the product id + * @param delegator the delegator + * @return returns all outstanding Purchase orders for a productId + */ + public static List<GenericValue> getOutstandingPurchaseOrders(String productId, Delegator delegator) { + try { + List<EntityCondition> purchaseOrderConditions = UtilMisc.<EntityCondition>toList(EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_COMPLETED"), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_CANCELLED"), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_REJECTED"), + EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_COMPLETED"), + EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_CANCELLED"), + EntityCondition.makeCondition("itemStatusId", EntityOperator.NOT_EQUAL, "ITEM_REJECTED")); + purchaseOrderConditions.add(EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "PURCHASE_ORDER")); + purchaseOrderConditions.add(EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId)); + List<GenericValue> purchaseOrders = EntityQuery.use(delegator).from("OrderHeaderAndItems") + .where(EntityCondition.makeCondition(purchaseOrderConditions, EntityOperator.AND)) + .orderBy("estimatedDeliveryDate DESC", "orderDate") + .queryList(); + return purchaseOrders; + } catch (GenericEntityException ex) { + Debug.logError("Unable to find outstanding purchase orders for product [" + productId + "] due to " + ex.getMessage() + " - returning null", module); + return null; + } + } + + /** + * Finds the net outstanding ordered quantity for a productId, netting quantity on outstanding purchase orders against cancelQuantity + * @param productId the product id + * @param delegator the delegator + * @return returns the net outstanding ordered quantity for a productId + */ + public static BigDecimal getOutstandingPurchasedQuantity(String productId, Delegator delegator) { + BigDecimal qty = BigDecimal.ZERO; + List<GenericValue> purchaseOrders = getOutstandingPurchaseOrders(productId, delegator); + if (UtilValidate.isEmpty(purchaseOrders)) { + return qty; + } else { + for (GenericValue nextOrder: purchaseOrders) { + if (nextOrder.get("quantity") != null) { + BigDecimal itemQuantity = nextOrder.getBigDecimal("quantity"); + BigDecimal cancelQuantity = BigDecimal.ZERO; + if (nextOrder.get("cancelQuantity") != null) { + cancelQuantity = nextOrder.getBigDecimal("cancelQuantity"); + } + itemQuantity = itemQuantity.subtract(cancelQuantity); + if (itemQuantity.compareTo(BigDecimal.ZERO) >= 0) { + qty = qty.add(itemQuantity); + } + } + } + } + + return qty; + } + + /** + * Gets the quanitty of each product in the order that is outstanding across all orders of the given input type. + * Uses the OrderItemQuantityReportGroupByProduct view entity. + * + * @param productIds Collection of disticnt productIds in an order. Use OrderReadHelper.getOrderProductIds() + * @param orderTypeId Either "SALES_ORDER" or "PURCHASE_ORDER" + * @param delegator The delegator to use + * @return Map of productIds to quantities outstanding. + */ + public static Map<String, BigDecimal> getOutstandingProductQuantities(Collection<String> productIds, String orderTypeId, Delegator delegator) { + Set<String> fieldsToSelect = UtilMisc.toSet("productId", "quantityOpen"); + List<EntityCondition> condList = UtilMisc.<EntityCondition>toList( + EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, orderTypeId), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_COMPLETED"), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_REJECTED"), + EntityCondition.makeCondition("orderStatusId", EntityOperator.NOT_EQUAL, "ORDER_CANCELLED") + ); + if (productIds.size() > 0) { + condList.add(EntityCondition.makeCondition("productId", EntityOperator.IN, productIds)); + } + condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_COMPLETED")); + condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_REJECTED")); + condList.add(EntityCondition.makeCondition("orderItemStatusId", EntityOperator.NOT_EQUAL, "ITEM_CANCELLED")); + EntityConditionList<EntityCondition> conditions = EntityCondition.makeCondition(condList, EntityOperator.AND); + + Map<String, BigDecimal> results = new HashMap<String, BigDecimal>(); + try { + List<GenericValue> orderedProducts = EntityQuery.use(delegator).select(fieldsToSelect).from("OrderItemQuantityReportGroupByProduct").where(conditions).queryList(); + for (GenericValue value: orderedProducts) { + results.put(value.getString("productId"), value.getBigDecimal("quantityOpen")); + } + } catch (GenericEntityException e) { + Debug.logError(e, module); + } + return results; + } + + /** As above, but for sales orders */ + public static Map<String, BigDecimal> getOutstandingProductQuantitiesForSalesOrders(Collection<String> productIds, Delegator delegator) { + return getOutstandingProductQuantities(productIds, "SALES_ORDER", delegator); + } + + /** As above, but for purchase orders */ + public static Map<String, BigDecimal> getOutstandingProductQuantitiesForPurchaseOrders(Collection<String> productIds, Delegator delegator) { + return getOutstandingProductQuantities(productIds, "PURCHASE_ORDER", delegator); + } +} Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/inventory/InventoryWorker.java ('svn:eol-style' removed) Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/concurrent/ExecutionPool.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/concurrent/ExecutionPool.java?rev=1695126&r1=1695125&r2=1695126&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/org/ofbiz/base/concurrent/ExecutionPool.java (original) +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/concurrent/ExecutionPool.java Mon Aug 10 16:15:37 2015 @@ -1,155 +1,155 @@ -/******************************************************************************* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - *******************************************************************************/ -package org.ofbiz.base.concurrent; - -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.DelayQueue; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ForkJoinPool; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import org.ofbiz.base.lang.SourceMonitored; -import org.ofbiz.base.util.Debug; - -@SourceMonitored -public final class ExecutionPool { - public static final String module = ExecutionPool.class.getName(); - public static final ExecutorService GLOBAL_BATCH = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ExecutionPoolThreadFactory(null, "OFBiz-batch")); - public static final ForkJoinPool GLOBAL_FORK_JOIN = new ForkJoinPool(); - private static final ExecutorService pulseExecutionPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ExecutionPoolThreadFactory(null, "OFBiz-ExecutionPoolPulseWorker")); - - protected static class ExecutionPoolThreadFactory implements ThreadFactory { - private final ThreadGroup group; - private final String namePrefix; - private volatile int count = 1; - - protected ExecutionPoolThreadFactory(ThreadGroup group, String namePrefix) { - this.group = group; - this.namePrefix = namePrefix; - } - - public Thread newThread(Runnable r) { - Thread t = new Thread(group, r); - t.setDaemon(true); - t.setPriority(Thread.NORM_PRIORITY); - t.setName(namePrefix + "-" + count++); - return t; - } - } - - public static ScheduledExecutorService getScheduledExecutor(ThreadGroup group, String namePrefix, int threadCount, long keepAliveSeconds, boolean preStart) { - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(threadCount, new ExecutionPoolThreadFactory(group, namePrefix)); - if (keepAliveSeconds > 0) { - executor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS); - executor.allowCoreThreadTimeOut(true); - } - if (preStart) { - executor.prestartAllCoreThreads(); - } - return executor; - } - - public static <F> List<F> getAllFutures(Collection<Future<F>> futureList) { - List<F> result = new LinkedList<F>(); - for (Future<F> future: futureList) { - try { - result.add(future.get()); - } catch (ExecutionException e) { - Debug.logError(e, module); - } catch (InterruptedException e) { - Debug.logError(e, module); - } - } - return result; - } - - public static void addPulse(Pulse pulse) { - delayQueue.put(pulse); - } - - public static void removePulse(Pulse pulse) { - delayQueue.remove(pulse); - } - - static { - int numberOfExecutionPoolPulseWorkers = Runtime.getRuntime().availableProcessors(); - for (int i = 0; i < numberOfExecutionPoolPulseWorkers; i++) { - pulseExecutionPool.execute(new ExecutionPoolPulseWorker()); - } - } - - private static final DelayQueue<Pulse> delayQueue = new DelayQueue<Pulse>(); - - public static class ExecutionPoolPulseWorker implements Runnable { - public void run() { - try { - while (true) { - delayQueue.take().run(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public static abstract class Pulse implements Delayed, Runnable { - protected final long expireTimeNanos; - protected final long loadTimeNanos; - - protected Pulse(long delayNanos) { - this(System.nanoTime(), delayNanos); - } - - protected Pulse(long loadTimeNanos, long delayNanos) { - this.loadTimeNanos = loadTimeNanos; - expireTimeNanos = loadTimeNanos + delayNanos; - } - - public long getLoadTimeNanos() { - return loadTimeNanos; - } - - public long getExpireTimeNanos() { - return expireTimeNanos; - } - - public final long getDelay(TimeUnit unit) { - return unit.convert(expireTimeNanos - System.nanoTime(), TimeUnit.NANOSECONDS); - } - - public final int compareTo(Delayed other) { - long r = (expireTimeNanos - ((Pulse) other).expireTimeNanos); - if (r < 0) return -1; - if (r > 0) return 1; - return 0; - } - } - -} +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.base.concurrent; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.ofbiz.base.lang.SourceMonitored; +import org.ofbiz.base.util.Debug; + +@SourceMonitored +public final class ExecutionPool { + public static final String module = ExecutionPool.class.getName(); + public static final ExecutorService GLOBAL_BATCH = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ExecutionPoolThreadFactory(null, "OFBiz-batch")); + public static final ForkJoinPool GLOBAL_FORK_JOIN = new ForkJoinPool(); + private static final ExecutorService pulseExecutionPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ExecutionPoolThreadFactory(null, "OFBiz-ExecutionPoolPulseWorker")); + + protected static class ExecutionPoolThreadFactory implements ThreadFactory { + private final ThreadGroup group; + private final String namePrefix; + private volatile int count = 1; + + protected ExecutionPoolThreadFactory(ThreadGroup group, String namePrefix) { + this.group = group; + this.namePrefix = namePrefix; + } + + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r); + t.setDaemon(true); + t.setPriority(Thread.NORM_PRIORITY); + t.setName(namePrefix + "-" + count++); + return t; + } + } + + public static ScheduledExecutorService getScheduledExecutor(ThreadGroup group, String namePrefix, int threadCount, long keepAliveSeconds, boolean preStart) { + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(threadCount, new ExecutionPoolThreadFactory(group, namePrefix)); + if (keepAliveSeconds > 0) { + executor.setKeepAliveTime(keepAliveSeconds, TimeUnit.SECONDS); + executor.allowCoreThreadTimeOut(true); + } + if (preStart) { + executor.prestartAllCoreThreads(); + } + return executor; + } + + public static <F> List<F> getAllFutures(Collection<Future<F>> futureList) { + List<F> result = new LinkedList<F>(); + for (Future<F> future: futureList) { + try { + result.add(future.get()); + } catch (ExecutionException e) { + Debug.logError(e, module); + } catch (InterruptedException e) { + Debug.logError(e, module); + } + } + return result; + } + + public static void addPulse(Pulse pulse) { + delayQueue.put(pulse); + } + + public static void removePulse(Pulse pulse) { + delayQueue.remove(pulse); + } + + static { + int numberOfExecutionPoolPulseWorkers = Runtime.getRuntime().availableProcessors(); + for (int i = 0; i < numberOfExecutionPoolPulseWorkers; i++) { + pulseExecutionPool.execute(new ExecutionPoolPulseWorker()); + } + } + + private static final DelayQueue<Pulse> delayQueue = new DelayQueue<Pulse>(); + + public static class ExecutionPoolPulseWorker implements Runnable { + public void run() { + try { + while (true) { + delayQueue.take().run(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public static abstract class Pulse implements Delayed, Runnable { + protected final long expireTimeNanos; + protected final long loadTimeNanos; + + protected Pulse(long delayNanos) { + this(System.nanoTime(), delayNanos); + } + + protected Pulse(long loadTimeNanos, long delayNanos) { + this.loadTimeNanos = loadTimeNanos; + expireTimeNanos = loadTimeNanos + delayNanos; + } + + public long getLoadTimeNanos() { + return loadTimeNanos; + } + + public long getExpireTimeNanos() { + return expireTimeNanos; + } + + public final long getDelay(TimeUnit unit) { + return unit.convert(expireTimeNanos - System.nanoTime(), TimeUnit.NANOSECONDS); + } + + public final int compareTo(Delayed other) { + long r = (expireTimeNanos - ((Pulse) other).expireTimeNanos); + if (r < 0) return -1; + if (r > 0) return 1; + return 0; + } + } + +} Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/concurrent/ExecutionPool.java ('svn:eol-style' removed) Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/config/CoberturaInstrumenter.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/config/CoberturaInstrumenter.java?rev=1695126&r1=1695125&r2=1695126&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/org/ofbiz/base/config/CoberturaInstrumenter.java (original) +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/config/CoberturaInstrumenter.java Mon Aug 10 16:15:37 2015 @@ -1,94 +1,94 @@ -/******************************************************************************* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - *******************************************************************************/ -package org.ofbiz.base.config; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.Collections; - -import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler; -import net.sourceforge.cobertura.coveragedata.ProjectData; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.ofbiz.base.start.Instrumenter; - -public final class CoberturaInstrumenter implements Instrumenter { - private static final Constructor<?> INSTRUMENTER_CONSTRUCTOR; - private static final Method IS_INSTRUMENTED_METHOD; - static { - try { - Class<?> clz = CoberturaInstrumenter.class.getClassLoader().loadClass("net.sourceforge.cobertura.instrument.ClassInstrumenter"); - INSTRUMENTER_CONSTRUCTOR = clz.getConstructor(ProjectData.class, ClassVisitor.class, Collection.class, Collection.class); - INSTRUMENTER_CONSTRUCTOR.setAccessible(true); - IS_INSTRUMENTED_METHOD = clz.getDeclaredMethod("isInstrumented"); - IS_INSTRUMENTED_METHOD.setAccessible(true); - } catch (Throwable t) { - throw (InternalError) new InternalError(t.getMessage()).initCause(t); - } - } - - protected File dataFile; - protected ProjectData projectData; - protected boolean forInstrumenting; - - public File getDefaultFile() throws IOException { - return CoverageDataFileHandler.getDefaultDataFile(); - } - - public void open(File dataFile, boolean forInstrumenting) throws IOException { - System.setProperty("net.sourceforge.cobertura.datafile", dataFile.toString()); - this.forInstrumenting = forInstrumenting; - this.dataFile = dataFile; - if (forInstrumenting) { - if (dataFile.exists()) { - projectData = CoverageDataFileHandler.loadCoverageData(dataFile); - } else { - projectData = new ProjectData(); - } - } - } - - public void close() throws IOException { - if (forInstrumenting) { - CoverageDataFileHandler.saveCoverageData(projectData, dataFile); - } - } - - public byte[] instrumentClass(byte[] bytes) throws IOException { - if (forInstrumenting) { - ClassReader cr = new ClassReader(bytes); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS/* | ClassWriter.COMPUTE_FRAMES*/); - try { - ClassVisitor ci = (ClassVisitor) INSTRUMENTER_CONSTRUCTOR.newInstance(projectData, cw, Collections.EMPTY_LIST, Collections.EMPTY_LIST); - cr.accept(ci, 0); - if (((Boolean) IS_INSTRUMENTED_METHOD.invoke(ci)).booleanValue()) { - return cw.toByteArray(); - } - } catch (Throwable t) { - throw (IOException) new IOException(t.getMessage()).initCause(t); - } - } - return bytes; - } -} +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.base.config; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Collections; + +import net.sourceforge.cobertura.coveragedata.CoverageDataFileHandler; +import net.sourceforge.cobertura.coveragedata.ProjectData; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.ofbiz.base.start.Instrumenter; + +public final class CoberturaInstrumenter implements Instrumenter { + private static final Constructor<?> INSTRUMENTER_CONSTRUCTOR; + private static final Method IS_INSTRUMENTED_METHOD; + static { + try { + Class<?> clz = CoberturaInstrumenter.class.getClassLoader().loadClass("net.sourceforge.cobertura.instrument.ClassInstrumenter"); + INSTRUMENTER_CONSTRUCTOR = clz.getConstructor(ProjectData.class, ClassVisitor.class, Collection.class, Collection.class); + INSTRUMENTER_CONSTRUCTOR.setAccessible(true); + IS_INSTRUMENTED_METHOD = clz.getDeclaredMethod("isInstrumented"); + IS_INSTRUMENTED_METHOD.setAccessible(true); + } catch (Throwable t) { + throw (InternalError) new InternalError(t.getMessage()).initCause(t); + } + } + + protected File dataFile; + protected ProjectData projectData; + protected boolean forInstrumenting; + + public File getDefaultFile() throws IOException { + return CoverageDataFileHandler.getDefaultDataFile(); + } + + public void open(File dataFile, boolean forInstrumenting) throws IOException { + System.setProperty("net.sourceforge.cobertura.datafile", dataFile.toString()); + this.forInstrumenting = forInstrumenting; + this.dataFile = dataFile; + if (forInstrumenting) { + if (dataFile.exists()) { + projectData = CoverageDataFileHandler.loadCoverageData(dataFile); + } else { + projectData = new ProjectData(); + } + } + } + + public void close() throws IOException { + if (forInstrumenting) { + CoverageDataFileHandler.saveCoverageData(projectData, dataFile); + } + } + + public byte[] instrumentClass(byte[] bytes) throws IOException { + if (forInstrumenting) { + ClassReader cr = new ClassReader(bytes); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS/* | ClassWriter.COMPUTE_FRAMES*/); + try { + ClassVisitor ci = (ClassVisitor) INSTRUMENTER_CONSTRUCTOR.newInstance(projectData, cw, Collections.EMPTY_LIST, Collections.EMPTY_LIST); + cr.accept(ci, 0); + if (((Boolean) IS_INSTRUMENTED_METHOD.invoke(ci)).booleanValue()) { + return cw.toByteArray(); + } + } catch (Throwable t) { + throw (IOException) new IOException(t.getMessage()).initCause(t); + } + } + return bytes; + } +} Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/config/CoberturaInstrumenter.java ('svn:eol-style' removed) Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/container/JustLoadComponentsContainer.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/container/JustLoadComponentsContainer.java?rev=1695126&r1=1695125&r2=1695126&view=diff ============================================================================== --- ofbiz/trunk/framework/base/src/org/ofbiz/base/container/JustLoadComponentsContainer.java (original) +++ ofbiz/trunk/framework/base/src/org/ofbiz/base/container/JustLoadComponentsContainer.java Mon Aug 10 16:15:37 2015 @@ -1,58 +1,58 @@ -/******************************************************************************* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - *******************************************************************************/ -package org.ofbiz.base.container; - -import org.ofbiz.base.component.AlreadyLoadedException; -import org.ofbiz.base.component.ComponentException; -import org.ofbiz.base.util.Debug; - -/** - * A Container implementation to run the tests configured through this testtools stuff. - */ -public class JustLoadComponentsContainer implements Container { - - public static final String module = JustLoadComponentsContainer.class.getName(); - - private String name; - - @Override - public void init(String[] args, String name, String configFile) { - this.name = name; - try { - ComponentContainer cc = new ComponentContainer(); - cc.loadComponents(null); - } catch (AlreadyLoadedException e) { - Debug.logError(e, module); - } catch (ComponentException e) { - Debug.logError(e, module); - //throw UtilMisc.initCause(new ContainerException(e.getMessage()), e); - } - } - - public boolean start() throws ContainerException { - return true; - } - - public void stop() throws ContainerException { - } - - public String getName() { - return name; - } -} +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.ofbiz.base.container; + +import org.ofbiz.base.component.AlreadyLoadedException; +import org.ofbiz.base.component.ComponentException; +import org.ofbiz.base.util.Debug; + +/** + * A Container implementation to run the tests configured through this testtools stuff. + */ +public class JustLoadComponentsContainer implements Container { + + public static final String module = JustLoadComponentsContainer.class.getName(); + + private String name; + + @Override + public void init(String[] args, String name, String configFile) { + this.name = name; + try { + ComponentContainer cc = new ComponentContainer(); + cc.loadComponents(null); + } catch (AlreadyLoadedException e) { + Debug.logError(e, module); + } catch (ComponentException e) { + Debug.logError(e, module); + //throw UtilMisc.initCause(new ContainerException(e.getMessage()), e); + } + } + + public boolean start() throws ContainerException { + return true; + } + + public void stop() throws ContainerException { + } + + public String getName() { + return name; + } +} Propchange: ofbiz/trunk/framework/base/src/org/ofbiz/base/container/JustLoadComponentsContainer.java ('svn:eol-style' removed) |
Free forum by Nabble | Edit this page |