FR3004020 - Delivery Policy.

This is a slightly large commit affecting the core functionality of shipments
so I'm happy for all eyeballs I can get on this code. I've tested as thorough
one person can do.
If there are no undiscovered bugs this doesn't change current functionality unless
you change the new setting of "Delivery Policy" available on Client Info and
Organization Info.
See also http://www.adempiere.com/index.php/Delivery_Policy
Link to SF Tracker: http://sourceforge.net/support/tracker.php?aid=3004020
This commit is contained in:
usrdno 2010-06-23 07:31:43 +00:00
parent 2a64502984
commit 984f2b35b7
42 changed files with 2913 additions and 189 deletions

View File

@ -0,0 +1,227 @@
package org.adempiere.process;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
import org.compiere.model.MOrderLine;
import org.compiere.model.MOrgInfo;
import org.compiere.model.MProduct;
import org.compiere.model.MClientInfo;
import org.compiere.model.MWarehouse;
import org.compiere.process.ProcessInfoParameter;
import org.compiere.process.SvrProcess;
import org.compiere.util.DB;
import org.compiere.util.Env;
/**
* This process finds all complete sales orders that has physical items yet to
* deliver and tries to allocate items from the items on hand.
*
* @author daniel.tamm
*
*/
public class AllocateSalesOrders extends SvrProcess {
private int m_warehouseId;
public static class StockInfo {
public int productId;
public BigDecimal qtyOnHand;
public BigDecimal qtyAvailable;
public BigDecimal qtyReserved;
public BigDecimal qtyAllocated;
public StockInfo() {}
}
private static final String
query = "select C_OrderLine.* from C_OrderLine " +
"JOIN C_Order ON C_OrderLine.C_Order_ID=C_Order.C_Order_ID " +
"JOIN M_Product ON C_OrderLine.M_Product_ID=M_Product.M_Product_ID " +
"where C_Order.IsSOTrx='Y' AND C_Order.DocStatus='CO' AND QtyAllocated<(QtyOrdered-QtyDelivered) " +
"AND M_Product.M_Product_ID=? " +
"order by PriorityRule, C_OrderLine.Created ";
@Override
protected void prepare() {
m_warehouseId = 1000000; // TODO: Should be mandatory in the process definition
ProcessInfoParameter[] para = getParameter();
for (int i = 0; i < para.length; i++) {
String name = para[i].getParameterName();
if (para[i].getParameter() == null);
else if (name.equals("M_Warehouse_ID")) {
m_warehouseId = para[i].getParameterAsInt();
} else {
log.log(Level.SEVERE, "Unknown Parameter: " + name);
}
}
}
/**
* Finds all order lines that contains not yet delivered physical items of a specific product.
*
* @param conn An open connection.
* @param productId The product id being allocated
* @return Order lines to allocate products to.
* @throws SQLException
*/
public static Vector<MOrderLine> getOrderLinesToAllocate(Connection conn, int productId, String trxName) throws SQLException {
Vector<MOrderLine> result = new Vector<MOrderLine>();
Properties ctx = Env.getCtx();
MOrderLine line;
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(1, productId);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
line = new MOrderLine(ctx, rs, trxName);
result.add(line);
}
rs.close();
ps.close();
return(result);
}
/**
* Finds all products that can be allocated. A product can be allocated if there are more items
* on hand than what is already allocated. To be allocated the item must also be in demand
* (reserved < allocated)
*
* @param conn
* @return
* @throws SQLException
*/
public static Vector<StockInfo> getProductsToAllocate(Connection conn, int WarehouseID) throws SQLException {
Vector<StockInfo> result = new Vector<StockInfo>();
StockInfo si;
String query1 = "select M_Product_ID, sum(qtyonhand), sum(qtyreserved), sum(m_Product_Stock_v.qtyallocated) " +
"from M_Product_Stock_v " +
"WHERE M_Warehouse_ID=? AND M_Product_ID in " +
"(select DISTINCT C_OrderLine.M_Product_ID FROM C_OrderLine " +
"JOIN C_Order ON C_OrderLine.C_Order_ID=C_Order.C_Order_ID " +
"JOIN M_Product ON C_OrderLine.M_Product_ID=M_Product.M_Product_ID " +
"JOIN M_Product_Stock_v ON C_OrderLine.M_Product_ID=M_Product_Stock_v.M_Product_ID " +
"WHERE " +
"C_Order.IsSOTrx='Y' AND C_Order.DocStatus='CO' AND C_OrderLine.M_Warehouse_ID=? AND " +
"(QtyOrdered-QtyDelivered)>0 AND (QtyOrdered-QtyDelivered)>C_OrderLine.QtyAllocated)" +
"group by M_Product_ID " +
"order by M_Product_ID";
PreparedStatement ps = conn.prepareStatement(query1);
ps.setInt(1, WarehouseID);
ps.setInt(2, WarehouseID);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
si = new StockInfo();
si.productId = rs.getInt(1);
si.qtyOnHand = rs.getBigDecimal(2);
si.qtyReserved = rs.getBigDecimal(3);
si.qtyAvailable = si.qtyOnHand.subtract(si.qtyReserved);
si.qtyAllocated = rs.getBigDecimal(4);
result.add(si);
}
rs.close();
ps.close();
return(result);
}
@Override
protected String doIt() throws Exception {
Connection conn = DB.getConnectionRO();
Vector<StockInfo> products = AllocateSalesOrders.getProductsToAllocate(conn, m_warehouseId);
conn.close();
Vector<MOrderLine> lines;
MOrderLine line;
BigDecimal lineAllocate;
BigDecimal toAllocate;
BigDecimal onHand;
BigDecimal allocated;
BigDecimal qtyAvailable;
BigDecimal willAllocate;
StockInfo si;
// Make sure we have settings that needs allocation
MWarehouse warehouse = new MWarehouse(getCtx(), m_warehouseId, get_TrxName());
MOrgInfo orgInfo = MOrgInfo.get(getCtx(), warehouse.getAD_Org_ID(), get_TrxName());
if (!orgInfo.getDeliveryPolicy().equals(MClientInfo.DELIVERY_POLICY_STRICT_ORDER)) {
return "The current delivery policy of the warehouse doesn't use allocation.";
}
if (products.size()==0) {
log.info("There are no products to allocate.");
return "";
}
/** Iterate through all products to allocate */
for (Iterator<StockInfo> it = products.iterator(); it.hasNext();) {
MProduct product = null;
si = it.next();
conn = DB.getConnectionRO();
// Get all lines to allocate
lines = AllocateSalesOrders.getOrderLinesToAllocate(conn, si.productId, get_TrxName());
conn.close();
// Check if there are any lines to allocate
// and create a log.
if (lines.size()>0) {
product = lines.get(0).getProduct();
line = lines.get(0);
qtyAvailable = si.qtyAvailable;
onHand = si.qtyOnHand;
// TO allocate = Min (qtyOnHand - qtyAllocated, qtyReserved - qtyAllocated)
toAllocate = si.qtyOnHand.subtract(si.qtyAllocated).min(si.qtyReserved.subtract(si.qtyAllocated));
if (toAllocate.signum()>0) {
log.info("Allocating " + product.getValue() + " : " + product.getName() + " Avail: " + qtyAvailable + " On hand: " + onHand + " To alloc: " + toAllocate);
log.info(lines.size() + " lines to allocate.");
} else {
continue;
}
} else {
continue;
}
allocated = BigDecimal.ZERO;
// When we are here we know what product, qty available and we have the lines
// that need to be allocated.
for (Iterator<MOrderLine> it2 = lines.iterator(); it2.hasNext(); ) {
line = it2.next();
// Calculate what to allocate (what we want)
lineAllocate = line.getQtyOrdered().subtract(line.getQtyDelivered()).subtract(line.getQtyAllocated());
willAllocate = lineAllocate.min(toAllocate);
if (willAllocate.signum()==1) {
willAllocate = line.allocateOnHand(willAllocate, get_TrxName());
allocated = allocated.add(willAllocate);
toAllocate = toAllocate.subtract(willAllocate);
log.info("Allocated " + willAllocate + " to order " + line.getC_Order().getDocumentNo() + " " + toAllocate + " left to allocate.");
if (toAllocate.equals(BigDecimal.ZERO))
break;
} else {
log.info("Skipping allocation of order " + line.getC_Order().getDocumentNo());
continue;
}
}
}
return("");
}
}

View File

@ -0,0 +1,131 @@
package org.adempiere.validator;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Vector;
import org.adempiere.process.AllocateSalesOrders;
import org.compiere.model.MClient;
import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine;
import org.compiere.model.MOrderLine;
import org.compiere.model.ModelValidationEngine;
import org.compiere.model.ModelValidator;
import org.compiere.model.PO;
import org.compiere.util.CLogger;
import org.compiere.util.Trx;
/**
* Validator that allocates products as soon as they hit the warehouse.
* Not yet activated but will be in upcoming revisions.
*
* @author Daniel Tamm
*
*/
public class MaterialReceiptModelValidator implements ModelValidator {
private static final CLogger logger = CLogger.getCLogger(MaterialReceiptModelValidator.class);
private int ad_Client_ID = -1;
@Override
public int getAD_Client_ID() {
return ad_Client_ID;
}
@Override
public void initialize(ModelValidationEngine engine, MClient client) {
if (client != null) {
ad_Client_ID = client.getAD_Client_ID();
}
engine.addDocValidate(MInOut.Table_Name, this);
}
@Override
public String docValidate(PO po, int timing) {
if (timing == ModelValidator.TIMING_AFTER_COMPLETE) {
MInOut io = (MInOut)po;
// We only allocate incoming material
if (!io.isSOTrx()) {
MInOutLine[] lines = io.getLines();
MInOutLine line;
try {
String trxName = Trx.createTrxName();
Trx trx = Trx.get(trxName, true);
Connection conn = trx.getConnection();
for (int i=0; i<lines.length; i++) {
line = lines[i];
try {
allocateProducts(conn, trxName, line);
trx.commit();
trx.close();
conn.close();
} catch (SQLException e) {
trx.rollback();
trx.close();
conn.close();
return(e.getMessage());
}
}
} catch (SQLException ee) {
}
}
}
return "";
}
private void allocateProducts(Connection conn, String trxName, MInOutLine iol) throws SQLException {
BigDecimal qty = iol.getMovementQty();
// Make sure we have a positive amount
if (qty.signum()>0) {
Vector<MOrderLine> lines = AllocateSalesOrders.getOrderLinesToAllocate(conn, iol.getProduct().get_ID(), trxName);
MOrderLine line;
BigDecimal receivedQty = iol.getMovementQty();
BigDecimal toAllocate;
BigDecimal willAllocate;
for (Iterator<MOrderLine> it = lines.iterator(); it.hasNext(); ) {
line = it.next();
// Calculate what to allocate (what we want)
toAllocate = line.getQtyOrdered().subtract(line.getQtyDelivered());
// What we got (minimum of what was received and what we want)
willAllocate = toAllocate.min(receivedQty);
line.setQtyAllocated(willAllocate);
line.saveEx(trxName);
logger.info("Allocated " + willAllocate + " to order " + line.getC_Order().getDocumentNo());
receivedQty = receivedQty.subtract(willAllocate);
if (receivedQty.equals(BigDecimal.ZERO))
break;
}
}
}
public String login(final int AD_Org_ID, final int AD_Role_ID,
final int AD_User_ID) {
logger.info("AD_Org_ID=" + AD_Org_ID + "; AD_Role_ID=" + AD_Role_ID
+ "; AD_User_ID=" + AD_User_ID);
return null;
}
@Override
public String modelChange(PO po, int type) throws Exception {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -273,6 +273,21 @@ public interface I_AD_ClientInfo
public I_C_UOM getC_UOM_Time() throws RuntimeException;
/** Column name C_UOM_Weight_ID */
public static final String COLUMNNAME_C_UOM_Weight_ID = "C_UOM_Weight_ID";
/** Set UOM for Weight.
* Standard Unit of Measure for Weight
*/
public void setC_UOM_Weight_ID (int C_UOM_Weight_ID);
/** Get UOM for Weight.
* Standard Unit of Measure for Weight
*/
public int getC_UOM_Weight_ID();
public I_C_UOM getC_UOM_Weight() throws RuntimeException;
/** Column name C_UOM_Volume_ID */
public static final String COLUMNNAME_C_UOM_Volume_ID = "C_UOM_Volume_ID";
@ -288,20 +303,18 @@ public interface I_AD_ClientInfo
public I_C_UOM getC_UOM_Volume() throws RuntimeException;
/** Column name C_UOM_Weight_ID */
public static final String COLUMNNAME_C_UOM_Weight_ID = "C_UOM_Weight_ID";
/** Column name DeliveryPolicy */
public static final String COLUMNNAME_DeliveryPolicy = "DeliveryPolicy";
/** Set UOM for Weight.
* Standard Unit of Measure for Weight
/** Set Delivery Policy.
* Delivery Policy
*/
public void setC_UOM_Weight_ID (int C_UOM_Weight_ID);
public void setDeliveryPolicy (String DeliveryPolicy);
/** Get UOM for Weight.
* Standard Unit of Measure for Weight
/** Get Delivery Policy.
* Delivery Policy
*/
public int getC_UOM_Weight_ID();
public I_C_UOM getC_UOM_Weight() throws RuntimeException;
public String getDeliveryPolicy();
/** Column name IsActive */
public static final String COLUMNNAME_IsActive = "IsActive";

View File

@ -123,6 +123,19 @@ public interface I_AD_OrgInfo
*/
public int getCreatedBy();
/** Column name DeliveryPolicy */
public static final String COLUMNNAME_DeliveryPolicy = "DeliveryPolicy";
/** Set Delivery Policy.
* Delivery Policy
*/
public void setDeliveryPolicy (String DeliveryPolicy);
/** Get Delivery Policy.
* Delivery Policy
*/
public String getDeliveryPolicy();
/** Column name DropShip_Warehouse_ID */
public static final String COLUMNNAME_DropShip_Warehouse_ID = "DropShip_Warehouse_ID";

View File

@ -602,6 +602,19 @@ public interface I_C_OrderLine
*/
public boolean isProcessed();
/** Column name QtyAllocated */
public static final String COLUMNNAME_QtyAllocated = "QtyAllocated";
/** Set Qty Allocated.
* Allocated quantity
*/
public void setQtyAllocated (BigDecimal QtyAllocated);
/** Get Qty Allocated.
* Allocated quantity
*/
public BigDecimal getQtyAllocated();
/** Column name QtyDelivered */
public static final String COLUMNNAME_QtyDelivered = "QtyDelivered";

View File

@ -149,6 +149,19 @@ public interface I_M_Storage
public I_M_Product getM_Product() throws RuntimeException;
/** Column name QtyAllocated */
public static final String COLUMNNAME_QtyAllocated = "QtyAllocated";
/** Set Qty Allocated.
* Allocated quantity
*/
public void setQtyAllocated (BigDecimal QtyAllocated);
/** Get Qty Allocated.
* Allocated quantity
*/
public BigDecimal getQtyAllocated();
/** Column name QtyOnHand */
public static final String COLUMNNAME_QtyOnHand = "QtyOnHand";

View File

@ -39,7 +39,9 @@ public class MClientInfo extends X_AD_ClientInfo
*
*/
private static final long serialVersionUID = 4861006368856890116L;
public static final String DELIVERY_POLICY_STRICT_ORDER = "O";
public static final String DELIVERY_POLICY_NO_HOLD = "N";
/**
* Get Client Info

View File

@ -26,6 +26,7 @@ import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.process.AllocateSalesOrders;
import org.compiere.print.ReportEngine;
import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine;
@ -64,6 +65,8 @@ public class MInOut extends X_M_InOut implements DocAction
/**
* Create Shipment From Order
* @param order order
* @param oLines order lines to use when creating the shipment. If null all lines
* from the order is used.
* @param movementDate optional movement date
* @param forceDelivery ignore order delivery rule
* @param allAttributeInstances if true, all attribute set instances
@ -72,10 +75,10 @@ public class MInOut extends X_M_InOut implements DocAction
* @param trxName transaction
* @return Shipment or null
*/
public static MInOut createFrom (MOrder order, Timestamp movementDate,
boolean forceDelivery, boolean allAttributeInstances, Timestamp minGuaranteeDate,
boolean complete, String trxName)
{
public static MInOut createFrom (MOrder order, MOrderLine[] oLines, Timestamp movementDate,
boolean forceDelivery, boolean allAttributeInstances, Timestamp minGuaranteeDate,
boolean complete, String trxName) {
if (order == null)
throw new IllegalArgumentException("No Order");
//
@ -88,10 +91,16 @@ public class MInOut extends X_M_InOut implements DocAction
MInOut retValue = new MInOut (order, 0, movementDate);
retValue.setDocAction(complete ? DOCACTION_Complete : DOCACTION_Prepare);
// Check if we can create the lines
MOrderLine[] oLines = order.getLines(true, "M_Product_ID");
if (oLines == null) {
oLines = order.getLines(true, "M_Product_ID");
}
for (int i = 0; i < oLines.length; i++)
{
if (oLines[i].getC_Order_ID()!=order.get_ID()) {
// If the orderline ID and order ID doesn't match, skip the line
continue;
}
// Calculate how much is left to deliver (ordered - delivered)
BigDecimal qty = oLines[i].getQtyOrdered().subtract(oLines[i].getQtyDelivered());
// Nothing to deliver
if (qty.signum() == 0)
@ -99,6 +108,7 @@ public class MInOut extends X_M_InOut implements DocAction
// Stock Info
MStorage[] storages = null;
MProduct product = oLines[i].getProduct();
// If the order line is a product (not a charge) and the product is stocked, find the locators
if (product != null && product.get_ID() != 0 && product.isStocked())
{
String MMPolicy = product.getMMPolicy();
@ -106,9 +116,11 @@ public class MInOut extends X_M_InOut implements DocAction
oLines[i].getM_Product_ID(), oLines[i].getM_AttributeSetInstance_ID(),
minGuaranteeDate, MClient.MMPOLICY_FiFo.equals(MMPolicy), true, 0, trxName);
} else {
// If the order is a charge or the product is not stocked, don't try to deliver it.
continue;
}
// Unless the order is force delivery then check delivery rule
if (!forceDelivery)
{
BigDecimal maxQty = Env.ZERO;
@ -119,9 +131,11 @@ public class MInOut extends X_M_InOut implements DocAction
if (maxQty.compareTo(qty) < 0)
qty = maxQty;
}
else if (DELIVERYRULE_CompleteLine.equals(order.getDeliveryRule()))
else if (DELIVERYRULE_CompleteLine.equals(order.getDeliveryRule())
|| DELIVERYRULE_CompleteOrder.equals(order.getDeliveryRule()))
{
if (maxQty.compareTo(qty) < 0)
// Not enough to deliver the complete line
continue;
}
}
@ -129,9 +143,12 @@ public class MInOut extends X_M_InOut implements DocAction
if (retValue.get_ID() == 0) // not saved yet
retValue.save(trxName);
// Create a line until qty is reached
// There will be one line per storage (if there items are stored in more than one storage)
for (int ll = 0; ll < storages.length; ll++)
{
// Set lineQty to what's available in the storage
BigDecimal lineQty = storages[ll].getQtyOnHand();
// If lineQty is more than enough, set lineQty to original qty to be delivered.
if (lineQty.compareTo(qty) > 0)
lineQty = qty;
MInOutLine line = new MInOutLine (retValue);
@ -142,6 +159,7 @@ public class MInOut extends X_M_InOut implements DocAction
line.setQtyEntered(lineQty
.multiply(oLines[i].getQtyEntered())
.divide(oLines[i].getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP));
// Set project ID if any
line.setC_Project_ID(oLines[i].getC_Project_ID());
line.save(trxName);
// Delivered everything ?
@ -158,6 +176,27 @@ public class MInOut extends X_M_InOut implements DocAction
return null;
return retValue;
}
/**
* Create Shipment From Order (using all order lines)
* @param order order
* @param movementDate optional movement date
* @param forceDelivery ignore order delivery rule
* @param allAttributeInstances if true, all attribute set instances
* @param minGuaranteeDate optional minimum guarantee date if all attribute instances
* @param complete complete document (Process if false, Complete if true)
* @param trxName transaction
* @return Shipment or null
*/
public static MInOut createFrom (MOrder order, Timestamp movementDate,
boolean forceDelivery, boolean allAttributeInstances, Timestamp minGuaranteeDate,
boolean complete, String trxName)
{
// Select all lines of the order
MOrderLine[] oLines = order.getLines(true, "M_Product_ID");
return createFrom(order, oLines, movementDate, forceDelivery, allAttributeInstances, minGuaranteeDate,complete,trxName);
} // createFrom
/**
@ -1277,6 +1316,10 @@ public class MInOut extends X_M_InOut implements DocAction
}
log.info("Line=" + sLine.getLine() + " - Qty=" + sLine.getMovementQty());
// Check delivery policy
MOrgInfo orgInfo = MOrgInfo.get(getCtx(), sLine.getAD_Org_ID(), get_TrxName());
boolean isStrictOrder = MClientInfo.DELIVERY_POLICY_STRICT_ORDER.equalsIgnoreCase(orgInfo.getDeliveryPolicy());
// Stock Movement - Counterpart MOrder.reserveStock
if (product != null
@ -1311,10 +1354,13 @@ public class MInOut extends X_M_InOut implements DocAction
QtyMA = QtyMA.negate();
BigDecimal reservedDiff = Env.ZERO;
BigDecimal orderedDiff = Env.ZERO;
BigDecimal allocatedDiff = Env.ZERO;
if (sLine.getC_OrderLine_ID() != 0)
{
if (isSOTrx())
if (isSOTrx()) {
reservedDiff = ma.getMovementQty().negate();
allocatedDiff = ma.getMovementQty().negate();
}
else
orderedDiff = ma.getMovementQty().negate();
}
@ -1328,6 +1374,7 @@ public class MInOut extends X_M_InOut implements DocAction
QtyMA,
sameWarehouse ? reservedDiff : Env.ZERO,
sameWarehouse ? orderedDiff : Env.ZERO,
sameWarehouse && isStrictOrder ? allocatedDiff : Env.ZERO,
get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
@ -1340,7 +1387,7 @@ public class MInOut extends X_M_InOut implements DocAction
wh.getDefaultLocator().getM_Locator_ID(),
sLine.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
Env.ZERO, reservedDiff, orderedDiff, get_TrxName()))
Env.ZERO, reservedDiff, orderedDiff, allocatedDiff, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA) in order warehouse";
return DocAction.STATUS_Invalid;
@ -1364,13 +1411,14 @@ public class MInOut extends X_M_InOut implements DocAction
{
BigDecimal reservedDiff = sameWarehouse ? QtySO.negate() : Env.ZERO;
BigDecimal orderedDiff = sameWarehouse ? QtyPO.negate(): Env.ZERO;
BigDecimal allocatedDiff = isStrictOrder ? reservedDiff : Env.ZERO;
// Fallback: Update Storage - see also VMatch.createMatchRecord
if (!MStorage.add(getCtx(), getM_Warehouse_ID(),
sLine.getM_Locator_ID(),
sLine.getM_Product_ID(),
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
Qty, reservedDiff, orderedDiff, get_TrxName()))
Qty, reservedDiff, orderedDiff, allocatedDiff, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory";
return DocAction.STATUS_Invalid;
@ -1382,7 +1430,7 @@ public class MInOut extends X_M_InOut implements DocAction
wh.getDefaultLocator().getM_Locator_ID(),
sLine.getM_Product_ID(),
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
Env.ZERO, QtySO.negate(), QtyPO.negate(), get_TrxName()))
Env.ZERO, QtySO.negate(), QtyPO.negate(), allocatedDiff, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory";
return DocAction.STATUS_Invalid;
@ -1412,10 +1460,15 @@ public class MInOut extends X_M_InOut implements DocAction
if (isSOTrx() // PO is done by Matching
|| sLine.getM_Product_ID() == 0) // PO Charges, empty lines
{
if (isSOTrx())
if (isSOTrx()) {
oLine.setQtyDelivered(oLine.getQtyDelivered().subtract(Qty));
else
// Adjust allocated on order line
if (isStrictOrder && product.isStocked()) oLine.setQtyAllocated(oLine.getQtyAllocated().add(Qty));
} else {
oLine.setQtyDelivered(oLine.getQtyDelivered().add(Qty));
// Adjust allocated on order line
if (isStrictOrder && product.isStocked()) oLine.setQtyAllocated(oLine.getQtyAllocated().subtract(Qty));
}
oLine.setDateDelivered(getMovementDate()); // overwrite=last
}
if (!oLine.save())

View File

@ -431,7 +431,7 @@ public class MInventory extends X_M_Inventory implements DocAction
line.getM_Locator_ID(),
line.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), 0,
QtyMA.negate(), Env.ZERO, Env.ZERO, get_TrxName()))
QtyMA.negate(), Env.ZERO, Env.ZERO, Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;
@ -489,7 +489,7 @@ public class MInventory extends X_M_Inventory implements DocAction
line.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), 0,
qtyDiff, Env.ZERO, Env.ZERO, get_TrxName()))
qtyDiff, Env.ZERO, Env.ZERO, Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;

View File

@ -403,7 +403,7 @@ public class MMovement extends X_M_Movement implements DocAction
line.getM_Locator_ID(),
line.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), 0,
ma.getMovementQty().negate(), Env.ZERO , Env.ZERO , get_TrxName()))
ma.getMovementQty().negate(), Env.ZERO , Env.ZERO , Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;
@ -420,7 +420,7 @@ public class MMovement extends X_M_Movement implements DocAction
line.getM_LocatorTo_ID(),
line.getM_Product_ID(),
M_AttributeSetInstanceTo_ID, 0,
ma.getMovementQty(), Env.ZERO , Env.ZERO , get_TrxName()))
ma.getMovementQty(), Env.ZERO , Env.ZERO , Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;
@ -459,7 +459,7 @@ public class MMovement extends X_M_Movement implements DocAction
line.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), 0,
line.getMovementQty().negate(), Env.ZERO , Env.ZERO , get_TrxName()))
line.getMovementQty().negate(), Env.ZERO , Env.ZERO , Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;
@ -470,7 +470,7 @@ public class MMovement extends X_M_Movement implements DocAction
line.getM_LocatorTo_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstanceTo_ID(), 0,
line.getMovementQty(), Env.ZERO , Env.ZERO , get_TrxName()))
line.getMovementQty(), Env.ZERO , Env.ZERO , Env.ZERO, get_TrxName()))
{
m_processMsg = "Cannot correct Inventory (MA)";
return DocAction.STATUS_Invalid;

View File

@ -1391,7 +1391,7 @@ public class MOrder extends X_C_Order implements DocAction
* @param lines order lines (ordered by M_Product_ID for deadlock prevention)
* @return true if (un) reserved
*/
private boolean reserveStock (MDocType dt, MOrderLine[] lines)
public boolean reserveStock (MDocType dt, MOrderLine[] lines)
{
if (dt == null)
dt = MDocType.get(getCtx(), getC_DocType_ID());
@ -1415,6 +1415,7 @@ public class MOrder extends X_C_Order implements DocAction
BigDecimal Volume = Env.ZERO;
BigDecimal Weight = Env.ZERO;
BigDecimal diffQtyAllocated = Env.ZERO;
// Always check and (un) Reserve Inventory
for (int i = 0; i < lines.length; i++)
@ -1480,15 +1481,28 @@ public class MOrder extends X_C_Order implements DocAction
M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
}
}
// Update Storage
// == Update Storage
// reserve but don't allocate if quantity is increased.
// If quantity is decreased, release allocation.
if (reserved.signum()<0) {
// Decreasing reservation, check if allocation should be released
diffQtyAllocated = target.subtract(line.getQtyAllocated());
diffQtyAllocated = diffQtyAllocated.min(BigDecimal.ZERO);
} else {
diffQtyAllocated = BigDecimal.ZERO;
}
if (!MStorage.add(getCtx(), line.getM_Warehouse_ID(), M_Locator_ID,
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
Env.ZERO, reserved, ordered, get_TrxName()))
Env.ZERO, reserved, ordered, diffQtyAllocated, get_TrxName()))
return false;
// == End of update storage
} // stockec
// update line
line.setQtyReserved(line.getQtyReserved().add(difference));
if (diffQtyAllocated.signum()!=0) {
line.setQtyAllocated(line.getQtyAllocated().add(diffQtyAllocated));
}
if (!line.save(get_TrxName()))
return false;
//

View File

@ -27,6 +27,7 @@ import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Trx;
/**
* Order Line Model.
@ -118,6 +119,7 @@ public class MOrderLine extends X_C_OrderLine
return retValue;
} // getNotReserved
/** Logger */
private static CLogger s_log = CLogger.getCLogger (MOrderLine.class);
@ -573,6 +575,97 @@ public class MOrderLine extends X_C_OrderLine
// We can change
return true;
} // canChangeWarehouse
/**
* Allocates at most 'toAllocate' number of items.
* If the toAllocate is a negative number material is unallocated.
*
* @return Number allocated
*/
public BigDecimal allocateOnHand(BigDecimal toAllocate, String trxName) {
if (BigDecimal.ZERO.equals(toAllocate))
return BigDecimal.ZERO;
boolean reverse = toAllocate.signum()<0;
BigDecimal allocated = BigDecimal.ZERO;
MProduct product = getProduct();
boolean fifo = MClient.MMPOLICY_FiFo.equals(product.getMMPolicy());
// Find storages
MStorage[] storages = MStorage.getWarehouse(
getCtx(),
getM_Warehouse_ID(),
getM_Product_ID(),
getM_AttributeSetInstance_ID(),
null, // TODO: Min Guarantee date
fifo, // Material policy
!reverse, // Return positive only unless this is a reverse allocation.
0, // Optional Locator ID (check all locators)
trxName);
MStorage s;
BigDecimal unallocated;
BigDecimal allocate;
if (!reverse) {
// Normal allocation
// Iterate through the storages and allocate
for (int i = 0; i<storages.length; i++) {
s = storages[i];
if (s.getQtyOnHand().signum()<=0) break; // Nothing to allocate.
unallocated = s.getQtyOnHand().subtract(s.getQtyAllocated());
if (unallocated.signum()>0) {
allocate = toAllocate.min(unallocated); // Allocate all unallocated or max of what we want to allocate.
allocated = allocated.add(allocate);
// Update storage
s.setQtyAllocated(s.getQtyAllocated().add(allocate));
s.saveEx(trxName); // Save storage
// Update order line
setQtyAllocated(getQtyAllocated().add(allocate));
// Adjust toAllocate
toAllocate = toAllocate.subtract(allocate);
// If what we have allocated now is what we want to allocate then
// exit this loop.
if (toAllocate.signum()<=0) {
break;
}
}
}
} else {
// Reverse allocation
BigDecimal currentlyAllocated;
BigDecimal unallocate;
BigDecimal toUnallocate = toAllocate.abs();
unallocated = BigDecimal.ZERO;
for (int i = 0; i<storages.length; i++) {
s = storages[i];
currentlyAllocated = s.getQtyAllocated();
if (currentlyAllocated.signum()>0) {
unallocate = currentlyAllocated.min(toUnallocate);
unallocated = unallocated.add(unallocate);
// Update storage
s.setQtyAllocated(currentlyAllocated.subtract(unallocate));
s.saveEx(trxName);
// Update order line
setQtyAllocated(getQtyAllocated().subtract(unallocate));
// Adjust toUnallocate
toUnallocate = toUnallocate.subtract(unallocate);
// If we have unallocated all, exit this loop
if (toUnallocate.signum()<=0) {
break;
}
}
}
allocated = unallocated.negate();
}
if (allocated.signum()!=0) {
// Save order line
saveEx(trxName);
}
return(allocated);
}
/**
* Get C_Project_ID
@ -936,9 +1029,18 @@ public class MOrderLine extends X_C_OrderLine
}
if (Env.ZERO.compareTo(getQtyReserved()) != 0)
{
// Unreserve
setQty(BigDecimal.ZERO);
((MOrder)getC_Order()).reserveStock(null, new MOrderLine[]{this});
// For PO should be On Order
log.saveError("DeleteError", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved());
return false;
if (!getQtyReserved().equals(BigDecimal.ZERO)) {
log.saveError("DeleteError", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved());
return false;
}
}
if (Env.ZERO.compareTo(getQtyAllocated()) != 0) {
// Unallocate
allocateOnHand(getQtyAllocated().negate(), get_TrxName());
}
// UnLink All Requisitions

View File

@ -20,6 +20,7 @@ import java.sql.ResultSet;
import java.util.Properties;
import org.compiere.util.CCache;
import org.compiere.util.Env;
/**
* Organization Info Model
@ -100,4 +101,19 @@ public class MOrgInfo extends X_AD_OrgInfo
setTaxID ("?");
} // MOrgInfo
/**
* Returns the delivery policy of this organization. If no specific organization is set
* the delivery policy of the client is returned
*/
@Override
public String getDeliveryPolicy() {
String orgDeliveryPolicy = super.getDeliveryPolicy();
if (orgDeliveryPolicy!=null && orgDeliveryPolicy.trim().length()>0) {
return(orgDeliveryPolicy);
}
// Get the client's delivery policy
MClientInfo info = MClientInfo.get(Env.getCtx(), getAD_Client_ID());
return(info.getDeliveryPolicy());
}
}

View File

@ -165,7 +165,7 @@ public class MProjectIssue extends X_C_ProjectIssue
MLocator loc = MLocator.get(getCtx(), getM_Locator_ID());
if (MStorage.add(getCtx(), loc.getM_Warehouse_ID(), getM_Locator_ID(),
getM_Product_ID(), getM_AttributeSetInstance_ID(), getM_AttributeSetInstance_ID(),
getMovementQty().negate(), null, null, get_TrxName()))
getMovementQty().negate(), null, null, null, get_TrxName()))
{
if (mTrx.save(get_TrxName()))
{

View File

@ -267,7 +267,7 @@ public class MStorage extends X_M_Storage
// Specific Attribute Set Instance
String sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.QtyAllocated,s.DateLastInventory "
+ "FROM M_Storage s"
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) ";
if (M_Locator_ID > 0)
@ -292,7 +292,7 @@ public class MStorage extends X_M_Storage
{
sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.QtyAllocated,s.DateLastInventory "
+ "FROM M_Storage s"
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)"
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) ";
@ -413,7 +413,10 @@ public class MStorage extends X_M_Storage
public static boolean add (Properties ctx, int M_Warehouse_ID, int M_Locator_ID,
int M_Product_ID, int M_AttributeSetInstance_ID, int reservationAttributeSetInstance_ID,
BigDecimal diffQtyOnHand,
BigDecimal diffQtyReserved, BigDecimal diffQtyOrdered, String trxName)
BigDecimal diffQtyReserved,
BigDecimal diffQtyOrdered,
BigDecimal diffQtyAllocated,
String trxName)
{
MStorage storage = null;
StringBuffer diffText = new StringBuffer("(");
@ -478,6 +481,15 @@ public class MStorage extends X_M_Storage
diffText.append(" Ordered=").append(diffQtyOrdered);
changed = true;
}
if (diffQtyAllocated !=null && diffQtyAllocated.signum() != 0)
{
if (storage0 == null)
storage.setQtyAllocated(storage.getQtyAllocated().add(diffQtyAllocated));
else
storage0.setQtyAllocated(storage0.getQtyAllocated().add(diffQtyAllocated));
diffText.append(" Allocated=").append(diffQtyAllocated);
changed = true;
}
if (changed)
{
diffText.append(") -> ").append(storage.toString());
@ -611,6 +623,47 @@ public class MStorage extends X_M_Storage
return retValue;
} // getQtyAvailable
/**
* Get Warehouse/Locator on hand Qty.
* The call is accurate only if there is a storage record
* and assumes that the product is stocked
* @param M_Warehouse_ID wh (if the M_Locator_ID!=0 then M_Warehouse_ID is ignored)
* @param M_Locator_ID locator (if 0, the whole warehouse will be evaluated)
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID masi
* @param trxName transaction
* @return qty on hand (QtyOnHand) or null if error
*/
public static BigDecimal getQtyOnHand (int M_Warehouse_ID, int M_Locator_ID,
int M_Product_ID, int M_AttributeSetInstance_ID, String trxName)
{
ArrayList<Object> params = new ArrayList<Object>();
StringBuffer sql = new StringBuffer("SELECT COALESCE(SUM(s.QtyOnHand),0)")
.append(" FROM M_Storage s")
.append(" WHERE s.M_Product_ID=?");
params.add(M_Product_ID);
// Warehouse level
if (M_Locator_ID == 0) {
sql.append(" AND EXISTS (SELECT 1 FROM M_Locator l WHERE s.M_Locator_ID=l.M_Locator_ID AND l.M_Warehouse_ID=?)");
params.add(M_Warehouse_ID);
}
// Locator level
else {
sql.append(" AND s.M_Locator_ID=?");
params.add(M_Locator_ID);
}
// With ASI
if (M_AttributeSetInstance_ID != 0) {
sql.append(" AND s.M_AttributeSetInstance_ID=?");
params.add(M_AttributeSetInstance_ID);
}
//
BigDecimal retValue = DB.getSQLValueBD(trxName, sql.toString(), params);
if (CLogMgt.isLevelFine())
s_log.fine("M_Warehouse_ID=" + M_Warehouse_ID + ", M_Locator_ID=" + M_Locator_ID
+ ",M_Product_ID=" + M_Product_ID + " = " + retValue);
return retValue;
} // getQtyAvailable
/**************************************************************************
* Persistency Constructor

View File

@ -29,7 +29,7 @@ public class X_AD_ClientInfo extends PO implements I_AD_ClientInfo, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20100614L;
private static final long serialVersionUID = 20100622L;
/** Standard Constructor */
public X_AD_ClientInfo (Properties ctx, int AD_ClientInfo_ID, String trxName)
@ -433,6 +433,34 @@ public class X_AD_ClientInfo extends PO implements I_AD_ClientInfo, I_Persistent
return ii.intValue();
}
public I_C_UOM getC_UOM_Weight() throws RuntimeException
{
return (I_C_UOM)MTable.get(getCtx(), I_C_UOM.Table_Name)
.getPO(getC_UOM_Weight_ID(), get_TrxName()); }
/** Set UOM for Weight.
@param C_UOM_Weight_ID
Standard Unit of Measure for Weight
*/
public void setC_UOM_Weight_ID (int C_UOM_Weight_ID)
{
if (C_UOM_Weight_ID < 1)
set_Value (COLUMNNAME_C_UOM_Weight_ID, null);
else
set_Value (COLUMNNAME_C_UOM_Weight_ID, Integer.valueOf(C_UOM_Weight_ID));
}
/** Get UOM for Weight.
@return Standard Unit of Measure for Weight
*/
public int getC_UOM_Weight_ID ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_C_UOM_Weight_ID);
if (ii == null)
return 0;
return ii.intValue();
}
public I_C_UOM getC_UOM_Volume() throws RuntimeException
{
return (I_C_UOM)MTable.get(getCtx(), I_C_UOM.Table_Name)
@ -461,32 +489,28 @@ public class X_AD_ClientInfo extends PO implements I_AD_ClientInfo, I_Persistent
return ii.intValue();
}
public I_C_UOM getC_UOM_Weight() throws RuntimeException
{
return (I_C_UOM)MTable.get(getCtx(), I_C_UOM.Table_Name)
.getPO(getC_UOM_Weight_ID(), get_TrxName()); }
/** Set UOM for Weight.
@param C_UOM_Weight_ID
Standard Unit of Measure for Weight
/** DeliveryPolicy AD_Reference_ID=53355 */
public static final int DELIVERYPOLICY_AD_Reference_ID=53355;
/** No Hold = N */
public static final String DELIVERYPOLICY_NoHold = "N";
/** Strict order = O */
public static final String DELIVERYPOLICY_StrictOrder = "O";
/** Set Delivery Policy.
@param DeliveryPolicy
Delivery Policy
*/
public void setC_UOM_Weight_ID (int C_UOM_Weight_ID)
public void setDeliveryPolicy (String DeliveryPolicy)
{
if (C_UOM_Weight_ID < 1)
set_Value (COLUMNNAME_C_UOM_Weight_ID, null);
else
set_Value (COLUMNNAME_C_UOM_Weight_ID, Integer.valueOf(C_UOM_Weight_ID));
set_Value (COLUMNNAME_DeliveryPolicy, DeliveryPolicy);
}
/** Get UOM for Weight.
@return Standard Unit of Measure for Weight
/** Get Delivery Policy.
@return Delivery Policy
*/
public int getC_UOM_Weight_ID ()
public String getDeliveryPolicy ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_C_UOM_Weight_ID);
if (ii == null)
return 0;
return ii.intValue();
return (String)get_Value(COLUMNNAME_DeliveryPolicy);
}
/** Set Discount calculated from Line Amounts.

View File

@ -29,7 +29,7 @@ public class X_AD_OrgInfo extends PO implements I_AD_OrgInfo, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20100614L;
private static final long serialVersionUID = 20100622L;
/** Standard Constructor */
public X_AD_OrgInfo (Properties ctx, int AD_OrgInfo_ID, String trxName)
@ -156,6 +156,30 @@ public class X_AD_OrgInfo extends PO implements I_AD_OrgInfo, I_Persistent
return ii.intValue();
}
/** DeliveryPolicy AD_Reference_ID=53355 */
public static final int DELIVERYPOLICY_AD_Reference_ID=53355;
/** No Hold = N */
public static final String DELIVERYPOLICY_NoHold = "N";
/** Strict order = O */
public static final String DELIVERYPOLICY_StrictOrder = "O";
/** Set Delivery Policy.
@param DeliveryPolicy
Delivery Policy
*/
public void setDeliveryPolicy (String DeliveryPolicy)
{
set_Value (COLUMNNAME_DeliveryPolicy, DeliveryPolicy);
}
/** Get Delivery Policy.
@return Delivery Policy
*/
public String getDeliveryPolicy ()
{
return (String)get_Value(COLUMNNAME_DeliveryPolicy);
}
public I_M_Warehouse getDropShip_Warehouse() throws RuntimeException
{
return (I_M_Warehouse)MTable.get(getCtx(), I_M_Warehouse.Table_Name)

View File

@ -33,7 +33,7 @@ public class X_C_OrderLine extends PO implements I_C_OrderLine, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20100614L;
private static final long serialVersionUID = 20100622L;
/** Standard Constructor */
public X_C_OrderLine (Properties ctx, int C_OrderLine_ID, String trxName)
@ -998,6 +998,26 @@ public class X_C_OrderLine extends PO implements I_C_OrderLine, I_Persistent
return false;
}
/** Set Qty Allocated.
@param QtyAllocated
Allocated quantity
*/
public void setQtyAllocated (BigDecimal QtyAllocated)
{
set_Value (COLUMNNAME_QtyAllocated, QtyAllocated);
}
/** Get Qty Allocated.
@return Allocated quantity
*/
public BigDecimal getQtyAllocated ()
{
BigDecimal bd = (BigDecimal)get_Value(COLUMNNAME_QtyAllocated);
if (bd == null)
return Env.ZERO;
return bd;
}
/** Set Delivered Quantity.
@param QtyDelivered
Delivered Quantity

View File

@ -32,7 +32,7 @@ public class X_M_Storage extends PO implements I_M_Storage, I_Persistent
/**
*
*/
private static final long serialVersionUID = 20100614L;
private static final long serialVersionUID = 20100622L;
/** Standard Constructor */
public X_M_Storage (Properties ctx, int M_Storage_ID, String trxName)
@ -178,6 +178,26 @@ public class X_M_Storage extends PO implements I_M_Storage, I_Persistent
return ii.intValue();
}
/** Set Qty Allocated.
@param QtyAllocated
Allocated quantity
*/
public void setQtyAllocated (BigDecimal QtyAllocated)
{
set_Value (COLUMNNAME_QtyAllocated, QtyAllocated);
}
/** Get Qty Allocated.
@return Allocated quantity
*/
public BigDecimal getQtyAllocated ()
{
BigDecimal bd = (BigDecimal)get_Value(COLUMNNAME_QtyAllocated);
if (bd == null)
return Env.ZERO;
return bd;
}
/** Set On Hand Quantity.
@param QtyOnHand
On Hand Quantity

View File

@ -24,13 +24,17 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import org.adempiere.process.AllocateSalesOrders;
import org.compiere.model.MClient;
import org.compiere.model.MClientInfo;
import org.compiere.model.MInOut;
import org.compiere.model.MInOutLine;
import org.compiere.model.MOrder;
import org.compiere.model.MOrderLine;
import org.compiere.model.MOrgInfo;
import org.compiere.model.MProduct;
import org.compiere.model.MStorage;
import org.compiere.model.MWarehouse;
import org.compiere.util.AdempiereUserError;
import org.compiere.util.DB;
import org.compiere.util.Env;
@ -75,6 +79,11 @@ public class InOutGenerate extends SvrProcess
/** The Query sql */
private String m_sql = null;
/** Strict order flag */
private boolean m_strictOrder = false;
/** Warehouse */
private MWarehouse m_warehouse;
/** Storages temp space */
private HashMap<SParameter,MStorage[]> m_map = new HashMap<SParameter,MStorage[]>();
@ -89,6 +98,7 @@ public class InOutGenerate extends SvrProcess
*/
protected void prepare()
{
ProcessInfoParameter[] para = getParameter();
for (int i = 0; i < para.length; i++)
{
@ -125,6 +135,8 @@ public class InOutGenerate extends SvrProcess
if (!DocAction.ACTION_Complete.equals(p_docAction))
p_docAction = DocAction.ACTION_Prepare;
}
} // prepare
/**
@ -143,6 +155,11 @@ public class InOutGenerate extends SvrProcess
if (p_M_Warehouse_ID == 0)
throw new AdempiereUserError("@NotFound@ @M_Warehouse_ID@");
// Get client info for warehouse
m_warehouse = new MWarehouse(this.getCtx(), p_M_Warehouse_ID, this.get_TrxName());
MOrgInfo orgInfo = MOrgInfo.get(getCtx(), m_warehouse.getAD_Org_ID(), get_TrxName());
m_strictOrder = MClientInfo.DELIVERY_POLICY_STRICT_ORDER.equalsIgnoreCase(orgInfo.getDeliveryPolicy());
if (p_Selection) // VInOutGen
{
@ -164,6 +181,10 @@ public class InOutGenerate extends SvrProcess
// Open Order Lines with Warehouse
+ " AND EXISTS (SELECT * FROM C_OrderLine ol "
+ "WHERE ol.M_Warehouse_ID=?"; // #1
// And the lines have allocated stock
if (m_strictOrder) {
m_sql += " AND (ol.qtyAllocated>0 OR (SELECT IsShippable(ol.M_Product_ID))='N')";
}
if (p_DatePromised != null)
m_sql += " AND TRUNC(ol.DatePromised)<=?"; // #2
m_sql += " AND o.C_Order_ID=ol.C_Order_ID AND ol.QtyOrdered<>ol.QtyDelivered)";
@ -228,7 +249,11 @@ public class InOutGenerate extends SvrProcess
String where = " AND M_Warehouse_ID=" + p_M_Warehouse_ID;
if (p_DatePromised != null)
where += " AND (TRUNC(DatePromised)<=" + DB.TO_DATE(p_DatePromised, true)
+ " OR DatePromised IS NULL)";
+ " OR DatePromised IS NULL)";
// Strict order
if (m_strictOrder) {
where += " AND (QtyAllocated>0 OR (SELECT IsShippable(M_Product_ID))='N')";
}
// Exclude Auto Delivery if not Force
if (!MOrder.DELIVERYRULE_Force.equals(order.getDeliveryRule()))
where += " AND (C_OrderLine.M_Product_ID IS NULL"
@ -251,6 +276,9 @@ public class InOutGenerate extends SvrProcess
BigDecimal onHand = Env.ZERO;
BigDecimal toDeliver = line.getQtyOrdered()
.subtract(line.getQtyDelivered());
BigDecimal qtyAllocated = (BigDecimal)line.getQtyAllocated();
MProduct product = line.getProduct();
// Nothing to Deliver
if (product != null && toDeliver.signum() == 0)
@ -305,13 +333,14 @@ public class InOutGenerate extends SvrProcess
MStorage storage = storages[j];
onHand = onHand.add(storage.getQtyOnHand());
}
boolean fullLine = onHand.compareTo(toDeliver) >= 0
|| toDeliver.signum() < 0;
boolean fullLine = m_strictOrder ? (qtyAllocated.compareTo(toDeliver)>=0 || toDeliver.signum() < 0)
: (onHand.compareTo(toDeliver) >= 0 || toDeliver.signum() < 0);
// Complete Order
if (completeOrder && !fullLine)
{
log.fine("Failed CompleteOrder - OnHand=" + onHand
log.fine("Failed CompleteOrder - OnHand=" + onHand
+ " Allocated=" + qtyAllocated
+ " (Unconfirmed=" + unconfirmedShippedQty
+ "), ToDeliver=" + toDeliver + " - " + line);
completeOrder = false;
@ -323,15 +352,15 @@ public class InOutGenerate extends SvrProcess
log.fine("CompleteLine - OnHand=" + onHand
+ " (Unconfirmed=" + unconfirmedShippedQty
+ ", ToDeliver=" + toDeliver + " - " + line);
//
//
createLine (order, line, toDeliver, storages, false);
}
// Availability
else if (MOrder.DELIVERYRULE_Availability.equals(order.getDeliveryRule())
&& (onHand.signum() > 0
&& (onHand.signum() > 0 && ((m_strictOrder && qtyAllocated.signum() > 0) || !m_strictOrder)
|| toDeliver.signum() < 0))
{
BigDecimal deliver = toDeliver;
BigDecimal deliver = m_strictOrder ? qtyAllocated : toDeliver;
if (deliver.compareTo(onHand) > 0)
deliver = onHand;
log.fine("Available - OnHand=" + onHand
@ -372,7 +401,11 @@ public class InOutGenerate extends SvrProcess
if (line.getM_Warehouse_ID() != p_M_Warehouse_ID)
continue;
MProduct product = line.getProduct();
BigDecimal toDeliver = line.getQtyOrdered().subtract(line.getQtyDelivered());
BigDecimal toDeliver;
if (m_strictOrder && product.isStocked())
toDeliver = (BigDecimal)line.getQtyAllocated();
else
toDeliver = line.getQtyOrdered().subtract(line.getQtyDelivered());
//
MStorage[] storages = null;
if (product != null && product.isStocked())

View File

@ -160,6 +160,7 @@ public class M_Production_Run extends SvrProcess {
MovementQty,
Env.ZERO,
Env.ZERO,
Env.ZERO,
get_TrxName()))
{
raiseError("Cannot correct Inventory", "");

View File

@ -17,16 +17,24 @@
package org.compiere.process;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import org.compiere.model.MClient;
import org.compiere.model.MLocator;
import org.compiere.model.MMovement;
import org.compiere.model.MMovementLine;
import org.compiere.model.MProduct;
import org.compiere.model.MRefList;
import org.compiere.model.MStorage;
import org.compiere.model.Query;
import org.compiere.util.DB;
import org.compiere.util.Env;
@ -98,15 +106,18 @@ public class StorageCleanup extends SvrProcess
PreparedStatement pstmt = null;
ResultSet rs = null;
int lines = 0;
int allocationLines = 0;
try
{
pstmt = DB.prepareStatement (sql, get_TrxName());
/** pstmt = DB.prepareStatement (sql, get_TrxName());
pstmt.setInt(1, Env.getAD_Client_ID(getCtx()));
rs = pstmt.executeQuery ();
while (rs.next ())
{
lines += move (new MStorage(getCtx(), rs, get_TrxName()));
}
} */
// Clean up allocations
allocationLines = cleanupAllocations();
}
catch (Exception e)
{
@ -114,13 +125,125 @@ public class StorageCleanup extends SvrProcess
}
finally
{
DB.close(rs, pstmt);
// DB.close(rs, pstmt);
rs = null; pstmt = null;
}
return "#" + lines;
return "#" + lines + ", # " + allocationLines + " cleared allocations.";
} // doIt
/**
* This method cleans up allocations in storages. Currently it only cleans up allocations
* of products where no product is reserved. If there are storages with more than 0 items
* allocated of a specific product and nothing is reserved then the storages' allocation
* is set to zero.
*/
private int cleanupAllocations() throws Exception {
// TODO: Fix this method. It must be able to both clean up allocations that should
// be zero and storages that are "over allocated".
// Find all allocations that should be zero
String query = "SELECT M_Product_ID, M_Warehouse_ID FROM M_Product_Stock_v WHERE " +
"(QtyAllocated>0 and " +
"(select sum(QtyReserved) from M_Product_Stock_v WHERE M_Product_ID=M_Product_ID and M_Warehouse_ID=M_Warehouse_ID)<=0) " +
"OR qtyAllocated<0";
Statement stmt = DB.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, get_TrxName());
ResultSet rs = null;
List<MStorage> storages;
int productId, warehouseId;
MProduct product;
MStorage storage;
int adjustmentCounter = 0;
/**
rs = stmt.executeQuery(query);
while(rs.next()) {
productId = rs.getInt(1);
warehouseId = rs.getInt(2);
product = new MProduct(getCtx(),productId,get_TrxName());
storages = new Query(getCtx(), MStorage.Table_Name, "M_Product_ID=? and (select M_Warehouse_ID from M_Locator where M_Storage.M_Locator_ID=M_Locator_ID) in (?) and QtyAllocated<>0", get_TrxName())
.setParameters(new Object[]{productId, warehouseId})
.list();
// Iterate through storages
for (Iterator<MStorage> it = storages.iterator(); it.hasNext();) {
storage = it.next();
storage.setQtyAllocated(Env.ZERO);
storage.saveEx(get_TrxName());
log.info("Ajusted allocation for product " + product.getValue() + " " + product.getName());
adjustmentCounter++;
}
}
stmt.close();
rs.close();
*/
BigDecimal allocatedStorage;
BigDecimal allocatedOrder;
BigDecimal diff;
BigDecimal tmpQty;
// stmt = DB.createStatement();
// Find all storages that have more items allocated than what is allocated on order level
query = "SELECT M_Product_ID, M_Warehouse_ID, QtyAllocated, get_allocated_on_order(M_Product_ID, M_Warehouse_ID) FROM M_Product_Stock_v WHERE " +
"QtyAllocated>(select get_allocated_on_order(M_Product_ID, M_Warehouse_ID))";
rs = stmt.executeQuery(query);
String where = "M_Product_ID=? and (select M_Warehouse_ID from M_Locator where M_Storage.M_Locator_ID=M_Locator_ID) in (?) and QtyAllocated<>0";
String q2 = "select * from M_Storage where " + where;
ResultSet rs2;
PreparedStatement ps;
while(rs.next()) {
productId = rs.getInt(1);
warehouseId = rs.getInt(2);
allocatedStorage = rs.getBigDecimal(3);
allocatedOrder = rs.getBigDecimal(4);
diff = allocatedStorage.subtract(allocatedOrder);
product = new MProduct(getCtx(),productId,get_TrxName());
storages = new Query(getCtx(), MStorage.Table_Name, where , get_TrxName())
.setParameters(new Object[]{productId, warehouseId})
.list();
if (storages.size()==0) {
Connection conn = DB.getConnectionRO();
ps = conn.prepareStatement(q2);
ps.setInt(1, productId);
ps.setInt(2, warehouseId);
rs2 = ps.executeQuery();
storages = new Vector<MStorage>();
while(rs2.next()) {
storage = new MStorage(getCtx(), rs2, get_TrxName());
storages.add(storage);
}
rs2.close();
ps.close();
conn.close();
}
// Iterate through storages
for (Iterator<MStorage> it = storages.iterator(); it.hasNext() && diff.signum()>0;) {
storage = it.next();
tmpQty = storage.getQtyAllocated();
tmpQty = tmpQty.min(diff);
if (tmpQty.signum()!=0) {
storage.setQtyAllocated(storage.getQtyAllocated().subtract(tmpQty));
storage.saveEx(get_TrxName());
// Decrease difference
diff = diff.subtract(tmpQty);
log.info("Ajusted allocation for product " + product.getValue() + " " + product.getName() + " Changed: " + tmpQty);
adjustmentCounter++;
}
}
}
DB.close(rs, stmt);
return(adjustmentCounter);
}
/**
* Move stock to location
* @param target target storage
@ -183,6 +306,7 @@ public class StorageCleanup extends SvrProcess
/**
* Eliminate Reserved/Ordered
* Allocation is left untouched.
* @param target target Storage
*/
private void eliminateReservation(MStorage target)
@ -217,12 +341,12 @@ public class StorageCleanup extends SvrProcess
if (MStorage.add(getCtx(), target.getM_Warehouse_ID(), target.getM_Locator_ID(),
target.getM_Product_ID(),
target.getM_AttributeSetInstance_ID(), target.getM_AttributeSetInstance_ID(),
Env.ZERO, reserved.negate(), ordered.negate(), get_TrxName()))
Env.ZERO, reserved.negate(), ordered.negate(), Env.ZERO, get_TrxName()))
{
if (MStorage.add(getCtx(), storage0.getM_Warehouse_ID(), storage0.getM_Locator_ID(),
storage0.getM_Product_ID(),
storage0.getM_AttributeSetInstance_ID(), storage0.getM_AttributeSetInstance_ID(),
Env.ZERO, reserved, ordered, get_TrxName()))
Env.ZERO, reserved, ordered, Env.ZERO, get_TrxName()))
log.info("Reserved=" + reserved + ",Ordered=" + ordered);
else
log.warning("Failed Storage0 Update");

View File

@ -689,17 +689,13 @@ public class MDDOrder extends X_DD_Order implements DocAction
{
if (is_ValueChanged(columnName))
{
final String whereClause = I_DD_Order.COLUMNNAME_DD_Order_ID + "=?";
List<MDDOrderLine> lines = new Query (getCtx(), I_DD_OrderLine.Table_Name, whereClause, get_TrxName())
.setParameters(getDD_Order_ID())
.list();
for (MDDOrderLine line : lines)
{
line.set_ValueOfColumn(columnName, get_Value(columnName));
line.saveEx();
log.fine(columnName + " Lines -> #" + get_Value(columnName));
}
String sql = "UPDATE DD_OrderLine ol"
+ " SET " + columnName + " ="
+ "(SELECT " + columnName
+ " FROM DD_Order o WHERE ol.DD_Order_ID=o.DD_Order_ID) "
+ "WHERE DD_Order_ID=" + getDD_Order_ID();
int no = DB.executeUpdate(sql, get_TrxName());
log.fine(columnName + " Lines -> #" + no);
}
} // afterSaveSync
@ -843,7 +839,8 @@ public class MDDOrder extends X_DD_Order implements DocAction
/**
* Reserve Inventory.
* Reserve Inventory.
* No allocation is done.
* Counterpart: MMovement.completeIt()
* @param lines distribution order lines (ordered by M_Product_ID for deadlock prevention)
* @return true if (un) reserved
@ -886,7 +883,7 @@ public class MDDOrder extends X_DD_Order implements DocAction
if (!MStorage.add(getCtx(), locator_to.getM_Warehouse_ID(), locator_to.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
Env.ZERO, Env.ZERO , reserved_ordered , get_TrxName()))
Env.ZERO, Env.ZERO , reserved_ordered , Env.ZERO, get_TrxName()))
{
throw new AdempiereException();
}
@ -894,7 +891,7 @@ public class MDDOrder extends X_DD_Order implements DocAction
if (!MStorage.add(getCtx(), locator_from.getM_Warehouse_ID(), locator_from.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstanceTo_ID(), line.getM_AttributeSetInstance_ID(),
Env.ZERO, reserved_ordered, Env.ZERO , get_TrxName()))
Env.ZERO, reserved_ordered, Env.ZERO , Env.ZERO, get_TrxName()))
{
throw new AdempiereException();
}

View File

@ -469,7 +469,7 @@ public class Match
sLine.getM_Locator_ID(),
sLine.getM_Product_ID(),
sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(),
null, null, qty.negate(), trxName);
null, null, qty.negate(), Env.ZERO, trxName);
}
}
else

View File

@ -0,0 +1,51 @@
/************************************************************************
* Function Is_InOut_Candidate_Order - Return Y or N depending if
* this order can be shipped or not.
* Delivery Policy, Shipping rule etc is considered.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION is_inout_candidate_order
(
p_order_id IN NUMBER
)
RETURN CHAR AS
v_lines_ready NUMBER;
v_lines_total NUMBER;
v_deliveryRule CHAR;
BEGIN
-- Get order info
-- Only orders that are complete, not delivered, delivery rule anything else than manual and is a sales order
-- can be inout candidates
select DeliveryRule INTO v_deliveryRule FROM C_Order WHERE
c_order_id=p_order_id AND
docstatus = 'CO' AND
isdelivered = 'N' AND
deliveryrule <> 'M' AND
(c_doctype_id IN ( SELECT c_doctype.c_doctype_id FROM c_doctype
WHERE c_doctype.docbasetype = 'SOO' AND c_doctype.docsubtypeso NOT IN('ON','OB','WR')));
IF v_deliveryRule IS NULL THEN
RETURN 'N';
END IF;
IF v_deliveryRule='F' THEN RETURN 'Y'; END IF; -- Force
-- Check lines
SELECT sum(is_inout_candidate_orderline(c_orderline_id)), sum(1)
INTO v_lines_ready, v_lines_total
FROM c_orderline where c_order_id=p_order_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'A' THEN -- Availability
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'O' THEN -- Complete order
IF v_lines_ready = v_lines_total THEN RETURN 'Y'; END IF;
END CASE;
return 'N';
END;
/

View File

@ -0,0 +1,128 @@
/************************************************************************
* Function Is_InOut_Candidate_OrderLine - Return Y or N depending if
* order line can be shipped or not.
* Delivery Policy, Shipping rule etc is considered.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION is_inout_candidate_orderline
(
c_order_line_id IN NUMBER
)
RETURN NUMBER AS
v_qtyordered NUMBER;
v_qtydelivered NUMBER;
v_qtyallocated NUMBER;
v_qtyonhand NUMBER;
v_qtytodeliver NUMBER;
v_qtyreserved NUMBER;
v_order_id NUMBER;
v_inoutExists NUMBER;
v_warehouse_id NUMBER;
v_product_id NUMBER;
v_orderReady NUMBER;
v_isShippable CHAR;
v_deliveryRule CHAR;
v_deliveryPolicy CHAR;
v_return CHAR;
BEGIN
SELECT qtyordered, qtydelivered, qtyallocated, qtyreserved, c_order_id,
get_delivery_policy(m_warehouse_id), isshippable(m_product_id),
m_warehouse_id, m_product_id
INTO
v_qtyordered, v_qtydelivered, v_qtyallocated, v_qtyreserved, v_order_id,
v_deliveryPolicy, v_isShippable,
v_warehouse_id, v_product_id
FROM
C_OrderLine where C_OrderLine_ID=c_order_line_id;
-- If all is already delivered then it's not a candidate
IF v_qtyordered = v_qtydelivered THEN
-- RAISE NOTICE 'All is delivered';
RETURN 0;
END IF;
-- Non shippable (ie non physical items) are always inout candidate
IF v_isShippable='N' THEN
-- RAISE NOTICE 'Non physical item, always deliverable';
RETURN 1;
END IF;
SELECT 1 INTO v_inoutExists FROM m_inoutline iol
JOIN m_inout io ON iol.m_inout_id = io.m_inout_id
WHERE iol.c_orderline_id = c_order_line_id AND (io.docstatus IN ('IP', 'WC', 'IN'));
-- If an in-out line is in progress this is not a candidate
IF v_inoutExists = 1 THEN
-- RAISE NOTICE 'Already being shipped';
RETURN 0;
END IF;
-- Check delivery rule
SELECT DeliveryRule INTO
v_deliveryRule
FROM
C_Order where C_Order_ID=v_order_id;
IF v_deliveryRule='F' THEN
-- RAISE NOTICE 'Delivery rule = Force';
RETURN 1;
END IF; -- Force
v_qtytodeliver := v_qtyordered - v_qtydelivered;
IF v_qtytodeliver = 0 THEN
-- RAISE NOTICE 'Nothing to deliver';
RETURN 0;
END IF;
IF v_DeliveryPolicy = 'O' THEN -- Deliver in strict order, compare with qty allocated
BEGIN
-- RAISE NOTICE 'Delivery policy = Strict order';
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_qtytodeliver = v_qtyallocated THEN
-- RAISE NOTICE 'Quantity to deliver = qty allocated';
RETURN 1;
END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver > v_qtyallocated THEN
-- RAISE NOTICE 'Not enough allocated for complete order';
RETURN 0;
END IF;
WHEN 'A' THEN -- Availability
IF v_qtyallocated > 0 THEN
-- RAISE NOTICE 'Something to deliver';
RETURN 1;
END IF;
END CASE;
-- RAISE NOTICE 'No inout candidate';
RETURN 0;
END;
END IF;
IF v_DeliveryPolicy = 'N' THEN -- No hold, only compare with on hand
BEGIN
-- RAISE NOTICE 'Delivery policy = No hold';
SELECT qtyonhand INTO
v_qtyonhand
FROM m_product_stock_v
WHERE M_Product_ID=v_product_id AND M_Warehouse_ID=v_warehouse_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF (v_qtytodeliver = v_qtyreserved AND v_qtytodeliver <= v_qtyonhand) THEN RETURN 1; END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver < v_qtyreserved OR v_qtytodeliver >= v_qtyonhand THEN RETURN 0; END IF;
WHEN 'A' THEN -- Availability
IF v_qtyonhand > 0 THEN RETURN 1; END IF;
END CASE;
END;
END IF;
-- RAISE NOTICE 'Default answer, something to deliver';
return 1;
END;
/

View File

@ -0,0 +1,24 @@
/************************************************************************
* Function Get_Allocated_On_Order - Return number of allocated products
* of the specific product in the given warehouse.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION get_allocated_on_order
(
p_product_id IN NUMBER,
p_warehouse_id IN NUMBER)
RETURN NUMBER AS
v_sum NUMBER;
BEGIN
-- Get Product Attribute Set Instance
SELECT sum(qtyallocated) into v_sum from C_OrderLine ol
JOIN C_Order o on (o.C_Order_ID=ol.C_Order_ID)
WHERE
M_Product_ID=p_product_id AND
COALESCE(ol.M_Warehouse_ID, o.M_Warehouse_ID)=p_warehouse_id;
RETURN v_sum;
END get_allocated_on_order;
/

View File

@ -0,0 +1,27 @@
/************************************************************************
* Function Get_Delivery_Policy - Return delivery policy of warehouse
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION get_delivery_policy
(
warehouse_id IN NUMBER
)
RETURN CHAR AS
v_orgId NUMBER;
v_clientId NUMBER;
v_return CHAR;
BEGIN
SELECT ad_client_id, ad_org_id INTO
v_clientId, v_orgId FROM
M_Warehouse WHERE M_Warehouse_ID=warehouse_id;
SELECT COALESCE(ad_orginfo.deliverypolicy, ad_clientinfo.deliverypolicy) INTO
v_return
FROM AD_ClientInfo
JOIN AD_OrgInfo ON (AD_ClientInfo.AD_Client_ID=AD_OrgInfo.AD_Client_ID)
WHERE AD_ClientInfo.AD_Client_ID = v_clientId AND
AD_OrgInfo.AD_Org_ID = v_orgId;
return v_return;
END get_delivery_policy;
/

View File

@ -0,0 +1,32 @@
/************************************************************************
* Function IsShippable - Return Y or N depending if this is a physical
* 'shippable' product or not.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION isshippable
(
product_id IN NUMBER
)
RETURN CHAR AS
v_IsStocked CHAR;
v_IsBom CHAR;
v_ProductType CHAR;
v_return CHAR;
BEGIN
IF product_id = NULL THEN
return 'N';
END IF;
SELECT IsStocked, IsBom, ProductType
INTO v_IsStocked, v_IsBom, v_ProductType
FROM M_Product WHERE M_Product_ID=product_id;
IF (v_IsStocked='Y' AND v_ProductType='I' AND v_IsBom='N') THEN
v_return := 'Y';
ELSE
v_return := 'N';
END IF;
return v_return;
END isshippable;
/

View File

@ -1,37 +1,26 @@
CREATE OR REPLACE VIEW M_INOUT_CANDIDATE_V
(AD_CLIENT_ID, AD_ORG_ID, C_BPARTNER_ID, C_ORDER_ID, DOCUMENTNO,
DATEORDERED, C_DOCTYPE_ID, POREFERENCE, DESCRIPTION, SALESREP_ID,
M_WAREHOUSE_ID, TOTALLINES)
AS
SELECT
o.AD_Client_ID, o.AD_Org_ID, o.C_BPartner_ID, o.C_Order_ID,
o.DocumentNo, o.DateOrdered, o.C_DocType_ID,
o.POReference, o.Description, o.SalesRep_ID,
l.M_Warehouse_ID,
SUM((l.QtyOrdered-l.QtyDelivered)*l.PriceActual) AS TotalLines
FROM C_Order o
INNER JOIN C_OrderLine l ON (o.C_Order_ID=l.C_Order_ID)
WHERE (o.DocStatus = 'CO' AND o.IsDelivered='N') -- Status must be CO - not CL/RE
-- not Offers and open Walkin-Receipts
AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType
WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR'))
-- Delivery Rule - not manual
AND o.DeliveryRule<>'M'
AND (l.M_Product_ID IS NULL OR EXISTS
(SELECT * FROM M_Product p
WHERE l.M_Product_ID=p.M_Product_ID AND p.IsExcludeAutoDelivery='N'))
-- we need to ship
AND l.QtyOrdered <> l.QtyDelivered
AND o.IsDropShip='N'
AND (l.M_Product_ID IS NOT NULL OR l.C_Charge_ID IS NOT NULL)
-- Not confirmed shipment
AND NOT EXISTS (SELECT * FROM M_InOutLine iol
INNER JOIN M_InOut io ON (iol.M_InOut_ID=io.M_InOut_ID)
WHERE iol.C_OrderLine_ID=l.C_OrderLine_ID AND io.DocStatus IN ('IP','WC'))
--
GROUP BY o.AD_Client_ID, o.AD_Org_ID, o.C_BPartner_ID, o.C_Order_ID,
o.DocumentNo, o.DateOrdered, o.C_DocType_ID,
o.POReference, o.Description, o.SalesRep_ID, l.M_Warehouse_ID;
CREATE OR REPLACE VIEW m_inout_candidate_v AS
SELECT
o.ad_client_id,
o.ad_org_id,
o.c_bpartner_id,
o.c_order_id,
o.documentno,
o.dateordered,
o.c_doctype_id,
o.poreference,
o.description,
o.salesrep_id,
l.m_warehouse_id,
sum((l.qtyordered - l.qtydelivered) * l.priceactual) AS totallines
FROM c_order o
JOIN c_orderline l ON o.c_order_id = l.c_order_id
WHERE
(l.m_product_id IS NULL OR (EXISTS ( SELECT 1
FROM m_product p
WHERE l.m_product_id = p.m_product_id AND p.isexcludeautodelivery = 'N'))) AND
(l.m_product_id IS NOT NULL OR l.c_charge_id IS NOT NULL) AND
is_inout_candidate_order(o.c_order_id) = 'Y'
GROUP BY o.ad_client_id, o.ad_org_id, o.c_bpartner_id, o.c_order_id, o.documentno, o.dateordered, o.c_doctype_id, o.poreference, o.description, o.salesrep_id, l.m_warehouse_id;

View File

@ -1,13 +1,17 @@
--create views
CREATE OR REPLACE VIEW M_PRODUCT_STOCK_V
AS
SELECT
ms.IsActive, ms.Created, ms.CreatedBy, ms.Updated, ms.UpdatedBy,
mp.VALUE, mp.help, (ms.qtyonhand - ms.qtyreserved) AS qtyavailable, ms.qtyonhand,
ms.qtyreserved, mp.description, mw.NAME AS warehouse, mw.m_warehouse_id, mw.ad_client_id,
mw.ad_org_id, mp.documentnote
FROM M_STORAGE ms
JOIN M_PRODUCT mp ON ms.m_product_id = mp.m_product_id
JOIN M_LOCATOR ml ON ms.m_locator_id = ml.m_locator_id
JOIN M_WAREHOUSE mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.NAME;
CREATE OR REPLACE VIEW m_product_stock_v AS
SELECT ms.isactive, ms.created, ms.createdby, ms.updated, ms.updatedby,
ms.m_product_id, mp.value, mp.name, mp.help,
ms.qtyonhand - ms.qtyreserved AS qtyavailable,
ms.qtyonhand, ms.qtyreserved,
ms.qtyallocated,
mp.description,
mw.name AS warehouse,
mw.m_warehouse_id,
mw.ad_client_id,
mw.ad_org_id,
mp.documentnote
FROM m_storage ms
JOIN m_product mp ON ms.m_product_id = mp.m_product_id
JOIN m_locator ml ON ms.m_locator_id = ml.m_locator_id
JOIN m_warehouse mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.name;

View File

@ -0,0 +1,49 @@
/************************************************************************
* Function Is_InOut_Candidate_Order - Return Y or N depending if
* this order can be shipped or not.
* Delivery Policy, Shipping rule etc is considered.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION is_inout_candidate_order(p_order_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_lines_ready numeric;
v_lines_total numeric;
v_deliveryRule character(1);
BEGIN
-- Get order info
-- Only orders that are complete, not delivered, delivery rule anything else than manual and is a sales order
-- can be inout candidates
select DeliveryRule INTO v_deliveryRule FROM C_Order WHERE
c_order_id=p_order_id AND
docstatus = 'CO'::bpchar AND
isdelivered = 'N'::bpchar AND
deliveryrule <> 'M'::bpchar AND
(c_doctype_id IN ( SELECT c_doctype.c_doctype_id FROM c_doctype
WHERE c_doctype.docbasetype = 'SOO'::bpchar AND (c_doctype.docsubtypeso <> ALL (ARRAY['ON'::bpchar, 'OB'::bpchar, 'WR'::bpchar]))));
IF v_deliveryRule IS NULL THEN
RETURN 'N';
END IF;
IF v_deliveryRule='F' THEN RETURN 'Y'; END IF; -- Force
-- Check lines
SELECT sum(is_inout_candidate_orderline(c_orderline_id)), sum(1)
INTO v_lines_ready, v_lines_total
FROM c_orderline where c_order_id=p_order_id;
CASE v_deliveryRule
WHEN 'L','A' THEN -- Complete line and Availability
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'O' THEN -- Complete order
IF v_lines_ready = v_lines_total THEN RETURN 'Y'; END IF;
END CASE;
return 'N';
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

View File

@ -0,0 +1,127 @@
/************************************************************************
* Function Is_InOut_Candidate_OrderLine - Return Y or N depending if
* order line can be shipped or not.
* Delivery Policy, Shipping rule etc is considered.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION is_inout_candidate_orderline(c_order_line_id numeric)
RETURNS numeric AS
$BODY$
DECLARE
v_qtyordered numeric;
v_qtydelivered numeric;
v_qtyallocated numeric;
v_qtyonhand numeric;
v_qtytodeliver numeric;
v_qtyreserved numeric;
v_order_id numeric;
v_inoutExists numeric;
v_warehouse_id numeric;
v_product_id numeric;
v_orderReady numeric;
v_isShippable character(1);
v_deliveryRule character(1);
v_deliveryPolicy character(1);
v_return character(1);
BEGIN
SELECT qtyordered, qtydelivered, qtyallocated, qtyreserved, c_order_id,
get_delivery_policy(m_warehouse_id), isshippable(m_product_id),
m_warehouse_id, m_product_id
INTO
v_qtyordered, v_qtydelivered, v_qtyallocated, v_qtyreserved, v_order_id,
v_deliveryPolicy, v_isShippable,
v_warehouse_id, v_product_id
FROM
C_OrderLine where C_OrderLine_ID=c_order_line_id;
-- If all is already delivered then it's not a candidate
IF v_qtyordered = v_qtydelivered THEN
-- RAISE NOTICE 'All is delivered';
RETURN 0;
END IF;
-- Non shippable (ie non physical items) are always inout candidate
IF v_isShippable='N' THEN
-- RAISE NOTICE 'Non physical item, always deliverable';
RETURN 1;
END IF;
SELECT 1 INTO v_inoutExists FROM m_inoutline iol
JOIN m_inout io ON iol.m_inout_id = io.m_inout_id
WHERE iol.c_orderline_id = c_order_line_id AND (io.docstatus = ANY (ARRAY['IP'::bpchar, 'WC'::bpchar, 'IN'::bpchar]));
-- If an in-out line is in progress this is not a candidate
IF v_inoutExists = 1 THEN
-- RAISE NOTICE 'Already being shipped';
RETURN 0;
END IF;
-- Check delivery rule
SELECT DeliveryRule INTO
v_deliveryRule
FROM
C_Order where C_Order_ID=v_order_id;
IF v_deliveryRule='F' THEN
-- RAISE NOTICE 'Delivery rule = Force';
RETURN 1;
END IF; -- Force
v_qtytodeliver := v_qtyordered - v_qtydelivered;
IF v_qtytodeliver = 0 THEN
-- RAISE NOTICE 'Nothing to deliver';
RETURN 0;
END IF;
IF v_DeliveryPolicy = 'O' THEN -- Deliver in strict order, compare with qty allocated
BEGIN
-- RAISE NOTICE 'Delivery policy = Strict order';
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_qtytodeliver = v_qtyallocated THEN
-- RAISE NOTICE 'Quantity to deliver = qty allocated';
RETURN 1;
END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver > v_qtyallocated THEN
-- RAISE NOTICE 'Not enough allocated for complete order';
RETURN 0;
END IF;
WHEN 'A' THEN -- Availability
IF v_qtyallocated > 0 THEN
-- RAISE NOTICE 'Something to deliver';
RETURN 1;
END IF;
END CASE;
-- RAISE NOTICE 'No inout candidate';
RETURN 0;
END;
END IF;
IF v_DeliveryPolicy = 'N' THEN -- No hold, only compare with on hand
BEGIN
-- RAISE NOTICE 'Delivery policy = No hold';
SELECT qtyonhand INTO
v_qtyonhand
FROM m_product_stock_v
WHERE M_Product_ID=v_product_id AND M_Warehouse_ID=v_warehouse_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF (v_qtytodeliver = v_qtyreserved AND v_qtytodeliver <= v_qtyonhand) THEN RETURN 1; END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver < v_qtyreserved OR v_qtytodeliver >= v_qtyonhand THEN RETURN 0; END IF;
WHEN 'A' THEN -- Availability
IF v_qtyonhand > 0 THEN RETURN 1; END IF;
END CASE;
END;
END IF;
-- RAISE NOTICE 'Default answer, something to deliver';
return 1;
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

View File

@ -0,0 +1,26 @@
/************************************************************************
* Function Get_Allocated_On_Order - Return number of allocated products
* of the specific product in the given warehouse.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION get_allocated_on_order(p_product_id numeric, p_warehouse_id numeric)
RETURNS numeric AS
$BODY$
DECLARE
v_sum numeric;
BEGIN
-- Get Product Attribute Set Instance
SELECT sum(qtyallocated) into v_sum from C_OrderLine ol
JOIN C_Order o on (o.C_Order_ID=ol.C_Order_ID)
WHERE
M_Product_ID=p_product_id AND
COALESCE(ol.M_Warehouse_ID, o.M_Warehouse_ID)=p_warehouse_id;
RETURN v_sum;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

View File

@ -0,0 +1,29 @@
/************************************************************************
* Function Get_Delivery_Policy - Return delivery policy of warehouse
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION get_delivery_policy(warehouse_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_orgId numeric;
v_clientId numeric;
v_return character(1);
BEGIN
SELECT ad_client_id, ad_org_id INTO
v_clientId, v_orgId FROM
M_Warehouse WHERE M_Warehouse_ID=warehouse_id;
SELECT COALESCE(ad_orginfo.deliverypolicy, ad_clientinfo.deliverypolicy) INTO
v_return
FROM AD_ClientInfo
JOIN AD_OrgInfo ON (AD_ClientInfo.AD_Client_ID=AD_OrgInfo.AD_Client_ID)
WHERE AD_ClientInfo.AD_Client_ID = v_clientId AND
AD_OrgInfo.AD_Org_ID = v_orgId;
return v_return;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

View File

@ -0,0 +1,33 @@
/************************************************************************
* Function IsShippable - Return Y or N depending if this is a physical
* 'shippable' product or not.
* Author: Daniel Tamm (usrdno)
************************************************************************/
CREATE OR REPLACE FUNCTION isshippable(product_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_IsStocked character(1);
v_IsBom character(1);
v_ProductType character(1);
v_return character(1);
BEGIN
IF product_id = NULL THEN
return 'N';
END IF;
SELECT IsStocked, IsBom, ProductType
INTO v_IsStocked, v_IsBom, v_ProductType
FROM M_Product WHERE M_Product_ID=product_id;
IF (v_IsStocked='Y' AND v_ProductType='I' AND v_IsBom='N') THEN
v_return := 'Y';
ELSE
v_return := 'N';
END IF;
return v_return;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;

View File

@ -1,37 +1,28 @@
CREATE OR REPLACE VIEW M_INOUT_CANDIDATE_V
(AD_CLIENT_ID, AD_ORG_ID, C_BPARTNER_ID, C_ORDER_ID, DOCUMENTNO,
DATEORDERED, C_DOCTYPE_ID, POREFERENCE, DESCRIPTION, SALESREP_ID,
M_WAREHOUSE_ID, TOTALLINES)
AS
SELECT
o.AD_Client_ID, o.AD_Org_ID, o.C_BPartner_ID, o.C_Order_ID,
o.DocumentNo, o.DateOrdered, o.C_DocType_ID,
o.POReference, o.Description, o.SalesRep_ID,
l.M_Warehouse_ID,
SUM((l.QtyOrdered-l.QtyDelivered)*l.PriceActual) AS TotalLines
FROM C_Order o
INNER JOIN C_OrderLine l ON (o.C_Order_ID=l.C_Order_ID)
WHERE (o.DocStatus = 'CO' AND o.IsDelivered='N') -- Status must be CO - not CL/RE
-- not Offers and open Walkin-Receipts
AND o.C_DocType_ID IN (SELECT C_DocType_ID FROM C_DocType
WHERE DocBaseType='SOO' AND DocSubTypeSO NOT IN ('ON','OB','WR'))
-- Delivery Rule - not manual
AND o.DeliveryRule<>'M'
AND (l.M_Product_ID IS NULL OR EXISTS
(SELECT * FROM M_Product p
WHERE l.M_Product_ID=p.M_Product_ID AND p.IsExcludeAutoDelivery='N'))
-- we need to ship
AND l.QtyOrdered <> l.QtyDelivered
AND o.IsDropShip='N'
AND (l.M_Product_ID IS NOT NULL OR l.C_Charge_ID IS NOT NULL)
-- Not confirmed shipment
AND NOT EXISTS (SELECT * FROM M_InOutLine iol
INNER JOIN M_InOut io ON (iol.M_InOut_ID=io.M_InOut_ID)
WHERE iol.C_OrderLine_ID=l.C_OrderLine_ID AND io.DocStatus IN ('IP','WC'))
--
GROUP BY o.AD_Client_ID, o.AD_Org_ID, o.C_BPartner_ID, o.C_Order_ID,
o.DocumentNo, o.DateOrdered, o.C_DocType_ID,
o.POReference, o.Description, o.SalesRep_ID, l.M_Warehouse_ID;
CREATE OR REPLACE VIEW m_inout_candidate_v AS
SELECT
o.ad_client_id,
o.ad_org_id,
o.c_bpartner_id,
o.c_order_id,
o.documentno,
o.dateordered,
o.c_doctype_id,
o.poreference,
o.description,
o.salesrep_id,
l.m_warehouse_id,
sum((l.qtyordered - l.qtydelivered) * l.priceactual) AS totallines
FROM c_order o
JOIN c_orderline l ON o.c_order_id = l.c_order_id
WHERE
(l.m_product_id IS NULL OR (EXISTS ( SELECT 1
FROM m_product p
WHERE l.m_product_id = p.m_product_id AND p.isexcludeautodelivery = 'N'::bpchar))) AND
(l.m_product_id IS NOT NULL OR l.c_charge_id IS NOT NULL) AND
is_inout_candidate_order(o.c_order_id) = 'Y'
GROUP BY o.ad_client_id, o.ad_org_id, o.c_bpartner_id, o.c_order_id, o.documentno, o.dateordered, o.c_doctype_id, o.poreference, o.description, o.salesrep_id, l.m_warehouse_id;
ALTER TABLE m_inout_candidate_v OWNER TO adempiere;

View File

@ -1,13 +1,18 @@
--create views
CREATE OR REPLACE VIEW M_PRODUCT_STOCK_V
AS
SELECT
ms.IsActive, ms.Created, ms.CreatedBy, ms.Updated, ms.UpdatedBy,
mp.VALUE, mp.help, (ms.qtyonhand - ms.qtyreserved) AS qtyavailable, ms.qtyonhand,
ms.qtyreserved, mp.description, mw.NAME AS warehouse, mw.m_warehouse_id, mw.ad_client_id,
mw.ad_org_id, mp.documentnote
FROM M_STORAGE ms
JOIN M_PRODUCT mp ON ms.m_product_id = mp.m_product_id
JOIN M_LOCATOR ml ON ms.m_locator_id = ml.m_locator_id
JOIN M_WAREHOUSE mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.NAME;
DROP VIEW IF EXISTS m_product_stock_v;
CREATE OR REPLACE VIEW m_product_stock_v AS
SELECT ms.isactive, ms.created, ms.createdby, ms.updated, ms.updatedby,
ms.m_product_id, mp.value, mp.name, mp.help,
ms.qtyonhand - ms.qtyreserved AS qtyavailable,
ms.qtyonhand, ms.qtyreserved,
ms.qtyallocated,
mp.description,
mw.name AS warehouse,
mw.m_warehouse_id,
mw.ad_client_id,
mw.ad_org_id,
mp.documentnote
FROM m_storage ms
JOIN m_product mp ON ms.m_product_id = mp.m_product_id
JOIN m_locator ml ON ms.m_locator_id = ml.m_locator_id
JOIN m_warehouse mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.name;

View File

@ -0,0 +1,353 @@
-- 2010-maj-19 14:36:56 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54156,0,'QtyAllocated',TO_DATE('2010-05-19 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity','D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Qty Allocated','Qty Allocated',TO_DATE('2010-05-19 14:36:56','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:36:56 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54156 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
;
-- 2010-maj-19 14:42:55 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54157,0,'DeliveryPolicy',TO_DATE('2010-05-19 14:42:55','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy','D','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Delivery Policy','Delivery Policy',TO_DATE('2010-05-19 14:42:55','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:42:55 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54157 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
;
-- 2010-maj-19 14:43:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Reference (AD_Client_ID,AD_Org_ID,AD_Reference_ID,Created,CreatedBy,Description,EntityType,IsActive,IsOrderByValue,Name,Updated,UpdatedBy,ValidationType) VALUES (0,0,53355,TO_DATE('2010-05-19 14:43:59','YYYY-MM-DD HH24:MI:SS'),100,'List of Delivery Policies','D','Y','N','DeliveryPolicies',TO_DATE('2010-05-19 14:43:59','YYYY-MM-DD HH24:MI:SS'),100,'L')
;
-- 2010-maj-19 14:43:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Reference_Trl (AD_Language,AD_Reference_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Reference_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Reference t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Reference_ID=53355 AND NOT EXISTS (SELECT * FROM AD_Reference_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Reference_ID=t.AD_Reference_ID)
;
-- 2010-maj-19 14:44:40 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Reference_ID,AD_Ref_List_ID,Created,CreatedBy,Description,EntityType,IsActive,Name,Updated,UpdatedBy,Value) VALUES (0,0,53355,53581,TO_DATE('2010-05-19 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'Default delivery policy - deliver as soon as orders are fulfilled according to delivery rule','D','Y','No Hold',TO_DATE('2010-05-19 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'N')
;
-- 2010-maj-19 14:44:40 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=53581 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID)
;
-- 2010-maj-19 14:45:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Reference_ID,AD_Ref_List_ID,Created,CreatedBy,Description,EntityType,IsActive,Name,Updated,UpdatedBy,Value) VALUES (0,0,53355,53582,TO_DATE('2010-05-19 14:45:59','YYYY-MM-DD HH24:MI:SS'),100,'Allocate items to orders and fulfill them in strict order.','D','Y','Strict order',TO_DATE('2010-05-19 14:45:59','YYYY-MM-DD HH24:MI:SS'),100,'O')
;
-- 2010-maj-19 14:45:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=53582 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID)
;
-- 2010-maj-19 14:47:45 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59188,54156,0,29,260,'QtyAllocated',TO_DATE('2010-05-19 14:47:45','YYYY-MM-DD HH24:MI:SS'),100,'0','Allocated quantity','D',22,'Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Qty Allocated',0,TO_DATE('2010-05-19 14:47:45','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 14:47:45 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59188 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 14:48:05 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE C_OrderLine ADD QtyAllocated NUMBER DEFAULT 0
;
-- 2010-maj-19 14:49:07 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59189,54156,0,29,250,'QtyAllocated',TO_DATE('2010-05-19 14:49:07','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity','D',22,'Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Qty Allocated',0,TO_DATE('2010-05-19 14:49:07','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 14:49:07 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59189 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 14:49:18 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE M_Storage ADD QtyAllocated NUMBER DEFAULT 0
;
-- 2010-maj-19 14:49:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Column SET DefaultValue='0',Updated=TO_DATE('2010-05-19 14:49:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=59189
;
-- 2010-maj-19 14:54:08 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_FieldGroup_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,DisplayLogic,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,Updated,UpdatedBy) VALUES (0,59188,102,58877,0,187,TO_DATE('2010-05-19 14:54:08','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity',26,'@OrderType@=''OB'' | @OrderType@=''SO'' | @Processed@=''Y''','D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','Y','N','N','N','Y','N','Qty Allocated',190,TO_DATE('2010-05-19 14:54:08','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:54:08 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58877 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=210,IsDisplayed='Y' WHERE AD_Field_ID=58877
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=220,IsDisplayed='Y' WHERE AD_Field_ID=1135
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=230,IsDisplayed='Y' WHERE AD_Field_ID=10829
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=240,IsDisplayed='Y' WHERE AD_Field_ID=1138
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=250,IsDisplayed='Y' WHERE AD_Field_ID=1137
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=260,IsDisplayed='Y' WHERE AD_Field_ID=2115
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=270,IsDisplayed='Y' WHERE AD_Field_ID=1141
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=280,IsDisplayed='Y' WHERE AD_Field_ID=3124
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=290,IsDisplayed='Y' WHERE AD_Field_ID=12745
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=300,IsDisplayed='Y' WHERE AD_Field_ID=13644
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=310,IsDisplayed='Y' WHERE AD_Field_ID=13645
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=320,IsDisplayed='Y' WHERE AD_Field_ID=13691
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=330,IsDisplayed='Y' WHERE AD_Field_ID=13650
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=340,IsDisplayed='Y' WHERE AD_Field_ID=13651
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=350,IsDisplayed='Y' WHERE AD_Field_ID=2880
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=360,IsDisplayed='Y' WHERE AD_Field_ID=12744
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=370,IsDisplayed='Y' WHERE AD_Field_ID=10332
;
-- 2010-maj-19 14:55:07 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET Name='Allocated Quantity',Updated=TO_DATE('2010-05-19 14:55:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58877
;
-- 2010-maj-19 14:55:07 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field_Trl SET IsTranslated='N' WHERE AD_Field_ID=58877
;
-- 2010-maj-19 14:56:52 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,59189,58878,0,179,TO_DATE('2010-05-19 14:56:52','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity',26,'D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','Y','N','N','N','N','N','Qty Allocated',110,0,TO_DATE('2010-05-19 14:56:52','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:56:52 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58878 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 14:57:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET Name='Allocated Quantity',Updated=TO_DATE('2010-05-19 14:57:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58878
;
-- 2010-maj-19 14:57:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field_Trl SET IsTranslated='N' WHERE AD_Field_ID=58878
;
-- 2010-maj-19 15:02:03 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59190,54157,0,17,53355,228,'DeliveryPolicy',TO_DATE('2010-05-19 15:02:03','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy','D',1,'The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Delivery Policy',0,TO_DATE('2010-05-19 15:02:03','YYYY-MM-DD HH24:MI:SS'),100,0)
;
-- 2010-maj-19 15:02:03 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59190 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 15:02:11 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Column SET Version=1.000000000000,Updated=TO_DATE('2010-05-19 15:02:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=59190
;
-- 2010-maj-19 15:02:18 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE AD_OrgInfo ADD DeliveryPolicy CHAR(1) DEFAULT NULL
;
-- 2010-maj-19 15:06:47 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59191,54157,0,17,53355,227,'DeliveryPolicy',TO_DATE('2010-05-19 15:06:46','YYYY-MM-DD HH24:MI:SS'),100,'N','Delivery Policy','D',1,'The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Delivery Policy',0,TO_DATE('2010-05-19 15:06:46','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 15:06:47 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59191 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 15:06:53 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE AD_ClientInfo ADD DeliveryPolicy CHAR(1) DEFAULT 'N'
;
-- Add field to Client Info Window
-- 2010-maj-19 15:10:10 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_FieldGroup_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DefaultValue,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,Updated,UpdatedBy) VALUES (0,59191,118,58879,0,169,TO_DATE('2010-05-19 15:10:10','YYYY-MM-DD HH24:MI:SS'),100,'N','Delivery Policy',14,'U','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','Y','N','N','N','N','Y','Delivery Policy',155,TO_DATE('2010-05-19 15:10:10','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 15:10:10 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58879 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 15:12:01 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,59190,58880,0,170,TO_DATE('2010-05-19 15:12:01','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy',0,'D','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','Y','N','N','N','N','N','Delivery Policy',85,0,TO_DATE('2010-05-19 15:12:01','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 15:12:01 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58880 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 15:12:11 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET DisplayLength=22,Updated=TO_DATE('2010-05-19 15:12:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58880
;
-- Jun 22, 2010 1:47:33 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process (AccessLevel,AD_Client_ID,AD_Org_ID,AD_Process_ID,Classname,CopyFromProcess,Created,CreatedBy,Description,EntityType,Help,IsActive,IsBetaFunctionality,IsDirectPrint,IsReport,IsServerProcess,Name,ShowHelp,Statistic_Count,Statistic_Seconds,Updated,UpdatedBy,Value) VALUES ('3',0,0,53217,'org.adempiere.process.AllocateSalesOrders','N',TO_DATE('2010-06-22 13:47:31','YYYY-MM-DD HH24:MI:SS'),100,'Allocate available on hand stock to sales orders','D','This process is only necessary for delivery policy = Strict order','Y','N','N','N','N','Allocate Sales Orders','Y',0,0,TO_DATE('2010-06-22 13:47:31','YYYY-MM-DD HH24:MI:SS'),100,'AllocateSalesOrders')
;
-- Jun 22, 2010 1:47:33 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Trl (AD_Language,AD_Process_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_ID=53217 AND NOT EXISTS (SELECT * FROM AD_Process_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_ID=t.AD_Process_ID)
;
-- Jun 22, 2010 1:48:24 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Para (AD_Client_ID,AD_Element_ID,AD_Org_ID,AD_Process_ID,AD_Process_Para_ID,AD_Reference_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,IsActive,IsCentrallyMaintained,IsMandatory,IsRange,Name,SeqNo,Updated,UpdatedBy) VALUES (0,459,0,53217,53422,18,'M_Warehouse_ID',TO_DATE('2010-06-22 13:48:23','YYYY-MM-DD HH24:MI:SS'),100,'Warehouse where allocation should be executed.','D',0,'Y','Y','N','N','Warehouse',10,TO_DATE('2010-06-22 13:48:23','YYYY-MM-DD HH24:MI:SS'),100)
;
-- Jun 22, 2010 1:48:24 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Para_Trl (AD_Language,AD_Process_Para_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_Para_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process_Para t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_Para_ID=53422 AND NOT EXISTS (SELECT * FROM AD_Process_Para_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_Para_ID=t.AD_Process_Para_ID)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Menu (Action,AD_Client_ID,AD_Menu_ID,AD_Org_ID,AD_Process_ID,Created,CreatedBy,Description,EntityType,IsActive,IsCentrallyMaintained,IsReadOnly,IsSOTrx,IsSummary,Name,Updated,UpdatedBy) VALUES ('P',0,53283,0,53217,TO_DATE('2010-06-22 13:49:04','YYYY-MM-DD HH24:MI:SS'),100,'Allocate available on hand stock to sales orders','D','Y','Y','N','N','N','Allocate Sales Orders',TO_DATE('2010-06-22 13:49:04','YYYY-MM-DD HH24:MI:SS'),100)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Menu_Trl (AD_Language,AD_Menu_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Menu_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Menu t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Menu_ID=53283 AND NOT EXISTS (SELECT * FROM AD_Menu_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Menu_ID=t.AD_Menu_ID)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo) SELECT t.AD_Client_ID, 0, 'Y', SysDate, 100, SysDate, 100,t.AD_Tree_ID, 53283, 0, 999 FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=53283)
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=0, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53283
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=1, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=346
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=2, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=53132
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=3, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=193
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=4, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=180
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=5, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=494
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=6, Updated=SysDate WHERE AD_Tree_ID=10 AND Node_ID=444
;

View File

@ -0,0 +1,296 @@
-- Adjust, alter view M_Product_Stock_v
CREATE OR REPLACE VIEW m_product_stock_v AS
SELECT ms.isactive, ms.created, ms.createdby, ms.updated, ms.updatedby,
ms.m_product_id, mp.value, mp.name, mp.help,
ms.qtyonhand - ms.qtyreserved AS qtyavailable,
ms.qtyonhand, ms.qtyreserved,
ms.qtyallocated,
mp.description,
mw.name AS warehouse,
mw.m_warehouse_id,
mw.ad_client_id,
mw.ad_org_id,
mp.documentnote
FROM m_storage ms
JOIN m_product mp ON ms.m_product_id = mp.m_product_id
JOIN m_locator ml ON ms.m_locator_id = ml.m_locator_id
JOIN m_warehouse mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.name;
-- Create function isShippable
CREATE OR REPLACE FUNCTION isshippable
(
product_id IN NUMBER
)
RETURN CHAR AS
v_IsStocked CHAR;
v_IsBom CHAR;
v_ProductType CHAR;
v_return CHAR;
BEGIN
IF product_id = NULL THEN
return 'N';
END IF;
SELECT IsStocked, IsBom, ProductType
INTO v_IsStocked, v_IsBom, v_ProductType
FROM M_Product WHERE M_Product_ID=product_id;
IF (v_IsStocked='Y' AND v_ProductType='I' AND v_IsBom='N') THEN
v_return := 'Y';
ELSE
v_return := 'N';
END IF;
return v_return;
END isshippable;
/
-- Function to get delivery policy
CREATE OR REPLACE FUNCTION get_delivery_policy
(
warehouse_id IN NUMBER
)
RETURN CHAR AS
v_orgId NUMBER;
v_clientId NUMBER;
v_return CHAR;
BEGIN
SELECT ad_client_id, ad_org_id INTO
v_clientId, v_orgId FROM
M_Warehouse WHERE M_Warehouse_ID=warehouse_id;
SELECT COALESCE(ad_orginfo.deliverypolicy, ad_clientinfo.deliverypolicy) INTO
v_return
FROM AD_ClientInfo
JOIN AD_OrgInfo ON (AD_ClientInfo.AD_Client_ID=AD_OrgInfo.AD_Client_ID)
WHERE AD_ClientInfo.AD_Client_ID = v_clientId AND
AD_OrgInfo.AD_Org_ID = v_orgId;
return v_return;
END get_delivery_policy;
/
-- Get allocated on order
CREATE OR REPLACE FUNCTION get_allocated_on_order
(
p_product_id IN NUMBER,
p_warehouse_id IN NUMBER)
RETURN NUMBER AS
v_sum NUMBER;
BEGIN
-- Get Product Attribute Set Instance
SELECT sum(qtyallocated) into v_sum from C_OrderLine ol
JOIN C_Order o on (o.C_Order_ID=ol.C_Order_ID)
WHERE
M_Product_ID=p_product_id AND
COALESCE(ol.M_Warehouse_ID, o.M_Warehouse_ID)=p_warehouse_id;
RETURN v_sum;
END get_allocated_on_order;
/
-- IN OUT CANDIDATE ORDERLINE
CREATE OR REPLACE FUNCTION is_inout_candidate_orderline
(
c_order_line_id IN NUMBER
)
RETURN NUMBER AS
v_qtyordered NUMBER;
v_qtydelivered NUMBER;
v_qtyallocated NUMBER;
v_qtyonhand NUMBER;
v_qtytodeliver NUMBER;
v_qtyreserved NUMBER;
v_order_id NUMBER;
v_inoutExists NUMBER;
v_warehouse_id NUMBER;
v_product_id NUMBER;
v_orderReady NUMBER;
v_isShippable CHAR;
v_deliveryRule CHAR;
v_deliveryPolicy CHAR;
v_return CHAR;
BEGIN
SELECT qtyordered, qtydelivered, qtyallocated, qtyreserved, c_order_id,
get_delivery_policy(m_warehouse_id), isshippable(m_product_id),
m_warehouse_id, m_product_id
INTO
v_qtyordered, v_qtydelivered, v_qtyallocated, v_qtyreserved, v_order_id,
v_deliveryPolicy, v_isShippable,
v_warehouse_id, v_product_id
FROM
C_OrderLine where C_OrderLine_ID=c_order_line_id;
-- If all is already delivered then it's not a candidate
IF v_qtyordered = v_qtydelivered THEN
-- RAISE NOTICE 'All is delivered';
RETURN 0;
END IF;
-- Non shippable (ie non physical items) are always inout candidate
IF v_isShippable='N' THEN
-- RAISE NOTICE 'Non physical item, always deliverable';
RETURN 1;
END IF;
SELECT 1 INTO v_inoutExists FROM m_inoutline iol
JOIN m_inout io ON iol.m_inout_id = io.m_inout_id
WHERE iol.c_orderline_id = c_order_line_id AND (io.docstatus IN ('IP', 'WC', 'IN'));
-- If an in-out line is in progress this is not a candidate
IF v_inoutExists = 1 THEN
-- RAISE NOTICE 'Already being shipped';
RETURN 0;
END IF;
-- Check delivery rule
SELECT DeliveryRule INTO
v_deliveryRule
FROM
C_Order where C_Order_ID=v_order_id;
IF v_deliveryRule='F' THEN
-- RAISE NOTICE 'Delivery rule = Force';
RETURN 1;
END IF; -- Force
v_qtytodeliver := v_qtyordered - v_qtydelivered;
IF v_qtytodeliver = 0 THEN
-- RAISE NOTICE 'Nothing to deliver';
RETURN 0;
END IF;
IF v_DeliveryPolicy = 'O' THEN -- Deliver in strict order, compare with qty allocated
BEGIN
-- RAISE NOTICE 'Delivery policy = Strict order';
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_qtytodeliver = v_qtyallocated THEN
-- RAISE NOTICE 'Quantity to deliver = qty allocated';
RETURN 1;
END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver > v_qtyallocated THEN
-- RAISE NOTICE 'Not enough allocated for complete order';
RETURN 0;
END IF;
WHEN 'A' THEN -- Availability
IF v_qtyallocated > 0 THEN
-- RAISE NOTICE 'Something to deliver';
RETURN 1;
END IF;
END CASE;
-- RAISE NOTICE 'No inout candidate';
RETURN 0;
END;
END IF;
IF v_DeliveryPolicy = 'N' THEN -- No hold, only compare with on hand
BEGIN
-- RAISE NOTICE 'Delivery policy = No hold';
SELECT qtyonhand INTO
v_qtyonhand
FROM m_product_stock_v
WHERE M_Product_ID=v_product_id AND M_Warehouse_ID=v_warehouse_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF (v_qtytodeliver = v_qtyreserved AND v_qtytodeliver <= v_qtyonhand) THEN RETURN 1; END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver < v_qtyreserved OR v_qtytodeliver >= v_qtyonhand THEN RETURN 0; END IF;
WHEN 'A' THEN -- Availability
IF v_qtyonhand > 0 THEN RETURN 1; END IF;
END CASE;
END;
END IF;
-- RAISE NOTICE 'Default answer, something to deliver';
return 1;
END;
/
-- INOUT CANDIDATE ORDER
CREATE OR REPLACE FUNCTION is_inout_candidate_order
(
p_order_id IN NUMBER
)
RETURN CHAR AS
v_lines_ready NUMBER;
v_lines_total NUMBER;
v_deliveryRule CHAR;
BEGIN
-- Get order info
-- Only orders that are complete, not delivered, delivery rule anything else than manual and is a sales order
-- can be inout candidates
select DeliveryRule INTO v_deliveryRule FROM C_Order WHERE
c_order_id=p_order_id AND
docstatus = 'CO' AND
isdelivered = 'N' AND
deliveryrule <> 'M' AND
(c_doctype_id IN ( SELECT c_doctype.c_doctype_id FROM c_doctype
WHERE c_doctype.docbasetype = 'SOO' AND c_doctype.docsubtypeso NOT IN('ON','OB','WR')));
IF v_deliveryRule IS NULL THEN
RETURN 'N';
END IF;
IF v_deliveryRule='F' THEN RETURN 'Y'; END IF; -- Force
-- Check lines
SELECT sum(is_inout_candidate_orderline(c_orderline_id)), sum(1)
INTO v_lines_ready, v_lines_total
FROM c_orderline where c_order_id=p_order_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'A' THEN -- Availability
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'O' THEN -- Complete order
IF v_lines_ready = v_lines_total THEN RETURN 'Y'; END IF;
END CASE;
return 'N';
END;
/
-- INOUT CANDIDATE
CREATE OR REPLACE VIEW m_inout_candidate_v AS
SELECT
o.ad_client_id,
o.ad_org_id,
o.c_bpartner_id,
o.c_order_id,
o.documentno,
o.dateordered,
o.c_doctype_id,
o.poreference,
o.description,
o.salesrep_id,
l.m_warehouse_id,
sum((l.qtyordered - l.qtydelivered) * l.priceactual) AS totallines
FROM c_order o
JOIN c_orderline l ON o.c_order_id = l.c_order_id
WHERE
(l.m_product_id IS NULL OR (EXISTS ( SELECT 1
FROM m_product p
WHERE l.m_product_id = p.m_product_id AND p.isexcludeautodelivery = 'N'))) AND
(l.m_product_id IS NOT NULL OR l.c_charge_id IS NOT NULL) AND
is_inout_candidate_order(o.c_order_id) = 'Y'
GROUP BY o.ad_client_id, o.ad_org_id, o.c_bpartner_id, o.c_order_id, o.documentno, o.dateordered, o.c_doctype_id, o.poreference, o.description, o.salesrep_id, l.m_warehouse_id;

View File

@ -0,0 +1,360 @@
-- 2010-maj-19 14:36:56 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54156,0,'QtyAllocated',TO_TIMESTAMP('2010-05-19 14:36:56','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity','D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Qty Allocated','Qty Allocated',TO_TIMESTAMP('2010-05-19 14:36:56','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:36:56 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54156 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
;
-- 2010-maj-19 14:42:55 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element (AD_Client_ID,AD_Element_ID,AD_Org_ID,ColumnName,Created,CreatedBy,Description,EntityType,Help,IsActive,Name,PrintName,Updated,UpdatedBy) VALUES (0,54157,0,'DeliveryPolicy',TO_TIMESTAMP('2010-05-19 14:42:55','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy','D','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Delivery Policy','Delivery Policy',TO_TIMESTAMP('2010-05-19 14:42:55','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:42:55 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Element_Trl (AD_Language,AD_Element_ID, Description,Help,Name,PO_Description,PO_Help,PO_Name,PO_PrintName,PrintName, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Element_ID, t.Description,t.Help,t.Name,t.PO_Description,t.PO_Help,t.PO_Name,t.PO_PrintName,t.PrintName, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Element t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Element_ID=54157 AND NOT EXISTS (SELECT * FROM AD_Element_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Element_ID=t.AD_Element_ID)
;
-- 2010-maj-19 14:43:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Reference (AD_Client_ID,AD_Org_ID,AD_Reference_ID,Created,CreatedBy,Description,EntityType,IsActive,IsOrderByValue,Name,Updated,UpdatedBy,ValidationType) VALUES (0,0,53355,TO_TIMESTAMP('2010-05-19 14:43:59','YYYY-MM-DD HH24:MI:SS'),100,'List of Delivery Policies','D','Y','N','DeliveryPolicies',TO_TIMESTAMP('2010-05-19 14:43:59','YYYY-MM-DD HH24:MI:SS'),100,'L')
;
-- 2010-maj-19 14:43:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Reference_Trl (AD_Language,AD_Reference_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Reference_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Reference t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Reference_ID=53355 AND NOT EXISTS (SELECT * FROM AD_Reference_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Reference_ID=t.AD_Reference_ID)
;
-- 2010-maj-19 14:44:40 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Reference_ID,AD_Ref_List_ID,Created,CreatedBy,Description,EntityType,IsActive,Name,Updated,UpdatedBy,Value) VALUES (0,0,53355,53581,TO_TIMESTAMP('2010-05-19 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'Default delivery policy - deliver as soon as orders are fulfilled according to delivery rule','D','Y','No Hold',TO_TIMESTAMP('2010-05-19 14:44:40','YYYY-MM-DD HH24:MI:SS'),100,'N')
;
-- 2010-maj-19 14:44:40 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=53581 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID)
;
-- 2010-maj-19 14:45:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List (AD_Client_ID,AD_Org_ID,AD_Reference_ID,AD_Ref_List_ID,Created,CreatedBy,Description,EntityType,IsActive,Name,Updated,UpdatedBy,Value) VALUES (0,0,53355,53582,TO_TIMESTAMP('2010-05-19 14:45:59','YYYY-MM-DD HH24:MI:SS'),100,'Allocate items to orders and fulfill them in strict order.','D','Y','Strict order',TO_TIMESTAMP('2010-05-19 14:45:59','YYYY-MM-DD HH24:MI:SS'),100,'O')
;
-- 2010-maj-19 14:45:59 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Ref_List_Trl (AD_Language,AD_Ref_List_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Ref_List_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Ref_List t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Ref_List_ID=53582 AND NOT EXISTS (SELECT * FROM AD_Ref_List_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Ref_List_ID=t.AD_Ref_List_ID)
;
-- 2010-maj-19 14:47:45 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59188,54156,0,29,260,'QtyAllocated',TO_TIMESTAMP('2010-05-19 14:47:45','YYYY-MM-DD HH24:MI:SS'),100,'0','Allocated quantity','D',22,'Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Qty Allocated',0,TO_TIMESTAMP('2010-05-19 14:47:45','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 14:47:45 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59188 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 14:48:05 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE C_OrderLine ADD COLUMN QtyAllocated NUMERIC DEFAULT '0'
;
-- 2010-maj-19 14:49:07 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59189,54156,0,29,250,'QtyAllocated',TO_TIMESTAMP('2010-05-19 14:49:07','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity','D',22,'Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Qty Allocated',0,TO_TIMESTAMP('2010-05-19 14:49:07','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 14:49:07 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59189 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 14:49:18 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE M_Storage ADD COLUMN QtyAllocated NUMERIC DEFAULT '0'
;
-- 2010-maj-19 14:49:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Column SET DefaultValue='0',Updated=TO_TIMESTAMP('2010-05-19 14:49:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=59189
;
-- Add field QtyAllocated to Sales Order Line
-- 2010-maj-19 14:54:08 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_FieldGroup_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,DisplayLogic,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,Updated,UpdatedBy) VALUES (0,59188,102,58877,0,187,TO_TIMESTAMP('2010-05-19 14:54:08','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity',26,'@OrderType@=''OB'' | @OrderType@=''SO'' | @Processed@=''Y''','D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','Y','N','N','N','Y','N','Qty Allocated',190,TO_TIMESTAMP('2010-05-19 14:54:08','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:54:08 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58877 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=210,IsDisplayed='Y' WHERE AD_Field_ID=58877
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=220,IsDisplayed='Y' WHERE AD_Field_ID=1135
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=230,IsDisplayed='Y' WHERE AD_Field_ID=10829
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=240,IsDisplayed='Y' WHERE AD_Field_ID=1138
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=250,IsDisplayed='Y' WHERE AD_Field_ID=1137
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=260,IsDisplayed='Y' WHERE AD_Field_ID=2115
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=270,IsDisplayed='Y' WHERE AD_Field_ID=1141
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=280,IsDisplayed='Y' WHERE AD_Field_ID=3124
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=290,IsDisplayed='Y' WHERE AD_Field_ID=12745
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=300,IsDisplayed='Y' WHERE AD_Field_ID=13644
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=310,IsDisplayed='Y' WHERE AD_Field_ID=13645
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=320,IsDisplayed='Y' WHERE AD_Field_ID=13691
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=330,IsDisplayed='Y' WHERE AD_Field_ID=13650
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=340,IsDisplayed='Y' WHERE AD_Field_ID=13651
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=350,IsDisplayed='Y' WHERE AD_Field_ID=2880
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=360,IsDisplayed='Y' WHERE AD_Field_ID=12744
;
-- 2010-maj-19 14:54:35 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET SeqNo=370,IsDisplayed='Y' WHERE AD_Field_ID=10332
;
-- 2010-maj-19 14:55:07 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET Name='Allocated Quantity',Updated=TO_TIMESTAMP('2010-05-19 14:55:07','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58877
;
-- 2010-maj-19 14:55:07 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field_Trl SET IsTranslated='N' WHERE AD_Field_ID=58877
;
-- Add field QtyAllocated to MStorage
-- 2010-maj-19 14:56:52 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,59189,58878,0,179,TO_TIMESTAMP('2010-05-19 14:56:52','YYYY-MM-DD HH24:MI:SS'),100,'Allocated quantity',26,'D','Allocated quantity is the quantity that is actually reserved for a specific customer. The customer "owns" this quantity. The allocated quantity can never be more than what''s in stock (as opposed to resevedQty).','Y','Y','Y','N','N','N','N','N','Qty Allocated',110,0,TO_TIMESTAMP('2010-05-19 14:56:52','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 14:56:52 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58878 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 14:57:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET Name='Allocated Quantity',Updated=TO_TIMESTAMP('2010-05-19 14:57:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58878
;
-- 2010-maj-19 14:57:28 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field_Trl SET IsTranslated='N' WHERE AD_Field_ID=58878
;
-- Add column Delivery Policy to OrganizationInfo
-- 2010-maj-19 15:02:03 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59190,54157,0,17,53355,228,'DeliveryPolicy',TO_TIMESTAMP('2010-05-19 15:02:03','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy','D',1,'The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Delivery Policy',0,TO_TIMESTAMP('2010-05-19 15:02:03','YYYY-MM-DD HH24:MI:SS'),100,0)
;
-- 2010-maj-19 15:02:03 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59190 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 15:02:11 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Column SET Version=1.000000000000,Updated=TO_TIMESTAMP('2010-05-19 15:02:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=59190
;
-- 2010-maj-19 15:02:18 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE AD_OrgInfo ADD COLUMN DeliveryPolicy CHAR(1) DEFAULT NULL
;
-- 2010-maj-19 15:06:47 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column (AD_Client_ID,AD_Column_ID,AD_Element_ID,AD_Org_ID,AD_Reference_ID,AD_Reference_Value_ID,AD_Table_ID,ColumnName,Created,CreatedBy,DefaultValue,Description,EntityType,FieldLength,Help,IsActive,IsAllowLogging,IsAlwaysUpdateable,IsAutocomplete,IsEncrypted,IsIdentifier,IsKey,IsMandatory,IsParent,IsSelectionColumn,IsSyncDatabase,IsTranslated,IsUpdateable,Name,SeqNo,Updated,UpdatedBy,Version) VALUES (0,59191,54157,0,17,53355,227,'DeliveryPolicy',TO_TIMESTAMP('2010-05-19 15:06:46','YYYY-MM-DD HH24:MI:SS'),100,'N','Delivery Policy','D',1,'The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','N','N','N','N','N','N','N','N','N','N','Y','Delivery Policy',0,TO_TIMESTAMP('2010-05-19 15:06:46','YYYY-MM-DD HH24:MI:SS'),100,1.000000000000)
;
-- 2010-maj-19 15:06:47 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Column_Trl (AD_Language,AD_Column_ID, Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Column_ID, t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Column t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Column_ID=59191 AND NOT EXISTS (SELECT * FROM AD_Column_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Column_ID=t.AD_Column_ID)
;
-- 2010-maj-19 15:06:53 CEST
-- FR 3002040 - Delivery Policy
ALTER TABLE AD_ClientInfo ADD COLUMN DeliveryPolicy CHAR(1) DEFAULT 'N'
;
-- Add field to Client Info Window
-- 2010-maj-19 15:10:10 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_FieldGroup_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,DefaultValue,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,Updated,UpdatedBy) VALUES (0,59191,118,58879,0,169,TO_TIMESTAMP('2010-05-19 15:10:10','YYYY-MM-DD HH24:MI:SS'),100,'N','Delivery Policy',14,'U','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','Y','N','N','N','N','Y','Delivery Policy',155,TO_TIMESTAMP('2010-05-19 15:10:10','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 15:10:10 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58879 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- Add DeliveryPolicy field to Organization Window
-- 2010-maj-19 15:12:01 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field (AD_Client_ID,AD_Column_ID,AD_Field_ID,AD_Org_ID,AD_Tab_ID,Created,CreatedBy,Description,DisplayLength,EntityType,Help,IsActive,IsCentrallyMaintained,IsDisplayed,IsEncrypted,IsFieldOnly,IsHeading,IsReadOnly,IsSameLine,Name,SeqNo,SortNo,Updated,UpdatedBy) VALUES (0,59190,58880,0,170,TO_TIMESTAMP('2010-05-19 15:12:01','YYYY-MM-DD HH24:MI:SS'),100,'Delivery Policy',0,'D','The delivery policy determines how outbound orders will be allocated.
The default delivery policy is to deliver fulfilled orders as soon as possible even if it means
other non fulfilled orders also needs the items being delivered on the fulfilled orders.','Y','Y','Y','N','N','N','N','N','Delivery Policy',85,0,TO_TIMESTAMP('2010-05-19 15:12:01','YYYY-MM-DD HH24:MI:SS'),100)
;
-- 2010-maj-19 15:12:01 CEST
-- FR 3002040 - Delivery Policy
INSERT INTO AD_Field_Trl (AD_Language,AD_Field_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Field_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Field t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Field_ID=58880 AND NOT EXISTS (SELECT * FROM AD_Field_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Field_ID=t.AD_Field_ID)
;
-- 2010-maj-19 15:12:11 CEST
-- FR 3002040 - Delivery Policy
UPDATE AD_Field SET DisplayLength=22,Updated=TO_TIMESTAMP('2010-05-19 15:12:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=58880
;
-- Jun 22, 2010 1:47:33 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process (AccessLevel,AD_Client_ID,AD_Org_ID,AD_Process_ID,Classname,CopyFromProcess,Created,CreatedBy,Description,EntityType,Help,IsActive,IsBetaFunctionality,IsDirectPrint,IsReport,IsServerProcess,Name,ShowHelp,Statistic_Count,Statistic_Seconds,Updated,UpdatedBy,Value) VALUES ('3',0,0,53217,'org.adempiere.process.AllocateSalesOrders','N',TO_TIMESTAMP('2010-06-22 13:47:31','YYYY-MM-DD HH24:MI:SS'),100,'Allocate available on hand stock to sales orders','D','This process is only necessary for delivery policy = Strict order','Y','N','N','N','N','Allocate Sales Orders','Y',0,0,TO_TIMESTAMP('2010-06-22 13:47:31','YYYY-MM-DD HH24:MI:SS'),100,'AllocateSalesOrders')
;
-- Jun 22, 2010 1:47:33 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Trl (AD_Language,AD_Process_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_ID=53217 AND NOT EXISTS (SELECT * FROM AD_Process_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_ID=t.AD_Process_ID)
;
-- Jun 22, 2010 1:48:24 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Para (AD_Client_ID,AD_Element_ID,AD_Org_ID,AD_Process_ID,AD_Process_Para_ID,AD_Reference_ID,ColumnName,Created,CreatedBy,Description,EntityType,FieldLength,IsActive,IsCentrallyMaintained,IsMandatory,IsRange,Name,SeqNo,Updated,UpdatedBy) VALUES (0,459,0,53217,53422,18,'M_Warehouse_ID',TO_TIMESTAMP('2010-06-22 13:48:23','YYYY-MM-DD HH24:MI:SS'),100,'Warehouse where allocation should be executed.','D',0,'Y','Y','N','N','Warehouse',10,TO_TIMESTAMP('2010-06-22 13:48:23','YYYY-MM-DD HH24:MI:SS'),100)
;
-- Jun 22, 2010 1:48:24 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Process_Para_Trl (AD_Language,AD_Process_Para_ID, Description,Help,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Process_Para_ID, t.Description,t.Help,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Process_Para t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Process_Para_ID=53422 AND NOT EXISTS (SELECT * FROM AD_Process_Para_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Process_Para_ID=t.AD_Process_Para_ID)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Menu ("action",AD_Client_ID,AD_Menu_ID,AD_Org_ID,AD_Process_ID,Created,CreatedBy,Description,EntityType,IsActive,IsCentrallyMaintained,IsReadOnly,IsSOTrx,IsSummary,Name,Updated,UpdatedBy) VALUES ('P',0,53283,0,53217,TO_TIMESTAMP('2010-06-22 13:49:04','YYYY-MM-DD HH24:MI:SS'),100,'Allocate available on hand stock to sales orders','D','Y','Y','N','N','N','Allocate Sales Orders',TO_TIMESTAMP('2010-06-22 13:49:04','YYYY-MM-DD HH24:MI:SS'),100)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_Menu_Trl (AD_Language,AD_Menu_ID, Description,Name, IsTranslated,AD_Client_ID,AD_Org_ID,Created,Createdby,Updated,UpdatedBy) SELECT l.AD_Language,t.AD_Menu_ID, t.Description,t.Name, 'N',t.AD_Client_ID,t.AD_Org_ID,t.Created,t.Createdby,t.Updated,t.UpdatedBy FROM AD_Language l, AD_Menu t WHERE l.IsActive='Y' AND l.IsSystemLanguage='Y' AND l.IsBaseLanguage='N' AND t.AD_Menu_ID=53283 AND NOT EXISTS (SELECT * FROM AD_Menu_Trl tt WHERE tt.AD_Language=l.AD_Language AND tt.AD_Menu_ID=t.AD_Menu_ID)
;
-- Jun 22, 2010 1:49:05 PM CEST
-- FR 3004020 Delivery Policy
INSERT INTO AD_TreeNodeMM (AD_Client_ID,AD_Org_ID, IsActive,Created,CreatedBy,Updated,UpdatedBy, AD_Tree_ID, Node_ID, Parent_ID, SeqNo) SELECT t.AD_Client_ID, 0, 'Y', CURRENT_TIMESTAMP, 100, CURRENT_TIMESTAMP, 100,t.AD_Tree_ID, 53283, 0, 999 FROM AD_Tree t WHERE t.AD_Client_ID=0 AND t.IsActive='Y' AND t.IsAllNodes='Y' AND t.TreeType='MM' AND NOT EXISTS (SELECT * FROM AD_TreeNodeMM e WHERE e.AD_Tree_ID=t.AD_Tree_ID AND Node_ID=53283)
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=0, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=53283
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=1, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=346
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=2, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=53132
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=3, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=193
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=4, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=180
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=5, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=494
;
-- Jun 22, 2010 1:49:15 PM CEST
-- FR 3004020 Delivery Policy
UPDATE AD_TreeNodeMM SET Parent_ID=459, SeqNo=6, Updated=CURRENT_TIMESTAMP WHERE AD_Tree_ID=10 AND Node_ID=444
;

View File

@ -0,0 +1,307 @@
-- Adjust, alter view M_Product_Stock_v
DROP VIEW IF EXISTS m_product_stock_v;
CREATE OR REPLACE VIEW m_product_stock_v AS
SELECT ms.isactive, ms.created, ms.createdby, ms.updated, ms.updatedby,
ms.m_product_id, mp.value, mp.name, mp.help,
ms.qtyonhand - ms.qtyreserved AS qtyavailable,
ms.qtyonhand, ms.qtyreserved,
ms.qtyallocated,
mp.description,
mw.name AS warehouse,
mw.m_warehouse_id,
mw.ad_client_id,
mw.ad_org_id,
mp.documentnote
FROM m_storage ms
JOIN m_product mp ON ms.m_product_id = mp.m_product_id
JOIN m_locator ml ON ms.m_locator_id = ml.m_locator_id
JOIN m_warehouse mw ON ml.m_warehouse_id = mw.m_warehouse_id
ORDER BY mw.name;
ALTER TABLE m_product_stock_v OWNER TO adempiere;
-- Create function isShippable
CREATE OR REPLACE FUNCTION isshippable(product_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_IsStocked character(1);
v_IsBom character(1);
v_ProductType character(1);
v_return character(1);
BEGIN
IF product_id = NULL THEN
return 'N';
END IF;
SELECT IsStocked, IsBom, ProductType
INTO v_IsStocked, v_IsBom, v_ProductType
FROM M_Product WHERE M_Product_ID=product_id;
IF (v_IsStocked='Y' AND v_ProductType='I' AND v_IsBom='N') THEN
v_return := 'Y';
ELSE
v_return := 'N';
END IF;
return v_return;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION isshippable(numeric) OWNER TO adempiere;
-- Function to get delivery policy
CREATE OR REPLACE FUNCTION get_delivery_policy(warehouse_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_orgId numeric;
v_clientId numeric;
v_return character(1);
BEGIN
SELECT ad_client_id, ad_org_id INTO
v_clientId, v_orgId FROM
M_Warehouse WHERE M_Warehouse_ID=warehouse_id;
SELECT COALESCE(ad_orginfo.deliverypolicy, ad_clientinfo.deliverypolicy) INTO
v_return
FROM AD_ClientInfo
JOIN AD_OrgInfo ON (AD_ClientInfo.AD_Client_ID=AD_OrgInfo.AD_Client_ID)
WHERE AD_ClientInfo.AD_Client_ID = v_clientId AND
AD_OrgInfo.AD_Org_ID = v_orgId;
return v_return;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION get_delivery_policy(numeric) OWNER TO adempiere;
-- Get allocated on order
CREATE OR REPLACE FUNCTION get_allocated_on_order(p_product_id numeric, p_warehouse_id numeric)
RETURNS numeric AS
$BODY$
DECLARE
v_sum numeric;
BEGIN
-- Get Product Attribute Set Instance
SELECT sum(qtyallocated) into v_sum from C_OrderLine ol
JOIN C_Order o on (o.C_Order_ID=ol.C_Order_ID)
WHERE
M_Product_ID=p_product_id AND
COALESCE(ol.M_Warehouse_ID, o.M_Warehouse_ID)=p_warehouse_id;
RETURN v_sum;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION get_allocated_on_order(numeric, numeric) OWNER TO adempiere;
-- IN OUT CANDIDATE ORDERLINE
-- DROP FUNCTION is_inout_candidate_orderline(numeric);
CREATE OR REPLACE FUNCTION is_inout_candidate_orderline(c_order_line_id numeric)
RETURNS numeric AS
$BODY$
DECLARE
v_qtyordered numeric;
v_qtydelivered numeric;
v_qtyallocated numeric;
v_qtyonhand numeric;
v_qtytodeliver numeric;
v_qtyreserved numeric;
v_order_id numeric;
v_inoutExists numeric;
v_warehouse_id numeric;
v_product_id numeric;
v_orderReady numeric;
v_isShippable character(1);
v_deliveryRule character(1);
v_deliveryPolicy character(1);
v_return character(1);
BEGIN
SELECT qtyordered, qtydelivered, qtyallocated, qtyreserved, c_order_id,
get_delivery_policy(m_warehouse_id), isshippable(m_product_id),
m_warehouse_id, m_product_id
INTO
v_qtyordered, v_qtydelivered, v_qtyallocated, v_qtyreserved, v_order_id,
v_deliveryPolicy, v_isShippable,
v_warehouse_id, v_product_id
FROM
C_OrderLine where C_OrderLine_ID=c_order_line_id;
-- If all is already delivered then it's not a candidate
IF v_qtyordered = v_qtydelivered THEN
-- RAISE NOTICE 'All is delivered';
RETURN 0;
END IF;
-- Non shippable (ie non physical items) are always inout candidate
IF v_isShippable='N' THEN
-- RAISE NOTICE 'Non physical item, always deliverable';
RETURN 1;
END IF;
SELECT 1 INTO v_inoutExists FROM m_inoutline iol
JOIN m_inout io ON iol.m_inout_id = io.m_inout_id
WHERE iol.c_orderline_id = c_order_line_id AND (io.docstatus = ANY (ARRAY['IP'::bpchar, 'WC'::bpchar, 'IN'::bpchar]));
-- If an in-out line is in progress this is not a candidate
IF v_inoutExists = 1 THEN
-- RAISE NOTICE 'Already being shipped';
RETURN 0;
END IF;
-- Check delivery rule
SELECT DeliveryRule INTO
v_deliveryRule
FROM
C_Order where C_Order_ID=v_order_id;
IF v_deliveryRule='F' THEN
-- RAISE NOTICE 'Delivery rule = Force';
RETURN 1;
END IF; -- Force
v_qtytodeliver := v_qtyordered - v_qtydelivered;
IF v_qtytodeliver = 0 THEN
-- RAISE NOTICE 'Nothing to deliver';
RETURN 0;
END IF;
IF v_DeliveryPolicy = 'O' THEN -- Deliver in strict order, compare with qty allocated
BEGIN
-- RAISE NOTICE 'Delivery policy = Strict order';
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF v_qtytodeliver = v_qtyallocated THEN
-- RAISE NOTICE 'Quantity to deliver = qty allocated';
RETURN 1;
END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver > v_qtyallocated THEN
-- RAISE NOTICE 'Not enough allocated for complete order';
RETURN 0;
END IF;
WHEN 'A' THEN -- Availability
IF v_qtyallocated > 0 THEN
-- RAISE NOTICE 'Something to deliver';
RETURN 1;
END IF;
END CASE;
-- RAISE NOTICE 'No inout candidate';
RETURN 0;
END;
END IF;
IF v_DeliveryPolicy = 'N' THEN -- No hold, only compare with on hand
BEGIN
-- RAISE NOTICE 'Delivery policy = No hold';
SELECT qtyonhand INTO
v_qtyonhand
FROM m_product_stock_v
WHERE M_Product_ID=v_product_id AND M_Warehouse_ID=v_warehouse_id;
CASE v_deliveryRule
WHEN 'L' THEN -- Complete line
IF (v_qtytodeliver = v_qtyreserved AND v_qtytodeliver <= v_qtyonhand) THEN RETURN 1; END IF;
WHEN 'O' THEN -- Complete order
IF v_qtytodeliver < v_qtyreserved OR v_qtytodeliver >= v_qtyonhand THEN RETURN 0; END IF;
WHEN 'A' THEN -- Availability
IF v_qtyonhand > 0 THEN RETURN 1; END IF;
END CASE;
END;
END IF;
-- RAISE NOTICE 'Default answer, something to deliver';
return 1;
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION is_inout_candidate_orderline(numeric) OWNER TO adempiere;
-- INOUT CANDIDATE ORDER
CREATE OR REPLACE FUNCTION is_inout_candidate_order(p_order_id numeric)
RETURNS character AS
$BODY$
DECLARE
v_lines_ready numeric;
v_lines_total numeric;
v_deliveryRule character(1);
BEGIN
-- Get order info
-- Only orders that are complete, not delivered, delivery rule anything else than manual and is a sales order
-- can be inout candidates
select DeliveryRule INTO v_deliveryRule FROM C_Order WHERE
c_order_id=p_order_id AND
docstatus = 'CO'::bpchar AND
isdelivered = 'N'::bpchar AND
deliveryrule <> 'M'::bpchar AND
(c_doctype_id IN ( SELECT c_doctype.c_doctype_id FROM c_doctype
WHERE c_doctype.docbasetype = 'SOO'::bpchar AND (c_doctype.docsubtypeso <> ALL (ARRAY['ON'::bpchar, 'OB'::bpchar, 'WR'::bpchar]))));
IF v_deliveryRule IS NULL THEN
RETURN 'N';
END IF;
IF v_deliveryRule='F' THEN RETURN 'Y'; END IF; -- Force
-- Check lines
SELECT sum(is_inout_candidate_orderline(c_orderline_id)), sum(1)
INTO v_lines_ready, v_lines_total
FROM c_orderline where c_order_id=p_order_id;
CASE v_deliveryRule
WHEN 'L','A' THEN -- Complete line and Availability
IF v_lines_ready > 0 THEN RETURN 'Y'; END IF;
WHEN 'O' THEN -- Complete order
IF v_lines_ready = v_lines_total THEN RETURN 'Y'; END IF;
END CASE;
return 'N';
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION is_inout_candidate_order(numeric) OWNER TO adempiere;
-- INOUT CANDIDATE
CREATE OR REPLACE VIEW m_inout_candidate_v AS
SELECT
o.ad_client_id,
o.ad_org_id,
o.c_bpartner_id,
o.c_order_id,
o.documentno,
o.dateordered,
o.c_doctype_id,
o.poreference,
o.description,
o.salesrep_id,
l.m_warehouse_id,
sum((l.qtyordered - l.qtydelivered) * l.priceactual) AS totallines
FROM c_order o
JOIN c_orderline l ON o.c_order_id = l.c_order_id
WHERE
(l.m_product_id IS NULL OR (EXISTS ( SELECT 1
FROM m_product p
WHERE l.m_product_id = p.m_product_id AND p.isexcludeautodelivery = 'N'::bpchar))) AND
(l.m_product_id IS NOT NULL OR l.c_charge_id IS NOT NULL) AND
is_inout_candidate_order(o.c_order_id) = 'Y'
GROUP BY o.ad_client_id, o.ad_org_id, o.c_bpartner_id, o.c_order_id, o.documentno, o.dateordered, o.c_doctype_id, o.poreference, o.description, o.salesrep_id, l.m_warehouse_id;
ALTER TABLE m_inout_candidate_v OWNER TO adempiere;