Thursday, 8 August 2024

Run CAR(Customization Analysis report) in Dynamics 365 for Finance and operations

Customization Analysis Report tool analyzes your customization and extension models, and runs a predefined set of best practice rules. The report is in the form of a Microsoft Excel workbook. Steps to generate the report 1) Get the latest code in your dev machine where you want to run the CAR.Build and Sync the environemnt. 2) Locate the xppbp.exe tool in c:\packages\bin or I:\AosService\PackagesLocalDirectory\bin. 3) Run the following command in your development environment. Copy xppbp.exe -metadata= -all -model= -xmlLog=C:\BPCheckLogcd.xml -module= -car= 4) If your custom model references an ISV model, then you must include the -PackagesRoot parameter at the end of the command. Copy xppbp.exe -metadata= -all -model= -xmlLog=C:\BPCheckLogcd.xml -module= -car= -packagesroot=K:\AosService\PackagesLocalDirectory Example : xppbp.exe -metadata=C:\Packages -all -model="MyCustomModel" -xmlLog=C:\temp\BPCheckLogcd.xml -module="MyCustomModel" -car=c:\temp\CAReport.xlsx All best practice rules (errors, warnings, or informational messages) will appear on the Issues List page . Issues are of the metadata or code type.

How to load number sequence class in UAT\PROD in dynamics 365 for finance and operations.

In any Development environment number sequences are loaded by executing the runnable class , but for UAT or production we cannot access the Visual studio. Hence in UAT or production server number sequences can be loaded by executing teh runnable class in the dynamics url as below. [Dynamics base URL][/?cmp=company used]&mi=SysClassRunner&cls=[job/runnable class name] For instance, if the number sequences runnable class name is testNumberSeqLoadModule, add the class name after base url as SysClassRunner&cls=testNumberSeqLoadModule

Wednesday, 22 June 2022

How to Extend Purchase Order Update Functionality to Purchase lines in D365

 To extend header field updates to line level is to use extensions and delegates in D365.  

Scenario : DlvMode field from PurchTable should be carried and updated to PurchLine.DlvMode field.

Extend the data model

Extend Purchline table in customized model and add DlvMode field to the extension table .


Add DlvMode field to PurchTable fieldGroup HeaderToLineUpdate



Prepare the update-order-lines dialog

The dialog to choose if and which fields need to be updates at the lines is generated automatically based on the HeaderToLineUpdate field group. There is some code needed to show the fields name in the dialog. This is done by subscribing a custom method to the delegate PurchTable2LineField.getFieldDescriptionDelegate.




Create a new class with below code


Extend the framework classes

Create an extension for the AxPurchLinee class and add the below code :



Build your code .

Open the Header to Line update dialog by clicking on Procurement and Sourcing > Setup > Procurement and Sourcing  parameters > General update > update order lines button 



Done!! Go ahead and test your code.

Change value for DlvMode in Purchase order header update Order lines dialog will open as below. Enable "Update Delivery mode", and select "Update all" and click OK.The DlvMode value from header will get updated at line level DlvMode value.




Happy Coding!!!!


Thanks & Regards

Sindhu 




Wednesday, 9 February 2022

Ax 2012\D365 : Cheque creation code

                     Ax 2012\D365 : Cheque creation code 

public void createCheque(Args args)
    {
        LedgerJournalTrans                ledgerJournalTrans;
        BankAccountTable                   bankAccountTable;
        BankChequeTable                    bankChequeTable;
        DimensionAttributeValueCombination dimensionAttributeValueCombination;
        select  firstonly forupdate ledgerJournalTrans
            where ledgerJournalTrans.JournalNum == '12345' &&
                  ledgerJournalTrans.linenum    == 1;                                                                                                          ledgerJournalTrans.LineNum      == 1;
        if (ledgerJournalTrans.AmountCurDebit)
        {
            select firstonly DisplayValue
                from  dimensionAttributeValueCombination
                    where dimensionAttributeValueCombination.RecId == ledgerJournalTrans.LedgerDimension;
            bankChequeTable.clear();
            bankChequeTable.ChequeNum               =   ledgerJournalTrans.PLI_BankChequeNum;
            bankChequeTable.ChequeStatus            =   ChequeStatus::Payment;
            bankChequeTable.AccountID               =   bankAccountTable.AccountId;
            bankChequeTable.RecipientType           =   BankChequeRecipientType::Cust;
            bankChequeTable.AmountCur               =   ledgerJournalTrans.AmountCurDebit;
            bankChequeTable.BankCurrencyAmount      =   ledgerJournalTrans.AmountCurDebit;
            bankChequeTable.RecipientCompany        =   ledgerJournalTrans.Company;
            bankChequeTable.TransDate               =   staging.TransactionDate ;
            bankChequeTable.CurrencyCode            =   ledgerjournalTrans.CurrencyCode;
            bankChequeTable.BankCurrency            =   ledgerjournalTrans.CurrencyCode;
            bankChequeTable.RecipientAccountNum     =   dimensionAttributeValueCombination.DisplayValue;
            bankChequeTable.Voucher                 =   ledgerjournalTrans.Voucher;
            bankChequeTable.RecipientTransVoucher   =   ledgerjournalTrans.Voucher;
            bankChequeTable.SourceTableId           =   ledgerjournalTrans.TableId;
            bankChequeTable.SourceRecId             =   ledgerjournalTrans.RecId;
            if (BankChequeTable::exist(ledgerJournalTrans.PLI_BankChequeNum, ledgerjournalTrans.PLI_Account))
            {
                checkFailed(strfmt("@SYS24139", bankChequeTable.ChequeNum));
                throw error("@SYS18447");
            }
            bankChequeTable.insert();
            ttsbegin;
            ledgerJournalTrans.BankChequeNum = bankChequeTable.ChequeNum;
            ledgerjournalTrans.PaymentStatus = CustVendPaymStatus::Sent;
            ledgerJournalTrans.PaymReference = bankChequeTable.ChequeNum;
            ledgerJournalTrans.update();
            ttscommit;
        }
    }

Populate LedgerDimension value through code Ax 2012 & D365

Populate LedgerDimension value through code Ax 2012 & D365


public DimensionDynamicAccount getLedgerDimensionId(container _dimensionValue)
    {
        DimensionStorage        dimensionStorage = DimensionStorage::construct(0,      LedgerDimensionType::Account);
        DimensionAttributeValue dimAttributeValue;
        DimensionStorageSegment dimensionStorageSegment;
        DimensionHierarchyLevel dimHierarchyLevel;
        MainAccount             mainAccount;
        Recid                   dimHierarchyId;
        Recid                   mainAccountRecId;
        DimensionValue          dimensionValue;
        container               dimensions;

        for(int i = 1; i<= conLen(_dimensionValue); i++)
        {
            try
            {              
                    // Rest of dimensions
                    if(dimensionValue)
                    {
                        dimAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValueNoError(DimensionAttribute::findByName(conPeek(dimensions, i)), dimensionValue, false, true);
                        if (!dimAttributeValue)
                        {
                            // @JAT:DimensionNotFound = The value '%1' of the dimension '%2' does not exist.
                            throw error(strFmt("DimensionNotFound", dimensionValue, conPeek(dimensions, i)));
                        }
                        dimensionStorageSegment = DimensionStorageSegment::constructFromValue(dimAttributeValue.CachedDisplayValue, dimAttributeValue);
                        dimensionStorage.setSegment(i, dimensionStorageSegment);
                    }
                    else
                    {
                        dimensionStorageSegment = DimensionStorageSegment::emptySegment();
                        dimensionStorage.setSegment(i, dimensionStorageSegment);
                    }
                }
            
            catch
            {
                return 0;
            }
        }
        return dimensionStorage.save();
    }

Monday, 11 January 2021

X++ code to generate ledger voucher number sequence in AX 2012 & D365

 

X++ code to generate ledger voucher number sequence in AX 2012 & D365


NumberSeq numberSeq;
NumberSequenceTable numSeqTable;
Voucher voucher;

select firstOnly numSeqTable
where numSeqTable.RecId == LedgerJournalName::find(ledgerJournalTable.JournalName).NumberSequenceTable;
if (numSeqTable && !voucher)
{
numberseq = numberseq::newGetVoucherFromCode(numSeqTable.NumberSequence);
voucher = numberseq.voucher();
}

ledgerJournalTrans.Voucher = voucher;

Thanks & Regards
Sindhu

Saturday, 2 January 2021

Create Ledger Dimension through Code (x++)

          Create Ledger Dimension through Code (x++)


Microsoft has provided a service class which has a method provided  internally that merges the default dimension and the ledger account that you require.
This works only when you have default dimension & ledgerAccount that you want to merge .


LedgerDimension = DimensionDerivationDistributionRule::buildLedgerDimension(ledgerDimension,DefaultDimension);


Here the parameter Default dimension is the recid contains combination of your dimension values.
LedgerDimension is the LedgerMainAccount that is defaulted when you creating journals.


P.S : Default dimension creation code is provided in my another blog which return the RecId needed as aa parameter 'DefaultDimension' for the method buildLedgerDimension() in the above one liner code.

Blog for default dimension creation code : 

https://sbdynaax.blogspot.com/2021/01/c-reate-default-dimension-with-set-of.html

Thanks & Regards

Sindhu