diff --git a/sqlj/src/org/compiere/sqlj/Invoice.java b/sqlj/src/org/compiere/sqlj/Invoice.java new file mode 100644 index 0000000000..4a5181cb01 --- /dev/null +++ b/sqlj/src/org/compiere/sqlj/Invoice.java @@ -0,0 +1,367 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.sqlj; + +import java.math.*; +import java.sql.*; + + +/** + * SQLJ Invoice related Functions + * + * @author Jorg Janke + * @version $Id: Invoice.java,v 1.3 2006/07/30 00:59:07 jjanke Exp $ + */ +public class Invoice +{ + /** + * Open Invoice Amount. + * - incoiceOpen + * @param p_C_Invoice_ID invoice + * @param p_C_InvoicePaySchedule_ID payment schedule + * @return open amount + * @throws SQLException + */ + public static BigDecimal open (int p_C_Invoice_ID, int p_C_InvoicePaySchedule_ID) + 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=?"; + if (p_C_InvoicePaySchedule_ID != 0) + sql += " AND C_InvoicePaySchedule_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_C_Invoice_ID); + if (p_C_InvoicePaySchedule_ID != 0) + pstmt.setInt(2, 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(); + // No Invoice + if (GrandTotal == null) + return null; + + + BigDecimal paidAmt = allocatedAmt(p_C_Invoice_ID, C_Currency_ID, + C_ConversionType_ID, MultiplierAP); + 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 + + + /** + * Get Invoice paid(allocated) amount. + * - invoicePaid + * @param p_C_Invoice_ID invoice + * @param p_C_Currency_ID currency + * @param p_MultiplierAP multiplier + * @return paid amount + * @throws SQLException + */ + public static BigDecimal paid (int p_C_Invoice_ID, int p_C_Currency_ID, int p_MultiplierAP) + 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 = allocatedAmt(p_C_Invoice_ID, + p_C_Currency_ID, C_ConversionType_ID, MultiplierAP); + return Currency.round(paymentAmt, p_C_Currency_ID, null); + } // paid + + + /** + * 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 + * @return allocated amount + * @throws SQLException + */ + public static BigDecimal allocatedAmt(int C_Invoice_ID, + int C_Currency_ID, int C_ConversionType_ID, BigDecimal MultiplierAP) + 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'"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, C_Invoice_ID); + 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(); + // + return paidAmt; + } // getAllocatedAmt + + + /** + * Get Invoice discount. + * C_Invoice_Discount - invoiceDiscount + * @param p_C_Invoice_ID invoice + * @param p_PayDate pay date + * @param p_C_InvoicePaySchedule_ID pay schedule + * @return discount amount or null + * @throws SQLException + */ + public static BigDecimal discount (int p_C_Invoice_ID, + Timestamp p_PayDate, int p_C_InvoicePaySchedule_ID) + throws SQLException + { + // Parameters + if (p_C_Invoice_ID == 0) + return null; + Timestamp PayDate = p_PayDate; + if (PayDate == null) + PayDate = new Timestamp (System.currentTimeMillis()); + PayDate = Adempiere.trunc(PayDate); + + // Invoice Info + boolean IsDiscountLineAmt = false; + BigDecimal GrandTotal = null; + BigDecimal TotalLines = null; + int C_PaymentTerm_ID = 0; + Timestamp DateInvoiced = null; + boolean IsPayScheduleValid = false; + int C_Currency_ID = 0; + String sql = "SELECT ci.IsDiscountLineAmt, i.GrandTotal, i.TotalLines, " + + " i.C_PaymentTerm_ID, i.DateInvoiced, i.IsPayScheduleValid, i.C_Currency_ID " + + "FROM C_Invoice i" + + " INNER JOIN AD_ClientInfo ci ON (ci.AD_Client_ID=i.AD_Client_ID) " + + "WHERE i.C_Invoice_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_C_Invoice_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + IsDiscountLineAmt = "Y".equals(rs.getString(1)); + GrandTotal = rs.getBigDecimal(2); + TotalLines = rs.getBigDecimal(3); + C_PaymentTerm_ID = rs.getInt(4); + DateInvoiced = rs.getTimestamp(5); + IsPayScheduleValid = "Y".equals(rs.getString(6)); + C_Currency_ID = rs.getInt(7); + } + rs.close(); + pstmt.close(); + // Not found + if (GrandTotal == null) + //vpj-cd return null; + return Adempiere.ZERO; + + // What Amount is the Discount Base? + BigDecimal amount = GrandTotal; + if (IsDiscountLineAmt) + amount = TotalLines; + + // Anything to discount? + if (amount.signum() == 0) + return Adempiere.ZERO; + + // Valid Payment Schedule (has discount) + if (IsPayScheduleValid && p_C_InvoicePaySchedule_ID > 0) + { + BigDecimal discount = Adempiere.ZERO; + sql = "SELECT DiscountAmt " + + "FROM C_InvoicePaySchedule " + + "WHERE C_InvoicePaySchedule_ID=?" + + " AND TRUNC(DiscountDate) <= ?"; + pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_C_InvoicePaySchedule_ID); + pstmt.setTimestamp(2, PayDate); + rs = pstmt.executeQuery(); + if (rs.next()) + discount = rs.getBigDecimal(1); + rs.close(); + pstmt.close(); + // + return discount; + } + + // return discount amount + return PaymentTerm.discount (amount, C_Currency_ID, + C_PaymentTerm_ID, DateInvoiced, PayDate); + } // discount + + /** + * Test + * @param args + * + public static void main (String[] args) + { + + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + Adempiere.s_type = Adempiere.TYPE_ORACLE; + Adempiere.s_url = "jdbc:oracle:thin:@//dev1:1521/dev1.adempiere.org"; + Adempiere.s_uid = "adempiere"; + Adempiere.s_pwd = "adempiere"; + // System.out.println(Invoice.open(1000000, 1000004)); + // System.out.println(Invoice.open(1000000, 1000005)); + // System.out.println(Invoice.open(1000001, 1000006)); + // System.out.println(Invoice.open(1000001, 1000007)); + System.out.println(Invoice.paid(101, 100, 1)); + System.out.println(Invoice.paid(1000000, 100, 1)); + System.out.println(Invoice.paid(1000001, 100, 1)); + System.out.println(Invoice.paid(1000002, 100, 1)); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } // main /* */ + +} // Invoice diff --git a/sqlj/src/org/compiere/sqlj/Product.java b/sqlj/src/org/compiere/sqlj/Product.java new file mode 100644 index 0000000000..411398656b --- /dev/null +++ b/sqlj/src/org/compiere/sqlj/Product.java @@ -0,0 +1,472 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.sqlj; + +import java.math.*; +import java.sql.*; + + +/** + * SQLJ Product related Functions + * + * @author Jorg Janke + * @version $Id: Product.java,v 1.3 2006/07/30 00:59:07 jjanke Exp $ + */ +public class Product +{ + /** + * Get Product Attribute Instance Name. + * Previously: M_Attribute_Name - Now: productAttribute + * Test: + SELECT M_Attribute_Name (M_AttributeSetInstance_ID) + FROM M_InOutLine WHERE M_AttributeSetInstance_ID > 0 + -- + SELECT p.Name + FROM C_InvoiceLine il LEFT OUTER JOIN M_Product p ON (il.M_Product_ID=p.M_Product_ID); + SELECT p.Name || M_Attribute_Name (il.M_AttributeSetInstance_ID) + FROM C_InvoiceLine il LEFT OUTER JOIN M_Product p ON (il.M_Product_ID=p.M_Product_ID); + * @param p_M_AttributeSetInstance_ID instance + * @return Name or "" + * @throws SQLException + */ + public static String attributeName (int p_M_AttributeSetInstance_ID) + throws SQLException + { + if (p_M_AttributeSetInstance_ID == 0) + return ""; + // + StringBuffer sb = new StringBuffer(); + // Get Base Info + String sql = "SELECT asi.Lot, asi.SerNo, asi.GuaranteeDate " + + "FROM M_AttributeSetInstance asi " + + "WHERE asi.M_AttributeSetInstance_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_AttributeSetInstance_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + { + String lot = rs.getString(1); + if (lot != null && lot.length() > 0) + sb.append(lot).append(" "); + String serNo = rs.getString(2); + if (serNo != null && serNo.length() > 0) + sb.append("#").append(serNo).append(" "); + Date guaranteeDate = null; + //either date or timestamp + Object guarantee = rs.getObject(3); + if (guarantee != null) + { + if (guarantee instanceof Timestamp) + { + Timestamp ts = (Timestamp)guarantee; + guaranteeDate = new Date(ts.getTime()); + } + else + { + guaranteeDate = (Date)guaranteeDate; + } + } + if (guaranteeDate != null) + sb.append(guaranteeDate).append(" "); + } + rs.close(); + pstmt.close(); + + // Get Instance Info + sql = "SELECT ai.Value, a.Name " + + "FROM M_AttributeInstance ai" + + " INNER JOIN M_Attribute a ON (ai.M_Attribute_ID=a.M_Attribute_ID AND a.IsInstanceAttribute='Y') " + + "WHERE ai.M_AttributeSetInstance_ID=?"; + pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_AttributeSetInstance_ID); + rs = pstmt.executeQuery(); + while (rs.next()) + { + sb.append(rs.getString(1)) // value + .append(":").append(rs.getString(2)) // name + .append(" "); + } + rs.close(); + pstmt.close(); + + if (sb.length() == 0) + return ""; + sb.insert(0, " ("); + sb.append(")"); + return sb.toString(); + } // getAttributeName + + + /************************************************************************** + * Get BOM Price Limit + * Previously: BOM_PriceLimit - Now: bomPriceLimit + * @param p_M_Product_ID + * @param p_M_PriceList_Version_ID + * @return Price Limit + * @throws SQLException + */ + public static BigDecimal bomPriceLimit (int p_M_Product_ID, int p_M_PriceList_Version_ID) + throws SQLException + { + return bomPrice(p_M_Product_ID, p_M_PriceList_Version_ID, "PriceLimit"); + } // bomPriceLimit + + /** + * Get BOM Price List + * Previously: BOM_PriceList - Now: bomPriceList + * @param p_M_Product_ID + * @param p_M_PriceList_Version_ID + * @return Price List + * @throws SQLException + */ + public static BigDecimal bomPriceList (int p_M_Product_ID, int p_M_PriceList_Version_ID) + throws SQLException + { + return bomPrice(p_M_Product_ID, p_M_PriceList_Version_ID, "PriceList"); + } // bomPriceList + + /** + * Get BOM Price Std + * Previously: BOM_PriceStd - Now: bomPriceStd + * @param p_M_Product_ID + * @param p_M_PriceList_Version_ID + * @return Price Std + * @throws SQLException + */ + public static BigDecimal bomPriceStd (int p_M_Product_ID, int p_M_PriceList_Version_ID) + throws SQLException + { + return bomPrice(p_M_Product_ID, p_M_PriceList_Version_ID, "PriceStd"); + } // bomPriceStd + + /** + * Get BOM Price + * @param p_M_Product_ID + * @param p_M_PriceList_Version_ID + * @param p_what variable name + * @return Price + * @throws SQLException + */ + static BigDecimal bomPrice (int p_M_Product_ID, int p_M_PriceList_Version_ID, String p_what) + throws SQLException + { + BigDecimal price = null; + // Try to get price from PriceList directly + String sql = "SELECT " + p_what + + " FROM M_ProductPrice " + + "WHERE M_PriceList_Version_ID=? AND M_Product_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_PriceList_Version_ID); + pstmt.setInt(2, p_M_Product_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + price = rs.getBigDecimal(1); + rs.close(); + pstmt.close(); + // Loop through BOM + if (price == null || price.signum() == 0) + { + price = Adempiere.ZERO; + 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=?"; + 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 qty = rs.getBigDecimal(2); + BigDecimal productPrice = bomPrice(M_ProductBOM_ID, p_M_PriceList_Version_ID, p_what); + productPrice = productPrice.multiply(qty); + price = price.add(productPrice); + } + rs.close(); + pstmt.close(); + } + return price; + } // bomPrice + + + /************************************************************************** + * Get BOM Quantity Available + * Previously: BOM_Qty_Available - Now: bomQtyAvailable + * @param p_M_Product_ID product + * @param p_M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @return Quantity Available + * @throws SQLException + */ + public static BigDecimal bomQtyAvailable (int p_M_Product_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQty(p_M_Product_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyOnHand") + .subtract(bomQty(p_M_Product_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyReserved")); + } // bomQtyAvailable + + /** + * Get BOM Quantity OnHand + * Previously: BOM_Qty_OnHand - Now: bomQtyOnHand + * @param p_M_Product_ID product + * @param p_M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @return Quantity Available + * @throws SQLException + */ + public static BigDecimal bomQtyOnHand (int p_M_Product_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQty(p_M_Product_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyOnHand"); + } // bomQtyOnHand + + /** + * Get BOM Quantity Ordered + * Previously: BOM_Qty_Ordered - Now: bomQtyOrdered + * @param p_M_Product_ID product + * @param p_M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @return Quantity Ordered + * @throws SQLException + */ + public static BigDecimal bomQtyOrdered (int p_M_Product_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQty(p_M_Product_ID, p_M_Warehouse_ID, p_M_Locator_ID, "QtyOrdered"); + } // bomQtyOrdered + + /** + * Get BOM Quantity Reserved + * Previously: BOM_Qty_Reserved - Now: bomQtyReserved + * @param p_M_Product_ID product + * @param p_M_Warehouse_ID warehouse + * @param p_M_Locator_ID locator + * @return Qyantity Reserved + * @throws SQLException + */ + public static BigDecimal bomQtyReserved (int p_M_Product_ID, + int p_M_Warehouse_ID, int p_M_Locator_ID) + throws SQLException + { + return bomQty(p_M_Product_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 + * @throws SQLException + */ + static BigDecimal bomQty (int p_M_Product_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 Adempiere.ZERO; + else + { + String sql = "SELECT M_Warehouse_ID " + + "FROM M_Locator " + + "WHERE M_Locator_ID=?"; + M_Warehouse_ID = Adempiere.getSQLValue(sql, p_M_Locator_ID); + } + } + // begin globalqss 2005-10-11 + // if (M_Warehouse_ID == 0) + if (M_Warehouse_ID == 0 || M_Warehouse_ID == -1) + // end globalqss 2005-10-11 + return Adempiere.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 Adempiere.ZERO; + // Unlimited capacity if no item + if (!isBOM && (!ProductType.equals("I") || !isStocked)) + return UNLIMITED; + // Get Qty + if (isStocked) + return getStorageQty(p_M_Product_ID, 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=?"; + 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 = getStorageQty(M_ProductBOM_ID, M_Warehouse_ID, p_M_Locator_ID, p_what); + // Get Rounding Precision + int uomPrecision = getUOMPrecision(M_ProductBOM_ID); + // How much can we make with this product + //hengsin, [ 1649453 ] bomQtyAvailable sqlj function throw ArithmeticException + //productQuantity = productQuantity.setScale(uomPrecision) + // .divide(bomQty, uomPrecision, BigDecimal.ROUND_HALF_UP); + productQuantity = productQuantity.divide(bomQty, uomPrecision, BigDecimal.ROUND_HALF_UP); + // How much can we make overall + if (productQuantity.compareTo(quantity) < 0) + quantity = productQuantity; + } + else if (isBOM) // Another BOM + { + productQuantity = bomQty (M_ProductBOM_ID, 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 uomPrecision = getUOMPrecision(p_M_Product_ID); + return quantity.setScale(uomPrecision, BigDecimal.ROUND_HALF_UP); + } + return Adempiere.ZERO; + } // bomQtyOnHand + + /** Unlimited Quantity */ + private static final BigDecimal UNLIMITED = new BigDecimal((double)99999.0); + + /** + * 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 getStorageQty (int p_M_Product_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_Locator_ID != 0) + sql += " AND s.M_Locator_ID=?"; + else + sql += " AND EXISTS (SELECT * FROM M_Locator l WHERE s.M_Locator_ID=l.M_Locator_ID" + + " AND l.M_Warehouse_ID=?)"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_Product_ID); + if (p_M_Locator_ID != 0) + pstmt.setInt(2, p_M_Locator_ID); + else + pstmt.setInt(2, 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 + + /** + * Get UOM Precision for Product + * @param p_M_Product_ID product + * @return precision or 0 + * @throws SQLException + */ + static int getUOMPrecision (int p_M_Product_ID) throws SQLException + { + int precision = 0; + String sql = "SELECT u.StdPrecision " + + "FROM C_UOM u" + + " INNER JOIN M_Product p ON (u.C_UOM_ID=p.C_UOM_ID) " + + "WHERE p.M_Product_ID=?"; + PreparedStatement pstmt = Adempiere.prepareStatement(sql); + pstmt.setInt(1, p_M_Product_ID); + ResultSet rs = pstmt.executeQuery(); + if (rs.next()) + precision = rs.getInt(1); + rs.close(); + pstmt.close(); + return precision; + } // getStdPrecision + + /** + * Test + * @param args + * + public static void main (String[] args) + { + + try + { + DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver()); + Adempiere.s_type = Adempiere.TYPE_ORACLE; + Adempiere.s_url = "jdbc:oracle:thin:@//dev1:1521/dev1.adempiere.org"; + Adempiere.s_uid = "adempiere"; + Adempiere.s_pwd = "adempiere"; + // System.out.println(Product.bomQtyOnHand(p_M_Product_ID, 0, p_M_Locator_ID)); + } + catch (SQLException e) + { + e.printStackTrace(); + } + } // main /* */ + +} // Product