Running custom X++ scripts in Production


Running custom X++ scripts without any downtime?

In 10.0.25 you can run simple X++ scripts on a production environment without any downtime.

This feature lets you run custom X++ scripts without having to go through Dynamics LCS or suspend your system. Therefore, you can correct minor data inconsistencies without causing any disruptive downtime.

Script details page.

Read more :

https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/deployment/run-custom-scripts

Settle payment journal against sales invoice in D365 FinOpsApps


Code used to settle posted payment journal transaction against the sales invoice

// <summary>
    /// Settle payment journal (which still has balance) against sales invoice. Each payment journal is make for one sales order only.
    /// No payment is made for multiple order. If balance is available after settle, leave the balance as there might be another invoice
    /// not comes in yet for the same order. This periodic job will settle against them when the invoice is in.
    /// </summary>
    /// <param name = "_contract"></param>
    public void processSettlement(AG_CustSalesPaymSettlementDataContract _contract)
    {
        RefRecId            paymLedgerJournalTransRefRecId = _contract.parmPaymLedgerJournalTransRecId();
        boolean             showInfoLog                    = _contract.parmShowInfoLog();
        LedgerJournalTable  paymLedgerJournalTable;
        LedgerJournalTrans  paymLedgerJournalTrans;
        CustTransOpen       paymCustTransOpen, custTransOpen;
        CustTrans           paymCustTrans;

        //Loop through all payment journal which still has open balance
        while select paymLedgerJournalTable
            where   paymLedgerJournalTable.Posted       == NoYes::Yes
            join    paymLedgerJournalTrans
            where   paymLedgerJournalTrans.JournalNum   == paymLedgerJournalTable.JournalNum
                &&  ((!paymLedgerJournalTransRefRecId)                                      //If specific payment journal line is provided, get that only,
                ||   (paymLedgerJournalTrans.RecId      == paymLedgerJournalTransRefRecId)) //else, get all lines (which satisfy other query criteria)
            join    paymCustTrans
            where   paymCustTrans.Voucher               == paymLedgerJournalTrans.Voucher
                &&  paymCustTrans.RecId                 == paymLedgerJournalTrans.CustTransId
                &&  paymCustTrans.TransType             == LedgerTransType::Payment
            join    paymCustTransOpen
            where   paymCustTransOpen.RefRecId          == paymCustTrans.RecId
        {
           AG_CustSalesPaymSettlementService::settleByPaymJourTrans(paymLedgerJournalTrans, showInfoLog);
        }

    }

    public static void settleByPaymJourTrans(LedgerJournalTrans _paymLedgerJournalTrans, boolean _showInfoLog)
    {
        boolean             useLegacyMethod = false;
        CustTable           custTable;
        LedgerJournalTrans  paymLedgerJournalTrans;
        CustTransOpen       invCustTransOpen, paymCustTransOpen, custTransOpen;
        CustTrans           invCustTrans, paymCustTrans;
        CustInvoiceJour     custInvoiceJour;
        SpecTransManager    manager;
        CustVendTransData   custVendTransData;

        //Given the payment LedgerJournalTrans, find the related CustTrans which has CustTransOpen
        select firstonly paymLedgerJournalTrans
            where   paymLedgerJournalTrans.RecId  == _paymLedgerJournalTrans.RecId
            join    paymCustTrans
            where   paymCustTrans.Voucher         == paymLedgerJournalTrans.Voucher
                &&  paymCustTrans.RecId           == paymLedgerJournalTrans.CustTransId
                &&  paymCustTrans.TransType       == LedgerTransType::Payment
            join    paymCustTransOpen
            where   paymCustTransOpen.RefRecId    == paymCustTrans.RecId;

        //Find the related invoice to be settled against the payment journal in the query above
        select firstonly invCustTrans
            where   invCustTrans.AccountNum      == paymCustTrans.AccountNum
                &&  invCustTrans.MCRPaymOrderID  == paymCustTrans.MCRPaymOrderID
                &&  invCustTrans.TransType       == LedgerTransType::Sales
            join    invCustTransOpen
            where   invCustTransOpen.RefRecId    == invCustTrans.RecId;

        custTable = CustTable::find(paymCustTrans.AccountNum);

        try
        {
            ttsbegin;

            if(paymCustTransOpen && invCustTransOpen)
            {
                //Legacy code for settlement --------------------------------------------------------------------------------------------------------
                if(useLegacyMethod)
                {
                    //Create an object of the CustVendTransData class with the invoice transaction as parameter and mark it for settlement
                    custVendTransData = CustVendTransData::construct(invCustTrans);
                    custVendTransData.markForSettlement(custTable);

                    //Create an object of the CustVendTransData class with the payment transaction as parameter and mark it for settlement
                    custVendTransData = CustVendTransData::construct(paymCustTrans);
                    custVendTransData.markForSettlement(custTable);

                    // Settle all transactions marked for settlement for this customer
                    CustTrans::settleTransact(custTable, null, true, SettleDatePrinc::DaysDate, systemdateget());
                }
                //New code for settlement -----------------------------------------------------------------------------------------------------------
                else
                {
                    //Mark for settlement
                    SpecTransExecutionContext specTransExecutionContext = SpecTransExecutionContext::newFromSource(custTable);
                    SpecTransManager          specTransManager          = SpecTransManager::construct(specTransExecutionContext.parmSpecContext());
                    Amount                    settleAmount              = invCustTransOpen.AmountCur;

                    //Prevent over settle
                    if(settleAmount > (-paymCustTransOpen.AmountCur))
                        settleAmount = (-paymCustTransOpen.AmountCur);

                    //Payment
                    specTransManager.insert(paymCustTransOpen.DataAreaId,
                                            paymCustTransOpen.TableId,
                                            paymCustTransOpen.RecId,
                                            -settleAmount,
                                            paymCustTrans.CurrencyCode);
            
                    //Invoice
                    specTransManager.insert(invCustTransOpen.DataAreaId,
                                            invCustTransOpen.TableId,
                                            invCustTransOpen.RecId,
                                            settleAmount,
                                            invCustTrans.CurrencyCode);
                
                    //Settle
                    if(CustTrans::settleTransaction(specTransExecutionContext, CustTransSettleTransactionParameters::construct()))
                    {
                        if(_showInfoLog)
                            info(strFmt("@AG:AG_SettlementCompletedFor", invCustTrans.MCRPaymOrderID, invCustTrans.Invoice, settleAmount)); //Label: Settlement completed for Sales order %1, Invoice %2, Amount %3
                    }
                }
            }

            ttscommit;
        }
        catch
        {
            error(strFmt("@AG:AG_SettlementForPaymentJournalLineFailed", _paymLedgerJournalTrans.RecId, _paymLedgerJournalTrans.accountDisplay())); //label: Settlement for payment journal line is unsuccessful (RecId: %1, Account: %2)
        }
    }

What are the differences between addOrderByField and addSortField


With addSortField you can set “only” the records order.

With AddOrderByField you can build some logic because is used the kernel class QueryOrderByField.

So, you can use the follow methods :
– direction
– autoHeader
– autoHeaderDetailLevel
– autoSum
– autoSumDetailLevel
– datasource
– fieldId

You can find some examples on the standard class :

– DimensionProvider Class, getDimensionOrderBysFromQuery method
– InventDimCtrl_Frm_OnHand class, modifyQuery method

How to get Label Id from a text


If you want retrieve the Label ID from a specific text description, here the code.
If are present more Label ID for a specific text, you will have the first.

sysLabelEdit     sysLabelEdit = New sysLabelEdit();
labelid          labelid;
str              text = “Customer account”;
str              specialCharsText;

specialCharsText = SysLabel::searchStringBuildSpecialCharString(text);
specialCharsText = SysLabel::seachStringBuildExactStr(specialCharsText);

labelid = sysLabelEdit.findLabel(“en-us”, specialCharsText);

info ( labelid );

Cascade+Restricted Concept in Ax 2012Ax


Step 1:
Create 3 tables for an example :

Table 1- SheetTable, with Two fields Sheetid and sheetname
Table 2-PartitionTable with three fields sheetid , partitionid and sheetsize
Table 3-SheetPartitionTable with two fields partitionid and Shape 

Step 2:

1) Create a relationship between SheetTable and PartitionTable (Ex:PartitionTable.SheetID==SheetTable.SheetId) 

2) Create a relationship between PartitionTable and SheetPartitionTable(EX:SheetPartitionTable.PartitionID==PartitionTable.PartitionID)

Step 3:

1) Create Cascade DeleteAction between SheetTable and PartitionTable

2) Create Cascade+Restricted DeleteAction between PartitionTable and SheetPartitionTable

Step 4:
Open SheetTable and delete the matched record with PartitionTable.

Automatically the matched record from SheetTable , PartititonTable and SheetPartitionTable will be deleted .

Get the phone number of the Delivery Address in the Purchase Order


static void getphoneNumber(Args _args)
{
PurchTable purchTable;
LogisticsLocation logisticslocation;
LogisticsPostalAddress logisticsPostalAddress;
select purchTable where purchTable.PurchId==”P000059″;
select logisticslocation where logisticslocation.ParentLocation ==
LogisticsPostalAddress::findRecId(purchTable.DeliveryPostalAddress).Location;
info(LogisticsElectronicAddress::findByLocation(logisticslocation.RecId).Description);
info(LogisticsElectronicAddress::findByLocation(logisticslocation.RecId).Locator);
}

Validate the Special Characters from the given String in Ax 2012


X++ code to validate the special characters from the given string

static void RemoveSpecialCharacters(Args _args)
{str stringVar1,stringVar2;

//String with special characters and numbers
stringVar1= test!@#$%^&*(){}[]|\+-;,.?/~`12344;

//String without Special characters and  numbers
stringVar2=strRem(strAlpha(stringVar1),”1234567890″);

if(stringVar2!=stringVar1 )
{          throw error(“Enter Valid data”);
}else
{            info(“ok”);
}
}