Thursday, March 17, 2022

Lookup, JumpRef, Modified for a form data source field through CoC

 As  explained in his old article https://community.dynamics.com/365/financeandoperations/b/ievgensaxblog/posts/d365foe-how-to-override-form-data-source-field-lookup-method, it is much better to override methods directly on a data source field than on its linked form controls.

I just want to re-iterate it and place here code snippets.


  • User can add new control using form personalization and this control won’t support overridden logic. It could be critical if you are restricting field lookup values or adding validations.
  • One form could have several controls that refers to one data source field so you have to duplicate your code.
  • Number of delegates are limited as well.
So, say we need to implement Lookup, JumpRef, and Modified methods for a custom field on CustInvoiceTable data source of CustFreeInvoice form. Implement these three aforementioned methods, e.g., directly in an extension to the form class.

 
[ExtensionOf(formStr(CustFreeInvoice))]
final class myCustFreeInvoice_Form_Extension
{
    public void myAssignedBankAccountIdModified(FormDataObject _targetField)
    {
       <logic>
    }
    public void myAssignedBankAccountIdJumpRef(FormDataObject _targetField)
    {
       <logic>
}
    // Different parameter here!
    public void myAssignedBankAccountIdLookup(FormStringControl _callingControl)
    {
       <logic>
    }

Now simply override them for the field when the data source is initialized.
 
public class myCustFreeInvoice_Form_EventHandler
{
    [FormDataSourceEventHandler(formDataSourceStr(CustFreeInvoice, CustInvoiceTable), FormDataSourceEventType::Initialized)]
    public static void myCustInvoiceTable_OnInitialized(FormDataSource _sender, FormDataSourceEventArgs _e)
    {
        FormRun         eogFormRun                  = _sender.formRun();
        FormDataObject  eogCustomField              = _sender.object(fieldNum(CustInvoiceTable, eogCustomField));
fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, jumpRef), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdJumpRef), myFormRun); fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, lookup), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdLookup), myFormRun); fdoEOGAssignedBankAccountId.registerOverrideMethod(methodStr(FormDataObject, modified), formMethodStr(CustFreeInvoice, myAssignedBankAccountIdModified), myFormRun); }

Monday, March 7, 2022

How to populate custom fields in GeneralJournalAccountEntry from LedgerJournalTrans for Ledger, Customer, Vendor, and Bank account type

 Say, we need to add a new field UniqueId to LedgerJournalTrans and then have it populated in GeneralJournalAccountEntry, once a General journal posted.



In other words the field value must be transferred from a general journal line to a related voucher transaction.


Generally speaking there are two different ways how GL transactions created in D365FO: via Source document framework and via LedgerVoucherObject. Moreover, one transaction may be a result of summarization of multiple documents. So, this approach works for this particular scenario, when GL transactions come from a general journal. The proposed solution covers Ledger, Customer, Vendor, and Bank types. You can elaborate it for Project, Fixed Asset, etc. Check their appropriate classes.

LedgerJournalCheckPost class creates one transaction per a line of Ledger type, two if the latter has an offset info.



When it comes to other transaction type, first, a transaction in CustTransVendTransBankTrans etc is created, and then based on the latter a new transaction is added.




So, we creates the following extensions.

Tables.





Classes.




Below, you can find code snippets for each of them.

BankVoucher_Extension

[ExtensionOf(classStr(BankVoucher))]
final class BankVoucher_Extension
{
    public UniqueId UniqueId;


    public UniqueId parmUniqueId(UniqueId _parm = uniqueId)
    {
        uniqueId = _parm;

        return uniqueId;
    }


    protected LedgerVoucherTransObject initializeLedgerVoucherTransObjectForPosting(LedgerVoucherObject _ledgerVoucherObject, CurrencyExchangeHelper _exchangeRateHelper)
    {
        LedgerVoucherTransObject ledgerVoucherTransObject = next initializeLedgerVoucherTransObjectForPosting(_ledgerVoucherObject, _exchangeRateHelper);
        if(ledgerVoucherTransObject)
{ ledgerVoucherTransObject.parmUniqueId(_ledgerVoucherObject.parmUniqueId()); } return ledgerVoucherTransObject; } }

CustVendVoucher_Extension

[ExtensionOf(classStr(CustVendVoucher))]
final class CustVendVoucher_Extension
{
    public UniqueId uniqueId;
    public UniqueId parmUniqueId(UniqueId _parm = uniqueId)
    {
        uniqueId = _parm;

        return uniqueId;
    }

   protected LedgerVoucherTransObject createLedgerVoucherTransObject(boolean _useSubLedger,
                                                                     LedgerDimensionAccount _ledgerDimensionMerged,
                                                                     LedgerJournalTrans _ledgerJournalTrans,
                                                                     LedgerVoucher _ledgerPostingJournal,
                                                                     CustVendTrans _custVendTrans)
    {
        LedgerVoucherTransObject ledgerVoucherTransObject = next createLedgerVoucherTransObject( _useSubLedger, _ledgerDimensionMerged, _ledgerJournalTrans, _ledgerPostingJournal, _custVendTrans);
        if(ledgerVoucherTransObject)
{ ledgerVoucherTransObject.parmUniqueId(uniqueId); } return ledgerVoucherTransObject; } }

LedgerJournalCheckPost_Extension

[ExtensionOf(classStr(LedgerJournalCheckPost))]
final class LedgerJournalCheckPost_Extension
{

    protected LedgerVoucherObject createPostingReference(LedgerJournalTrans _ledgerJournalTrans, SysModule _sysModule)
    {
        LedgerVoucherObject newVoucher = next  createPostingReference(_ledgerJournalTrans, _sysModule);
        if(newVoucher)
{ newVoucher.parmUniqueId(_ledgerJournalTrans.uniqueId); } return newVoucher; } protected LedgerVoucherObject updatePostingReference(LedgerVoucherObject _postingReference, LedgerJournalTrans _ledgerJournalTrans, SysModule _sysModule) { next updatePostingReference(_postingReference, _ledgerJournalTrans, _sysModule); if(_postingReference)
        {     _postingReference.parmUniqueId(_ledgerJournalTrans.uniqueId);         } return _postingReference; } }

LedgerJournalTransUpdateBank_Extension

[ExtensionOf(classStr(LedgerJournalTransUpdateBank))]
final class LedgerJournalTransUpdateBank_Extension
{

    protected BankVoucher initBankVoucher(  LedgerJournalTrans _ledgerJournalTrans,
                                            TaxAmount _taxAmount,
                                            real _taxWithholdAmount,
                                            DimensionDefault _defaultDimension,
                                            LedgerJournalType _ledgerJournalType,
                                            boolean _skipDimensionValidation)
    {
        BankVoucher bankVoucher = next initBankVoucher(_ledgerJournalTrans, _taxAmount, _taxWithholdAmount, _defaultDimension, _ledgerJournalType, _skipDimensionValidation);
        if(bankVoucher)
        {     bankVoucher.parmUniqueId(_ledgerJournalTrans.uniqueId);         } return bankVoucher; } }

LedgerVoucherObject_Extension

[ExtensionOf(classStr(LedgerVoucherObject))]
final class LedgerVoucherObject_Extension
{
    public UniqueId uniqueId;

    public UniqueId parmUniqueId(UniqueId _parm = uniqueId)
    {
        uniqueId = _parm;

        return uniqueId;
    }

}

LedgerVoucherTransObject_Extension

[ExtensionOf(classStr(LedgerVoucherTransObject))]
final class LedgerVoucherTransObject_Extension
{
    public UniqueId uniqueId;

    public UniqueId parmUniqueId(UniqueId _parm = uniqueId)
    {
        generalJournalAccountEntry.UniqueId  = _parm;
        return generalJournalAccountEntry.UniqueId;
    }

   
    public static LedgerVoucherTransObject newTransLedgerJournal(
                                                                    LedgerJournalTrans  _ledgerJournalTrans,
                                                                    TaxAmount           _taxAmount,
                                                                    boolean             _bridging,
                                                                    container           _intercompanyRecIds,
                                                                    boolean             _reversalsMayExist,
                                                                    boolean             _forcedExchangeRate)
    {
        LedgerVoucherTransObject ledgerVoucherTransObject = next newTransLedgerJournal(_ledgerJournalTrans, _taxAmount, _bridging, _intercompanyRecIds, _reversalsMayExist, _forcedExchangeRate);
        if(ledgerVoucherTransObject)
        {     ledgerVoucherTransObject.parmUniqueId(_ledgerJournalTrans.UniqueId);         } return ledgerVoucherTransObject; } public LedgerPostingTransactionTmp getLedgerPostingTransaction() { LedgerPostingTransactionTmp ledgerPostingTransaction = next getLedgerPostingTransaction(); ledgerPostingTransaction.UniqueId = generalJournalAccountEntry.UniqueId; return ledgerPostingTransaction; } public void initFromLedgerPostingTransaction(LedgerPostingTransactionTmp _ledgerPostingTransaction,LedgerPostingTransactionProjectTmp _projectPostingTransaction) { next initFromLedgerPostingTransaction(_ledgerPostingTransaction,_projectPostingTransaction); generalJournalAccountEntry.UniqueId = _ledgerPostingTransaction.UniqueId; } public static LedgerVoucherTransObject newTransactionAccountingAmountsDefault( LedgerVoucherObject _defaultLedgerPostingReference, LedgerPostingType _postingType, RecId _ledgerDimensionId, CurrencyCode _transactionCurrencyCode, Money _transactionCurrencyAmount, MoneyMST _accountingCurrencyAmount, CurrencyExchangeHelper _currencyExchangeHelper) { LedgerVoucherTransObject postingTrans; postingTrans = next newTransactionAccountingAmountsDefault(_defaultLedgerPostingReference, _postingType, _ledgerDimensionId, _transactionCurrencyCode, _transactionCurrencyAmount, _accountingCurrencyAmount, _currencyExchangeHelper);         if(postingTrans)
        {     postingTrans.parmUniqueId(_defaultLedgerPostingReference.parmUniqueId());         } return postingTrans; } }

I wish to credit the following articles I used:

http://axforum.info/forums/showthread.php?t=74038

https://allaboutdynamic.com/2018/06/25/d365-ax7-update-custom-fields-in-custtrans-vendtrans-from-ledgerjournaltrans-during-the-posting-of-journal/

http://axwiki.blogspot.com/2017/01/customize-field-in-ledgerjournaltabletr.html