This is a customization where I added a custom field at the line level to capture the legal entity. When a specific legal entity is selected in this field, the system triggers the above process to validate the budget. If sufficient budget is available for that legal entity, the transaction proceeds. If not, the standard process is allowed to execute and throw the appropriate error.
[ExtensionOf(classStr(BudgetControlProcessor))]
final class Dax_BudgetControlProcessor_Extension
{
public str errormsg;
public boolean result;
protected boolean abortProcessForBudgetCheckFailure()
{
boolean doAbortProcess;
Ledger primaryLedger;
BudgetControlConfiguration configuration;
CompanyInfo CompanyInfo = CompanyInfo::findDataArea(curExt());
primaryLedger = Ledger::findByLegalEntity(CompanyInfo.recid);
if (primaryLedger.IsBudgetControlEnabled)
{
configuration = BudgetControlConfiguration::findActiveByPrimaryLedger(primaryLedger.RecId);
}
doAbortProcess = next abortProcessForBudgetCheckFailure();
if(configuration)
{
doAbortProcess = false;
}
return doAbortProcess;
}
public DimensionDisplayValue getAttributeValueFromCombination(
DimensionAttributeValueCombination _combination,
Name _attributeName)
{
DimensionAttributeLevelValueView valueView;
DimensionAttribute attribute = DimensionAttribute::findByName(_attributeName); //Retrive attribute record by Name
select valueView
where valueView.ValueCombinationRecId == _combination.recId
&& valueView.DimensionAttribute == attribute.RecId; //Retrieve individual Dimension attribute record
return valueView.DisplayValue; //Retrive dimension attribute value
}
public boolean checkBudgetAmount(BudgetSource _budgetSource,BudgetCheckResultErrorWarningDetail _detailResult)
{
boolean ret;
BUDGETTRANSACTIONLINE bUDGETTRANSACTIONLINE,bUDGETTRANSACTIONLINELoc;
BUDGETTRANSACTIONHEADER bUDGETTRANSACTIONHEADER,bUDGETTRANSACTIONHEADERloc;
BudgetSource budgetSource = _budgetSource;
BudgetCheckResultErrorWarningDetail budgetCheckResultErrorWarningDetail;
DimensionAttributeValueCombination dimensionAttributeValueCombination,dimensionAttributeValueCombinationloc,dimensionAttributeValueCombinationlocerror;
DimensionAttribute dimensionAttribue,dimensionAttribueloc;
DimensionAttributeLevelValueAllView dimensionAttributeLevelValueAllView,dimensionAttributeLevelValueAllViewloc;
LedgerDimensionBudgetControl controlLedgerDimension;
Map map = new Map(Types::String, Types::String);
MapEnumerator mapEnumerator;
container conDimensions;
DimensionDisplayValue mainAccount,businessUnit,costCenter,legalEntity,mainAccountloc,businessUnitloc,costCenterloc,legalEntityloc,project,projectloc,region,regionloc;
select bUDGETTRANSACTIONLINELoc
where bUDGETTRANSACTIONLINELoc.RecId == budgetSource.BudgetTransactionLine;
select bUDGETTRANSACTIONHEADERloc
where bUDGETTRANSACTIONHEADERloc.RecId == bUDGETTRANSACTIONLINELoc.BudgetTransactionHeader;
if(bUDGETTRANSACTIONHEADERloc.Dax_TransferCrossCompany == NoYes::Yes /*&& bUDGETTRANSACTIONLINELoc.Dax_ToCompany != curExt() */ && bUDGETTRANSACTIONLINELoc.displayAccountingAmount() < 0)
{
//LedgerRecId primaryLedgerId = primaryLedgersToCheckBudget.lookup(CompanyInfo::findDataArea(curExt()));
// Budget control rule found, get budget control ledger dimension
controlLedgerDimension = BudgetControlLedgerDimensionHelper::findBudgetControlLedgerDimension(
bUDGETTRANSACTIONHEADERloc.PrimaryLedger,
bUDGETTRANSACTIONLINELoc.LedgerDimension);
// real currentAmount = abs(bUDGETTRANSACTIONLINELoc.displayAccountingAmount());
real currentAmount = abs(bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount);
select dimensionAttributeValueCombination
where dimensionAttributeValueCombination.RecId == bUDGETTRANSACTIONLINELoc.LedgerDimension;
select dimensionAttributeValueCombinationlocerror
where dimensionAttributeValueCombinationlocerror.RecId == controlLedgerDimension;
while select dimensionAttributeLevelValueAllView
where dimensionAttributeLevelValueAllView.ValueCombinationRecId == controlLedgerDimension
{
DimensionAttribute attribute = DimensionAttribute::find(dimensionAttributeLevelValueAllView.DimensionAttribute);
conDimensions += attribute.Name;
}
for(int c=1; c<=conLen(conDimensions);c++)
{
str dimensionValue = this.getAttributeValueFromCombination(dimensionAttributeValueCombination,conPeek(conDimensions,c));
map.insert(conPeek(conDimensions,c),dimensionValue);
}
// mainAccount = LedgerDimensionFacade::getMainAccountFromLedgerDimension(bUDGETTRANSACTIONLINELoc.LedgerDimension).MainAccountId;
Amount budgetAmount;
boolean mapResult;
while select bUDGETTRANSACTIONLINE
join bUDGETTRANSACTIONHEADER
where bUDGETTRANSACTIONHEADER.RECID == bUDGETTRANSACTIONLINE.BUDGETTRANSACTIONHEADER
&& bUDGETTRANSACTIONHEADER.BUDGETMODELDATAAREAID == bUDGETTRANSACTIONLINELoc.DAX_TOCOMPANY
&& budgetTransactionHeader.TransactionStatus == BudgetTransactionStatus::Completed
{
map maploc = new Map(Types::String, Types::String);
select dimensionAttributeValueCombinationloc
where dimensionAttributeValueCombinationloc.RecId == bUDGETTRANSACTIONLINE.LedgerDimension;
for(int c=1; c<=conLen(conDimensions);c++)
{
str dimensionValue = this.getAttributeValueFromCombination(dimensionAttributeValueCombinationloc,conPeek(conDimensions,c));
maploc.insert(conPeek(conDimensions,c),dimensionValue);
}
mapResult = Map::equal(map,maploc);
if(mapResult)
{
budgetAmount += bUDGETTRANSACTIONLINE.displayAccountingAmount();
}
}
if(budgetAmount == 0)
{
errormsg = strFmt("@SYS128612",
bUDGETTRANSACTIONHEADERloc.TransactionNumber,
dimensionAttributeValueCombinationlocerror.DisplayValue,
// bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount,
bUDGETTRANSACTIONLINELoc.TransactionCurrency);
return false;
//throw Error(strFmt("@SYS128612",
// bUDGETTRANSACTIONHEADERloc.TransactionNumber,
// dimensionAttributeValueCombinationlocerror.DisplayValue,
// // bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
// bUDGETTRANSACTIONLINELoc.TransactionCurrencyAmount,
// bUDGETTRANSACTIONLINELoc.TransactionCurrency));
}
Amount exbudget;
changecompany(bUDGETTRANSACTIONLINELoc.DAX_TOCOMPANY)
{
CurrencyExchangeHelper currencyExchangeHelper;
currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), systemDateGet());
CurrencyCode tocurrCode = Ledger::accountingCurrency(CompanyInfo::current());
currencyExchangeHelper.parmLedgerRecId(Ledger::current());
currencyExchangeHelper.parmExchangeRateTypeRecId(Ledger::budgetExchangeRateType());
exbudget = currencyExchangeHelper.calculateCurrencyToCurrency(tocurrCode,bUDGETTRANSACTIONLINELoc.TransactionCurrency,budgetAmount,true);
}
if(exbudget >= currentAmount)
{
ret = true;
}
else
{
/* if(_detailResult)
{
ttsbegin;
_detailResult.selectForUpdate(true);
_detailResult.AccountingCurrencyAmountOverAvailable = currentAmount - exbudget;
_detailResult.update();
ttscommit;
} */
Amount value = currentAmount - exbudget;
if(!errormsg)
{
errormsg = strFmt("@SYS128612",
bUDGETTRANSACTIONHEADERloc.TransactionNumber,
dimensionAttributeValueCombinationlocerror.DisplayValue,
// bUDGETTRANSACTIONLINELoc.displayAccountingAmount(),
value,
bUDGETTRANSACTIONLINELoc.TransactionCurrency);
}
}
}
return ret;
}
public void ttsNotifyPreCommit()
{
BudgetSource budgetSource,budgetSourceloc = currentSource;
BudgetCheckResultErrorWarningDetail _detailResult;
PurchReqLine purchReqLine;
SourceDocumentLine sourceDocumentLine;
VendInvoiceInfoLine vendInvoiceInfoLine;
next ttsNotifyPreCommit();
select forupdate budgetSource
where budgetSource.RecId == budgetSourceloc.RecId;
select purchReqLine
where purchReqLine.SourceDocumentLine == budgetSourceloc.SourceDocumentLine;
PurchReqTable purchReqTable =PurchReqTable::find(purchReqLine.PurchReqTable);
if(budgetSource && budgetSource.CheckResult == BudgetCheckResult::Failed && strStartsWith(purchReqTable.YNV_PurchReqStatus,"DoA"))
{
ttsbegin;
budgetSource.selectForUpdate(true);
budgetSource.CheckResult = BudgetCheckResult::PassedWithWarnings;
budgetSource.update();
ttscommit;
}
select * from vendInvoiceInfoLine
where vendInvoiceInfoLine.SourceDocumentLine == budgetSourceloc.SourceDocumentLine;
// VendInvoiceInfoTable VendInvoiceInfoTable = VendInvoiceInfoTable::find(vendInvoiceInfoLine.SourceDocumentLine);
if(budgetSource && budgetSource.CheckResult == BudgetCheckResult::Failed && vendInvoiceInfoLine && purchReqTable)
{
ttsbegin;
budgetSource.selectForUpdate(true);
budgetSource.CheckResult = BudgetCheckResult::PassedWithWarnings;
budgetSource.update();
ttscommit;
}
result = this.checkBudgetAmount(budgetSourceloc,_detailResult);
if(result)
{
select forupdate budgetSource
where budgetSource.RecId == budgetSourceloc.RecId;
if(budgetSource)
{
ttsbegin;
budgetSource.selectForUpdate(true);
budgetSource.CheckResult = BudgetCheckResult::Passed;
budgetSource.update();
ttscommit;
}
}
else
{
if(errormsg)
{
select forupdate _detailResult
where _detailResult.BudgetSource == budgetSourceloc.RecId;
if(_detailResult)
{
ttsbegin;
_detailResult.CheckResult = BudgetCheckResult::Failed;
_detailResult.update();
ttscommit;
}
select forupdate budgetSource
where budgetSource.RecId == budgetSourceloc.RecId;
if(budgetSource)
{
ttsbegin;
budgetSource.selectForUpdate(true);
budgetSource.CheckResult = BudgetCheckResult::Failed;
budgetSource.update();
ttscommit;
}
// throw Error(errormsg);
}
}
}
protected boolean determineMessagesForCheckResultDetails(
LedgerRecId _primaryLedgerId,
BudgetCheckResultErrorWarningDetail _detailResult,
BudgetCheckResultErrorWarningDetail _groupResult)
{
BudgetSource budgetSource;
BUDGETTRANSACTIONLINE bUDGETTRANSACTIONLINE;
BudgetTransactionHeader bUDGETTRANSACTIONHEADERloc;
str toCompany;
select budgetSource
where budgetSource.RecId == _detailResult.budgetSource;
select bUDGETTRANSACTIONLINE
where bUDGETTRANSACTIONLINE.RecId == budgetSource.BudgetTransactionLine;
select bUDGETTRANSACTIONHEADERloc
where bUDGETTRANSACTIONHEADERloc.RecId == bUDGETTRANSACTIONLINE.BudgetTransactionHeader;
boolean ret,check;
if(bUDGETTRANSACTIONHEADERloc.YNV_TransferCrossCompany == NoYes::Yes && /*bUDGETTRANSACTIONLINE.YNV_ToCompany != curExt() && */ bUDGETTRANSACTIONLINE.displayAccountingAmount() < 0)
{
result = this.checkBudgetAmount(budgetSource,_detailResult);
ttsbegin;
_detailResult.selectForUpdate(true);
_detailResult.CheckResult = BudgetCheckResult::Passed;
_detailResult.update();
ttscommit;
}
ret = next determineMessagesForCheckResultDetails(_primaryLedgerId,_detailResult,_groupResult);
return ret;
}
public void ttsNotifyCommit()
{
next ttsNotifyCommit();
if(errormsg)
{
throw Error(errormsg);
}
}
}