KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > compiere > acct > Doc


1 /******************************************************************************
2  * The contents of this file are subject to the Compiere License Version 1.1
3  * ("License"); You may not use this file except in compliance with the License
4  * You may obtain a copy of the License at http://www.compiere.org/license.html
5  * Software distributed under the License is distributed on an "AS IS" basis,
6  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
7  * the specific language governing rights and limitations under the License.
8  * The Original Code is Compiere ERP & CRM Business Solution
9  * The Initial Developer of the Original Code is Jorg Janke and ComPiere, Inc.
10  * Portions created by Jorg Janke are Copyright (C) 1999-2001 Jorg Janke, parts
11  * created by ComPiere are Copyright (C) ComPiere, Inc.; All Rights Reserved.
12  * Contributor(s): ______________________________________.
13  *****************************************************************************/

14 package org.compiere.acct;
15
16 import java.sql.*;
17 import java.math.*;
18 import java.util.*;
19
20 import org.apache.log4j.*;
21
22 import org.compiere.util.DB;
23 import org.compiere.util.Env;
24 import org.compiere.util.Msg;
25 import org.compiere.model.*;
26
27 /**
28  * Posting Document Root.
29  *
30  * <pre>
31  * Table Base Document Types (C_DocType.DocBaseType & AD_Reference_ID=183)
32  * Class AD_Table_ID
33  * ------------------ ------------------------------
34  * C_Invoice: ARI, ARC, ARF, API, APC
35  * Doc_Invoice 318 - has C_DocType_ID
36  *
37  * C_Payment: ARP, APP
38  * Doc_Payment 335 - has C_DocType_ID
39  *
40  * C_Order: SOO, POO, POR (Requisition)
41  * Doc_Order 259 - has C_DocType_ID
42  *
43  * M_InOut: MMS, MMR
44  * Doc_InOut 319 - DocType derived
45  *
46  * M_Inventory: MMI
47  * Doc_Inventory 321 - DocType fixed
48  *
49  * M_Movement: MMM
50  * Doc_Movement 323 - DocType fixed
51  *
52  * M_Production: MMP
53  * Doc_Production 325 - DocType fixed
54  *
55  * C_BankStatement: CMB
56  * Doc_Bank 392 - DocType fixed
57  *
58  * C_Cash: CMC
59  * Doc_Cash 407 - DocType fixed
60  *
61  * C_Allocation: CMA
62  * Doc_Allocation 390 - DocType fixed
63  *
64  * GL_Journal: GLJ
65  * Doc_GLJournal 224 = has C_DocType_ID
66  *
67  * Matching Invoice MXI
68  * M_MatchInv 472 - DocType fixed
69  *
70  * Matching PO MXP
71  * M_MatchPO 473 - DocType fixed
72  *
73  * Project Issue PJI
74  * C_ProjectIssue 623 - DocType fixed
75  *
76  * </pre>
77  * @author Jorg Janke
78  * @version $Id: Doc.java,v 1.29 2003/10/10 06:35:58 jjanke Exp $
79  */

80 public abstract class Doc
81 {
82     /** AD_Table_ID's of documents */
83     protected static int[] documents = new int[] {
84         318, // C_Invoice
85
390, // C_Allocation
86
407, // C_Cash
87
392, // C_BankStatement
88
259, // C_Order
89
335, // C_Payment
90
Doc_InOut.AD_TABLE_ID, // M_InOut
91
321, // M_Inventory
92
323, // M_Movement
93
325, // M_Production
94
224, // GL_Journal
95
472, // M_MatchInv
96
473, // M_MatchPO
97
Doc_ProjectIssue.AD_TABLE_ID // C_ProjectIssue
98
};
99
100
101     /**
102      * Factory - Create Posting document
103      *
104      * @param AD_Table_ID Table ID of Documents
105      * @param AD_Client_ID Client ID of Documents
106      * @return Document
107      */

108     protected static Doc get (int AD_Table_ID, int AD_Client_ID)
109     {
110         Doc doc = null;
111         switch (AD_Table_ID)
112         {
113             case 318:
114                 doc = new Doc_Invoice (AD_Client_ID);
115                 break;
116             case 390:
117                 doc = new Doc_Allocation (AD_Client_ID);
118                 break;
119             case 407:
120                 doc = new Doc_Cash (AD_Client_ID);
121                 break;
122             case 392:
123                 doc = new Doc_Bank (AD_Client_ID);
124                 break;
125             case 259:
126                 doc = new Doc_Order (AD_Client_ID);
127                 break;
128             case 335:
129                 doc = new Doc_Payment (AD_Client_ID);
130                 break;
131             case 319:
132                 doc = new Doc_InOut (AD_Client_ID);
133                 break;
134             case 321:
135                 doc = new Doc_Inventory (AD_Client_ID);
136                 break;
137             case 323:
138                 doc = new Doc_Movement (AD_Client_ID);
139                 break;
140             case 325:
141                 doc = new Doc_Production (AD_Client_ID);
142                 break;
143             case 224:
144                 doc = new Doc_GLJournal (AD_Client_ID);
145                 break;
146             case 472:
147                 doc = new Doc_MatchInv (AD_Client_ID);
148                 break;
149             case 473:
150                 doc = new Doc_MatchPO (AD_Client_ID);
151                 break;
152             case Doc_ProjectIssue.AD_TABLE_ID:
153                 doc = new Doc_ProjectIssue (AD_Client_ID);
154                 break;
155         }
156         if (doc == null)
157             s_log.error("get - Unknown AD_Table_ID=" + AD_Table_ID);
158         return doc;
159     } // get
160

161     /**
162      * Post Document
163      *
164      * @param AD_Table_ID Table ID of Document
165      * @param AD_Client_ID Client ID of Document
166      * @param Record_ID Record ID of this document
167      * @param force force posting
168      * @return true if the document was posted
169      */

170     protected static boolean post (int AD_Table_ID, int AD_Client_ID, int Record_ID, boolean force)
171     {
172         Doc doc = get (AD_Table_ID, AD_Client_ID);
173         if (doc != null)
174             return doc.post (Record_ID, force);
175         return false;
176     } // post
177

178     /** Connection for commits */
179     private static Connection s_connection = null;
180     /** Log */
181     protected Logger log = Logger.getLogger(getClass());
182     protected static Logger s_log = Logger.getLogger(Doc.class);
183
184     /**
185      * Return Serialized Connection for Commits (not AutoCommit)
186      * @return connection for posting
187      */

188     private static Connection getConnection ()
189     {
190         if (s_connection != null)
191         {
192             try
193             {
194                 if (!s_connection.isClosed())
195                     return s_connection;
196             }
197             catch (SQLException e)
198             {
199                 s_log.error("getConnection", e);
200             }
201         }
202         s_connection = DB.createConnection(false, Connection.TRANSACTION_SERIALIZABLE);
203         return s_connection;
204     } // getConnection
205

206     /*************************************************************************/
207
208     /**
209      * Cosntructor
210      * @param AD_Client_ID Client ID of these Documents
211      */

212     Doc (int AD_Client_ID)
213     {
214         log.info(getTableName() + ", Client=" + AD_Client_ID);
215         m_AD_Client_ID = AD_Client_ID;
216         m_as = AcctSchema.getAcctSchemaArray (AD_Client_ID);
217         p_vo = new DocVO (getAD_Table_ID());
218     } // Doc
219

220     /** Client for data access - there is also a document Client_ID (which should be the same) */
221     private int m_AD_Client_ID;
222     /** Accounting Schema Array */
223     private AcctSchema[] m_as = null;
224     /** Facts */
225     private Fact[] m_fact = null;
226
227     /** No Currency in Document Indicator */
228     protected static final int NO_CURRENCY = -1;
229
230     /** Document Value Object */
231     protected DocVO p_vo = null;
232
233     /** Contained Doc Lines */
234     protected DocLine[] p_lines = new DocLine[0];
235
236
237     /**
238      * Post Document.
239      * <pre>
240      * - try to lock document (Processed='Y' (AND Processing='N' AND Posted='N'))
241      * - if not ok - return false
242      * - read ResultSet
243      * - postlogic (for all Accounting Schema)
244      * - create Fact lines
245      * - postCommit
246      * - commits Fact lines and Document & sets Processing = 'N'
247      * - if error - create Note
248      * </pre>
249      * @param Record_ID ID of the record in the table
250      * @param force - if true, repost (ignore if already posted or locked)
251      * @return true if posted
252      */

253     public final boolean post (int Record_ID, boolean force)
254     {
255         boolean retValue = false;
256
257         // Lock Record ----
258
StringBuffer JavaDoc sql = new StringBuffer JavaDoc ("UPDATE ");
259         sql.append(getTableName()).append( " SET Processing='Y' WHERE ")
260             .append(getTableName()).append("_ID=").append(Record_ID)
261             .append(" AND Processed='Y'");
262         if (!force)
263             sql.append(" AND (Processing='N' OR Processing IS NULL) AND Posted='N'");
264         if (DB.executeUpdate(sql.toString()) != 1)
265         {
266             log.error("post - Cannot lock Document - ignored: " + getTableName() + "_ID=" + Record_ID);
267             return false;
268         }
269
270         // Get Record Info ----
271
sql = new StringBuffer JavaDoc ("SELECT * FROM ");
272         sql.append(getTableName())
273             .append(" WHERE AD_Client_ID=? AND ") // additional security
274
.append(getTableName()).append("_ID=?");
275         try
276         {
277             PreparedStatement pstmt = DB.prepareStatement(sql.toString());
278             pstmt.setInt(1, m_AD_Client_ID);
279             pstmt.setInt(2, Record_ID);
280             ResultSet rs = pstmt.executeQuery();
281             if (rs.next())
282                 retValue = post (rs, force); // ----
283
rs.close();
284             pstmt.close();
285         }
286         catch (SQLException e)
287         {
288             log.error("post", e);
289             retValue = false;
290         }
291         return retValue;
292     } // post
293

294     /*************************************************************************/
295
296     /**
297      * Post current Document in ResultSet.
298      * - Create Fact per Accounting Schema
299      * - Load Document
300      * - Post Commit
301      *
302      * @param rs Resultset with one row (SELECT * FROM documentTable)
303      * @param force if true delete existing accounting
304      * @return true if posted
305      */

306     private final boolean post (ResultSet rs, boolean force)
307     {
308     // log.info("post");
309
if (!loadDocument (rs, force))
310             return false;
311
312         // Create Fact per AcctSchema
313
m_fact = new Fact [m_as.length];
314
315         // for all Accounting Schema
316
boolean OK = true;
317         for (int i = 0; OK && i < m_as.length; i++)
318         {
319             p_vo.Status = postLogic (i);
320             if (!p_vo.Status.equals(DocVO.STATUS_Posted))
321                 OK = false;
322         }
323
324         // commitFact
325
p_vo.Status = postCommit (p_vo.Status);
326
327         // Create Note
328
if (!p_vo.Status.equals(DocVO.STATUS_Posted))
329         {
330             // Insert Note
331
String JavaDoc AD_Message = "PostingError-" + p_vo.Status;
332             // Refernce - Document
333
String JavaDoc Reference = toString();
334             // Reference
335
String JavaDoc cn = getClass().getName();
336             StringBuffer JavaDoc Text = new StringBuffer JavaDoc (Msg.getMsg(Env.getCtx(), AD_Message));
337             if (p_vo.Error != null)
338                 Text.append(" (").append(p_vo.Error).append(")");
339             Text.append(" - ").append(cn.substring(cn.lastIndexOf('.')))
340                 .append(" (").append(p_vo.DocumentType)
341                 .append(" - DocumentNo=").append(p_vo.DocumentNo)
342                 .append(", DateAcct=").append(p_vo.DateAcct.toString().substring(0,10))
343                 .append(", Amount=").append(getAmount())
344                 .append(", Sta=").append(p_vo.Status)
345                 .append(" - PeriodOpen=").append(isPeriodOpen())
346                 .append(", Balanced=").append(isBalanced());
347             int AD_User_ID = 0;
348             DB.insertNote(p_vo.AD_Client_ID, p_vo.AD_Org_ID, AD_User_ID,
349                 getAD_Table_ID(), p_vo.Record_ID, AD_Message, Text.toString(), Reference);
350         // new MNote ().save();
351
}
352
353         // dispose facts
354
for (int i = 0; i < m_fact.length; i++)
355             if (m_fact[i] != null)
356                 m_fact[i].dispose();
357         p_lines = null;
358
359         return p_vo.Status.equals(DocVO.STATUS_Posted);
360     } // post
361

362
363     /**
364      * Posting logic for Accounting Schema index
365      * @param index Accounting Schema index
366      * @return posting status/error code
367      */

368     private final String JavaDoc postLogic (int index)
369     {
370         // rejectUnbalanced
371
if (!m_as[index].isSuspenseBalancing() && !isBalanced())
372             return DocVO.STATUS_NotBalanced;
373
374         // rejectUnconvertible
375
if (!isConvertible(m_as[index]))
376             return DocVO.STATUS_NotConvertible;
377
378         // rejectPeriodClosed
379
if (!isPeriodOpen())
380             return DocVO.STATUS_PeriodClosed;
381
382         // createFacts
383
m_fact[index] = createFact (m_as[index]);
384         if (m_fact[index] == null)
385             return DocVO.STATUS_Error;
386         p_vo.Status = DocVO.STATUS_PostPrepared;
387
388         // balanceSource
389
if (!m_fact[index].isSourceBalanced())
390             m_fact[index].balanceSource();
391
392         // balanceSegments
393
if (!m_fact[index].isSegmentBalanced())
394             m_fact[index].balanceSegments();
395
396         // balanceAccounting
397
if (!m_fact[index].isAcctBalanced())
398             m_fact[index].balanceAccounting();
399
400         return DocVO.STATUS_Posted;
401     } // postLogic
402

403     /**
404      * Post Commit.
405      * Save Facts & Document
406      * @param status status
407      * @return Posting Status
408      */

409     private final String JavaDoc postCommit (String JavaDoc status)
410     {
411         log.info("postCommit Sta=" + status + " DT=" + p_vo.DocumentType + " ID=" + p_vo.Record_ID);
412         p_vo.Status = status;
413
414         Connection con = getConnection();
415         try
416         {
417         // *** Transaction Start ***
418
// Commit Facts
419
if (status.equals(DocVO.STATUS_Posted))
420             {
421                 for (int i = 0; i < m_fact.length; i++)
422                 {
423                     if (m_fact[i] != null && m_fact[i].save(con))
424                         ;
425                     else
426                     {
427                         con.rollback();
428                         unlock();
429                         return DocVO.STATUS_Error;
430                     }
431                 }
432             }
433             // Commit Doc
434
if (!save(con)) // contains unlock
435
{
436                 con.rollback();
437                 unlock();
438                 return DocVO.STATUS_Error;
439             }
440             con.commit();
441         // *** Transaction End ***
442
}
443         catch (Exception JavaDoc e)
444         {
445             log.error("postCommit", e);
446             status = DocVO.STATUS_Error;
447             try
448             {
449                 con.rollback();
450             }
451             catch (SQLException e2)
452             {
453             }
454             unlock();
455         }
456         return status;
457     } // postCommit
458

459     /**
460      * Unlock Document
461      */

462     private void unlock()
463     {
464         StringBuffer JavaDoc sql = new StringBuffer JavaDoc ("UPDATE ");
465         sql.append(getTableName()).append( " SET Processing='N' WHERE ")
466             .append(getTableName()).append("_ID=").append(p_vo.Record_ID);
467         DB.executeUpdate(sql.toString());
468     } // unlock
469

470     /*************************************************************************/
471     // General Document Methods
472

473     /**
474      * Load Generic Document Information and then document specific info.
475      *
476      * @param rs document to load from current record (SELECT * FROM documentTable)
477      * @param force if true delete existing accounting
478      * @return true if document loaded correctly
479      */

480     private boolean loadDocument (ResultSet rs, boolean force)
481     {
482         log.debug("loadDocument - " + getTableName());
483
484         p_vo.Status = DocVO.STATUS_Error;
485         String JavaDoc Name = null;
486
487         try
488         {
489             String JavaDoc key = getTableName() + "_ID";
490             ResultSetMetaData rsmd = rs.getMetaData();
491             for (int i = 1; i <= rsmd.getColumnCount(); i++)
492             {
493                 String JavaDoc col = rsmd.getColumnName(i);
494                 if (col.equalsIgnoreCase(key))
495                     p_vo.Record_ID = rs.getInt(i);
496                 else if (col.equalsIgnoreCase("AD_Client_ID"))
497                     p_vo.AD_Client_ID = rs.getInt(i);
498                 else if (col.equalsIgnoreCase("AD_Org_ID"))
499                     p_vo.AD_Org_ID = rs.getInt(i);
500                 else if (col.equalsIgnoreCase("C_BPartner_ID"))
501                     p_vo.C_BPartner_ID = rs.getInt(i);
502                 else if (col.equalsIgnoreCase("C_BPartner_Location_ID"))
503                     p_vo.C_BPartner_Location_ID = rs.getInt(i);
504                 else if (col.equalsIgnoreCase("M_Product_ID"))
505                     p_vo.M_Product_ID = rs.getInt(i);
506                 else if (col.equalsIgnoreCase("AD_OrgTrx_ID"))
507                     p_vo.AD_OrgTrx_ID = rs.getInt(i);
508                 else if (col.equalsIgnoreCase("C_SalesRegion_ID"))
509                     p_vo.C_SalesRegion_ID = rs.getInt(i);
510                 else if (col.equalsIgnoreCase("C_Project_ID"))
511                     p_vo.C_Project_ID = rs.getInt(i);
512                 else if (col.equalsIgnoreCase("C_Campaign_ID"))
513                     p_vo.C_Campaign_ID = rs.getInt(i);
514                 else if (col.equalsIgnoreCase("C_Activity_ID"))
515                     p_vo.C_Activity_ID = rs.getInt(i);
516                 else if (col.equalsIgnoreCase("C_LocFrom_ID"))
517                     p_vo.C_LocFrom_ID = rs.getInt(i);
518                 else if (col.equalsIgnoreCase("C_LocTo_ID"))
519                     p_vo.C_LocTo_ID = rs.getInt(i);
520                 else if (col.equalsIgnoreCase("User1_ID"))
521                     p_vo.User1_ID = rs.getInt(i);
522                 else if (col.equalsIgnoreCase("User2_ID"))
523                     p_vo.User2_ID = rs.getInt(i);
524                 //
525
else if (col.equalsIgnoreCase("DocumentNo"))
526                     p_vo.DocumentNo = rs.getString(i);
527                 else if (col.equalsIgnoreCase("Name"))
528                     Name = rs.getString(i);
529                 else if (col.equalsIgnoreCase("DateAcct"))
530                     p_vo.DateAcct = rs.getTimestamp(i);
531                 else if (col.equalsIgnoreCase("DateDoc"))
532                     p_vo.DateDoc = rs.getTimestamp(i);
533                 else if (col.equalsIgnoreCase("C_Period_ID"))
534                     p_vo.C_Period_ID = rs.getInt(i);
535                 //
536
else if (col.equalsIgnoreCase("C_Currency_ID"))
537                     p_vo.C_Currency_ID = rs.getInt(i);
538                 //
539
else if (col.equalsIgnoreCase("C_DocType_ID"))
540                     p_vo.C_DocType_ID = rs.getInt(i);
541                 // Special Document Fields
542
else if (col.equalsIgnoreCase("C_Charge_ID"))
543                     p_vo.C_Charge_ID = rs.getInt(i);
544                 else if (col.equalsIgnoreCase("ChargeAmt"))
545                     p_vo.ChargeAmt = rs.getBigDecimal(i);
546                 else if (col.equalsIgnoreCase("C_BankAccount_ID"))
547                     p_vo.C_BankAccount_ID = rs.getInt(i);
548                 else if (col.equalsIgnoreCase("M_Warehouse_ID"))
549                     p_vo.M_Warehouse_ID = rs.getInt(i);
550                 //
551
else if (col.equalsIgnoreCase("Posted"))
552                     p_vo.Posted = "Y".equals(rs.getString(i));
553             } // for all columns
554
p_vo.Status = DocVO.STATUS_NotPosted;
555         }
556         catch (SQLException e)
557         {
558             log.error("loadDocument", e);
559         }
560
561         // Call Document Specific Info
562
if (!loadDocumentDetails (rs))
563             loadDocumentType();
564
565         // Fill Acct/Trx Date
566
if (p_vo.DateAcct == null & p_vo.DateDoc != null)
567             p_vo.DateAcct = p_vo.DateDoc;
568         else if (p_vo.DateDoc == null & p_vo.DateAcct != null)
569             p_vo.DateDoc = p_vo.DateAcct;
570         // DocumentNo (or Name)
571
if (p_vo.DocumentNo == null || p_vo.DocumentNo.length() == 0)
572             p_vo.DocumentNo = Name;
573         if (p_vo.DocumentNo == null || p_vo.DocumentNo.length() == 0)
574             p_vo.DocumentNo = "";
575
576         // Check Mandatory Info
577
String JavaDoc error = "";
578         if (p_vo.AD_Table_ID == 0)
579             error += " AD_Table_ID";
580         if (p_vo.Record_ID == 0)
581             error += " Record_ID";
582         if (p_vo.AD_Client_ID == 0)
583             error += " AD_Client_ID";
584         if (p_vo.AD_Org_ID == 0)
585             error += " AD_Org_ID";
586         if (p_vo.C_Currency_ID == 0)
587             error += " C_Currency_ID";
588         if (p_vo.DateAcct == null)
589             error += " DateAcct";
590         if (p_vo.DateDoc == null)
591             error += " DateDoc";
592         if (error.length() > 0)
593         {
594             log.error("loadDocument - " + toString() + " - Mandatory info missing: " + error);
595             return false;
596         }
597
598         // Delete existing Accounting
599
if (force)
600         {
601             if (p_vo.Posted && !isPeriodOpen()) // already posted - don't delete if period closed
602
{
603                 log.error("loadDocument - " + toString() + " - Period Closed for already posed document");
604                 return false;
605             }
606
607             // delete it
608
StringBuffer JavaDoc sql = new StringBuffer JavaDoc ("DELETE Fact_Acct "
609                 + "WHERE AD_Table_ID=");
610             sql.append(getAD_Table_ID()).append(" AND Record_ID=").append(p_vo.Record_ID);
611             int no = DB.executeUpdate(sql.toString());
612             log.info("post - deleted=" + no);
613         }
614         else if (p_vo.Posted)
615         {
616             log.error("loadDocument - " + toString() + " - Document already posted");
617             return false;
618         }
619         return true;
620     } // loadDocument
621

622     /**
623      * Load Document Type and GL Info
624      */

625     protected void loadDocumentType()
626     {
627         // No Document Type defined
628
if (p_vo.DocumentType == null && p_vo.C_DocType_ID != 0)
629         {
630             String JavaDoc sql = "SELECT DocBaseType, GL_Category_ID FROM C_DocType WHERE C_DocType_ID=?";
631             try
632             {
633                 PreparedStatement pstmt = DB.prepareStatement(sql);
634                 pstmt.setInt(1, p_vo.C_DocType_ID);
635                 ResultSet rsDT = pstmt.executeQuery();
636                 if (rsDT.next())
637                 {
638                     p_vo.DocumentType = rsDT.getString(1);
639                     p_vo.GL_Category_ID = rsDT.getInt(2);
640                 }
641                 rsDT.close();
642                 pstmt.close();
643             }
644             catch (SQLException e)
645             {
646                 log.error("loadDocumentType-1", e);
647             }
648         }
649
650         // We have a document Type, but no GL info - search for DocType
651
if (p_vo.GL_Category_ID == 0)
652         {
653             String JavaDoc sql = "SELECT GL_Category_ID FROM C_DocType "
654                 + "WHERE AD_Client_ID=? AND DocBaseType=?";
655             try
656             {
657                 PreparedStatement pstmt = DB.prepareStatement(sql);
658                 pstmt.setInt(1, p_vo.AD_Client_ID);
659                 pstmt.setString(2, p_vo.DocumentType);
660                 ResultSet rsDT = pstmt.executeQuery();
661                 if (rsDT.next())
662                     p_vo.GL_Category_ID = rsDT.getInt(1);
663                 rsDT.close();
664                 pstmt.close();
665             }
666             catch (SQLException e)
667             {
668                 log.error("loadDocumentType-2", e);
669             }
670         }
671
672         if (p_vo.DocumentType == null)
673             log.error("loadDocumentType - No DocType for GL Info - " + toString());
674
675         // Still no GL_Category - get Default GL Category
676
if (p_vo.GL_Category_ID == 0)
677         {
678             String JavaDoc sql = "SELECT GL_Category_ID FROM GL_Category "
679                 + "WHERE AD_Client_ID=? "
680                 + "ORDER BY IsDefault DESC";
681             try
682             {
683                 PreparedStatement pstmt = DB.prepareStatement(sql);
684                 pstmt.setInt(1, p_vo.AD_Client_ID);
685                 ResultSet rsDT = pstmt.executeQuery();
686                 if (rsDT.next())
687                     p_vo.GL_Category_ID = rsDT.getInt(1);
688                 rsDT.close();
689                 pstmt.close();
690             }
691             catch (SQLException e)
692             {
693                 log.error("loadDocumentType-3", e);
694             }
695         }
696         if (p_vo.GL_Category_ID == 0)
697             log.error("loadDocumentType - No GL_Category - " + toString());
698
699         // Budget
700
p_vo.GL_Budget_ID = 0;
701     } // loadDocumentType
702

703     /*************************************************************************/
704
705     /**
706      * Is the Source Document Balanced
707      * @return true if (source) baanced
708      */

709     public boolean isBalanced()
710     {
711         // Multi-Currency documents are source balanced by definition
712
if (p_vo.MultiCurrency)
713             return true;
714         //
715
boolean retValue = getBalance().compareTo(Env.ZERO) == 0;
716         if (retValue)
717             log.debug("isBalanced - " + p_vo.toString());
718         else
719             log.warn("isBalanced NO - " + p_vo.toString());
720         return retValue;
721     } // isBalanced
722

723     /**
724      * Is Document convertible to currency and Conversion Type
725      * @param acctSchema accounting schema
726      * @return true, if vonvertable to accounting currency
727      */

728     public boolean isConvertible (AcctSchema acctSchema)
729     {
730         // No Currency in document
731
if (p_vo.C_Currency_ID == NO_CURRENCY)
732         {
733             log.debug ("isConvertible (none) - " + p_vo.toString());
734             return true;
735         }
736         // Get All Currencies
737
HashSet set = new HashSet();
738         set.add(new Integer JavaDoc(p_vo.C_Currency_ID));
739         for (int i = 0; p_lines != null && i < p_lines.length; i++)
740         {
741             int currency = p_lines[i].getC_Currency_ID();
742             set.add(new Integer JavaDoc(currency));
743         }
744
745         // just one and the same
746
if (set.size() == 1 && acctSchema.getC_Currency_ID() == p_vo.C_Currency_ID)
747         {
748             log.debug ("isConvertible (same) Cur=" + p_vo.C_Currency_ID + " - " + p_vo.toString());
749             return true;
750         }
751
752         boolean convertible = true;
753         Iterator it = set.iterator();
754         while (it.hasNext() && convertible)
755         {
756             int currency = ((Integer JavaDoc)it.next()).intValue();
757             if (currency != acctSchema.getC_Currency_ID())
758             {
759                 BigDecimal amt = DB.getConvertedAmt(new BigDecimal(1.0), currency, acctSchema.getC_Currency_ID(),
760                     p_vo.DateAcct, acctSchema.getCurrencyRateType(), p_vo.AD_Client_ID, p_vo.AD_Org_ID);
761                 if (amt == null)
762                 {
763                     convertible = false;
764                     log.warn ("isConvertible NOT from " + currency + " - " + p_vo.toString());
765                 }
766                 else
767                     log.debug ("isConvertible from " + currency);
768             }
769         }
770
771         log.debug ("isConvertible=" + convertible + ", AcctSchemaCur=" + acctSchema.getC_Currency_ID() + " - " + p_vo.toString());
772         return convertible;
773     } // isConvertible
774

775
776     /**
777      * Calculate Period ID.
778      * Set to -1 if no period open, 0 if no period control
779      */

780     public void setC_Period_ID()
781     {
782         if (p_vo.C_Period_ID != DocVO.PERIOD_UNDEFINED)
783             return;
784         //
785
try
786         {
787             CallableStatement cstmt = DB.prepareCall("{? = call GL_Period_Open(?,?,?,?)}");
788             //
789
cstmt.registerOutParameter(1, Types.INTEGER); // C_Period_ID
790
cstmt.setInt(2, p_vo.AD_Client_ID);
791             cstmt.setTimestamp(3, p_vo.DateAcct);
792             cstmt.setString(4, p_vo.DocumentType);
793             cstmt.setNull(5, Types.INTEGER); // C_AcctSchema_ID
794
//
795
cstmt.execute();
796             p_vo.C_Period_ID = cstmt.getInt(1);
797             cstmt.close();
798         }
799         catch (SQLException e)
800         {
801             log.error ("getC_Period_ID", e);
802         }
803         log.debug ("setC_Period_ID - "
804             + p_vo.AD_Client_ID + " - " + p_vo.DateAcct + " - " + p_vo.DocumentType + " => " + p_vo.C_Period_ID);
805     } // setC_Period_ID
806

807     /**
808      * Is Period Open
809      * @return true if period is open
810      */

811     public boolean isPeriodOpen()
812     {
813         setC_Period_ID();
814         boolean open = p_vo.C_Period_ID != -1;
815         if (open)
816             log.debug("isPeriodOpen - " + p_vo.toString());
817         else
818             log.warn("isPeriodOpen NO - " + p_vo.toString());
819         return open;
820     } // isPeriodOpen
821

822     /*************************************************************************/
823
824     /** Amount Type - Invoice */
825     public static final int AMTTYPE_Gross = 0;
826     public static final int AMTTYPE_Net = 1;
827     public static final int AMTTYPE_Charge = 2;
828     /** Amount Type - Allocation */
829     public static final int AMTTYPE_Invoice = 0;
830     public static final int AMTTYPE_Allocation = 1;
831     public static final int AMTTYPE_Discount = 2;
832     public static final int AMTTYPE_WriteOff = 3;
833
834     /**
835      * Get the Amount
836      * (loaded in loadDocumentDetails)
837      *
838      * @param AmtType see AMTTYPE_*
839      * @return Amount
840      */

841     public BigDecimal getAmount(int AmtType)
842     {
843         if (AmtType < 0 || AmtType >= p_vo.Amounts.length)
844             return null;
845         return p_vo.Amounts[AmtType];
846     } // getAmount
847

848     /**
849      * Get Amount with index 0
850      * @return Amount (primary document amount)
851      */

852     public BigDecimal getAmount()
853     {
854         return p_vo.Amounts[0];
855     } // getAmount
856

857     /*************************************************************************/
858
859     /** Account Type - Invoice */
860     public static final int ACCTTYPE_Charge = 0;
861     public static final int ACCTTYPE_C_Receivable = 1;
862     public static final int ACCTTYPE_V_Liability = 2;
863     public static final int ACCTTYPE_V_Liability_Services = 3;
864
865     /** Account Type - Payment */
866     public static final int ACCTTYPE_UnallocatedCash = 10;
867     public static final int ACCTTYPE_BankInTransit = 11;
868     public static final int ACCTTYPE_PaymentSelect = 12;
869
870     /** Account Type - Cash */
871     public static final int ACCTTYPE_CashAsset = 20;
872     public static final int ACCTTYPE_CashTransfer = 21;
873     public static final int ACCTTYPE_CashExpense = 22;
874     public static final int ACCTTYPE_CashReceipt = 23;
875     public static final int ACCTTYPE_CashDifference = 24;
876
877     /** Account Type - Allocation */
878     public static final int ACCTTYPE_DiscountExp = 30;
879     public static final int ACCTTYPE_DiscountRev = 31;
880     public static final int ACCTTYPE_WriteOff = 32;
881
882     /** Account Type - Bank Statement */
883     public static final int ACCTTYPE_BankAsset = 40;
884     public static final int ACCTTYPE_InterestRev = 41;
885     public static final int ACCTTYPE_InterestExp = 42;
886
887     /** Inventory Accounts */
888     public static final int ACCTTYPE_InvDifferences = 50;
889     public static final int ACCTTYPE_NotInvoicedReceipts = 51;
890
891     /** Project Accounts */
892     public static final int ACCTTYPE_ProjectAsset = 61;
893     public static final int ACCTTYPE_ProjectWIP = 62;
894
895     /** GL Accounts */
896     public static final int ACCTTYPE_PPVOffset = 101;
897
898
899     /**
900      * Get the account for Accounting Schema
901      * @param AcctType see ACCTTYPE_*
902      * @param as accounting schema
903      * @return Account
904      */

905     public final Account getAccount (int AcctType, AcctSchema as)
906     {
907         int para_1 = 0; // first parameter (second is always AcctSchema)
908
String JavaDoc sql = null;
909
910         /** Account Type - Invoice */
911         if (AcctType == ACCTTYPE_Charge) // see getChargeAccount in DocLine
912
{
913             int cmp = getAmount(AMTTYPE_Charge).compareTo(Env.ZERO);
914             if (cmp == 0)
915                 return null;
916             else if (cmp < 0)
917                 sql = "SELECT CH_Expense_Acct FROM C_Charge_Acct WHERE C_Charge_ID=? AND C_AcctSchema_ID=?";
918             else
919                 sql = "SELECT CH_Revenue_Acct FROM C_Charge_Acct WHERE C_Charge_ID=? AND C_AcctSchema_ID=?";
920             para_1 = p_vo.C_Charge_ID;
921         }
922         else if (AcctType == ACCTTYPE_V_Liability)
923         {
924             sql = "SELECT V_Liability_Acct FROM C_BP_Vendor_Acct WHERE C_BPartner_ID=? AND C_AcctSchema_ID=?";
925             para_1 = p_vo.C_BPartner_ID;
926         }
927         else if (AcctType == ACCTTYPE_V_Liability_Services)
928         {
929             sql = "SELECT V_Liability_Services_Acct FROM C_BP_Vendor_Acct WHERE C_BPartner_ID=? AND C_AcctSchema_ID=?";
930             para_1 = p_vo.C_BPartner_ID;
931         }
932         else if (AcctType == ACCTTYPE_C_Receivable)
933         {
934             sql = "SELECT C_Receivable_Acct FROM C_BP_Customer_Acct WHERE C_BPartner_ID=? AND C_AcctSchema_ID=?";
935             para_1 = p_vo.C_BPartner_ID;
936         }
937
938         /** Account Type - Payment */
939         else if (AcctType == ACCTTYPE_UnallocatedCash)
940         {
941             sql = "SELECT B_UnallocatedCash_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
942             para_1 = p_vo.C_BankAccount_ID;
943         }
944         else if (AcctType == ACCTTYPE_BankInTransit)
945         {
946             sql = "SELECT B_InTransit_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
947             para_1 = p_vo.C_BankAccount_ID;
948         }
949         else if (AcctType == ACCTTYPE_PaymentSelect)
950         {
951             sql = "SELECT B_PaymentSelect_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
952             para_1 = p_vo.C_BankAccount_ID;
953         }
954         /** Account Type - Allocation */
955         else if (AcctType == ACCTTYPE_DiscountExp)
956         {
957             sql = "SELECT a.PayDiscount_Exp_Acct FROM C_BP_Group_Acct a, C_BPartner bp "
958                 + "WHERE a.C_BP_Group_ID=bp.C_BP_Group_ID AND bp.C_BPartner_ID=? AND a.C_AcctSchema_ID=?";
959             para_1 = p_vo.C_BPartner_ID;
960         }
961         else if (AcctType == ACCTTYPE_DiscountRev)
962         {
963             sql = "SELECT PayDiscount_Rev_Acct FROM C_BP_Group_Acct a, C_BPartner bp "
964                 + "WHERE a.C_BP_Group_ID=bp.C_BP_Group_ID AND bp.C_BPartner_ID=? AND a.C_AcctSchema_ID=?";
965             para_1 = p_vo.C_BPartner_ID;
966         }
967         else if (AcctType == ACCTTYPE_WriteOff)
968         {
969             sql = "SELECT WriteOff_Acct FROM C_BP_Group_Acct a, C_BPartner bp "
970                 + "WHERE a.C_BP_Group_ID=bp.C_BP_Group_ID AND bp.C_BPartner_ID=? AND a.C_AcctSchema_ID=?";
971             para_1 = p_vo.C_BPartner_ID;
972         }
973
974         /** Account Type - Bank Statement */
975         else if (AcctType == ACCTTYPE_BankAsset)
976         {
977             sql = "SELECT B_Asset_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
978             para_1 = p_vo.C_BankAccount_ID;
979         }
980         else if (AcctType == ACCTTYPE_InterestRev)
981         {
982             sql = "SELECT B_InterestRev_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
983             para_1 = p_vo.C_BankAccount_ID;
984         }
985         else if (AcctType == ACCTTYPE_InterestExp)
986         {
987             sql = "SELECT B_InterestExp_Acct FROM C_BankAccount_Acct WHERE C_BankAccount_ID=? AND C_AcctSchema_ID=?";
988             para_1 = p_vo.C_BankAccount_ID;
989         }
990
991         /** Account Type - Cash */
992         else if (AcctType == ACCTTYPE_CashAsset)
993         {
994             sql = "SELECT CB_Asset_Acct FROM C_CashBook_Acct WHERE C_CashBook_ID=? AND C_AcctSchema_ID=?";
995             para_1 = p_vo.C_CashBook_ID;
996         }
997         else if (AcctType == ACCTTYPE_CashTransfer)
998         {
999             sql = "SELECT CB_CashTransfer_Acct FROM C_CashBook_Acct WHERE C_CashBook_ID=? AND C_AcctSchema_ID=?";
1000            para_1 = p_vo.C_CashBook_ID;
1001        }
1002        else if (AcctType == ACCTTYPE_CashExpense)
1003        {
1004            sql = "SELECT CB_Expense_Acct FROM C_CashBook_Acct WHERE C_CashBook_ID=? AND C_AcctSchema_ID=?";
1005            para_1 = p_vo.C_CashBook_ID;
1006        }
1007        else if (AcctType == ACCTTYPE_CashReceipt)
1008        {
1009            sql = "SELECT CB_Receipt_Acct FROM C_CashBook_Acct WHERE C_CashBook_ID=? AND C_AcctSchema_ID=?";
1010            para_1 = p_vo.C_CashBook_ID;
1011        }
1012        else if (AcctType == ACCTTYPE_CashDifference)
1013        {
1014            sql = "SELECT CB_Differences_Acct FROM C_CashBook_Acct WHERE C_CashBook_ID=? AND C_AcctSchema_ID=?";
1015            para_1 = p_vo.C_CashBook_ID;
1016        }
1017
1018        /** Inventory Accounts */
1019        else if (AcctType == ACCTTYPE_InvDifferences)
1020        {
1021            sql = "SELECT W_Differences_Acct FROM M_Warehouse_Acct WHERE M_Warehouse_ID=? AND C_AcctSchema_ID=?";
1022            // "SELECT W_Inventory_Acct, W_Revaluation_Acct, W_InvActualAdjust_Acct FROM M_Warehouse_Acct WHERE M_Warehouse_ID=? AND C_AcctSchema_ID=?";
1023
para_1 = p_vo.M_Warehouse_ID;
1024        }
1025        else if (AcctType == ACCTTYPE_NotInvoicedReceipts)
1026        {
1027            sql = "SELECT NotInvoicedReceipts_Acct FROM C_BP_Group_Acct a, C_BPartner bp "
1028                + "WHERE a.C_BP_Group_ID=bp.C_BP_Group_ID AND bp.C_BPartner_ID=? AND a.C_AcctSchema_ID=?";
1029            para_1 = p_vo.C_BPartner_ID;
1030        }
1031
1032        /** Project Accounts */
1033        else if (AcctType == ACCTTYPE_ProjectAsset)
1034        {
1035            sql = "SELECT PJ_Asset_Acct FROM C_Project_Acct WHERE C_Project_ID=? AND C_AcctSchema_ID=?";
1036            para_1 = p_vo.C_Project_ID;
1037        }
1038        else if (AcctType == ACCTTYPE_ProjectWIP)
1039        {
1040            sql = "SELECT PJ_WIP_Acct FROM C_Project_Acct WHERE C_Project_ID=? AND C_AcctSchema_ID=?";
1041            para_1 = p_vo.C_Project_ID;
1042        }
1043
1044        /** GL Accounts */
1045        else if (AcctType == ACCTTYPE_PPVOffset)
1046        {
1047            sql = "SELECT PPVOffset_Acct FROM C_AcctSchema_GL WHERE C_AcctSchema_ID=?";
1048            para_1 = -1;
1049        }
1050
1051        else
1052        {
1053            log.error ("getAccount - Not found AcctType=" + AcctType);
1054            return null;
1055        }
1056        // Do we have sql & Parameter
1057
if (sql == null || para_1 == 0)
1058        {
1059            log.error ("getAccount - No Parameter for AcctType=" + AcctType + " - SQL=" + sql);
1060            return null;
1061        }
1062
1063        // Get Acct
1064
int Account_ID = 0;
1065        try
1066        {
1067            PreparedStatement pstmt = DB.prepareStatement(sql);
1068            if (para_1 == -1) // GL Accounts
1069
pstmt.setInt (1, as.getC_AcctSchema_ID());
1070            else
1071            {
1072                pstmt.setInt (1, para_1);
1073                pstmt.setInt (2, as.getC_AcctSchema_ID());
1074            }
1075            ResultSet rs = pstmt.executeQuery();
1076            if (rs.next())
1077                Account_ID = rs.getInt(1);
1078            rs.close();
1079            pstmt.close();
1080        }
1081        catch (SQLException e)
1082        {
1083            log.error ("getAccount - AcctType=" + AcctType + " - SQL=" + sql, e);
1084            return null;
1085        }
1086        // No account
1087
if (Account_ID == 0)
1088        {
1089            log.error ("getAccount - NO account Type="
1090                + AcctType + ", Record=" + p_vo.Record_ID);
1091            return null;
1092        }
1093
1094        // Return Account
1095
Account acct = Account.getAccount (Account_ID);
1096        return acct;
1097    } // getAccount
1098

1099    /*************************************************************************/
1100
1101    /**
1102     * Save to Disk - set posted flag
1103     * @param con connection
1104     * @return true if saved
1105     */

1106    private final boolean save (Connection con)
1107    {
1108        log.debug ("save - " + toString() + "->" + p_vo.Status);
1109
1110        StringBuffer JavaDoc sql = new StringBuffer JavaDoc("UPDATE ");
1111        sql.append(getTableName()).append(" SET Posted='").append(p_vo.Status).append("',Processing='N' ")
1112            .append("WHERE ").append(getTableName()).append("_ID=").append(p_vo.Record_ID);
1113        int no = 0;
1114        try
1115        {
1116            Statement stmt = con.createStatement();
1117            no = stmt.executeUpdate(sql.toString());
1118            stmt.close();
1119        }
1120        catch (SQLException e)
1121        {
1122            log.error ("save", e);
1123            no = 0;
1124        }
1125        return no == 1;
1126    } // save
1127

1128    /**
1129     * Get DocLine with ID
1130     * @param Record_ID Record ID
1131     * @return DocLine
1132     */

1133    public DocLine getDocLine (int Record_ID)
1134    {
1135        if (p_lines.length == 0 || Record_ID == 0)
1136            return null;
1137
1138        for (int i = 0; i < p_lines.length; i++)
1139        {
1140            if (p_lines[i].getTrxLine_ID() == Record_ID)
1141                return p_lines[i];
1142        }
1143        return null;
1144    } // getDocLine
1145

1146    /**
1147     * String Representation
1148     * @return String
1149     */

1150    public String JavaDoc toString()
1151    {
1152        if (p_vo == null)
1153            return "Doc";
1154        return p_vo.toString();
1155    } // toString
1156

1157    /*************************************************************************/
1158    // To be overwritten by Subclasses
1159

1160    /**
1161     * Return TableName of Document
1162     * @return Table Name
1163     */

1164    public abstract String JavaDoc getTableName();
1165
1166    /**
1167     * Get Document Table ID
1168     * @return AD_Table_ID
1169     */

1170    public abstract int getAD_Table_ID();
1171
1172    /**
1173     * Load Specific Document Details
1174     * @param rs result set
1175     * @return true if loadDocumentType was set
1176     */

1177    protected abstract boolean loadDocumentDetails (ResultSet rs);
1178
1179    /**
1180     * Get Source Currency Balance - subtracts line (and tax) amounts from total - no rounding
1181     * @return positive amount, if total header is bigger than lines
1182     */

1183    public abstract BigDecimal getBalance();
1184
1185    /**
1186     * Create Facts (the accounting logic)
1187     * @param as accounting schema
1188     * @return Fact
1189     */

1190    public abstract Fact createFact (AcctSchema as);
1191
1192} // Doc
1193
Popular Tags