Tuesday, February 17, 2026

Extending Standard Budget Validation with Line-Level Legal Entity Customization

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);
        }
    }

 

}

 

No comments:

Post a Comment