+
+Project: Base Functionality for Server and Client
+Author: Jorg Janke
+Version: $Id: Base.html,v 1.1 2006/04/21 17:41:36 jjanke Exp $
+
+Description:
+
+The project creates the jar file Adempiere/base/Base.jar, which is included
+in Server and Client jars (i.e. not directly distributed to minimize number of jars).
+
+
+
+Things to do...
+
+
+
+
Item 1
+
Item 2
+
+
+
+
diff --git a/base/RUN_build.bat b/base/RUN_build.bat
new file mode 100644
index 0000000000..1c1fcd9104
--- /dev/null
+++ b/base/RUN_build.bat
@@ -0,0 +1,20 @@
+@Title Build Base
+@Rem $Header: /cvsroot/adempiere/base/RUN_build.bat,v 1.10 2005/09/16 00:48:27 jjanke Exp $
+@Echo off
+
+@CALL ..\utils_dev\myDevEnv.bat
+@IF NOT %ADEMPIERE_ENV%==Y GOTO NOBUILD
+
+@echo Cleanup ...
+@"%JAVA_HOME%\bin\java" -Dant.home="." %ANT_PROPERTIES% org.apache.tools.ant.Main clean
+
+@echo Building ...
+@"%JAVA_HOME%\bin\java" -Dant.home="." %ANT_PROPERTIES% org.apache.tools.ant.Main dist
+
+@Echo Done ...
+@sleep 60
+@exit
+
+:NOBUILD
+@Echo Check myDevEnv.bat (copy from myDevEnvTemplate.bat)
+@Pause
diff --git a/base/RUN_build.sh b/base/RUN_build.sh
new file mode 100644
index 0000000000..5f80633c60
--- /dev/null
+++ b/base/RUN_build.sh
@@ -0,0 +1,18 @@
+# Module compiling script
+# Ported from Windows script Marek Mosiewicz
+
+
+SAVED_DIR=`pwd` #save current dir
+cd `dirname $0`/../utils_dev #change dir to place where script resides - doesn not work with sym links
+UTILS_DEV=`pwd` #this is adempiere source
+cd $SAVED_DIR #back to the saved directory
+
+. $UTILS_DEV/myDevEnv.sh #call environment
+echo done
+if [ ! $ADEMPIERE_ENV==Y ] ; then
+ echo "Can't set developemeent environemnt - check myDevEnv.sh"
+ exit 1
+fi
+
+echo running Ant
+$JAVA_HOME/bin/java -Dant.home="." $ANT_PROPERTIES org.apache.tools.ant.Main
diff --git a/base/build.xml b/base/build.xml
new file mode 100644
index 0000000000..c22fb9b4ae
--- /dev/null
+++ b/base/build.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+ This buildfile is used to build the base subproject within
+ the Adempiere project.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/base/documentation.bat b/base/documentation.bat
new file mode 100644
index 0000000000..659c934f80
--- /dev/null
+++ b/base/documentation.bat
@@ -0,0 +1,5 @@
+@Rem API Documentation for Base
+
+call ..\doc\documentation.bat src doc -private
+
+@pause
\ No newline at end of file
diff --git a/base/packages.txt b/base/packages.txt
new file mode 100644
index 0000000000..cd4f9cfa65
--- /dev/null
+++ b/base/packages.txt
@@ -0,0 +1,6 @@
+org.compiere
+org.compiere.impexp
+org.compiere.model
+org.compiere.report.core
+org.compiere.server
+org.compiere.util
diff --git a/base/packaging-build.xml b/base/packaging-build.xml
new file mode 100644
index 0000000000..971b488314
--- /dev/null
+++ b/base/packaging-build.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/base/src/org/compiere/Base.java b/base/src/org/compiere/Base.java
new file mode 100644
index 0000000000..84675bc0ad
--- /dev/null
+++ b/base/src/org/compiere/Base.java
@@ -0,0 +1,156 @@
+/******************************************************************************
+ * 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;
+
+import java.math.*;
+import java.util.*;
+import org.compiere.model.*;
+import org.compiere.util.*;
+
+/**
+ * Base Library Test Classes mainly for Optimize it
+ *
+ * @author Jorg Janke
+ * @version $Id: Base.java,v 1.5 2006/09/21 20:44:54 jjanke Exp $
+ */
+class Base
+{
+ /**
+ * Base Test
+ */
+ public static void test()
+ {
+ System.out.println("** Before Init **"); //$NON-NLS-1$
+ getMemoryUsed();
+ Properties ctx = Login.initTest(false);
+ // Log.printProperties(System.getProperties(), "System", false);
+ //
+ System.gc(); // cleanup Init
+ //
+ System.out.println("** Before Creation **");
+ long start = getMemoryUsed();
+
+ // *******************************************************************
+
+ // Table=100, Shipper=142, Window=102, Reference=101
+ int AD_Window_ID = 102;
+ long startTime = System.currentTimeMillis();
+ GridWindowVO vo = GridWindowVO.create(Env.getCtx(), 1, AD_Window_ID);
+ GridWindow w = new GridWindow(vo);
+ long endDef = System.currentTimeMillis();
+ System.out.println("Load Definition Time in ms = " + String.valueOf(endDef-startTime));
+ if (1==2) // optional step
+ {
+ w.loadCompete();
+ long endDefComplete = System.currentTimeMillis();
+ System.out.println("Load Definition Complete Time in ms = " + String.valueOf(endDefComplete-startTime));
+ }
+ w.query();
+ long endData = System.currentTimeMillis();
+ System.out.println("Load Data Time in ms = " + String.valueOf(endData-startTime));
+ w.loadCompete();
+ long endDataComplete = System.currentTimeMillis();
+ System.out.println("Load Data Complete Time in ms = " + String.valueOf(endDataComplete-startTime));
+ w.getTab(0).navigate(0);
+
+ // *******************************************************************
+// sleep();
+
+ System.out.println("** Before Dispose **");
+ getMemoryUsed();
+ w.dispose();
+// sleep();
+ //
+ System.out.println("** Before GC **");
+ getMemoryUsed();
+ w = null;
+ System.gc();
+ System.out.println("** After GC **");
+ getMemoryUsed();
+ System.gc();
+
+ System.out.println("** Final **");
+ long complete = System.currentTimeMillis();
+ System.out.println("Complete Time in ms = " + String.valueOf(complete-startTime));
+ long end = getMemoryUsed();
+ System.out.println("Memory increase in kB = End-Start=" + String.valueOf((end-start)/1024));
+ listThreads();
+ //
+ System.out.println("API Test");
+ System.out.println("64.72=" + MConversionRate.convert(ctx, new BigDecimal(100.0), 116, 100,0,0));
+ System.out.println("0.647169=" + MConversionRate.getRate(116, 100, null, 0,0,0));
+ System.out.println("12.5=" + MUOMConversion.convert(101, 102, new BigDecimal(100.0), true));
+
+ } // Base
+
+ /**
+ * Get Used Memory in bytes
+ * @return memory used
+ */
+ private static long getMemoryUsed()
+ {
+ long free = Runtime.getRuntime().freeMemory();
+ long total = Runtime.getRuntime().totalMemory();
+ long used = total - free;
+ //
+ System.out.println("Memory used in kB = Total("
+ + String.valueOf(total/1024) + ")-Free("
+ + String.valueOf(free/1024) + ") = " + String.valueOf(used/1024));
+ System.out.println("Active Threads=" + Thread.activeCount());
+ return used;
+ } // getMemoryUsed
+
+ /**
+ * Sleep for a second
+ */
+ private static void sleep()
+ {
+ System.out.println(".. sleeping-ini .. -> " + Thread.activeCount());
+ Thread.yield();
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (final InterruptedException ie)
+ {}
+ System.out.println(".. sleeping-end .. -> " + Thread.activeCount());
+ } // sleep
+
+ /**
+ * List Threads
+ */
+ private static void listThreads()
+ {
+ Thread[] list = new Thread[Thread.activeCount()];
+ // int no = Thread.currentThread().enumerate(list);
+ for (int i = 0; i < list.length; i++)
+ {
+ if (list[i] != null)
+ System.out.println("Thread " + i + " - " + list[i].toString());
+ }
+ } // listThreads
+
+ /**
+ * Start
+ * @param args ignored
+ */
+ public static void main(String[] args)
+ {
+ Base.test();
+ Env.exitEnv(0);
+ } // main
+} // Base
diff --git a/base/src/org/compiere/MigrateData.java b/base/src/org/compiere/MigrateData.java
new file mode 100644
index 0000000000..9f8f6a08e3
--- /dev/null
+++ b/base/src/org/compiere/MigrateData.java
@@ -0,0 +1,132 @@
+/******************************************************************************
+ * 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;
+
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+
+import org.compiere.util.*;
+import org.compiere.model.*;
+import org.compiere.print.*;
+
+/**
+ * Migrate Data
+ * @author Jorg Janke
+ * @version $Id: MigrateData.java,v 1.3 2006/07/30 00:51:06 jjanke Exp $
+ */
+public class MigrateData
+{
+ /**
+ * Migrate Data.
+ * Called from DB.afterMigration
+ */
+ public MigrateData ()
+ {
+ release252c();
+
+ // Update existing Print Format
+ PrintFormatUtil pfu = new PrintFormatUtil (Env.getCtx());
+ pfu.addMissingColumns();
+ } // MigrateData
+
+ /** Logger */
+ private static CLogger log = CLogger.getCLogger (MigrateData.class);
+
+ /**
+ * Release 252c
+ */
+ private void release252c()
+ {
+ String sql = "SELECT COUNT(*) FROM M_ProductDownload";
+ int no = DB.getSQLValue(null, sql);
+ if (no > 0)
+ {
+ log.finer("No Need - Downloads #" + no);
+ return;
+ }
+ //
+ int count = 0;
+ sql = "SELECT AD_Client_ID, AD_Org_ID, M_Product_ID, Name, DownloadURL "
+ + "FROM M_Product "
+ + "WHERE DownloadURL IS NOT NULL";
+ PreparedStatement pstmt = null;
+ try
+ {
+ pstmt = DB.prepareStatement (sql, null);
+ ResultSet rs = pstmt.executeQuery ();
+ while (rs.next ())
+ {
+ int AD_Client_ID = rs.getInt(1);
+ int AD_Org_ID = rs.getInt(2);
+ int M_Product_ID = rs.getInt(3);
+ String Name = rs.getString(4);
+ String DownloadURL = rs.getString(5);
+ //
+ Properties ctx = new Properties (Env.getCtx());
+ Env.setContext(ctx, "#AD_Client_ID", AD_Client_ID);
+ Env.setContext(ctx, "AD_Client_ID", AD_Client_ID);
+ Env.setContext(ctx, "#AD_Org_ID", AD_Org_ID);
+ Env.setContext(ctx, "AD_Org_ID", AD_Org_ID);
+ MProductDownload pdl = new MProductDownload(ctx, 0, null);
+ pdl.setM_Product_ID(M_Product_ID);
+ pdl.setName(Name);
+ pdl.setDownloadURL(DownloadURL);
+ if (pdl.save())
+ {
+ count++;
+ String sqlUpdate = "UPDATE M_Product SET DownloadURL = NULL WHERE M_Product_ID=" + M_Product_ID;
+ int updated = DB.executeUpdate(sqlUpdate, null);
+ if (updated != 1)
+ log.warning("Product not updated");
+ }
+ else
+ log.warning("Product Download not created M_Product_ID=" + M_Product_ID);
+ }
+ rs.close ();
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ log.log (Level.SEVERE, sql, e);
+ }
+ try
+ {
+ if (pstmt != null)
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ pstmt = null;
+ }
+ log.info("#" + count);
+ } // release252c
+
+
+ /**
+ * Migrate Data
+ * @param args ignored
+ */
+ public static void main (String[] args)
+ {
+ Adempiere.startup(true);
+ new MigrateData();
+ } // main
+
+} // MigrateData
diff --git a/base/src/org/compiere/cm/CStageValidate.java b/base/src/org/compiere/cm/CStageValidate.java
new file mode 100644
index 0000000000..2833fe1f75
--- /dev/null
+++ b/base/src/org/compiere/cm/CStageValidate.java
@@ -0,0 +1,63 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.util.logging.*;
+import org.compiere.model.*;
+import org.compiere.process.*;
+
+/**
+ * Validate Container Stage
+ *
+ * @author Jorg Janke
+ * @version $Id: CStageValidate.java,v 1.3 2006/07/30 00:51:06 jjanke Exp $
+ */
+public class CStageValidate extends SvrProcess
+{
+ private int p_CM_CStage_ID = 0;
+
+ /**
+ * Prepare - e.g., get Parameters.
+ */
+ protected void prepare()
+ {
+ ProcessInfoParameter[] para = getParameter();
+ for (int i = 0; i < para.length; i++)
+ {
+ String name = para[i].getParameterName();
+ if (para[i].getParameter() == null)
+ ;
+ else
+ log.log(Level.SEVERE, "Unknown Parameter: " + name);
+ }
+ p_CM_CStage_ID = getRecord_ID();
+ } // prepare
+
+ /**
+ * Process
+ * @return info
+ * @throws Exception
+ */
+ protected String doIt ()
+ throws Exception
+ {
+ log.info("CM_CStage_ID=" + p_CM_CStage_ID);
+ MCStage stage = new MCStage (getCtx(), p_CM_CStage_ID, get_TrxName());
+ return stage.validate();
+ } // doIt
+
+} // CStageValidate
diff --git a/base/src/org/compiere/cm/CacheHandler.java b/base/src/org/compiere/cm/CacheHandler.java
new file mode 100644
index 0000000000..cae8363375
--- /dev/null
+++ b/base/src/org/compiere/cm/CacheHandler.java
@@ -0,0 +1,192 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.*;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import org.compiere.util.*;
+import org.compiere.model.*;
+
+/**
+ * The CacheHandler handles deployment and clean of internal and external caches
+ *
+ * @author Yves Sandfort
+ * @version $Id$
+ */
+public class CacheHandler {
+ protected String[] cacheURLs;
+ protected CLogger log;
+
+ /**
+ * CacheHandler for single URL environment
+ * @param thisURL URL of this Server
+ * @param tLog thisLogger
+ * @param ctx Propertie Context
+ * @param trxName Transaction
+ */
+ public CacheHandler(String thisURL, CLogger tLog, Properties ctx, String trxName) {
+ int [] theseServers = X_CM_BroadcastServer.getAllIDs ("CM_BroadcastServer", "CM_WebProject_ID=0", trxName);
+ if (theseServers!=null && theseServers.length>0) {
+ String [] thisURLs = new String [theseServers.length];
+ for(int i=0;i=0) {
+ JNPURL = JNPURL.substring(JNPURL.indexOf("jnp://")+6);
+ }
+ if (JNPURL.indexOf(":")>=0) {
+ JNPURL = JNPURL.substring(0,JNPURL.indexOf(":"));
+ }
+ if (JNPURL.length()>0) {
+ return JNPURL;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/base/src/org/compiere/cm/CalloutTemplate.java b/base/src/org/compiere/cm/CalloutTemplate.java
new file mode 100644
index 0000000000..71670bf5a8
--- /dev/null
+++ b/base/src/org/compiere/cm/CalloutTemplate.java
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+import org.compiere.model.*;
+
+/**
+ * Template
+ *
+ * @author Yves Sandfort
+ * @version $Id$
+ */
+public class CalloutTemplate extends CalloutEngine
+{
+ /**
+ * Invoice Line - Charge.
+ * - updates PriceActual from Charge
+ * - sets PriceLimit, PriceList to zero
+ * Calles tax
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String invalidate (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ // Summary ?
+ if (mTab.getValue("IsSummary")!=null)
+ {
+ mTab.setValue("IsValid", false);
+ return "";
+ }
+ return "";
+ } // charge
+} // CalloutTemplate
diff --git a/base/src/org/compiere/cm/MediaDirectDeploy.java b/base/src/org/compiere/cm/MediaDirectDeploy.java
new file mode 100644
index 0000000000..c2642246f8
--- /dev/null
+++ b/base/src/org/compiere/cm/MediaDirectDeploy.java
@@ -0,0 +1,27 @@
+/******************************************************************************
+ * 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.
+ * You may reach us at: ComPiere, Inc. - http://www.adempiere.org/license.html
+ * 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA or info@adempiere.org
+ *****************************************************************************/
+package org.compiere.cm;
+
+
+/**
+ *
+ *
+ * @author Yves Sandfort
+ * @version $Id$
+ */
+public class MediaDirectDeploy
+{
+}
diff --git a/base/src/org/compiere/cm/StringUtil.java b/base/src/org/compiere/cm/StringUtil.java
new file mode 100644
index 0000000000..74978639e0
--- /dev/null
+++ b/base/src/org/compiere/cm/StringUtil.java
@@ -0,0 +1,307 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/*
+ * @author Yves Sandfort
+ * @version $Revision$
+ */
+
+/**
+ * StringUtil is a helper class to run different String managements not implemented in Java Core
+ *
+ * @author Yves Sandfort
+ * @version $id$
+ *
+ */
+public class StringUtil {
+ /**
+ * Replace all occurences of search with replace in original
+ * @param original the original String
+ * @param search the string to look for
+ * @param replace the string we will replace search with
+ * @return StringBuffer with result
+ */
+ public static StringBuffer replace(StringBuffer original, String search, String replace) {
+ return doReplace (original, search, replace, false, true);
+ }
+
+ /**
+ * Replace all occurences of search with replace in original
+ * @param original the original String
+ * @param search the string to look for
+ * @param replace the string we will replace search with
+ * @return String with result, null will get replaced by ""
+ */
+ public static String replace (String original, String search, String replace) {
+ if (original==null) original = "";
+ return doReplace (new StringBuffer(original), search, replace, false, true).toString();
+ }
+
+ /**
+ * Replace all occurences of search with replace in original
+ * @param original the original String
+ * @param search the string to look for
+ * @param replace the string we will replace search with
+ * @return String with result, null will get replaced by ""
+ */
+ public static String replace (String original, char search, String replace) {
+ if (original==null) original = "";
+ return doReplace (new StringBuffer(original), search, replace, true).toString();
+ }
+
+ /**
+ * Replace all or one occurence of search with replace in original
+ * @param original the original StringBuffer
+ * @param search String to get replaced
+ * @param replace String to replace
+ * @param ignoreCase should we ignore cases
+ * @param allOccurences should all Occurences get replaced
+ * @return StringBuffer with result
+ */
+ public static StringBuffer replace(StringBuffer original, String search, String replace, boolean ignoreCase, boolean allOccurences) {
+ return doReplace (original, search, replace, ignoreCase, allOccurences);
+ }
+
+ /**
+ * Replace all or one occurence of search with replace in original
+ * @param original the original StringBuffer
+ * @param search String to get replaced
+ * @param replace String to replace
+ * @param ignoreCase should we ignore cases
+ * @param allOccurences should all Occurences get replaced
+ * @return StringBuffer with result
+ */
+ public static String replace(String original, String search, String replace, boolean ignoreCase, boolean allOccurences) {
+ if (original==null) original="";
+ return replace(new StringBuffer(original), search, replace, ignoreCase, allOccurences).toString();
+ }
+
+ /**
+ * Replace one occurence of search with replace in original
+ * @param original StringBuffer
+ * @param search String to look for
+ * @param replace String to replace search with
+ * @return new StringBuffer with result
+ */
+ public static StringBuffer replaceOne(StringBuffer original, String search, String replace) {
+ if (original.toString().indexOf(search)>=0) {
+ original.replace(original.toString().indexOf(search),original.toString().indexOf(search)+search.length(),replace);
+ }
+ return original;
+ }
+
+ /**
+ * Replace one occurence of search with replace in original
+ * @param original String to look in
+ * @param search String to search for
+ * @param replace String to replace search with
+ * @return new String with result
+ */
+ public static String replaceOne(String original, String search, String replace) {
+ StringBuffer toriginal = new StringBuffer(original);
+ if (toriginal.toString().indexOf(search)>=0) {
+ toriginal.replace(toriginal.toString().indexOf(search),toriginal.toString().indexOf(search)+search.length(),replace);
+ }
+ return toriginal.toString();
+ }
+
+ /**
+ * Run RegEx Expression against original String
+ * @param original StringBuffer with original context
+ * @param regex Regular Expression to run as query
+ * @param replace Replace String
+ * @param CASE_INSENSITIVE whether we should take care of case or not
+ * @return StringBuffer with result
+ */
+ public static StringBuffer replaceRegex(StringBuffer original, String regex, String replace, boolean CASE_INSENSITIVE) {
+ int flags=0;
+ if (CASE_INSENSITIVE) flags=Pattern.CASE_INSENSITIVE;
+ Pattern p = Pattern.compile(regex, flags);
+ Matcher m = p.matcher(original);
+ StringBuffer newSB = new StringBuffer();
+ boolean result = m.find();
+ while(result) {
+ m.appendReplacement(newSB, replace);
+ result = m.find();
+ }
+ m.appendTail(newSB);
+ return newSB;
+ }
+
+ /**
+ * Run RegEx Expression against original String
+ * @param original StringBuffer with original context
+ * @param regex Regular Expression to run as query
+ * @param replace Replace String
+ * @param CASE_INSENSITIVE whether we should take care of case or not
+ * @return String with result
+ */
+ public static String replaceRegex(String original, String regex, String replace, boolean CASE_INSENSITIVE) {
+ return replaceRegex(new StringBuffer(original), regex, replace, CASE_INSENSITIVE).toString();
+ }
+
+ private static StringBuffer doReplace(StringBuffer original, String alt, String neu, boolean ignoreCase, boolean allOccurences) {
+ int position = -1;
+ if (alt==null) alt="";
+ if (neu==null) neu="";
+ if (original==null) original = new StringBuffer("");
+ int altNeuDiff = neu.length()-alt.length();
+ if (neu.lastIndexOf(alt)>=altNeuDiff) altNeuDiff = neu.lastIndexOf(alt)+1;
+ if (ignoreCase) {
+ position = original.toString().toLowerCase().indexOf(alt.toLowerCase());
+ while (position>=0) {
+ original.replace(position,position + alt.length(),neu);
+ position = original.toString().toLowerCase().indexOf(alt.toLowerCase(),position+altNeuDiff);
+ }
+ } else {
+ position = original.toString().indexOf(alt);
+ while (position>=0) {
+ original.replace(position,position + alt.length(),neu);
+ position = original.toString().indexOf(alt,position+altNeuDiff);
+ }
+ }
+ return original;
+ }
+
+ private static StringBuffer doReplace(StringBuffer original, char alt, String neu, boolean allOccurences) {
+ int position = -1;
+ if (original==null) original = new StringBuffer("");
+ int altNeuDiff = neu.length()-1;
+ if (neu.lastIndexOf(alt)>=altNeuDiff) altNeuDiff = neu.lastIndexOf(alt)+1;
+ position = original.toString().indexOf(alt);
+ while (position>=0) {
+ original.replace(position,position + 1,neu);
+ position = original.toString().indexOf(alt,position+altNeuDiff);
+ }
+ return original;
+ }
+
+ /**
+ * This function will split a string based on a split character.
+ * @param searchIn The string to split
+ * @param splitter The separator
+ * @return String array of split values
+ */
+ public static String[] split(String searchIn, String splitter) {
+ String[] results = new String[count(searchIn,splitter)+1];
+ int position=0;
+ int i=0;
+ while (searchIn.indexOf(splitter,position)>=0) {
+ results[i]=searchIn.substring(position,searchIn.indexOf(splitter,position+2));
+ position = searchIn.indexOf(splitter,position)+1;
+ i++;
+ }
+ results[(results.length-1)]=searchIn.substring(position);
+ return results;
+ }
+
+ /**
+ * Remove String toBeRemoved from oroginal
+ * @param original String to look in
+ * @param toBeRemoved String to get removed
+ * @param ignoreCase should we take care of case
+ * @return String without toBeRemoved
+ */
+ public static String remove(String original, String toBeRemoved, boolean ignoreCase) {
+ String thisResult = null;
+ if (!toBeRemoved.equals("") && toBeRemoved!=null) {
+ thisResult = replace(original, toBeRemoved, "", ignoreCase, true);
+ }
+ return thisResult;
+ }
+
+ /**
+ * To split for indexes we will look for the next Word in tempstr
+ * @param tempStr to look into
+ * @return nextWord in String
+ */
+ public static String getNextWord(String tempStr) {
+ String word = "";
+ if (tempStr.indexOf(" ")>=0) {
+ word=tempStr.substring(0,tempStr.indexOf(" "));
+ } else {
+ word=tempStr;
+ }
+ return word;
+ }
+
+ /**
+ * For some save scnearios and analysis we should remove special characters, i.e. HTML
+ * @param tempStr to remove Special Char
+ * @return new String without special chars
+ */
+ public static String removeSpecialChar(String tempStr) {
+ if (tempStr!=null) {
+ tempStr=replace(tempStr,",","", true, true);
+ tempStr=replace(tempStr,".","", true, true);
+ tempStr=replace(tempStr,"!","", true, true);
+ tempStr=replace(tempStr,"?","", true, true);
+ tempStr=replace(tempStr,"'","", true, true);
+ tempStr=replace(tempStr,":","", true, true);
+ tempStr=replace(tempStr,"(","", true, true);
+ tempStr=replace(tempStr,")","", true, true);
+ tempStr=replace(tempStr,"+","", true, true);
+ tempStr=replace(tempStr,"-","", true, true);
+ tempStr=replace(tempStr,">","", true, true);
+ tempStr=replace(tempStr,"<","", true, true);
+ tempStr=replace(tempStr,"/","", true, true);
+ while (tempStr.indexOf(" ")>0) {
+ tempStr=replace(tempStr," "," ", true, true);
+ }
+ tempStr=replace(tempStr," "," ", true, true);
+ }
+ return tempStr;
+ }
+
+ /**
+ * Should return you the number of occurences of "find" in "orig
+ * @param orig The String to look in
+ * @param find The String to look for
+ * @return Number of occurences, 0 if none
+ */
+
+ public static int count(String orig, String find) {
+ int retVal = 0;
+ int pos = 0;
+ while (orig.indexOf(find,pos)>0) {
+ pos = orig.indexOf(find,pos)+1;
+ retVal++;
+ }
+ return retVal;
+ }
+
+ /**
+ * Gnerate CRC String for tempStr
+ * @param tempStr
+ * @return CRC Code for tempStr
+ * @throws IOException
+ */
+ public static String crc(String tempStr) throws IOException {
+ java.util.zip.Adler32 inChecker = new java.util.zip.Adler32();
+ java.util.zip.CheckedInputStream in = null;
+ in = new java.util.zip.CheckedInputStream(new java.io.ByteArrayInputStream(tempStr.getBytes()), inChecker);
+ @SuppressWarnings("unused") int c;
+ while ((c = in.read()) != -1) c=0;
+ String myCheckSum = "" + inChecker.getValue();
+ return myCheckSum;
+ }
+}
diff --git a/base/src/org/compiere/cm/TemplateValidate.java b/base/src/org/compiere/cm/TemplateValidate.java
new file mode 100644
index 0000000000..61ccfca5f9
--- /dev/null
+++ b/base/src/org/compiere/cm/TemplateValidate.java
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.util.logging.Level;
+import org.compiere.process.*;
+import org.compiere.model.*;
+
+/**
+ * CM Template Validation Process
+ *
+ * @author Jorg Janke
+ * @version $Id: TemplateValidate.java,v 1.3 2006/08/08 13:29:49 comdivision Exp $
+ */
+public class TemplateValidate extends SvrProcess
+{
+ @Override
+ protected void prepare ()
+ {
+ 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("CM_WebProject_ID"))
+ //p_CM_WebProject_ID = ((BigDecimal)para[i].getParameter()).intValue();
+ else
+ log.log(Level.SEVERE, "Unknown Parameter: " + name);
+ }
+ } // prepare
+
+ @Override
+ protected String doIt ()
+ throws Exception
+ {
+ MTemplate thisTemplate = new MTemplate(getCtx (), getRecord_ID (), get_TrxName ());
+ thisTemplate.setIsValid (true);
+ thisTemplate.save ();
+ return null;
+ }
+
+} // TemplateValidate
diff --git a/base/src/org/compiere/cm/WebProjectDeploy.java b/base/src/org/compiere/cm/WebProjectDeploy.java
new file mode 100644
index 0000000000..1be0160bd9
--- /dev/null
+++ b/base/src/org/compiere/cm/WebProjectDeploy.java
@@ -0,0 +1,185 @@
+/******************************************************************************
+ * 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.cm;
+
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.model.*;
+import org.compiere.process.*;
+import org.compiere.util.*;
+
+/**
+ * Deploy Web Project
+ *
+ * @author Jorg Janke
+ * @version $Id: WebProjectDeploy.java,v 1.10 2006/09/04 21:21:31 comdivision Exp $
+ */
+public class WebProjectDeploy extends SvrProcess
+{
+ /** WebProject */
+ private int p_CM_WebProject_ID = 0;
+
+ /** Project */
+ private MWebProject m_project = null;
+ /** Stage Hash Map */
+ private HashMap m_map = new HashMap();
+ /** List of IDs */
+ private ArrayList m_idList = new ArrayList();
+
+
+ /**
+ * Prepare - e.g., get Parameters.
+ */
+ protected void prepare()
+ {
+ 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("CM_WebProject_ID"))
+ p_CM_WebProject_ID = para[i].getParameterAsInt();
+ else
+ log.log(Level.SEVERE, "Unknown Parameter: " + name);
+ }
+ } // prepare
+
+ /**
+ * Process
+ * @return info
+ * @throws Exception
+ */
+ protected String doIt ()
+ throws Exception
+ {
+ org.compiere.cm.CacheHandler thisHandler = new org.compiere.cm.CacheHandler(org.compiere.cm.CacheHandler.convertJNPURLToCacheURL(getCtx().getProperty("java.naming.provider.url")), log, getCtx(), get_TrxName());
+
+ log.info("CM_WebProject_ID=" + p_CM_WebProject_ID);
+ m_project = new MWebProject(getCtx(), p_CM_WebProject_ID, get_TrxName());
+ if (m_project.get_ID() != p_CM_WebProject_ID)
+ throw new AdempiereUserError("@NotFound@ @CM_WebProject_ID@ " + p_CM_WebProject_ID);
+
+ // Deploy Media
+ MMedia[] media = MMedia.getMedia(m_project);
+ MMediaServer[] mserver = MMediaServer.getMediaServer(m_project);
+ for (int i = 0; i < mserver.length; i++)
+ mserver[i].deploy(media);
+
+ // Stage
+ MCStage[] stages = MCStage.getStages(m_project);
+ for (int i = 0; i < stages.length; i++)
+ m_map.put(new Integer(stages[i].getCM_CStage_ID()), stages[i]);
+
+ // Copy Stage Tree
+ MTree treeS = new MTree (getCtx(), m_project.getAD_TreeCMS_ID(), false, false, get_TrxName());
+ MTreeNode root = treeS.getRoot();
+ copyStage(root, "/");
+
+ // Delete Inactive Containers
+ MContainer[] containers = MContainer.getContainers(m_project);
+ for (int i = 0; i < containers.length; i++)
+ {
+ MContainer container = containers[i];
+ if (!m_idList.contains(new Integer(container.getCM_Container_ID())))
+ {
+ String name = container.getName();
+ if (container.delete(true))
+ log.fine("Deleted: " + name);
+ else // e.g. was referenced
+ {
+ log.warning("Failed Delete: " + name);
+ addLog(0,null,null, "@Error@ @Delete@: " + name);
+ }
+ }
+ // Remove Container from cache
+ thisHandler.cleanContainer(container.get_ID());
+ } // Delete Inactive
+
+ // Sync Stage & Container Tree
+ MTree_NodeCMS nodesCMS[] = MTree_NodeCMS.getTree(getCtx(), m_project.getAD_TreeCMS_ID(), get_TrxName());
+ MTree_NodeCMC nodesCMC[] = MTree_NodeCMC.getTree(getCtx(), m_project.getAD_TreeCMC_ID(), get_TrxName());
+ for (int s = 0; s < nodesCMS.length; s++)
+ {
+ MTree_NodeCMS nodeCMS = nodesCMS[s];
+ int Node_ID = nodeCMS.getNode_ID();
+ for (int c = 0; c < nodesCMC.length; c++)
+ {
+ MTree_NodeCMC nodeCMC = nodesCMC[c];
+ if (nodeCMC.getNode_ID() == Node_ID)
+ {
+ //if (nodeCMS.getParent_ID()!=0)
+ nodeCMC.setParent_ID(nodeCMS.getParent_ID());
+ nodeCMC.setSeqNo(nodeCMS.getSeqNo());
+ nodeCMC.save();
+ break;
+ }
+ }
+ } // for all stage nodes
+ // Clean ContainerTree Cache
+ thisHandler.cleanContainerTree (p_CM_WebProject_ID);
+
+ return "@Copied@ @CM_Container_ID@ #" + m_idList.size();
+ } // doIt
+
+
+ /**
+ * Copy Stage
+ * @param node node
+ * @param path path
+ */
+ private void copyStage (MTreeNode node, String path)
+ {
+ org.compiere.cm.CacheHandler thisHandler = new org.compiere.cm.CacheHandler(org.compiere.cm.CacheHandler.convertJNPURLToCacheURL(getCtx().getProperty("java.naming.provider.url")), log, getCtx(), get_TrxName());
+ Integer ID = new Integer(node.getNode_ID());
+ MCStage stage = m_map.get(ID);
+ //
+ int size = node.getChildCount();
+ for (int i = 0; i < size; i++)
+ {
+ MTreeNode child = (MTreeNode)node.getChildAt(i);
+ ID = new Integer(child.getNode_ID());
+ stage = m_map.get(ID);
+ if (stage == null)
+ {
+ log.warning("Not Found ID=" + ID);
+ continue;
+ }
+ if (!stage.isActive())
+ continue;
+ //
+ if (stage != null && stage.isModified())
+ {
+ MContainer cc = MContainer.copy (m_project, stage, path);
+ if (cc != null)
+ {
+ addLog (0, null, null, "@Copied@: " + cc.getName());
+ m_idList.add(ID);
+ }
+ // Remove Container from cache
+ thisHandler.cleanContainer(cc.get_ID());
+ // Reset Modified flag...
+ stage.setIsModified(false);
+ stage.save(stage.get_TrxName());
+ }
+ if (child.isSummary())
+ copyStage (child, path + stage.getRelativeURL() + "/");
+
+ }
+ } // copyStage
+
+} // WebProjectDeploy
diff --git a/base/src/org/compiere/impexp/BankStatementLoaderInterface.java b/base/src/org/compiere/impexp/BankStatementLoaderInterface.java
new file mode 100644
index 0000000000..8afff1ac24
--- /dev/null
+++ b/base/src/org/compiere/impexp/BankStatementLoaderInterface.java
@@ -0,0 +1,265 @@
+/******************************************************************************
+ * 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.impexp;
+
+import org.compiere.model.*;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+
+
+/**
+ * Interface to be implemented by bank statement loader classes
+ *
+ * Bank statement loader classes that extend this interface can be loaded
+ * by the MBankStatementLoader controller class.
+ * The usage patter looks like this:
+ *
+ * -init() is called in order to initialize the loader
+ *
+ * -validate() is called, allowing the loader to perform data validation if
+ * it provides this.
+ *
+ * -loadLines() is called, request the loader to start loading statement lines
+ *
+ * -for everu statement line that the loader encounteres, it calls the
+ * saveLine() method of the MBankStatement controller object it obtained
+ * as part of the call to init()
+ *
+ * -The MBankStatementLoader controller object can now obtain the data for the current bank
+ * statement line by using the corresponding get methods of the loader class.
+ *
+ * @author Maarten Klinker, Eldir Tomassen
+ * @version $Id: BankStatementLoaderInterface.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+
+public interface BankStatementLoaderInterface
+{
+ /**
+ * Initialize the loader
+ * @param controller Reference to the MBankStatementLoader controller object
+ * @return Initialized succesfully
+ */
+ public boolean init(MBankStatementLoader controller);
+
+ /**
+ * Verify whether the data to be imported is valid
+ * @return Data is valid
+ * If the actual loaders does not do any validity checks
+ * it will just return true.
+ */
+ public boolean isValid();
+
+ /**
+ * Start importing statement lines
+ * @return Statement lines imported succesfully
+ */
+ public boolean loadLines();
+
+ /**
+ * Return the most recent error
+ * @return Error message
+ * This error message will be handled as a Adempiere message,
+ * (e.g. it can be translated)
+ */
+ public String getLastErrorMessage();
+
+ /**
+ * Return the most recent error description
+ * @return Error discription
+ * This is an additional error description, it can be used to provided
+ * descriptive iformation, such as a file name or SQL error, that can not
+ * be translated by the Adempiere message system.
+ */
+ public String getLastErrorDescription();
+
+ /**
+ * The last time this loader aquired bank statement data.
+ * For OFX this is the value. This is generally only available\
+ * after loadLines() has been called. If a specific loader class
+ * does not provided this information it is allowed to return null
+ * @return Date last run
+ */
+ public Timestamp getDateLastRun();
+
+ /**
+ * The routing number of the bank account for the statement line.
+ * @return Routing number
+ */
+ public String getRoutingNo();
+
+ /**
+ * The account number of the bank account for the statement line.
+ * @return Bank account number
+ */
+ public String getBankAccountNo();
+
+ /**
+ * Additional reference information
+ * Statement level reference information. If a specific loader class
+ * does not provided this, it is allowed to return null.
+ * @return Error discription
+ */
+ public String getStatementReference();
+
+ /**
+ * Statement Date
+ * Date of the bank statement. If a specific loader does not provide this,
+ * it is allowed to return null.
+ * @return Statement Date
+ */
+ public Timestamp getStatementDate();
+
+ /**
+ * Transaction ID assigned by the bank.
+ * For OFX this is the
+ * If a specific loader does not provide this, it is allowed to return
+ * null.
+ * @return Transaction ID
+ */
+ public String getTrxID();
+
+ /**
+ * Additional reference information
+ * Statement line level reference information.
+ * For OFX this is the field.
+ * If a specific loader does not provided this, it is allowed to return null.
+ * @return Error discription
+ */
+ public String getReference();
+
+ /**
+ * Check number
+ * Check number, in case the transaction was initiated by a check.
+ * For OFX this is the field, for MS-Money (OFC) this is the
+ * field.
+ * If a specific loader does not provide this, it is allowed to return null.
+ * @return Transaction reference
+ */
+ public String getCheckNo();
+
+ /**
+ * Payee name
+ * Name information, for OFX this is the or
+ * field
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ * @return Payee name
+ */
+ public String getPayeeName();
+
+ /**
+ * Payee account
+ * Account information of "the other party"
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ * @return Payee bank account number
+ */
+ public String getPayeeAccountNo();
+
+ /**
+ * Statement line date
+ * This has to be provided by all loader classes.
+ * @return Statement line date
+ */
+ public Timestamp getStatementLineDate();
+
+ /**
+ * Effective date
+ * Date theat the funds became available.
+ * If a specific loader does not provide this, it is allowed to return null.
+ * @return Effective date
+ */
+ public Timestamp getValutaDate();
+
+ /**
+ * Transaction type
+ * @return Transaction type
+ * This returns the transaction type as used by the bank
+ * Whether a transaction is credit or debit depends on the amount (i.e. negative),
+ * this field is for reference only.
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ */
+ public String getTrxType();
+
+ /**
+ * Indicates whether this transaction is a reversal
+ * @return true if this is a reversal
+ */
+ public boolean getIsReversal();
+
+ /**
+ * Currency
+ * @return Currency
+ * Return the currency, if included in the statement data.
+ * It is returned as it appears in the import data, it should
+ * not be processed by the loader in any way.
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ */
+ public String getCurrency();
+
+ /**
+ * Statement line amount
+ * @return Statement Line Amount
+ * This has to be provided by all loader classes.
+ */
+ public BigDecimal getStmtAmt();
+
+ /**
+ * Transaction Amount
+ * @return Transaction Amount
+ */
+ public BigDecimal getTrxAmt();
+
+ /**
+ * Interest Amount
+ * @return Interest Amount
+ */
+ public BigDecimal getInterestAmt();
+
+ /**
+ * Transaction memo
+ * @return Memo
+ * Additional descriptive information.
+ * For OFX this is the filed, for SWIFT MT940
+ * this is the "86" line.
+ * If a specific loader does not provide this, it is allowed to return null.
+ */
+ public String getMemo();
+
+ /**
+ * Charge name
+ * @return Charge name
+ * Name of the charge, in case this transaction is a bank charge.
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ */
+ public String getChargeName();
+
+ /**
+ * Charge amount
+ * @return Charge amount
+ * Name of the charge, in case this transaction is a bank charge.
+ * If a specific loader class does not provide this, it is allowed
+ * to return null.
+ */
+ public BigDecimal getChargeAmt();
+
+} //BankStatementLoaderInterface
+
diff --git a/base/src/org/compiere/impexp/BankStatementMatchInfo.java b/base/src/org/compiere/impexp/BankStatementMatchInfo.java
new file mode 100644
index 0000000000..47917e0511
--- /dev/null
+++ b/base/src/org/compiere/impexp/BankStatementMatchInfo.java
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * 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.impexp;
+
+/**
+ * Bank Statement Match Information.
+ * Returned by Bank Statement Matcher
+ *
+ * @author Jorg Janke
+ * @version $Id: BankStatementMatchInfo.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class BankStatementMatchInfo
+{
+ /**
+ * Standard Constructor
+ */
+ public BankStatementMatchInfo()
+ {
+ super();
+ } // BankStatementMatchInfo
+
+
+ private int m_C_BPartner_ID = 0;
+ private int m_C_Payment_ID = 0;
+ private int m_C_Invoice_ID = 0;
+
+
+ /**
+ * Do we have a match?
+ * @return true if something could be matched
+ */
+ public boolean isMatched()
+ {
+ return m_C_BPartner_ID > 0 || m_C_Payment_ID > 0 || m_C_Invoice_ID > 0;
+ } // isValid
+
+
+ /**
+ * Get matched BPartner
+ * @return BPartner
+ */
+ public int getC_BPartner_ID()
+ {
+ return m_C_BPartner_ID;
+ }
+ /**
+ * Set matched BPartner
+ * @param C_BPartner_ID BPartner
+ */
+ public void setC_BPartner_ID (int C_BPartner_ID)
+ {
+ m_C_BPartner_ID = C_BPartner_ID;
+ }
+
+ /**
+ * Get matched Payment
+ * @return Payment
+ */
+ public int getC_Payment_ID()
+ {
+ return m_C_Payment_ID;
+ }
+ /**
+ * Set matched Payment
+ * @param C_Payment_ID payment
+ */
+ public void setC_Payment_ID (int C_Payment_ID)
+ {
+ m_C_Payment_ID = C_Payment_ID;
+ }
+
+ /**
+ * Get matched Invoice
+ * @return invoice
+ */
+ public int getC_Invoice_ID()
+ {
+ return m_C_Invoice_ID;
+ }
+ /**
+ * Set matched Invoice
+ * @param C_Invoice_ID invoice
+ */
+ public void setC_Invoice_ID (int C_Invoice_ID)
+ {
+ m_C_Invoice_ID = C_Invoice_ID;
+ }
+
+} // BankStatementMatchInfo
diff --git a/base/src/org/compiere/impexp/BankStatementMatcherInterface.java b/base/src/org/compiere/impexp/BankStatementMatcherInterface.java
new file mode 100644
index 0000000000..a29b1884a5
--- /dev/null
+++ b/base/src/org/compiere/impexp/BankStatementMatcherInterface.java
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * 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.impexp;
+
+import org.compiere.model.*;
+
+/**
+ * Bank Statement Matcher Algorithm Interface
+ *
+ * @author Jorg Janke
+ * @version $Id: BankStatementMatcherInterface.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public interface BankStatementMatcherInterface
+{
+ /**
+ * Match Bank Statement Line
+ * @param bsl bank statement line
+ * @return found matches or null
+ */
+ public BankStatementMatchInfo findMatch (MBankStatementLine bsl);
+
+
+ /**
+ * Match Bank Statement Import Line
+ * @param ibs bank statement import line
+ * @return found matches or null
+ */
+ public BankStatementMatchInfo findMatch (X_I_BankStatement ibs);
+
+
+} // BankStatementMatcherInterface
diff --git a/base/src/org/compiere/impexp/CopyImportFormat.java b/base/src/org/compiere/impexp/CopyImportFormat.java
new file mode 100644
index 0000000000..9559cc217a
--- /dev/null
+++ b/base/src/org/compiere/impexp/CopyImportFormat.java
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.math.*;
+import java.util.logging.*;
+import org.compiere.process.*;
+
+
+/**
+ * Copy Import Format (lines)
+ *
+ * @author Jorg Janke
+ * @version $Id: CopyImportFormat.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CopyImportFormat extends SvrProcess
+{
+ private int from_AD_ImpFormat_ID = 0;
+ private int to_AD_ImpFormat_ID = 0;
+
+ /**
+ * Prepare - e.g., get Parameters.
+ */
+ protected void prepare()
+ {
+ 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("AD_ImpFormat_ID"))
+ from_AD_ImpFormat_ID = ((BigDecimal)para[i].getParameter()).intValue();
+ else
+ log.log(Level.SEVERE, "prepare - Unknown Parameter: " + name);
+ }
+ to_AD_ImpFormat_ID = getRecord_ID();
+ } // prepare
+
+
+ /**
+ * Process Copy
+ * @return info
+ * @throws Exception
+ */
+ protected String doIt () throws Exception
+ {
+ log.info("doIt = From=" + from_AD_ImpFormat_ID + " To=" + to_AD_ImpFormat_ID);
+ MImpFormat from = new MImpFormat (getCtx(), from_AD_ImpFormat_ID, get_TrxName());
+ if (from.getAD_ImpFormat_ID() != from_AD_ImpFormat_ID)
+ throw new Exception ("From Format not found - " + from_AD_ImpFormat_ID);
+ //
+ MImpFormat to = new MImpFormat (getCtx(), to_AD_ImpFormat_ID, get_TrxName());
+ if (to.getAD_ImpFormat_ID() != to_AD_ImpFormat_ID)
+ throw new Exception ("To Format not found - " + from_AD_ImpFormat_ID);
+ //
+ if (from.getAD_Table_ID() != to.getAD_Table_ID())
+ throw new Exception ("From-To do Not have same Format Table");
+ //
+ MImpFormatRow[] rows = from.getRows(); // incl. inactive
+ for (int i = 0; i < rows.length; i++)
+ {
+ MImpFormatRow row = rows[i];
+ MImpFormatRow copy = new MImpFormatRow (to, row);
+ if (!copy.save())
+ throw new Exception ("Copy error");
+ }
+
+ String msg = "#" + rows.length;
+ if (!from.getFormatType().equals(to.getFormatType()))
+ return msg + " - Note: Format Type different!";
+ return msg;
+ } // doIt
+
+} // CopyImportFormat
diff --git a/base/src/org/compiere/impexp/ImpFormat.java b/base/src/org/compiere/impexp/ImpFormat.java
new file mode 100644
index 0000000000..4f0157f4b0
--- /dev/null
+++ b/base/src/org/compiere/impexp/ImpFormat.java
@@ -0,0 +1,600 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.model.*;
+import org.compiere.util.*;
+
+/**
+ * Import Format a Row
+ *
+ * @author Jorg Janke
+ * @version $Id: ImpFormat.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public final class ImpFormat
+{
+ /**
+ * Format
+ * @param name name
+ * @param AD_Table_ID table
+ * @param formatType format type
+ */
+ public ImpFormat (String name, int AD_Table_ID, String formatType)
+ {
+ setName(name);
+ setTable(AD_Table_ID);
+ setFormatType(formatType);
+ } // ImpFormat
+
+ /** Logger */
+ private static CLogger log = CLogger.getCLogger(ImpFormat.class);
+
+ private String m_name;
+ private String m_formatType;
+
+ /** The Table to be imported */
+ private int m_AD_Table_ID;
+ private String m_tableName;
+ private String m_tablePK;
+ private String m_tableUnique1;
+ private String m_tableUnique2;
+ private String m_tableUniqueParent;
+ private String m_tableUniqueChild;
+ //
+ private String m_BPartner;
+ private ArrayList m_rows = new ArrayList();
+
+ /**
+ * Set Name
+ * @param newName new name
+ */
+ public void setName(String newName)
+ {
+ if (newName == null || newName.length() == 0)
+ throw new IllegalArgumentException("Name must be at least 1 char");
+ else
+ m_name = newName;
+ }
+
+ /**
+ * Get Name
+ * @return name
+ */
+ public String getName()
+ {
+ return m_name;
+ } // getName
+
+ /**
+ * Import Table
+ * @param AD_Table_ID table
+ */
+ public void setTable (int AD_Table_ID)
+ {
+ m_AD_Table_ID = AD_Table_ID;
+ m_tableName = null;
+ m_tablePK = null;
+ String sql = "SELECT t.TableName,c.ColumnName "
+ + "FROM AD_Table t INNER JOIN AD_Column c ON (t.AD_Table_ID=c.AD_Table_ID AND c.IsKey='Y') "
+ + "WHERE t.AD_Table_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, AD_Table_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ m_tableName = rs.getString(1);
+ m_tablePK = rs.getString(2);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "ImpFormat.setTable", e);
+ }
+ if (m_tableName == null || m_tablePK == null)
+ log.log(Level.SEVERE, "Data not found for AD_Table_ID=" + AD_Table_ID);
+
+ // Set Additional Table Info
+ m_tableUnique1 = "";
+ m_tableUnique2 = "";
+ m_tableUniqueParent = "";
+ m_tableUniqueChild = "";
+
+ if (m_AD_Table_ID == 311) // I_061_SyncItem
+ {
+ m_tableUnique1 = "H_UPC"; // UPC = unique
+ m_tableUnique2 = "Value";
+ m_tableUniqueChild = "H_Commodity1"; // Vendor No may not be unique !
+ m_tableUniqueParent = "H_PartnrID"; // Makes it unique
+ }
+ else if (m_AD_Table_ID == 532) // I_Product
+ {
+ m_tableUnique1 = "UPC"; // UPC = unique
+ m_tableUnique2 = "Value";
+ m_tableUniqueChild = "VendorProductNo"; // Vendor No may not be unique !
+ m_tableUniqueParent = "BPartner_Value"; // Makes it unique
+ }
+ else if (m_AD_Table_ID == 533) // I_BPartner
+ {
+ m_tableUnique1 = "Value"; // the key
+ }
+ else if (m_AD_Table_ID == 534) // I_ElementValue
+ {
+ m_tableUniqueParent = "ElementName"; // the parent key
+ m_tableUniqueChild = "Value"; // the key
+ }
+ else if (m_AD_Table_ID == 535) // I_ReportLine
+ {
+ m_tableUniqueParent = "ReportLineSetName"; // the parent key
+ m_tableUniqueChild = "Name"; // the key
+ }
+ } // setTable
+
+ /**
+ * Get Import Table Name
+ * @return AD_Table_ID
+ */
+ public int getAD_Table_ID()
+ {
+ return m_AD_Table_ID;
+ } // getAD_Table_ID
+
+ /** Format Type - Fixed Length F */
+ public static final String FORMATTYPE_FIXED = "F";
+ /** Format Type - Comma Separated C */
+ public static final String FORMATTYPE_COMMA = "C";
+ /** Format Type - Tab Separated T */
+ public static final String FORMATTYPE_TAB = "T";
+ /** Format Type - XML X */
+ public static final String FORMATTYPE_XML = "X";
+
+ /**
+ * Set Format Type
+ * @param newFormatType - F/C/T/X
+ */
+ public void setFormatType(String newFormatType)
+ {
+ if (newFormatType.equals(FORMATTYPE_FIXED) || newFormatType.equals(FORMATTYPE_COMMA)
+ || newFormatType.equals(FORMATTYPE_TAB) || newFormatType.equals(FORMATTYPE_XML))
+ m_formatType = newFormatType;
+ else
+ throw new IllegalArgumentException("FormatType must be F/C/T/X");
+ } // setFormatType
+
+ /**
+ * Set Format Type
+ * @return format type - F/C/T/X
+ */
+ public String getFormatType()
+ {
+ return m_formatType;
+ } // getFormatType
+
+ /**
+ * Set Business Partner
+ * @param newBPartner (value)
+ */
+ public void setBPartner(String newBPartner)
+ {
+ m_BPartner = newBPartner;
+ } // setBPartner
+
+ /**
+ * Get Business Partner
+ * @return BPartner (value)
+ */
+ public String getBPartner()
+ {
+ return m_BPartner;
+ } // getVPartner
+
+ /*************************************************************************
+ * Add Format Row
+ * @param row row
+ */
+ public void addRow (ImpFormatRow row)
+ {
+ m_rows.add (row);
+ } // addRow
+
+ /**
+ * Get Row
+ * @param index index
+ * @return Import Format Row
+ */
+ public ImpFormatRow getRow (int index)
+ {
+ if (index >=0 && index < m_rows.size())
+ return (ImpFormatRow)m_rows.get(index);
+ return null;
+ } // getRow
+
+ /**
+ * Get Row Count
+ * @return row count
+ */
+ public int getRowCount()
+ {
+ return m_rows.size();
+ } // getRowCount
+
+ /*************************************************************************
+ * Factory load
+ * @param name name
+ * @return Import Format
+ */
+ public static ImpFormat load (String name)
+ {
+ log.config(name);
+ ImpFormat retValue = null;
+ String sql = "SELECT * FROM AD_ImpFormat WHERE Name=?";
+ int ID = 0;
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setString (1, name);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ retValue = new ImpFormat (name, rs.getInt("AD_Table_ID"), rs.getString("FormatType"));
+ ID = rs.getInt ("AD_ImpFormat_ID");
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return null;
+ }
+ loadRows (retValue, ID);
+ return retValue;
+ } // getFormat
+
+ /**
+ * Load Format Rows with ID
+ * @param format format
+ * @param ID id
+ */
+ private static void loadRows (ImpFormat format, int ID)
+ {
+ String sql = "SELECT f.SeqNo,c.ColumnName,f.StartNo,f.EndNo,f.DataType,c.FieldLength," // 1..6
+ + "f.DataFormat,f.DecimalPoint,f.DivideBy100,f.ConstantValue,f.Callout " // 7..11
+ + "FROM AD_ImpFormat_Row f,AD_Column c "
+ + "WHERE f.AD_ImpFormat_ID=? AND f.AD_Column_ID=c.AD_Column_ID AND f.IsActive='Y'"
+ + "ORDER BY f.SeqNo";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt (1, ID);
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next())
+ {
+ ImpFormatRow row = new ImpFormatRow (rs.getInt(1),
+ rs.getString(2), rs.getInt(3), rs.getInt(4), rs.getString(5), rs.getInt(6));
+ //
+ row.setFormatInfo(rs.getString(7), rs.getString(8),
+ rs.getString(9).equals("Y"),
+ rs.getString(10), rs.getString(11));
+ //
+ format.addRow (row);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ } // loadLines
+
+ /*************************************************************************
+ * Parse Line returns ArrayList of values
+ *
+ * @param line line
+ * @param withLabel true if with label
+ * @param trace create trace info
+ * @param ignoreEmpty - ignore empty fields
+ * @return Array of values
+ */
+ public String[] parseLine (String line, boolean withLabel, boolean trace, boolean ignoreEmpty)
+ {
+ if (trace)
+ log.config("" + line);
+
+ ArrayList list = new ArrayList();
+ // for all columns
+ for (int i = 0; i < m_rows.size(); i++)
+ {
+ ImpFormatRow row = (ImpFormatRow)m_rows.get(i);
+ StringBuffer entry = new StringBuffer ();
+ // Label-Start
+ if (withLabel)
+ {
+ entry.append(row.getColumnName());
+ entry.append("=");
+ if (row.isString())
+ entry.append("'");
+ else if (row.isDate())
+ entry.append("TO_DATE('");
+ }
+
+ // Get Data
+ String info = null;
+ if (row.isConstant())
+ info = "Constant";
+ else if (m_formatType.equals(FORMATTYPE_FIXED))
+ {
+ // check length
+ if (row.getStartNo() > 0 && row.getEndNo() <= line.length())
+ info = line.substring(row.getStartNo()-1, row.getEndNo());
+ }
+ else
+ {
+ info = parseFlexFormat (line, m_formatType, row.getStartNo());
+ }
+
+ if (info == null)
+ info = "";
+
+ // Interpret Data
+ entry.append(row.parse(info));
+
+ // Label-End
+ if (withLabel)
+ {
+ if (row.isString())
+ entry.append("'");
+ else if (row.isDate())
+ entry.append("','YYYY-MM-DD HH24:MI:SS')"); // JDBC Timestamp format w/o miliseconds
+ }
+
+ if (!ignoreEmpty || (ignoreEmpty && info.length() != 0))
+ list.add(entry.toString());
+ //
+ if (trace)
+ log.fine(info + "=>" + entry.toString() + " (Length=" + info.length() + ")");
+ } // for all columns
+
+ String[] retValue = new String[list.size()];
+ list.toArray(retValue);
+ return retValue;
+ } // parseLine
+
+ /**
+ * Parse flexible line format.
+ * A bit inefficient as it always starts from the start
+ *
+ * @param line the line to be parsed
+ * @param formatType Comma or Tab
+ * @param fieldNo number of field to be returned
+ * @return field in lime or ""
+ @throws IllegalArgumentException if format unknows
+ * */
+ private String parseFlexFormat (String line, String formatType, int fieldNo)
+ {
+ final char QUOTE = '"';
+ // check input
+ char delimiter = ' ';
+ if (formatType.equals(FORMATTYPE_COMMA))
+ delimiter = ',';
+ else if (formatType.equals(FORMATTYPE_TAB))
+ delimiter = '\t';
+ else
+ throw new IllegalArgumentException ("ImpFormat.parseFlexFormat - unknown format: " + formatType);
+ if (line == null || line.length() == 0 || fieldNo < 0)
+ return "";
+
+ // We need to read line sequentially as the fields may be delimited
+ // with quotes (") when fields contain the delimiter
+ // Example: "Artikel,bez","Artikel,""nr""",DEM,EUR
+ // needs to result in - Artikel,bez - Artikel,"nr" - DEM - EUR
+ int pos = 0;
+ int length = line.length();
+ for (int field = 1; field <= fieldNo && pos < length; field++)
+ {
+ StringBuffer content = new StringBuffer();
+ // two delimiter directly after each other
+ if (line.charAt(pos) == delimiter)
+ {
+ pos++;
+ continue;
+ }
+ // Handle quotes
+ if (line.charAt(pos) == QUOTE)
+ {
+ pos++; // move over beginning quote
+ while (pos < length)
+ {
+ // double quote
+ if (line.charAt(pos) == QUOTE && pos+1 < length && line.charAt(pos+1) == QUOTE)
+ {
+ content.append(line.charAt(pos++));
+ pos++;
+ }
+ // end quote
+ else if (line.charAt(pos) == QUOTE)
+ {
+ pos++;
+ break;
+ }
+ // normal character
+ else
+ content.append(line.charAt(pos++));
+ }
+ // we should be at end of line or a delimiter
+ if (pos < length && line.charAt(pos) != delimiter)
+ log.info("Did not find delimiter at pos " + pos + " " + line);
+ pos++; // move over delimiter
+ }
+ else // plain copy
+ {
+ while (pos < length && line.charAt(pos) != delimiter)
+ content.append(line.charAt(pos++));
+ pos++; // move over delimiter
+ }
+ if (field == fieldNo)
+ return content.toString();
+ }
+
+ // nothing found
+ return "";
+ } // parseFlexFormat
+
+ /*************************************************************************
+ * Insert/Update Database.
+ * @param ctx context
+ * @param line line
+ * @param trxName transaction
+ * @return true if inserted/updated
+ */
+ public boolean updateDB (Properties ctx, String line, String trxName)
+ {
+ if (line == null || line.trim().length() == 0)
+ {
+ log.finest("No Line");
+ return false;
+ }
+ String[] nodes = parseLine (line, true, false, true); // with label, no trace, ignore empty
+ if (nodes.length == 0)
+ {
+ log.finest("Nothing parsed from: " + line);
+ return false;
+ }
+ // log.config( "ImpFormat.updateDB - listSize=" + nodes.length);
+
+ // Standard Fields
+ int AD_Client_ID = Env.getAD_Client_ID(ctx);
+ int AD_Org_ID = Env.getAD_Org_ID(ctx);
+ if (getAD_Table_ID() == X_I_GLJournal.Table_ID)
+ AD_Org_ID = 0;
+ int UpdatedBy = Env.getAD_User_ID(ctx);
+
+
+ // Check if the record is already there ------------------------------
+ StringBuffer sql = new StringBuffer ("SELECT COUNT(*), MAX(")
+ .append(m_tablePK).append(") FROM ").append(m_tableName)
+ .append(" WHERE AD_Client_ID=").append(AD_Client_ID).append(" AND (");
+ //
+ String where1 = null;
+ String where2 = null;
+ String whereParentChild = null;
+ for (int i = 0; i < nodes.length; i++)
+ {
+ if (nodes[i].endsWith("=''") || nodes[i].endsWith("=0"))
+ ;
+ else if (nodes[i].startsWith(m_tableUnique1 + "="))
+ where1 = nodes[i];
+ else if (nodes[i].startsWith(m_tableUnique2 + "="))
+ where2 = nodes[i];
+ else if (nodes[i].startsWith(m_tableUniqueParent + "=") || nodes[i].startsWith(m_tableUniqueChild + "="))
+ {
+ if (whereParentChild == null)
+ whereParentChild = nodes[i];
+ else
+ whereParentChild += " AND " + nodes[i];
+ }
+ }
+ StringBuffer find = new StringBuffer();
+ if (where1 != null)
+ find.append(where1);
+ if (where2 != null)
+ {
+ if (find.length() > 0)
+ find.append(" OR ");
+ find.append(where2);
+ }
+ if (whereParentChild != null && whereParentChild.indexOf(" AND ") != -1) // need to have both criteria
+ {
+ if (find.length() > 0)
+ find.append(" OR (").append(whereParentChild).append(")"); // may have only one
+ else
+ find.append(whereParentChild);
+ }
+ sql.append(find).append(")");
+ int count = 0;
+ int ID = 0;
+ try
+ {
+ if (find.length() > 0)
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql.toString(), trxName);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ count = rs.getInt(1);
+ if (count == 1)
+ ID = rs.getInt(2);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql.toString(), e);
+ return false;
+ }
+
+
+ // Insert Basic Record -----------------------------------------------
+ if (ID == 0)
+ {
+ ID = DB.getNextID(ctx, m_tableName, null); // get ID
+ sql = new StringBuffer("INSERT INTO ")
+ .append(m_tableName).append("(").append(m_tablePK).append(",")
+ .append("AD_Client_ID,AD_Org_ID,Created,CreatedBy,Updated,UpdatedBy,IsActive") // StdFields
+ .append(") VALUES (").append(ID).append(",")
+ .append(AD_Client_ID).append(",").append(AD_Org_ID)
+ .append(",SysDate,").append(UpdatedBy).append(",SysDate,").append(UpdatedBy).append(",'Y'")
+ .append(")");
+ //
+ int no = DB.executeUpdate(sql.toString(), trxName);
+ if (no != 1)
+ {
+ log.log(Level.SEVERE, "Insert records=" + no + "; SQL=" + sql.toString());
+ return false;
+ }
+ log.finer("New ID=" + ID + " " + find);
+ }
+ else
+ log.finer("Old ID=" + ID + " " + find);
+
+ // Update Info -------------------------------------------------------
+ sql = new StringBuffer ("UPDATE ")
+ .append(m_tableName).append(" SET ");
+ for (int i = 0; i < nodes.length; i++)
+ sql.append(nodes[i]).append(","); // column=value
+ sql.append("IsActive='Y',Processed='N',I_IsImported='N',Updated=SysDate,UpdatedBy=").append(UpdatedBy);
+ sql.append(" WHERE ").append(m_tablePK).append("=").append(ID);
+ // Update Cmd
+ int no = DB.executeUpdate(sql.toString(), trxName);
+ if (no != 1)
+ {
+ log.log(Level.SEVERE, m_tablePK + "=" + ID + " - rows updated=" + no);
+ return false;
+ }
+ return true;
+ } // updateDB
+
+} // ImpFormat
diff --git a/base/src/org/compiere/impexp/ImpFormatRow.java b/base/src/org/compiere/impexp/ImpFormatRow.java
new file mode 100644
index 0000000000..856a6cb262
--- /dev/null
+++ b/base/src/org/compiere/impexp/ImpFormatRow.java
@@ -0,0 +1,490 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.math.*;
+import java.sql.*;
+import java.text.*;
+import java.util.logging.*;
+import org.compiere.model.*;
+import org.compiere.util.*;
+
+/**
+ * Import Format Row with pasing capability
+ *
+ * @author Jorg Janke
+ * @version $Id: ImpFormatRow.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public final class ImpFormatRow
+{
+ /**
+ * Constructor for fixed format
+ * @param seqNo sequence
+ * @param columnName db dolumn name
+ * @param startNo start no
+ * @param endNo and no
+ * @param dataType data type - see constants DATATYPE_
+ * @param maxLength if String it is the maximum length (truncated)
+ */
+ public ImpFormatRow(int seqNo, String columnName, int startNo, int endNo, String dataType, int maxLength)
+ {
+ m_seqNo = seqNo;
+ setColumnName(columnName);
+ m_startNo = startNo;
+ m_endNo = endNo;
+ setDataType (dataType);
+ setMaxLength (maxLength);
+ } // ImpFormatRow
+
+ /**
+ * Constructor for non-fixed format
+ * @param seqNo sequence
+ * @param columnName db column name
+ * @param dataType data type - see constants DATATYPE_
+ * @param maxLength if String it is the maximum length (truncated)
+ */
+ public ImpFormatRow(int seqNo, String columnName, String dataType, int maxLength)
+ {
+ m_seqNo = seqNo;
+ setColumnName(columnName);
+ setDataType (dataType);
+ setMaxLength (maxLength);
+ } // ImpFormatRow
+
+ private int m_seqNo;
+ private String m_columnName;
+ private int m_startNo = 0;
+ private int m_endNo = 0;
+ private String m_dataType;
+ private String m_dataFormat = "";
+ private String m_decimalPoint = ".";
+ private boolean m_divideBy100 = false;
+ private String m_constantValue = "";
+ private boolean m_constantIsString = true;
+ //
+ private Callout m_callout = null;
+ private String m_method = null;
+ //
+ private SimpleDateFormat m_dformat = null;
+ private int m_maxLength = 0;
+
+ /** Logger */
+ private CLogger log = CLogger.getCLogger(getClass());
+
+ /**
+ * Sequence No
+ * @return seq no
+ */
+ public int getSeqNo ()
+ {
+ return m_seqNo;
+ } // getSeqNo
+
+ /**
+ * Set Sequence No
+ * @param newSeqNo sequence
+ */
+ public void setSeqNo (int newSeqNo)
+ {
+ m_seqNo = newSeqNo;
+ } // setSeqNo
+
+ /**
+ * Start Position
+ * @param newStartNo start position
+ */
+ public void setStartNo (int newStartNo)
+ {
+ m_startNo = newStartNo;
+ } // setStartNo
+
+ /**
+ * Get Start Position
+ * @return start position
+ */
+ public int getStartNo()
+ {
+ return m_startNo;
+ } // getStartNo
+
+ /**
+ * End Position
+ * @param newEndNo end position
+ */
+ public void setEndNo (int newEndNo)
+ {
+ m_endNo = newEndNo;
+ } // setEndNo
+
+ /**
+ * Get End Position
+ * @return End Position
+ */
+ public int getEndNo ()
+ {
+ return m_endNo;
+ } // getEndNo
+
+ /**
+ * Column
+ * @param columnName column name
+ */
+ public void setColumnName (String columnName)
+ {
+ if (columnName == null || columnName.length() == 0)
+ throw new IllegalArgumentException("ColumnName must be at least 1 char");
+ else
+ m_columnName = columnName;
+ } // setColumnName
+
+ /**
+ * Get Column Name
+ * @return Column Name
+ */
+ public String getColumnName()
+ {
+ return m_columnName;
+ } // getColumnName
+
+ /**
+ * Data Type
+ * @param dataType data type - see constants DATATYPE_
+ */
+ public void setDataType (String dataType)
+ {
+ if (dataType.equals(DATATYPE_String) || dataType.equals(DATATYPE_Date)
+ || dataType.equals(DATATYPE_Number) || dataType.equals(DATATYPE_Constant))
+ m_dataType = dataType;
+ else
+ throw new IllegalArgumentException("DataType must be S/D/N/C");
+ } // setDataType
+
+ /** String Data type */
+ public static final String DATATYPE_String = "S";
+ /** Data Data type */
+ public static final String DATATYPE_Date = "D";
+ /** Numeric Data type */
+ public static final String DATATYPE_Number = "N";
+ /** Constant Data type */
+ public static final String DATATYPE_Constant = "C";
+
+ /**
+ * Data Type
+ * @return data type
+ */
+ public String getDataType()
+ {
+ return m_dataType;
+ } // getDataType
+
+ /**
+ * Is String
+ * @return true if data type is String
+ */
+ public boolean isString()
+ {
+ if (m_dataType.equals(DATATYPE_Constant))
+ return m_constantIsString;
+ return m_dataType.equals(DATATYPE_String);
+ } // isString
+
+ /**
+ * Is Number
+ * @return true if data type is Number
+ */
+ public boolean isNumber()
+ {
+ return m_dataType.equals(DATATYPE_Number);
+ }
+
+ /**
+ * Is Date
+ * @return true if data type is Date
+ */
+ public boolean isDate()
+ {
+ return m_dataType.equals(DATATYPE_Date);
+ }
+
+ /**
+ * Is Constant
+ * @return true if data type is Constant
+ */
+ public boolean isConstant()
+ {
+ return m_dataType.equals(DATATYPE_Constant);
+ }
+
+ /**
+ * Set Format Info
+ * @param dataFormat data format - see constants DATATYPE_
+ * @param decimalPoint decimal point representation
+ * @param divideBy100 divide number by 100
+ * @param constantValue constant value
+ * @param callout Java callout
+ */
+ public void setFormatInfo (String dataFormat, String decimalPoint, boolean divideBy100,
+ String constantValue, String callout)
+ {
+ if (dataFormat == null)
+ m_dataFormat = "";
+ else
+ m_dataFormat = dataFormat;
+ // number
+ if (decimalPoint == null || !decimalPoint.equals(","))
+ m_decimalPoint = ".";
+ else
+ m_decimalPoint = ",";
+ m_divideBy100 = divideBy100;
+ // constant
+ if (constantValue == null || constantValue.length() == 0 || !m_dataType.equals(DATATYPE_Constant))
+ {
+ m_constantValue = "";
+ m_constantIsString = true;
+ }
+ else
+ {
+ m_constantValue = constantValue;
+ m_constantIsString = false;
+ for (int i = 0; i < m_constantValue.length(); i++)
+ {
+ char c = m_constantValue.charAt(i);
+ if (!(Character.isDigit(c) || c == '.')) // if a constant number, it must be with . (not ,)
+ {
+ m_constantIsString = true;
+ break;
+ }
+ }
+ }
+ // callout
+ if (callout != null)
+ {
+ int methodStart = callout.lastIndexOf(".");
+ try
+ {
+ if (methodStart != -1) // no class
+ {
+ Class cClass = Class.forName(callout.substring(0,methodStart));
+ m_callout = (Callout)cClass.newInstance();
+ m_method = callout.substring(methodStart+1);
+ }
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "MTab.setFormatInfo - " + e.toString());
+ }
+ if (m_callout == null || m_method == null || m_method.length() == 0)
+ {
+ log.log(Level.SEVERE, "MTab.setFormatInfo - Invalid Callout " + callout);
+ m_callout = null;
+ }
+ }
+ } // setFormatInfo
+
+ /**
+ * Get Format
+ * @return Data Format
+ */
+ public String getDataFormat()
+ {
+ return m_dataFormat;
+ }
+
+ /**
+ * Get Decimal Point
+ * @return Decimal Point
+ */
+ public String getDecimalPoint()
+ {
+ return m_decimalPoint;
+ }
+
+ /**
+ * Divide result by 100
+ * @return true if result will be divided by 100
+ */
+ public boolean isDivideBy100()
+ {
+ return m_divideBy100;
+ }
+
+ /**
+ * Get the constant value
+ * @return constant value
+ */
+ public String getConstantValue()
+ {
+ return m_constantValue;
+ }
+
+ /**
+ * Set maximum length for Strings (truncated).
+ * Ignored, if 0
+ * @param maxLength max length
+ */
+ public void setMaxLength (int maxLength)
+ {
+ m_maxLength = maxLength;
+ } // setMaxLength
+
+
+ /*************************************************************************
+ * Parse value.
+ * Field content in [] are treated as comments
+ * @param info data item
+ * @return pased info
+ */
+ public String parse (String info)
+ {
+ if (info == null || info.length() == 0)
+ return "";
+
+ // Comment ?
+ if (info.startsWith("[") && info.endsWith("]"))
+ return "";
+ //
+ String retValue = null;
+ if (isNumber())
+ retValue = parseNumber (info);
+ else if (isDate())
+ retValue = parseDate (info);
+ else if (isConstant())
+ retValue = m_constantIsString ? parseString (m_constantValue) : m_constantValue;
+ else
+ retValue = parseString (info);
+ //
+ if (m_callout != null)
+ {
+ try
+ {
+ retValue = m_callout.convert (m_method, retValue);
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "ImpFormatRow.parse - " + info + " (" + retValue + ")", e);
+ }
+ }
+ //
+ if (retValue == null)
+ retValue = "";
+ return retValue.trim();
+ } // parse
+
+
+ /**
+ * Return date as YYYY-MM-DD HH24:MI:SS (JDBC Timestamp format w/o miliseconds)
+ * @param info data
+ * @return date as JDBC format String
+ */
+ private String parseDate (String info)
+ {
+ if (m_dformat == null)
+ {
+ try
+ {
+ m_dformat = new SimpleDateFormat(m_dataFormat);
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "ImpFormatRow.parseDate Format=" + m_dataFormat, e);
+ }
+ if (m_dformat == null)
+ m_dformat = (SimpleDateFormat)DateFormat.getDateInstance();
+ m_dformat.setLenient(true);
+ }
+
+ Timestamp ts = null;
+ try
+ {
+ ts = new Timestamp (m_dformat.parse(info).getTime());
+ }
+ catch (ParseException pe)
+ {
+ log.log(Level.SEVERE, "ImpFormatRow.parseDate - " + info, pe);
+ }
+ if (ts == null)
+ ts = new Timestamp (System.currentTimeMillis());
+ //
+ String dateString = ts.toString();
+ return dateString.substring(0, dateString.indexOf(".")); // cut off miliseconds
+ } // parseNumber
+
+ /**
+ * Return String.
+ * - clean ' and backslash
+ * - check max length
+ * @param info data
+ * @return info with in SQL format
+ */
+ private String parseString (String info)
+ {
+ String retValue = info;
+ // Length restriction
+ if (m_maxLength > 0 && retValue.length() > m_maxLength)
+ retValue = retValue.substring(0, m_maxLength);
+
+ // copy characters (wee need to look through anyway)
+ StringBuffer out = new StringBuffer(retValue.length());
+ for (int i = 0; i < retValue.length(); i++)
+ {
+ char c = retValue.charAt(i);
+ if (c == '\'')
+ out.append("''");
+ else if (c == '\\')
+ out.append("\\\\");
+ else
+ out.append(c);
+ }
+ return out.toString();
+ } // parseString
+
+ /**
+ * Return number with "." decimal
+ * @param info data
+ * @return converted number
+ */
+ private String parseNumber (String info)
+ {
+ boolean hasPoint = info.indexOf(".") != -1;
+ boolean hasComma = info.indexOf(",") != -1;
+ // delete thousands
+ if (hasComma && m_decimalPoint.equals("."))
+ info = info.replace(',', ' ');
+ if (hasPoint && m_decimalPoint.equals(","))
+ info = info.replace('.', ' ');
+ hasComma = info.indexOf(",") != -1;
+
+ // replace decimal
+ if (hasComma && m_decimalPoint.equals(","))
+ info = info.replace(',', '.');
+
+ // remove everything but digits & '.'
+ char[] charArray = info.toCharArray();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < charArray.length; i++)
+ if (Character.isDigit(charArray[i]) || charArray[i] == '.')
+ sb.append(charArray[i]);
+
+ if (sb.length() == 0)
+ return "0";
+ BigDecimal bd = new BigDecimal(sb.toString());
+ if (m_divideBy100) // assumed two decimal scale
+ bd = bd.divide(new BigDecimal(100.0), 2, BigDecimal.ROUND_HALF_UP);
+ return bd.toString();
+ } // parseNumber
+
+} // ImpFormatFow
diff --git a/base/src/org/compiere/impexp/MImpFormat.java b/base/src/org/compiere/impexp/MImpFormat.java
new file mode 100644
index 0000000000..583acd73ba
--- /dev/null
+++ b/base/src/org/compiere/impexp/MImpFormat.java
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.model.*;
+import org.compiere.util.*;
+
+
+/**
+ * Import Format Model
+ *
+ * @author Jorg Janke
+ * @version $Id: MImpFormat.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class MImpFormat extends X_AD_ImpFormat
+{
+
+ /**
+ * Standard Constructor
+ * @param ctx context
+ * @param AD_ImpFormat_ID id
+ * @param trxName transaction
+ */
+ public MImpFormat (Properties ctx, int AD_ImpFormat_ID, String trxName)
+ {
+ super (ctx, AD_ImpFormat_ID, trxName);
+ } // MImpFormat
+
+ /**
+ * Load Constructor
+ * @param ctx context
+ * @param rs result set
+ * @param trxName transaction
+ */
+ public MImpFormat (Properties ctx, ResultSet rs, String trxName)
+ {
+ super(ctx, rs, trxName);
+ } // MImpFormat
+
+ /**
+ * Get (all) Rows
+ * @return array of Rows
+ */
+ public MImpFormatRow[] getRows()
+ {
+ ArrayList list = new ArrayList();
+ String sql = "SELECT * FROM AD_ImpFormat_Row "
+ + "WHERE AD_ImpFormat_ID=? "
+ + "ORDER BY SeqNo";
+ PreparedStatement pstmt = null;
+ try
+ {
+ pstmt = DB.prepareStatement (sql, get_TrxName());
+ pstmt.setInt (1, getAD_ImpFormat_ID());
+ ResultSet rs = pstmt.executeQuery ();
+ while (rs.next ())
+ list.add(new MImpFormatRow (getCtx(), rs, get_TrxName()));
+ rs.close ();
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "getRows", e);
+ }
+ try
+ {
+ if (pstmt != null)
+ pstmt.close ();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ pstmt = null;
+ }
+ MImpFormatRow[] retValue = new MImpFormatRow[list.size ()];
+ list.toArray (retValue);
+ return retValue;
+ } // getRows
+
+} // MImpFormat
diff --git a/base/src/org/compiere/impexp/MImpFormatRow.java b/base/src/org/compiere/impexp/MImpFormatRow.java
new file mode 100644
index 0000000000..216b406b51
--- /dev/null
+++ b/base/src/org/compiere/impexp/MImpFormatRow.java
@@ -0,0 +1,89 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.sql.*;
+import java.util.*;
+
+import org.compiere.model.*;
+
+
+/**
+ * Import Format Row Model
+ *
+ * @author Jorg Janke
+ * @version $Id: MImpFormatRow.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class MImpFormatRow extends X_AD_ImpFormat_Row
+{
+
+ /**
+ * Standard Constructor
+ * @param ctx context
+ * @param AD_ImpFormat_Row_ID id
+ * @param trxName transaction
+ */
+ public MImpFormatRow (Properties ctx, int AD_ImpFormat_Row_ID, String trxName)
+ {
+ super (ctx, AD_ImpFormat_Row_ID, trxName);
+ if (AD_ImpFormat_Row_ID == 0)
+ {
+ // setAD_ImpFormat_ID (0); Parent
+ // setAD_Column_ID (0);
+ // setDataType (null);
+ // setName (null);
+ // setSeqNo (10);
+ setDecimalPoint (".");
+ setDivideBy100 (false);
+ }
+ } // MImpFormatRow
+
+ /**
+ * Load Construcor
+ * @param ctx context
+ * @param rs result set
+ * @param trxName transaction
+ */
+ public MImpFormatRow (Properties ctx, ResultSet rs, String trxName)
+ {
+ super(ctx, rs, trxName);
+ } // MImpFormatRow
+
+ /**
+ * Parent Construcor
+ * @param format format parent
+ */
+ public MImpFormatRow (MImpFormat format)
+ {
+ this (format.getCtx(), 0, format.get_TrxName());
+ setAD_ImpFormat_ID(format.getAD_ImpFormat_ID());
+ } // MImpFormatRow
+
+ /**
+ * Parent/Copy Construcor
+ * @param parent format parent
+ * @param original to copy
+ */
+ public MImpFormatRow (MImpFormat parent, MImpFormatRow original)
+ {
+ this (parent.getCtx(), 0, parent.get_TrxName());
+ copyValues(original, this);
+ setClientOrg(parent);
+ setAD_ImpFormat_ID(parent.getAD_ImpFormat_ID());
+ } // MImpFormatRow
+
+} // MImpFormatRow
diff --git a/base/src/org/compiere/impexp/OFX1ToXML.java b/base/src/org/compiere/impexp/OFX1ToXML.java
new file mode 100644
index 0000000000..a541b01b42
--- /dev/null
+++ b/base/src/org/compiere/impexp/OFX1ToXML.java
@@ -0,0 +1,242 @@
+/******************************************************************************
+ * 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.impexp;
+
+import java.io.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Covert OFX 1XX (SQGML) into valid XML
+ *
+ * SGML BASED OFX 1 compliant data is read from the BufferedReader
+ * passed to init. This class extends InputSream, allowing the
+ * XML compliant output data to be read from it.
+ *
+ * @author Maarten Klinker
+ * @version $Id: OFX1ToXML.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public final class OFX1ToXML extends InputStream implements Runnable
+{
+ /** Reader object */
+ private PipedReader m_reader = new PipedReader();
+ /** Writer object */
+ private BufferedWriter m_writer;
+ /** Temp String */
+ private String m_ofx = "";
+
+ /** Logger */
+ private CLogger log = CLogger.getCLogger(getClass());
+
+ /**
+ * Constructor for OFX1ToXML
+ * @param is InputStream
+ * @throws IOException
+ */
+ public OFX1ToXML(InputStream is) throws IOException
+ {
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ init(br);
+ } // OFX1ToXML
+
+ /**
+ * Constructor for OFX1ToXML
+ * @param br BufferedReader
+ * @throws IOException
+ */
+ public OFX1ToXML(BufferedReader br) throws IOException
+ {
+ init(br);
+ } // OFX1ToXML
+
+ /**
+ * Method init
+ * @param br BufferedReader
+ * @throws IOException
+ */
+ public void init(BufferedReader br) throws IOException
+ {
+ m_writer = new BufferedWriter(new PipedWriter(m_reader));
+ String line = br.readLine();
+
+ write("\n");
+ write(" 0)
+ {
+ write(line.replaceAll(":", "=\"") + "\" ");
+ }
+ line = br.readLine();
+ }
+ write("?>\n");
+
+ while(line != null)
+ {
+ m_ofx += line + "\n";
+ line = br.readLine();
+ }
+ br.close();
+
+ new Thread(this).start();
+ } //i nit
+
+ /**
+ * Method run
+ * @see java.lang.Runnable#run()
+ */
+ public void run()
+ {
+ boolean addCloseTag;
+ int tag2Start;
+ int tagStart;
+ int tagEnd;
+ String tag;
+ String line = "";
+
+ try
+ {
+ while(m_ofx != "")
+ {
+ addCloseTag = false;
+ tagStart = m_ofx.indexOf("<");
+ if (tagStart == -1)
+ {
+ break;
+ }
+ tagEnd = m_ofx.indexOf(">");
+ if (tagEnd <= tagStart + 1)
+ {
+ throw new IOException("PARSE ERROR: Invalid tag");
+ }
+ tag = m_ofx.substring(tagStart + 1, tagEnd);
+ if (tag.indexOf(" ") != -1)
+ {
+ throw new IOException("PARSE ERROR: Invalid tag");
+ }
+ if (!tag.startsWith("/"))
+ {
+ addCloseTag = (m_ofx.indexOf(""+tag+">") == -1);
+ }
+ tag2Start = m_ofx.indexOf("<", tagEnd);
+ if (m_ofx.indexOf("\n", tagEnd) < tag2Start)
+ {
+ tag2Start = m_ofx.indexOf("\n", tagEnd);
+ }
+ if (tag2Start == -1)
+ {
+ tag2Start = m_ofx.length();
+ }
+
+ String data=m_ofx.substring(tagEnd+1, tag2Start);
+ line = m_ofx.substring(0, tagEnd+1)+xmlEncodeTextAsPCDATA(data);
+
+ m_ofx = m_ofx.substring(tag2Start);
+ if (addCloseTag)
+ {
+ line += "" + tag + ">";
+ }
+ write(line);
+ }
+ write(m_ofx);
+ m_writer.close();
+ }
+ catch (IOException e)
+ {
+ log.log(Level.SEVERE, "Ofx1To2Convertor: IO Exception", e);
+ }
+ } // run
+
+ /**
+ * Method write
+ * @param str String
+ * @throws IOException
+ */
+ private void write(String str) throws IOException
+ {
+ m_writer.write(str, 0, str.length());
+ } // write
+
+ /**
+ * Method read
+ * @return int
+ * @throws IOException
+ */
+ public int read() throws IOException
+ {
+ return m_reader.read();
+ } // read
+
+ /**
+ * Method read
+ * @param cbuf char[]
+ * @param off int
+ * @param len int
+ * @return int
+ * @throws IOException
+ */
+ public int read(char[] cbuf, int off, int len) throws IOException
+ {
+ return m_reader.read(cbuf, off, len);
+ } // read
+
+
+
+
+ /**
+ * Encodes strings for XML
+ * @param text text
+ * @return string
+ */
+ public final static String xmlEncodeTextAsPCDATA(String text)
+ {
+ if (text == null)
+ return null;
+ char c;
+ StringBuffer n = new StringBuffer (text.length () * 2);
+ for (int i = 0; i < text.length (); i++)
+ {
+ c = text.charAt (i);
+ switch (c)
+ {
+ case '&':
+ n.append ("&");
+ break;
+ case '<':
+ n.append ("<");
+ break;
+ case '>':
+ n.append (">");
+ break;
+ case '"':
+ n.append (""");
+ break;
+ case '\'':
+ n.append ("'");
+ break;
+ default:
+ {
+ n.append (c);
+ break;
+ }
+ }
+ }
+ return n.toString ();
+ } // xmlEncodeTextAsPCDATA
+
+
+} //Ofx1To2Convertor
diff --git a/base/src/org/compiere/impexp/OFXBankStatementHandler.java b/base/src/org/compiere/impexp/OFXBankStatementHandler.java
new file mode 100644
index 0000000000..2f48c3118f
--- /dev/null
+++ b/base/src/org/compiere/impexp/OFXBankStatementHandler.java
@@ -0,0 +1,817 @@
+/******************************************************************************
+ * 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.impexp;
+
+import org.compiere.model.*;
+import org.compiere.util.Env;
+
+import java.io.*;
+import java.math.BigDecimal;
+
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.text.ParseException;
+
+import javax.xml.parsers.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+
+/**
+ * Parser for OFX bank statements
+ *
+ * This class is a parser for OFX bankstatements. OFX versions from 102 to 202
+ * and MS-Money OFC message sets are supported.
+ * Only fully XML compliant OFX data is supported. Files that are not XML
+ * compliant, e.g. OFX versions older then 200, will be preprocessed by
+ * the OFX1ToXML class before parsing.
+ * This class should be extended by a class that obtains the data to be parsed
+ * for example from a file, or using HTTP.
+ *
+ * @author Eldir Tomassen
+ * @version $Id: OFXBankStatementHandler.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+
+public abstract class OFXBankStatementHandler extends DefaultHandler
+{
+
+ protected MBankStatementLoader m_controller;
+ protected String m_errorMessage = "";
+ protected String m_errorDescription = "";
+ protected BufferedReader m_reader = null;
+
+ protected SAXParser m_parser;
+ protected boolean m_success = false;
+ //private boolean m_valid = false;
+
+ protected StatementLine m_line;
+ protected String m_routingNo = "0";
+ protected String m_bankAccountNo = null;
+ protected String m_currency = null;
+ protected int HEADER_SIZE = 20;
+
+ protected boolean m_test = false;
+ protected Timestamp m_dateLastRun = null;
+ protected Timestamp m_statementDate = null;
+
+ StringBuffer m_valueBuffer = new StringBuffer();
+
+
+
+ /** XML OFX Tag */
+ public static final String XML_OFX_TAG = "OFX";
+
+ /** XML SIGNONMSGSRSV2 Tag */
+ public static final String XML_SIGNONMSGSRSV2_TAG = "SIGNONMSGSRSV2";
+ /** XML SIGNONMSGSRSV1 Tag */
+ public static final String XML_SIGNONMSGSRSV1_TAG = "SIGNONMSGSRSV1";
+
+ /** Record-response aggregate */
+ public static final String XML_SONRS_TAG = "SONRS";
+ /** Date and time of the server response */
+ public static final String XML_DTSERVER_TAG = "DTSERVER";
+ /** Use USERKEY instead of USERID and USEPASS */
+ public static final String XML_USERKEY_TAG = "USERKEY";
+ /** Date and time that USERKEY expires */
+ public static final String XML_TSKEYEXPIRE_TAG = "TSKEYEXPIRE";
+ /** Language */
+ public static final String XML_LANGUAGE_TAG = "LANGUAGE";
+ /** Date and rime last update to profile information*/
+ public static final String XML_DTPROFUP_TAG = "DTPROFUP";
+
+ /** Status aggregate */
+ public static final String XML_STATUS_TAG = "STATUS";
+
+
+ /** Statement-response aggregate */
+ public static final String XML_STMTRS_TAG = "STMTRS";
+ /** XML CURDEF Tag */
+ public static final String XML_CURDEF_TAG = "CURDEF";
+
+ /** Account-from aggregate */
+ public static final String XML_BANKACCTFROM_TAG = "BANKACCTFROM";
+ /** Bank identifier */
+ public static final String XML_BANKID_TAG = "BANKID";
+ /** Branch identifier */
+ public static final String XML_BRANCHID_TAG = "BRANCHID";
+ /** XML ACCTID Tag */
+ public static final String XML_ACCTID_TAG = "ACCTID";
+ /** Type of account */
+ public static final String XML_ACCTTYPE_TAG = "ACCTTYPE";
+ /** Type of account */
+ public static final String XML_ACCTTYPE2_TAG = "ACCTTYPE2";
+ /** Checksum */
+ public static final String XML_ACCTKEY_TAG = "ACCTKEY";
+
+ /** XML BANKTRANLIST Tag */
+ public static final String XML_BANKTRANLIST_TAG = "BANKTRANLIST";
+ /** XML DTSTART Tag */
+ public static final String XML_DTSTART_TAG = "DTSTART";
+ /** XML DTEND Tag */
+ public static final String XML_DTEND_TAG = "DTEND";
+ /** XML STMTTRN Tag */
+ public static final String XML_STMTTRN_TAG = "STMTTRN";
+ /** XML TRNTYPE Tag */
+ public static final String XML_TRNTYPE_TAG = "TRNTYPE";
+ /** XML TRNAMT Tag */
+ public static final String XML_TRNAMT_TAG = "TRNAMT";
+ /** Transaction date */
+ public static final String XML_DTPOSTED_TAG = "DTPOSTED";
+ /** Effective date */
+ public static final String XML_DTAVAIL_TAG = "DTAVAIL";
+ /** XML FITID Tag */
+ public static final String XML_FITID_TAG = "FITID";
+ /** XML CHECKNUM Tag */
+ public static final String XML_CHECKNUM_TAG = "CHECKNUM";
+ /** XML CHKNUM Tag (MS-Money OFC) */
+ public static final String XML_CHKNUM_TAG = "CHKNUM";
+ /** XML REFNUM Tag */
+ public static final String XML_REFNUM_TAG = "REFNUM";
+ /** Transaction Memo */
+ public static final String XML_MEMO_TAG = "MEMO";
+ /** XML NAME Tag */
+ public static final String XML_NAME_TAG = "NAME";
+ /** XML PAYEEID Tag */
+ public static final String XML_PAYEEID_TAG = "PAYEEID";
+ /** TXML PAYEE Tag */
+ public static final String XML_PAYEE_TAG = "PAYEE";
+
+ /** XML LEDGERBAL Tag */
+ public static final String XML_LEDGERBAL_TAG = "LEDGERBAL";
+ /** XML BALAMT Tag */
+ public static final String XML_BALAMT_TAG = "BALAMT";
+ /** XML DTASOF Tag */
+ public static final String XML_DTASOF_TAG = "DTASOF";
+ /** XML AVAILBAL Tag */
+ public static final String XML_AVAILBAL_TAG = "AVAILBAL";
+ /** XML MKTGINFO Tag */
+ public static final String XML_MKTGINFO_TAG = "MKTGINFO";
+
+ /**
+ * Initialize the loader
+ * * @param controller Reference to the BankStatementLoaderController
+ @return Initialized succesfully
+ */
+ protected boolean init(MBankStatementLoader controller)
+ {
+ boolean result = false;
+ if (controller == null)
+ {
+ m_errorMessage = "ErrorInitializingParser";
+ m_errorDescription = "ImportController is a null reference";
+ return result;
+ }
+ this.m_controller = controller;
+ try
+ {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ m_parser = factory.newSAXParser();
+ result = true;
+ }
+ catch(ParserConfigurationException e)
+ {
+ m_errorMessage = "ErrorInitializingParser";
+ m_errorDescription = "Unable to configure SAX parser: " + e.getMessage();
+ }
+ catch(SAXException e)
+ {
+ m_errorMessage = "ErrorInitializingParser";
+ m_errorDescription = "Unable to initialize SAX parser: " + e.getMessage();
+ }
+ return result;
+ } // init
+
+ /**
+ * Attach OFX input source, detect whether we are dealing with OFX1
+ * (SGML) or OFX2 (XML). In case of OFX1, process the data to create
+ * valid XML.
+ * @param is Reference to the BankStatementLoaderController
+ * @return true if input is valid OFX data
+ */
+ protected boolean attachInput(InputStream is)
+ {
+ boolean isOfx1 = true;
+ boolean result = false;
+
+ try
+ {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ reader.mark(HEADER_SIZE + 100);
+ String header = "";
+ for (int i = 0; i < HEADER_SIZE; i++)
+ {
+ header = header + reader.readLine();
+ }
+ if ((header.indexOf(")
+ * is detected.
+ * @param uri String
+ * @param localName String
+ * @param qName String
+ * @throws SAXException
+ * @see org.xml.sax.ContentHandler#endElement(String, String, String)
+ */
+ public void endElement (String uri, String localName, String qName) throws SAXException
+ {
+
+ String XML_TAG=qName;
+ String value=m_valueBuffer.toString();
+
+ try
+ {
+ //Read statment level data
+
+ /*
+ * Default currency for this set of statement lines
+ * ---
+ */
+ if (XML_TAG.equals(XML_CURDEF_TAG))
+ {
+ m_currency = value;
+ }
+
+ /* Routing Number (or SWIFT Code) for this set of statement lines
+ * ----
+ */
+ else if (XML_TAG.equals(XML_BANKID_TAG))
+ {
+ m_routingNo = value;
+ }
+
+ /*
+ * Bank Account Number for this set of bank statement lines
+ * ----
+ */
+ else if (XML_TAG.equals(XML_ACCTID_TAG))
+ {
+ m_bankAccountNo = value;
+ }
+
+ /*
+ * Last date for this set of statement lines
+ * This is the date that should be specified as the
+ * for the next batch of statement lines, in order not to miss any
+ * transactions.
+ * ----
+ */
+ else if (XML_TAG.equals(XML_DTEND_TAG))
+ {
+ m_dateLastRun = parseOfxDate(value);
+ }
+
+ /*
+ *
+ * ----
+ */
+ else if (XML_TAG.equals(XML_DTASOF_TAG))
+ {
+ m_statementDate = parseOfxDate(value);
+ }
+
+
+ //Read statement line level data
+
+ /*
+ * Transaction type, e.g. DEBIT, CREDIT, SRVCHG
+ * ----
+ */
+ else if (XML_TAG.equals(XML_TRNTYPE_TAG))
+ {
+ m_line.trxType = value;
+ }
+
+ /*
+ * Statement line date
+ * ----
+ */
+ else if (XML_TAG.equals(XML_DTPOSTED_TAG))
+ {
+ m_line.statementLineDate = parseOfxDate(value);
+ }
+
+ /*
+ * Valuta date
+ * ----
+ */
+ else if (XML_TAG.equals(XML_DTAVAIL_TAG))
+ {
+ m_line.valutaDate = parseOfxDate(value);
+ }
+
+ /*
+ * Total statement line amount
+ * ----
+ */
+ else if (XML_TAG.equals(XML_TRNAMT_TAG))
+ {
+ m_line.stmtAmt = new BigDecimal(value);
+ }
+
+ /*
+ * Transaction Identification
+ * ----
+ */
+ else if (XML_TAG.equals(XML_FITID_TAG))
+ {
+ m_line.trxID = value;
+ }
+
+ /*
+ * Check number for check transactions
+ * CHECKNUM for generic OFX, CHKNUM for MS-Money OFC
+ * ----
+ */
+ else if ((XML_TAG.equals(XML_CHECKNUM_TAG)) || (XML_TAG.equals(XML_CHKNUM_TAG)))
+ {
+ m_line.checkNo = value;
+ }
+
+ /*
+ * Statement line reference
+ * Additional transaction reference information
+ * ----
+ */
+ else if (XML_TAG.equals(XML_REFNUM_TAG))
+ {
+ m_line.reference = value;
+ }
+
+ /*
+ * Transaction memo
+ * ----
+ */
+ else if (XML_TAG.equals(XML_MEMO_TAG))
+ {
+ m_line.memo = value;
+ }
+
+ /*
+ * Payee Name
+ * ----
+ */
+ else if (XML_TAG.equals(XML_NAME_TAG))
+ {
+ m_line.payeeName = value;
+ }
+ }
+ catch(Exception e)
+ {
+
+ m_errorDescription = "Invalid data: " + value + " <-> " + e.getMessage();
+ throw new SAXException("Invalid data: " + value);
+ }
+
+ if (qName.equals(XML_STMTTRN_TAG))
+ {
+ if (!m_test)
+ {
+ if (!m_controller.saveLine())
+ {
+ m_errorMessage = m_controller.getErrorMessage();
+ m_errorDescription = m_controller.getErrorDescription();
+ throw new SAXException(m_errorMessage);
+ }
+ }
+ }
+ } // endElement
+
+
+ /**
+ * Method parseOfxDate
+ * @param value String
+ * @return Timestamp
+ * @throws ParseException
+ */
+ private Timestamp parseOfxDate(String value) throws ParseException
+ {
+ try
+ {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+ sdf.setLenient(false);
+ return new Timestamp (sdf.parse(value).getTime());
+ }
+ catch(Exception e)
+ {
+ throw new ParseException("Error parsing date: " + value, 0);
+ }
+ } //parseOfxDate
+
+ /**
+ * Method getLastErrorMessage
+ * @return String
+ */
+ public String getLastErrorMessage()
+ {
+ return m_errorMessage;
+ }
+
+ /**
+ * Method getLastErrorDescription
+ * @return String
+ */
+ public String getLastErrorDescription()
+ {
+ return m_errorDescription;
+ }
+
+ /**
+ * @author ET
+ * @version $Id: OFXBankStatementHandler.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+ class StatementLine
+ {
+ protected String routingNo = null;
+ protected String bankAccountNo = null;
+ protected String statementReference = null;
+
+
+ protected Timestamp statementLineDate = null;
+ protected String reference = null;
+ protected Timestamp valutaDate;
+ protected String trxType = null;
+ protected boolean isReversal = false;
+ protected String currency = null;
+ protected BigDecimal stmtAmt = null;
+ protected String memo = null;
+ protected String chargeName = null;
+ protected BigDecimal chargeAmt = null;
+ protected String payeeAccountNo = null;
+ protected String payeeName = null;
+ protected String trxID = null;
+ protected String checkNo = null;
+
+
+ /**
+ * Constructor for StatementLine
+ * @param RoutingNo String
+ * @param BankAccountNo String
+ * @param Currency String
+ */
+ public StatementLine(String RoutingNo, String BankAccountNo, String Currency)
+ {
+ bankAccountNo = BankAccountNo;
+ routingNo = RoutingNo;
+ currency = Currency;
+ }
+
+ }
+
+} //OFXBankStatementHandler
diff --git a/base/src/org/compiere/impexp/OFXFileBankStatementLoader.java b/base/src/org/compiere/impexp/OFXFileBankStatementLoader.java
new file mode 100644
index 0000000000..a3d29c5b5e
--- /dev/null
+++ b/base/src/org/compiere/impexp/OFXFileBankStatementLoader.java
@@ -0,0 +1,100 @@
+/******************************************************************************
+ * 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.impexp;
+
+import org.compiere.model.*;
+
+import java.io.*;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Loader for OFX bank statements (file based)
+ *
+ * @author Eldir Tomassen
+ * @version $Id:
+ */
+
+public final class OFXFileBankStatementLoader extends OFXBankStatementHandler implements BankStatementLoaderInterface
+{
+
+ /**
+ * Method init
+ * @param controller MBankStatementLoader
+ * @return boolean
+ * @see org.compiere.impexp.BankStatementLoaderInterface#init(MBankStatementLoader)
+ */
+ public boolean init(MBankStatementLoader controller)
+ {
+ boolean result = false;
+ FileInputStream m_stream = null;
+ try
+ {
+ // Try to open the file specified as a process parameter
+ if (controller.getLocalFileName() != null)
+ {
+ m_stream = new FileInputStream(controller.getLocalFileName());
+ }
+ // Try to open the file specified as part of the loader configuration
+ else if (controller.getFileName() != null)
+ {
+ m_stream = new FileInputStream(controller.getFileName());
+ }
+ else
+ {
+ return result;
+ }
+ if (!super.init(controller))
+ {
+ return result;
+ }
+ if (m_stream == null)
+ {
+ return result;
+ }
+ result = attachInput(m_stream);
+ }
+ catch(Exception e)
+ {
+ m_errorMessage = "ErrorReadingData";
+ m_errorDescription = "";
+ }
+
+ return result;
+ } // init
+
+
+ /**
+ * Method characters
+ * @param ch char[]
+ * @param start int
+ * @param length int
+ * @throws SAXException
+ * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+ */
+ public void characters (char ch[], int start, int length)
+ throws SAXException
+ {
+ /*
+ * There are no additional things to do when importing from file.
+ * All data is handled by OFXBankStatementHandler
+ */
+ super.characters(ch, start, length);
+ } // characterS
+
+
+} // OFXFileBankStatementLoader
diff --git a/base/src/org/compiere/impexp/package.html b/base/src/org/compiere/impexp/package.html
new file mode 100644
index 0000000000..eaceadcaad
--- /dev/null
+++ b/base/src/org/compiere/impexp/package.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+Provides for....
+
+
+
+
+
+
+
diff --git a/base/src/org/compiere/model/AdempiereProcessor.java b/base/src/org/compiere/model/AdempiereProcessor.java
new file mode 100644
index 0000000000..aeacea8a08
--- /dev/null
+++ b/base/src/org/compiere/model/AdempiereProcessor.java
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * 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.model;
+
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Processor Interface
+ *
+ * @author Jorg Janke
+ * @version $Id: AdempiereProcessor.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $
+ */
+public interface AdempiereProcessor
+{
+ /**
+ * Get Client
+ * @return AD_Client_ID
+ */
+ public int getAD_Client_ID();
+
+ /**
+ * Get Name
+ * @return Name
+ */
+ public String getName();
+
+ /**
+ * Get Description
+ * @return Description
+ */
+ public String getDescription();
+
+ /**
+ * Get Context
+ * @return context
+ */
+ public Properties getCtx();
+
+ /**
+ * Get the frequency type
+ * @return frequency type
+ */
+ public String getFrequencyType();
+
+ /**
+ * Get the frequency
+ * @return frequency
+ */
+ public int getFrequency();
+
+
+ /**
+ * Get Unique ID
+ * @return Unique ID
+ */
+ public String getServerID();
+
+ /**
+ * Get the date Next run
+ * @param requery requery database
+ * @return date next run
+ */
+ public Timestamp getDateNextRun (boolean requery);
+
+ /**
+ * Set Date Next Run
+ * @param dateNextWork next work
+ */
+ public void setDateNextRun(Timestamp dateNextWork);
+
+ /**
+ * Get the date Last run
+ * @return date lext run
+ */
+ public Timestamp getDateLastRun ();
+
+ /**
+ * Set Date Last Run
+ * @param dateLastRun last run
+ */
+ public void setDateLastRun(Timestamp dateLastRun);
+
+ /**
+ * Save
+ * @return true if saved
+ */
+ public boolean save();
+
+
+ /**
+ * Get Processor Logs
+ * @return logs
+ */
+ public AdempiereProcessorLog[] getLogs();
+
+} // AdempiereProcessor
diff --git a/base/src/org/compiere/model/AdempiereProcessorLog.java b/base/src/org/compiere/model/AdempiereProcessorLog.java
new file mode 100644
index 0000000000..8338d92d96
--- /dev/null
+++ b/base/src/org/compiere/model/AdempiereProcessorLog.java
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * 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.model;
+
+import java.sql.*;
+
+/**
+ * Processor Log Interface
+ *
+ * @author Jorg Janke
+ * @version $Id: AdempiereProcessorLog.java,v 1.3 2006/07/30 00:51:04 jjanke Exp $
+ */
+public interface AdempiereProcessorLog
+{
+ /**
+ * Get Created Date
+ * @return created
+ */
+ public Timestamp getCreated();
+
+ /**
+ * Get Summary. Textual summary of this request
+ * @return Summary
+ */
+ public String getSummary ();
+
+ /**
+ * Get Description. Optional short description of the record
+ * @return description
+ */
+ public String getDescription ();
+
+ /**
+ * Get Error. An Error occured in the execution
+ * @return true if error
+ */
+ public boolean isError ();
+
+ /**
+ * Get Reference. Reference for this record
+ * @return reference
+ */
+ public String getReference ();
+
+ /**
+ * Get Text Message. Text Message
+ * @return text message
+ */
+ public String getTextMsg ();
+
+} // AdempiereProcessorLog
diff --git a/base/src/org/compiere/model/Callout.java b/base/src/org/compiere/model/Callout.java
new file mode 100644
index 0000000000..52051e30f0
--- /dev/null
+++ b/base/src/org/compiere/model/Callout.java
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * 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.model;
+
+import java.util.*;
+
+/**
+ * Callout Interface for Callout.
+ * Used in MTab and ImpFormatRow
+ *
+ * @author Jorg Janke
+ * @version $Id: Callout.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public interface Callout
+{
+ /**
+ * Start Callout.
+ *
+ * Callout's are used for cross field validation and setting values in other fields
+ * when returning a non empty (error message) string, an exception is raised
+ *
+ * When invoked, the Tab model has the new value!
+ *
+ * @param ctx Context
+ * @param method Method name
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @param oldValue The old value
+ * @return Error message or ""
+ */
+ public String start (Properties ctx, String method, int WindowNo,
+ GridTab mTab, GridField mField, Object value, Object oldValue);
+
+ /**
+ * Conversion Rules.
+ * Convert a String
+ *
+ * @param method in notation User_Function
+ * @param value the value
+ * @return converted String or Null if no method found
+ */
+ public String convert (String method, String value);
+
+} // callout
diff --git a/base/src/org/compiere/model/CalloutAssignment.java b/base/src/org/compiere/model/CalloutAssignment.java
new file mode 100644
index 0000000000..dbc313ae57
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutAssignment.java
@@ -0,0 +1,106 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+
+/**
+ * Resource Assignment Callout
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutAssignment.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutAssignment extends CalloutEngine
+{
+
+ /**
+ * Assignment_Product.
+ * - called from S_ResourceAssignment_ID
+ * - sets M_Product_ID, Description
+ * - Qty..
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ // get value
+ int S_ResourceAssignment_ID = ((Integer)value).intValue();
+ if (S_ResourceAssignment_ID == 0)
+ return "";
+ setCalloutActive(true);
+
+ int M_Product_ID = 0;
+ String Name = null;
+ String Description = null;
+ BigDecimal Qty = null;
+ String sql = "SELECT p.M_Product_ID, ra.Name, ra.Description, ra.Qty "
+ + "FROM S_ResourceAssignment ra"
+ + " INNER JOIN M_Product p ON (p.S_Resource_ID=ra.S_Resource_ID) "
+ + "WHERE ra.S_ResourceAssignment_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, S_ResourceAssignment_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ M_Product_ID = rs.getInt (1);
+ Name = rs.getString(2);
+ Description = rs.getString(3);
+ Qty = rs.getBigDecimal(4);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "product", e);
+ }
+
+ log.fine("S_ResourceAssignment_ID=" + S_ResourceAssignment_ID + " - M_Product_ID=" + M_Product_ID);
+ if (M_Product_ID != 0)
+ {
+ mTab.setValue ("M_Product_ID", new Integer (M_Product_ID));
+ if (Description != null)
+ Name += " (" + Description + ")";
+ if (!".".equals(Name))
+ mTab.setValue("Description", Name);
+ //
+ String variable = "Qty"; // TimeExpenseLine
+ if (mTab.getTableName().startsWith("C_Order"))
+ variable = "QtyOrdered";
+ else if (mTab.getTableName().startsWith("C_Invoice"))
+ variable = "QtyInvoiced";
+ if (Qty != null)
+ mTab.setValue(variable, Qty);
+ }
+ setCalloutActive(false);
+ return "";
+ } // product
+
+} // CalloutAssignment
diff --git a/base/src/org/compiere/model/CalloutBankStatement.java b/base/src/org/compiere/model/CalloutBankStatement.java
new file mode 100644
index 0000000000..05c72891fd
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutBankStatement.java
@@ -0,0 +1,151 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+
+/**
+ * Bank Statement Callout
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutBankStatement.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutBankStatement extends CalloutEngine
+{
+ /**
+ * Bank Account Changed.
+ * Update Beginning Balance
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String bankAccount (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (value == null)
+ return "";
+ int C_BankAccount_ID = ((Integer)value).intValue();
+ MBankAccount ba = MBankAccount.get(ctx, C_BankAccount_ID);
+ mTab.setValue("BeginningBalance", ba.getCurrentBalance());
+ return "";
+ } // bankAccount
+
+ /**
+ * BankStmt - Amount.
+ * Calculate ChargeAmt = StmtAmt - TrxAmt - InterestAmt
+ * or id Charge is entered - InterestAmt = StmtAmt - TrxAmt - ChargeAmt
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String amount (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ setCalloutActive(true);
+
+ // Get Stmt & Trx
+ BigDecimal stmt = (BigDecimal)mTab.getValue("StmtAmt");
+ if (stmt == null)
+ stmt = Env.ZERO;
+ BigDecimal trx = (BigDecimal)mTab.getValue("TrxAmt");
+ if (trx == null)
+ trx = Env.ZERO;
+ BigDecimal bd = stmt.subtract(trx);
+
+ // Charge - calculate Interest
+ if (mField.getColumnName().equals("ChargeAmt"))
+ {
+ BigDecimal charge = (BigDecimal)value;
+ if (charge == null)
+ charge = Env.ZERO;
+ bd = bd.subtract(charge);
+ // log.trace(log.l5_DData, "Interest (" + bd + ") = Stmt(" + stmt + ") - Trx(" + trx + ") - Charge(" + charge + ")");
+ mTab.setValue("InterestAmt", bd);
+ }
+ // Calculate Charge
+ else
+ {
+ BigDecimal interest = (BigDecimal)mTab.getValue("InterestAmt");
+ if (interest == null)
+ interest = Env.ZERO;
+ bd = bd.subtract(interest);
+ // log.trace(log.l5_DData, "Charge (" + bd + ") = Stmt(" + stmt + ") - Trx(" + trx + ") - Interest(" + interest + ")");
+ mTab.setValue("ChargeAmt", bd);
+ }
+ setCalloutActive(false);
+ return "";
+ } // amount
+
+
+ /**
+ * BankStmt - Payment.
+ * Update Transaction Amount when payment is selected
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String payment (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Payment_ID = (Integer)value;
+ if (C_Payment_ID == null || C_Payment_ID.intValue() == 0)
+ return "";
+ //
+ BigDecimal stmt = (BigDecimal)mTab.getValue("StmtAmt");
+ if (stmt == null)
+ stmt = Env.ZERO;
+
+ String sql = "SELECT PayAmt FROM C_Payment_v WHERE C_Payment_ID=?"; // 1
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Payment_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ BigDecimal bd = rs.getBigDecimal(1);
+ mTab.setValue("TrxAmt", bd);
+ if (stmt.compareTo(Env.ZERO) == 0)
+ mTab.setValue("StmtAmt", bd);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "BankStmt_Payment", e);
+ return e.getLocalizedMessage();
+ }
+ // Recalculate Amounts
+ amount (ctx, WindowNo, mTab, mField, value);
+ return "";
+ } // payment
+
+} // CalloutBankStatement
diff --git a/base/src/org/compiere/model/CalloutCashJournal.java b/base/src/org/compiere/model/CalloutCashJournal.java
new file mode 100644
index 0000000000..892674ecc3
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutCashJournal.java
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Cash Book Journal Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutCashJournal.java,v 1.3 2006/07/30 00:51:02 jjanke Exp $
+ */
+public class CalloutCashJournal extends CalloutEngine
+{
+ /**
+ * Cash Journal Line Invoice.
+ * when Invoice selected
+ * - set C_Currency, DiscountAnt, Amount, WriteOffAmt
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String invoice (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive()) // assuming it is resetting value
+ return "";
+ setCalloutActive(true);
+
+ Integer C_Invoice_ID = (Integer)value;
+ if (C_Invoice_ID == null || C_Invoice_ID.intValue() == 0)
+ {
+ mTab.setValue("C_Currency_ID", null);
+ setCalloutActive(false);
+ return "";
+ }
+
+ // Date
+ Timestamp ts = Env.getContextAsDate(ctx, WindowNo, "DateAcct"); // from C_Cash
+ if (ts == null)
+ ts = new Timestamp(System.currentTimeMillis());
+ //
+ String sql = "SELECT C_BPartner_ID, C_Currency_ID," // 1..2
+ + "invoiceOpen(C_Invoice_ID, 0), IsSOTrx, " // 3..4
+ + "paymentTermDiscount(invoiceOpen(C_Invoice_ID, 0),C_Currency_ID,C_PaymentTerm_ID,DateInvoiced,?) "
+ + "FROM C_Invoice WHERE C_Invoice_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setTimestamp(1, ts);
+ pstmt.setInt(2, C_Invoice_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue("C_Currency_ID", new Integer(rs.getInt(2)));
+ BigDecimal PayAmt = rs.getBigDecimal(3);
+ BigDecimal DiscountAmt = rs.getBigDecimal(5);
+ boolean isSOTrx = "Y".equals(rs.getString(4));
+ if (!isSOTrx)
+ {
+ PayAmt = PayAmt.negate();
+ DiscountAmt = DiscountAmt.negate();
+ }
+ //
+ mTab.setValue("Amount", PayAmt.subtract(DiscountAmt));
+ mTab.setValue("DiscountAmt", DiscountAmt);
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ Env.setContext(ctx, WindowNo, "InvTotalAmt", PayAmt.toString());
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "invoice", e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ setCalloutActive(false);
+ return "";
+ } // CashJournal_Invoice
+
+
+ /**
+ * Cash Journal Line Invoice Amounts.
+ * when DiscountAnt, Amount, WriteOffAmt change
+ * making sure that add up to InvTotalAmt (created by CashJournal_Invoice)
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String amounts (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ // Needs to be Invoice
+ if (isCalloutActive() || !"I".equals(mTab.getValue("CashType")))
+ return "";
+ // Check, if InvTotalAmt exists
+ String total = Env.getContext(ctx, WindowNo, "InvTotalAmt");
+ if (total == null || total.length() == 0)
+ return "";
+ BigDecimal InvTotalAmt = new BigDecimal(total);
+ setCalloutActive(true);
+
+ BigDecimal PayAmt = (BigDecimal)mTab.getValue("Amount");
+ BigDecimal DiscountAmt = (BigDecimal)mTab.getValue("DiscountAmt");
+ BigDecimal WriteOffAmt = (BigDecimal)mTab.getValue("WriteOffAmt");
+ String colName = mField.getColumnName();
+ log.fine(colName + " - Invoice=" + InvTotalAmt
+ + " - Amount=" + PayAmt + ", Discount=" + DiscountAmt + ", WriteOff=" + WriteOffAmt);
+
+ // Amount - calculate write off
+ if (colName.equals("Amount"))
+ {
+ WriteOffAmt = InvTotalAmt.subtract(PayAmt).subtract(DiscountAmt);
+ mTab.setValue("WriteOffAmt", WriteOffAmt);
+ }
+ else // calculate PayAmt
+ {
+ PayAmt = InvTotalAmt.subtract(DiscountAmt).subtract(WriteOffAmt);
+ mTab.setValue("Amount", PayAmt);
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // amounts
+
+} // CalloutCashJournal
diff --git a/base/src/org/compiere/model/CalloutEngine.java b/base/src/org/compiere/model/CalloutEngine.java
new file mode 100644
index 0000000000..c8828a5e85
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutEngine.java
@@ -0,0 +1,242 @@
+/******************************************************************************
+ * 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.model;
+
+import java.lang.reflect.*;
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Callout Emgine.
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutEngine.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutEngine implements Callout
+{
+ /**
+ * Constructor
+ */
+ public CalloutEngine()
+ {
+ super();
+ }
+
+ /** Logger */
+ protected CLogger log = CLogger.getCLogger(getClass());
+
+ /**
+ * Start Callout.
+ *
+ * Callout's are used for cross field validation and setting values in other fields
+ * when returning a non empty (error message) string, an exception is raised
+ *
+ * When invoked, the Tab model has the new value!
+ *
+ * @param ctx Context
+ * @param methodName Method name
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @param oldValue The old value
+ * @return Error message or ""
+ */
+ public String start (Properties ctx, String methodName, int WindowNo,
+ GridTab mTab, GridField mField, Object value, Object oldValue)
+ {
+ if (methodName == null || methodName.length() == 0)
+ throw new IllegalArgumentException ("No Method Name");
+ //
+ String retValue = "";
+ StringBuffer msg = new StringBuffer(methodName).append(" - ")
+ .append(mField.getColumnName())
+ .append("=").append(value)
+ .append(" (old=").append(oldValue)
+ .append(") {active=").append(isCalloutActive()).append("}");
+ if (!isCalloutActive())
+ log.info (msg.toString());
+
+ // Find Method
+ Method method = getMethod(methodName);
+ if (method == null)
+ throw new IllegalArgumentException ("Method not found: " + methodName);
+ int argLength = method.getParameterTypes().length;
+ if (!(argLength == 5 || argLength == 6))
+ throw new IllegalArgumentException ("Method " + methodName
+ + " has invalid no of arguments: " + argLength);
+
+ // Call Method
+ try
+ {
+ Object[] args = null;
+ if (argLength == 6)
+ args = new Object[] {ctx, new Integer(WindowNo), mTab, mField, value, oldValue};
+ else
+ args = new Object[] {ctx, new Integer(WindowNo), mTab, mField, value};
+ retValue = (String)method.invoke(this, args);
+ }
+ catch (Exception e)
+ {
+ setCalloutActive(false);
+ Throwable ex = e.getCause(); // InvocationTargetException
+ if (ex == null)
+ ex = e;
+ log.log(Level.SEVERE, "start: " + methodName, ex);
+ ex.printStackTrace(System.err);
+ retValue = ex.getLocalizedMessage();
+ }
+ return retValue;
+ } // start
+
+ /**
+ * Conversion Rules.
+ * Convert a String
+ *
+ * @param methodName method name
+ * @param value the value
+ * @return converted String or Null if no method found
+ */
+ public String convert (String methodName, String value)
+ {
+ if (methodName == null || methodName.length() == 0)
+ throw new IllegalArgumentException ("No Method Name");
+ //
+ String retValue = null;
+ StringBuffer msg = new StringBuffer(methodName).append(" - ").append(value);
+ log.info (msg.toString());
+ //
+ // Find Method
+ Method method = getMethod(methodName);
+ if (method == null)
+ throw new IllegalArgumentException ("Method not found: " + methodName);
+ int argLength = method.getParameterTypes().length;
+ if (argLength != 1)
+ throw new IllegalArgumentException ("Method " + methodName
+ + " has invalid no of arguments: " + argLength);
+
+ // Call Method
+ try
+ {
+ Object[] args = new Object[] {value};
+ retValue = (String)method.invoke(this, args);
+ }
+ catch (Exception e)
+ {
+ setCalloutActive(false);
+ log.log(Level.SEVERE, "convert: " + methodName, e);
+ e.printStackTrace(System.err);
+ }
+ return retValue;
+ } // convert
+
+ /**
+ * Get Method
+ * @param methodName method name
+ * @return method or null
+ */
+ private Method getMethod (String methodName)
+ {
+ Method[] allMethods = getClass().getMethods();
+ for (int i = 0; i < allMethods.length; i++)
+ {
+ if (methodName.equals(allMethods[i].getName()))
+ return allMethods[i];
+ }
+ return null;
+ } // getMethod
+
+ /*************************************************************************/
+
+ private static boolean s_calloutActive = false;
+
+ /**
+ * Is Callout Active
+ * @return true if active
+ */
+ protected static boolean isCalloutActive()
+ {
+ return s_calloutActive;
+ } // isCalloutActive
+
+ /**
+ * Set Callout (in)active
+ * @param active active
+ */
+ protected static void setCalloutActive (boolean active)
+ {
+ s_calloutActive = active;
+ } // setCalloutActive
+
+ /**
+ * Set Account Date Value.
+ * org.compiere.model.CalloutEngine.dateAcct
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String dateAcct (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive()) // assuming it is resetting value
+ return "";
+ // setCalloutActive(true);
+ if (value == null || !(value instanceof Timestamp))
+ return "";
+ mTab.setValue("DateAcct", value);
+ // setCalloutActive(false);
+ return "";
+ } // dateAcct
+
+ /**
+ * Rate - set Multiply Rate from Divide Rate and vice versa
+ * org.compiere.model.CalloutEngine.rate
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String rate (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null) // assuming it is Conversion_Rate
+ return "";
+ setCalloutActive(true);
+
+ BigDecimal rate1 = (BigDecimal)value;
+ BigDecimal rate2 = Env.ZERO;
+ BigDecimal one = new BigDecimal(1.0);
+
+ if (rate1.doubleValue() != 0.0) // no divide by zero
+ rate2 = one.divide(rate1, 12, BigDecimal.ROUND_HALF_UP);
+ //
+ if (mField.getColumnName().equals("MultiplyRate"))
+ mTab.setValue("DivideRate", rate2);
+ else
+ mTab.setValue("MultiplyRate", rate2);
+ log.info(mField.getColumnName() + "=" + rate1 + " => " + rate2);
+ setCalloutActive(false);
+ return "";
+ } // rate
+
+} // CalloutEngine
diff --git a/base/src/org/compiere/model/CalloutGLJournal.java b/base/src/org/compiere/model/CalloutGLJournal.java
new file mode 100644
index 0000000000..86645a0216
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutGLJournal.java
@@ -0,0 +1,227 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * GL Journal Callout
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutGLJournal.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutGLJournal extends CalloutEngine
+{
+ /**
+ * Journal - Period.
+ * Check that selected period is in DateAcct Range or Adjusting Period
+ * Called when C_Period_ID or DateAcct, DateDoc changed
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String period (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String colName = mField.getColumnName();
+ if (value == null || isCalloutActive())
+ return "";
+ setCalloutActive(true);
+
+ int AD_Client_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Client_ID");
+ Timestamp DateAcct = null;
+ if (colName.equals("DateAcct"))
+ DateAcct = (Timestamp)value;
+ else
+ DateAcct = (Timestamp)mTab.getValue("DateAcct");
+ int C_Period_ID = 0;
+ if (colName.equals("C_Period_ID"))
+ C_Period_ID = ((Integer)value).intValue();
+
+ // When DateDoc is changed, update DateAcct
+ if (colName.equals("DateDoc"))
+ {
+ mTab.setValue("DateAcct", value);
+ }
+
+ // When DateAcct is changed, set C_Period_ID
+ else if (colName.equals("DateAcct"))
+ {
+ String sql = "SELECT C_Period_ID "
+ + "FROM C_Period "
+ + "WHERE C_Year_ID IN "
+ + " (SELECT C_Year_ID FROM C_Year WHERE C_Calendar_ID ="
+ + " (SELECT C_Calendar_ID FROM AD_ClientInfo WHERE AD_Client_ID=?))"
+ + " AND ? BETWEEN StartDate AND EndDate"
+ // globalqss - cruiz - Bug [ 1577712 ] Financial Period Bug
+ + " AND IsActive='Y'"
+ + " AND PeriodType='S'";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, AD_Client_ID);
+ pstmt.setTimestamp(2, DateAcct);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ C_Period_ID = rs.getInt(1);
+ rs.close();
+ pstmt.close();
+ pstmt = null;
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ if (C_Period_ID != 0)
+ mTab.setValue("C_Period_ID", new Integer(C_Period_ID));
+ }
+
+ // When C_Period_ID is changed, check if in DateAcct range and set to end date if not
+ else
+ {
+ String sql = "SELECT PeriodType, StartDate, EndDate "
+ + "FROM C_Period WHERE C_Period_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Period_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ String PeriodType = rs.getString(1);
+ Timestamp StartDate = rs.getTimestamp(2);
+ Timestamp EndDate = rs.getTimestamp(3);
+ if (PeriodType.equals("S")) // Standard Periods
+ {
+ // out of range - set to last day
+ if (DateAcct == null
+ || DateAcct.before(StartDate) || DateAcct.after(EndDate))
+ mTab.setValue("DateAcct", EndDate);
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ }
+ setCalloutActive(false);
+ return "";
+ } // Journal_Period
+
+ /**
+ * Journal/Line - rate.
+ * Set CurrencyRate from DateAcct, C_ConversionType_ID, C_Currency_ID
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String rate (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (value == null)
+ return "";
+
+ // Source info
+ Integer Currency_ID = (Integer)mTab.getValue("C_Currency_ID");
+ int C_Currency_ID = Currency_ID.intValue();
+ Integer ConversionType_ID = (Integer)mTab.getValue("C_ConversionType_ID");
+ int C_ConversionType_ID = ConversionType_ID.intValue();
+ Timestamp DateAcct = (Timestamp)mTab.getValue("DateAcct");
+ if (DateAcct == null)
+ DateAcct = new Timestamp(System.currentTimeMillis());
+ //
+ int C_AcctSchema_ID = Env.getContextAsInt(ctx, WindowNo, "C_AcctSchema_ID");
+ MAcctSchema as = MAcctSchema.get (ctx, C_AcctSchema_ID);
+ int AD_Client_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Client_ID");
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+
+ BigDecimal CurrencyRate = MConversionRate.getRate(C_Currency_ID, as.getC_Currency_ID(),
+ DateAcct, C_ConversionType_ID, AD_Client_ID, AD_Org_ID);
+ log.fine("rate = " + CurrencyRate);
+ if (CurrencyRate == null)
+ CurrencyRate = Env.ZERO;
+ mTab.setValue("CurrencyRate", CurrencyRate);
+
+ return "";
+ } // rate
+
+ /**
+ * JournalLine - Amt.
+ * Convert the source amount to accounted amount (AmtAcctDr/Cr)
+ * Called when source amount (AmtSourceCr/Dr) or rate changes
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String amt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String colName = mField.getColumnName();
+ if (value == null || isCalloutActive())
+ return "";
+
+ setCalloutActive(true);
+
+ // Get Target Currency & Precision from C_AcctSchema.C_Currency_ID
+ int C_AcctSchema_ID = Env.getContextAsInt(ctx, WindowNo, "C_AcctSchema_ID");
+ MAcctSchema as = MAcctSchema.get(ctx, C_AcctSchema_ID);
+ int Precision = as.getStdPrecision();
+
+ BigDecimal CurrencyRate = (BigDecimal)mTab.getValue("CurrencyRate");
+ if (CurrencyRate == null)
+ {
+ CurrencyRate = Env.ONE;
+ mTab.setValue("CurrencyRate", CurrencyRate);
+ }
+
+ // AmtAcct = AmtSource * CurrencyRate ==> Precision
+ BigDecimal AmtSourceDr = (BigDecimal)mTab.getValue("AmtSourceDr");
+ if (AmtSourceDr == null)
+ AmtSourceDr = Env.ZERO;
+ BigDecimal AmtSourceCr = (BigDecimal)mTab.getValue("AmtSourceCr");
+ if (AmtSourceCr == null)
+ AmtSourceCr = Env.ZERO;
+
+ BigDecimal AmtAcctDr = AmtSourceDr.multiply(CurrencyRate);
+ AmtAcctDr = AmtAcctDr.setScale(Precision, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("AmtAcctDr", AmtAcctDr);
+ BigDecimal AmtAcctCr = AmtSourceCr.multiply(CurrencyRate);
+ AmtAcctCr = AmtAcctCr.setScale(Precision, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("AmtAcctCr", AmtAcctCr);
+
+ setCalloutActive(false);
+ return "";
+ } // amt
+
+} // CalloutGLJournal
diff --git a/base/src/org/compiere/model/CalloutInOut.java b/base/src/org/compiere/model/CalloutInOut.java
new file mode 100644
index 0000000000..fa9ff5b845
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutInOut.java
@@ -0,0 +1,521 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+import com.sun.org.apache.bcel.internal.generic.*;
+
+
+/**
+ * Shipment/Receipt Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutInOut.java,v 1.7 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutInOut extends CalloutEngine
+{
+ /**
+ * C_Order - Order Defaults.
+ * @param ctx
+ * @param WindowNo
+ * @param mTab
+ * @param mField
+ * @param value
+ * @return error message or ""
+ */
+ public String order (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Order_ID = (Integer)value;
+ if (C_Order_ID == null || C_Order_ID.intValue() == 0)
+ return "";
+ // No Callout Active to fire dependent values
+ if (isCalloutActive()) // prevent recursive
+ return "";
+
+ // Get Details
+ MOrder order = new MOrder (ctx, C_Order_ID.intValue(), null);
+ if (order.get_ID() != 0)
+ {
+ mTab.setValue("DateOrdered", order.getDateOrdered());
+ mTab.setValue("POReference", order.getPOReference());
+ mTab.setValue("AD_Org_ID", new Integer(order.getAD_Org_ID()));
+ mTab.setValue("AD_OrgTrx_ID", new Integer(order.getAD_OrgTrx_ID()));
+ mTab.setValue("C_Activity_ID", new Integer(order.getC_Activity_ID()));
+ mTab.setValue("C_Campaign_ID", new Integer(order.getC_Campaign_ID()));
+ mTab.setValue("C_Project_ID", new Integer(order.getC_Project_ID()));
+ mTab.setValue("User1_ID", new Integer(order.getUser1_ID()));
+ mTab.setValue("User2_ID", new Integer(order.getUser2_ID()));
+ mTab.setValue("M_Warehouse_ID", new Integer(order.getM_Warehouse_ID()));
+ //
+ mTab.setValue("DeliveryRule", order.getDeliveryRule());
+ mTab.setValue("DeliveryViaRule", order.getDeliveryViaRule());
+ mTab.setValue("M_Shipper_ID", new Integer(order.getM_Shipper_ID()));
+ mTab.setValue("FreightCostRule", order.getFreightCostRule());
+ mTab.setValue("FreightAmt", order.getFreightAmt());
+
+ mTab.setValue("C_BPartner_ID", new Integer(order.getC_BPartner_ID()));
+ }
+ return "";
+ } // order
+
+
+ /**
+ * InOut - DocType.
+ * - sets MovementType
+ * - gets DocNo
+ * @param ctx
+ * @param WindowNo
+ * @param mTab
+ * @param mField
+ * @param value
+ * @return error message or ""
+ */
+ public String docType (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_DocType_ID = (Integer)value;
+ if (C_DocType_ID == null || C_DocType_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT d.DocBaseType, d.IsDocNoControlled, s.CurrentNext "
+ + "FROM C_DocType d, AD_Sequence s "
+ + "WHERE C_DocType_ID=?" // 1
+ + " AND d.DocNoSequence_ID=s.AD_Sequence_ID(+)";
+ try
+ {
+ Env.setContext(ctx, WindowNo, "C_DocTypeTarget_ID", C_DocType_ID.intValue());
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_DocType_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // Set Movement Type
+ String DocBaseType = rs.getString("DocBaseType");
+ if (DocBaseType.equals("MMS")) // Material Shipments
+ mTab.setValue("MovementType", "C-"); // Customer Shipments
+ else if (DocBaseType.equals("MMR")) // Material Receipts
+ mTab.setValue("MovementType", "V+"); // Vendor Receipts
+
+ // DocumentNo
+ if (rs.getString("IsDocNoControlled").equals("Y"))
+ mTab.setValue("DocumentNo", "<" + rs.getString("CurrentNext") + ">");
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ return "";
+ } // docType
+
+
+ /**
+ * M_InOut - Defaults for BPartner.
+ * - Location
+ * - Contact
+ * @param ctx
+ * @param WindowNo
+ * @param mTab
+ * @param mField
+ * @param value
+ * @return error message or ""
+ */
+ public String bpartner (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_BPartner_ID = (Integer)value;
+ if (C_BPartner_ID == null || C_BPartner_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT p.AD_Language,p.C_PaymentTerm_ID,"
+ + "p.M_PriceList_ID,p.PaymentRule,p.POReference,"
+ + "p.SO_Description,p.IsDiscountPrinted,"
+ + "p.SO_CreditLimit-p.SO_CreditUsed AS CreditAvailable,"
+ + "l.C_BPartner_Location_ID,c.AD_User_ID "
+ + "FROM C_BPartner p, C_BPartner_Location l, AD_User c "
+ + "WHERE p.C_BPartner_ID=l.C_BPartner_ID(+)"
+ + " AND p.C_BPartner_ID=c.C_BPartner_ID(+)"
+ + " AND p.C_BPartner_ID=?"; // 1
+
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_BPartner_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ BigDecimal bd;
+ if (rs.next())
+ {
+ // Location
+ Integer ii = new Integer(rs.getInt("C_BPartner_Location_ID"));
+ if (rs.wasNull())
+ mTab.setValue("C_BPartner_Location_ID", null);
+ else
+ mTab.setValue("C_BPartner_Location_ID", ii);
+ // Contact
+ ii = new Integer(rs.getInt("AD_User_ID"));
+ if (rs.wasNull())
+ mTab.setValue("AD_User_ID", null);
+ else
+ mTab.setValue("AD_User_ID", ii);
+
+ // CreditAvailable
+ double CreditAvailable = rs.getDouble("CreditAvailable");
+ if (!rs.wasNull() && CreditAvailable < 0)
+ mTab.fireDataStatusEEvent("CreditLimitOver",
+ DisplayType.getNumberFormat(DisplayType.Amount).format(CreditAvailable),
+ false);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+
+ return "";
+ } // bpartner
+
+ /**
+ * M_Warehouse.
+ * Set Organization and Default Locator
+ * @param ctx
+ * @param WindowNo
+ * @param mTab
+ * @param mField
+ * @param value
+ * @return error message or ""
+ */
+ public String warehouse (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ Integer M_Warehouse_ID = (Integer)value;
+ if (M_Warehouse_ID == null || M_Warehouse_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+
+ String sql = "SELECT w.AD_Org_ID, l.M_Locator_ID "
+ + "FROM M_Warehouse w"
+ + " LEFT OUTER JOIN M_Locator l ON (l.M_Warehouse_ID=w.M_Warehouse_ID AND l.IsDefault='Y') "
+ + "WHERE w.M_Warehouse_ID=?"; // 1
+
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, M_Warehouse_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ BigDecimal bd;
+ if (rs.next())
+ {
+ // Org
+ Integer ii = new Integer(rs.getInt(1));
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+ if (AD_Org_ID != ii.intValue())
+ mTab.setValue("AD_Org_ID", ii);
+ // Locator
+ ii = new Integer(rs.getInt(2));
+ if (rs.wasNull())
+ Env.setContext(ctx, WindowNo, 0, "M_Locator_ID", null);
+ else
+ {
+ log.config("M_Locator_ID=" + ii);
+ Env.setContext(ctx, WindowNo, "M_Locator_ID", ii.intValue());
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // warehouse
+
+
+ /**************************************************************************
+ * OrderLine Callout
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab model
+ * @param mField field model
+ * @param value new value
+ * @return error message or ""
+ */
+ public String orderLine (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_OrderLine_ID = (Integer)value;
+ if (C_OrderLine_ID == null || C_OrderLine_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+
+ // Get Details
+ MOrderLine ol = new MOrderLine (ctx, C_OrderLine_ID.intValue(), null);
+ if (ol.get_ID() != 0)
+ {
+ mTab.setValue("M_Product_ID", new Integer(ol.getM_Product_ID()));
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(ol.getM_AttributeSetInstance_ID()));
+ //
+ mTab.setValue("C_UOM_ID", new Integer(ol.getC_UOM_ID()));
+ BigDecimal MovementQty = ol.getQtyOrdered().subtract(ol.getQtyDelivered());
+ mTab.setValue("MovementQty", MovementQty);
+ BigDecimal QtyEntered = MovementQty;
+ if (ol.getQtyEntered().compareTo(ol.getQtyOrdered()) != 0)
+ QtyEntered = QtyEntered.multiply(ol.getQtyEntered())
+ .divide(ol.getQtyOrdered(), 12, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("QtyEntered", QtyEntered);
+ //
+ mTab.setValue("C_Activity_ID", new Integer(ol.getC_Activity_ID()));
+ mTab.setValue("C_Campaign_ID", new Integer(ol.getC_Campaign_ID()));
+ mTab.setValue("C_Project_ID", new Integer(ol.getC_Project_ID()));
+ mTab.setValue("C_ProjectPhase_ID", new Integer(ol.getC_ProjectPhase_ID()));
+ mTab.setValue("C_ProjectTask_ID", new Integer(ol.getC_ProjectTask_ID()));
+ mTab.setValue("AD_OrgTrx_ID", new Integer(ol.getAD_OrgTrx_ID()));
+ mTab.setValue("User1_ID", new Integer(ol.getUser1_ID()));
+ mTab.setValue("User2_ID", new Integer(ol.getUser2_ID()));
+ }
+ setCalloutActive(false);
+ return "";
+ } // orderLine
+
+ /**
+ * M_InOutLine - Default UOM/Locator for Product.
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab model
+ * @param mField field model
+ * @param value new value
+ * @return error message or ""
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+
+ // Set Attribute & Locator
+ int M_Locator_ID = 0;
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ {
+ mTab.setValue("M_AttributeSetInstance_ID",
+ new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ M_Locator_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Locator_ID");
+ if (M_Locator_ID != 0)
+ mTab.setValue("M_Locator_ID", new Integer(M_Locator_ID));
+ }
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ //
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID");
+ boolean IsSOTrx = "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx"));
+ if (IsSOTrx)
+ {
+ setCalloutActive(false);
+ return "";
+ }
+
+ // Set UOM/Locator/Qty
+ MProduct product = MProduct.get(ctx, M_Product_ID.intValue());
+ mTab.setValue("C_UOM_ID", new Integer (product.getC_UOM_ID()));
+ BigDecimal QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ mTab.setValue("MovementQty", QtyEntered);
+ if (M_Locator_ID != 0)
+ ; // already set
+ else if (product.getM_Locator_ID() != 0)
+ {
+ MLocator loc = MLocator.get(ctx, product.getM_Locator_ID());
+ if (M_Warehouse_ID == loc.getM_Warehouse_ID())
+ mTab.setValue("M_Locator_ID", new Integer (product.getM_Locator_ID()));
+ else
+ log.fine("No Locator for M_Product_ID=" + M_Product_ID + " and M_Warehouse_ID=" + M_Warehouse_ID);
+ }
+ else
+ log.fine("No Locator for M_Product_ID=" + M_Product_ID);
+ setCalloutActive(false);
+ return "";
+ } // product
+
+ /**
+ * InOut Line - Quantity.
+ * - called from C_UOM_ID, QtyEntered, MovementQty
+ * - enforces qty UOM relationship
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab model
+ * @param mField field model
+ * @param value new value
+ * @return error message or ""
+ */
+ public String qty (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ // log.log(Level.WARNING,"qty - init - M_Product_ID=" + M_Product_ID);
+ BigDecimal MovementQty, QtyEntered;
+
+ // No Product
+ if (M_Product_ID == 0)
+ {
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ mTab.setValue("MovementQty", QtyEntered);
+ }
+ // UOM Changed - convert from Entered -> Product
+ else if (mField.getColumnName().equals("C_UOM_ID"))
+ {
+ int C_UOM_To_ID = ((Integer)value).intValue();
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ MovementQty = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (MovementQty == null)
+ MovementQty = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(MovementQty) != 0;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", QtyEntered=" + QtyEntered
+ + " -> " + conversion
+ + " MovementQty=" + MovementQty);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("MovementQty", MovementQty);
+ }
+ // No UOM defined
+ else if (Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID") == 0)
+ {
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ mTab.setValue("MovementQty", QtyEntered);
+ }
+ // QtyEntered changed - calculate MovementQty
+ else if (mField.getColumnName().equals("QtyEntered"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ QtyEntered = (BigDecimal)value;
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ MovementQty = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (MovementQty == null)
+ MovementQty = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(MovementQty) != 0;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", QtyEntered=" + QtyEntered
+ + " -> " + conversion
+ + " MovementQty=" + MovementQty);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("MovementQty", MovementQty);
+ }
+ // MovementQty changed - calculate QtyEntered (should not happen)
+ else if (mField.getColumnName().equals("MovementQty"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ MovementQty = (BigDecimal)value;
+ int precision = MProduct.get(ctx, M_Product_ID).getUOMPrecision();
+ BigDecimal MovementQty1 = MovementQty.setScale(precision, BigDecimal.ROUND_HALF_UP);
+ if (MovementQty.compareTo(MovementQty1) != 0)
+ {
+ log.fine("Corrected MovementQty "
+ + MovementQty + "->" + MovementQty1);
+ MovementQty = MovementQty1;
+ mTab.setValue("MovementQty", MovementQty);
+ }
+ QtyEntered = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, MovementQty);
+ if (QtyEntered == null)
+ QtyEntered = MovementQty;
+ boolean conversion = MovementQty.compareTo(QtyEntered) != 0;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", MovementQty=" + MovementQty
+ + " -> " + conversion
+ + " QtyEntered=" + QtyEntered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ //
+ setCalloutActive(false);
+ return "";
+ } // qty
+
+ /**
+ * M_InOutLine - ASI.
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab model
+ * @param mField field model
+ * @param value new value
+ * @return error message or ""
+ */
+ public String asi (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ Integer M_ASI_ID = (Integer)value;
+ if (M_ASI_ID == null || M_ASI_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ //
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID");
+ int M_Locator_ID = Env.getContextAsInt(ctx, WindowNo, "M_Locator_ID");
+ log.fine("M_Product_ID=" + M_Product_ID
+ + ", M_ASI_ID=" + M_ASI_ID
+ + " - M_Warehouse_ID=" + M_Warehouse_ID
+ + ", M_Locator_ID=" + M_Locator_ID);
+ // Check Selection
+ int M_AttributeSetInstance_ID = Env.getContextAsInt(Env.getCtx(), Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID");
+ if (M_ASI_ID.intValue() == M_AttributeSetInstance_ID)
+ {
+ int selectedM_Locator_ID = Env.getContextAsInt(Env.getCtx(), Env.WINDOW_INFO, Env.TAB_INFO, "M_Locator_ID");
+ if (selectedM_Locator_ID != 0)
+ {
+ log.fine("Selected M_Locator_ID=" + selectedM_Locator_ID);
+ mTab.setValue("M_Locator_ID", new Integer (selectedM_Locator_ID));
+ }
+ }
+ setCalloutActive(false);
+ return "";
+ } // asi
+
+} // CalloutInOut
diff --git a/base/src/org/compiere/model/CalloutInventory.java b/base/src/org/compiere/model/CalloutInventory.java
new file mode 100644
index 0000000000..6f5caa37bb
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutInventory.java
@@ -0,0 +1,124 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Physical Inventory Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutInventory.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutInventory extends CalloutEngine
+{
+ /**
+ * Product/Locator/ASI modified.
+ * Set Attribute Set Instance
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ Integer InventoryLine = (Integer)mTab.getValue("M_InventoryLine_ID");
+ if (InventoryLine != null && InventoryLine.intValue() != 0)
+ return "";
+
+ // New Line - Get Book Value
+ int M_Product_ID = 0;
+ Integer Product = (Integer)mTab.getValue("M_Product_ID");
+ if (Product != null)
+ M_Product_ID = Product.intValue();
+ if (M_Product_ID == 0)
+ return "";
+ int M_Locator_ID = 0;
+ Integer Locator = (Integer)mTab.getValue("M_Locator_ID");
+ if (Locator != null)
+ M_Locator_ID = Locator.intValue();
+ if (M_Locator_ID == 0)
+ return "";
+
+ setCalloutActive(true);
+ // Set Attribute
+ int M_AttributeSetInstance_ID = 0;
+ Integer ASI = (Integer)mTab.getValue("M_AttributeSetInstance_ID");
+ if (ASI != null)
+ M_AttributeSetInstance_ID = ASI.intValue();
+ // Product Selection
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID)
+ {
+ M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID");
+ if (M_AttributeSetInstance_ID != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(M_AttributeSetInstance_ID));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ }
+
+ // Set QtyBook from first storage location
+ BigDecimal bd = null;
+ String sql = "SELECT QtyOnHand FROM M_Storage "
+ + "WHERE M_Product_ID=?" // 1
+ + " AND M_Locator_ID=?" // 2
+ + " AND M_AttributeSetInstance_ID=?";
+ if (M_AttributeSetInstance_ID == 0)
+ sql = "SELECT SUM(QtyOnHand) FROM M_Storage "
+ + "WHERE M_Product_ID=?" // 1
+ + " AND M_Locator_ID=?"; // 2
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, M_Product_ID);
+ pstmt.setInt(2, M_Locator_ID);
+ if (M_AttributeSetInstance_ID != 0)
+ pstmt.setInt(3, M_AttributeSetInstance_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ bd = rs.getBigDecimal(1);
+ if (bd != null)
+ mTab.setValue("QtyBook", bd);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ //
+ log.info("M_Product_ID=" + M_Product_ID
+ + ", M_Locator_ID=" + M_Locator_ID
+ + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID
+ + " - QtyBook=" + bd);
+ setCalloutActive(false);
+ return "";
+ } // product
+
+} // CalloutInventory
diff --git a/base/src/org/compiere/model/CalloutInvoice.java b/base/src/org/compiere/model/CalloutInvoice.java
new file mode 100644
index 0000000000..2e05b0b229
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutInvoice.java
@@ -0,0 +1,764 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Invoice Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutInvoice.java,v 1.4 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutInvoice extends CalloutEngine
+{
+
+ /**
+ * Invoice Header - DocType.
+ * - PaymentRule
+ * - temporary Document
+ * Context:
+ * - DocSubTypeSO
+ * - HasCharges
+ * - (re-sets Business Partner info of required)
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String docType (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_DocType_ID = (Integer)value;
+ if (C_DocType_ID == null || C_DocType_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT d.HasCharges,'N',d.IsDocNoControlled,"
+ + "s.CurrentNext, d.DocBaseType "
+ + "FROM C_DocType d, AD_Sequence s "
+ + "WHERE C_DocType_ID=?" // 1
+ + " AND d.DocNoSequence_ID=s.AD_Sequence_ID(+)";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_DocType_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // Charges - Set Context
+ Env.setContext(ctx, WindowNo, "HasCharges", rs.getString(1));
+ // DocumentNo
+ if (rs.getString(3).equals("Y"))
+ mTab.setValue("DocumentNo", "<" + rs.getString(4) + ">");
+ // DocBaseType - Set Context
+ String s = rs.getString(5);
+ Env.setContext(ctx, WindowNo, "DocBaseType", s);
+ // AP Check & AR Credit Memo
+ if (s.startsWith("AP"))
+ mTab.setValue("PaymentRule", "S"); // Check
+ else if (s.endsWith("C"))
+ mTab.setValue("PaymentRule", "P"); // OnCredit
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ return "";
+ } // docType
+
+
+ /**
+ * Invoice Header- BPartner.
+ * - M_PriceList_ID (+ Context)
+ * - C_BPartner_Location_ID
+ * - AD_User_ID
+ * - POReference
+ * - SO_Description
+ * - IsDiscountPrinted
+ * - PaymentRule
+ * - C_PaymentTerm_ID
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String bPartner (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_BPartner_ID = (Integer)value;
+ if (C_BPartner_ID == null || C_BPartner_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT p.AD_Language,p.C_PaymentTerm_ID,"
+ + " COALESCE(p.M_PriceList_ID,g.M_PriceList_ID) AS M_PriceList_ID, p.PaymentRule,p.POReference,"
+ + " p.SO_Description,p.IsDiscountPrinted,"
+ + " p.SO_CreditLimit, p.SO_CreditLimit-p.SO_CreditUsed AS CreditAvailable,"
+ + " l.C_BPartner_Location_ID,c.AD_User_ID,"
+ + " COALESCE(p.PO_PriceList_ID,g.PO_PriceList_ID) AS PO_PriceList_ID, p.PaymentRulePO,p.PO_PaymentTerm_ID "
+ + "FROM C_BPartner p"
+ + " INNER JOIN C_BP_Group g ON (p.C_BP_Group_ID=g.C_BP_Group_ID)"
+ + " LEFT OUTER JOIN C_BPartner_Location l ON (p.C_BPartner_ID=l.C_BPartner_ID AND l.IsBillTo='Y' AND l.IsActive='Y')"
+ + " LEFT OUTER JOIN AD_User c ON (p.C_BPartner_ID=c.C_BPartner_ID) "
+ + "WHERE p.C_BPartner_ID=? AND p.IsActive='Y'"; // #1
+
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_BPartner_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ //
+ if (rs.next())
+ {
+ // PriceList & IsTaxIncluded & Currency
+ Integer ii = new Integer(rs.getInt(IsSOTrx ? "M_PriceList_ID" : "PO_PriceList_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("M_PriceList_ID", ii);
+ else
+ { // get default PriceList
+ int i = Env.getContextAsInt(ctx, "#M_PriceList_ID");
+ if (i != 0)
+ mTab.setValue("M_PriceList_ID", new Integer(i));
+ }
+
+ // PaymentRule
+ String s = rs.getString(IsSOTrx ? "PaymentRule" : "PaymentRulePO");
+ if (s != null && s.length() != 0)
+ {
+ if (Env.getContext(ctx, WindowNo, "DocBaseType").endsWith("C")) // Credits are Payment Term
+ s = "P";
+ else if (IsSOTrx && (s.equals("S") || s.equals("U"))) // No Check/Transfer for SO_Trx
+ s = "P"; // Payment Term
+ mTab.setValue("PaymentRule", s);
+ }
+ // Payment Term
+ ii = new Integer(rs.getInt(IsSOTrx ? "C_PaymentTerm_ID" : "PO_PaymentTerm_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_PaymentTerm_ID", ii);
+
+ // Location
+ int locID = rs.getInt("C_BPartner_Location_ID");
+ // overwritten by InfoBP selection - works only if InfoWindow
+ // was used otherwise creates error (uses last value, may belong to differnt BP)
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String loc = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_Location_ID");
+ if (loc.length() > 0)
+ locID = Integer.parseInt(loc);
+ }
+ if (locID == 0)
+ mTab.setValue("C_BPartner_Location_ID", null);
+ else
+ mTab.setValue("C_BPartner_Location_ID", new Integer(locID));
+
+ // Contact - overwritten by InfoBP selection
+ int contID = rs.getInt("AD_User_ID");
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String cont = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "AD_User_ID");
+ if (cont.length() > 0)
+ contID = Integer.parseInt(cont);
+ }
+ if (contID == 0)
+ mTab.setValue("AD_User_ID", null);
+ else
+ mTab.setValue("AD_User_ID", new Integer(contID));
+
+ // CreditAvailable
+ if (IsSOTrx)
+ {
+ double CreditLimit = rs.getDouble("SO_CreditLimit");
+ if (CreditLimit != 0)
+ {
+ double CreditAvailable = rs.getDouble("CreditAvailable");
+ if (!rs.wasNull() && CreditAvailable < 0)
+ mTab.fireDataStatusEEvent("CreditLimitOver",
+ DisplayType.getNumberFormat(DisplayType.Amount).format(CreditAvailable),
+ false);
+ }
+ }
+
+ // PO Reference
+ s = rs.getString("POReference");
+ if (s != null && s.length() != 0)
+ mTab.setValue("POReference", s);
+ else
+ mTab.setValue("POReference", null);
+ // SO Description
+ s = rs.getString("SO_Description");
+ if (s != null && s.trim().length() != 0)
+ mTab.setValue("Description", s);
+ // IsDiscountPrinted
+ s = rs.getString("IsDiscountPrinted");
+ if (s != null && s.length() != 0)
+ mTab.setValue("IsDiscountPrinted", s);
+ else
+ mTab.setValue("IsDiscountPrinted", "N");
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "bPartner", e);
+ return e.getLocalizedMessage();
+ }
+
+ return "";
+ } // bPartner
+
+ /**
+ * Set Payment Term.
+ * Payment Term has changed
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String paymentTerm (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_PaymentTerm_ID = (Integer)value;
+ int C_Invoice_ID = Env.getContextAsInt(ctx, WindowNo, "C_Invoice_ID");
+ if (C_PaymentTerm_ID == null || C_PaymentTerm_ID.intValue() == 0
+ || C_Invoice_ID == 0) // not saved yet
+ return "";
+ //
+ MPaymentTerm pt = new MPaymentTerm (ctx, C_PaymentTerm_ID.intValue(), null);
+ if (pt.get_ID() == 0)
+ return "PaymentTerm not found";
+
+ boolean valid = pt.apply (C_Invoice_ID);
+ mTab.setValue("IsPayScheduleValid", valid ? "Y" : "N");
+
+ return "";
+ } // paymentTerm
+
+
+ /**************************************************************************
+ * Invoice Line - Product.
+ * - reset C_Charge_ID / M_AttributeSetInstance_ID
+ * - PriceList, PriceStd, PriceLimit, C_Currency_ID, EnforcePriceLimit
+ * - UOM
+ * Calls Tax
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ mTab.setValue("C_Charge_ID", null);
+
+ // Set Attribute
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+
+ /***** Price Calculation see also qty ****/
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, WindowNo, "C_BPartner_ID");
+ BigDecimal Qty = (BigDecimal)mTab.getValue("QtyInvoiced");
+ MProductPricing pp = new MProductPricing (M_Product_ID.intValue(), C_BPartner_ID, Qty, IsSOTrx);
+ //
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp date = Env.getContextAsDate(ctx, WindowNo, "DateInvoiced");
+ pp.setPriceDate(date);
+ //
+ mTab.setValue("PriceList", pp.getPriceList());
+ mTab.setValue("PriceLimit", pp.getPriceLimit());
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ mTab.setValue("PriceEntered", pp.getPriceStd());
+ mTab.setValue("C_Currency_ID", new Integer(pp.getC_Currency_ID()));
+ // mTab.setValue("Discount", pp.getDiscount());
+ mTab.setValue("C_UOM_ID", new Integer(pp.getC_UOM_ID()));
+ Env.setContext(ctx, WindowNo, "EnforcePriceLimit", pp.isEnforcePriceLimit() ? "Y" : "N");
+ Env.setContext(ctx, WindowNo, "DiscountSchema", pp.isDiscountSchema() ? "Y" : "N");
+ //
+ setCalloutActive(false);
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // product
+
+ /**
+ * Invoice Line - Charge.
+ * - updates PriceActual from Charge
+ * - sets PriceLimit, PriceList to zero
+ * Calles tax
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String charge (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Charge_ID = (Integer)value;
+ if (C_Charge_ID == null || C_Charge_ID.intValue() == 0)
+ return "";
+
+ // No Product defined
+ if (mTab.getValue("M_Product_ID") != null)
+ {
+ mTab.setValue("C_Charge_ID", null);
+ return "ChargeExclusively";
+ }
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ mTab.setValue("S_ResourceAssignment_ID", null);
+ mTab.setValue("C_UOM_ID", new Integer(100)); // EA
+
+ Env.setContext(ctx, WindowNo, "DiscountSchema", "N");
+ String sql = "SELECT ChargeAmt FROM C_Charge WHERE C_Charge_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Charge_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue ("PriceEntered", rs.getBigDecimal (1));
+ mTab.setValue ("PriceActual", rs.getBigDecimal (1));
+ mTab.setValue ("PriceLimit", Env.ZERO);
+ mTab.setValue ("PriceList", Env.ZERO);
+ mTab.setValue ("Discount", Env.ZERO);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql + e);
+ return e.getLocalizedMessage();
+ }
+ //
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // charge
+
+
+ /**
+ * Invoice Line - Tax.
+ * - basis: Product, Charge, BPartner Location
+ * - sets C_Tax_ID
+ * Calles Amount
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String tax (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String column = mField.getColumnName();
+ if (value == null)
+ return "";
+
+ // Check Product
+ int M_Product_ID = 0;
+ if (column.equals("M_Product_ID"))
+ M_Product_ID = ((Integer)value).intValue();
+ else
+ M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ int C_Charge_ID = 0;
+ if (column.equals("C_Charge_ID"))
+ C_Charge_ID = ((Integer)value).intValue();
+ else
+ C_Charge_ID = Env.getContextAsInt(ctx, WindowNo, "C_Charge_ID");
+ log.fine("Product=" + M_Product_ID + ", C_Charge_ID=" + C_Charge_ID);
+ if (M_Product_ID == 0 && C_Charge_ID == 0)
+ return amt (ctx, WindowNo, mTab, mField, value); //
+
+ // Check Partner Location
+ int shipC_BPartner_Location_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_Location_ID");
+ if (shipC_BPartner_Location_ID == 0)
+ return amt (ctx, WindowNo, mTab, mField, value); //
+ log.fine("Ship BP_Location=" + shipC_BPartner_Location_ID);
+ int billC_BPartner_Location_ID = shipC_BPartner_Location_ID;
+ log.fine("Bill BP_Location=" + billC_BPartner_Location_ID);
+
+ // Dates
+ Timestamp billDate = Env.getContextAsDate(ctx, WindowNo, "DateInvoiced");
+ log.fine("Bill Date=" + billDate);
+ Timestamp shipDate = billDate;
+ log.fine("Ship Date=" + shipDate);
+
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+ log.fine("Org=" + AD_Org_ID);
+
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, "#M_Warehouse_ID");
+ log.fine("Warehouse=" + M_Warehouse_ID);
+
+ //
+ int C_Tax_ID = Tax.get(ctx, M_Product_ID, C_Charge_ID, billDate, shipDate,
+ AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID,
+ Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"));
+ log.info("Tax ID=" + C_Tax_ID);
+ //
+ if (C_Tax_ID == 0)
+ mTab.fireDataStatusEEvent(CLogger.retrieveError());
+ else
+ mTab.setValue("C_Tax_ID", new Integer(C_Tax_ID));
+ //
+ return amt (ctx, WindowNo, mTab, mField, value);
+ } // tax
+
+
+ /**
+ * Invoice - Amount.
+ * - called from QtyInvoiced, PriceActual
+ * - calculates LineNetAmt
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String amt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ // log.log(Level.WARNING,"amt - init");
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ int StdPrecision = MPriceList.getStandardPrecision(ctx, M_PriceList_ID);
+ BigDecimal QtyEntered, QtyInvoiced, PriceEntered, PriceActual, PriceLimit, Discount, PriceList;
+ // get values
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ QtyInvoiced = (BigDecimal)mTab.getValue("QtyInvoiced");
+ log.fine("QtyEntered=" + QtyEntered + ", Invoiced=" + QtyInvoiced + ", UOM=" + C_UOM_To_ID);
+ //
+ PriceEntered = (BigDecimal)mTab.getValue("PriceEntered");
+ PriceActual = (BigDecimal)mTab.getValue("PriceActual");
+ // Discount = (BigDecimal)mTab.getValue("Discount");
+ PriceLimit = (BigDecimal)mTab.getValue("PriceLimit");
+ PriceList = (BigDecimal)mTab.getValue("PriceList");
+ log.fine("PriceList=" + PriceList + ", Limit=" + PriceLimit + ", Precision=" + StdPrecision);
+ log.fine("PriceEntered=" + PriceEntered + ", Actual=" + PriceActual);// + ", Discount=" + Discount);
+
+ // Qty changed - recalc price
+ if ((mField.getColumnName().equals("QtyInvoiced")
+ || mField.getColumnName().equals("QtyEntered")
+ || mField.getColumnName().equals("M_Product_ID"))
+ && !"N".equals(Env.getContext(ctx, WindowNo, "DiscountSchema")))
+ {
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID");
+ if (mField.getColumnName().equals("QtyEntered"))
+ QtyInvoiced = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyInvoiced == null)
+ QtyInvoiced = QtyEntered;
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ MProductPricing pp = new MProductPricing (M_Product_ID, C_BPartner_ID, QtyInvoiced, IsSOTrx);
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp date = (Timestamp)mTab.getValue("DateInvoiced");
+ pp.setPriceDate(date);
+ //
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, pp.getPriceStd());
+ if (PriceEntered == null)
+ PriceEntered = pp.getPriceStd();
+ //
+ log.fine("amt - QtyChanged -> PriceActual=" + pp.getPriceStd()
+ + ", PriceEntered=" + PriceEntered + ", Discount=" + pp.getDiscount());
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ // mTab.setValue("Discount", pp.getDiscount());
+ mTab.setValue("PriceEntered", PriceEntered);
+ Env.setContext(ctx, WindowNo, "DiscountSchema", pp.isDiscountSchema() ? "Y" : "N");
+ }
+ else if (mField.getColumnName().equals("PriceActual"))
+ {
+ PriceActual = (BigDecimal)value;
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ //
+ log.fine("amt - PriceActual=" + PriceActual
+ + " -> PriceEntered=" + PriceEntered);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ else if (mField.getColumnName().equals("PriceEntered"))
+ {
+ PriceEntered = (BigDecimal)value;
+ PriceActual = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceEntered);
+ if (PriceActual == null)
+ PriceActual = PriceEntered;
+ //
+ log.fine("amt - PriceEntered=" + PriceEntered
+ + " -> PriceActual=" + PriceActual);
+ mTab.setValue("PriceActual", PriceActual);
+ }
+
+ /** Discount entered - Calculate Actual/Entered
+ if (mField.getColumnName().equals("Discount"))
+ {
+ PriceActual = new BigDecimal ((100.0 - Discount.doubleValue()) / 100.0 * PriceList.doubleValue());
+ if (PriceActual.scale() > StdPrecision)
+ PriceActual = PriceActual.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ mTab.setValue("PriceActual", PriceActual);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ // calculate Discount
+ else
+ {
+ if (PriceList.intValue() == 0)
+ Discount = Env.ZERO;
+ else
+ Discount = new BigDecimal ((PriceList.doubleValue() - PriceActual.doubleValue()) / PriceList.doubleValue() * 100.0);
+ if (Discount.scale() > 2)
+ Discount = Discount.setScale(2, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("Discount", Discount);
+ }
+ log.fine("amt = PriceEntered=" + PriceEntered + ", Actual" + PriceActual + ", Discount=" + Discount);
+ /* */
+
+ // Check PriceLimit
+ String epl = Env.getContext(ctx, WindowNo, "EnforcePriceLimit");
+ boolean enforce = Env.isSOTrx(ctx, WindowNo) && epl != null && epl.equals("Y");
+ if (enforce && MRole.getDefault().isOverwritePriceLimit())
+ enforce = false;
+ // Check Price Limit?
+ if (enforce && PriceLimit.doubleValue() != 0.0
+ && PriceActual.compareTo(PriceLimit) < 0)
+ {
+ PriceActual = PriceLimit;
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceLimit);
+ if (PriceEntered == null)
+ PriceEntered = PriceLimit;
+ log.fine("amt =(under) PriceEntered=" + PriceEntered + ", Actual" + PriceLimit);
+ mTab.setValue ("PriceActual", PriceLimit);
+ mTab.setValue ("PriceEntered", PriceEntered);
+ mTab.fireDataStatusEEvent ("UnderLimitPrice", "", false);
+ // Repeat Discount calc
+ if (PriceList.intValue() != 0)
+ {
+ Discount = new BigDecimal ((PriceList.doubleValue () - PriceActual.doubleValue ()) / PriceList.doubleValue () * 100.0);
+ if (Discount.scale () > 2)
+ Discount = Discount.setScale (2, BigDecimal.ROUND_HALF_UP);
+ // mTab.setValue ("Discount", Discount);
+ }
+ }
+
+ // Line Net Amt
+ BigDecimal LineNetAmt = QtyInvoiced.multiply(PriceActual);
+ if (LineNetAmt.scale() > StdPrecision)
+ LineNetAmt = LineNetAmt.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ log.info("amt = LineNetAmt=" + LineNetAmt);
+ mTab.setValue("LineNetAmt", LineNetAmt);
+
+ // Calculate Tax Amount for PO
+ boolean IsSOTrx = "Y".equals(Env.getContext(Env.getCtx(), WindowNo, "IsSOTrx"));
+ if (!IsSOTrx)
+ {
+ BigDecimal TaxAmt = null;
+ if (mField.getColumnName().equals("TaxAmt"))
+ {
+ TaxAmt = (BigDecimal)mTab.getValue("TaxAmt");
+ }
+ else
+ {
+ Integer taxID = (Integer)mTab.getValue("C_Tax_ID");
+ if (taxID != null)
+ {
+ int C_Tax_ID = taxID.intValue();
+ MTax tax = new MTax (ctx, C_Tax_ID, null);
+ TaxAmt = tax.calculateTax(LineNetAmt, isTaxIncluded(WindowNo), StdPrecision);
+ mTab.setValue("TaxAmt", TaxAmt);
+ }
+ }
+ // Add it up
+ mTab.setValue("LineTotalAmt", LineNetAmt.add(TaxAmt));
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // amt
+
+ /**
+ * Is Tax Included
+ * @param WindowNo window no
+ * @return tax included (default: false)
+ */
+ private boolean isTaxIncluded (int WindowNo)
+ {
+ String ss = Env.getContext(Env.getCtx(), WindowNo, "IsTaxIncluded");
+ // Not Set Yet
+ if (ss.length() == 0)
+ {
+ int M_PriceList_ID = Env.getContextAsInt(Env.getCtx(), WindowNo, "M_PriceList_ID");
+ if (M_PriceList_ID == 0)
+ return false;
+ ss = DB.getSQLValueString(null,
+ "SELECT IsTaxIncluded FROM M_PriceList WHERE M_PriceList_ID=?",
+ M_PriceList_ID);
+ if (ss == null)
+ ss = "N";
+ Env.setContext(Env.getCtx(), WindowNo, "IsTaxIncluded", ss);
+ }
+ return "Y".equals(ss);
+ } // isTaxIncluded
+
+ /**
+ * Invoice Line - Quantity.
+ * - called from C_UOM_ID, QtyEntered, QtyInvoiced
+ * - enforces qty UOM relationship
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String qty (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ // log.log(Level.WARNING,"qty - init - M_Product_ID=" + M_Product_ID);
+ BigDecimal QtyInvoiced, QtyEntered, PriceActual, PriceEntered;
+
+ // No Product
+ if (M_Product_ID == 0)
+ {
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ mTab.setValue("QtyInvoiced", QtyEntered);
+ }
+ // UOM Changed - convert from Entered -> Product
+ else if (mField.getColumnName().equals("C_UOM_ID"))
+ {
+ int C_UOM_To_ID = ((Integer)value).intValue();
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ QtyInvoiced = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyInvoiced == null)
+ QtyInvoiced = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(QtyInvoiced) != 0;
+ PriceActual = (BigDecimal)mTab.getValue("PriceActual");
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ log.fine("qty - UOM=" + C_UOM_To_ID
+ + ", QtyEntered/PriceActual=" + QtyEntered + "/" + PriceActual
+ + " -> " + conversion
+ + " QtyInvoiced/PriceEntered=" + QtyInvoiced + "/" + PriceEntered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyInvoiced", QtyInvoiced);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ // QtyEntered changed - calculate QtyInvoiced
+ else if (mField.getColumnName().equals("QtyEntered"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ QtyEntered = (BigDecimal)value;
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ QtyInvoiced = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyInvoiced == null)
+ QtyInvoiced = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(QtyInvoiced) != 0;
+ log.fine("qty - UOM=" + C_UOM_To_ID
+ + ", QtyEntered=" + QtyEntered
+ + " -> " + conversion
+ + " QtyInvoiced=" + QtyInvoiced);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyInvoiced", QtyInvoiced);
+ }
+ // QtyInvoiced changed - calculate QtyEntered (should not happen)
+ else if (mField.getColumnName().equals("QtyInvoiced"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ QtyInvoiced = (BigDecimal)value;
+ int precision = MProduct.get(ctx, M_Product_ID).getUOMPrecision();
+ BigDecimal QtyInvoiced1 = QtyInvoiced.setScale(precision, BigDecimal.ROUND_HALF_UP);
+ if (QtyInvoiced.compareTo(QtyInvoiced1) != 0)
+ {
+ log.fine("Corrected QtyInvoiced Scale "
+ + QtyInvoiced + "->" + QtyInvoiced1);
+ QtyInvoiced = QtyInvoiced1;
+ mTab.setValue("QtyInvoiced", QtyInvoiced);
+ }
+ QtyEntered = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyInvoiced);
+ if (QtyEntered == null)
+ QtyEntered = QtyInvoiced;
+ boolean conversion = QtyInvoiced.compareTo(QtyEntered) != 0;
+ log.fine("qty - UOM=" + C_UOM_To_ID
+ + ", QtyInvoiced=" + QtyInvoiced
+ + " -> " + conversion
+ + " QtyEntered=" + QtyEntered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ //
+ setCalloutActive(false);
+ return "";
+ } // qty
+
+
+} // CalloutInvoice
diff --git a/base/src/org/compiere/model/CalloutInvoiceBatch.java b/base/src/org/compiere/model/CalloutInvoiceBatch.java
new file mode 100644
index 0000000000..e57759ebaf
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutInvoiceBatch.java
@@ -0,0 +1,393 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+
+/**
+ * Callouts for Invoice Batch
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutInvoiceBatch.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutInvoiceBatch extends CalloutEngine
+{
+ /**
+ * Invoice Batch Line - DateInvoiced.
+ * - updates DateAcct
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String date (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (value == null)
+ return "";
+ mTab.setValue ("DateAcct", value);
+ //
+ setDocumentNo(ctx, WindowNo, mTab);
+ return "";
+ } // date
+
+
+
+ /**
+ * Invoice Batch Line - BPartner.
+ * - C_BPartner_Location_ID
+ * - AD_User_ID
+ * - PaymentRule
+ * - C_PaymentTerm_ID
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String bPartner (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_BPartner_ID = (Integer)value;
+ if (C_BPartner_ID == null || C_BPartner_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT p.AD_Language,p.C_PaymentTerm_ID,"
+ + " COALESCE(p.M_PriceList_ID,g.M_PriceList_ID) AS M_PriceList_ID, p.PaymentRule,p.POReference,"
+ + " p.SO_Description,p.IsDiscountPrinted,"
+ + " p.SO_CreditLimit, p.SO_CreditLimit-p.SO_CreditUsed AS CreditAvailable,"
+ + " l.C_BPartner_Location_ID,c.AD_User_ID,"
+ + " COALESCE(p.PO_PriceList_ID,g.PO_PriceList_ID) AS PO_PriceList_ID, p.PaymentRulePO,p.PO_PaymentTerm_ID "
+ + "FROM C_BPartner p"
+ + " INNER JOIN C_BP_Group g ON (p.C_BP_Group_ID=g.C_BP_Group_ID)"
+ + " LEFT OUTER JOIN C_BPartner_Location l ON (p.C_BPartner_ID=l.C_BPartner_ID AND l.IsBillTo='Y' AND l.IsActive='Y')"
+ + " LEFT OUTER JOIN AD_User c ON (p.C_BPartner_ID=c.C_BPartner_ID) "
+ + "WHERE p.C_BPartner_ID=? AND p.IsActive='Y'"; // #1
+
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_BPartner_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ //
+ if (rs.next())
+ {
+ // PaymentRule
+ String s = rs.getString(IsSOTrx ? "PaymentRule" : "PaymentRulePO");
+ if (s != null && s.length() != 0)
+ {
+ if (Env.getContext(ctx, WindowNo, "DocBaseType").endsWith("C")) // Credits are Payment Term
+ s = "P";
+ else if (IsSOTrx && (s.equals("S") || s.equals("U"))) // No Check/Transfer for SO_Trx
+ s = "P"; // Payment Term
+ // mTab.setValue("PaymentRule", s);
+ }
+ // Payment Term
+ Integer ii = new Integer(rs.getInt(IsSOTrx ? "C_PaymentTerm_ID" : "PO_PaymentTerm_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_PaymentTerm_ID", ii);
+
+ // Location
+ int locID = rs.getInt("C_BPartner_Location_ID");
+ // overwritten by InfoBP selection - works only if InfoWindow
+ // was used otherwise creates error (uses last value, may belong to differnt BP)
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String loc = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_Location_ID");
+ if (loc.length() > 0)
+ locID = Integer.parseInt(loc);
+ }
+ if (locID == 0)
+ mTab.setValue("C_BPartner_Location_ID", null);
+ else
+ mTab.setValue("C_BPartner_Location_ID", new Integer(locID));
+
+ // Contact - overwritten by InfoBP selection
+ int contID = rs.getInt("AD_User_ID");
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String cont = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "AD_User_ID");
+ if (cont.length() > 0)
+ contID = Integer.parseInt(cont);
+ }
+ if (contID == 0)
+ mTab.setValue("AD_User_ID", null);
+ else
+ mTab.setValue("AD_User_ID", new Integer(contID));
+
+ // CreditAvailable
+ if (IsSOTrx)
+ {
+ double CreditLimit = rs.getDouble("SO_CreditLimit");
+ if (CreditLimit != 0)
+ {
+ double CreditAvailable = rs.getDouble("CreditAvailable");
+ if (!rs.wasNull() && CreditAvailable < 0)
+ mTab.fireDataStatusEEvent("CreditLimitOver",
+ DisplayType.getNumberFormat(DisplayType.Amount).format(CreditAvailable),
+ false);
+ }
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ //
+ setDocumentNo(ctx, WindowNo, mTab);
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // bPartner
+
+ /**
+ * Document Type.
+ * - called from DocType
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String docType (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ setDocumentNo(ctx, WindowNo, mTab);
+ return "";
+ } // docType
+
+ /**
+ * Set Document No (increase existing)
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ */
+ private void setDocumentNo (Properties ctx, int WindowNo, GridTab mTab)
+ {
+ // Get last line
+ int C_InvoiceBatch_ID = Env.getContextAsInt(ctx, WindowNo, "C_InvoiceBatch_ID");
+ String sql = "SELECT COALESCE(MAX(C_InvoiceBatchLine_ID),0) FROM C_InvoiceBatchLine WHERE C_InvoiceBatch_ID=?";
+ int C_InvoiceBatchLine_ID = DB.getSQLValue(null, sql, C_InvoiceBatch_ID);
+ if (C_InvoiceBatchLine_ID == 0)
+ return;
+ MInvoiceBatchLine last = new MInvoiceBatchLine(Env.getCtx(), C_InvoiceBatchLine_ID, null);
+
+ // Need to Increase when different DocType or BP
+ int C_DocType_ID = Env.getContextAsInt(ctx, WindowNo, "C_DocType_ID");
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID");
+ if (C_DocType_ID == last.getC_DocType_ID()
+ && C_BPartner_ID == last.getC_BPartner_ID())
+ return;
+
+ // New Number
+ String oldDocNo = last.getDocumentNo();
+ if (oldDocNo == null)
+ return;
+ int docNo = 0;
+ try
+ {
+ docNo = Integer.parseInt(oldDocNo);
+ }
+ catch (Exception e)
+ {
+ }
+ if (docNo == 0)
+ return;
+ String newDocNo = String.valueOf(docNo+1);
+ mTab.setValue("DocumentNo", newDocNo);
+ } // setDocumentNo
+
+ /**
+ * Invoice Batch Line - Charge.
+ * - updates PriceEntered from Charge
+ * Calles tax
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String charge (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Charge_ID = (Integer)value;
+ if (C_Charge_ID == null || C_Charge_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT ChargeAmt FROM C_Charge WHERE C_Charge_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Charge_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue ("PriceEntered", rs.getBigDecimal (1));
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ //
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // charge
+
+ /**
+ * Invoice Line - Tax.
+ * - basis: Charge, BPartner Location
+ * - sets C_Tax_ID
+ * Calles Amount
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String tax (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String column = mField.getColumnName();
+ if (value == null)
+ return "";
+
+ int C_Charge_ID = 0;
+ if (column.equals("C_Charge_ID"))
+ C_Charge_ID = ((Integer)value).intValue();
+ else
+ C_Charge_ID = Env.getContextAsInt(ctx, WindowNo, "C_Charge_ID");
+ log.fine("C_Charge_ID=" + C_Charge_ID);
+ if (C_Charge_ID == 0)
+ return amt (ctx, WindowNo, mTab, mField, value); //
+
+ // Check Partner Location
+ int C_BPartner_Location_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_Location_ID");
+ if (C_BPartner_Location_ID == 0)
+ return amt (ctx, WindowNo, mTab, mField, value); //
+ log.fine("BP_Location=" + C_BPartner_Location_ID);
+
+ // Dates
+ Timestamp billDate = Env.getContextAsDate(ctx, WindowNo, "DateInvoiced");
+ log.fine("Bill Date=" + billDate);
+ Timestamp shipDate = billDate;
+ log.fine("Ship Date=" + shipDate);
+
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+ log.fine("Org=" + AD_Org_ID);
+
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, "#M_Warehouse_ID");
+ log.fine("Warehouse=" + M_Warehouse_ID);
+
+ //
+ int C_Tax_ID = Tax.get(ctx, 0, C_Charge_ID, billDate, shipDate,
+ AD_Org_ID, M_Warehouse_ID, C_BPartner_Location_ID, C_BPartner_Location_ID,
+ Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y"));
+ log.info("Tax ID=" + C_Tax_ID);
+ //
+ if (C_Tax_ID == 0)
+ mTab.fireDataStatusEEvent(CLogger.retrieveError());
+ else
+ mTab.setValue("C_Tax_ID", new Integer(C_Tax_ID));
+ //
+ return amt (ctx, WindowNo, mTab, mField, value);
+ } // tax
+
+
+ /**
+ * Invoice - Amount.
+ * - called from QtyEntered, PriceEntered
+ * - calculates LineNetAmt
+ * @param ctx context
+ * @param WindowNo window no
+ * @param mTab tab
+ * @param mField field
+ * @param value value
+ * @return null or error message
+ */
+ public String amt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ int StdPrecision = 2; // temporary
+
+ // get values
+ BigDecimal QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ BigDecimal PriceEntered = (BigDecimal)mTab.getValue("PriceEntered");
+ log.fine("QtyEntered=" + QtyEntered + ", PriceEntered=" + PriceEntered);
+ if (QtyEntered == null)
+ QtyEntered = Env.ZERO;
+ if (PriceEntered == null)
+ PriceEntered = Env.ZERO;
+
+ // Line Net Amt
+ BigDecimal LineNetAmt = QtyEntered.multiply(PriceEntered);
+ if (LineNetAmt.scale() > StdPrecision)
+ LineNetAmt = LineNetAmt.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+
+ // Calculate Tax Amount
+ boolean IsSOTrx = "Y".equals(Env.getContext(Env.getCtx(), WindowNo, "IsSOTrx"));
+ boolean IsTaxIncluded = "Y".equals(Env.getContext(Env.getCtx(), WindowNo, "IsTaxIncluded"));
+
+ BigDecimal TaxAmt = null;
+ if (mField.getColumnName().equals("TaxAmt"))
+ {
+ TaxAmt = (BigDecimal)mTab.getValue("TaxAmt");
+ }
+ else
+ {
+ Integer taxID = (Integer)mTab.getValue("C_Tax_ID");
+ if (taxID != null)
+ {
+ int C_Tax_ID = taxID.intValue();
+ MTax tax = new MTax (ctx, C_Tax_ID, null);
+ TaxAmt = tax.calculateTax(LineNetAmt, IsTaxIncluded, StdPrecision);
+ mTab.setValue("TaxAmt", TaxAmt);
+ }
+ }
+
+ //
+ if (IsTaxIncluded)
+ {
+ mTab.setValue("LineTotalAmt", LineNetAmt);
+ mTab.setValue("LineNetAmt", LineNetAmt.subtract(TaxAmt));
+ }
+ else
+ {
+ mTab.setValue("LineNetAmt", LineNetAmt);
+ mTab.setValue("LineTotalAmt", LineNetAmt.add(TaxAmt));
+ }
+ setCalloutActive(false);
+ return "";
+ } // amt
+
+
+
+} // CalloutInvoiceBatch
diff --git a/base/src/org/compiere/model/CalloutMovement.java b/base/src/org/compiere/model/CalloutMovement.java
new file mode 100644
index 0000000000..6f05b64103
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutMovement.java
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * 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.model;
+
+import java.util.*;
+import org.compiere.util.*;
+
+/**
+ * Inventory Movement Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutMovement.java,v 1.2 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutMovement extends CalloutEngine
+{
+ /**
+ * Product modified
+ * Set Attribute Set Instance
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ // Set Attribute
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ return "";
+ } // product
+
+} // CalloutMove
diff --git a/base/src/org/compiere/model/CalloutOrder.java b/base/src/org/compiere/model/CalloutOrder.java
new file mode 100644
index 0000000000..622a8bccee
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutOrder.java
@@ -0,0 +1,1188 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Order Callouts.
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutOrder.java,v 1.5 2006/10/08 06:57:33 comdivision Exp $
+ */
+public class CalloutOrder extends CalloutEngine
+{
+ /** Debug Steps */
+ private boolean steps = false;
+
+ /**
+ * Order Header Change - DocType.
+ * - InvoiceRuld/DeliveryRule/PaymentRule
+ * - temporary Document
+ * Context:
+ * - DocSubTypeSO
+ * - HasCharges
+ * - (re-sets Business Partner info of required)
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String docType (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_DocType_ID = (Integer)value; // Actually C_DocTypeTarget_ID
+ if (C_DocType_ID == null || C_DocType_ID.intValue() == 0)
+ return "";
+
+ // Re-Create new DocNo, if there is a doc number already
+ // and the existing source used a different Sequence number
+ String oldDocNo = (String)mTab.getValue("DocumentNo");
+ boolean newDocNo = (oldDocNo == null);
+ if (!newDocNo && oldDocNo.startsWith("<") && oldDocNo.endsWith(">"))
+ newDocNo = true;
+ Integer oldC_DocType_ID = (Integer)mTab.getValue("C_DocType_ID");
+
+ String sql = "SELECT d.DocSubTypeSO,d.HasCharges,'N'," // 1..3
+ + "d.IsDocNoControlled,s.CurrentNext,s.CurrentNextSys," // 4..6
+ + "s.AD_Sequence_ID,d.IsSOTrx " // 7..8
+ + "FROM C_DocType d, AD_Sequence s "
+ + "WHERE C_DocType_ID=?" // #1
+ + " AND d.DocNoSequence_ID=s.AD_Sequence_ID(+)";
+ try
+ {
+ int AD_Sequence_ID = 0;
+
+ // Get old AD_SeqNo for comparison
+ if (!newDocNo && oldC_DocType_ID.intValue() != 0)
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, oldC_DocType_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ AD_Sequence_ID = rs.getInt(6);
+ rs.close();
+ pstmt.close();
+ }
+
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_DocType_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ String DocSubTypeSO = "";
+ boolean IsSOTrx = true;
+ if (rs.next()) // we found document type
+ {
+ // Set Context: Document Sub Type for Sales Orders
+ DocSubTypeSO = rs.getString(1);
+ if (DocSubTypeSO == null)
+ DocSubTypeSO = "--";
+ Env.setContext(ctx, WindowNo, "OrderType", DocSubTypeSO);
+ // No Drop Ship other than Standard
+ if (!DocSubTypeSO.equals(MOrder.DocSubTypeSO_Standard))
+ mTab.setValue ("IsDropShip", "N");
+
+ // Delivery Rule
+ if (DocSubTypeSO.equals(MOrder.DocSubTypeSO_POS))
+ mTab.setValue ("DeliveryRule", MOrder.DELIVERYRULE_Force);
+ else if (DocSubTypeSO.equals(MOrder.DocSubTypeSO_Prepay))
+ mTab.setValue ("DeliveryRule", MOrder.DELIVERYRULE_AfterReceipt);
+ else
+ mTab.setValue ("DeliveryRule", MOrder.DELIVERYRULE_Availability);
+
+ // Invoice Rule
+ if (DocSubTypeSO.equals(MOrder.DocSubTypeSO_POS)
+ || DocSubTypeSO.equals(MOrder.DocSubTypeSO_Prepay)
+ || DocSubTypeSO.equals(MOrder.DocSubTypeSO_OnCredit) )
+ mTab.setValue ("InvoiceRule", MOrder.INVOICERULE_Immediate);
+ else
+ mTab.setValue ("InvoiceRule", MOrder.INVOICERULE_AfterDelivery);
+
+ // Payment Rule - POS Order
+ if (DocSubTypeSO.equals(MOrder.DocSubTypeSO_POS))
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_Cash);
+ else
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_OnCredit);
+
+ // IsSOTrx
+ if ("N".equals(rs.getString(8)))
+ IsSOTrx = false;
+
+ // Set Context:
+ Env.setContext(ctx, WindowNo, "HasCharges", rs.getString(2));
+ // DocumentNo
+ if (rs.getString(4).equals("Y")) // IsDocNoControlled
+ {
+ if (!newDocNo && AD_Sequence_ID != rs.getInt(7))
+ newDocNo = true;
+ if (newDocNo)
+ if (Ini.isPropertyBool(Ini.P_ADEMPIERESYS) && Env.getAD_Client_ID(Env.getCtx()) < 1000000)
+ mTab.setValue("DocumentNo", "<" + rs.getString(6) + ">");
+ else
+ mTab.setValue("DocumentNo", "<" + rs.getString(5) + ">");
+ }
+ }
+ rs.close();
+ pstmt.close();
+ // When BPartner is changed, the Rules are not set if
+ // it is a POS or Credit Order (i.e. defaults from Standard BPartner)
+ // This re-reads the Rules and applies them.
+ if (DocSubTypeSO.equals(MOrder.DocSubTypeSO_POS)
+ || DocSubTypeSO.equals(MOrder.DocSubTypeSO_Prepay)) // not for POS/PrePay
+ ;
+ else
+ {
+ sql = "SELECT PaymentRule,C_PaymentTerm_ID," // 1..2
+ + "InvoiceRule,DeliveryRule," // 3..4
+ + "FreightCostRule,DeliveryViaRule, " // 5..6
+ + "PaymentRulePO,PO_PaymentTerm_ID "
+ + "FROM C_BPartner "
+ + "WHERE C_BPartner_ID=?"; // #1
+ pstmt = DB.prepareStatement(sql, null);
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID");
+ pstmt.setInt(1, C_BPartner_ID);
+ //
+ rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // PaymentRule
+ String s = rs.getString(IsSOTrx ? "PaymentRule" : "PaymentRulePO");
+ if (s != null && s.length() != 0)
+ {
+ if (IsSOTrx && (s.equals("B") || s.equals("S") || s.equals("U"))) // No Cash/Check/Transfer for SO_Trx
+ s = "P"; // Payment Term
+ if (!IsSOTrx && (s.equals("B"))) // No Cash for PO_Trx
+ s = "P"; // Payment Term
+ mTab.setValue("PaymentRule", s);
+ }
+ // Payment Term
+ Integer ii =new Integer(rs.getInt(IsSOTrx ? "C_PaymentTerm_ID" : "PO_PaymentTerm_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_PaymentTerm_ID", ii);
+ // InvoiceRule
+ s = rs.getString(3);
+ if (s != null && s.length() != 0)
+ mTab.setValue("InvoiceRule", s);
+ // DeliveryRule
+ s = rs.getString(4);
+ if (s != null && s.length() != 0)
+ mTab.setValue("DeliveryRule", s);
+ // FreightCostRule
+ s = rs.getString(5);
+ if (s != null && s.length() != 0)
+ mTab.setValue("FreightCostRule", s);
+ // DeliveryViaRule
+ s = rs.getString(6);
+ if (s != null && s.length() != 0)
+ mTab.setValue("DeliveryViaRule", s);
+ }
+ rs.close();
+ pstmt.close();
+ } // re-read customer rules
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+
+ return "";
+ } // docType
+
+
+ /**
+ * Order Header - BPartner.
+ * - M_PriceList_ID (+ Context)
+ * - C_BPartner_Location_ID
+ * - Bill_BPartner_ID/Bill_Location_ID
+ * - AD_User_ID
+ * - POReference
+ * - SO_Description
+ * - IsDiscountPrinted
+ * - InvoiceRule/DeliveryRule/PaymentRule/FreightCost/DeliveryViaRule
+ * - C_PaymentTerm_ID
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String bPartner (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_BPartner_ID = (Integer)value;
+ if (C_BPartner_ID == null || C_BPartner_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+
+ String sql = "SELECT p.AD_Language,p.C_PaymentTerm_ID,"
+ + " COALESCE(p.M_PriceList_ID,g.M_PriceList_ID) AS M_PriceList_ID, p.PaymentRule,p.POReference,"
+ + " p.SO_Description,p.IsDiscountPrinted,"
+ + " p.InvoiceRule,p.DeliveryRule,p.FreightCostRule,DeliveryViaRule,"
+ + " p.SO_CreditLimit, p.SO_CreditLimit-p.SO_CreditUsed AS CreditAvailable,"
+ + " lship.C_BPartner_Location_ID,c.AD_User_ID,"
+ + " COALESCE(p.PO_PriceList_ID,g.PO_PriceList_ID) AS PO_PriceList_ID, p.PaymentRulePO,p.PO_PaymentTerm_ID,"
+ + " lbill.C_BPartner_Location_ID AS Bill_Location_ID, p.SOCreditStatus "
+ + "FROM C_BPartner p"
+ + " INNER JOIN C_BP_Group g ON (p.C_BP_Group_ID=g.C_BP_Group_ID)"
+ + " LEFT OUTER JOIN C_BPartner_Location lbill ON (p.C_BPartner_ID=lbill.C_BPartner_ID AND lbill.IsBillTo='Y' AND lbill.IsActive='Y')"
+ + " LEFT OUTER JOIN C_BPartner_Location lship ON (p.C_BPartner_ID=lship.C_BPartner_ID AND lship.IsShipTo='Y' AND lship.IsActive='Y')"
+ + " LEFT OUTER JOIN AD_User c ON (p.C_BPartner_ID=c.C_BPartner_ID) "
+ + "WHERE p.C_BPartner_ID=? AND p.IsActive='Y'"; // #1
+
+ boolean IsSOTrx = "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx"));
+
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_BPartner_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // PriceList (indirect: IsTaxIncluded & Currency)
+ Integer ii = new Integer(rs.getInt(IsSOTrx ? "M_PriceList_ID" : "PO_PriceList_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("M_PriceList_ID", ii);
+ else
+ { // get default PriceList
+ int i = Env.getContextAsInt(ctx, "#M_PriceList_ID");
+ if (i != 0)
+ mTab.setValue("M_PriceList_ID", new Integer(i));
+ }
+
+ // Bill-To
+ mTab.setValue("Bill_BPartner_ID", C_BPartner_ID);
+ int bill_Location_ID = rs.getInt("Bill_Location_ID");
+ if (bill_Location_ID == 0)
+ mTab.setValue("Bill_Location_ID", null);
+ else
+ mTab.setValue("Bill_Location_ID", new Integer(bill_Location_ID));
+ // Ship-To Location
+ int shipTo_ID = rs.getInt("C_BPartner_Location_ID");
+ // overwritten by InfoBP selection - works only if InfoWindow
+ // was used otherwise creates error (uses last value, may belong to differnt BP)
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String loc = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_Location_ID");
+ if (loc.length() > 0)
+ shipTo_ID = Integer.parseInt(loc);
+ }
+ if (shipTo_ID == 0)
+ mTab.setValue("C_BPartner_Location_ID", null);
+ else
+ mTab.setValue("C_BPartner_Location_ID", new Integer(shipTo_ID));
+
+ // Contact - overwritten by InfoBP selection
+ int contID = rs.getInt("AD_User_ID");
+ if (C_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String cont = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "AD_User_ID");
+ if (cont.length() > 0)
+ contID = Integer.parseInt(cont);
+ }
+ if (contID == 0)
+ mTab.setValue("AD_User_ID", null);
+ else
+ {
+ mTab.setValue("AD_User_ID", new Integer(contID));
+ mTab.setValue("Bill_User_ID", new Integer(contID));
+ }
+
+ // CreditAvailable
+ if (IsSOTrx)
+ {
+ double CreditLimit = rs.getDouble("SO_CreditLimit");
+ String SOCreditStatus = rs.getString("SOCreditStatus");
+ if (CreditLimit != 0)
+ {
+ double CreditAvailable = rs.getDouble("CreditAvailable");
+ if (!rs.wasNull() && CreditAvailable < 0)
+ mTab.fireDataStatusEEvent("CreditLimitOver",
+ DisplayType.getNumberFormat(DisplayType.Amount).format(CreditAvailable),
+ false);
+ }
+ }
+
+ // PO Reference
+ String s = rs.getString("POReference");
+ if (s != null && s.length() != 0)
+ mTab.setValue("POReference", s);
+ // should not be reset to null if we entered already value! VHARCQ, accepted YS makes sense that way
+ // TODO: should get checked and removed if no longer needed!
+ /*else
+ mTab.setValue("POReference", null);*/
+
+ // SO Description
+ s = rs.getString("SO_Description");
+ if (s != null && s.trim().length() != 0)
+ mTab.setValue("Description", s);
+ // IsDiscountPrinted
+ s = rs.getString("IsDiscountPrinted");
+ if (s != null && s.length() != 0)
+ mTab.setValue("IsDiscountPrinted", s);
+ else
+ mTab.setValue("IsDiscountPrinted", "N");
+
+ // Defaults, if not Walkin Receipt or Walkin Invoice
+ String OrderType = Env.getContext(ctx, WindowNo, "OrderType");
+ mTab.setValue("InvoiceRule", MOrder.INVOICERULE_AfterDelivery);
+ mTab.setValue("DeliveryRule", MOrder.DELIVERYRULE_Availability);
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_OnCredit);
+ if (OrderType.equals(MOrder.DocSubTypeSO_Prepay))
+ {
+ mTab.setValue("InvoiceRule", MOrder.INVOICERULE_Immediate);
+ mTab.setValue("DeliveryRule", MOrder.DELIVERYRULE_AfterReceipt);
+ }
+ else if (OrderType.equals(MOrder.DocSubTypeSO_POS)) // for POS
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_Cash);
+ else
+ {
+ // PaymentRule
+ s = rs.getString(IsSOTrx ? "PaymentRule" : "PaymentRulePO");
+ if (s != null && s.length() != 0)
+ {
+ if (s.equals("B")) // No Cache in Non POS
+ s = "P";
+ if (IsSOTrx && (s.equals("S") || s.equals("U"))) // No Check/Transfer for SO_Trx
+ s = "P"; // Payment Term
+ mTab.setValue("PaymentRule", s);
+ }
+ // Payment Term
+ ii = new Integer(rs.getInt(IsSOTrx ? "C_PaymentTerm_ID" : "PO_PaymentTerm_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_PaymentTerm_ID", ii);
+ // InvoiceRule
+ s = rs.getString("InvoiceRule");
+ if (s != null && s.length() != 0)
+ mTab.setValue("InvoiceRule", s);
+ // DeliveryRule
+ s = rs.getString("DeliveryRule");
+ if (s != null && s.length() != 0)
+ mTab.setValue("DeliveryRule", s);
+ // FreightCostRule
+ s = rs.getString("FreightCostRule");
+ if (s != null && s.length() != 0)
+ mTab.setValue("FreightCostRule", s);
+ // DeliveryViaRule
+ s = rs.getString("DeliveryViaRule");
+ if (s != null && s.length() != 0)
+ mTab.setValue("DeliveryViaRule", s);
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ setCalloutActive(false);
+ return "";
+ } // bPartner
+
+ /**
+ * Order Header - Invoice BPartner.
+ * - M_PriceList_ID (+ Context)
+ * - Bill_Location_ID
+ * - Bill_User_ID
+ * - POReference
+ * - SO_Description
+ * - IsDiscountPrinted
+ * - InvoiceRule/PaymentRule
+ * - C_PaymentTerm_ID
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String bPartnerBill (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ Integer bill_BPartner_ID = (Integer)value;
+ if (bill_BPartner_ID == null || bill_BPartner_ID.intValue() == 0)
+ return "";
+
+ String sql = "SELECT p.AD_Language,p.C_PaymentTerm_ID,"
+ + "p.M_PriceList_ID,p.PaymentRule,p.POReference,"
+ + "p.SO_Description,p.IsDiscountPrinted,"
+ + "p.InvoiceRule,p.DeliveryRule,p.FreightCostRule,DeliveryViaRule,"
+ + "p.SO_CreditLimit, p.SO_CreditLimit-p.SO_CreditUsed AS CreditAvailable,"
+ + "c.AD_User_ID,"
+ + "p.PO_PriceList_ID, p.PaymentRulePO, p.PO_PaymentTerm_ID,"
+ + "lbill.C_BPartner_Location_ID AS Bill_Location_ID "
+ + "FROM C_BPartner p"
+ + " LEFT OUTER JOIN C_BPartner_Location lbill ON (p.C_BPartner_ID=lbill.C_BPartner_ID AND lbill.IsBillTo='Y' AND lbill.IsActive='Y')"
+ + " LEFT OUTER JOIN AD_User c ON (p.C_BPartner_ID=c.C_BPartner_ID) "
+ + "WHERE p.C_BPartner_ID=? AND p.IsActive='Y'"; // #1
+
+ boolean IsSOTrx = "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx"));
+
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, bill_BPartner_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // PriceList (indirect: IsTaxIncluded & Currency)
+ Integer ii = new Integer(rs.getInt(IsSOTrx ? "M_PriceList_ID" : "PO_PriceList_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("M_PriceList_ID", ii);
+ else
+ { // get default PriceList
+ int i = Env.getContextAsInt(ctx, "#M_PriceList_ID");
+ if (i != 0)
+ mTab.setValue("M_PriceList_ID", new Integer(i));
+ }
+
+ int bill_Location_ID = rs.getInt("Bill_Location_ID");
+ // overwritten by InfoBP selection - works only if InfoWindow
+ // was used otherwise creates error (uses last value, may belong to differnt BP)
+ if (bill_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String loc = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_Location_ID");
+ if (loc.length() > 0)
+ bill_Location_ID = Integer.parseInt(loc);
+ }
+ if (bill_Location_ID == 0)
+ mTab.setValue("Bill_Location_ID", null);
+ else
+ mTab.setValue("Bill_Location_ID", new Integer(bill_Location_ID));
+
+ // Contact - overwritten by InfoBP selection
+ int contID = rs.getInt("AD_User_ID");
+ if (bill_BPartner_ID.toString().equals(Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_BPartner_ID")))
+ {
+ String cont = Env.getContext(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "AD_User_ID");
+ if (cont.length() > 0)
+ contID = Integer.parseInt(cont);
+ }
+ if (contID == 0)
+ mTab.setValue("Bill_User_ID", null);
+ else
+ mTab.setValue("Bill_User_ID", new Integer(contID));
+
+ // CreditAvailable
+ if (IsSOTrx)
+ {
+ double CreditLimit = rs.getDouble("SO_CreditLimit");
+ if (CreditLimit != 0)
+ {
+ double CreditAvailable = rs.getDouble("CreditAvailable");
+ if (!rs.wasNull() && CreditAvailable < 0)
+ mTab.fireDataStatusEEvent("CreditLimitOver",
+ DisplayType.getNumberFormat(DisplayType.Amount).format(CreditAvailable),
+ false);
+ }
+ }
+
+ // PO Reference
+ String s = rs.getString("POReference");
+ if (s != null && s.length() != 0)
+ mTab.setValue("POReference", s);
+ else
+ mTab.setValue("POReference", null);
+ // SO Description
+ s = rs.getString("SO_Description");
+ if (s != null && s.trim().length() != 0)
+ mTab.setValue("Description", s);
+ // IsDiscountPrinted
+ s = rs.getString("IsDiscountPrinted");
+ if (s != null && s.length() != 0)
+ mTab.setValue("IsDiscountPrinted", s);
+ else
+ mTab.setValue("IsDiscountPrinted", "N");
+
+ // Defaults, if not Walkin Receipt or Walkin Invoice
+ String OrderType = Env.getContext(ctx, WindowNo, "OrderType");
+ mTab.setValue("InvoiceRule", MOrder.INVOICERULE_AfterDelivery);
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_OnCredit);
+ if (OrderType.equals(MOrder.DocSubTypeSO_Prepay))
+ mTab.setValue("InvoiceRule", MOrder.INVOICERULE_Immediate);
+ else if (OrderType.equals(MOrder.DocSubTypeSO_POS)) // for POS
+ mTab.setValue("PaymentRule", MOrder.PAYMENTRULE_Cash);
+ else
+ {
+ // PaymentRule
+ s = rs.getString(IsSOTrx ? "PaymentRule" : "PaymentRulePO");
+ if (s != null && s.length() != 0)
+ {
+ if (s.equals("B")) // No Cache in Non POS
+ s = "P";
+ if (IsSOTrx && (s.equals("S") || s.equals("U"))) // No Check/Transfer for SO_Trx
+ s = "P"; // Payment Term
+ mTab.setValue("PaymentRule", s);
+ }
+ // Payment Term
+ ii = new Integer(rs.getInt(IsSOTrx ? "C_PaymentTerm_ID" : "PO_PaymentTerm_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_PaymentTerm_ID", ii);
+ // InvoiceRule
+ s = rs.getString("InvoiceRule");
+ if (s != null && s.length() != 0)
+ mTab.setValue("InvoiceRule", s);
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "bPartnerBill", e);
+ return e.getLocalizedMessage();
+ }
+
+ return "";
+ } // bPartnerBill
+
+
+ /**
+ * Order Header - PriceList.
+ * (used also in Invoice)
+ * - C_Currency_ID
+ * - IsTaxIncluded
+ * Window Context:
+ * - EnforcePriceLimit
+ * - StdPrecision
+ * - M_PriceList_Version_ID
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String priceList (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_PriceList_ID = (Integer)value;
+ if (M_PriceList_ID == null || M_PriceList_ID.intValue()== 0)
+ return "";
+ if (steps) log.warning("init");
+
+ String sql = "SELECT pl.IsTaxIncluded,pl.EnforcePriceLimit,pl.C_Currency_ID,c.StdPrecision,"
+ + "plv.M_PriceList_Version_ID,plv.ValidFrom "
+ + "FROM M_PriceList pl,C_Currency c,M_PriceList_Version plv "
+ + "WHERE pl.C_Currency_ID=c.C_Currency_ID"
+ + " AND pl.M_PriceList_ID=plv.M_PriceList_ID"
+ + " AND pl.M_PriceList_ID=? " // 1
+ + "ORDER BY plv.ValidFrom DESC";
+ // Use newest price list - may not be future
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, M_PriceList_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // Tax Included
+ mTab.setValue("IsTaxIncluded", new Boolean("Y".equals(rs.getString(1))));
+ // Price Limit Enforce
+ Env.setContext(ctx, WindowNo, "EnforcePriceLimit", rs.getString(2));
+ // Currency
+ Integer ii = new Integer(rs.getInt(3));
+ mTab.setValue("C_Currency_ID", ii);
+ // PriceList Version
+ Env.setContext(ctx, WindowNo, "M_PriceList_Version_ID", rs.getInt(5));
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ if (steps) log.warning("fini");
+
+ return "";
+ } // priceList
+
+
+ /*************************************************************************
+ * Order Line - Product.
+ * - reset C_Charge_ID / M_AttributeSetInstance_ID
+ * - PriceList, PriceStd, PriceLimit, C_Currency_ID, EnforcePriceLimit
+ * - UOM
+ * Calls Tax
+ *
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ if (steps) log.warning("init");
+ //
+ mTab.setValue("C_Charge_ID", null);
+ // Set Attribute
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+
+ /***** Price Calculation see also qty ****/
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID");
+ BigDecimal Qty = (BigDecimal)mTab.getValue("QtyOrdered");
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ MProductPricing pp = new MProductPricing (M_Product_ID.intValue(), C_BPartner_ID, Qty, IsSOTrx);
+ //
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ /** PLV is only accurate if PL selected in header */
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp orderDate = (Timestamp)mTab.getValue("DateOrdered");
+ pp.setPriceDate(orderDate);
+ //
+ mTab.setValue("PriceList", pp.getPriceList());
+ mTab.setValue("PriceLimit", pp.getPriceLimit());
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ mTab.setValue("PriceEntered", pp.getPriceStd());
+ mTab.setValue("C_Currency_ID", new Integer(pp.getC_Currency_ID()));
+ mTab.setValue("Discount", pp.getDiscount());
+ mTab.setValue("C_UOM_ID", new Integer(pp.getC_UOM_ID()));
+ mTab.setValue("QtyOrdered", mTab.getValue("QtyEntered"));
+ Env.setContext(ctx, WindowNo, "EnforcePriceLimit", pp.isEnforcePriceLimit() ? "Y" : "N");
+ Env.setContext(ctx, WindowNo, "DiscountSchema", pp.isDiscountSchema() ? "Y" : "N");
+
+ // Check/Update Warehouse Setting
+ // int M_Warehouse_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, "M_Warehouse_ID");
+ // Integer wh = (Integer)mTab.getValue("M_Warehouse_ID");
+ // if (wh.intValue() != M_Warehouse_ID)
+ // {
+ // mTab.setValue("M_Warehouse_ID", new Integer(M_Warehouse_ID));
+ // ADialog.warn(,WindowNo, "WarehouseChanged");
+ // }
+
+
+ if (Env.isSOTrx(ctx, WindowNo))
+ {
+ MProduct product = MProduct.get (ctx, M_Product_ID.intValue());
+ if (product.isStocked())
+ {
+ BigDecimal QtyOrdered = (BigDecimal)mTab.getValue("QtyOrdered");
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID");
+ int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID");
+ BigDecimal available = MStorage.getQtyAvailable
+ (M_Warehouse_ID, M_Product_ID.intValue(), M_AttributeSetInstance_ID, null);
+ if (available == null)
+ available = Env.ZERO;
+ if (available.signum() == 0)
+ mTab.fireDataStatusEEvent ("NoQtyAvailable", "0", false);
+ else if (available.compareTo(QtyOrdered) < 0)
+ mTab.fireDataStatusEEvent ("InsufficientQtyAvailable", available.toString(), false);
+ else
+ {
+ Integer C_OrderLine_ID = (Integer)mTab.getValue("C_OrderLine_ID");
+ if (C_OrderLine_ID == null)
+ C_OrderLine_ID = new Integer(0);
+ BigDecimal notReserved = MOrderLine.getNotReserved(ctx,
+ M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID,
+ C_OrderLine_ID.intValue());
+ if (notReserved == null)
+ notReserved = Env.ZERO;
+ BigDecimal total = available.subtract(notReserved);
+ if (total.compareTo(QtyOrdered) < 0)
+ {
+ String info = Msg.parseTranslation(ctx, "@QtyAvailable@=" + available
+ + " - @QtyNotReserved@=" + notReserved + " = " + total);
+ mTab.fireDataStatusEEvent ("InsufficientQtyAvailable",
+ info, false);
+ }
+ }
+ }
+ }
+ //
+ setCalloutActive(false);
+ if (steps) log.warning("fini");
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // product
+
+ /**
+ * Order Line - Charge.
+ * - updates PriceActual from Charge
+ * - sets PriceLimit, PriceList to zero
+ * Calles tax
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String charge (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Charge_ID = (Integer)value;
+ if (C_Charge_ID == null || C_Charge_ID.intValue() == 0)
+ return "";
+ // No Product defined
+ if (mTab.getValue("M_Product_ID") != null)
+ {
+ mTab.setValue("C_Charge_ID", null);
+ return "ChargeExclusively";
+ }
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ mTab.setValue("S_ResourceAssignment_ID", null);
+ mTab.setValue("C_UOM_ID", new Integer(100)); // EA
+
+ Env.setContext(ctx, WindowNo, "DiscountSchema", "N");
+ String sql = "SELECT ChargeAmt FROM C_Charge WHERE C_Charge_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Charge_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue ("PriceEntered", rs.getBigDecimal (1));
+ mTab.setValue ("PriceActual", rs.getBigDecimal (1));
+ mTab.setValue ("PriceLimit", Env.ZERO);
+ mTab.setValue ("PriceList", Env.ZERO);
+ mTab.setValue ("Discount", Env.ZERO);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ return e.getLocalizedMessage();
+ }
+ //
+ return tax (ctx, WindowNo, mTab, mField, value);
+ } // charge
+
+
+ /**
+ * Order Line - Tax.
+ * - basis: Product, Charge, BPartner Location
+ * - sets C_Tax_ID
+ * Calles Amount
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String tax (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String column = mField.getColumnName();
+ if (value == null)
+ return "";
+ if (steps) log.warning("init");
+
+ // Check Product
+ int M_Product_ID = 0;
+ if (column.equals("M_Product_ID"))
+ M_Product_ID = ((Integer)value).intValue();
+ else
+ M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ int C_Charge_ID = 0;
+ if (column.equals("C_Charge_ID"))
+ C_Charge_ID = ((Integer)value).intValue();
+ else
+ C_Charge_ID = Env.getContextAsInt(ctx, WindowNo, "C_Charge_ID");
+ log.fine("Product=" + M_Product_ID + ", C_Charge_ID=" + C_Charge_ID);
+ if (M_Product_ID == 0 && C_Charge_ID == 0)
+ return amt(ctx, WindowNo, mTab, mField, value); //
+
+ // Check Partner Location
+ int shipC_BPartner_Location_ID = 0;
+ if (column.equals("C_BPartner_Location_ID"))
+ shipC_BPartner_Location_ID = ((Integer)value).intValue();
+ else
+ shipC_BPartner_Location_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_Location_ID");
+ if (shipC_BPartner_Location_ID == 0)
+ return amt(ctx, WindowNo, mTab, mField, value); //
+ log.fine("Ship BP_Location=" + shipC_BPartner_Location_ID);
+
+ //
+ Timestamp billDate = Env.getContextAsDate(ctx, WindowNo, "DateOrdered");
+ log.fine("Bill Date=" + billDate);
+
+ Timestamp shipDate = Env.getContextAsDate(ctx, WindowNo, "DatePromised");
+ log.fine("Ship Date=" + shipDate);
+
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+ log.fine("Org=" + AD_Org_ID);
+
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID");
+ log.fine("Warehouse=" + M_Warehouse_ID);
+
+ int billC_BPartner_Location_ID = Env.getContextAsInt(ctx, WindowNo, "Bill_Location_ID");
+ if (billC_BPartner_Location_ID == 0)
+ billC_BPartner_Location_ID = shipC_BPartner_Location_ID;
+ log.fine("Bill BP_Location=" + billC_BPartner_Location_ID);
+
+ //
+ int C_Tax_ID = Tax.get (ctx, M_Product_ID, C_Charge_ID, billDate, shipDate,
+ AD_Org_ID, M_Warehouse_ID, billC_BPartner_Location_ID, shipC_BPartner_Location_ID,
+ "Y".equals(Env.getContext(ctx, WindowNo, "IsSOTrx")));
+ log.info("Tax ID=" + C_Tax_ID);
+ //
+ if (C_Tax_ID == 0)
+ mTab.fireDataStatusEEvent(CLogger.retrieveError());
+ else
+ mTab.setValue("C_Tax_ID", new Integer(C_Tax_ID));
+ //
+ if (steps) log.warning("fini");
+ return amt(ctx, WindowNo, mTab, mField, value);
+ } // tax
+
+
+ /**
+ * Order Line - Amount.
+ * - called from QtyOrdered, Discount and PriceActual
+ * - calculates Discount or Actual Amount
+ * - calculates LineNetAmt
+ * - enforces PriceLimit
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String amt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ if (steps) log.warning("init");
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ int StdPrecision = MPriceList.getStandardPrecision(ctx, M_PriceList_ID);
+ BigDecimal QtyEntered, QtyOrdered, PriceEntered, PriceActual, PriceLimit, Discount, PriceList;
+ // get values
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ QtyOrdered = (BigDecimal)mTab.getValue("QtyOrdered");
+ log.fine("QtyEntered=" + QtyEntered + ", Ordered=" + QtyOrdered + ", UOM=" + C_UOM_To_ID);
+ //
+ PriceEntered = (BigDecimal)mTab.getValue("PriceEntered");
+ PriceActual = (BigDecimal)mTab.getValue("PriceActual");
+ Discount = (BigDecimal)mTab.getValue("Discount");
+ PriceLimit = (BigDecimal)mTab.getValue("PriceLimit");
+ PriceList = (BigDecimal)mTab.getValue("PriceList");
+ log.fine("PriceList=" + PriceList + ", Limit=" + PriceLimit + ", Precision=" + StdPrecision);
+ log.fine("PriceEntered=" + PriceEntered + ", Actual=" + PriceActual + ", Discount=" + Discount);
+
+ // Qty changed - recalc price
+ if ((mField.getColumnName().equals("QtyOrdered")
+ || mField.getColumnName().equals("QtyEntered")
+ || mField.getColumnName().equals("M_Product_ID"))
+ && !"N".equals(Env.getContext(ctx, WindowNo, "DiscountSchema")))
+ {
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID");
+ if (mField.getColumnName().equals("QtyEntered"))
+ QtyOrdered = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyOrdered == null)
+ QtyOrdered = QtyEntered;
+ boolean IsSOTrx = Env.getContext(ctx, WindowNo, "IsSOTrx").equals("Y");
+ MProductPricing pp = new MProductPricing (M_Product_ID, C_BPartner_ID, QtyOrdered, IsSOTrx);
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp date = (Timestamp)mTab.getValue("DateOrdered");
+ pp.setPriceDate(date);
+ //
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, pp.getPriceStd());
+ if (PriceEntered == null)
+ PriceEntered = pp.getPriceStd();
+ //
+ log.fine("QtyChanged -> PriceActual=" + pp.getPriceStd()
+ + ", PriceEntered=" + PriceEntered + ", Discount=" + pp.getDiscount());
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ mTab.setValue("Discount", pp.getDiscount());
+ mTab.setValue("PriceEntered", PriceEntered);
+ Env.setContext(ctx, WindowNo, "DiscountSchema", pp.isDiscountSchema() ? "Y" : "N");
+ }
+ else if (mField.getColumnName().equals("PriceActual"))
+ {
+ PriceActual = (BigDecimal)value;
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ //
+ log.fine("PriceActual=" + PriceActual
+ + " -> PriceEntered=" + PriceEntered);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ else if (mField.getColumnName().equals("PriceEntered"))
+ {
+ PriceEntered = (BigDecimal)value;
+ PriceActual = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceEntered);
+ if (PriceActual == null)
+ PriceActual = PriceEntered;
+ //
+ log.fine("PriceEntered=" + PriceEntered
+ + " -> PriceActual=" + PriceActual);
+ mTab.setValue("PriceActual", PriceActual);
+ }
+
+ // Discount entered - Calculate Actual/Entered
+ if (mField.getColumnName().equals("Discount"))
+ {
+ PriceActual = new BigDecimal ((100.0 - Discount.doubleValue()) / 100.0 * PriceList.doubleValue());
+ if (PriceActual.scale() > StdPrecision)
+ PriceActual = PriceActual.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ mTab.setValue("PriceActual", PriceActual);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ // calculate Discount
+ else
+ {
+ if (PriceList.intValue() == 0)
+ Discount = Env.ZERO;
+ else
+ Discount = new BigDecimal ((PriceList.doubleValue() - PriceActual.doubleValue()) / PriceList.doubleValue() * 100.0);
+ if (Discount.scale() > 2)
+ Discount = Discount.setScale(2, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("Discount", Discount);
+ }
+ log.fine("PriceEntered=" + PriceEntered + ", Actual=" + PriceActual + ", Discount=" + Discount);
+
+ // Check PriceLimit
+ String epl = Env.getContext(ctx, WindowNo, "EnforcePriceLimit");
+ boolean enforce = Env.isSOTrx(ctx, WindowNo) && epl != null && epl.equals("Y");
+ if (enforce && MRole.getDefault().isOverwritePriceLimit())
+ enforce = false;
+ // Check Price Limit?
+ if (enforce && PriceLimit.doubleValue() != 0.0
+ && PriceActual.compareTo(PriceLimit) < 0)
+ {
+ PriceActual = PriceLimit;
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceLimit);
+ if (PriceEntered == null)
+ PriceEntered = PriceLimit;
+ log.fine("(under) PriceEntered=" + PriceEntered + ", Actual" + PriceLimit);
+ mTab.setValue ("PriceActual", PriceLimit);
+ mTab.setValue ("PriceEntered", PriceEntered);
+ mTab.fireDataStatusEEvent ("UnderLimitPrice", "", false);
+ // Repeat Discount calc
+ if (PriceList.intValue() != 0)
+ {
+ Discount = new BigDecimal ((PriceList.doubleValue () - PriceActual.doubleValue ()) / PriceList.doubleValue () * 100.0);
+ if (Discount.scale () > 2)
+ Discount = Discount.setScale (2, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue ("Discount", Discount);
+ }
+ }
+
+ // Line Net Amt
+ BigDecimal LineNetAmt = QtyOrdered.multiply(PriceActual);
+ if (LineNetAmt.scale() > StdPrecision)
+ LineNetAmt = LineNetAmt.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ log.info("LineNetAmt=" + LineNetAmt);
+ mTab.setValue("LineNetAmt", LineNetAmt);
+ //
+ setCalloutActive(false);
+ return "";
+ } // amt
+
+ /**
+ * Order Line - Quantity.
+ * - called from C_UOM_ID, QtyEntered, QtyOrdered
+ * - enforces qty UOM relationship
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String qty (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID");
+ if (steps) log.warning("init - M_Product_ID=" + M_Product_ID + " - " );
+ BigDecimal QtyOrdered = Env.ZERO;
+ BigDecimal QtyEntered, PriceActual, PriceEntered;
+
+ // No Product
+ if (M_Product_ID == 0)
+ {
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ QtyOrdered = QtyEntered;
+ mTab.setValue("QtyOrdered", QtyOrdered);
+ }
+ // UOM Changed - convert from Entered -> Product
+ else if (mField.getColumnName().equals("C_UOM_ID"))
+ {
+ int C_UOM_To_ID = ((Integer)value).intValue();
+ QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ QtyOrdered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyOrdered == null)
+ QtyOrdered = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(QtyOrdered) != 0;
+ PriceActual = (BigDecimal)mTab.getValue("PriceActual");
+ PriceEntered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, PriceActual);
+ if (PriceEntered == null)
+ PriceEntered = PriceActual;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", QtyEntered/PriceActual=" + QtyEntered + "/" + PriceActual
+ + " -> " + conversion
+ + " QtyOrdered/PriceEntered=" + QtyOrdered + "/" + PriceEntered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyOrdered", QtyOrdered);
+ mTab.setValue("PriceEntered", PriceEntered);
+ }
+ // QtyEntered changed - calculate QtyOrdered
+ else if (mField.getColumnName().equals("QtyEntered"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ QtyEntered = (BigDecimal)value;
+ BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
+ if (QtyEntered.compareTo(QtyEntered1) != 0)
+ {
+ log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID
+ + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);
+ QtyEntered = QtyEntered1;
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ QtyOrdered = MUOMConversion.convertProductFrom (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyEntered);
+ if (QtyOrdered == null)
+ QtyOrdered = QtyEntered;
+ boolean conversion = QtyEntered.compareTo(QtyOrdered) != 0;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", QtyEntered=" + QtyEntered
+ + " -> " + conversion
+ + " QtyOrdered=" + QtyOrdered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyOrdered", QtyOrdered);
+ }
+ // QtyOrdered changed - calculate QtyEntered (should not happen)
+ else if (mField.getColumnName().equals("QtyOrdered"))
+ {
+ int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
+ QtyOrdered = (BigDecimal)value;
+ int precision = MProduct.get(ctx, M_Product_ID).getUOMPrecision();
+ BigDecimal QtyOrdered1 = QtyOrdered.setScale(precision, BigDecimal.ROUND_HALF_UP);
+ if (QtyOrdered.compareTo(QtyOrdered1) != 0)
+ {
+ log.fine("Corrected QtyOrdered Scale "
+ + QtyOrdered + "->" + QtyOrdered1);
+ QtyOrdered = QtyOrdered1;
+ mTab.setValue("QtyOrdered", QtyOrdered);
+ }
+ QtyEntered = MUOMConversion.convertProductTo (ctx, M_Product_ID,
+ C_UOM_To_ID, QtyOrdered);
+ if (QtyEntered == null)
+ QtyEntered = QtyOrdered;
+ boolean conversion = QtyOrdered.compareTo(QtyEntered) != 0;
+ log.fine("UOM=" + C_UOM_To_ID
+ + ", QtyOrdered=" + QtyOrdered
+ + " -> " + conversion
+ + " QtyEntered=" + QtyEntered);
+ Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
+ mTab.setValue("QtyEntered", QtyEntered);
+ }
+ else
+ {
+ // QtyEntered = (BigDecimal)mTab.getValue("QtyEntered");
+ QtyOrdered = (BigDecimal)mTab.getValue("QtyOrdered");
+ }
+
+ // Storage
+ if (M_Product_ID != 0
+ && Env.isSOTrx(ctx, WindowNo)
+ && QtyOrdered.signum() > 0) // no negative (returns)
+ {
+ MProduct product = MProduct.get (ctx, M_Product_ID);
+ if (product.isStocked())
+ {
+ int M_Warehouse_ID = Env.getContextAsInt(ctx, WindowNo, "M_Warehouse_ID");
+ int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID");
+ BigDecimal available = MStorage.getQtyAvailable
+ (M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, null);
+ if (available == null)
+ available = Env.ZERO;
+ if (available.signum() == 0)
+ mTab.fireDataStatusEEvent ("NoQtyAvailable", "0", false);
+ else if (available.compareTo(QtyOrdered) < 0)
+ mTab.fireDataStatusEEvent ("InsufficientQtyAvailable", available.toString(), false);
+ else
+ {
+ Integer C_OrderLine_ID = (Integer)mTab.getValue("C_OrderLine_ID");
+ if (C_OrderLine_ID == null)
+ C_OrderLine_ID = new Integer(0);
+ BigDecimal notReserved = MOrderLine.getNotReserved(ctx,
+ M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID,
+ C_OrderLine_ID.intValue());
+ if (notReserved == null)
+ notReserved = Env.ZERO;
+ BigDecimal total = available.subtract(notReserved);
+ if (total.compareTo(QtyOrdered) < 0)
+ {
+ String info = Msg.parseTranslation(ctx, "@QtyAvailable@=" + available
+ + " - @QtyNotReserved@=" + notReserved + " = " + total);
+ mTab.fireDataStatusEEvent ("InsufficientQtyAvailable",
+ info, false);
+ }
+ }
+ }
+ }
+ //
+ setCalloutActive(false);
+ return "";
+ } // qty
+
+} // CalloutOrder
+
diff --git a/base/src/org/compiere/model/CalloutPaySelection.java b/base/src/org/compiere/model/CalloutPaySelection.java
new file mode 100644
index 0000000000..d18763b5c6
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutPaySelection.java
@@ -0,0 +1,137 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+
+/**
+ * Payment Selection Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutPaySelection.java,v 1.3 2006/07/30 00:51:02 jjanke Exp $
+ */
+public class CalloutPaySelection extends CalloutEngine
+{
+ /**
+ * Payment Selection Line - Payment Amount.
+ * - called from C_PaySelectionLine.PayAmt
+ * - update DifferenceAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String payAmt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ // get invoice info
+ Integer ii = (Integer)mTab.getValue("C_Invoice_ID");
+ if (ii == null)
+ return "";
+ int C_Invoice_ID = ii.intValue();
+ if (C_Invoice_ID == 0)
+ return "";
+ //
+ BigDecimal OpenAmt = (BigDecimal)mTab.getValue("OpenAmt");
+ BigDecimal PayAmt = (BigDecimal)mTab.getValue("PayAmt");
+ BigDecimal DiscountAmt = (BigDecimal)mTab.getValue("DiscountAmt");
+ setCalloutActive(true);
+ BigDecimal DifferenceAmt = OpenAmt.subtract(PayAmt).subtract(DiscountAmt);
+ log.fine(" - OpenAmt=" + OpenAmt + " - PayAmt=" + PayAmt
+ + ", Discount=" + DiscountAmt + ", Difference=" + DifferenceAmt);
+
+ mTab.setValue("DifferenceAmt", DifferenceAmt);
+
+ setCalloutActive(false);
+ return "";
+ } // PaySel_PayAmt
+
+ /**
+ * Payment Selection Line - Invoice.
+ * - called from C_PaySelectionLine.C_Invoice_ID
+ * - update PayAmt & DifferenceAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String invoice (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ // get value
+ int C_Invoice_ID = ((Integer)value).intValue();
+ if (C_Invoice_ID == 0)
+ return "";
+ int C_BankAccount_ID = Env.getContextAsInt(ctx, WindowNo, "C_BankAccount_ID");
+ Timestamp PayDate = Env.getContextAsDate(ctx, "PayDate");
+ if (PayDate == null)
+ PayDate = new Timestamp(System.currentTimeMillis());
+ setCalloutActive(true);
+
+ BigDecimal OpenAmt = Env.ZERO;
+ BigDecimal DiscountAmt = Env.ZERO;
+ Boolean IsSOTrx = Boolean.FALSE;
+ String sql = "SELECT currencyConvert(invoiceOpen(i.C_Invoice_ID, 0), i.C_Currency_ID,"
+ + "ba.C_Currency_ID, i.DateInvoiced, i.C_ConversionType_ID, i.AD_Client_ID, i.AD_Org_ID),"
+ + " paymentTermDiscount(i.GrandTotal,i.C_Currency_ID,i.C_PaymentTerm_ID,i.DateInvoiced, ?), i.IsSOTrx "
+ + "FROM C_Invoice_v i, C_BankAccount ba "
+ + "WHERE i.C_Invoice_ID=? AND ba.C_BankAccount_ID=?"; // #1..2
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Invoice_ID);
+ pstmt.setInt(2, C_BankAccount_ID);
+ pstmt.setTimestamp(3, PayDate);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ OpenAmt = rs.getBigDecimal(1);
+ DiscountAmt = rs.getBigDecimal(2);
+ IsSOTrx = new Boolean ("Y".equals(rs.getString(3)));
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+
+ log.fine(" - OpenAmt=" + OpenAmt + " (Invoice=" + C_Invoice_ID + ",BankAcct=" + C_BankAccount_ID + ")");
+ mTab.setValue("OpenAmt", OpenAmt);
+ mTab.setValue("PayAmt", OpenAmt.subtract(DiscountAmt));
+ mTab.setValue("DiscountAmt", DiscountAmt);
+ mTab.setValue("DifferenceAmt", Env.ZERO);
+ mTab.setValue("IsSOTrx", IsSOTrx);
+
+ setCalloutActive(false);
+ return "";
+ } // PaySel_Invoice
+
+
+} // CalloutPaySelection
diff --git a/base/src/org/compiere/model/CalloutPayment.java b/base/src/org/compiere/model/CalloutPayment.java
new file mode 100644
index 0000000000..f27eedd5cb
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutPayment.java
@@ -0,0 +1,444 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Payment Callouts.
+ * org.compiere.model.CalloutPayment.*
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutPayment.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutPayment extends CalloutEngine
+{
+ /**
+ * Payment_Invoice.
+ * when Invoice selected
+ * - set C_Currency_ID
+ * - C_BPartner_ID
+ * - DiscountAmt = C_Invoice_Discount (ID, DateTrx)
+ * - PayAmt = invoiceOpen (ID) - Discount
+ * - WriteOffAmt = 0
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String invoice (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Invoice_ID = (Integer)value;
+ if (isCalloutActive() // assuming it is resetting value
+ || C_Invoice_ID == null || C_Invoice_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ mTab.setValue("C_Order_ID", null);
+ mTab.setValue("C_Charge_ID", null);
+ mTab.setValue("IsPrepayment", Boolean.FALSE);
+ //
+ mTab.setValue("DiscountAmt", Env.ZERO);
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ mTab.setValue("IsOverUnderPayment", Boolean.FALSE);
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+
+ int C_InvoicePaySchedule_ID = 0;
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_Invoice_ID") == C_Invoice_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID") != 0)
+ C_InvoicePaySchedule_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID");
+
+ // Payment Date
+ Timestamp ts = (Timestamp)mTab.getValue("DateTrx");
+ if (ts == null)
+ ts = new Timestamp(System.currentTimeMillis());
+ //
+ String sql = "SELECT C_BPartner_ID,C_Currency_ID," // 1..2
+ + " invoiceOpen(C_Invoice_ID, ?)," // 3 #1
+ + " invoiceDiscount(C_Invoice_ID,?,?), IsSOTrx " // 4..5 #2/3
+ + "FROM C_Invoice WHERE C_Invoice_ID=?"; // #4
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_InvoicePaySchedule_ID);
+ pstmt.setTimestamp(2, ts);
+ pstmt.setInt(3, C_InvoicePaySchedule_ID);
+ pstmt.setInt(4, C_Invoice_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue("C_BPartner_ID", new Integer(rs.getInt(1)));
+ int C_Currency_ID = rs.getInt(2); // Set Invoice Currency
+ mTab.setValue("C_Currency_ID", new Integer(C_Currency_ID));
+ //
+ BigDecimal InvoiceOpen = rs.getBigDecimal(3); // Set Invoice OPen Amount
+ if (InvoiceOpen == null)
+ InvoiceOpen = Env.ZERO;
+ BigDecimal DiscountAmt = rs.getBigDecimal(4); // Set Discount Amt
+ if (DiscountAmt == null)
+ DiscountAmt = Env.ZERO;
+ mTab.setValue("PayAmt", InvoiceOpen.subtract(DiscountAmt));
+ mTab.setValue("DiscountAmt", DiscountAmt);
+ // reset as dependent fields get reset
+ Env.setContext(ctx, WindowNo, "C_Invoice_ID", C_Invoice_ID.toString());
+ mTab.setValue("C_Invoice_ID", C_Invoice_ID);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+
+ setCalloutActive(false);
+ return docType(ctx, WindowNo, mTab, mField, value);
+ } // invoice
+
+ /**
+ * Payment_Order.
+ * when Waiting Payment Order selected
+ * - set C_Currency_ID
+ * - C_BPartner_ID
+ * - DiscountAmt = C_Invoice_Discount (ID, DateTrx)
+ * - PayAmt = invoiceOpen (ID) - Discount
+ * - WriteOffAmt = 0
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String order (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Order_ID = (Integer)value;
+ if (isCalloutActive() // assuming it is resetting value
+ || C_Order_ID == null || C_Order_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ mTab.setValue("C_Invoice_ID", null);
+ mTab.setValue("C_Charge_ID", null);
+ mTab.setValue("IsPrepayment", Boolean.TRUE);
+ //
+ mTab.setValue("DiscountAmt", Env.ZERO);
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ mTab.setValue("IsOverUnderPayment", Boolean.FALSE);
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+
+ // Payment Date
+ Timestamp ts = (Timestamp)mTab.getValue("DateTrx");
+ if (ts == null)
+ ts = new Timestamp(System.currentTimeMillis());
+ //
+ String sql = "SELECT C_BPartner_ID,C_Currency_ID, GrandTotal "
+ + "FROM C_Order WHERE C_Order_ID=?"; // #1
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_Order_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ mTab.setValue("C_BPartner_ID", new Integer(rs.getInt(1)));
+ int C_Currency_ID = rs.getInt(2); // Set Order Currency
+ mTab.setValue("C_Currency_ID", new Integer(C_Currency_ID));
+ //
+ BigDecimal GrandTotal = rs.getBigDecimal(3); // Set Pay Amount
+ if (GrandTotal == null)
+ GrandTotal = Env.ZERO;
+ mTab.setValue("PayAmt", GrandTotal);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+
+ setCalloutActive(false);
+ return docType(ctx, WindowNo, mTab, mField, value);
+ } // order
+
+ /**
+ * Payment_Project.
+ * - reset - C_BPartner_ID, Invoice, Order, Project,
+ * Discount, WriteOff
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String project (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Project_ID = (Integer)value;
+ if (isCalloutActive() // assuming it is resetting value
+ || C_Project_ID == null || C_Project_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ mTab.setValue("C_Charge_ID", null);
+ setCalloutActive(false);
+ return "";
+ } // project
+
+ /**
+ * Payment_Charge.
+ * - reset - C_BPartner_ID, Invoice, Order, Project,
+ * Discount, WriteOff
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String charge (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Charge_ID = (Integer)value;
+ if (isCalloutActive() // assuming it is resetting value
+ || C_Charge_ID == null || C_Charge_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ mTab.setValue("C_Invoice_ID", null);
+ mTab.setValue("C_Order_ID", null);
+ mTab.setValue("C_Project_ID", null);
+ mTab.setValue("IsPrepayment", Boolean.FALSE);
+ //
+ mTab.setValue("DiscountAmt", Env.ZERO);
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ mTab.setValue("IsOverUnderPayment", Boolean.FALSE);
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+ setCalloutActive(false);
+ return "";
+ } // charge
+
+ /**
+ * Payment_Document Type.
+ * Verify that Document Type (AP/AR) and Invoice (SO/PO) are in sync
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String docType (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ int C_Invoice_ID = Env.getContextAsInt(ctx, WindowNo, "C_Invoice_ID");
+ int C_Order_ID = Env.getContextAsInt(ctx, WindowNo, "C_Order_ID");
+ int C_DocType_ID = Env.getContextAsInt(ctx, WindowNo, "C_DocType_ID");
+ log.fine("Payment_DocType - C_Invoice_ID=" + C_Invoice_ID + ", C_DocType_ID=" + C_DocType_ID);
+ MDocType dt = null;
+ if (C_DocType_ID != 0)
+ {
+ dt = MDocType.get(ctx, C_DocType_ID);
+ Env.setContext(ctx, WindowNo, "IsSOTrx", dt.isSOTrx() ? "Y" : "N");
+ }
+ // Invoice
+ if (C_Invoice_ID != 0)
+ {
+ MInvoice inv = new MInvoice (ctx, C_Invoice_ID, null);
+ if (dt != null)
+ {
+ if (inv.isSOTrx() != dt.isSOTrx())
+ return "PaymentDocTypeInvoiceInconsistent";
+ }
+ }
+ // Order Waiting Payment (can only be SO)
+ if (C_Order_ID != 0 && !dt.isSOTrx())
+ return "PaymentDocTypeInvoiceInconsistent";
+
+ return "";
+ } // docType
+
+
+ /**
+ * Payment_Amounts.
+ * Change of:
+ * - IsOverUnderPayment -> set OverUnderAmt to 0
+ * - C_Currency_ID, C_ConvesionRate_ID -> convert all
+ * - PayAmt, DiscountAmt, WriteOffAmt, OverUnderAmt -> PayAmt
+ * make sure that add up to InvoiceOpenAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @param oldValue Old Value
+ * @return null or error message
+ */
+ public String amounts (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue)
+ {
+ if (isCalloutActive()) // assuming it is resetting value
+ return "";
+ int C_Invoice_ID = Env.getContextAsInt(ctx, WindowNo, "C_Invoice_ID");
+ // New Payment
+ if (Env.getContextAsInt(ctx, WindowNo, "C_Payment_ID") == 0
+ && Env.getContextAsInt(ctx, WindowNo, "C_BPartner_ID") == 0
+ && C_Invoice_ID == 0)
+ return "";
+ setCalloutActive(true);
+
+ // Changed Column
+ String colName = mField.getColumnName();
+ if (colName.equals("IsOverUnderPayment") // Set Over/Under Amt to Zero
+ || !"Y".equals(Env.getContext(ctx, WindowNo, "IsOverUnderPayment")))
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+
+ int C_InvoicePaySchedule_ID = 0;
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_Invoice_ID") == C_Invoice_ID
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID") != 0)
+ C_InvoicePaySchedule_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID");
+
+ // Get Open Amount & Invoice Currency
+ BigDecimal InvoiceOpenAmt = Env.ZERO;
+ int C_Currency_Invoice_ID = 0;
+ if (C_Invoice_ID != 0)
+ {
+ Timestamp ts = (Timestamp)mTab.getValue("DateTrx");
+ if (ts == null)
+ ts = new Timestamp(System.currentTimeMillis());
+ String sql = "SELECT C_BPartner_ID,C_Currency_ID," // 1..2
+ + " invoiceOpen(C_Invoice_ID,?)," // 3 #1
+ + " invoiceDiscount(C_Invoice_ID,?,?), IsSOTrx " // 4..5 #2/3
+ + "FROM C_Invoice WHERE C_Invoice_ID=?"; // #4
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_InvoicePaySchedule_ID);
+ pstmt.setTimestamp(2, ts);
+ pstmt.setInt(3, C_InvoicePaySchedule_ID);
+ pstmt.setInt(4, C_Invoice_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ C_Currency_Invoice_ID= rs.getInt(2);
+ InvoiceOpenAmt = rs.getBigDecimal(3); // Set Invoice Open Amount
+ if (InvoiceOpenAmt == null)
+ InvoiceOpenAmt = Env.ZERO;
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+ } // get Invoice Info
+ log.fine("Open=" + InvoiceOpenAmt + ", C_Invoice_ID=" + C_Invoice_ID
+ + ", C_Currency_ID=" + C_Currency_Invoice_ID);
+
+ // Get Info from Tab
+ BigDecimal PayAmt = (BigDecimal)mTab.getValue("PayAmt");
+ BigDecimal DiscountAmt = (BigDecimal)mTab.getValue("DiscountAmt");
+ BigDecimal WriteOffAmt = (BigDecimal)mTab.getValue("WriteOffAmt");
+ BigDecimal OverUnderAmt = (BigDecimal)mTab.getValue("OverUnderAmt");
+ log.fine("Pay=" + PayAmt + ", Discount=" + DiscountAmt
+ + ", WriteOff=" + WriteOffAmt + ", OverUnderAmt=" + OverUnderAmt);
+ // Get Currency Info
+ int C_Currency_ID = ((Integer)mTab.getValue("C_Currency_ID")).intValue();
+ MCurrency currency = MCurrency.get(ctx, C_Currency_ID);
+ Timestamp ConvDate = (Timestamp)mTab.getValue("DateTrx");
+ int C_ConversionType_ID = 0;
+ Integer ii = (Integer)mTab.getValue("C_ConversionType_ID");
+ if (ii != null)
+ C_ConversionType_ID = ii.intValue();
+ int AD_Client_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Client_ID");
+ int AD_Org_ID = Env.getContextAsInt(ctx, WindowNo, "AD_Org_ID");
+ // Get Currency Rate
+ BigDecimal CurrencyRate = Env.ONE;
+ if ((C_Currency_ID > 0 && C_Currency_Invoice_ID > 0 &&
+ C_Currency_ID != C_Currency_Invoice_ID)
+ || colName.equals("C_Currency_ID") || colName.equals("C_ConversionType_ID"))
+ {
+ log.fine("InvCurrency=" + C_Currency_Invoice_ID
+ + ", PayCurrency=" + C_Currency_ID
+ + ", Date=" + ConvDate + ", Type=" + C_ConversionType_ID);
+ CurrencyRate = MConversionRate.getRate (C_Currency_Invoice_ID, C_Currency_ID,
+ ConvDate, C_ConversionType_ID, AD_Client_ID, AD_Org_ID);
+ if (CurrencyRate == null || CurrencyRate.compareTo(Env.ZERO) == 0)
+ {
+ // mTab.setValue("C_Currency_ID", new Integer(C_Currency_Invoice_ID)); // does not work
+ setCalloutActive(false);
+ if (C_Currency_Invoice_ID == 0)
+ return ""; // no error message when no invoice is selected
+ return "NoCurrencyConversion";
+ }
+ //
+ InvoiceOpenAmt = InvoiceOpenAmt.multiply(CurrencyRate)
+ .setScale(currency.getStdPrecision(), BigDecimal.ROUND_HALF_UP);
+ log.fine("Rate=" + CurrencyRate + ", InvoiceOpenAmt=" + InvoiceOpenAmt);
+ }
+
+ // Currency Changed - convert all
+ if (colName.equals("C_Currency_ID") || colName.equals("C_ConversionType_ID"))
+ {
+ PayAmt = PayAmt.multiply(CurrencyRate)
+ .setScale(currency.getStdPrecision(), BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("PayAmt", PayAmt);
+ DiscountAmt = DiscountAmt.multiply(CurrencyRate)
+ .setScale(currency.getStdPrecision(), BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("DiscountAmt", DiscountAmt);
+ WriteOffAmt = WriteOffAmt.multiply(CurrencyRate)
+ .setScale(currency.getStdPrecision(), BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("WriteOffAmt", WriteOffAmt);
+ OverUnderAmt = OverUnderAmt.multiply(CurrencyRate)
+ .setScale(currency.getStdPrecision(), BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("OverUnderAmt", OverUnderAmt);
+ }
+
+ // No Invoice - Set Discount, Witeoff, Under/Over to 0
+ else if (C_Invoice_ID == 0)
+ {
+ if (Env.ZERO.compareTo(DiscountAmt) != 0)
+ mTab.setValue("DiscountAmt", Env.ZERO);
+ if (Env.ZERO.compareTo(WriteOffAmt) != 0)
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ if (Env.ZERO.compareTo(OverUnderAmt) != 0)
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+ }
+ // PayAmt - calculate write off
+ else if (colName.equals("PayAmt"))
+ {
+ WriteOffAmt = InvoiceOpenAmt.subtract(PayAmt).subtract(DiscountAmt).subtract(OverUnderAmt);
+ mTab.setValue("WriteOffAmt", WriteOffAmt);
+ }
+ else // calculate PayAmt
+ {
+ PayAmt = InvoiceOpenAmt.subtract(DiscountAmt).subtract(WriteOffAmt).subtract(OverUnderAmt);
+ mTab.setValue("PayAmt", PayAmt);
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // amounts
+
+} // CalloutPayment
diff --git a/base/src/org/compiere/model/CalloutPaymentAllocate.java b/base/src/org/compiere/model/CalloutPaymentAllocate.java
new file mode 100644
index 0000000000..86e44254fe
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutPaymentAllocate.java
@@ -0,0 +1,174 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Callout for Allocate Payments
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutPaymentAllocate.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $
+ */
+public class CalloutPaymentAllocate extends CalloutEngine
+{
+ /**
+ * Payment_Invoice.
+ * when Invoice selected
+ * - set InvoiceAmt = invoiceOpen
+ * - DiscountAmt = C_Invoice_Discount (ID, DateTrx)
+ * - Amount = invoiceOpen (ID) - Discount
+ * - WriteOffAmt,OverUnderAmt = 0
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String invoice (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer C_Invoice_ID = (Integer)value;
+ if (isCalloutActive() // assuming it is resetting value
+ || C_Invoice_ID == null || C_Invoice_ID.intValue() == 0)
+ return "";
+
+ // Check Payment
+ int C_Payment_ID = Env.getContextAsInt(ctx, WindowNo, "C_Payment_ID");
+ MPayment payment = new MPayment (ctx, C_Payment_ID, null);
+ if (payment.getC_Charge_ID() != 0 || payment.getC_Invoice_ID() != 0
+ || payment.getC_Order_ID() != 0)
+ return Msg.getMsg(ctx, "PaymentIsAllocated");
+
+ setCalloutActive(true);
+ //
+ mTab.setValue("DiscountAmt", Env.ZERO);
+ mTab.setValue("WriteOffAmt", Env.ZERO);
+ mTab.setValue("OverUnderAmt", Env.ZERO);
+
+ int C_InvoicePaySchedule_ID = 0;
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_Invoice_ID") == C_Invoice_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID") != 0)
+ C_InvoicePaySchedule_ID = Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "C_InvoicePaySchedule_ID");
+
+ // Payment Date
+ Timestamp ts = Env.getContextAsDate(ctx, WindowNo, "DateTrx");
+ //
+ String sql = "SELECT C_BPartner_ID,C_Currency_ID," // 1..2
+ + " invoiceOpen(C_Invoice_ID, ?)," // 3 #1
+ + " invoiceDiscount(C_Invoice_ID,?,?), IsSOTrx " // 4..5 #2/3
+ + "FROM C_Invoice WHERE C_Invoice_ID=?"; // #4
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_InvoicePaySchedule_ID);
+ pstmt.setTimestamp(2, ts);
+ pstmt.setInt(3, C_InvoicePaySchedule_ID);
+ pstmt.setInt(4, C_Invoice_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // mTab.setValue("C_BPartner_ID", new Integer(rs.getInt(1)));
+ // int C_Currency_ID = rs.getInt(2); // Set Invoice Currency
+ // mTab.setValue("C_Currency_ID", new Integer(C_Currency_ID));
+ //
+ BigDecimal InvoiceOpen = rs.getBigDecimal(3); // Set Invoice OPen Amount
+ if (InvoiceOpen == null)
+ InvoiceOpen = Env.ZERO;
+ BigDecimal DiscountAmt = rs.getBigDecimal(4); // Set Discount Amt
+ if (DiscountAmt == null)
+ DiscountAmt = Env.ZERO;
+ mTab.setValue("InvoiceAmt", InvoiceOpen);
+ mTab.setValue("Amount", InvoiceOpen.subtract(DiscountAmt));
+ mTab.setValue("DiscountAmt", DiscountAmt);
+ // reset as dependent fields get reset
+ Env.setContext(ctx, WindowNo, "C_Invoice_ID", C_Invoice_ID.toString());
+ mTab.setValue("C_Invoice_ID", C_Invoice_ID);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // invoice
+
+ /**
+ * Payment_Amounts.
+ * Change of:
+ * - IsOverUnderPayment -> set OverUnderAmt to 0
+ * - C_Currency_ID, C_ConvesionRate_ID -> convert all
+ * - PayAmt, DiscountAmt, WriteOffAmt, OverUnderAmt -> PayAmt
+ * make sure that add up to InvoiceOpenAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @param oldValue Old Value
+ * @return null or error message
+ */
+ public String amounts (Properties ctx, int WindowNo, GridTab mTab, GridField mField,
+ Object value, Object oldValue)
+ {
+ if (isCalloutActive()) // assuming it is resetting value
+ return "";
+ // No Invoice
+ int C_Invoice_ID = Env.getContextAsInt(ctx, WindowNo, "C_Invoice_ID");
+ if (C_Invoice_ID == 0)
+ return "";
+ setCalloutActive(true);
+ // Get Info from Tab
+ BigDecimal Amount = (BigDecimal)mTab.getValue("Amount");
+ BigDecimal DiscountAmt = (BigDecimal)mTab.getValue("DiscountAmt");
+ BigDecimal WriteOffAmt = (BigDecimal)mTab.getValue("WriteOffAmt");
+ BigDecimal OverUnderAmt = (BigDecimal)mTab.getValue("OverUnderAmt");
+ BigDecimal InvoiceAmt = (BigDecimal)mTab.getValue("InvoiceAmt");
+ log.fine("Amt=" + Amount + ", Discount=" + DiscountAmt
+ + ", WriteOff=" + WriteOffAmt + ", OverUnder=" + OverUnderAmt
+ + ", Invoice=" + InvoiceAmt);
+
+ // Changed Column
+ String colName = mField.getColumnName();
+ // PayAmt - calculate write off
+ if (colName.equals("Amount"))
+ {
+ WriteOffAmt = InvoiceAmt.subtract(Amount).subtract(DiscountAmt).subtract(OverUnderAmt);
+ mTab.setValue("WriteOffAmt", WriteOffAmt);
+ }
+ else // calculate Amount
+ {
+ Amount = InvoiceAmt.subtract(DiscountAmt).subtract(WriteOffAmt).subtract(OverUnderAmt);
+ mTab.setValue("Amount", Amount);
+ }
+
+ setCalloutActive(false);
+ return "";
+ } // amounts
+
+
+} // CalloutPaymentAllocate
diff --git a/base/src/org/compiere/model/CalloutProduction.java b/base/src/org/compiere/model/CalloutProduction.java
new file mode 100644
index 0000000000..90cd1b70cd
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutProduction.java
@@ -0,0 +1,55 @@
+/******************************************************************************
+ * 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.model;
+
+import java.util.*;
+import org.compiere.util.*;
+
+/**
+ * Production Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutProduction.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutProduction extends CalloutEngine
+{
+ /**
+ * Product modified
+ * Set Attribute Set Instance
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ // Set Attribute
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ return "";
+ } // product
+
+} // CalloutProduction
diff --git a/base/src/org/compiere/model/CalloutProject.java b/base/src/org/compiere/model/CalloutProject.java
new file mode 100644
index 0000000000..fe61d9e463
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutProject.java
@@ -0,0 +1,71 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.util.*;
+import org.compiere.util.*;
+
+
+/**
+ * Project Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutProject.java,v 1.3 2006/07/30 00:51:04 jjanke Exp $
+ */
+public class CalloutProject extends CalloutEngine
+{
+ /**
+ * Project Planned - Price + Qty.
+ * - called from PlannedPrice, PlannedQty
+ * - calculates PlannedAmt (same as Trigger)
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String planned (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ BigDecimal PlannedQty, PlannedPrice;
+ int StdPrecision = Env.getContextAsInt(ctx, WindowNo, "StdPrecision");
+
+
+ // get values
+ PlannedQty = (BigDecimal)mTab.getValue("PlannedQty");
+ if (PlannedQty == null)
+ PlannedQty = Env.ONE;
+ PlannedPrice = ((BigDecimal)mTab.getValue("PlannedPrice"));
+ if (PlannedPrice == null)
+ PlannedPrice = Env.ZERO;
+ //
+ BigDecimal PlannedAmt = PlannedQty.multiply(PlannedPrice);
+ if (PlannedAmt.scale() > StdPrecision)
+ PlannedAmt = PlannedAmt.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ //
+ log.fine("PlannedQty=" + PlannedQty + " * PlannedPrice=" + PlannedPrice + " -> PlannedAmt=" + PlannedAmt + " (Precision=" + StdPrecision+ ")");
+ mTab.setValue("PlannedAmt", PlannedAmt);
+ setCalloutActive(false);
+ return "";
+ } // planned
+
+} // CalloutProject
diff --git a/base/src/org/compiere/model/CalloutRequest.java b/base/src/org/compiere/model/CalloutRequest.java
new file mode 100644
index 0000000000..da28d7371d
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutRequest.java
@@ -0,0 +1,142 @@
+/******************************************************************************
+ * 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.model;
+
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Request Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutRequest.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutRequest extends CalloutEngine
+{
+ /**
+ * Request - Copy Mail Text - Callout
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String copyMail (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String colName = mField.getColumnName();
+ log.info(colName + "=" + value);
+ if (value == null)
+ return "";
+
+ Integer R_MailText_ID = (Integer)value;
+ String sql = "SELECT MailHeader, MailText FROM R_MailText "
+ + "WHERE R_MailText_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, R_MailText_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ String txt = rs.getString(2);
+ txt = Env.parseContext(ctx, WindowNo, txt, false, true);
+ mTab.setValue("Result", txt);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ return "";
+ } // copyText
+
+
+ /**
+ * Request - Copy Response Text - Callout
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String copyResponse (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String colName = mField.getColumnName();
+ log.info(colName + "=" + value);
+ if (value == null)
+ return "";
+
+ Integer R_StandardResponse_ID = (Integer)value;
+ String sql = "SELECT Name, ResponseText FROM R_StandardResponse "
+ + "WHERE R_StandardResponse_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, R_StandardResponse_ID.intValue());
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ String txt = rs.getString(2);
+ txt = Env.parseContext(ctx, WindowNo, txt, false, true);
+ mTab.setValue("Result", txt);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ return "";
+ } // copyResponse
+
+ /**
+ * Request - Chane of Request Type - Callout
+ *
+ * @param ctx Context
+ * @param WindowNo current Window No
+ * @param mTab Model Tab
+ * @param mField Model Field
+ * @param value The new value
+ * @return Error message or ""
+ */
+ public String type (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ String colName = mField.getColumnName();
+ log.info(colName + "=" + value);
+ mTab.setValue("R_Status_ID", null);
+ if (value == null)
+ return "";
+ int R_RequestType_ID = ((Integer)value).intValue();
+ if (R_RequestType_ID == 0)
+ return "";
+ MRequestType rt = MRequestType.get(ctx, R_RequestType_ID);
+ int R_Status_ID = rt.getDefaultR_Status_ID();
+ if (R_Status_ID != 0)
+ mTab.setValue("R_Status_ID", new Integer(R_Status_ID));
+
+ return "";
+ } // type
+} // CalloutRequest
diff --git a/base/src/org/compiere/model/CalloutRequisition.java b/base/src/org/compiere/model/CalloutRequisition.java
new file mode 100644
index 0000000000..1d16a78320
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutRequisition.java
@@ -0,0 +1,134 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import org.compiere.util.*;
+
+/**
+ * Requisition Callouts
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutRequisition.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public class CalloutRequisition extends CalloutEngine
+{
+ /**
+ * Requisition Line - Product.
+ * - PriceStd
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ // setCalloutActive(true);
+ //
+ /** Set Attribute
+ if (Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_Product_ID") == M_Product_ID.intValue()
+ && Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID") != 0)
+ mTab.setValue("M_AttributeSetInstance_ID", new Integer(Env.getContextAsInt(ctx, Env.WINDOW_INFO, Env.TAB_INFO, "M_AttributeSetInstance_ID")));
+ else
+ mTab.setValue("M_AttributeSetInstance_ID", null);
+ **/
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, WindowNo, "C_BPartner_ID");
+ BigDecimal Qty = (BigDecimal)mTab.getValue("Qty");
+ boolean isSOTrx = false;
+ MProductPricing pp = new MProductPricing (M_Product_ID.intValue(),
+ C_BPartner_ID, Qty, isSOTrx);
+ //
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp orderDate = (Timestamp)mTab.getValue("DateRequired");
+ pp.setPriceDate(orderDate);
+ //
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ Env.setContext(ctx, WindowNo, "EnforcePriceLimit", pp.isEnforcePriceLimit() ? "Y" : "N"); // not used
+ Env.setContext(ctx, WindowNo, "DiscountSchema", pp.isDiscountSchema() ? "Y" : "N");
+
+ // setCalloutActive(false);
+ return "";
+ } // product
+
+ /**
+ * Order Line - Amount.
+ * - called from Qty, PriceActual
+ * - calculates LineNetAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String amt (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive() || value == null)
+ return "";
+ setCalloutActive(true);
+
+ // Qty changed - recalc price
+ if (mField.getColumnName().equals("Qty")
+ && "Y".equals(Env.getContext(ctx, WindowNo, "DiscountSchema")))
+ {
+ int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, WindowNo, "M_Product_ID");
+ int C_BPartner_ID = Env.getContextAsInt(ctx, WindowNo, WindowNo, "C_BPartner_ID");
+ BigDecimal Qty = (BigDecimal)value;
+ boolean isSOTrx = false;
+ MProductPricing pp = new MProductPricing (M_Product_ID,
+ C_BPartner_ID, Qty, isSOTrx);
+ //
+ int M_PriceList_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID");
+ pp.setM_PriceList_ID(M_PriceList_ID);
+ int M_PriceList_Version_ID = Env.getContextAsInt(ctx, WindowNo, "M_PriceList_Version_ID");
+ pp.setM_PriceList_Version_ID(M_PriceList_Version_ID);
+ Timestamp orderDate = (Timestamp)mTab.getValue("DateInvoiced");
+ pp.setPriceDate(orderDate);
+ //
+ mTab.setValue("PriceActual", pp.getPriceStd());
+ }
+
+ int StdPrecision = Env.getContextAsInt(ctx, WindowNo, "StdPrecision");
+ BigDecimal Qty = (BigDecimal)mTab.getValue("Qty");
+ BigDecimal PriceActual = (BigDecimal)mTab.getValue("PriceActual");
+
+ // get values
+ log.fine("amt - Qty=" + Qty + ", Price=" + PriceActual + ", Precision=" + StdPrecision);
+
+ // Multiply
+ BigDecimal LineNetAmt = Qty.multiply(PriceActual);
+ if (LineNetAmt.scale() > StdPrecision)
+ LineNetAmt = LineNetAmt.setScale(StdPrecision, BigDecimal.ROUND_HALF_UP);
+ mTab.setValue("LineNetAmt", LineNetAmt);
+ log.info("amt - LineNetAmt=" + LineNetAmt);
+ //
+ setCalloutActive(false);
+ return "";
+ } // amt
+
+
+} // CalloutRequisition
diff --git a/base/src/org/compiere/model/CalloutTimeExpense.java b/base/src/org/compiere/model/CalloutTimeExpense.java
new file mode 100644
index 0000000000..063785b109
--- /dev/null
+++ b/base/src/org/compiere/model/CalloutTimeExpense.java
@@ -0,0 +1,206 @@
+/******************************************************************************
+ * 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.model;
+
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+
+/**
+ * Time & Expense Report Callout
+ *
+ * @author Jorg Janke
+ * @version $Id: CalloutTimeExpense.java,v 1.3 2006/07/30 00:51:02 jjanke Exp $
+ */
+public class CalloutTimeExpense extends CalloutEngine
+{
+ /**
+ * Expense Report Line
+ * - called from M_Product_ID, S_ResourceAssignment_ID
+ * - set ExpenseAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String product (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ Integer M_Product_ID = (Integer)value;
+ if (M_Product_ID == null || M_Product_ID.intValue() == 0)
+ return "";
+ setCalloutActive(true);
+ BigDecimal priceActual = null;
+
+ // get expense date - or default to today's date
+ Timestamp DateExpense = Env.getContextAsDate(ctx, WindowNo, "DateExpense");
+ if (DateExpense == null)
+ DateExpense = new Timestamp(System.currentTimeMillis());
+
+ String sql = null;
+ try
+ {
+ boolean noPrice = true;
+
+ // Search Pricelist for current version
+ sql = "SELECT bomPriceStd(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceStd,"
+ + "bomPriceList(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceList,"
+ + "bomPriceLimit(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceLimit,"
+ + "p.C_UOM_ID,pv.ValidFrom,pl.C_Currency_ID "
+ + "FROM M_Product p, M_ProductPrice pp, M_Pricelist pl, M_PriceList_Version pv "
+ + "WHERE p.M_Product_ID=pp.M_Product_ID"
+ + " AND pp.M_PriceList_Version_ID=pv.M_PriceList_Version_ID"
+ + " AND pv.M_PriceList_ID=pl.M_PriceList_ID"
+ + " AND pv.IsActive='Y'"
+ + " AND p.M_Product_ID=?" // 1
+ + " AND pl.M_PriceList_ID=?" // 2
+ + " ORDER BY pv.ValidFrom DESC";
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, M_Product_ID.intValue());
+ pstmt.setInt(2, Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID"));
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next() && noPrice)
+ {
+ java.sql.Date plDate = rs.getDate("ValidFrom");
+ // we have the price list
+ // if order date is after or equal PriceList validFrom
+ if (plDate == null || !DateExpense.before(plDate))
+ {
+ noPrice = false;
+ // Price
+ priceActual = rs.getBigDecimal("PriceStd");
+ if (priceActual == null)
+ priceActual = rs.getBigDecimal("PriceList");
+ if (priceActual == null)
+ priceActual = rs.getBigDecimal("PriceLimit");
+ // Currency
+ Integer ii = new Integer(rs.getInt("C_Currency_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_Currency_ID", ii);
+ }
+ }
+ rs.close();
+ pstmt.close();
+
+ // no prices yet - look base pricelist
+ if (noPrice)
+ {
+ // Find if via Base Pricelist
+ sql = "SELECT bomPriceStd(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceStd,"
+ + "bomPriceList(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceList,"
+ + "bomPriceLimit(p.M_Product_ID,pv.M_PriceList_Version_ID) AS PriceLimit,"
+ + "p.C_UOM_ID,pv.ValidFrom,pl.C_Currency_ID "
+ + "FROM M_Product p, M_ProductPrice pp, M_Pricelist pl, M_Pricelist bpl, M_PriceList_Version pv "
+ + "WHERE p.M_Product_ID=pp.M_Product_ID"
+ + " AND pp.M_PriceList_Version_ID=pv.M_PriceList_Version_ID"
+ + " AND pv.M_PriceList_ID=bpl.M_PriceList_ID"
+ + " AND pv.IsActive='Y'"
+ + " AND bpl.M_PriceList_ID=pl.BasePriceList_ID" // Base
+ + " AND p.M_Product_ID=?" // 1
+ + " AND pl.M_PriceList_ID=?" // 2
+ + " ORDER BY pv.ValidFrom DESC";
+
+ pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, M_Product_ID.intValue());
+ pstmt.setInt(2, Env.getContextAsInt(ctx, WindowNo, "M_PriceList_ID"));
+ rs = pstmt.executeQuery();
+ while (rs.next() && noPrice)
+ {
+ java.sql.Date plDate = rs.getDate("ValidFrom");
+ // we have the price list
+ // if order date is after or equal PriceList validFrom
+ if (plDate == null || !DateExpense.before(plDate))
+ {
+ noPrice = false;
+ // Price
+ priceActual = rs.getBigDecimal("PriceStd");
+ if (priceActual == null)
+ priceActual = rs.getBigDecimal("PriceList");
+ if (priceActual == null)
+ priceActual = rs.getBigDecimal("PriceLimit");
+ // Currency
+ Integer ii = new Integer(rs.getInt("C_Currency_ID"));
+ if (!rs.wasNull())
+ mTab.setValue("C_Currency_ID", ii);
+ }
+ }
+ rs.close();
+ pstmt.close();
+ }
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ setCalloutActive(false);
+ return e.getLocalizedMessage();
+ }
+
+ // finish
+ setCalloutActive(false); // calculate amount
+ if (priceActual == null)
+ priceActual = Env.ZERO;
+ mTab.setValue("ExpenseAmt", priceActual);
+ return "";
+ } // Expense_Product
+
+ /**
+ * Expense - Amount.
+ * - called from ExpenseAmt, C_Currency_ID
+ * - calculates ConvertedAmt
+ * @param ctx context
+ * @param WindowNo current Window No
+ * @param mTab Grid Tab
+ * @param mField Grid Field
+ * @param value New Value
+ * @return null or error message
+ */
+ public String amount (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
+ {
+ if (isCalloutActive())
+ return "";
+ setCalloutActive(true);
+
+ // get values
+ BigDecimal ExpenseAmt = (BigDecimal)mTab.getValue("ExpenseAmt");
+ Integer C_Currency_From_ID = (Integer)mTab.getValue("C_Currency_ID");
+ int C_Currency_To_ID = Env.getContextAsInt(ctx, "$C_Currency_ID");
+ Timestamp DateExpense = Env.getContextAsDate(ctx, WindowNo, "DateExpense");
+ //
+ log.fine("Amt=" + ExpenseAmt + ", C_Currency_ID=" + C_Currency_From_ID);
+ // Converted Amount = Unit price
+ BigDecimal ConvertedAmt = ExpenseAmt;
+ // convert if required
+ if (!ConvertedAmt.equals(Env.ZERO) && C_Currency_To_ID != C_Currency_From_ID.intValue())
+ {
+ int AD_Client_ID = Env.getContextAsInt (ctx, WindowNo, "AD_Client_ID");
+ int AD_Org_ID = Env.getContextAsInt (ctx, WindowNo, "AD_Org_ID");
+ ConvertedAmt = MConversionRate.convert (ctx,
+ ConvertedAmt, C_Currency_From_ID.intValue(), C_Currency_To_ID,
+ DateExpense, 0, AD_Client_ID, AD_Org_ID);
+ }
+ mTab.setValue("ConvertedAmt", ConvertedAmt);
+ log.fine("= ConvertedAmt=" + ConvertedAmt);
+
+ setCalloutActive(false);
+ return "";
+ } // Expense_Amount
+
+} // CalloutTimeExpense
diff --git a/base/src/org/compiere/model/DataStatusEvent.java b/base/src/org/compiere/model/DataStatusEvent.java
new file mode 100644
index 0000000000..cb708fe8cc
--- /dev/null
+++ b/base/src/org/compiere/model/DataStatusEvent.java
@@ -0,0 +1,335 @@
+/******************************************************************************
+ * 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.model;
+
+import java.io.*;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * Data Status Event
+ *
+ * Indicates the current Status of the database
+ *
+ * @author Jorg Janke
+ * @version $Id: DataStatusEvent.java,v 1.4 2006/07/30 00:51:02 jjanke Exp $
+ */
+public final class DataStatusEvent extends EventObject implements Serializable
+{
+ /**
+ * Constructor
+ * @param source1 source
+ * @param totalRows total rows
+ * @param changed changed
+ * @param autoSave auto save
+ * @param inserting inserting
+ */
+ public DataStatusEvent (Object source1, int totalRows, boolean changed,
+ boolean autoSave, boolean inserting)
+ {
+ super(source1);
+ m_totalRows = totalRows;
+ m_changed = changed;
+ m_autoSave = autoSave;
+ m_inserting = inserting;
+ } // DataStatusEvent
+
+ private int m_totalRows;
+ private boolean m_changed;
+ private boolean m_autoSave;
+ private boolean m_inserting;
+ //
+ private String m_AD_Message = null;
+ private String m_info = null;
+ private boolean m_isError = false;
+ private boolean m_isWarning = false;
+ private boolean m_confirmed = false;
+ //
+ private boolean m_allLoaded = true;
+ private int m_loadedRows = -1;
+ private int m_currentRow = -1;
+ //
+ private int m_changedColumn = 0;
+ private String m_columnName = null;
+
+ /** Created */
+ public Timestamp Created = null;
+ /** Created By */
+ public Integer CreatedBy = null;
+ /** Updated */
+ public Timestamp Updated = null;
+ /** Updated By */
+ public Integer UpdatedBy = null;
+ /** Info */
+ public String Info = null;
+ /** Table ID */
+ public int AD_Table_ID = 0;
+ /** Record ID */
+ public Object Record_ID = null;
+
+ /**
+ * Set Loaded Info
+ * @param loadedRows loaded rows
+ */
+ public void setLoading (int loadedRows)
+ {
+ m_allLoaded = false;
+ m_loadedRows = loadedRows;
+ } // setLoaded
+
+ /**
+ * Is loading
+ * @return true if loading
+ */
+ public boolean isLoading()
+ {
+ return !m_allLoaded;
+ } // isLoading
+
+ /**
+ * Get loaded rows
+ * @return loaded rows
+ */
+ public int getLoadedRows()
+ {
+ return m_loadedRows;
+ } // getLoadedRows
+
+ /**
+ * Set current Row (zero based)
+ * @param currentRow current row
+ */
+ public void setCurrentRow (int currentRow)
+ {
+ m_currentRow = currentRow;
+ } // setCurrentRow
+
+ /**
+ * Get current row (zero based)
+ * @return current roe
+ */
+ public int getCurrentRow()
+ {
+ return m_currentRow;
+ } // getCurrentRow
+
+ /**
+ * Get total rows
+ * @return total rows
+ */
+ public int getTotalRows()
+ {
+ return m_totalRows;
+ } // getTotalRows
+
+ /**
+ * Set Message Info
+ * @param AD_Message message
+ * @param info info
+ * @param isError error
+ * @param isWarning true if warning
+ */
+ public void setInfo (String AD_Message, String info, boolean isError, boolean isWarning)
+ {
+ m_AD_Message = AD_Message;
+ m_info = info;
+ m_isError = isError;
+ m_isWarning = isWarning;
+ } // setInfo
+
+ /**
+ * Set Inserting
+ * @param inserting inserting
+ */
+ public void setInserting (boolean inserting)
+ {
+ m_inserting = inserting;
+ } // setInserting
+
+ /**
+ * Are we inserting
+ * @return true if inserting
+ */
+ public boolean isInserting()
+ {
+ return m_inserting;
+ } // isInserting
+
+ /**
+ * Get Message Info
+ * @return Message
+ */
+ public String getAD_Message()
+ {
+ return m_AD_Message;
+ } // getAD_Message
+
+ /**
+ * Get Message Info
+ * @return Info
+ */
+ public String getInfo()
+ {
+ return m_info;
+ } // getInfo
+
+ /**
+ * Is this an error
+ * @return true if error
+ */
+ public boolean isError()
+ {
+ return m_isError;
+ } // isError
+
+ /**
+ * Is this a warning
+ * @return true if warning
+ */
+ public boolean isWarning()
+ {
+ return m_isWarning;
+ } // isWarning
+
+ /**
+ * String representation of Status.
+ * @return Examples: +*1?/20
+ * 1/256->2000
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer("DataStatusEvent - ");
+ if (m_AD_Message != null)
+ sb.append(m_AD_Message);
+ if (m_info != null)
+ sb.append(" ").append(m_info);
+ sb.append(" : ").append(getMessage());
+ return sb.toString();
+ } // toString
+
+ /**
+ * String representation of Status.
+ *
+ * *1/20 Change - automatic commit
+ * ?1/20 Change - manual confirm
+ * 1/56->200 Loading
+ * 1/20 Normal
+ * +*1/20 Inserting, changed - automatic commit
+ * The row number is converted from zero based representation
+ *
+ * @return Status info
+ */
+ public String getMessage()
+ {
+ StringBuffer retValue = new StringBuffer();
+ if (m_inserting)
+ retValue.append("+");
+ retValue.append(m_changed ? (m_autoSave ? "*" : "?") : " ");
+ // current row
+ if (m_totalRows == 0)
+ retValue.append(m_currentRow);
+ else
+ retValue.append(m_currentRow+1);
+ // of
+ retValue.append("/");
+ if (m_allLoaded)
+ retValue.append(m_totalRows);
+ else
+ retValue.append(m_loadedRows).append("->").append(m_totalRows);
+ //
+ return retValue.toString();
+ } // getMessage
+
+ /**
+ * Is Data Changed
+ * @return true if changed
+ */
+ public boolean isChanged()
+ {
+ return m_changed;
+ } // isChanged
+
+ /**
+ * Is First Row - (zero based)
+ * @return true if first row
+ */
+ public boolean isFirstRow()
+ {
+ if (m_totalRows == 0)
+ return true;
+ return m_currentRow == 0;
+ } // isFirstRow
+
+ /**
+ * Is Last Row - (zero based)
+ * @return true if last row
+ */
+ public boolean isLastRow()
+ {
+ if (m_totalRows == 0)
+ return true;
+ return m_currentRow == m_totalRows-1;
+ } // isLastRow
+
+ /**
+ * Set Changed Column
+ * @param col column
+ * @param columnName column name
+ */
+ public void setChangedColumn (int col, String columnName)
+ {
+ m_changedColumn = col;
+ m_columnName = columnName;
+ } // setChangedColumn
+
+ /**
+ * Get Changed Column
+ * @return changed column
+ */
+ public int getChangedColumn()
+ {
+ return m_changedColumn;
+ } // getChangedColumn
+
+ /**
+ * Get Column Name
+ * @return column name
+ */
+ public String getColumnName()
+ {
+ return m_columnName;
+ } // getColumnName
+
+ /**
+ * Set Confirmed toggle
+ * @param confirmed confirmed
+ */
+ public void setConfirmed (boolean confirmed)
+ {
+ m_confirmed = confirmed;
+ } // setConfirmed
+
+ /**
+ * Is Confirmed (e.g. user has seen it)
+ * @return true if confirmed
+ */
+ public boolean isConfirmed()
+ {
+ return m_confirmed;
+ } // isConfirmed
+
+} // DataStatusEvent
diff --git a/base/src/org/compiere/model/DataStatusListener.java b/base/src/org/compiere/model/DataStatusListener.java
new file mode 100644
index 0000000000..eacb88cc38
--- /dev/null
+++ b/base/src/org/compiere/model/DataStatusListener.java
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * 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.model;
+
+import java.util.*;
+
+/**
+ * Data Status Interface
+ *
+ * @author Jorg Janke
+ * @version $Id: DataStatusListener.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
+ */
+public interface DataStatusListener extends EventListener
+{
+ /**
+ * Data Changed
+ * @param e event
+ */
+ public void dataStatusChanged(DataStatusEvent e);
+} // DataStatusListener
diff --git a/base/src/org/compiere/model/GridField.java b/base/src/org/compiere/model/GridField.java
new file mode 100644
index 0000000000..2df47f9596
--- /dev/null
+++ b/base/src/org/compiere/model/GridField.java
@@ -0,0 +1,1464 @@
+/******************************************************************************
+ * 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.model;
+
+import java.beans.*;
+import java.io.*;
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import org.compiere.util.*;
+
+/**
+ * Grid Field Model.
+ *
+ * Fields are a combination of AD_Field (the display attributes)
+ * and AD_Column (the storage attributes).
+ *
+ * The Field maintains the current edited value. If the value is changed,
+ * it fire PropertyChange "FieldValue".
+ * If the background is changed the PropertyChange "FieldAttribute" is fired.
+ *
+ * Usually editors listen to their fields.
+ *
+ * @author Jorg Janke
+ * @version $Id: GridField.java,v 1.5 2006/07/30 00:51:02 jjanke Exp $
+ */
+public class GridField
+ implements Serializable, Evaluatee
+{
+ /**
+ * Field Constructor.
+ * requires initField for complete instatanciation
+ * @param vo ValueObjecy
+ */
+ public GridField (GridFieldVO vo)
+ {
+ m_vo = vo;
+ // Set Attributes
+ loadLookup();
+ setError(false);
+ } // MField
+
+ /** Value Object */
+ private GridFieldVO m_vo;
+ /** The Mnemonic */
+ private char m_mnemonic = 0;
+
+ /**
+ * Dispose
+ */
+ protected void dispose()
+ {
+ // log.fine( "MField.dispose = " + m_vo.ColumnName);
+ m_propertyChangeListeners = null;
+ if (m_lookup != null)
+ m_lookup.dispose();
+ m_lookup = null;
+ m_vo.lookupInfo = null;
+ m_vo = null;
+ } // dispose
+
+
+ /** Lookup for this field */
+ private Lookup m_lookup = null;
+ /** New Row / inserting */
+ private boolean m_inserting = false;
+
+
+ /** Max Display Length = 60 */
+ public static final int MAXDISPLAY_LENGTH = 60;
+
+ /** The current value */
+ private Object m_value = null;
+ /** The old to force Property Change */
+ private static Object s_oldValue = new Object();
+ /** The old/previous value */
+ private Object m_oldValue = s_oldValue;
+ /** Only fire Property Change if old value really changed */
+ private boolean m_valueNoFire = true;
+ /** Error Status */
+ private boolean m_error = false;
+ /** Parent Check */
+ private boolean m_parentChecked = false;
+
+ /** Property Change */
+ private PropertyChangeSupport m_propertyChangeListeners = new PropertyChangeSupport(this);
+ /** PropertyChange Name */
+ public static final String PROPERTY = "FieldValue";
+ /** Indicator for new Value */
+ public static final String INSERTING = "FieldValueInserting";
+
+ /** Error Value for HTML interface */
+ private String m_errorValue = null;
+ /** Error Value indicator for HTML interface */
+ private boolean m_errorValueFlag = false;
+
+ /** Logger */
+ private static CLogger log = CLogger.getCLogger(GridField.class);
+
+
+ /**************************************************************************
+ * Set Lookup for columns with lookup
+ */
+ public void loadLookup()
+ {
+ if (!isLookup())
+ return;
+ log.config("(" + m_vo.ColumnName + ")");
+
+ if (DisplayType.isLookup(m_vo.displayType))
+ {
+ if (m_vo.lookupInfo == null)
+ {
+ log.log(Level.SEVERE, "(" + m_vo.ColumnName + ") - No LookupInfo");
+ return;
+ }
+ // Prevent loading of CreatedBy/UpdatedBy
+ if (m_vo.displayType == DisplayType.Table
+ && (m_vo.ColumnName.equals("CreatedBy") || m_vo.ColumnName.equals("UpdatedBy")) )
+ {
+ m_vo.lookupInfo.IsCreadedUpdatedBy = true;
+ m_vo.lookupInfo.DisplayType = DisplayType.Search;
+ }
+ //
+ m_vo.lookupInfo.IsKey = isKey();
+ MLookup ml = new MLookup (m_vo.lookupInfo, m_vo.TabNo);
+ m_lookup = ml;
+ }
+ else if (m_vo.displayType == DisplayType.Location) // not cached
+ {
+ MLocationLookup ml = new MLocationLookup (m_vo.ctx, m_vo.WindowNo);
+ m_lookup = ml;
+ }
+ else if (m_vo.displayType == DisplayType.Locator)
+ {
+ MLocatorLookup ml = new MLocatorLookup (m_vo.ctx, m_vo.WindowNo);
+ m_lookup = ml;
+ }
+ else if (m_vo.displayType == DisplayType.Account) // not cached
+ {
+ MAccountLookup ma = new MAccountLookup (m_vo.ctx, m_vo.WindowNo);
+ m_lookup = ma;
+ }
+ else if (m_vo.displayType == DisplayType.PAttribute) // not cached
+ {
+ MPAttributeLookup pa = new MPAttributeLookup (m_vo.ctx, m_vo.WindowNo);
+ m_lookup = pa;
+ }
+ } // m_lookup
+
+ /**
+ * Wait until Load is complete
+ */
+ public void lookupLoadComplete()
+ {
+ if (m_lookup == null)
+ return;
+ m_lookup.loadComplete();
+ } // loadCompete
+
+ /**
+ * Get Lookup, may return null
+ * @return lookup
+ */
+ public Lookup getLookup()
+ {
+ return m_lookup;
+ } // getLookup
+
+ /**
+ * Is this field a Lookup?.
+ * @return true if lookup field
+ */
+ public boolean isLookup()
+ {
+ boolean retValue = false;
+ if (m_vo.IsKey)
+ retValue = false;
+ // else if (m_vo.ColumnName.equals("CreatedBy") || m_vo.ColumnName.equals("UpdatedBy"))
+ // retValue = false;
+ else if (DisplayType.isLookup(m_vo.displayType))
+ retValue = true;
+ else if (m_vo.displayType == DisplayType.Location
+ || m_vo.displayType == DisplayType.Locator
+ || m_vo.displayType == DisplayType.Account
+ || m_vo.displayType == DisplayType.PAttribute)
+ retValue = true;
+
+ return retValue;
+ } // isLookup
+
+ /**
+ * Refresh Lookup if the lookup is unstable
+ * @return true if lookup is validated
+ */
+ public boolean refreshLookup()
+ {
+ // if there is a validation string, the lookup is unstable
+ if (m_lookup == null || m_lookup.getValidation().length() == 0)
+ return true;
+ //
+ log.fine("(" + m_vo.ColumnName + ")");
+ m_lookup.refresh();
+ return m_lookup.isValidated();
+ } // refreshLookup
+
+ /**
+ * Get a list of variables, this field is dependent on.
+ * - for display purposes or
+ * - for lookup purposes
+ * @return ArrayList
+ */
+ public ArrayList getDependentOn()
+ {
+ ArrayList list = new ArrayList();
+ // Display
+ Evaluator.parseDepends(list, m_vo.DisplayLogic);
+ Evaluator.parseDepends(list, m_vo.ReadOnlyLogic);
+ // Lookup
+ if (m_lookup != null)
+ Evaluator.parseDepends(list, m_lookup.getValidation());
+ //
+ if (list.size() > 0 && CLogMgt.isLevelFiner())
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < list.size(); i++)
+ sb.append(list.get(i)).append(" ");
+ log.finer("(" + m_vo.ColumnName + ") " + sb.toString());
+ }
+ return list;
+ } // getDependentOn
+
+
+ /**************************************************************************
+ * Set Error.
+ * Used by editors to set the color
+ * @param error true if error
+ */
+ public void setError (boolean error)
+ {
+ m_error = error;
+ } // setBackground
+
+ /**
+ * Get Background Error.
+ * @return error
+ */
+ public boolean isError()
+ {
+ return m_error;
+ } // isError
+
+
+ /**
+ * Is it Mandatory to enter for user?
+ * Mandatory checking is dome in MTable.getMandatory
+ * @param checkContext - check environment (requires correct row position)
+ * @return true if mandatory
+ */
+ public boolean isMandatory (boolean checkContext)
+ {
+ // Not mandatory
+ if (!m_vo.IsMandatory || isVirtualColumn())
+ return false;
+
+ // Numeric Keys and Created/Updated as well as
+ // DocumentNo/Value/ASI ars not mandatory (persistency layer manages them)
+ if ((m_vo.IsKey && m_vo.ColumnName.endsWith("_ID"))
+ || m_vo.ColumnName.startsWith("Created") || m_vo.ColumnName.startsWith("Updated")
+ || m_vo.ColumnName.equals("Value")
+ || m_vo.ColumnName.equals("DocumentNo")
+ || m_vo.ColumnName.equals("M_AttributeSetInstance_ID")) // 0 is valid
+ return false;
+
+ // Mandatory if displayed
+ return isDisplayed (checkContext);
+ } // isMandatory
+
+ /**
+ * Is it Editable - checks IsActive, IsUpdateable, and isDisplayed
+ * @param checkContext if true checks Context for Active, IsProcessed, LinkColumn
+ * @return true, if editable
+ */
+ public boolean isEditable (boolean checkContext)
+ {
+ if (isVirtualColumn())
+ return false;
+ // Fields always enabled (are usually not updateable)
+ if (m_vo.ColumnName.equals("Posted")
+ || (m_vo.ColumnName.equals("Record_ID") && m_vo.displayType == DisplayType.Button)) // Zoom
+ return true;
+
+ // Fields always updareable
+ if (m_vo.IsAlwaysUpdateable) // Zoom
+ return true;
+
+ // Tab or field is R/O
+ if (m_vo.tabReadOnly || m_vo.IsReadOnly)
+ {
+ log.finest(m_vo.ColumnName + " NO - TabRO=" + m_vo.tabReadOnly + ", FieldRO=" + m_vo.IsReadOnly);
+ return false;
+ }
+
+ // Not Updateable - only editable if new updateable row
+ if (!m_vo.IsUpdateable && !m_inserting)
+ {
+ log.finest(m_vo.ColumnName + " NO - FieldUpdateable=" + m_vo.IsUpdateable);
+ return false;
+ }
+
+ // Field is the Link Column of the tab
+ if (m_vo.ColumnName.equals(Env.getContext(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "LinkColumnName")))
+ {
+ log.finest(m_vo.ColumnName + " NO - LinkColumn");
+ return false;
+ }
+
+ // Role Access & Column Access
+ if (checkContext)
+ {
+ int AD_Client_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "AD_Client_ID");
+ int AD_Org_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "AD_Org_ID");
+ String keyColumn = Env.getContext(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "KeyColumnName");
+ int Record_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, keyColumn);
+ int AD_Table_ID = m_vo.AD_Table_ID;
+ if (!MRole.getDefault(m_vo.ctx, false).canUpdate(
+ AD_Client_ID, AD_Org_ID, AD_Table_ID, Record_ID, false))
+ return false;
+ if (!MRole.getDefault(m_vo.ctx, false).isColumnAccess(AD_Table_ID, m_vo.AD_Column_ID, false))
+ return false;
+ }
+
+ // Do we have a readonly rule
+ if (checkContext && m_vo.ReadOnlyLogic.length() > 0)
+ {
+ boolean retValue = !Evaluator.evaluateLogic(this, m_vo.ReadOnlyLogic);
+ log.finest(m_vo.ColumnName + " R/O(" + m_vo.ReadOnlyLogic + ") => R/W-" + retValue);
+ if (!retValue)
+ return false;
+ }
+
+ // Always editable if Active
+ if (m_vo.ColumnName.equals("Processing")
+ || m_vo.ColumnName.equals("PaymentRule")
+ || m_vo.ColumnName.equals("DocAction")
+ || m_vo.ColumnName.equals("GenerateTo"))
+ return true;
+
+ // Record is Processed ***
+ if (checkContext
+ && (Env.getContext(m_vo.ctx, m_vo.WindowNo, "Processed").equals("Y")
+ || Env.getContext(m_vo.ctx, m_vo.WindowNo, "Processing").equals("Y")))
+ return false;
+
+ // IsActive field is editable, if record not processed
+ if (m_vo.ColumnName.equals("IsActive"))
+ return true;
+
+ // Record is not Active
+ if (checkContext && !Env.getContext(m_vo.ctx, m_vo.WindowNo, "IsActive").equals("Y"))
+ return false;
+
+ // ultimately visibily decides
+ return isDisplayed (checkContext);
+ } // isEditable
+
+ /**
+ * Set Inserting (allows to enter not updateable fields).
+ * Reset when setting the Field Value
+ * @param inserting true if inserting
+ */
+ public void setInserting (boolean inserting)
+ {
+ m_inserting = inserting;
+ } // setInserting
+
+
+ /**************************************************************************
+ * Create default value.
+ *
+ * @param value string
+ * @return type dependent converted object
+ */
+ private Object createDefault (String value)
+ {
+ // true NULL
+ if (value == null || value.toString().length() == 0)
+ return null;
+ // see also MTable.readData
+ try
+ {
+ // IDs & Integer & CreatedBy/UpdatedBy
+ if (m_vo.ColumnName.endsWith("atedBy")
+ || m_vo.ColumnName.endsWith("_ID"))
+ {
+ try // defaults -1 => null
+ {
+ int ii = Integer.parseInt(value);
+ if (ii < 0)
+ return null;
+ return new Integer(ii);
+ }
+ catch (Exception e)
+ {
+ log.warning("Cannot parse: " + value + " - " + e.getMessage());
+ }
+ return new Integer(0);
+ }
+ // Integer
+ if (m_vo.displayType == DisplayType.Integer)
+ return new Integer(value);
+
+ // Number
+ if (DisplayType.isNumeric(m_vo.displayType))
+ return new BigDecimal(value);
+
+ // Timestamps
+ if (DisplayType.isDate(m_vo.displayType))
+ {
+ java.util.Date date = DisplayType.getDateFormat_JDBC().parse (value);
+ return new Timestamp (date.getTime());
+ }
+
+ // Boolean
+ if (m_vo.displayType == DisplayType.YesNo)
+ return new Boolean ("Y".equals(value));
+
+ // Default
+ return value;
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, m_vo.ColumnName + " - " + e.getMessage());
+ }
+ return null;
+ } // createDefault
+
+ /**
+ * Validate initial Field Value.
+ * Called from MTab.dataNew and MTab.setCurrentRow when inserting
+ * @return true if valid
+ */
+ public boolean validateValue()
+ {
+ // null
+ if (m_value == null || m_value.toString().length() == 0)
+ {
+ if (isMandatory(true))
+ {
+ m_error = true;
+ return false;
+ }
+ else
+ return true;
+ }
+
+ // Search not cached
+ if (getDisplayType() == DisplayType.Search && m_lookup != null)
+ {
+ // need to re-set invalid values - OK BPartner in PO Line - not OK SalesRep in Invoice
+ if (m_lookup.getDirect(m_value, false, true) == null)
+ {
+ log.finest(m_vo.ColumnName + " Serach not valid - set to null");
+ setValue(null, m_inserting);
+ m_error = true;
+ return false;
+ }
+ return true;
+ }
+
+ // cannot be validated
+ if (!isLookup()
+ || m_lookup.containsKey(m_value))
+ return true;
+ // it's not null, a lookup and does not have the key
+ if (isKey() || isParentValue()) // parents/ket are not validated
+ return true;
+
+ log.finest(m_vo.ColumnName + " - set to null");
+ setValue(null, m_inserting);
+ m_error = true;
+ return false;
+ } // validateValue
+
+
+ /**************************************************************************
+ * Is the Column Visible ?
+ * @param checkContext - check environment (requires correct row position)
+ * @return true, if visible
+ */
+ public boolean isDisplayed (boolean checkContext)
+ {
+ // ** static content **
+ // not displayed
+ if (!m_vo.IsDisplayed)
+ return false;
+ // no restrictions
+ if (m_vo.DisplayLogic.equals(""))
+ return true;
+
+ // ** dynamic content **
+ if (checkContext)
+ {
+ boolean retValue = Evaluator.evaluateLogic(this, m_vo.DisplayLogic);
+ log.finest(m_vo.ColumnName
+ + " (" + m_vo.DisplayLogic + ") => " + retValue);
+ return retValue;
+ }
+ return true;
+ } // isDisplayed
+
+ /**
+ * Get Variable Value (Evaluatee)
+ * @param variableName name
+ * @return value
+ */
+ public String get_ValueAsString (String variableName)
+ {
+ return Env.getContext (m_vo.ctx, m_vo.WindowNo, variableName, true);
+ } // get_ValueAsString
+
+
+ /**
+ * Add Display Dependencies to given List.
+ * Source: DisplayLogic
+ * @param list list to be added to
+ */
+ public void addDependencies (ArrayList list)
+ {
+ // nothing to parse
+ if (!m_vo.IsDisplayed || m_vo.DisplayLogic.equals(""))
+ return;
+
+ StringTokenizer logic = new StringTokenizer(m_vo.DisplayLogic.trim(), "&|", false);
+
+ while (logic.hasMoreTokens())
+ {
+ StringTokenizer st = new StringTokenizer(logic.nextToken().trim(), "!=^", false);
+ while (st.hasMoreTokens())
+ {
+ String tag = st.nextToken().trim(); // get '@tag@'
+ // Do we have a @variable@ ?
+ if (tag.indexOf('@') != -1)
+ {
+ tag = tag.replace('@', ' ').trim(); // strip 'tag'
+ // Add columns (they might not be a column, but then it is static)
+ if (!list.contains(tag))
+ list.add(tag);
+ }
+ }
+ }
+ } // addDependencies
+
+
+ /**************************************************************************
+ * Get Column Name
+ * @return column name
+ */
+ public String getColumnName()
+ {
+ return m_vo.ColumnName;
+ } // getColumnName
+
+ /**
+ * Get Column Name or SQL .. with/without AS
+ * @param withAS include AS ColumnName for virtual columns in select statements
+ * @return column name
+ */
+ public String getColumnSQL(boolean withAS)
+ {
+ if (m_vo.ColumnSQL != null && m_vo.ColumnSQL.length() > 0)
+ {
+ if (withAS)
+ return m_vo.ColumnSQL + " AS " + m_vo.ColumnName;
+ else
+ return m_vo.ColumnSQL;
+ }
+ return m_vo.ColumnName;
+ } // getColumnSQL
+
+ /**
+ * Is Virtual Column
+ * @return column is virtual
+ */
+ public boolean isVirtualColumn()
+ {
+ if (m_vo.ColumnSQL != null && m_vo.ColumnSQL.length() > 0)
+ return true;
+ return false;
+ } // isColumnVirtual
+
+ /**
+ * Get Header
+ * @return header
+ */
+ public String getHeader()
+ {
+ return m_vo.Header;
+ }
+ /**
+ * Get Display Type
+ * @return dt
+ */
+ public int getDisplayType()
+ {
+ return m_vo.displayType;
+ }
+ /**
+ * Get AD_Reference_Value_ID
+ * @return reference value
+ */
+ public int getAD_Reference_Value_ID()
+ {
+ return m_vo.AD_Reference_Value_ID;
+ }
+ /**
+ * Get AD_Window_ID
+ * @return window
+ */
+ public int getAD_Window_ID()
+ {
+ return m_vo.AD_Window_ID;
+ }
+ /**
+ * Get Window No
+ * @return window no
+ */
+ public int getWindowNo()
+ {
+ return m_vo.WindowNo;
+ }
+ /**
+ * Get AD_Column_ID
+ * @return column
+ */
+ public int getAD_Column_ID()
+ {
+ return m_vo.AD_Column_ID;
+ }
+ /**
+ * Get Display Length
+ * @return display
+ */
+ public int getDisplayLength()
+ {
+ return m_vo.DisplayLength;
+ }
+ /**
+ * Is SameLine
+ * @return trie if same line
+ */
+ public boolean isSameLine()
+ {
+ return m_vo.IsSameLine;
+ }
+ /**
+ * Is Displayed
+ * @return true if displayed
+ */
+ public boolean isDisplayed()
+ {
+ return m_vo.IsDisplayed;
+ }
+ /**
+ * Get DisplayLogic
+ * @return display logic
+ */
+ public String getDisplayLogic()
+ {
+ return m_vo.DisplayLogic;
+ }
+ /**
+ * Get Default Value
+ * @return default
+ */
+ public String getDefaultValue()
+ {
+ return m_vo.DefaultValue;
+ }
+ /**
+ * Is ReadOnly
+ * @return true if read only
+ */
+ public boolean isReadOnly()
+ {
+ if (isVirtualColumn())
+ return true;
+ return m_vo.IsReadOnly;
+ }
+ /**
+ * Is Updateable
+ * @return true if updateable
+ */
+ public boolean isUpdateable()
+ {
+ if (isVirtualColumn())
+ return false;
+ return m_vo.IsUpdateable;
+ }
+ /**
+ * Is Always Updateable
+ * @return true if always updateable
+ */
+ public boolean isAlwaysUpdateable()
+ {
+ if (isVirtualColumn() || !m_vo.IsUpdateable)
+ return false;
+ return m_vo.IsAlwaysUpdateable;
+ }
+ /**
+ * Is Heading
+ * @return heading
+ */
+ public boolean isHeading()
+ {
+ return m_vo.IsHeading;
+ }
+ /**
+ * Is Field Only
+ * @return field only
+ */
+ public boolean isFieldOnly()
+ {
+ return m_vo.IsFieldOnly;
+ }
+ /**
+ * Is Encrypted Field (display)
+ * @return encrypted field
+ */
+ public boolean isEncryptedField()
+ {
+ return m_vo.IsEncryptedField;
+ }
+ /**
+ * Is Encrypted Column (data)
+ * @return encrypted column
+ */
+ public boolean isEncryptedColumn()
+ {
+ return m_vo.IsEncryptedColumn;
+ }
+ /**
+ * Is Selection Column
+ * @return selection
+ */
+ public boolean isSelectionColumn()
+ {
+ return m_vo.IsSelectionColumn;
+ }
+ /**
+ * Get Obscure Type
+ * @return obscure
+ */
+ public String getObscureType()
+ {
+ return m_vo.ObscureType;
+ }
+ /**
+ * Get Sort No
+ * @return sort
+ */
+ public int getSortNo()
+ {
+ return m_vo.SortNo;
+ }
+ /**
+ * Get Field Length
+ * @return field length
+ */
+ public int getFieldLength()
+ {
+ return m_vo.FieldLength;
+ }
+ /**
+ * Get VFormat
+ * @return format
+ */
+ public String getVFormat()
+ {
+ return m_vo.VFormat;
+ }
+ /**
+ * Get Value Min
+ * @return min
+ */
+ public String getValueMin()
+ {
+ return m_vo.ValueMin;
+ }
+ /**
+ * Get Value Max
+ * @return max
+ */
+ public String getValueMax()
+ {
+ return m_vo.ValueMax;
+ }
+ /**
+ * Get Field Group
+ * @return field group
+ */
+ public String getFieldGroup()
+ {
+ return m_vo.FieldGroup;
+ }
+ /**
+ * Key
+ * @return key
+ */
+ public boolean isKey()
+ {
+ return m_vo.IsKey;
+ }
+ /**
+ * Parent Column
+ * @return parent column
+ */
+ public boolean isParentColumn()
+ {
+ return m_vo.IsParent;
+ }
+ /**
+ * Parent Value
+ * @return parent value
+ */
+ public boolean isParentValue()
+ {
+ if (m_parentChecked)
+ return m_vo.IsParent;
+ if (!DisplayType.isID(m_vo.displayType) || m_vo.TabNo == 0)
+ m_vo.IsParent = false;
+ else
+ {
+ String LinkColumnName = Env.getContext(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "LinkColumnName");
+ if (LinkColumnName.length() == 0)
+ ;
+ else
+ m_vo.IsParent = m_vo.ColumnName.equals(LinkColumnName);
+ if (m_vo.IsParent)
+ log.config(m_vo.IsParent
+ + " - Link(" + LinkColumnName + ", W=" + m_vo.WindowNo + ",T=" + m_vo.TabNo
+ + ") = " + m_vo.ColumnName);
+ }
+ m_parentChecked = true;
+ return m_vo.IsParent;
+ }
+ /**
+ * Get Callout
+ * @return callout
+ */
+ public String getCallout()
+ {
+ return m_vo.Callout;
+ }
+ /**
+ * Get AD_Process_ID
+ * @return process
+ */
+ public int getAD_Process_ID()
+ {
+ return m_vo.AD_Process_ID;
+ }
+ /**
+ * Get Description
+ * @return description
+ */
+ public String getDescription()
+ {
+ return m_vo.Description;
+ }
+ /**
+ * Get Help
+ * @return help
+ */
+ public String getHelp()
+ {
+ return m_vo.Help;
+ }
+ /**
+ * Get AD_Tab_ID
+ * @return tab
+ */
+ public int getAD_Tab_ID()
+ {
+ return m_vo.AD_Tab_ID;
+ }
+ /**
+ * Get VO
+ * @return value object
+ */
+ public GridFieldVO getVO()
+ {
+ return m_vo;
+ }
+
+ /**
+ * Is this a long (string/text) field (over 60/2=30 characters)
+ * @return true if long field
+ */
+ public boolean isLongField()
+ {
+ // if (m_vo.displayType == DisplayType.String
+ // || m_vo.displayType == DisplayType.Text
+ // || m_vo.displayType == DisplayType.Memo
+ // || m_vo.displayType == DisplayType.TextLong
+ // || m_vo.displayType == DisplayType.Image)
+ return (m_vo.DisplayLength >= MAXDISPLAY_LENGTH/2);
+ // return false;
+ } // isLongField
+
+ /**
+ * Set Value to null.
+ *
+ * Do not update context - called from GridTab.setCurrentRow
+ * Send Bean PropertyChange if there is a change
+ */
+ public void setValue ()
+ {
+ // log.fine(ColumnName + "=" + newValue);
+ if (m_valueNoFire) // set the old value
+ m_oldValue = m_value;
+ m_value = null;
+ m_inserting = false;
+ m_error = false; // reset error
+
+ // Does not fire, if same value
+ m_propertyChangeListeners.firePropertyChange(PROPERTY, m_oldValue, m_value);
+ // m_propertyChangeListeners.firePropertyChange(PROPERTY, s_oldValue, null);
+ } // setValue
+
+ /**
+ * Set Value.
+ *
+ * Update context, if not text or RowID;
+ * Send Bean PropertyChange if there is a change
+ * @param newValue new value
+ * @param inserting true if inserting
+ */
+ public void setValue (Object newValue, boolean inserting)
+ {
+ // log.fine(ColumnName + "=" + newValue);
+ if (m_valueNoFire) // set the old value
+ m_oldValue = m_value;
+ m_value = newValue;
+ m_inserting = inserting;
+ m_error = false; // reset error
+
+ // Set Context
+ if (m_vo.displayType == DisplayType.Text
+ || m_vo.displayType == DisplayType.Memo
+ || m_vo.displayType == DisplayType.TextLong
+ || m_vo.displayType == DisplayType.Binary
+ || m_vo.displayType == DisplayType.RowID)
+ ; // ignore
+ else if (newValue instanceof Boolean)
+ Env.setContext(m_vo.ctx, m_vo.WindowNo, m_vo.ColumnName,
+ ((Boolean)newValue).booleanValue());
+ else if (newValue instanceof Timestamp)
+ Env.setContext(m_vo.ctx, m_vo.WindowNo, m_vo.ColumnName, (Timestamp)m_value);
+ else
+ Env.setContext(m_vo.ctx, m_vo.WindowNo, m_vo.ColumnName,
+ m_value==null ? null : m_value.toString());
+
+ // Does not fire, if same value
+ Object oldValue = m_oldValue;
+ if (inserting)
+ oldValue = INSERTING;
+ m_propertyChangeListeners.firePropertyChange(PROPERTY, oldValue, m_value);
+ } // setValue
+
+ /**
+ * Set Value and Validate
+ * @param newValue value
+ * @param inserting insert
+ * @return null or error message
+ */
+ public String setValueValidate (String newValue, boolean inserting)
+ {
+ if (newValue == null)
+ setValue();
+
+ // Data Type Test
+ int dt = getDisplayType();
+ try
+ {
+ // Return Integer
+ if (dt == DisplayType.Integer
+ || (DisplayType.isID(dt) && getColumnName().endsWith("_ID")))
+ {
+ int i = Integer.parseInt(newValue);
+ setValue (new Integer(i), inserting);
+ }
+ // Return BigDecimal
+ else if (DisplayType.isNumeric(dt))
+ {
+ BigDecimal value = (BigDecimal)DisplayType.getNumberFormat(dt).parse(newValue);
+ setValue (value, inserting);
+ return null;
+ }
+ // Return Timestamp
+ else if (DisplayType.isDate(dt))
+ {
+ long time = DisplayType.getDateFormat_JDBC().parse(newValue).getTime();
+ setValue (new Timestamp(time), inserting);
+ return null;
+ }
+ // Return Boolean
+ else if (dt == DisplayType.YesNo)
+ {
+ Boolean value = null;
+ if (newValue.equals("Y"))
+ value = Boolean.TRUE;
+ else if (newValue.equals("N"))
+ value = Boolean.FALSE;
+ else
+ return getColumnName() + " = " + newValue + " - Must be Y/N";
+ setValue (value, inserting);
+ return null;
+ }
+ else if (DisplayType.isText(dt))
+ {
+ setValue (newValue, inserting);
+ return null;
+ }
+ else
+ return getColumnName() + " not mapped "
+ + DisplayType.getDescription(dt);
+ }
+ catch (Exception ex)
+ {
+ log.log(Level.SEVERE, "Value=" + newValue, ex);
+
+ String error = ex.getLocalizedMessage();
+ if (error == null || error.length() == 0)
+ error = ex.toString();
+ return getColumnName() + " = " + newValue + " - " + error;
+ }
+
+ // ID - test ID
+ if (!DisplayType.isID(dt))
+ return null;
+
+ //TODO: setValueValidate
+
+ return null;
+ } // setValueValidate
+
+ /**
+ * Get Value
+ * @return current value
+ */
+ public Object getValue()
+ {
+ return m_value;
+ } // getValue
+
+ /**
+ * Set old/previous Value.
+ * (i.e. don't fire Property change)
+ * Used by VColor.setField
+ * @param value if false property change will always be fires
+ */
+ public void setValueNoFire (boolean value)
+ {
+ m_valueNoFire = value;
+ } // setOldValue
+
+ /**
+ * Get old/previous Value.
+ * Called from MTab.processCallout
+ * @return old value
+ */
+ public Object getOldValue()
+ {
+ return m_oldValue;
+ } // getOldValue
+
+ /**
+ * Set Error Value (the value, which cuased some Error)
+ * @param errorValue error message
+ */
+ public void setErrorValue (String errorValue)
+ {
+ m_errorValue = errorValue;
+ m_errorValueFlag = true;
+ } // setErrorValue
+
+ /**
+ * Get Error Value (the value, which cuased some Error) AND reset it to null
+ * @return error value
+ */
+ public String getErrorValue ()
+ {
+ String s = m_errorValue;
+ m_errorValue = null;
+ m_errorValueFlag = false;
+ return s;
+ } // getErrorValue
+
+ /**
+ * Return true, if value has Error (for HTML interface) AND reset it to false
+ * @return has error
+ */
+ public boolean isErrorValue()
+ {
+ boolean b = m_errorValueFlag;
+ m_errorValueFlag = false;
+ return b;
+ } // isErrorValue
+
+ /**
+ * Overwrite default DisplayLength
+ * @param length new length
+ */
+ public void setDisplayLength (int length)
+ {
+ m_vo.DisplayLength = length;
+ } // setDisplayLength
+
+ /**
+ * Overwrite Displayed
+ * @param displayed trie if displayed
+ */
+ public void setDisplayed (boolean displayed)
+ {
+ m_vo.IsDisplayed = displayed;
+ } // setDisplayed
+
+
+ /**
+ * Create Mnemonic for field
+ * @return no for r/o, client, org, document no
+ */
+ public boolean isCreateMnemonic()
+ {
+ if (isReadOnly()
+ || m_vo.ColumnName.equals("AD_Client_ID")
+ || m_vo.ColumnName.equals("AD_Org_ID")
+ || m_vo.ColumnName.equals("DocumentNo"))
+ return false;
+ return true;
+ }
+
+ /**
+ * Get Label Mnemonic
+ * @return Mnemonic
+ */
+ public char getMnemonic()
+ {
+ return m_mnemonic;
+ } // getMnemonic
+
+ /**
+ * Set Label Mnemonic
+ * @param mnemonic Mnemonic
+ */
+ public void setMnemonic (char mnemonic)
+ {
+ m_mnemonic = mnemonic;
+ } // setMnemonic
+
+
+ /**
+ * String representation
+ * @return string representation
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer("MField[");
+ sb.append(m_vo.ColumnName).append("=").append(m_value).append("]");
+ return sb.toString();
+ } // toString
+
+ /**
+ * Extended String representation
+ * @return string representation
+ */
+ public String toStringX()
+ {
+ StringBuffer sb = new StringBuffer("MField[");
+ sb.append(m_vo.ColumnName).append("=").append(m_value)
+ .append(",DisplayType=").append(getDisplayType())
+ .append("]");
+ return sb.toString();
+ } // toStringX
+
+
+ /*************************************************************************
+ * Remove Property Change Listener
+ * @param l listener
+ */
+ public synchronized void removePropertyChangeListener(PropertyChangeListener l)
+ {
+ m_propertyChangeListeners.removePropertyChangeListener(l);
+ }
+
+ /**
+ * Add Property Change Listener
+ * @param l listener
+ */
+ public synchronized void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ m_propertyChangeListeners.addPropertyChangeListener(l);
+ }
+
+
+ /**************************************************************************
+ * Create Fields.
+ * Used by APanel.cmd_find and Viewer.cmd_find
+ * @param ctx context
+ * @param WindowNo window
+ * @param TabNo tab no
+ * @param AD_Tab_ID tab
+ * @return array of all fields in display order
+ */
+ public static GridField[] createFields (Properties ctx, int WindowNo, int TabNo,
+ int AD_Tab_ID)
+ {
+ ArrayList listVO = new ArrayList();
+ int AD_Window_ID = 0;
+ boolean readOnly = false;
+
+ String sql = GridFieldVO.getSQL(ctx);
+ PreparedStatement pstmt = null;
+ try
+ {
+ pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, AD_Tab_ID);
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next())
+ {
+ GridFieldVO vo = GridFieldVO.create(ctx, WindowNo, TabNo,
+ AD_Window_ID, AD_Tab_ID, readOnly, rs);
+ listVO.add(vo);
+ }
+ rs.close();
+ pstmt.close();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ try
+ {
+ if (pstmt != null)
+ pstmt.close();
+ pstmt = null;
+ }
+ catch (Exception e)
+ {
+ pstmt = null;
+ }
+
+ //
+ GridField[] retValue = new GridField[listVO.size()];
+ for (int i = 0; i < listVO.size(); i++)
+ retValue[i] = new GridField ((GridFieldVO)listVO.get(i));
+ return retValue;
+ } // createFields
+
+
+} // MField
diff --git a/base/src/org/compiere/model/GridTab.java b/base/src/org/compiere/model/GridTab.java
new file mode 100644
index 0000000000..7b22b55c8b
--- /dev/null
+++ b/base/src/org/compiere/model/GridTab.java
@@ -0,0 +1,2446 @@
+/******************************************************************************
+ * 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.model;
+
+import java.beans.*;
+import java.io.*;
+import java.sql.*;
+import java.text.*;
+import java.util.*;
+
+import java.util.logging.*;
+import javax.swing.event.*;
+import org.compiere.util.*;
+
+/**
+ * Tab Model.
+ * - a combination of AD_Tab (the display attributes) and AD_Table information.
+ *
+ * The Tab owns also it's Table model
+ * and listens to data changes to update the Field values.
+ *
+ *
+ * The Tab maintains the bound property: CurrentRow
+ *
+ *
+ * Event Hierarchies:
+ * - dataChanged (from MTable)
+ * - setCurrentRow
+ * - Update all Field Values
+ *
+ * - setValue
+ * - Update Field Value
+ * - Callout
+ *
+ * MTab provides a property listener for changed rows and a
+ * DataStatusListener for communicating changes of the underlying data
+ * @param vo Value Object
+ */
+ public GridTab(GridTabVO vo)
+ {
+ m_vo = vo;
+ // Create MTable
+ m_mTable = new GridTable (m_vo.ctx, m_vo.AD_Table_ID, m_vo.TableName, m_vo.WindowNo, m_vo.TabNo, true);
+ m_mTable.setReadOnly(m_vo.IsReadOnly || m_vo.IsView);
+ m_mTable.setDeleteable(m_vo.IsDeleteable);
+ // Load Tab
+ // if (vo.TabNo == 0)
+ initTab(false);
+ // else
+ // {
+ // m_loader = new Loader();
+ // m_loader.setPriority(Thread.MIN_PRIORITY);
+ // m_loader.start();
+ // }
+ // waitLoadCompete();
+ } // GridTab
+
+ /** Value Object */
+ private GridTabVO m_vo;
+
+ /** The Table Model for Query */
+ private GridTable m_mTable = null;
+
+ private String m_keyColumnName = "";
+ private String m_linkColumnName = "";
+ private String m_extendedWhere;
+ /** Attachments */
+ private HashMap m_Attachments = null;
+ /** Chats */
+ private HashMap m_Chats = null;
+ /** Locks */
+ private ArrayList m_Lock = null;
+
+ /** Current Row */
+ private int m_currentRow = -1;
+
+ /** Property Change */
+ private PropertyChangeSupport m_propertyChangeSupport = new PropertyChangeSupport(this);
+ /** Property Change Type */
+ public static final String PROPERTY = "CurrentRow";
+ /** A list of event listeners for this component. */
+ protected EventListenerList m_listenerList = new EventListenerList();
+ /** Current Data Status Event */
+ private DataStatusEvent m_DataStatusEvent = null;
+ /** Query */
+ private MQuery m_query = new MQuery();
+ private String m_oldQuery = "0=9";
+ private String m_linkValue = "999999";
+
+ /** Order By Array if SortNo 1..3 */
+ private String[] m_OrderBys = new String[3];
+ /** List of Key Parents */
+ private ArrayList m_parents = new ArrayList(2);
+
+ /** Map of ColumnName of source field (key) and the dependant field (value) */
+ private MultiMap m_depOnField = new MultiMap();
+
+ /** Async Loader */
+ private Loader m_loader = null;
+ /** Async Loading complete */
+ private volatile boolean m_loadComplete = false;
+ /** Is Tab Included in other Tab */
+ private boolean m_included = false;
+
+ /** Logger */
+ protected CLogger log = CLogger.getCLogger(getClass());
+
+
+ /**************************************************************************
+ * Tab loader for Tabs > 0
+ */
+ class Loader extends Thread
+ {
+ /**
+ * Async Loading of Tab > 0
+ */
+ public void run()
+ {
+ initTab (true);
+ } // run
+ } // Loader
+
+ /**
+ * Wait until load is complete
+ */
+ private void waitLoadCompete()
+ {
+ if (m_loadComplete)
+ return;
+ //
+ m_loader.setPriority(Thread.NORM_PRIORITY);
+ log.config ("");
+ while (m_loader.isAlive())
+ {
+ try
+ {
+ Thread.sleep(100); // 1/10 sec
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "", e);
+ }
+ }
+ log.config ("fini");
+ } // waitLoadComplete
+
+ /**
+ * Initialize Tab with record from AD_Tab_v
+ * @param async async
+ * @return true, if correctly initialized (ignored)
+ */
+ protected boolean initTab (boolean async)
+ {
+ log.fine("#" + m_vo.TabNo + " - Async=" + async + " - Where=" + m_vo.WhereClause);
+
+ m_extendedWhere = m_vo.WhereClause;
+
+ // Get Field Data
+ if (!loadFields())
+ {
+ m_loadComplete = true;
+ return false;
+ }
+
+ // Order By
+ m_mTable.setOrderClause(getOrderByClause(m_vo.onlyCurrentRows));
+
+ if (async)
+ log.fine("#" + m_vo.TabNo + " - Async=" + async + " - fini");
+ m_loadComplete = true;
+ return true;
+ } // initTab
+
+ /**
+ * Dispose - clean up resources
+ */
+ protected void dispose()
+ {
+ log.fine("#" + m_vo.TabNo);
+ m_OrderBys = null;
+ //
+ m_parents.clear();
+ m_parents = null;
+ //
+ m_mTable.close (true); // also disposes Fields
+ m_mTable = null;
+ //
+ m_depOnField.clear();
+ m_depOnField = null;
+ if (m_Attachments != null)
+ m_Attachments.clear();
+ m_Attachments = null;
+ if (m_Chats != null)
+ m_Chats.clear();
+ m_Chats = null;
+ //
+ m_vo.Fields.clear();
+ m_vo.Fields = null;
+ m_vo = null;
+ } // dispose
+
+
+ /**
+ * Get Field data and add to MTable, if it's required or displayed.
+ * Reqiored fields are keys, parents, or standard Columns
+ * @return true if fields loaded
+ */
+ private boolean loadFields()
+ {
+ log.fine("#" + m_vo.TabNo);
+
+ if (m_vo.Fields == null)
+ return false;
+
+ // Add Fields
+ for (int f = 0; f < m_vo.Fields.size(); f++)
+ {
+ GridFieldVO voF = (GridFieldVO)m_vo.Fields.get(f);
+ // Add Fields to Table
+ if (voF != null)
+ {
+ GridField field = new GridField (voF);
+ String columnName = field.getColumnName();
+ // Record Info
+ if (field.isKey())
+ m_keyColumnName = columnName;
+ // Parent Column(s)
+ if (field.isParentColumn())
+ m_parents.add(columnName);
+ // Order By
+ int sortNo = field.getSortNo();
+ if (sortNo == 0)
+ ;
+ else if (Math.abs(sortNo) == 1)
+ {
+ m_OrderBys[0] = columnName;
+ if (sortNo < 0)
+ m_OrderBys[0] += " DESC";
+ }
+ else if (Math.abs(sortNo) == 2)
+ {
+ m_OrderBys[1] = columnName;
+ if (sortNo < 0)
+ m_OrderBys[1] += " DESC";
+ }
+ else if (Math.abs(sortNo) == 3)
+ {
+ m_OrderBys[2] = columnName;
+ if (sortNo < 0)
+ m_OrderBys[2] += " DESC";
+ }
+ // Add field
+ m_mTable.addField(field);
+
+ // List of ColumnNames, this field is dependent on
+ ArrayList list = field.getDependentOn();
+ for (int i = 0; i < list.size(); i++)
+ m_depOnField.put(list.get(i), field); // ColumnName, Field
+ // Add fields all fields are dependent on
+ if (columnName.equals("IsActive")
+ || columnName.equals("Processed")
+ || columnName.equals("Processing"))
+ m_depOnField.put(columnName, null);
+ }
+ } // for all fields
+
+ // Add Standard Fields
+ if (m_mTable.getField("Created") == null)
+ {
+ GridField created = new GridField (GridFieldVO.createStdField(m_vo.ctx,
+ m_vo.WindowNo, m_vo.TabNo,
+ m_vo.AD_Window_ID, m_vo.AD_Tab_ID, false, true, true));
+ m_mTable.addField(created);
+ }
+ if (m_mTable.getField("CreatedBy") == null)
+ {
+ GridField createdBy = new GridField (GridFieldVO.createStdField(m_vo.ctx,
+ m_vo.WindowNo, m_vo.TabNo,
+ m_vo.AD_Window_ID, m_vo.AD_Tab_ID, false, true, false));
+ m_mTable.addField(createdBy);
+ }
+ if (m_mTable.getField("Updated") == null)
+ {
+ GridField updated = new GridField (GridFieldVO.createStdField(m_vo.ctx,
+ m_vo.WindowNo, m_vo.TabNo,
+ m_vo.AD_Window_ID, m_vo.AD_Tab_ID, false, false, true));
+ m_mTable.addField(updated);
+ }
+ if (m_mTable.getField("UpdatedBy") == null)
+ {
+ GridField updatedBy = new GridField (GridFieldVO.createStdField(m_vo.ctx,
+ m_vo.WindowNo, m_vo.TabNo,
+ m_vo.AD_Window_ID, m_vo.AD_Tab_ID, false, false, false));
+ m_mTable.addField(updatedBy);
+ }
+ return true;
+ } // loadFields
+
+ /**
+ * Get a list of variables, this tab is dependent on.
+ * - for display purposes
+ * @return ArrayList
+ */
+ public ArrayList getDependentOn()
+ {
+ ArrayList list = new ArrayList();
+ // Display
+ Evaluator.parseDepends(list, m_vo.DisplayLogic);
+ //
+ if (list.size() > 0 && CLogMgt.isLevelFiner())
+ {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < list.size(); i++)
+ sb.append(list.get(i)).append(" ");
+ log.finer("(" + m_vo.Name + ") " + sb.toString());
+ }
+ return list;
+ } // getDependentOn
+
+ /**
+ * Get Display Logic
+ * @return display logic
+ */
+ public String getDisplayLogic()
+ {
+ return m_vo.DisplayLogic;
+ } // getDisplayLogic
+
+ /**
+ * Get TableModel.
+ * Do not directly communicate with the table model,
+ * but through the methods of this class
+ * @return Table Model
+ */
+ public GridTable getTableModel()
+ {
+ return m_mTable;
+ } // getTableModel
+
+ /**
+ * Get Tab Icon
+ * @return Icon
+ */
+ public javax.swing.Icon getIcon()
+ {
+ if (m_vo.AD_Image_ID == 0)
+ return null;
+ //
+ /** @todo Load Image */
+ return null;
+ } // getIcon
+
+
+ /**************************************************************************
+ * Has this field dependents ?
+ * @param columnName column name
+ * @return true if column has dependent
+ */
+ public boolean hasDependants (String columnName)
+ {
+ // m_depOnField.printToLog();
+ return m_depOnField.containsKey(columnName);
+ } // isDependentOn
+
+ /**
+ * Get dependents fields of columnName
+ * @param columnName column name
+ * @return ArrayList with GridFields dependent on columnName
+ */
+ public ArrayList getDependantFields (String columnName)
+ {
+ return m_depOnField.getValues(columnName);
+ } // getDependentFields
+
+
+ /**************************************************************************
+ * Set Query
+ * @param query query
+ */
+ public void setQuery(MQuery query)
+ {
+ if (query == null)
+ m_query = new MQuery();
+ else
+ m_query = query;
+ } // setQuery
+
+ /**
+ * Get Query
+ * @return query
+ */
+ public MQuery getQuery()
+ {
+ return m_query;
+ } // getQuery
+
+ /**
+ * Is Query Active
+ * @return true if query active
+ */
+ public boolean isQueryActive()
+ {
+ if (m_query != null)
+ return m_query.isActive();
+ return false;
+ } // isQueryActive
+
+ /**
+ * Is Query New Record
+ * @return true if query active
+ */
+ public boolean isQueryNewRecord()
+ {
+ if (m_query != null)
+ return m_query.isNewRecordQuery();
+ return false;
+ } // isQueryNewRecord
+
+ /**
+ * Enable Events - enable data events of tabs (add listeners)
+ */
+ public void enableEvents()
+ {
+ // Setup Events
+ m_mTable.addDataStatusListener(this);
+ // m_mTable.addTableModelListener(this);
+ } // enableEvents
+
+ /**
+ * Assemble whereClause and query MTable and position to row 0.
+ *
+ * Scenarios:
+ * - Never opened (full query)
+ * - query changed (full query)
+ * - Detail link value changed (full query)
+ * - otherwise (refreshAll)
+ *
+ * @param onlyCurrentRows only current rows (1 day)
+ */
+ public void query (boolean onlyCurrentRows)
+ {
+ query (onlyCurrentRows, 0, 0);
+ } // query
+
+ /**
+ * Assemble whereClause and query MTable and position to row 0.
+ *
+ * Scenarios:
+ * - Never opened (full query)
+ * - query changed (full query)
+ * - Detail link value changed (full query)
+ * - otherwise (refreshAll)
+ *
+ * @param onlyCurrentRows only current rows
+ * @param onlyCurrentDays if only current row, how many days back
+ * @param maxRows maximim rows or 0 for all
+ */
+ public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows)
+ {
+ log.fine("#" + m_vo.TabNo
+ + " - Only Current Rows=" + onlyCurrentRows
+ + ", Days=" + onlyCurrentDays + ", Detail=" + isDetail());
+ // is it same query?
+ boolean refresh = m_oldQuery.equals(m_query.getWhereClause())
+ && m_vo.onlyCurrentRows == onlyCurrentRows && m_vo.onlyCurrentDays == onlyCurrentDays;
+ m_oldQuery = m_query.getWhereClause();
+ m_vo.onlyCurrentRows = onlyCurrentRows;
+ m_vo.onlyCurrentDays = onlyCurrentDays;
+
+ /**
+ * Set Where Clause
+ */
+ // Tab Where Clause
+ StringBuffer where = new StringBuffer(m_vo.WhereClause);
+ if (m_vo.onlyCurrentDays > 0)
+ {
+ if (where.length() > 0)
+ where.append(" AND ");
+ where.append("Created >= ");
+ if (DB.isDerby())
+ where.append("dateadd(dd,-").append(m_vo.onlyCurrentDays).append(",getdate())");
+ else
+ where.append("SysDate-").append(m_vo.onlyCurrentDays);
+ }
+ // Detail Query
+ if (isDetail())
+ {
+ String lc = getLinkColumnName();
+ if (lc.equals(""))
+ log.severe ("No link column");
+ else
+ {
+ String value = Env.getContext(m_vo.ctx, m_vo.WindowNo, lc);
+ // Same link value?
+ if (refresh)
+ refresh = m_linkValue.equals(value);
+ m_linkValue = value;
+ // Check validity
+ if (value.length() == 0)
+ log.severe ("No value for link column " + lc);
+ else
+ {
+ // we have column and value
+ if (where.length() != 0)
+ where.append(" AND ");
+ where.append(lc).append("=");
+ if (lc.endsWith("_ID"))
+ where.append(value);
+ else
+ where.append("'").append(value).append("'");
+ }
+ }
+ } // isDetail
+
+ m_extendedWhere = where.toString();
+
+ // Final Query
+ if (m_query.isActive())
+ {
+ String q = validateQuery(m_query);
+ if (q != null)
+ {
+ if (where.length() > 0 )
+ where.append(" AND ");
+ where.append(q);
+ }
+ }
+
+ /**
+ * Query
+ */
+ log.fine("#" + m_vo.TabNo + " - " + where);
+ if (m_mTable.isOpen())
+ {
+ if (refresh)
+ m_mTable.dataRefreshAll();
+ else
+ m_mTable.dataRequery(where.toString(), m_vo.onlyCurrentRows && !isDetail(), onlyCurrentDays);
+ }
+ else
+ {
+ m_mTable.setSelectWhereClause(where.toString(), m_vo.onlyCurrentRows && !isDetail(), onlyCurrentDays);
+ m_mTable.open(maxRows);
+ }
+ // Go to Record 0
+ setCurrentRow(0, true);
+ } // query
+
+ /**
+ * Validate Query.
+ * If query column is not a tab column create EXISTS query
+ * @param query query
+ * @return where clause
+ */
+ private String validateQuery (MQuery query)
+ {
+ if (query == null || query.getRestrictionCount() == 0)
+ return null;
+
+ // Check: only one restriction
+ if (query.getRestrictionCount() != 1)
+ {
+ log.fine("Ignored(More than 1 Restriction): " + query);
+ return query.getWhereClause();
+ }
+
+ String colName = query.getColumnName(0);
+ if (colName == null)
+ {
+ log.fine("Ignored(No Column): " + query);
+ return query.getWhereClause();
+ }
+ // a '(' in the name = function - don't try to resolve
+ if (colName.indexOf('(') != -1)
+ {
+ log.fine("Ignored(Function): " + colName);
+ return query.getWhereClause();
+ }
+ // OK - Query is valid
+
+ // Zooms to the same Window (Parents, ..)
+ String refColName = null;
+ if (colName.equals("R_RequestRelated_ID"))
+ refColName = "R_Request_ID";
+ else if (colName.startsWith("C_DocType"))
+ refColName = "C_DocType_ID";
+ if (refColName != null)
+ {
+ query.setColumnName(0, refColName);
+ if (getField(refColName) != null)
+ {
+ log.fine("Column " + colName + " replaced with synonym " + refColName);
+ return query.getWhereClause();
+ }
+ refColName = null;
+ }
+
+ // Simple Query.
+ if (getField(colName) != null)
+ {
+ log.fine("Field Found: " + colName);
+ return query.getWhereClause();
+ }
+
+ // Find Refernce Column e.g. BillTo_ID -> C_BPartner_Location_ID
+ String sql = "SELECT cc.ColumnName "
+ + "FROM AD_Column c"
+ + " INNER JOIN AD_Ref_Table r ON (c.AD_Reference_Value_ID=r.AD_Reference_ID)"
+ + " INNER JOIN AD_Column cc ON (r.AD_Key=cc.AD_Column_ID) "
+ + "WHERE c.AD_Reference_ID IN (18,30)" // Table/Search
+ + " AND c.ColumnName=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setString(1, colName);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ refColName = rs.getString(1);
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "(ref) - Column=" + colName, e);
+ return query.getWhereClause();
+ }
+ // Reference Column found
+ if (refColName != null)
+ {
+ query.setColumnName(0, refColName);
+ if (getField(refColName) != null)
+ {
+ log.fine("Column " + colName + " replaced with " + refColName);
+ return query.getWhereClause();
+ }
+ colName = refColName;
+ }
+
+ // Column NOT in Tab - create EXISTS subquery
+ String tableName = null;
+ String tabKeyColumn = getKeyColumnName();
+ // Column=SalesRep_ID, Key=AD_User_ID, Query=SalesRep_ID=101
+
+ sql = "SELECT t.TableName "
+ + "FROM AD_Column c"
+ + " INNER JOIN AD_Table t ON (c.AD_Table_ID=t.AD_Table_ID) "
+ + "WHERE c.ColumnName=? AND IsKey='Y'" // #1 Link Column
+ + " AND EXISTS (SELECT * FROM AD_Column cc"
+ + " WHERE cc.AD_Table_ID=t.AD_Table_ID AND cc.ColumnName=?)"; // #2 Tab Key Column
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setString(1, colName);
+ pstmt.setString(2, tabKeyColumn);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ tableName = rs.getString(1);
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "Column=" + colName + ", Key=" + tabKeyColumn, e);
+ return null;
+ }
+
+ // Special Reference Handling
+ if (tabKeyColumn.equals("AD_Reference_ID"))
+ {
+ // Column=AccessLevel, Key=AD_Reference_ID, Query=AccessLevel='6'
+ sql = "SELECT AD_Reference_ID FROM AD_Column WHERE ColumnName=?";
+ int AD_Reference_ID = DB.getSQLValue(null, sql, colName);
+ return "AD_Reference_ID=" + AD_Reference_ID;
+ }
+
+ // Causes could be functions in query
+ // e.g. Column=UPPER(Name), Key=AD_Element_ID, Query=UPPER(AD_Element.Name) LIKE '%CUSTOMER%'
+ if (tableName == null)
+ {
+ log.info ("Not successfull - Column="
+ + colName + ", Key=" + tabKeyColumn
+ + ", Query=" + query);
+ return query.getWhereClause();
+ }
+
+ query.setTableName("xx");
+ StringBuffer result = new StringBuffer ("EXISTS (SELECT * FROM ")
+ .append(tableName).append(" xx WHERE ")
+ .append(query.getWhereClause(true))
+ .append(" AND xx.").append(tabKeyColumn).append("=")
+ .append(getTableName()).append(".").append(tabKeyColumn).append(")");
+ log.fine(result.toString());
+ return result.toString();
+ } // validateQuery
+
+
+ /**************************************************************************
+ * Refresh all data
+ */
+ public void dataRefreshAll ()
+ {
+ log.fine("#" + m_vo.TabNo);
+ /** @todo does not work with alpha key */
+ int keyNo = m_mTable.getKeyID(m_currentRow);
+ m_mTable.dataRefreshAll();
+ // Should use RowID - not working for tables with multiple keys
+ if (keyNo != -1)
+ {
+ if (keyNo != m_mTable.getKeyID(m_currentRow)) // something changed
+ {
+ int size = getRowCount();
+ for (int i = 0; i < size; i++)
+ {
+ if (keyNo == m_mTable.getKeyID(i))
+ {
+ m_currentRow = i;
+ break;
+ }
+ }
+ }
+ }
+ setCurrentRow(m_currentRow, true);
+ } // dataRefreshAll
+
+ /**
+ * Refresh current row data
+ */
+ public void dataRefresh ()
+ {
+ dataRefresh (m_currentRow);
+ } // dataRefresh
+
+ /**
+ * Refresh row data
+ * @param row index
+ */
+ public void dataRefresh (int row)
+ {
+ log.fine("#" + m_vo.TabNo + " - row=" + row);
+ m_mTable.dataRefresh(row);
+ setCurrentRow(row, true);
+ } // dataRefresh
+
+
+ /**************************************************************************
+ * Uncoditionally Save data
+ * @param manualCmd if true, no vetoable PropertyChange will be fired for save confirmation from MTable
+ * @return true if save complete (or nor required)
+ */
+ public boolean dataSave(boolean manualCmd)
+ {
+ log.fine("#" + m_vo.TabNo + " - row=" + m_currentRow);
+ try
+ {
+ boolean retValue = (m_mTable.dataSave(manualCmd) == GridTable.SAVE_OK);
+ if (manualCmd)
+ setCurrentRow(m_currentRow, false);
+ return retValue;
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "#" + m_vo.TabNo + " - row=" + m_currentRow, e);
+ }
+ return false;
+ } // dataSave
+
+
+ /**
+ * Do we need to Save?
+ * @param rowChange row change
+ * @param onlyRealChange if true the value of a field was actually changed
+ * (e.g. for new records, which have not been changed) - default false
+ * @return true it needs to be saved
+ */
+ public boolean needSave (boolean rowChange, boolean onlyRealChange)
+ {
+ if (rowChange)
+ {
+ return m_mTable.needSave(-2, onlyRealChange);
+ }
+ else
+ {
+ if (onlyRealChange)
+ return m_mTable.needSave();
+ else
+ return m_mTable.needSave(onlyRealChange);
+ }
+ } // isDataChanged
+
+ /**
+ * Ignore data changes
+ */
+ public void dataIgnore()
+ {
+ log.fine("#" + m_vo.TabNo);
+ m_mTable.dataIgnore();
+ setCurrentRow(m_currentRow, false); // re-load data
+ log.fine("#" + m_vo.TabNo + "- fini");
+ } // dataIgnore
+
+
+ /**
+ * Create (copy) new Row
+ * and process Callouts
+ * @param copy copy
+ * @return true if copied/new
+ */
+ public boolean dataNew (boolean copy)
+ {
+ log.fine("#" + m_vo.TabNo);
+ if (!isInsertRecord())
+ {
+ log.warning ("Inset Not allowed in TabNo=" + m_vo.TabNo);
+ return false;
+ }
+ // Prevent New Where Main Record is processed
+ if (m_vo.TabNo > 0)
+ {
+ boolean processed = "Y".equals(Env.getContext(m_vo.ctx, m_vo.WindowNo, "Processed"));
+ // boolean active = "Y".equals(Env.getContext(m_vo.ctx, m_vo.WindowNo, "IsActive"));
+ if (processed)
+ {
+ log.warning ("Not allowed in TabNo=" + m_vo.TabNo + " -> Processed=" + processed);
+ return false;
+ }
+ log.finest("Processed=" + processed);
+ }
+ boolean retValue = m_mTable.dataNew (m_currentRow, copy);
+ if (!retValue)
+ return retValue;
+ setCurrentRow(m_currentRow + 1, true);
+ // process all Callouts (no dependency check - assumed that settings are valid)
+ for (int i = 0; i < getFieldCount(); i++)
+ processCallout(getField(i));
+ // check validity of defaults
+ for (int i = 0; i < getFieldCount(); i++)
+ {
+ getField(i).refreshLookup();
+ getField(i).validateValue();
+ }
+ m_mTable.setChanged(false);
+ return retValue;
+ } // dataNew
+
+ /**
+ * Delete current Row
+ * @return true if deleted
+ */
+ public boolean dataDelete()
+ {
+ log.fine("#" + m_vo.TabNo + " - row=" + m_currentRow);
+ boolean retValue = m_mTable.dataDelete(m_currentRow);
+ setCurrentRow(m_currentRow, true);
+ return retValue;
+ } // dataDelete
+
+
+ /**
+ * Get Name of Tab
+ * @return name
+ */
+ public String getName()
+ {
+ return m_vo.Name;
+ } // getName
+
+ /**
+ * Get Description of Tab
+ * @return description
+ */
+ public String getDescription()
+ {
+ return m_vo.Description;
+ } // getDescription
+
+ /**
+ * Get Help of Tab
+ * @return help
+ */
+ public String getHelp()
+ {
+ return m_vo.Help;
+ } // getHelp
+
+ /**
+ * Get Tab Level
+ * @return tab level
+ */
+ public int getTabLevel()
+ {
+ return m_vo.TabLevel;
+ } // getTabLevel
+
+ /**
+ * Get Commit Warning
+ * @return commit warning
+ */
+ public String getCommitWarning()
+ {
+ return m_vo.CommitWarning;
+ } // getCommitWarning
+
+ /**
+ * Return Table Model
+ * @return MTable
+ */
+ protected GridTable getMTable()
+ {
+ return m_mTable;
+ } // getMTable
+
+ /**
+ * Return the name of the key column - may be ""
+ * @return key column name
+ */
+ public String getKeyColumnName()
+ {
+ return m_keyColumnName;
+ } // getKeyColumnName
+
+ /**
+ * Return Name of link column
+ * @return link column name
+ */
+ public String getLinkColumnName()
+ {
+ return m_linkColumnName;
+ } // getLinkColumnName
+
+ /**
+ * Set Name of link column.
+ * Set from MWindow.loadTabData
+ * Used in MTab.isCurreny, (.setCurrentRow) .query - APanel.cmd_report
+ * and MField.isEditable and .isDefault via context
+ * @param linkColumnName name of column - or sets name to AD_Column_ID, if exists
+ */
+ public void setLinkColumnName (String linkColumnName)
+ {
+ if (linkColumnName != null)
+ m_linkColumnName = linkColumnName;
+ else
+ {
+ if (m_vo.AD_Column_ID == 0)
+ return;
+ // we have a link column identified (primary parent column)
+ else
+ {
+ String SQL = "SELECT ColumnName FROM AD_Column WHERE AD_Column_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(SQL, null);
+ pstmt.setInt(1, m_vo.AD_Column_ID); // Parent Link Column
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ m_linkColumnName = rs.getString(1);
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "", e);
+ }
+ log.fine("AD_Column_ID=" + m_vo.AD_Column_ID + " - " + m_linkColumnName);
+ }
+ }
+ Env.setContext(m_vo.ctx, m_vo.WindowNo, m_vo.TabNo, "LinkColumnName", m_linkColumnName);
+ } // setLinkColumnName
+
+ /**
+ * Is the tab current?.
+ *
+ * Yes - Table must be open
+ * - Query String is the same
+ * - Not Detail
+ * - Old link column value is same as current one
+ *
+ * @return true if current
+ */
+ public boolean isCurrent()
+ {
+ // Open?
+ if (!m_mTable.isOpen())
+ return false;
+ // Same Query
+ if (!m_oldQuery.equals(m_query.getWhereClause()))
+ return false;
+ // Detail?
+ if (!isDetail())
+ return true;
+ // Same link column value
+ String value = Env.getContext(m_vo.ctx, m_vo.WindowNo, getLinkColumnName());
+ return m_linkValue.equals(value);
+ } // isCurrent
+
+ /**
+ * Is the tab/table currently open
+ * @return true if open
+ */
+ public boolean isOpen()
+ {
+ // Open?
+ if (m_mTable != null)
+ return m_mTable.isOpen();
+ return false;
+ } // isCurrent
+
+
+ /**
+ * Is Tab Incluced in other Tab
+ * @return true if included
+ */
+ public boolean isIncluded()
+ {
+ return m_included;
+ } // isIncluded
+
+ /**
+ * Is Tab Incluced in other Tab
+ * @param isIncluded true if included
+ */
+ public void setIncluded(boolean isIncluded)
+ {
+ m_included = isIncluded;
+ } // setIncluded
+
+ /**
+ * Are Only Current Rows displayed
+ * @return true if no history
+ */
+ public boolean isOnlyCurrentRows()
+ {
+ return m_vo.onlyCurrentRows;
+ } // isOnlyCurrentRows
+ /**
+ * Return Parent ArrayList
+ * @return parent column names
+ */
+ public ArrayList getParentColumnNames()
+ {
+ return m_parents;
+ } // getParentColumnNames
+
+ /**
+ * Get Tree ID of this tab
+ * @return ID
+ */
+ private int getTreeID()
+ {
+ log.fine(m_vo.TableName);
+ String SQL = "SELECT * FROM AD_ClientInfo WHERE AD_Client="
+ + Env.getContext(m_vo.ctx, m_vo.WindowNo, "AD_Client_ID")
+ + " ORDER BY AD_Org DESC";
+ //
+ if (m_vo.TableName.equals("AD_Menu"))
+ return 10; // MM
+ else if (m_vo.TableName.equals("C_ElementValue"))
+ return 20; // EV
+ else if (m_vo.TableName.equals("M_Product"))
+ return 30; // PR
+ else if (m_vo.TableName.equals("C_BPartner"))
+ return 40; // BP
+ else if (m_vo.TableName.equals("AD_Org"))
+ return 50; // OO
+ else if (m_vo.TableName.equals("C_Project"))
+ return 60; // PJ
+ return 0;
+ } // getTreeID
+
+ /**
+ * Returns true if this is a detail record
+ * @return true if not parent tab
+ */
+ public boolean isDetail()
+ {
+ // We have IsParent columns and/or a link column
+ if (m_parents.size() > 0 || m_vo.AD_Column_ID != 0)
+ return true;
+ return false;
+ } // isDetail
+
+ /**
+ * Is Printed (Document can be printed)
+ * @return true if printing
+ */
+ public boolean isPrinted()
+ {
+ return m_vo.AD_Process_ID != 0;
+ } // isPrinted
+
+ /**
+ * Get WindowNo
+ * @return window no
+ */
+ public int getWindowNo()
+ {
+ return m_vo.WindowNo;
+ } // getWindowNo
+
+ /**
+ * Get TabNo
+ * @return tab no
+ */
+ public int getTabNo()
+ {
+ return m_vo.TabNo;
+ } // getTabNo
+
+ /**
+ * Get Process ID
+ * @return Process ID
+ */
+ public int getAD_Process_ID()
+ {
+ return m_vo.AD_Process_ID;
+ } // getAD_Process_ID
+
+ /**
+ * Is High Volume?
+ * @return true if high volumen table
+ */
+ public boolean isHighVolume()
+ {
+ return m_vo.IsHighVolume;
+ } // isHighVolume
+
+ /**
+ * Is Read Only?
+ * @return true if read only
+ */
+ public boolean isReadOnly()
+ {
+ if (m_vo.IsReadOnly)
+ return true;
+
+ // no restrictions
+ if (m_vo.ReadOnlyLogic == null || m_vo.ReadOnlyLogic.equals(""))
+ return m_vo.IsReadOnly;
+
+ // ** dynamic content ** uses get_ValueAsString
+ boolean retValue = Evaluator.evaluateLogic(this, m_vo.ReadOnlyLogic);
+ log.finest(m_vo.Name
+ + " (" + m_vo.ReadOnlyLogic + ") => " + retValue);
+ return retValue;
+ } // isReadOnly
+
+ /**
+ * Tab contains Always Update Field
+ * @return true if field with always updateable
+ */
+ public boolean isAlwaysUpdateField()
+ {
+ for (int i = 0; i < m_mTable.getColumnCount(); i++)
+ {
+ GridField field = m_mTable.getField(i);
+ if (field.isAlwaysUpdateable())
+ return true;
+ }
+ return false;
+ } // isAlwaysUpdateField
+
+ /**
+ * Can we Insert Records?
+ * @return true not read only and allowed
+ */
+ public boolean isInsertRecord()
+ {
+ if (isReadOnly())
+ return false;
+ return m_vo.IsInsertRecord;
+ } // isInsertRecord
+
+ /**
+ * Is the Tab Visible.
+ * Called when constructing the window.
+ * @return true, if displayed
+ */
+ public boolean isDisplayed ()
+ {
+ // no restrictions
+ String dl = m_vo.DisplayLogic;
+ if (dl == null || dl.equals(""))
+ return true;
+
+ // ** dynamic content **
+ String parsed = Env.parseContext (m_vo.ctx, 0, dl, false, false).trim();
+ if (parsed.length() == 0)
+ return true;
+ boolean retValue = Evaluator.evaluateLogic(this, dl);
+ log.config(m_vo.Name + " (" + dl + ") => " + retValue);
+ return retValue;
+ } // isDisplayed
+
+ /**
+ * Get Variable Value (Evaluatee)
+ * @param variableName name
+ * @return value
+ */
+ public String get_ValueAsString (String variableName)
+ {
+ return Env.getContext (m_vo.ctx, m_vo.WindowNo, variableName, true);
+ } // get_ValueAsString
+
+ /**
+ * Is Single Row
+ * @return true if single row
+ */
+ public boolean isSingleRow()
+ {
+ return m_vo.IsSingleRow;
+ } // isSingleRow;
+
+ /**
+ * Set Single Row.
+ * Temporary store of current value
+ * @param isSingleRow toggle
+ */
+ public void setSingleRow (boolean isSingleRow)
+ {
+ m_vo.IsSingleRow = isSingleRow;
+ } // setSingleRow
+
+
+ /**
+ * Has Tree
+ * @return true if tree exists
+ */
+ public boolean isTreeTab()
+ {
+ return m_vo.HasTree;
+ } // isTreeTab
+
+ /**
+ * Get Tab ID
+ * @return Tab ID
+ */
+ public int getAD_Tab_ID()
+ {
+ return m_vo.AD_Tab_ID;
+ } // getAD_Tab_ID
+
+ /**
+ * Get Table ID
+ * @return Table ID
+ */
+ public int getAD_Table_ID()
+ {
+ return m_vo.AD_Table_ID;
+ } // getAD_Table_ID
+
+ /**
+ * Get Window ID
+ * @return Window ID
+ */
+ public int getAD_Window_ID()
+ {
+ return m_vo.AD_Window_ID;
+ } // getAD_Window_ID
+
+ /**
+ * Get Included Tab ID
+ * @return Included_Tab_ID
+ */
+ public int getIncluded_Tab_ID()
+ {
+ return m_vo.Included_Tab_ID;
+ } // getIncluded_Tab_ID
+
+ /**
+ * Get TableName
+ * @return Table Name
+ */
+ public String getTableName()
+ {
+ return m_vo.TableName;
+ } // getTableName
+
+ /**
+ * Get Tab Where Clause
+ * @return where clause
+ */
+ public String getWhereClause()
+ {
+ return m_vo.WhereClause;
+ } // getWhereClause
+
+ /**
+ * Is Sort Tab
+ * @return true if sort tab
+ */
+ public boolean isSortTab()
+ {
+ return m_vo.IsSortTab;
+ } // isSortTab
+
+ /**
+ * Get Order column for sort tab
+ * @return AD_Column_ID
+ */
+ public int getAD_ColumnSortOrder_ID()
+ {
+ return m_vo.AD_ColumnSortOrder_ID;
+ } // getAD_ColumnSortOrder_ID
+
+ /**
+ * Get Yes/No column for sort tab
+ * @return AD_Column_ID
+ */
+ public int getAD_ColumnSortYesNo_ID()
+ {
+ return m_vo.AD_ColumnSortYesNo_ID;
+ } // getAD_ColumnSortYesNo_ID
+
+
+ /**************************************************************************
+ * Get extended Where Clause (parent link)
+ * @return parent link
+ */
+ public String getWhereExtended()
+ {
+ return m_extendedWhere;
+ } // getWhereExtended
+
+ /**
+ * Get Order By Clause
+ * @param onlyCurrentRows only current rows
+ * @return Order By Clause
+ */
+ private String getOrderByClause(boolean onlyCurrentRows)
+ {
+ // First Prio: Tab Order By
+ if (m_vo.OrderByClause.length() > 0)
+ return m_vo.OrderByClause;
+
+ // Second Prio: Fields (save it)
+ m_vo.OrderByClause = "";
+ for (int i = 0; i < 3; i++)
+ {
+ String order = m_OrderBys[i];
+ if (order != null && order.length() > 0)
+ {
+ if (m_vo.OrderByClause.length() > 0)
+ m_vo.OrderByClause += ",";
+ m_vo.OrderByClause += order;
+ }
+ }
+ if (m_vo.OrderByClause.length() > 0)
+ return m_vo.OrderByClause;
+
+ // Third Prio: onlyCurrentRows
+ m_vo.OrderByClause = "Created";
+ if (onlyCurrentRows && !isDetail()) // first tab only
+ m_vo.OrderByClause += " DESC";
+ return m_vo.OrderByClause;
+ } // getOrderByClause
+
+
+ /**************************************************************************
+ * Transaction support.
+ * Depending on Table returns transaction info
+ * @return info
+ */
+ public String getTrxInfo()
+ {
+ // InvoiceBatch
+ if (m_vo.TableName.startsWith("C_InvoiceBatch"))
+ {
+ int Record_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, "C_InvoiceBatch_ID");
+ log.fine(m_vo.TableName + " - " + Record_ID);
+ MessageFormat mf = null;
+ try
+ {
+ mf = new MessageFormat(Msg.getMsg(Env.getAD_Language(m_vo.ctx), "InvoiceBatchSummary"));
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "InvoiceBatchSummary=" + Msg.getMsg(Env.getAD_Language(m_vo.ctx), "InvoiceBatchSummary"), e);
+ }
+ if (mf == null)
+ return " ";
+ /**********************************************************************
+ * ** Message: ExpenseSummary **
+ * {0} Line(s) {1,number,#,##0.00} - Total: {2,number,#,##0.00}
+ *
+ * {0} - Number of lines
+ * {1} - Toral
+ * {2} - Currency
+ */
+ Object[] arguments = new Object[3];
+ boolean filled = false;
+ //
+ String sql = "SELECT COUNT(*), NVL(SUM(LineNetAmt),0), NVL(SUM(LineTotalAmt),0) "
+ + "FROM C_InvoiceBatchLine "
+ + "WHERE C_InvoiceBatch_ID=? AND IsActive='Y'";
+ //
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, Record_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // {0} - Number of lines
+ Integer lines = new Integer(rs.getInt(1));
+ arguments[0] = lines;
+ // {1} - Line net
+ Double net = new Double(rs.getDouble(2));
+ arguments[1] = net;
+ // {2} - Line net
+ Double total = new Double(rs.getDouble(3));
+ arguments[2] = total;
+ filled = true;
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, m_vo.TableName + "\nSQL=" + sql, e);
+ }
+ if (filled)
+ return mf.format (arguments);
+ return " ";
+ } // InvoiceBatch
+
+ // Order || Invoice
+ else if (m_vo.TableName.startsWith("C_Order") || m_vo.TableName.startsWith("C_Invoice"))
+ {
+ int Record_ID;
+ boolean isOrder = m_vo.TableName.startsWith("C_Order");
+ //
+ StringBuffer sql = new StringBuffer("SELECT COUNT(*) AS Lines,c.ISO_Code,o.TotalLines,o.GrandTotal,"
+ + "currencyBase(o.GrandTotal,o.C_Currency_ID,o.DateAcct, o.AD_Client_ID,o.AD_Org_ID) AS ConvAmt ");
+ if (isOrder)
+ {
+ Record_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, "C_Order_ID");
+ sql.append("FROM C_Order o"
+ + " INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)"
+ + " INNER JOIN C_OrderLine l ON (o.C_Order_ID=l.C_Order_ID) "
+ + "WHERE o.C_Order_ID=? ");
+ }
+ else
+ {
+ Record_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, "C_Invoice_ID");
+ sql.append("FROM C_Invoice o"
+ + " INNER JOIN C_Currency c ON (o.C_Currency_ID=c.C_Currency_ID)"
+ + " INNER JOIN C_InvoiceLine l ON (o.C_Invoice_ID=l.C_Invoice_ID) "
+ + "WHERE o.C_Invoice_ID=? ");
+ }
+ sql.append("GROUP BY o.C_Currency_ID, c.ISO_Code, o.TotalLines, o.GrandTotal, o.DateAcct, o.AD_Client_ID, o.AD_Org_ID");
+
+ log.fine(m_vo.TableName + " - " + Record_ID);
+ MessageFormat mf = null;
+ try
+ {
+ mf = new MessageFormat(Msg.getMsg(Env.getAD_Language(m_vo.ctx), "OrderSummary"));
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "OrderSummary=" + Msg.getMsg(Env.getAD_Language(m_vo.ctx), "OrderSummary"), e);
+ }
+ if (mf == null)
+ return " ";
+ /**********************************************************************
+ * ** Message: OrderSummary **
+ * {0} Line(s) - {1,number,#,##0.00} - Toral: {2,number,#,##0.00} {3} = {4,number,#,##0.00}
+ *
+ * {0} - Number of lines
+ * {1} - Line toral
+ * {2} - Grand total (including tax, etc.)
+ * {3} - Currency
+ * (4) - Grand total converted to local currency
+ */
+ Object[] arguments = new Object[5];
+ boolean filled = false;
+ //
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
+ pstmt.setInt(1, Record_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // {0} - Number of lines
+ Integer lines = new Integer(rs.getInt(1));
+ arguments[0] = lines;
+ // {1} - Line toral
+ Double lineTotal = new Double(rs.getDouble(3));
+ arguments[1] = lineTotal;
+ // {2} - Grand total (including tax, etc.)
+ Double grandTotal = new Double(rs.getDouble(4));
+ arguments[2] = grandTotal;
+ // {3} - Currency
+ String currency = rs.getString(2);
+ arguments[3] = currency;
+ // (4) - Grand total converted to Euro
+ Double grandEuro = new Double(rs.getDouble(5));
+ arguments[4] = grandEuro;
+ filled = true;
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, m_vo.TableName + "\nSQL=" + sql, e);
+ }
+ if (filled)
+ return mf.format (arguments);
+ return " ";
+ } // Order || Invoice
+
+ // Expense Report
+ else if (m_vo.TableName.startsWith("S_TimeExpense") && m_vo.TabNo == 0)
+ {
+ int Record_ID = Env.getContextAsInt(m_vo.ctx, m_vo.WindowNo, "S_TimeExpense_ID");
+ log.fine(m_vo.TableName + " - " + Record_ID);
+ MessageFormat mf = null;
+ try
+ {
+ mf = new MessageFormat(Msg.getMsg(Env.getAD_Language(m_vo.ctx), "ExpenseSummary"));
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "ExpenseSummary=" + Msg.getMsg(Env.getAD_Language(m_vo.ctx), "ExpenseSummary"), e);
+ }
+ if (mf == null)
+ return " ";
+ /**********************************************************************
+ * ** Message: ExpenseSummary **
+ * {0} Line(s) - Total: {1,number,#,##0.00} {2}
+ *
+ * {0} - Number of lines
+ * {1} - Toral
+ * {2} - Currency
+ */
+ Object[] arguments = new Object[3];
+ boolean filled = false;
+ //
+ String SQL = "SELECT COUNT(*) AS Lines, SUM(ConvertedAmt*Qty) "
+ + "FROM S_TimeExpenseLine "
+ + "WHERE S_TimeExpense_ID=?";
+
+ //
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(SQL, null);
+ pstmt.setInt(1, Record_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ {
+ // {0} - Number of lines
+ Integer lines = new Integer(rs.getInt(1));
+ arguments[0] = lines;
+ // {1} - Line toral
+ Double total = new Double(rs.getDouble(2));
+ arguments[1] = total;
+ // {3} - Currency
+ arguments[2] = " ";
+ filled = true;
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, m_vo.TableName + "\nSQL=" + SQL, e);
+ }
+ if (filled)
+ return mf.format (arguments);
+ return " ";
+ } // S_TimeExpense
+
+
+ // Default - No Trx Info
+ return null;
+ } // getTrxInfo
+
+ /**
+ * Load Dependant Information
+ */
+ private void loadDependentInfo()
+ {
+ /**
+ * Load Order Type from C_DocTypeTarget_ID
+ */
+ if (m_vo.TableName.equals("C_Order"))
+ {
+ int C_DocTyp_ID = 0;
+ Integer target = (Integer)getValue("C_DocTypeTarget_ID");
+ if (target != null)
+ C_DocTyp_ID = target.intValue();
+ if (C_DocTyp_ID == 0)
+ return;
+
+ String sql = "SELECT DocSubTypeSO FROM C_DocType WHERE C_DocType_ID=?";
+ try
+ {
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, C_DocTyp_ID);
+ ResultSet rs = pstmt.executeQuery();
+ if (rs.next())
+ Env.setContext(m_vo.ctx, m_vo.WindowNo, "OrderType", rs.getString(1));
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ } // loadOrderInfo
+ } // loadDependentInfo
+
+
+ /**************************************************************************
+ * Load Attachments for this table
+ */
+ public void loadAttachments()
+ {
+ log.fine("#" + m_vo.TabNo);
+ if (!canHaveAttachment())
+ return;
+
+ String SQL = "SELECT AD_Attachment_ID, Record_ID FROM AD_Attachment "
+ + "WHERE AD_Table_ID=?";
+ try
+ {
+ if (m_Attachments == null)
+ m_Attachments = new HashMap();
+ else
+ m_Attachments.clear();
+ PreparedStatement pstmt = DB.prepareStatement(SQL, null);
+ pstmt.setInt(1, m_vo.AD_Table_ID);
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next())
+ {
+ Integer key = new Integer(rs.getInt(2));
+ Integer value = new Integer(rs.getInt(1));
+ m_Attachments.put(key, value);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, "loadAttachments", e);
+ }
+ log.config("#" + m_Attachments.size());
+ } // loadAttachment
+
+ /**
+ * Can this tab have Attachments?.
+ *
+ * It can have an attachment if it has a key column ending with _ID.
+ * The key column is empty, if there is no single identifying key.
+ * @return true if record can have attachment
+ */
+ public boolean canHaveAttachment()
+ {
+ if (getKeyColumnName().endsWith("_ID"))
+ return true;
+ return false;
+ } // canHaveAttachment
+
+ /**
+ * Returns true, if current row has an Attachment
+ * @return true if record has attchment
+ */
+ public boolean hasAttachment()
+ {
+ if (m_Attachments == null)
+ loadAttachments();
+ if (m_Attachments == null || m_Attachments.isEmpty())
+ return false;
+ //
+ Integer key = new Integer(m_mTable.getKeyID (m_currentRow));
+ return m_Attachments.containsKey(key);
+ } // hasAttachment
+
+ /**
+ * Get Attachment_ID for current record.
+ * @return ID or 0, if not found
+ */
+ public int getAD_AttachmentID()
+ {
+ if (m_Attachments == null)
+ loadAttachments();
+ if (m_Attachments.isEmpty())
+ return 0;
+ //
+ Integer key = new Integer(m_mTable.getKeyID (m_currentRow));
+ Integer value = (Integer)m_Attachments.get(key);
+ if (value == null)
+ return 0;
+ else
+ return value.intValue();
+ } // getAttachmentID
+
+ /**************************************************************************
+ * Load Chats for this table
+ */
+ public void loadChats()
+ {
+ log.fine("#" + m_vo.TabNo);
+ if (!canHaveAttachment())
+ return;
+
+ String sql = "SELECT CM_Chat_ID, Record_ID FROM CM_Chat "
+ + "WHERE AD_Table_ID=?";
+ try
+ {
+ if (m_Chats == null)
+ m_Chats = new HashMap();
+ else
+ m_Chats.clear();
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, m_vo.AD_Table_ID);
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next())
+ {
+ Integer key = new Integer(rs.getInt(2)); // Record_ID
+ Integer value = new Integer(rs.getInt(1)); // CM_Chat_ID
+ m_Chats.put(key, value);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ log.config("#" + m_Chats.size());
+ } // loadChats
+
+ /**
+ * Returns true, if current row has a Chat
+ * @return true if record has chat
+ */
+ public boolean hasChat()
+ {
+ if (m_Chats == null)
+ loadChats();
+ if (m_Chats == null || m_Chats.isEmpty())
+ return false;
+ //
+ Integer key = new Integer(m_mTable.getKeyID (m_currentRow));
+ return m_Chats.containsKey(key);
+ } // hasChat
+
+ /**
+ * Get Chat_ID for this record.
+ * @return ID or 0, if not found
+ */
+ public int getCM_ChatID()
+ {
+ if (m_Chats == null)
+ loadChats();
+ if (m_Chats.isEmpty())
+ return 0;
+ //
+ Integer key = new Integer(m_mTable.getKeyID (m_currentRow));
+ Integer value = (Integer)m_Chats.get(key);
+ if (value == null)
+ return 0;
+ else
+ return value.intValue();
+ } // getCM_ChatID
+
+
+ /**************************************************************************
+ * Load Locks for Table and User
+ */
+ public void loadLocks()
+ {
+ int AD_User_ID = Env.getContextAsInt(Env.getCtx(), "#AD_User_ID");
+ log.fine("#" + m_vo.TabNo + " - AD_User_ID=" + AD_User_ID);
+ if (!canHaveAttachment())
+ return;
+
+ String sql = "SELECT Record_ID "
+ + "FROM AD_Private_Access "
+ + "WHERE AD_User_ID=? AND AD_Table_ID=? AND IsActive='Y' "
+ + "ORDER BY Record_ID";
+ try
+ {
+ if (m_Lock == null)
+ m_Lock = new ArrayList();
+ else
+ m_Lock.clear();
+ PreparedStatement pstmt = DB.prepareStatement(sql, null);
+ pstmt.setInt(1, AD_User_ID);
+ pstmt.setInt(2, m_vo.AD_Table_ID);
+ ResultSet rs = pstmt.executeQuery();
+ while (rs.next())
+ {
+ Integer key = new Integer(rs.getInt(1));
+ m_Lock.add(key);
+ }
+ rs.close();
+ pstmt.close();
+ }
+ catch (SQLException e)
+ {
+ log.log(Level.SEVERE, sql, e);
+ }
+ log.fine("#" + m_Lock.size());
+ } // loadLooks
+
+ /**
+ * Record Is Locked
+ * @return true if locked
+ */
+ public boolean isLocked()
+ {
+ if (!MRole.getDefault(m_vo.ctx, false).isPersonalLock())
+ return false;
+ if (m_Lock == null)
+ loadLocks();
+ if (m_Lock == null || m_Lock.isEmpty())
+ return false;
+ //
+ Integer key = new Integer(m_mTable.getKeyID (m_currentRow));
+ return m_Lock.contains(key);
+ } // isLocked
+
+ /**
+ * Lock Record
+ * @param ctx context
+ * @param Record_ID id
+ * @param lock true if lock, otherwise unlock
+ */
+ public void lock (Properties ctx, int Record_ID, boolean lock)
+ {
+ int AD_User_ID = Env.getContextAsInt(ctx, "#AD_User_ID");
+ log.fine("Lock=" + lock + ", AD_User_ID=" + AD_User_ID
+ + ", AD_Table_ID=" + m_vo.AD_Table_ID + ", Record_ID=" + Record_ID);
+ MPrivateAccess access = MPrivateAccess.get (ctx, AD_User_ID, m_vo.AD_Table_ID, Record_ID);
+ if (access == null)
+ access = new MPrivateAccess (ctx, AD_User_ID, m_vo.AD_Table_ID, Record_ID);
+ access.setIsActive(lock);
+ access.save();
+ //
+ loadLocks();
+ } // lock
+
+
+ /**************************************************************************
+ * Data Status Listener from MTable.
+ * - get raw info and add current row information
+ * - update the current row
+ * - redistribute (fire) Data Status event
+ * @param e event
+ */
+ public void dataStatusChanged (DataStatusEvent e)
+ {
+ log.fine("#" + m_vo.TabNo + " - " + e.toString());
+ int oldCurrentRow = e.getCurrentRow();
+ m_DataStatusEvent = e; // save it
+ // when sorted set current row to 0
+ String msg = m_DataStatusEvent.getAD_Message();
+ if (msg != null && msg.equals("Sorted"))
+ setCurrentRow(0, true);
+ // set current row
+ m_DataStatusEvent.setCurrentRow(m_currentRow);
+ // Same row - update value
+ if (oldCurrentRow == m_currentRow)
+ {
+ GridField field = m_mTable.getField(e.getChangedColumn());
+ if (field != null)
+ {
+ Object value = m_mTable.getValueAt(m_currentRow, e.getChangedColumn());
+ field.setValue(value, m_mTable.isInserting());
+ }
+ }
+ else // Redistribute Info with current row info
+ fireDataStatusChanged(m_DataStatusEvent);
+ // log.fine("dataStatusChanged #" + m_vo.TabNo + "- fini", e.toString());
+ } // dataStatusChanged
+
+ /**
+ * Inform Listeners and build WHO info
+ * @param e event
+ */
+ private void fireDataStatusChanged (DataStatusEvent e)
+ {
+ DataStatusListener[] listeners = m_listenerList.getListeners(DataStatusListener.class);
+ if (listeners.length == 0)
+ return;
+ log.fine(e.toString());
+ // WHO Info
+ if (e.getCurrentRow() >= 0)
+ {
+ e.Created = (Timestamp)getValue("Created");
+ e.CreatedBy = (Integer)getValue("CreatedBy");
+ e.Updated = (Timestamp)getValue("Updated");
+ e.UpdatedBy = (Integer)getValue("UpdatedBy");
+ e.Record_ID = getValue(m_keyColumnName);
+ // Info
+ StringBuffer info = new StringBuffer(getTableName());
+ // We have a key column
+ if (m_keyColumnName != null && m_keyColumnName.length() > 0)
+ {
+ info.append(" - ")
+ .append(m_keyColumnName).append("=").append(e.Record_ID);
+ }
+ else // we have multiple parents
+ {
+ for (int i = 0; i < m_parents.size(); i++)
+ {
+ String keyCol = (String)m_parents.get(i);
+ info.append(" - ")
+ .append(keyCol).append("=").append(getValue(keyCol));
+ }
+ }
+ e.Info = info.toString();
+ }
+ e.setInserting(m_mTable.isInserting());
+ // Distribute/fire it
+ for (int i = 0; i < listeners.length; i++)
+ listeners[i].dataStatusChanged(e);
+ // log.fine("fini - " + e.toString());
+ } // fireDataStatusChanged
+
+ /**
+ * Create and fire Data Status Error Event
+ * @param AD_Message message
+ * @param info info
+ * @param isError if not true, it is a Warning
+ */
+ protected void fireDataStatusEEvent(String AD_Message, String info, boolean isError)
+ {
+ m_mTable.fireDataStatusEEvent(AD_Message, info, isError);
+ } // fireDataStatusEvent
+
+ /**
+ * Create and fire Data Status Error Event (from Error Log)
+ * @param errorLog log
+ */
+ protected void fireDataStatusEEvent (ValueNamePair errorLog)
+ {
+ if (errorLog != null)
+ m_mTable.fireDataStatusEEvent(errorLog);
+ } // fireDataStatusEvent
+
+ /**
+ * Get Current Row
+ * @return current row
+ */
+ public int getCurrentRow()
+ {
+ if (m_currentRow != verifyRow(m_currentRow))
+ setCurrentRow(m_mTable.getRowCount()-1, true);
+ return m_currentRow;
+ } // getCurrentRow
+
+ /**
+ * Get Current Table Key ID
+ * @return Record_ID
+ */
+ public int getRecord_ID()
+ {
+ return m_mTable.getKeyID(m_currentRow);
+ } // getRecord_ID
+
+ /**
+ * Get Key ID of row
+ * @param row row number
+ * @return The Key ID of the row or -1 if not found
+ */
+ public int getKeyID (int row)
+ {
+ return m_mTable.getKeyID (row);
+ } // getCurrentKeyID
+
+ /**
+ * Navigate absolute - goto Row - (zero based).
+ * - does nothing, if in current row
+ * - saves old row if required
+ * @param targetRow target row
+ * @return current row
+ */
+ public int navigate (int targetRow)
+ {
+ // nothing to do
+ if (targetRow == m_currentRow)
+ return m_currentRow;
+ log.info ("Row=" + targetRow);
+
+ // Row range check
+ int newRow = verifyRow(targetRow);
+
+ // Check, if we have old uncommitted data
+ m_mTable.dataSave(newRow, false);
+
+ // new position
+ return setCurrentRow(newRow, true);
+ } // navigate
+
+ /**
+ * Navigate relatively - i.e. plus/minus from current position
+ * @param rowChange row change
+ * @return current row
+ */
+ public int navigateRelative (int rowChange)
+ {
+ return navigate (m_currentRow + rowChange);
+ } // navigateRelative
+
+ /**
+ * Navigate to current now (reload)
+ * @return current row
+ */
+ public int navigateCurrent()
+ {
+ log.info("Row=" + m_currentRow);
+ return setCurrentRow(m_currentRow, true);
+ } // navigateCurrent
+
+ /**
+ * Row Range check
+ * @param targetRow target row
+ * @return checked row
+ */
+ private int verifyRow (int targetRow)
+ {
+ int newRow = targetRow;
+ // Table Open?
+ if (!m_mTable.isOpen())
+ {
+ log.severe ("Table not open");
+ return -1;
+ }
+ // Row Count
+ int rows = getRowCount();
+ if (rows == 0)
+ {
+ log.fine("No Rows");
+ return -1;
+ }
+ if (newRow >= rows)
+ {
+ newRow = rows-1;
+ log.fine("Set to max Row: " + newRow);
+ }
+ else if (newRow < 0)
+ {
+ newRow = 0;
+ log.fine("Set to first Row");
+ }
+ return newRow;
+ } // verifyRow
+
+ /**
+ * Set current row and load data into fields.
+ * If there is no row - load nulls
+ * @param newCurrentRow new current row
+ * @param fireEvents fire events
+ * @return current row
+ */
+ private int setCurrentRow (int newCurrentRow, boolean fireEvents)
+ {
+ int oldCurrentRow = m_currentRow;
+ m_currentRow = verifyRow (newCurrentRow);
+ log.fine("Row=" + m_currentRow + " - fire=" + fireEvents);
+
+ // Update Field Values
+ int size = m_mTable.getColumnCount();
+ for (int i = 0; i < size; i++)
+ {
+ GridField mField = m_mTable.getField(i);
+ // get Value from Table
+ if (m_currentRow >= 0)
+ {
+ Object value = m_mTable.getValueAt(m_currentRow, i);
+ mField.setValue(value, m_mTable.isInserting());
+ if (m_mTable.isInserting()) // set invalid values to null
+ mField.validateValue();
+ }
+ else
+ { // no rows - set to a reasonable value - not updateable
+// Object value = null;
+// if (mField.isKey() || mField.isParent() || mField.getColumnName().equals(m_linkColumnName))
+// value = mField.getDefault();
+ mField.setValue();
+ }
+ }
+ loadDependentInfo();
+
+ if (!fireEvents) // prevents informing twice
+ return m_currentRow;
+
+ // inform VTable/.. -> rowChanged
+ m_propertyChangeSupport.firePropertyChange(PROPERTY, oldCurrentRow, m_currentRow);
+
+ // inform APanel/.. -> dataStatus with row updated
+ if (m_DataStatusEvent == null)
+ m_DataStatusEvent = new DataStatusEvent(this, getRowCount(),
+ m_mTable.isInserting(), // changed
+ Env.isAutoCommit(Env.getCtx(), m_vo.WindowNo), m_mTable.isInserting());
+ //
+ m_DataStatusEvent.setCurrentRow(m_currentRow);
+ String status = m_DataStatusEvent.getAD_Message();
+ if (status == null || status.length() == 0)
+ m_DataStatusEvent.setInfo("NavigateOrUpdate", null, false,false);
+ fireDataStatusChanged(m_DataStatusEvent);
+ return m_currentRow;
+ } // setCurrentRow
+
+
+ /**************************************************************************
+ * Get RowCount
+ * @return row count
+ */
+ public int getRowCount()
+ {
+ int count = m_mTable.getRowCount();
+ // Wait a bit if currently loading
+ if (count == 0 && m_mTable.isLoading())
+ {
+ try
+ {
+ Thread.sleep(100); // .1 sec
+ }
+ catch (Exception e) {}
+ count = m_mTable.getRowCount();
+ }
+ return count;
+ } // getRowCount
+
+ /**
+ * Get Column/Field Count
+ * @return field count
+ */
+ public int getFieldCount()
+ {
+ return m_mTable.getColumnCount();
+ } // getFieldCount
+
+ /**
+ * Get Field by index
+ * @param index index
+ * @return MField
+ */
+ public GridField getField (int index)
+ {
+ return m_mTable.getField(index);
+ } // getField
+
+ /**
+ * Get Field by DB column name
+ * @param columnName column name
+ * @return MField
+ */
+ public GridField getField (String columnName)
+ {
+ return m_mTable.getField(columnName);
+ } // getField
+
+ /**
+ * Get all Fields
+ * @return MFields
+ */
+ public GridField[] getFields ()
+ {
+ return m_mTable.getFields();
+ } // getField
+
+ /**
+ * Set New Value & call Callout
+ * @param columnName database column name
+ * @param value value
+ * @return error message or ""
+ */
+ public String setValue (String columnName, Object value)
+ {
+ if (columnName == null)
+ return "NoColumn";
+ return setValue(m_mTable.getField(columnName), value);
+ } // setValue
+
+ /**
+ * Set New Value & call Callout
+ * @param field field
+ * @param value value
+ * @return error message or ""
+ */
+ public String setValue (GridField field, Object value)
+ {
+ if (field == null)
+ return "NoField";
+
+ log.fine(field.getColumnName() + "=" + value + " - Row=" + m_currentRow);
+
+ int col = m_mTable.findColumn(field.getColumnName());
+ m_mTable.setValueAt(value, m_currentRow, col, false);
+ //
+ return processFieldChange (field);
+ } // setValue
+
+ /**
+ * Is Processed
+ * @return true if current record is processed
+ */
+ public boolean isProcessed()
+ {
+ int index = m_mTable.findColumn("Processed");
+ if (index != -1)
+ {
+ Object oo = m_mTable.getValueAt(m_currentRow, index);
+ if (oo instanceof String)
+ return "Y".equals(oo);
+ if (oo instanceof Boolean)
+ return ((Boolean)oo).booleanValue();
+ }
+ return "Y".equals(Env.getContext(m_vo.ctx, m_vo.WindowNo, "Processed"));
+ } // isProcessed
+
+ /**
+ * Process Field Change - evaluate Dependencies and process Callouts.
+ *
+ * called from MTab.setValue or GridController.dataStatusChanged
+ * @param changedField changed field
+ * @return error message or ""
+ */
+ public String processFieldChange (GridField changedField)
+ {
+ processDependencies (changedField);
+ return processCallout (changedField);
+ } // processFieldChange
+
+ /**
+ * Evaluate Dependencies
+ * @param changedField changed field
+ */
+ private void processDependencies (GridField changedField)
+ {
+ String columnName = changedField.getColumnName();
+ // log.trace(log.l4_Data, "Changed Column", columnName);
+
+ // when column name is not in list of DependentOn fields - fini
+ if (!hasDependants(columnName))
+ return;
+
+ // Get dependent MFields (may be because of display or dynamic lookup)
+ ArrayList list = getDependantFields(columnName);
+ for (int i = 0; i < list.size(); i++)
+ {
+ GridField dependentField = (GridField)list.get(i);
+ // log.trace(log.l5_DData, "Dependent Field", dependentField==null ? "null" : dependentField.getColumnName());
+ // if the field has a lookup
+ if (dependentField != null && dependentField.getLookup() instanceof MLookup)
+ {
+ MLookup mLookup = (MLookup)dependentField.getLookup();
+ // log.trace(log.l6_Database, "Lookup Validation", mLookup.getValidation());
+ // if the lookup is dynamic (i.e. contains this columnName as variable)
+ if (mLookup.getValidation().indexOf("@"+columnName+"@") != -1)
+ {
+ log.fine(columnName + " changed - "
+ + dependentField.getColumnName() + " set to null");
+ // invalidate current selection
+ setValue(dependentField, null);
+ }
+ }
+ } // for all dependent fields
+ } // processDependencies
+
+
+ /**************************************************************************
+ * Process Callout(s).
+ *
+ * The Callout is in the string of
+ * "class.method;class.method;"
+ * If there is no class name, i.e. only a method name, the class is regarded
+ * as CalloutSystem.
+ * The class needs to comply with the Interface Callout.
+ *
+ * For a limited time, the old notation of Sx_matheod / Ux_menthod is maintained.
+ *
+ * @param field field
+ * @return error message or ""
+ * @see org.compiere.model.Callout
+ */
+ private String processCallout (GridField field)
+ {
+ String callout = field.getCallout();
+ if (callout.length() == 0)
+ return "";
+ //
+ if (isProcessed()) // only active records
+ return ""; // "DocProcessed";
+
+ Object value = field.getValue();
+ Object oldValue = field.getOldValue();
+ log.fine(field.getColumnName() + "=" + value
+ + " (" + callout + ") - old=" + oldValue);
+
+ StringTokenizer st = new StringTokenizer(callout, ";,", false);
+ while (st.hasMoreTokens()) // for each callout
+ {
+ String cmd = st.nextToken().trim();
+ Callout call = null;
+ String method = null;
+ int methodStart = cmd.lastIndexOf(".");
+ try
+ {
+ if (methodStart != -1) // no class
+ {
+ Class cClass = Class.forName(cmd.substring(0,methodStart));
+ call = (Callout)cClass.newInstance();
+ method = cmd.substring(methodStart+1);
+ }
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "class", e);
+ return "Callout Invalid: " + cmd + " (" + e.toString() + ")";
+ }
+
+ if (call == null || method == null || method.length() == 0)
+ return "Callout Invalid: " + method;
+
+ String retValue = "";
+ try
+ {
+ retValue = call.start(m_vo.ctx, method, m_vo.WindowNo, this, field, value, oldValue);
+ }
+ catch (Exception e)
+ {
+ log.log(Level.SEVERE, "start", e);
+ retValue = "Callout Invalid: " + e.toString();
+ return retValue;
+ }
+ if (!retValue.equals("")) // interrupt on first error
+ {
+ log.severe (retValue);
+ return retValue;
+ }
+ } // for each callout
+ return "";
+ } // processCallout
+
+
+ /**
+ * Get Value of Field with columnName
+ * @param columnName column name
+ * @return value
+ */
+ public Object getValue (String columnName)
+ {
+ if (columnName == null)
+ return null;
+ GridField field = m_mTable.getField(columnName);
+ return getValue(field);
+ } // getValue
+
+ /**
+ * Get Value of Field
+ * @param field field
+ * @return value
+ */
+ public Object getValue (GridField field)
+ {
+ if (field == null)
+ return null;
+ return field.getValue();
+ } // getValue
+
+ /**
+ * Get Value of Field in row
+ * @param row row
+ * @param columnName column name
+ * @return value
+ */
+ public Object getValue (int row, String columnName)
+ {
+ int col = m_mTable.findColumn(columnName);
+ if (col == -1)
+ return null;
+ return m_mTable.getValueAt(row, col);
+ } // getValue
+
+ /**
+ * toString
+ * @return String representation
+ */
+ public String toString()
+ {
+ String retValue = "MTab #" + m_vo.TabNo;
+ if (m_vo != null)
+ retValue += " " + m_vo.Name + " (" + m_vo.AD_Tab_ID + ")";
+ return retValue;
+ } // toString
+
+
+ /**************************************************************************
+ * @param l listener
+ */
+ public synchronized void removePropertyChangeListener(PropertyChangeListener l)
+ {
+ m_propertyChangeSupport.removePropertyChangeListener(l);
+ }
+ /**
+ * @param l listener
+ */
+ public synchronized void addPropertyChangeListener(PropertyChangeListener l)
+ {
+ m_propertyChangeSupport.addPropertyChangeListener(l);
+ }
+
+ /**
+ * @param l listener
+ */
+ public synchronized void removeDataStatusListener(DataStatusListener l)
+ {
+ m_listenerList.remove(DataStatusListener.class, l);
+ }
+ /**
+ * @param l listener
+ */
+ public synchronized void addDataStatusListener(DataStatusListener l)
+ {
+ m_listenerList.add(DataStatusListener.class, l);
+ }
+
+} // MTab
diff --git a/base/src/org/compiere/model/GridTable.java b/base/src/org/compiere/model/GridTable.java
new file mode 100644
index 0000000000..70f8077149
--- /dev/null
+++ b/base/src/org/compiere/model/GridTable.java
@@ -0,0 +1,3076 @@
+/******************************************************************************
+ * 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.model;
+
+import java.beans.*;
+import java.io.*;
+import java.math.*;
+import java.sql.*;
+import java.util.*;
+import java.util.logging.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+
+import org.compiere.util.*;
+
+/**
+ * Grid Table Model for JDBC access including buffering.
+ *
+ * The following data types are handeled
+ * Integer for all IDs
+ * BigDecimal for all Numbers
+ * Timestamp for all Dates
+ * String for all others
+ * The data is read via r/o resultset and cached in m_buffer. Writes/updates
+ * are via dynamically constructed SQL INSERT/UPDATE statements. The record
+ * is re-read via the resultset to get results of triggers.
+ *
+ *
+ * The model maintains and fires the requires TableModelEvent changes,
+ * the DataChanged events (loading, changed, etc.)
+ * as well as Vetoable Change event "RowChange"
+ * (for row changes initiated by moving the row in the table grid).
+ *
+ * @author Jorg Janke
+ * @version $Id: GridTable.java,v 1.9 2006/08/09 16:38:25 jjanke Exp $
+ */
+public class GridTable extends AbstractTableModel
+ implements Serializable
+{
+ /**
+ * JDBC Based Buffered Table
+ *
+ * @param ctx Properties
+ * @param AD_Table_ID table id
+ * @param TableName table name
+ * @param WindowNo window no
+ * @param TabNo tab no
+ * @param withAccessControl if true adds AD_Client/Org restrictuins
+ */
+ public GridTable(Properties ctx, int AD_Table_ID, String TableName, int WindowNo, int TabNo,
+ boolean withAccessControl)
+ {
+ super();
+ log.info(TableName);
+ m_ctx = ctx;
+ m_AD_Table_ID = AD_Table_ID;
+ setTableName(TableName);
+ m_WindowNo = WindowNo;
+ m_TabNo = TabNo;
+ m_withAccessControl = withAccessControl;
+ } // MTable
+
+ private static CLogger log = CLogger.getCLogger(GridTable.class.getName());
+ private Properties m_ctx;
+ private int m_AD_Table_ID;
+ private String m_tableName = "";
+ private int m_WindowNo;
+ /** Tab No 0.. */
+ private int m_TabNo;
+ private boolean m_withAccessControl;
+ private boolean m_readOnly = true;
+ private boolean m_deleteable = true;
+ //
+
+ /** Rowcount */
+ private int m_rowCount = 0;
+ /** Has Data changed? */
+ private boolean m_changed = false;
+ /** Index of changed row via SetValueAt */
+ private int m_rowChanged = -1;
+ /** Insert mode active */
+ private boolean m_inserting = false;
+ /** Inserted Row number */
+ private int m_newRow = -1;
+ /** Is the Resultset open? */
+ private boolean m_open = false;
+ /** Compare to DB before save */
+ private boolean m_compareDB = true; // set to true after every save
+
+ // The buffer for all data
+ private volatile ArrayList