/******************************************************************************
* 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.ResultSet;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.BackDateTrxNotAllowedException;
import org.compiere.report.MReportTree;
import org.compiere.util.CCache;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.TimeUtil;
import org.compiere.util.Util;
import org.idempiere.cache.ImmutableIntPOCache;
import org.idempiere.cache.ImmutablePOSupport;
/**
* Accounting Schema Model
*
* @author Jorg Janke
* @author victor.perez@e-evolution.com, www.e-evolution.com
*
RF [ 2214883 ] Remove SQL code and Replace for Query https://sourceforge.net/p/adempiere/feature-requests/557/
* @version $Id: MAcctSchema.java,v 1.4 2006/07/30 00:58:04 jjanke Exp $
*/
public class MAcctSchema extends X_C_AcctSchema implements ImmutablePOSupport
{
/**
* generated serial id
*/
private static final long serialVersionUID = 2740537819749888011L;
/**
* Get AccountSchema
* @param C_AcctSchema_ID schema id
* @return Accounting schema
*/
public static MAcctSchema get (int C_AcctSchema_ID)
{
return get(Env.getCtx(), C_AcctSchema_ID);
}
/**
* Get AccountSchema
* @param ctx context
* @param C_AcctSchema_ID schema id
* @return Accounting schema
*/
public static MAcctSchema get (Properties ctx, int C_AcctSchema_ID)
{
return get(ctx, C_AcctSchema_ID, (String)null);
} // get
/**
* Get AccountSchema
* @param ctx context
* @param C_AcctSchema_ID schema id
* @param trxName optional trx
* @return Accounting schema
*/
public static MAcctSchema get (Properties ctx, int C_AcctSchema_ID, String trxName)
{
// Check Cache
Integer key = Integer.valueOf(C_AcctSchema_ID);
MAcctSchema retValue = s_cache.get(ctx, key, e -> new MAcctSchema(ctx, e));
if (retValue != null)
return retValue;
retValue = new MAcctSchema (ctx, C_AcctSchema_ID, trxName);
if (retValue.get_ID() == C_AcctSchema_ID)
{
s_cache.put(key, retValue, e -> new MAcctSchema(Env.getCtx(), e));
return retValue;
}
return null;
} // get
/**
* Get updateable copy of MAcctSchema from cache
* @param ctx
* @param C_AcctSchema_ID
* @param trxName
* @return MAcctSchema
*/
public static MAcctSchema getCopy(Properties ctx, int C_AcctSchema_ID, String trxName)
{
MAcctSchema as = get(ctx, C_AcctSchema_ID, trxName);
if (as != null)
as = new MAcctSchema(ctx, as, trxName);
return as;
}
/**
* Get AccountSchema of Client
* @param ctx context
* @param AD_Client_ID client or 0 for all
* @return Array of AcctSchema of Client
*/
public static MAcctSchema[] getClientAcctSchema (Properties ctx, int AD_Client_ID)
{
return getClientAcctSchema(ctx, AD_Client_ID, null);
} // getClientAcctSchema
/**
* Get AccountSchema of Client
* @param ctx context
* @param AD_Client_ID client or 0 for all
* @param trxName optional trx
* @return Array of AcctSchema of Client
*/
public static synchronized MAcctSchema[] getClientAcctSchema (Properties ctx, int AD_Client_ID, String trxName)
{
// Check Cache
Integer key = Integer.valueOf(AD_Client_ID);
if (s_schema.containsKey(key))
{
if (ctx == Env.getCtx())
return s_schema.get(key);
else
return Arrays.stream(s_schema.get(key)).map(e -> { return new MAcctSchema(ctx, e).markImmutable(); }).toArray(MAcctSchema[]::new);
}
// Create New
ArrayList list = new ArrayList();
MClientInfo info = MClientInfo.get(ctx, AD_Client_ID, trxName);
MAcctSchema as = MAcctSchema.get (ctx, info.getC_AcctSchema1_ID(), trxName);
if (as.get_ID() != 0)
list.add(as);
ArrayList params = new ArrayList();
StringBuilder whereClause = new StringBuilder("IsActive=? ")
.append(" AND EXISTS (SELECT * FROM C_AcctSchema_GL gl WHERE C_AcctSchema.C_AcctSchema_ID=gl.C_AcctSchema_ID)")
.append(" AND EXISTS (SELECT * FROM C_AcctSchema_Default d WHERE C_AcctSchema.C_AcctSchema_ID=d.C_AcctSchema_ID)");
params.add("Y");
if (AD_Client_ID != 0)
{
whereClause.append(" AND AD_Client_ID=?");
params.add(AD_Client_ID);
}
List ass = new Query(ctx, I_C_AcctSchema.Table_Name,whereClause.toString(),trxName)
.setParameters(params)
.setOrderBy(MAcctSchema.COLUMNNAME_C_AcctSchema_ID)
.list();
for(MAcctSchema acctschema : ass)
{
if (acctschema.get_ID() != info.getC_AcctSchema1_ID()) // already in list
{
if (acctschema.get_ID() != 0)
{
acctschema.markImmutable();
list.add(acctschema);
}
}
}
// Save
MAcctSchema[] retValue = new MAcctSchema [list.size()];
list.toArray(retValue);
if (ctx == Env.getCtx())
s_schema.put(key, retValue);
else
s_schema.put(key, Arrays.stream(retValue).map(e -> {return new MAcctSchema(Env.getCtx(), e).markImmutable();}).toArray(MAcctSchema[]::new));
return retValue;
} // getClientAcctSchema
/** Cache of Client AcctSchema Arrays **/
private static CCache s_schema = new CCache(I_AD_ClientInfo.Table_Name, I_AD_ClientInfo.Table_Name+"|MAcctSchema[]", 3, 0, false, 0); // 3 clients
/** Cache of AcctSchemas **/
private static ImmutableIntPOCache s_cache = new ImmutableIntPOCache(Table_Name, 3, 0, false, 0); // 3 accounting schemas
/**
* UUID based Constructor
* @param ctx Context
* @param C_AcctSchema_UU UUID key
* @param trxName Transaction
*/
public MAcctSchema(Properties ctx, String C_AcctSchema_UU, String trxName) {
super(ctx, C_AcctSchema_UU, trxName);
if (Util.isEmpty(C_AcctSchema_UU))
setInitialDefaults();
}
/**
* Standard Constructor
* @param ctx context
* @param C_AcctSchema_ID id
* @param trxName transaction
*/
public MAcctSchema (Properties ctx, int C_AcctSchema_ID, String trxName)
{
super (ctx, C_AcctSchema_ID, trxName);
if (C_AcctSchema_ID == 0)
setInitialDefaults();
} // MAcctSchema
/**
* Set the initial defaults for a new record
*/
private void setInitialDefaults() {
setAutoPeriodControl (true);
setPeriod_OpenFuture(2);
setPeriod_OpenHistory(2);
setCostingMethod (COSTINGMETHOD_StandardCosting);
setCostingLevel(COSTINGLEVEL_Client);
setIsAdjustCOGS(false);
setGAAP (GAAP_InternationalGAAP);
setHasAlias (true);
setHasCombination (false);
setIsAccrual (true); // Y
setCommitmentType(COMMITMENTTYPE_None);
setIsDiscountCorrectsTax (false);
setTaxCorrectionType(TAXCORRECTIONTYPE_None);
setIsTradeDiscountPosted (false);
setIsPostServices(false);
setIsExplicitCostAdjustment(false);
setSeparator ("-"); // -
}
/**
* Load Constructor
* @param ctx context
* @param rs result set
* @param trxName transaction
*/
public MAcctSchema (Properties ctx, ResultSet rs, String trxName)
{
super(ctx, rs, trxName);
} // MAcctSchema
/**
* Parent Constructor
* @param client client
* @param currency currency
*/
public MAcctSchema (MClient client, KeyNamePair currency)
{
this (client.getCtx(), 0, client.get_TrxName());
setClientOrg(client);
setC_Currency_ID (currency.getKey());
StringBuilder msgset = new StringBuilder().append(client.getName()).append(" ").append(getGAAP()).append("/").append(get_ColumnCount()).append(" ").append(currency.getName());
setName (msgset.toString());
} // MAcctSchema
/**
* Copy constructor
* @param copy
*/
public MAcctSchema(MAcctSchema copy)
{
this(Env.getCtx(), copy);
}
/**
* Copy constructor
* @param ctx
* @param copy
*/
public MAcctSchema(Properties ctx, MAcctSchema copy)
{
this(ctx, copy, (String)null);
}
/**
* Copy constructor
* @param ctx
* @param copy
* @param trxName
*/
public MAcctSchema(Properties ctx, MAcctSchema copy, String trxName)
{
super(ctx, 0, trxName);
copyPO(copy);
this.m_gl = copy.m_gl != null ? new MAcctSchemaGL(ctx, copy.m_gl) : null;
this.m_default = copy.m_default != null ? new MAcctSchemaDefault(ctx, copy.m_default) : null;
this.m_SuspenseError_Acct = copy.m_SuspenseError_Acct != null ? new MAccount(ctx, copy.m_SuspenseError_Acct) : null;
this.m_CurrencyBalancing_Acct = copy.m_CurrencyBalancing_Acct != null ? new MAccount(ctx, copy.m_CurrencyBalancing_Acct) : null;
this.m_DueTo_Acct = copy.m_DueTo_Acct != null ? new MAccount(ctx, copy.m_DueTo_Acct) : null;
this.m_DueFrom_Acct = copy.m_DueFrom_Acct != null ? new MAccount(ctx, copy.m_DueFrom_Acct) : null;
this.m_stdPrecision = copy.m_stdPrecision;
this.m_costPrecision = copy.m_costPrecision;
this.m_onlyOrg = copy.m_onlyOrg != null ? new MOrg(ctx, copy.m_onlyOrg) : null;
this.m_onlyOrgs = copy.m_onlyOrgs;
}
/** GL Info */
private MAcctSchemaGL m_gl = null;
/** Default Info */
private MAcctSchemaDefault m_default = null;
private MAccount m_SuspenseError_Acct = null;
private MAccount m_CurrencyBalancing_Acct = null;
private MAccount m_DueTo_Acct = null;
private MAccount m_DueFrom_Acct = null;
/** Accounting Currency Precision */
private int m_stdPrecision = -1;
/** Costing Currency Precision */
private int m_costPrecision = -1;
/** Only Post Org */
private MOrg m_onlyOrg = null;
/** Only Post Org Childs */
private Integer[] m_onlyOrgs = null;
/**
* AcctSchema Elements
* @return Array of AcctSchemaElement
*/
public MAcctSchemaElement[] getAcctSchemaElements()
{
return MAcctSchemaElement.getAcctSchemaElements(this);
} // getAcctSchemaElements
/**
* Get AcctSchema Element via element type
* @param elementType segment type - AcctSchemaElement.ELEMENTTYPE_
* @return AcctSchemaElement
*/
public MAcctSchemaElement getAcctSchemaElement (String elementType)
{
/** Element List */
for (MAcctSchemaElement ase : getAcctSchemaElements()) {
if (ase.getElementType().equals(elementType))
return ase;
}
return null;
} // getAcctSchemaElement
/**
* @param segmentType segment type - AcctSchemaElement.SEGMENT_
* @return true if schema has segment type
*/
public boolean isAcctSchemaElement (String segmentType)
{
return getAcctSchemaElement(segmentType) != null;
} // isAcctSchemaElement
/**
* Get AcctSchema GL info
* @return GL info
*/
public MAcctSchemaGL getAcctSchemaGL()
{
if (m_gl == null)
{
m_gl = MAcctSchemaGL.get(getCtx(), getC_AcctSchema_ID());
if (m_gl != null && is_Immutable())
m_gl.markImmutable();
}
if (m_gl == null)
throw new IllegalStateException("No GL Definition for C_AcctSchema_ID=" + getC_AcctSchema_ID());
return m_gl;
} // getAcctSchemaGL
/**
* Get AcctSchema Defaults
* @return defaults
*/
public MAcctSchemaDefault getAcctSchemaDefault()
{
if (m_default == null)
{
m_default = MAcctSchemaDefault.get(getCtx(), getC_AcctSchema_ID());
if (m_default != null && is_Immutable())
m_default.markImmutable();
}
if (m_default == null)
throw new IllegalStateException("No Default Definition for C_AcctSchema_ID=" + getC_AcctSchema_ID());
return m_default;
} // getAcctSchemaDefault
/**
* String representation
* @return String representation
*/
public String toString()
{
StringBuilder sb = new StringBuilder("AcctSchema[");
sb.append(get_ID()).append("-").append(getName())
.append("]");
return sb.toString();
} // toString
/**
* Is Suspense Balancing active
* @return true if schema is using suspense balancing account
*/
public boolean isSuspenseBalancing()
{
if (m_gl == null)
getAcctSchemaGL();
return m_gl.isUseSuspenseBalancing() && m_gl.getSuspenseBalancing_Acct() != 0;
} // isSuspenseBalancing
/**
* Get Suspense Balancing Account
* @return suspense balancing account
*/
public MAccount getSuspenseBalancing_Acct()
{
if (m_SuspenseError_Acct != null)
return m_SuspenseError_Acct;
if (m_gl == null)
getAcctSchemaGL();
int C_ValidCombination_ID = m_gl.getSuspenseBalancing_Acct();
m_SuspenseError_Acct = MAccount.get(C_ValidCombination_ID);
return m_SuspenseError_Acct;
} // getSuspenseBalancing_Acct
/**
* Is Currency Balancing active
* @return true if schema is using currency balancing account
*/
public boolean isCurrencyBalancing()
{
if (m_gl == null)
getAcctSchemaGL();
return m_gl.isUseCurrencyBalancing();
} // isSuspenseBalancing
/**
* Get Currency Balancing Account
* @return currency balancing account
*/
public MAccount getCurrencyBalancing_Acct()
{
if (m_CurrencyBalancing_Acct != null)
return m_CurrencyBalancing_Acct;
if (m_gl == null)
getAcctSchemaGL();
int C_ValidCombination_ID = m_gl.getCurrencyBalancing_Acct();
m_CurrencyBalancing_Acct = MAccount.get(C_ValidCombination_ID);
return m_CurrencyBalancing_Acct;
} // getCurrencyBalancing_Acct
/**
* Get Due To Account for Segment
* @param segment ignored
* @return Account
*/
public MAccount getDueTo_Acct(String segment)
{
if (m_DueTo_Acct != null)
return m_DueTo_Acct;
if (m_gl == null)
getAcctSchemaGL();
int C_ValidCombination_ID = m_gl.getIntercompanyDueTo_Acct();
m_DueTo_Acct = MAccount.get(C_ValidCombination_ID);
return m_DueTo_Acct;
} // getDueTo_Acct
/**
* Get Due From Account for Segment
* @param segment ignored
* @return Account
*/
public MAccount getDueFrom_Acct(String segment)
{
if (m_DueFrom_Acct != null)
return m_DueFrom_Acct;
if (m_gl == null)
getAcctSchemaGL();
int C_ValidCombination_ID = m_gl.getIntercompanyDueFrom_Acct();
m_DueFrom_Acct = MAccount.get(C_ValidCombination_ID);
return m_DueFrom_Acct;
} // getDueFrom_Acct
/**
* Set Only Org Childs
* @param orgs
* @deprecated only orgs are now fetched automatically
* @throws IllegalStateException every time when you call it
*/
@Deprecated
public void setOnlyOrgs (Integer[] orgs)
{
throw new IllegalStateException("The OnlyOrgs are now fetched automatically");
} // setOnlyOrgs
/**
* Get Only Org Children
* @return array of AD_Org_ID
*/
public synchronized Integer[] getOnlyOrgs()
{
if (m_onlyOrgs == null)
{
MReportTree tree = new MReportTree (getCtx(), 0, true, MAcctSchemaElement.ELEMENTTYPE_Organization);
m_onlyOrgs = tree.getChildIDs(getAD_OrgOnly_ID());
}
return m_onlyOrgs;
} // getOnlyOrgs
/**
* Skip creating postings for this Org.
* @param AD_Org_ID
* @return true if to skip posting
*/
public synchronized boolean isSkipOrg (int AD_Org_ID)
{
if (getAD_OrgOnly_ID() == 0)
return false;
// Only Organization
if (getAD_OrgOnly_ID() == AD_Org_ID)
return false;
if (m_onlyOrg == null)
m_onlyOrg = MOrg.get(getAD_OrgOnly_ID());
// Not Summary Only - i.e. skip it
if (!m_onlyOrg.isSummary())
return true;
final Integer[] onlyOrgs = getOnlyOrgs();
if (onlyOrgs == null)
{
return false;
}
for (int i = 0; i < onlyOrgs.length; i++)
{
if (AD_Org_ID == onlyOrgs[i].intValue())
return false;
}
return true;
} // isSkipOrg
/**
* Get Std Precision of accounting Currency
* @return precision
*/
public int getStdPrecision()
{
if (m_stdPrecision < 0)
{
MCurrency cur = MCurrency.get(getCtx(), getC_Currency_ID());
m_stdPrecision = cur.getStdPrecision();
m_costPrecision = cur.getCostingPrecision();
}
return m_stdPrecision;
} // getStdPrecision
/**
* Get Costing Precision of accounting Currency
* @return precision
*/
public int getCostingPrecision()
{
if (m_costPrecision < 0)
getStdPrecision();
return m_costPrecision;
} // getCostingPrecision
/**
* Check Costing Setup.
* Make sure that there is a Cost Type and Cost Element
*/
public void checkCosting()
{
if (log.isLoggable(Level.INFO)) log.info(toString());
// Create Cost Type
if (getM_CostType_ID() == 0)
{
MCostType ct = new MCostType (getCtx(), 0, get_TrxName());
ct.setClientOrg(getAD_Client_ID(), 0);
ct.setName(getName());
ct.saveEx();
setM_CostType_ID(ct.getM_CostType_ID());
}
// Create Cost Elements
MCostElement.getMaterialCostElement(this, getCostingMethod());
// Default Costing Level
if (getCostingLevel() == null)
setCostingLevel(COSTINGLEVEL_Client);
if (getCostingMethod() == null)
setCostingMethod (COSTINGMETHOD_StandardCosting);
if (getGAAP() == null)
setGAAP (GAAP_InternationalGAAP);
} // checkCosting
/**
* Is Client Costing Level (default)
* @return true if schema costing is at client level
*/
public boolean isCostingLevelClient()
{
String s = getCostingLevel();
if (s == null || COSTINGLEVEL_Client.equals(s))
return true;
return false;
} // isCostingLevelClient
/**
* Is Org Costing Level
* @return true if schema costing is at organization level
*/
public boolean isCostingLevelOrg()
{
return COSTINGLEVEL_Organization.equals(getCostingLevel());
} // isCostingLevelOrg
/**
* Is Batch Costing Level
* @return true if schema costing is at lot/batch level
*/
public boolean isCostingLevelBatch()
{
return COSTINGLEVEL_BatchLot.equals(getCostingLevel());
} // isCostingLevelBatch
/**
* @return true if using commitments accounting for PO
*/
public boolean isCreatePOCommitment()
{
String s = getCommitmentType();
if (s == null)
return false;
return COMMITMENTTYPE_POCommitmentOnly.equals(s)
|| COMMITMENTTYPE_POCommitmentReservation.equals(s)
|| COMMITMENTTYPE_POSOCommitmentReservation.equals(s)
|| COMMITMENTTYPE_POSOCommitment.equals(s);
} // isCreateCommitment
/**
* @return true if using commitments accounting for SO
*/
public boolean isCreateSOCommitment()
{
String s = getCommitmentType();
if (s == null)
return false;
return COMMITMENTTYPE_SOCommitmentOnly.equals(s)
|| COMMITMENTTYPE_POSOCommitmentReservation.equals(s)
|| COMMITMENTTYPE_POSOCommitment.equals(s);
} // isCreateCommitment
/**
* @return true if create reservations for PO
*/
public boolean isCreateReservation()
{
String s = getCommitmentType();
if (s == null)
return false;
return COMMITMENTTYPE_POCommitmentReservation.equals(s)
|| COMMITMENTTYPE_POSOCommitmentReservation.equals(s);
} // isCreateReservation
/**
* Get Tax Correction Type
* @return tax correction type (discount, write off or none)
*/
public String getTaxCorrectionType()
{
if (super.getTaxCorrectionType() == null) // created 07/23/06 2.5.3d
setTaxCorrectionType(isDiscountCorrectsTax()
? TAXCORRECTIONTYPE_Write_OffAndDiscount : TAXCORRECTIONTYPE_None);
return super.getTaxCorrectionType ();
} // getTaxCorrectionType
/**
* Tax Correction
* @return true if tax correction type is not none
*/
public boolean isTaxCorrection()
{
return !getTaxCorrectionType().equals(TAXCORRECTIONTYPE_None);
} // isTaxCorrection
/**
* @return true if tax correction type is discount or write off+discount
*/
public boolean isTaxCorrectionDiscount()
{
return getTaxCorrectionType().equals(TAXCORRECTIONTYPE_DiscountOnly)
|| getTaxCorrectionType().equals(TAXCORRECTIONTYPE_Write_OffAndDiscount);
} // isTaxCorrectionDiscount
/**
* @return true if tax correction type is write off or write off+discount
*/
public boolean isTaxCorrectionWriteOff()
{
return getTaxCorrectionType().equals(TAXCORRECTIONTYPE_Write_OffOnly)
|| getTaxCorrectionType().equals(TAXCORRECTIONTYPE_Write_OffAndDiscount);
} // isTaxCorrectionWriteOff
@Override
protected boolean beforeSave (boolean newRecord)
{
if (getAD_Org_ID() != 0)
setAD_Org_ID(0);
if (super.getTaxCorrectionType() == null)
setTaxCorrectionType(isDiscountCorrectsTax()
? TAXCORRECTIONTYPE_Write_OffAndDiscount : TAXCORRECTIONTYPE_None);
checkCosting();
// AD_OrgOnly_ID must be 0 if this is primary accounting schema of tenant
if (getAD_OrgOnly_ID() != 0)
{
MClientInfo info = MClientInfo.get(getCtx(), getAD_Client_ID());
if (info.getC_AcctSchema1_ID() == getC_AcctSchema_ID())
setAD_OrgOnly_ID(0);
}
// Disallow costing level change if there are existing costing detail records
if (!newRecord && is_ValueChanged(COLUMNNAME_CostingLevel))
{
String products = getProductsWithCost();
if (!Util.isEmpty(products)) {
log.saveError("Error", Msg.getMsg(getCtx(), "ChangeCostingLevelError") + ". Products: " + products);
return false;
}
}
return true;
} // beforeSave
/**
* Get products that has costing detail records.
* @return comma separated product values
*/
private String getProductsWithCost() {
StringBuilder products = new StringBuilder();
StringBuilder sql = new StringBuilder("SELECT DISTINCT p.Value FROM M_Product p JOIN M_CostDetail d ON p.M_Product_ID=d.M_Product_ID");
sql.append(" JOIN M_Product_Category_Acct pc ON p.M_Product_Category_ID=pc.M_Product_Category_ID AND d.C_AcctSchema_ID=pc.C_AcctSchema_ID");
sql.append(" WHERE p.IsActive='Y' AND pc.IsActive='Y' AND pc.CostingLevel IS NULL AND d.C_AcctSchema_ID=?");
String query = DB.getDatabase().addPagingSQL(sql.toString(), 1, 50);
List> list = DB.getSQLArrayObjectsEx(get_TrxName(), query, getC_AcctSchema_ID());
if (list != null) {
for(List entry : list) {
String value = (String) entry.get(0);
if (products.length() > 0)
products.append(",");
products.append(value);
}
}
return products.toString();
}
@Override
public MAcctSchema markImmutable()
{
if (is_Immutable())
return this;
makeImmutable();
if (m_gl != null)
m_gl.markImmutable();
if (m_default != null)
m_default.markImmutable();
return this;
}
/**
* Convenient method for testing if a back-date transaction is allowed in primary accounting schema
* @param ctx
* @param dateAcct
* @param trxName
* @throws BackDateTrxNotAllowedException
*/
public static void testBackDateTrxAllowed(Properties ctx, Timestamp dateAcct, String trxName)
throws BackDateTrxNotAllowedException
{
if (!MAcctSchema.isBackDateTrxAllowed(ctx, dateAcct, trxName)) {
throw new BackDateTrxNotAllowedException(dateAcct);
}
}
/**
* Is Back-Date transaction allowed in primary accounting schema?
* @param ctx context
* @param tableID
* @param recordID
* @param trxName
* @return true if back-date transaction is allowed
*/
public static boolean isBackDateTrxAllowed(Properties ctx, int tableID, int recordID, String trxName)
{
Timestamp dateAcct = MCostDetail.getDateAcct(tableID, recordID, trxName);;
if (dateAcct == null)
return true;
return isBackDateTrxAllowed(ctx, dateAcct, trxName);
}
/**
* Is Back-Date transaction allowed in primary accounting schema?
* @param ctx context
* @param dateAcct account date
* @param trxName
* @return true if back-date transaction is allowed
*/
public static boolean isBackDateTrxAllowed(Properties ctx, Timestamp dateAcct, String trxName)
{
if (dateAcct == null)
return true;
MClientInfo info = MClientInfo.get(ctx, Env.getAD_Client_ID(ctx), trxName);
MAcctSchema as = info.getMAcctSchema1();
return as.isBackDateTrxAllowed(dateAcct);
}
/**
* Is Back-Date transaction allowed?
* @param dateAcct account date
* @return true if back-date transaction is allowed
*/
public boolean isBackDateTrxAllowed(Timestamp dateAcct)
{
if (dateAcct == null)
return true;
if (getBackDateDay() != 0)
{
Timestamp today = TimeUtil.trunc(new Timestamp (System.currentTimeMillis()), TimeUtil.TRUNC_DAY);
Timestamp allowedBackDate = TimeUtil.addDays(today, - getBackDateDay());
if (dateAcct.before(allowedBackDate))
{
log.warning("Back-Date Days Control" + dateAcct + " before allowed back-date - " + allowedBackDate);
return false;
}
}
return true;
}
} // MAcctSchema