diff --git a/sqlj/src/org/compiere/sqlj/Invoice.java b/sqlj/src/org/compiere/sqlj/Invoice.java index 4a5181cb01..de31970771 100644 --- a/sqlj/src/org/compiere/sqlj/Invoice.java +++ b/sqlj/src/org/compiere/sqlj/Invoice.java @@ -169,6 +169,184 @@ public class Invoice return TotalOpenAmt; } // open + // Begin e-Evolution 15/03/2006 + /** + * Open Invoice Amount. + * - incoiceOpen + * @param p_C_Invoice_ID invoice + * @param p_C_InvoicePaySchedule_ID payment schedule + * @param DateAcct Date Account + * @return open amount + * @throws SQLException + */ + public static BigDecimal openToDate (int p_C_Invoice_ID, int p_C_InvoicePaySchedule_ID, Timestamp DateAcct) + throws SQLException + { + // Invoice info + int C_Currency_ID = 0; + int C_ConversionType_ID = 0; + BigDecimal GrandTotal = null; + BigDecimal MultiplierAP = null; + BigDecimal MultiplierCM = null; + // + String sql = "SELECT MAX(C_Currency_ID),MAX(C_ConversionType_ID)," + + " SUM(GrandTotal), MAX(MultiplierAP), MAX(Multiplier) " + + "FROM C_Invoice_v " // corrected for CM / Split Payment + + "WHERE C_Invoice_ID=?" + // Begin + + " AND DateAcct <= ?"; + // End + if (p_C_InvoicePaySchedule_ID != 0) + sql += " AND C_InvoicePaySchedule_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_C_Invoice_ID); + pstmt.setTimestamp(2, DateAcct); + if (p_C_InvoicePaySchedule_ID != 0) + pstmt.setInt(3, p_C_InvoicePaySchedule_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + C_Currency_ID = rs.getInt(1); + C_ConversionType_ID = rs.getInt(2); + GrandTotal = rs.getBigDecimal(3); + MultiplierAP = rs.getBigDecimal(4); + MultiplierCM = rs.getBigDecimal(5); + } + rs.close(); + pstmt.close(); + pstmt = null; + // No Invoice + if (GrandTotal == null) + return null; + + BigDecimal paidAmt = allocatedAmtToDate(p_C_Invoice_ID, C_Currency_ID, + C_ConversionType_ID, MultiplierAP,DateAcct); + BigDecimal TotalOpenAmt = GrandTotal.subtract(paidAmt); + + /** + GrandTotal Paid TotalOpen Remaining Due x + 100 0 100 =0 + 1a =50-0 50 x + 1b =0-50 =0 50 + 2a =0-50 =0 50 + 2b =50-0 50 x + -- + 100 10 100 =10 + 1a =50-10 50 x + 1b =10-50 =0 50 + 2a =10-50 =0 50 + 2b =50-0 50 x + -- + 100 60 100 =60 + 1a =50-60 =0 50 x + 1b =60-50 50 + 2a =60-50 =10 50 + 2b =50-10 50 x + -- + **/ + + // Do we have a Payment Schedule ? + if (p_C_InvoicePaySchedule_ID > 0) // if not valid = lists invoice amount + { + TotalOpenAmt = GrandTotal; + BigDecimal remainingAmt = paidAmt; + sql = "SELECT C_InvoicePaySchedule_ID, DueAmt " + + "FROM C_InvoicePaySchedule " + + "WHERE C_Invoice_ID=?" + + " AND IsValid='Y' " + + "ORDER BY DueDate"; + pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_C_Invoice_ID); + rs = pstmt.executeQuery(); + while (rs.next()) + { + int C_InvoicePaySchedule_ID = rs.getInt(1); + BigDecimal DueAmt = rs.getBigDecimal(2); + // + if (C_InvoicePaySchedule_ID == p_C_InvoicePaySchedule_ID) + { + if (DueAmt.signum() > 0) // positive + { + if (DueAmt.compareTo(remainingAmt) < 0) // paid more + TotalOpenAmt = Adempiere.ZERO; + else + TotalOpenAmt = DueAmt.multiply(MultiplierCM) + .subtract(remainingAmt); + } + else + { + if (DueAmt.compareTo(remainingAmt) > 0) // paid more + TotalOpenAmt = Adempiere.ZERO; + else + TotalOpenAmt = DueAmt.multiply(MultiplierCM) + .add(remainingAmt); + } + } + else + { + if (DueAmt.signum() > 0) // positive + { + remainingAmt = remainingAmt.subtract(DueAmt); + if (remainingAmt.signum() < 0) + remainingAmt = Adempiere.ZERO; + } + else + { + remainingAmt = remainingAmt.add(DueAmt); + if (remainingAmt.signum() < 0) + remainingAmt = Adempiere.ZERO; + } + } + } + rs.close(); + pstmt.close(); + } // Invoice Schedule + + // Rounding + TotalOpenAmt = Currency.round(TotalOpenAmt, C_Currency_ID, null); + + // Ignore Penny if there is a payment + if (paidAmt.signum() != 0) + { + double open = TotalOpenAmt.doubleValue(); + if (open >= -0.01 && open <= 0.01) + TotalOpenAmt = Adempiere.ZERO; + } + // + return TotalOpenAmt; + } // open + // End e-Evolution 15/03/2006 + + // Begin e-Evolution 15/03/2006 + /** + * Get Invoice paid(allocated) amount. + * - invoicePaid + * @param p_C_Invoice_ID invoice + * @param p_C_Currency_ID currency + * @param p_MultiplierAP multiplier + * @param DateAcct Date Account + * @return paid amount + * @throws SQLException + */ + + public static BigDecimal paidToDate (int p_C_Invoice_ID, int p_C_Currency_ID, int p_MultiplierAP, Timestamp DateAcct) + throws SQLException + { + // Invalid Parameters + if (p_C_Invoice_ID == 0 || p_C_Currency_ID == 0) + return null; + // Parameters + BigDecimal MultiplierAP = new BigDecimal((double)p_MultiplierAP); + if (p_MultiplierAP == 0) + MultiplierAP = Adempiere.ONE; + int C_ConversionType_ID = 0; + + // Calculate Allocated Amount + BigDecimal paymentAmt = allocatedAmtToDate(p_C_Invoice_ID, + p_C_Currency_ID, C_ConversionType_ID, MultiplierAP,DateAcct); + return Currency.round(paymentAmt, p_C_Currency_ID, null); + } // paid + // End e-Evolution 15/03/2006 /** * Get Invoice paid(allocated) amount. @@ -242,9 +420,63 @@ public class Invoice } rs.close(); pstmt.close(); + pstmt = null; // return paidAmt; } // getAllocatedAmt + + // Begin e-Evolution ogi-cd 15/03/2006 + /** + * Get Allocated Amt (not directly used) + * @param C_Invoice_ID invoice + * @param C_Currency_ID currency + * @param C_ConversionType_ID conversion type + * @param MultiplierAP multiplier + * @param DateAcct Date Account + * @return allocated amount + * @throws SQLException + */ + public static BigDecimal allocatedAmtToDate(int C_Invoice_ID, + int C_Currency_ID, int C_ConversionType_ID, BigDecimal MultiplierAP, Timestamp DateAcct) + throws SQLException + { + // Calculate Allocated Amount + BigDecimal paidAmt = Adempiere.ZERO; + String sql = "SELECT a.AD_Client_ID, a.AD_Org_ID," + + " al.Amount, al.DiscountAmt, al.WriteOffAmt," + + " a.C_Currency_ID, a.DateTrx " + + "FROM C_AllocationLine al" + + " INNER JOIN C_AllocationHdr a ON (al.C_AllocationHdr_ID=a.C_AllocationHdr_ID) " + + "WHERE al.C_Invoice_ID=?" + + " AND a.IsActive='Y' AND a.DateAcct <= ?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, C_Invoice_ID); + pstmt.setTimestamp(2, DateAcct); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) + { + int AD_Client_ID = rs.getInt(1); + int AD_Org_ID = rs.getInt(2); + BigDecimal Amount = rs.getBigDecimal(3); + BigDecimal DiscountAmt = rs.getBigDecimal(4); + BigDecimal WriteOffAmt = rs.getBigDecimal(5); + int C_CurrencyFrom_ID = rs.getInt(6); + Timestamp DateTrx = rs.getTimestamp(7); + // + BigDecimal invAmt = Amount.add(DiscountAmt).add(WriteOffAmt); + BigDecimal allocation = Currency.convert(invAmt.multiply(MultiplierAP), + C_CurrencyFrom_ID, C_Currency_ID, DateTrx, C_ConversionType_ID, + AD_Client_ID, AD_Org_ID); + if (allocation != null) + paidAmt = paidAmt.add(allocation); + } + rs.close(); + pstmt.close(); + pstmt = null; + // + return paidAmt; + } // getAllocatedAmt + // End e-Evolution 15/03/2006 /** diff --git a/sqlj/src/org/compiere/sqlj/Manufacturing.java b/sqlj/src/org/compiere/sqlj/Manufacturing.java new file mode 100644 index 0000000000..b4e35c5eae --- /dev/null +++ b/sqlj/src/org/compiere/sqlj/Manufacturing.java @@ -0,0 +1,72 @@ +/****************************************************************************** + * The contents of this file are subject to the Compiere License Version 1.1 + * ("License"); You may not use this file except in compliance with the License + * You may obtain a copy of the License at http://www.compiere.org/license.html + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * The Original Code is Compiere ERP & CRM Smart Business Solution. The Initial + * Developer of the Original Code is Jorg Janke. Portions created by Jorg Janke + * are Copyright (C) 1999-2005 Jorg Janke. + * All parts are Copyright (C) 1999-2005 ComPiere, Inc. All Rights Reserved. + * Created by Victor Perez are Copyright (C) e-Evolution,SC. All Rights Reserved. + * Contributor(s): ______________________________________. + *****************************************************************************/ +package org.compiere.sqlj; + +import java.math.*; +import java.sql.*; + + +/** + * SQLJ Manufacturing related Functions + * + * @author Victor Perez + * @version $Id: Manufacturing.java,v 1 2005/04/06 10:15:02 vj-cd Exp $ + */ +public class Manufacturing +{ + /** + * Get Order_ID for MRPType. * + * Test: + SELECT CASE WHEN mrp.TypeMRP = 'FTC' THEN (SELECT f.Name FROM M_Forecast f WHERE f.M_Forecast_ID=mrp.M_Forecast_ID) + WHEN mrp.TypeMRP = 'POO' THEN (SELECT o.DocumentNo FROM C_Order o WHERE o.C_Order_ID=mrp.C_Order_ID) + WHEN mrp.TypeMRP = 'DOO' THEN (SELECT o.DocumentNo FROM DD_Order o WHERE o.DD_Order_ID=mrp.DD_Order_ID) + WHEN mrp.TypeMRP = 'SOO' THEN (SELECT o.DocumentNo FROM C_Order o WHERE o.C_Order_ID=mrp.C_Order_ID) + WHEN mrp.TypeMRP = 'MOP' THEN (SELECT o.DocumentNo FROM PP_Order o WHERE o.PP_Order_ID=mrp.PP_Order_ID) + WHEN mrp.TypeMRP = 'POR' THEN (SELECT r.DocumentNo FROM M_Requisition r WHERE r.M_Requisition_ID=mrp.M_Requisition_ID) END AS DocumentNo + FROM PP_MRP mrp WHERE mrp.PP_MRP_ID=PP_MRP.PP_MRP_ID)) + * @param p_MPC_MRP_ID + * @return DocumentNo + */ + public static String documentNo (int p_MPC_MRP_ID) + throws SQLException + { + if (p_MPC_MRP_ID == 0) + return ""; + // + String documentNo = ""; + // Get Base Info + String sql = "SELECT CASE WHEN mrp.TypeMRP = 'FTC' THEN (SELECT f.Name FROM M_Forecast f WHERE f.M_Forecast_ID=mrp.M_Forecast_ID) " + + "WHEN mrp.TypeMRP = 'POO' THEN (SELECT o.DocumentNo FROM C_Order o WHERE o.C_Order_ID=mrp.C_Order_ID) " + + "WHEN mrp.TypeMRP = 'DOO' THEN (SELECT o.DocumentNo FROM DD_Order o WHERE o.DD_Order_ID=mrp.DD_Order_ID)" + + "WHEN mrp.TypeMRP = 'SOO' THEN (SELECT o.DocumentNo FROM C_Order o WHERE o.C_Order_ID=mrp.C_Order_ID) " + + "WHEN mrp.TypeMRP = 'MOP' THEN (SELECT o.DocumentNo FROM PP_Order o WHERE o.PP_Order_ID=mrp.PP_Order_ID) " + + "WHEN mrp.TypeMRP = 'POR' THEN (SELECT r.DocumentNo FROM M_Requisition r WHERE r.M_Requisition_ID=mrp.M_Requisition_ID) END AS DocumentNo " + + "FROM PP_MRP mrp WHERE mrp.PP_MRP_ID=?"; + + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_MPC_MRP_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + documentNo = rs.getString(1); + } + rs.close(); + pstmt.close(); + return documentNo; + } // getdocumentNo + + + +} // Manufacturing diff --git a/sqlj/src/org/compiere/sqlj/Product.java b/sqlj/src/org/compiere/sqlj/Product.java index 411398656b..7cdf1bbaac 100644 --- a/sqlj/src/org/compiere/sqlj/Product.java +++ b/sqlj/src/org/compiere/sqlj/Product.java @@ -181,10 +181,14 @@ public class Product if (price == null || price.signum() == 0) { price = Adempiere.ZERO; - sql = "SELECT b.M_ProductBOM_ID, b.BOMQty, p.IsBOM " + /*sql = "SELECT b.M_ProductBOM_ID, b.BOMQty, p.IsBOM " + "FROM M_Product_BOM b, M_Product p " + "WHERE b.M_ProductBOM_ID=p.M_Product_ID" - + " AND b.M_Product_ID=?"; + + " AND b.M_Product_ID=?";*/ + sql = "SELECT bl.M_Product_ID , CASE WHEN bl.IsQtyPercentage = 'N' THEN bl.QtyBOM ELSE bl.QtyBatch / 100 END AS Qty , p.IsBOM FROM PP_Product_BOM b " + + "INNER JOIN M_Product p ON (p.M_Product_ID=b.M_Product_ID) " + + "INNER JOIN PP_Product_BOMLine bl ON (bl.PP_Product_BOM_ID=b.PP_Product_BOM_ID) " + + "WHERE b.M_Product_ID = ?"; pstmt = Adempiere.prepareStatement(sql); pstmt.setInt(1, p_M_Product_ID); rs = pstmt.executeQuery(); @@ -332,10 +336,16 @@ public class Product // Go through BOM BigDecimal quantity = UNLIMITED; BigDecimal productQuantity = null; - sql = "SELECT b.M_ProductBOM_ID, b.BOMQty, p.IsBOM, p.IsStocked, p.ProductType " + /*sql = "SELECT b.M_ProductBOM_ID, b.BOMQty, p.IsBOM, p.IsStocked, p.ProductType " + "FROM M_Product_BOM b, M_Product p " + "WHERE b.M_ProductBOM_ID=p.M_Product_ID" - + " AND b.M_Product_ID=?"; + + " AND b.M_Product_ID=?";*/ + + sql = "SELECT bl.M_Product_ID , CASE WHEN bl.IsQtyPercentage = 'N' THEN bl.QtyBOM ELSE bl.QtyBatch / 100 END AS Qty , p.IsBOM , p.IsStocked, p.ProductType FROM PP_Product_BOM b " + + "INNER JOIN M_Product p ON (p.M_Product_ID=b.M_Product_ID) " + + "INNER JOIN PP_Product_BOMLine bl ON (bl.PP_Product_BOM_ID=b.PP_Product_BOM_ID) " + + "WHERE b.M_Product_ID = ?"; + pstmt = Adempiere.prepareStatement(sql); pstmt.setInt(1, p_M_Product_ID); rs = pstmt.executeQuery(); @@ -469,4 +479,200 @@ public class Product } } // main /* */ + + public static BigDecimal bomQtyAvailableASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQtyOnHandASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID) + .subtract(bomQtyReservedASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID)); + } // bomQtyAvailable + + public static BigDecimal bomQtyOnHandASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQtyASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyOnHand"); + } // bomQtyOnHand + + public static BigDecimal bomQtyOrderedASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQtyASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyOrdered"); + } // bomQtyOrdered + + public static BigDecimal bomQtyReservedASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQtyASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyReserved"); + } // bomQtyReserved + + /** + * Get BOM Quantity + * @param p_M_Product_ID product + * @param p_M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @param p_what variable name + * @return Quantity + */ + static BigDecimal bomQtyASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID, String p_what) + throws SQLException + { + // Check Parameters + /* + int M_Warehouse_ID = p_M_Warehouse_ID; + if (M_Warehouse_ID == 0) + { + if (p_M_Locator_ID == 0) + return Compiere.ZERO; + else + { + String sql = "SELECT M_Warehouse_ID " + + "FROM M_Locator " + + "WHERE M_Locator_ID=" + p_M_Locator_ID; + M_Warehouse_ID = Compiere.getSQLValue(sql, p_M_Locator_ID); + } + } + if (M_Warehouse_ID == 0) + return Compiere.ZERO; + */ + // Check, if product exists and if it is stocked + boolean isBOM = false; + String ProductType = null; + boolean isStocked = false; + String sql = "SELECT IsBOM, ProductType, IsStocked " + + "FROM M_Product " + + "WHERE M_Product_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_Product_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + isBOM = "Y".equals(rs.getString(1)); + ProductType = rs.getString(2); + isStocked = "Y".equals(rs.getString(3)); + } + rs.close(); + pstmt.close(); + // No Product + if (ProductType == null) + return Compiere.ZERO; + // Unlimited capacity if no item + if (!isBOM && (!ProductType.equals("I") || !isStocked)) + return UNLIMITED; + // Get Qty + if (isStocked) { + + return getStorageQtyASI(p_M_Product_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, p_what); + } + // Go through BOM + BigDecimal quantity = UNLIMITED; + BigDecimal productQuantity = null; + /*sql = "SELECT b.M_ProductBOM_ID, b.BOMQty, p.IsBOM, p.IsStocked, p.ProductType " + + "FROM M_Product_BOM b, M_Product p " + + "WHERE b.M_ProductBOM_ID=p.M_Product_ID" + + " AND b.M_Product_ID=?";*/ + sql = "SELECT bl.M_Product_ID , CASE WHEN bl.IsQtyPercentage = 'N' THEN bl.QtyBOM ELSE bl.QtyBatch / 100 END AS Qty , p.IsBOM , p.IsStocked, p.ProductType FROM PP_Product_BOM b " + + "INNER JOIN M_Product p ON (p.M_Product_ID=b.M_Product_ID) " + + "INNER JOIN PP_Product_BOMLine bl ON (bl.PP_Product_BOM_ID=b.PP_Product_BOM_ID) " + + "WHERE b.M_Product_ID = ?"; + pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_Product_ID); + rs = pstmt.executeQuery(); + while (rs.next()) + { + int M_ProductBOM_ID = rs.getInt(1); + BigDecimal bomQty = rs.getBigDecimal(2); + isBOM = "Y".equals(rs.getString(3)); + isStocked = "Y".equals(rs.getString(4)); + ProductType = rs.getString(5); + + // Stocked Items "leaf node" + if (ProductType.equals("I") && isStocked) + { + // Get ProductQty + productQuantity = getStorageQtyASI(M_ProductBOM_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, p_what); + // Get Rounding Precision + int StdPrecision = getUOMPrecision(M_ProductBOM_ID); + // How much can we make with this product + productQuantity = productQuantity.setScale(StdPrecision) + .divide(bomQty, BigDecimal.ROUND_HALF_UP); + // How much can we make overall + if (productQuantity.compareTo(quantity) < 0) + quantity = productQuantity; + } + else if (isBOM) // Another BOM + { + productQuantity = bomQtyASI (M_ProductBOM_ID, p_M_AttributeSetInstance_ID, p_M_Warehouse_ID, p_M_Locator_ID, p_what); + // How much can we make overall + if (productQuantity.compareTo(quantity) < 0) + quantity = productQuantity; + } + } + rs.close(); + pstmt.close(); + + if (quantity.signum() > 0) + { + int StdPrecision = getUOMPrecision(p_M_Product_ID); + return quantity.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP); + } + return Adempiere.ZERO; + } // bomQtyOnHand + + /** + * Get Storage Qty + * @param p_M_Product_ID product + * @param M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @param p_what variable name + * @return quantity or zero + * @throws SQLException + */ + static BigDecimal getStorageQtyASI (int p_M_Product_ID, int p_M_AttributeSetInstance_ID, + int M_Warehouse_ID, int p_M_Locator_ID, String p_what) + throws SQLException + { + BigDecimal quantity = null; + + String sql = "SELECT SUM(" + p_what + ") " + + "FROM M_Storage s " + + "WHERE M_Product_ID=?"; + if(p_M_AttributeSetInstance_ID != 0) { + sql +=" AND s.M_AttributeSetInstance_ID = ?"; + } + if (p_M_Locator_ID != 0) { + sql += " AND s.M_Locator_ID=?"; + } + else if(M_Warehouse_ID != 0) { + sql += " AND EXISTS (SELECT * FROM M_Locator l WHERE s.M_Locator_ID=l.M_Locator_ID" + + " AND l.M_Warehouse_ID=?)"; + } + + int index=1; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(index++, p_M_Product_ID); + if(p_M_AttributeSetInstance_ID != 0) { + pstmt.setInt(index++, p_M_AttributeSetInstance_ID); + } + if (p_M_Locator_ID != 0) { + pstmt.setInt(index++, p_M_Locator_ID); + } + else if(M_Warehouse_ID != 0) { + pstmt.setInt(index++, M_Warehouse_ID); + } + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + quantity = rs.getBigDecimal(1); + rs.close(); + pstmt.close(); + // Not found + if (quantity == null) + return Adempiere.ZERO; + return quantity; + } // getStorageQty + } // Product