Tuesday, December 2, 2025

Override custom dimension value on posting sales invoice in X++

 Requirement:

1. Override custom dimension value on posting sales invoice

2.  Ledger posting type as "Cost of goods, invoiced" & "Sales revenue"

3. Reason: Requirement is to default for certain orders type, these account has to be changed. 

4. Why can't we acheive in Customer or item level dimension. [Reason: Currently it was managed in item level, but requirement is to for same item if order type met certain criteria on posting, this need to defaulted with this dimension value for ledger reporting]


Class 1:

 

/// <summary>

///    The <c>LedgerVoucherTransObject</c> class represents a single transaction in an individual voucher. COC

/// </summary>

/// <remarks>

///    The transaction is stored in a temporary instance of a <see cref="T:LedgerTrans" /> record buffer.

///    The temporary transaction is inserted into the database during posting and made a permanent record.

/// </remarks>

[ExtensionOf(ClassStr(LedgerVoucherTransObject))]

final class LedgerVoucherTransObjectCls_SAN_Extension

{

    /// <summary>

    ///    Initializes a new instance of the <c>LedgerVoucherTransObject</c> class by using a transaction COC POL

    ///    currency amount and a ledger posting reference for defaulting.

    /// </summary>

    /// <param name="_defaultLedgerPostingReference">

    ///    The ledger posting reference to use for defaulting.

    /// </param>

    /// <param name="_postingType">

    ///    The posting type of the general journal entry.

    /// </param>

    /// <param name="_ledgerDimensionId">

    ///    The dimension attribute value combination of the general journal entry.

    /// </param>

    /// <param name="_transactionCurrencyCode">

    ///    The currency code of the general journal entry.

    /// </param>

    /// <param name="_transactionCurrencyAmount">

    ///    The amount in the transaction currency.

    /// </param>

    /// <param name="_exchangeRateHelper">

    ///    The accounting currency amount and secondary currency amount exchange rates.

    /// </param>

    /// <returns>

    ///    A new instance of the <c>LedgerVoucherTransObject</c> class.

    /// </returns>

    /// <remarks>

    ///    The default ledger posting reference is used to set the transaction type and exchange rate date.

    /// </remarks>

    public static LedgerVoucherTransObject newTransactionAmountDefault(

        LedgerVoucherObject _defaultLedgerPostingReference,

        LedgerPostingType _postingType,

        LedgerDimensionAccount _ledgerDimensionId,

        CurrencyCode _transactionCurrencyCode,

        Money _transactionCurrencyAmount,

        CurrencyExchangeHelper _exchangeRateHelper)

    {

        LedgerVoucherTransObject polpostingTrans;

        LedgerDimensionAccount  ledgerDimensionAccount, tempLedgerDimenionAcc;

        ledgerDimensionAccount = _ledgerDimensionId;

 

        if(ledgerDimensionAccount && (_postingType == LedgerPostingType::SalesConsump

            || _postingType == LedgerPostingType::SalesRevenue))

        {

            SAN_SalesInvoiceDimensionMockContext contextCur = SAN_SalesInvoiceDimensionMockContext::current();

            if(contextCur != null)

            {

                if(contextCur.isParameterActive && contextCur.isValidToOverride && contextCur.polproductLineToOverride)

                {

                    tempLedgerDimenionAcc = _ledgerDimensionId;

 

                    ledgerDimensionAccount = SalesInvoiceJournalPost::SAN_buildDefaultAndLedgerDimension(tempLedgerDimenionAcc,contextCur.polproductLineToOverride);

                }

            }

        }

 

        polpostingTrans = next newTransactionAmountDefault(_defaultLedgerPostingReference, _postingType, ledgerDimensionAccount, _transactionCurrencyCode, _transactionCurrencyAmount, _exchangeRateHelper);

 

        return polpostingTrans;

    }

 

}

 

 

Class 2:

/// <summary>

/// To hold the value of SAN_SalesInvoiceDimensionMockContext through out the runtime.

/// </summary>

class SAN_SalesInvoiceDimensionMockContext implements System.IDisposable

{

    public  boolean  isParameterActive;

    public  boolean  isValidToOverride;

    public  SalesTable      polsalesTable;

    public  str             polsmmSegmentId;

    public  str             polproductLineToOverride;

    static  SAN_SalesInvoiceDimensionMockContext   instance;

 

    protected void new ()

    {

        if (instance)

        {

            throw Error('Nesting of SAN_SalesInvoiceDimensionMockContext is not supported');

        }

 

        instance = this;

    }

 

    /// <summary>

    ///  To Create the instance wherever the method is called during the run time.

    /// </summary>

    /// <returns>current new instance</returns>

    Public static SAN_SalesInvoiceDimensionMockContext createInstance()

    {

        SAN_SalesInvoiceDimensionMockContext newInstance = new SAN_SalesInvoiceDimensionMockContext();

        instance = newInstance;

 

        return instance;

    }

 

    /// <summary>

    /// Dispose the instance once the Aging snapshot batch is run.

    /// </summary>

    public void dispose()

    {

        instance = null;

    }

 

    /// <summary>

    ///  To get the instance wherever the method is called during the run time.

    /// </summary>

    /// <returns>Current instance</returns>

    public static SAN_SalesInvoiceDimensionMockContext current()

    {

        return instance;

    }

 

}

 

 

Class 3:

/// <summary>

/// Extension of class SalesInvoiceJournalPost

/// </summary>

[Extensionof (classstr(SalesInvoiceJournalPost))]

Public Final class SalesInvoiceJournalPostCls_SAN_Extension

{

    /// <summary>

    ///     Posts to inventory.

    /// </summary>

    protected void postInventory()

    {

        using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())

        {

            if(SalesParameters::find().SAN_OverrideDimensionValue)

            {

                contextSet.isParameterActive = true; 

                SalesTable      salesTable;

                salesTable =  salesLine.SalesTable();

                if(salesTable && salesLine)

                {

                     contextSet.polsalesTable = salesTable;

                        contextSet.isValidToOverride = true;

                        contextSet.polproductLineToOverride = '09';

                }

            }

            next postInventory();

        }

    }

 

    /// <summary>

    ///     Posts one journal line.

    /// </summary>

    protected void postLine()

    {

        using(SAN_SalesInvoiceDimensionMockContext contextSet = SAN_SalesInvoiceDimensionMockContext::createInstance())

        {

           if(SalesParameters::find().SAN_OverrideDimensionValue)

            {

                contextSet.isParameterActive = true;

 

                SalesTable      salesTable;

                salesTable = salesParmLine.SalesLine().SalesTable();

                if(salesTable && salesParmLine  )

                {

                   contextSet.polsalesTable = salesTable;

                        contextSet.isValidToOverride = true;

                        contextSet.polproductLineToOverride = '09';

                }

            }            

            next postLine();

        }

    }

 

    /// <summary>

    /// buildDefaultAndLedgerDimension for govt and non-govt segment

    /// </summary>

    /// <param name = "_ledger">LedgerDimensionAccount</param>

    /// <param name = "_overridePL">overridePL</param>

    /// <returns>ledgerDimensionAccount</returns>

    Static ledgerDimensionAccount  SAN_buildDefaultAndLedgerDimension(LedgerDimensionAccount   _ledger, str _overridePL)

    {

        DimensionAttributeValueSetStorage   dimensionAttributeValueSetStorage;

        DimensionAttributeValue             dimensionAttributeValue;

        DimensionDefault                    dimensionDefault;

        LedgerDimensionAccount              ledgerDimensionAccount;

        DimensionAttributeLevelValueAllView dimAttrValueallview;

        dimensionAttributeValueSetStorage = new DimensionAttributeValueSetStorage();

        RefRecId            mainAccountRecId, LedgerDimensionAcc;

        mainAccountRecId = LedgerDimensionFacade::getMainAccountRecIdFromLedgerDimension(_ledger);

        LedgerDimensionAcc = LedgerDefaultAccountHelper::getDefaultAccountFromMainAccountRecId(mainAccountRecId);

 

        while select dimAttrValueallview 

            where dimAttrValueallview.ValueCombinationRecId == _ledger

        {

            if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name != "MainAccount")

            {

                if(DimensionAttribute::find(dimAttrValueallview.DimensionAttribute).Name == "ProductLine")

                {

                    dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(

                                    DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),

                                    _overridePL, false, true);

                }

                else

                {

                    dimensionAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValue(

                                    DimensionAttribute::find(dimAttrValueallview.DimensionAttribute),

                                    dimAttrValueallview.DisplayValue, false, true);

                }

                dimensionAttributeValueSetStorage.addItem(dimensionAttributeValue);

                dimensionDefault = dimensionAttributeValueSetStorage.save();

            }

        }

        ledgerDimensionAccount = LedgerDimensionFacade::serviceCreateLedgerDimension(LedgerDimensionAcc,dimensionDefault);

        return ledgerDimensionAccount;

    }

 

}

No comments:

Post a Comment

Dynamically setting entire Form security access through Extension in D365FO

/// <summary> /// To check if user can get access to the Parameter form /// </summary> class SAN_ParamFormsAccessCtrl {     prot...