blob: c1d36718055e80327ab99386ab0d0fb36317b6bb [file] [log] [blame]
/*
* 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.*
shipmentId = request.getParameter("shipmentId");
orderId = request.getParameter("purchaseOrderId");
shipGroupSeqId = request.getParameter("shipGroupSeqId");
context.shipmentId = shipmentId;
context.shipGroupSeqId = shipGroupSeqId;
// Retrieve the map resident in session which stores order item quantities to receive
itemQuantitiesToReceive = session.getAttribute("purchaseOrderItemQuantitiesToReceive");
if (itemQuantitiesToReceive) {
sessionShipmentId = itemQuantitiesToReceive._shipmentId;
sessionOrderId = itemQuantitiesToReceive._orderId;
if ((sessionShipmentId && !sessionShipmentId.equals(shipmentId)) ||
((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.findOne("Shipment", [shipmentId : shipmentId], false);
context.shipment = shipment;
if (!shipment) {
return;
}
isPurchaseShipment = "PURCHASE_SHIPMENT".equals(shipment.shipmentTypeId);
context.isPurchaseShipment = isPurchaseShipment;
if (!isPurchaseShipment) {
return;
}
facility = shipment.getRelatedOne("DestinationFacility", false);
context.facility = facility;
context.facilityId = shipment.destinationFacilityId;
context.now = UtilDateTime.nowTimestamp();
if (!orderId) {
orderId = shipment.primaryOrderId;
}
if (!shipGroupSeqId) {
shipGroupSeqId = shipment.primaryShipGroupSeqId;
}
context.orderId = orderId;
if (!orderId) {
return;
}
orderHeader = delegator.findOne("OrderHeader", [orderId : orderId], false);
context.orderHeader = orderHeader;
if (!orderHeader) {
return;
}
isPurchaseOrder = "PURCHASE_ORDER".equals(orderHeader.orderTypeId);
context.isPurchaseOrder = isPurchaseOrder;
if (!isPurchaseOrder) {
return;
}
// Get the base currency from the facility owner, for currency conversions
baseCurrencyUomId = null;
if (facility) {
owner = facility.getRelatedOne("OwnerParty", false);
if (owner) {
result = dispatcher.runSync("getPartyAccountingPreferences", [organizationPartyId : owner.partyId, userLogin : request.getAttribute("userLogin")]);
if (!ServiceUtil.isError(result) && result.partyAccountingPreference) {
ownerAcctgPref = result.partyAccountingPreference;
}
}
if (ownerAcctgPref) {
baseCurrencyUomId = ownerAcctgPref.baseCurrencyUomId;
}
}
inventoryItemTypes = delegator.findList("InventoryItemType", null, null, null, null, false);
context.inventoryItemTypes = inventoryItemTypes;
// Populate the tracking map with shipment and order IDs
if (!itemQuantitiesToReceive) {
itemQuantitiesToReceive = [_shipmentId : shipmentId, _orderId : orderId];
}
oiasgaLimitMap = null;
if (shipGroupSeqId) {
oiasgaLimitMap = [shipGroupSeqId : shipGroupSeqId];
}
orderItemDatas = [:] as TreeMap;
totalAvailableToReceive = 0;
// Populate the order item data for the FTL
orderItems = orderHeader.getRelated("OrderItemAndShipGroupAssoc", oiasgaLimitMap, ['shipGroupSeqId', 'orderItemSeqId'], false);
orderItems.each { orderItemAndShipGroupAssoc ->
product = orderItemAndShipGroupAssoc.getRelatedOne("Product", false);
// Get the order item, since the orderItemAndShipGroupAssoc's quantity field is manipulated in some cases
orderItem = delegator.findOne("OrderItem", [orderId : orderId, orderItemSeqId : orderItemAndShipGroupAssoc.orderItemSeqId], false);
orderItemData = [:];
// Get the item's ordered quantity
totalOrdered = 0;
ordered = orderItem.getDouble("quantity");
if (ordered) {
totalOrdered += ordered.doubleValue();
}
cancelled = orderItem.getDouble("cancelQuantity");
if (cancelled) {
totalOrdered -= cancelled.doubleValue();
}
// Get the item quantity received from all shipments via the ShipmentReceipt entity
totalReceived = 0.0;
receipts = delegator.findList("ShipmentReceipt", EntityCondition.makeCondition([orderId : orderId, orderItemSeqId : orderItem.orderItemSeqId]), null, null, null, false);
fulfilledReservations = [] as ArrayList;
if (receipts) {
receipts.each { rec ->
accepted = rec.getDouble("quantityAccepted");
rejected = rec.getDouble("quantityRejected");
if (accepted) {
totalReceived += accepted.doubleValue();
}
if (rejected) {
totalReceived += rejected.doubleValue();
}
// Get the reservations related to this receipt
oisgirs = delegator.findList("OrderItemShipGrpInvRes", EntityCondition.makeCondition([inventoryItemId : rec.inventoryItemId]), null, null, null, false);
if (oisgirs) {
fulfilledReservations.addAll(oisgirs);
}
}
}
orderItemData.fulfilledReservations = fulfilledReservations;
// Update the unit cost with the converted value, if any
if (baseCurrencyUomId && orderHeader.currencyUom) {
if (product) {
result = dispatcher.runSync("convertUom", [uomId : orderHeader.currencyUom, uomIdTo : baseCurrencyUomId, originalValue : orderItem.unitPrice]);
if (!ServiceUtil.isError(result)) {
orderItem.unitPrice = result.convertedValue;
}
}
}
// Retrieve the backordered quantity
// TODO: limit to a facility? The shipment destination facility is not necessarily the same facility as the inventory
conditions = [EntityCondition.makeCondition("productId", EntityOperator.EQUALS, product.productId),
EntityCondition.makeCondition("availableToPromiseTotal", EntityOperator.LESS_THAN, BigDecimal.ZERO)];
negativeInventoryItems = delegator.findList("InventoryItem", EntityCondition.makeCondition(conditions, EntityOperator.AND), null, null, null, false);
backOrderedQuantity = 0;
negativeInventoryItems.each { negativeInventoryItem ->
backOrderedQuantity += negativeInventoryItem.getDouble("availableToPromiseTotal").doubleValue();
}
orderItemData.backOrderedQuantity = Math.abs(backOrderedQuantity);
// Calculate how many units it should be possible to recieve for this purchase order
availableToReceive = totalOrdered - totalReceived;
totalAvailableToReceive += availableToReceive;
orderItemData.availableToReceive = availableToReceive;
orderItemData.totalQuantityReceived = totalReceived;
orderItemData.shipGroupSeqId = orderItemAndShipGroupAssoc.shipGroupSeqId;
orderItemData.orderItem = orderItem;
orderItemData.product = product;
orderItemDatas.put(orderItem.orderItemSeqId, orderItemData);
}
context.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.newQuantity = productQtyToReceive;
if (productIdToReceive) {
List candidateOrderItems = EntityUtil.filterByAnd(orderItems, [productId : productIdToReceive]);
// If the productId as given isn't found in the order, try any goodIdentifications and use the first match
if (!candidateOrderItems) {
goodIdentifications = delegator.findList("GoodIdentification", EntityCondition.makeCondition([idValue : productIdToReceive]), null, null, null, false);
if (goodIdentifications) {
giit = goodIdentifications.iterator();
while (giit.hasNext()) {
goodIdentification = giit.next();
candidateOrderItems = EntityUtil.filterByAnd(orderItems, [productId : goodIdentification.productId]);
if (candidateOrderItems) {
productIdToReceive = goodIdentification.productId;
break;
}
}
}
}
if (candidateOrderItems) {
quantity = 0;
if (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.orderItemSeqId;
qtyBefore = itemQuantitiesToReceive.containsKey(orderItemSeqId) ? itemQuantitiesToReceive.get(orderItemSeqId) : 0;
totalQuantityToReceiveBefore += qtyBefore;
qtyMaxAvailable = orderItemDatas.get(orderItemSeqId).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.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).orderItemSeqId).backOrderedQuantity - totalQuantityToReceiveBefore;
if (backOrderedQuantity > 0) {
totalQtyUsedForBackorders = backOrderedQuantity >= totalQuantityUsed ? totalQuantityUsed : backOrderedQuantity;
if (totalQtyUsedForBackorders > 0) {
context.quantityToReceive = totalQuantityUsed;
context.quantityToBackOrder = totalQtyUsedForBackorders;
context.ProductReceiveInventoryAgainstPurchaseOrderQuantityGoesToBackOrder = true;
}
}
} else {
// Add an error message to the context if the productId doesn't exist in this purchase order
context.ProductReceiveInventoryAgainstPurchaseOrderProductNotFound = true;
}
}
// Put the tracking map back into the session, in case it has been reconstructed
session.setAttribute("purchaseOrderItemQuantitiesToReceive", itemQuantitiesToReceive);
context.itemQuantitiesToReceive = itemQuantitiesToReceive;
context.totalAvailableToReceive = totalAvailableToReceive;