keys = map.keySet().iterator();
while (keys.hasNext())
{
Integer key = keys.next();
Balance difference = map.get(key);
if (log.isLoggable(Level.INFO)) log.info (elementType + "=" + key + ", " + difference);
//
if (!difference.isZeroBalance())
{
// Create Balancing Entry
FactLine line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(),
m_doc.get_ID(), 0, m_trxName);
line.setDocumentInfo(m_doc, null);
line.setPostingType(m_postingType);
// Amount & Account
if (difference.getBalance().signum() < 0)
{
if (difference.isReversal())
{
line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType));
line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance());
}
else
{
line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType));
line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO);
}
}
else
{
if (difference.isReversal())
{
line.setAccount(m_acctSchema, m_acctSchema.getDueFrom_Acct(elementType));
line.setAmtSource(m_doc.getC_Currency_ID(), difference.getPostBalance(), Env.ZERO);
}
else
{
line.setAccount(m_acctSchema, m_acctSchema.getDueTo_Acct(elementType));
line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, difference.getPostBalance());
}
}
line.convert();
line.setAD_Org_ID(key.intValue());
//
m_lines.add(line);
if (log.isLoggable(Level.FINE)) log.fine("(" + elementType + ") - " + line);
}
}
map.clear();
}
} // balanceSegment
/**
* Are the lines Accounting Balanced
* @return true if accounting lines are balanced
*/
public boolean isAcctBalanced()
{
// no lines -> balanced
if (m_lines.size() == 0)
return true;
BigDecimal balance = getAcctBalance();
boolean retValue = balance.signum() == 0;
if (retValue) {
if (log.isLoggable(Level.FINER)) log.finer(toString());
} else {
log.warning("NO - Diff=" + balance + " - " + toString());
}
return retValue;
} // isAcctBalanced
/**
* Return Accounting Balance
* @return true if accounting lines are balanced
*/
protected BigDecimal getAcctBalance()
{
BigDecimal result = Env.ZERO;
for (int i = 0; i < m_lines.size(); i++)
{
FactLine line = (FactLine)m_lines.get(i);
result = result.add(line.getAcctBalance());
}
return result;
} // getAcctBalance
/**
* Balance Accounting Currency.
*
* If the accounting currency is not balanced,
* if Currency balancing is enabled
* create a new line using the currency balancing account with zero source balance
* or
* adjust the line with the largest balance sheet account
* or if no balance sheet account exist, the line with the largest amount
*
* @return FactLine
*/
public FactLine balanceAccounting()
{
BigDecimal diff = getAcctBalance(); // DR-CR
if (log.isLoggable(Level.FINE)) log.fine("Balance=" + diff
+ ", CurrBal=" + m_acctSchema.isCurrencyBalancing()
+ " - " + toString());
FactLine line = null;
BigDecimal BSamount = Env.ZERO;
FactLine BSline = null;
BigDecimal PLamount = Env.ZERO;
FactLine PLline = null;
// Find line biggest BalanceSheet or P&L line
for (int i = 0; i < m_lines.size(); i++)
{
FactLine l = (FactLine)m_lines.get(i);
BigDecimal amt = l.getAcctBalance().abs();
if (l.isBalanceSheet() && amt.compareTo(BSamount) > 0)
{
BSamount = amt;
BSline = l;
}
else if (!l.isBalanceSheet() && amt.compareTo(PLamount) > 0)
{
PLamount = amt;
PLline = l;
}
}
// Create Currency Balancing Entry
if (m_acctSchema.isCurrencyBalancing())
{
line = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(),
m_doc.get_ID(), 0, m_trxName);
line.setDocumentInfo (m_doc, null);
line.setPostingType (m_postingType);
line.setAD_Org_ID(m_doc.getAD_Org_ID());
line.setAccount (m_acctSchema, m_acctSchema.getCurrencyBalancing_Acct());
// Amount
line.setAmtSource(m_doc.getC_Currency_ID(), Env.ZERO, Env.ZERO);
line.convert();
// Accounted
BigDecimal drAmt = Env.ZERO;
BigDecimal crAmt = Env.ZERO;
boolean isDR = diff.signum() < 0;
BigDecimal difference = diff.abs();
if (isDR)
drAmt = difference;
else
crAmt = difference;
// Switch sides
boolean switchIt = BSline != null
&& ((BSline.isDrSourceBalance() && isDR)
|| (!BSline.isDrSourceBalance() && !isDR));
if (switchIt)
{
drAmt = Env.ZERO;
crAmt = Env.ZERO;
if (isDR)
crAmt = difference.negate();
else
drAmt = difference.negate();
}
line.setAmtAcct(drAmt, crAmt);
if (log.isLoggable(Level.FINE)) log.fine(line.toString());
m_lines.add(line);
}
else // Adjust biggest (Balance Sheet) line amount
{
if (BSline != null)
line = BSline;
else
line = PLline;
if (line == null)
log.severe ("No Line found");
else
{
if (log.isLoggable(Level.FINE)) log.fine("Adjusting Amt=" + diff + "; Line=" + line);
line.currencyCorrect(diff);
if (log.isLoggable(Level.FINE)) log.fine(line.toString());
}
} // correct biggest amount
return line;
} // balanceAccounting
/**
* Check Accounts of Fact Lines
* @return true if success
*/
public boolean checkAccounts()
{
// no lines -> nothing to distribute
if (m_lines.size() == 0)
return true;
// For all fact lines
for (int i = 0; i < m_lines.size(); i++)
{
FactLine line = (FactLine)m_lines.get(i);
MAccount account = line.getAccount();
if (account == null)
{
log.warning("No Account for " + line);
return false;
}
MElementValue ev = account.getAccount();
if (ev == null)
{
log.warning("No Element Value for " + account
+ ": " + line);
m_doc.p_Error = account.toString();
return false;
}
if (ev.isSummary())
{
log.warning("Cannot post to Summary Account " + ev
+ ": " + line);
m_doc.p_Error = ev.toString();
return false;
}
if (!ev.isActive())
{
log.warning("Cannot post to Inactive Account " + ev
+ ": " + line);
m_doc.p_Error = ev.toString();
return false;
}
} // for all lines
return true;
} // checkAccounts
/**
* GL Distribution of Fact Lines
* @return true if success
*/
public boolean distribute()
{
// no lines -> nothing to distribute
if (m_lines.size() == 0)
return true;
ArrayList newLines = new ArrayList();
// For all fact lines
for (int i = 0; i < m_lines.size(); i++)
{
FactLine dLine = (FactLine)m_lines.get(i);
MDistribution[] distributions = MDistribution.get (dLine.getAccount(),
m_postingType, m_doc.getC_DocType_ID(), dLine.getDateAcct());
// No Distribution for this line
//AZ Goodwill
//The above "get" only work in GL Journal because it's using ValidCombination Account
if (distributions == null || distributions.length == 0)
{
distributions = MDistribution.get (dLine.getCtx(), dLine.getC_AcctSchema_ID(),
m_postingType, m_doc.getC_DocType_ID(), dLine.getDateAcct(),
dLine.getAD_Org_ID(), dLine.getAccount_ID(),
dLine.getM_Product_ID(), dLine.getC_BPartner_ID(), dLine.getC_Project_ID(),
dLine.getC_Campaign_ID(), dLine.getC_Activity_ID(), dLine.getAD_OrgTrx_ID(),
dLine.getC_SalesRegion_ID(), dLine.getC_LocTo_ID(), dLine.getC_LocFrom_ID(),
dLine.getUser1_ID(), dLine.getUser2_ID());
if (distributions == null || distributions.length == 0)
continue;
}
//end AZ
// Just the first
if (distributions.length > 1)
log.warning("More than one Distribution for " + dLine.getAccount());
MDistribution distribution = distributions[0];
// FR 2685367 - GL Distribution delete line instead reverse
if (distribution.isCreateReversal()) {
// Add Reversal
FactLine reversal = dLine.reverse(distribution.getName());
if (log.isLoggable(Level.INFO)) log.info("Reversal=" + reversal);
newLines.add(reversal); // saved in postCommit
} else {
// delete the line being distributed
m_lines.remove(i); // or it could be m_lines.remove(dLine);
i--;
}
// Prepare
distribution.distribute(dLine.getAccount(), dLine.getSourceBalance(), dLine.getQty(), dLine.getC_Currency_ID());
MDistributionLine[] lines = distribution.getLines(false);
for (int j = 0; j < lines.length; j++)
{
MDistributionLine dl = lines[j];
if (!dl.isActive() || dl.getAmt().signum() == 0)
continue;
FactLine factLine = new FactLine (m_doc.getCtx(), m_doc.get_Table_ID(),
m_doc.get_ID(), dLine.getLine_ID(), m_trxName);
// Set Info & Account
factLine.setDocumentInfo(m_doc, dLine.getDocLine());
factLine.setDescription(dLine.getDescription());
factLine.setAccount(m_acctSchema, dl.getAccount());
factLine.setPostingType(m_postingType);
if (dl.isOverwriteOrg()) // set Org explicitly
factLine.setAD_Org_ID(dl.getOrg_ID());
else
factLine.setAD_Org_ID(dLine.getAD_Org_ID());
// Silvano - freepath - F3P - Bug#2904994 Fact distribtution only overwriting Org
if(dl.isOverwriteAcct())
factLine.setAccount_ID(dl.getAccount_ID());
else
factLine.setAccount_ID(dLine.getAccount_ID());
if(dl.isOverwriteActivity())
factLine.setC_Activity_ID(dl.getC_Activity_ID());
else
factLine.setC_Activity_ID(dLine.getC_Activity_ID());
if(dl.isOverwriteBPartner())
factLine.setC_BPartner_ID(dl.getC_BPartner_ID());
else
factLine.setC_BPartner_ID(dLine.getC_BPartner_ID());
if(dl.isOverwriteCampaign())
factLine.setC_Campaign_ID(dl.getC_Campaign_ID());
else
factLine.setC_Campaign_ID(dLine.getC_Campaign_ID());
if(dl.isOverwriteLocFrom())
factLine.setC_LocFrom_ID(dl.getC_LocFrom_ID());
else
factLine.setC_LocFrom_ID(dLine.getC_LocFrom_ID());
if(dl.isOverwriteLocTo())
factLine.setC_LocTo_ID(dl.getC_LocTo_ID());
else
factLine.setC_LocTo_ID(dLine.getC_LocTo_ID());
if(dl.isOverwriteOrgTrx())
factLine.setAD_OrgTrx_ID(dl.getAD_OrgTrx_ID());
else
factLine.setAD_OrgTrx_ID(dLine.getAD_OrgTrx_ID());
if(dl.isOverwriteProduct())
factLine.setM_Product_ID(dl.getM_Product_ID());
else
factLine.setM_Product_ID(dLine.getM_Product_ID());
if(dl.isOverwriteProject())
factLine.setC_Project_ID(dl.getC_Project_ID());
else
factLine.setC_Project_ID(dLine.getC_Project_ID());
if(dl.isOverwriteSalesRegion())
factLine.setC_SalesRegion_ID(dl.getC_SalesRegion_ID());
else
factLine.setC_SalesRegion_ID(dLine.getC_SalesRegion_ID());
if(dl.isOverwriteUser1())
factLine.setUser1_ID(dl.getUser1_ID());
else
factLine.setUser1_ID(dLine.getUser1_ID());
if(dl.isOverwriteUser2())
factLine.setUser2_ID(dl.getUser2_ID());
else
factLine.setUser2_ID(dLine.getUser2_ID());
factLine.setUserElement1_ID(dLine.getUserElement1_ID());
factLine.setUserElement2_ID(dLine.getUserElement2_ID());
// F3P end
//
if (dLine.getAmtAcctCr().signum() != 0) // isCredit
factLine.setAmtSource(dLine.getC_Currency_ID(), null, dl.getAmt().negate());
else
factLine.setAmtSource(dLine.getC_Currency_ID(), dl.getAmt(), null);
factLine.setQty(dl.getQty());
// Convert
factLine.convert();
//
String description = distribution.getName() + " #" + dl.getLine();
if (dl.getDescription() != null)
description += " - " + dl.getDescription();
factLine.addDescription(description);
//
if (log.isLoggable(Level.INFO)) log.info(factLine.toString());
newLines.add(factLine);
}
} // for all lines
// Add Lines
for (int i = 0; i < newLines.size(); i++)
m_lines.add(newLines.get(i));
return true;
} // distribute
/**
* String representation
* @return String
*/
public String toString()
{
StringBuilder sb = new StringBuilder("Fact[");
sb.append(m_doc.toString());
sb.append(",").append(m_acctSchema.toString());
sb.append(",PostType=").append(m_postingType);
sb.append("]");
return sb.toString();
} // toString
/**
* Get Lines
* @return FactLine Array
*/
public FactLine[] getLines()
{
FactLine[] temp = new FactLine[m_lines.size()];
m_lines.toArray(temp);
return temp;
} // getLines
/**
* Save Fact Lines
* @param trxName transaction
* @return true if all lines were saved
*/
public boolean save (String trxName)
{
m_trxName = trxName;
// save Lines
for (int i = 0; i < m_lines.size(); i++)
{
FactLine fl = (FactLine)m_lines.get(i);
if (!fl.save(trxName)) // abort on first error
return false;
}
return true;
} // commit
/**
* Get Transaction Name
* @return trx nam
*/
public String get_TrxName()
{
return m_trxName;
} // getTrxName
/**
* Set Transaction name
* @param trxName
*/
@SuppressWarnings("unused")
private void set_TrxName(String trxName)
{
m_trxName = trxName;
} // set_TrxName
/**
* Fact Balance Utility
*
* @author Jorg Janke
* @version $Id: Fact.java,v 1.2 2006/07/30 00:53:33 jjanke Exp $
*/
public static class Balance
{
/**
* @param dr DR
* @param cr CR
*/
public Balance (BigDecimal dr, BigDecimal cr)
{
DR = dr;
CR = cr;
}
/** DR Amount */
public BigDecimal DR = Env.ZERO;
/** CR Amount */
public BigDecimal CR = Env.ZERO;
/**
* Add
* @param dr DR
* @param cr CR
*/
public void add (BigDecimal dr, BigDecimal cr)
{
DR = DR.add(dr);
CR = CR.add(cr);
}
/**
* Get Balance
* @return balance
*/
public BigDecimal getBalance()
{
return DR.subtract(CR);
} // getBalance
/**
* Get Post Balance
* @return absolute balance - negative if reversal
*/
public BigDecimal getPostBalance()
{
BigDecimal bd = getBalance().abs();
if (isReversal())
return bd.negate();
return bd;
} // getPostBalance
/**
* Zero Balance
* @return true if 0
*/
public boolean isZeroBalance()
{
return getBalance().signum() == 0;
} // isZeroBalance
/**
* Reversal
* @return true if both DR/CR are negative or zero
*/
public boolean isReversal()
{
return DR.signum() <= 0 && CR.signum() <= 0;
} // isReversal
/**
* String Representation
* @return info
*/
public String toString ()
{
StringBuilder sb = new StringBuilder ("Balance[");
sb.append ("DR=").append(DR)
.append ("-CR=").append(CR)
.append(" = ").append(getBalance())
.append ("]");
return sb.toString ();
} // toString
} // Balance
} // Fact