/* * 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. */ import org.ofbiz.entity.condition.*; import org.ofbiz.entity.util.*; import org.ofbiz.service.ServiceUtil; import org.ofbiz.base.util.*; delegator = request.getAttribute("delegator"); shipmentId = request.getParameter("shipmentId"); orderId = request.getParameter("purchaseOrderId"); shipGroupSeqId = request.getParameter("shipGroupSeqId"); context.put("shipmentId", shipmentId); context.put("shipGroupSeqId", shipGroupSeqId); // Retrieve the map resident in session which stores order item quantities to receive itemQuantitiesToReceive = session.getAttribute("purchaseOrderItemQuantitiesToReceive"); if (! UtilValidate.isEmpty(itemQuantitiesToReceive)) { sessionShipmentId = itemQuantitiesToReceive.get("_shipmentId"); sessionOrderId = itemQuantitiesToReceive.get("_orderId"); if ( (UtilValidate.isNotEmpty(sessionShipmentId) && ! sessionShipmentId.equals(shipmentId)) || ((UtilValidate.isNotEmpty(sessionOrderId) && ! sessionOrderId.equals(orderId))) || "Y".equals(request.getParameter("clearAll")) ) { // Clear the map if the shipmentId or orderId are different than the current ones, or // if the clearAll parameter is present itemQuantitiesToReceive.clear(); } } shipment = delegator.findByPrimaryKey("Shipment", UtilMisc.toMap("shipmentId", shipmentId)); context.put("shipment", shipment); if (UtilValidate.isEmpty(shipment)) { return; } isPurchaseShipment = "PURCHASE_SHIPMENT".equals(shipment.getString("shipmentTypeId")); context.put("isPurchaseShipment", isPurchaseShipment); if (! isPurchaseShipment) { return; } facility = shipment.getRelatedOne("DestinationFacility"); context.put("facility", facility); context.put("facilityId", shipment.get("destinationFacilityId")); context.put("now", UtilDateTime.nowTimestamp()); if (UtilValidate.isEmpty(orderId)) { orderId = shipment.get("primaryOrderId"); } if (UtilValidate.isEmpty(shipGroupSeqId)) { shipGroupSeqId = shipment.get("primaryShipGroupSeqId"); } context.put("orderId", orderId); if (UtilValidate.isEmpty(orderId)) { return; } orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId)); context.put("orderHeader", orderHeader); if (UtilValidate.isEmpty(orderHeader)) { return; } isPurchaseOrder = "PURCHASE_ORDER".equals(orderHeader.getString("orderTypeId")); context.put("isPurchaseOrder", isPurchaseOrder); if (! isPurchaseOrder) { return; } // Get the base currency from the facility owner, for currency conversions baseCurrencyUomId = null; if (! UtilValidate.isEmpty(facility)) { owner = facility.getRelatedOne("OwnerParty"); if (! UtilValidate.isEmpty(owner)) { ownerAcctgPref = owner.getRelatedOne("PartyAcctgPreference"); } if (! UtilValidate.isEmpty(ownerAcctgPref)) { baseCurrencyUomId = ownerAcctgPref.get("baseCurrencyUomId"); } } inventoryItemTypes = delegator.findAll("InventoryItemType"); context.put("inventoryItemTypes", inventoryItemTypes); // Populate the tracking map with shipment and order IDs if (UtilValidate.isEmpty(itemQuantitiesToReceive)) { itemQuantitiesToReceive = UtilMisc.toMap("_shipmentId", shipmentId, "_orderId", orderId); } oiasgaLimitMap = null; if (! UtilValidate.isEmpty(shipGroupSeqId)) { oiasgaLimitMap = UtilMisc.toMap("shipGroupSeqId", shipGroupSeqId); } orderItemDatas = new TreeMap(); totalAvailableToReceive = 0; // Populate the order item data for the FTL orderItems = orderHeader.getRelated("OrderItemAndShipGroupAssoc", oiasgaLimitMap, UtilMisc.toList("shipGroupSeqId", "orderItemSeqId")); orderItemIter = orderItems.iterator(); while (orderItemIter.hasNext()) { orderItemAndShipGroupAssoc = orderItemIter.next(); product = orderItemAndShipGroupAssoc.getRelatedOne("Product"); // Get the order item, since the orderItemAndShipGroupAssoc's quantity field is manipulated in some cases orderItem = delegator.findByPrimaryKey("OrderItem", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItemAndShipGroupAssoc.get("orderItemSeqId"))); orderItemData = new HashMap(); // Get the item's ordered quantity totalOrdered = 0; ordered = orderItem.getDouble("quantity"); if (ordered != null) totalOrdered += ordered.doubleValue(); cancelled = orderItem.getDouble("cancelQuantity"); if (cancelled != null) totalOrdered -= cancelled.doubleValue(); // Get the item quantity received from all shipments via the ShipmentReceipt entity totalReceived = 0.0; receipts = delegator.findByAnd("ShipmentReceipt", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId"))); fulfilledReservations = new ArrayList(); if (receipts != null && receipts.size() > 0) { recIter = receipts.iterator(); while (recIter.hasNext()) { rec = recIter.next(); accepted = rec.getDouble("quantityAccepted"); rejected = rec.getDouble("quantityRejected"); if (accepted != null) totalReceived += accepted.doubleValue(); if (rejected != null) totalReceived += rejected.doubleValue(); // Get the reservations related to this receipt oisgirs = delegator.findByAnd("OrderItemShipGrpInvRes", UtilMisc.toMap("inventoryItemId", rec.get("inventoryItemId"))); if (! UtilValidate.isEmpty(oisgirs)) { fulfilledReservations.addAll(oisgirs); } } } orderItemData.put("fulfilledReservations", fulfilledReservations); // Update the unit cost with the converted value, if any if (UtilValidate.isNotEmpty(baseCurrencyUomId) && UtilValidate.isNotEmpty(orderHeader.getString("currencyUom"))) { if (! UtilValidate.isEmpty(product)) { result = dispatcher.runSync("convertUom", UtilMisc.toMap("uomId", orderHeader.getString("currencyUom"), "uomIdTo", baseCurrencyUomId, "originalValue", orderItem.get("unitPrice"))); if (!ServiceUtil.isError(result)) { orderItem.put("unitPrice", result.get("convertedValue")); } } } // Retrieve the backordered quantity // TODO: limit to a facility? The shipment destination facility is not necessarily the same facility as the inventory conditions = UtilMisc.toList(new EntityExpr("productId", EntityOperator.EQUALS, product.get("productId")), new EntityExpr("availableToPromiseTotal", EntityOperator.LESS_THAN, new Double(0))); negativeInventoryItems = delegator.findByCondition("InventoryItem", new EntityConditionList(conditions, EntityOperator.AND), null, null); backOrderedQuantity = 0; niit = negativeInventoryItems.iterator(); while (niit.hasNext()) { negativeInventoryItem = niit.next(); backOrderedQuantity += negativeInventoryItem.getDouble("availableToPromiseTotal").doubleValue(); } orderItemData.put("backOrderedQuantity", Math.abs(backOrderedQuantity)); // Calculate how many units it should be possible to recieve for this purchase order availableToReceive = totalOrdered - totalReceived; totalAvailableToReceive += availableToReceive; orderItemData.put("availableToReceive", availableToReceive); orderItemData.put("totalQuantityReceived", totalReceived); orderItemData.put("shipGroupSeqId", orderItemAndShipGroupAssoc.get("shipGroupSeqId")); orderItemData.put("orderItem", orderItem); orderItemData.put("product", product); orderItemDatas.put(orderItem.getString("orderItemSeqId"), orderItemData); } context.put("orderItemDatas", orderItemDatas.values()); // Handle any item product quantities to receive by adding to the map in session productIdToReceive = request.getParameter("productId"); productQtyToReceive = request.getParameter("quantity"); context.put("newQuantity", productQtyToReceive); if (UtilValidate.isNotEmpty(productIdToReceive)) { List candidateOrderItems = EntityUtil.filterByAnd(orderItems, UtilMisc.toMap("productId", productIdToReceive)); // If the productId as given isn't found in the order, try any goodIdentifications and use the first match if (UtilValidate.isEmpty(candidateOrderItems)) { goodIdentifications = delegator.findByAnd("GoodIdentification", UtilMisc.toMap("idValue", productIdToReceive)); if (! UtilValidate.isEmpty(goodIdentifications)) { giit = goodIdentifications.iterator(); while (giit.hasNext()) { goodIdentification = giit.next(); candidateOrderItems = EntityUtil.filterByAnd(orderItems, UtilMisc.toMap("productId", goodIdentification.get("productId"))); if (! UtilValidate.isEmpty(candidateOrderItems)) { productIdToReceive = goodIdentification.get("productId"); break; } } } } if (! UtilValidate.isEmpty(candidateOrderItems)) { quantity = 0; if (! UtilValidate.isEmpty(productQtyToReceive)) { try { quantity = Double.parseDouble(productQtyToReceive); } catch (Exception e) { // Ignore the quantity update if there's a problem parsing it } } totalQuantityUsed = 0; totalQuantityToReceiveBefore = 0; pqit = candidateOrderItems.iterator(); while (pqit.hasNext() && totalQuantityUsed < quantity) { candidateOrderItem = pqit.next(); orderItemSeqId = candidateOrderItem.getString("orderItemSeqId"); qtyBefore = itemQuantitiesToReceive.containsKey(orderItemSeqId) ? itemQuantitiesToReceive.get(orderItemSeqId) : 0; totalQuantityToReceiveBefore += qtyBefore; qtyMaxAvailable = orderItemDatas.get(orderItemSeqId).get("availableToReceive") - qtyBefore; if (qtyMaxAvailable <= 0) { continue; } qtyUsedForItem = quantity - totalQuantityUsed >= qtyMaxAvailable ? qtyMaxAvailable : quantity - totalQuantityUsed; itemQuantitiesToReceive.put(orderItemSeqId, qtyUsedForItem + qtyBefore); totalQuantityUsed += qtyUsedForItem; } // If there's any quantity to receive left after using as much as possible for every relevant order item, add an error message to the context if (quantity > totalQuantityUsed) { context.put("ProductReceiveInventoryAgainstPurchaseOrderQuantityExceedsAvailableToReceive", true); } // Notify if some or all of the quantity just entered for the product will go to a backorder backOrderedQuantity = orderItemDatas.get(EntityUtil.getFirst(candidateOrderItems).get("orderItemSeqId")).get("backOrderedQuantity") - totalQuantityToReceiveBefore; if (backOrderedQuantity > 0) { totalQtyUsedForBackorders = backOrderedQuantity >= totalQuantityUsed ? totalQuantityUsed : backOrderedQuantity; if (totalQtyUsedForBackorders > 0) { context.put("quantityToReceive", totalQuantityUsed); context.put("quantityToBackOrder", totalQtyUsedForBackorders); context.put("ProductReceiveInventoryAgainstPurchaseOrderQuantityGoesToBackOrder", true); } } } else { // Add an error message to the context if the productId doesn't exist in this purchase order context.put("ProductReceiveInventoryAgainstPurchaseOrderProductNotFound", true); } } // Put the tracking map back into the session, in case it has been reconstructed session.setAttribute("purchaseOrderItemQuantitiesToReceive", itemQuantitiesToReceive); context.put("itemQuantitiesToReceive", itemQuantitiesToReceive); context.put("totalAvailableToReceive", totalAvailableToReceive);