Tuesday, 5 March 2024

Step-by-Step Guide to Restore a SQL BACPAC File - Microsoft dynamics D365 Fin & Ops

 Restore steps for bacpac file in to SQL server - Microsoft dynamics D365 Fin & Ops.


Log in to LCS and navigate to the asset library. Once there, select the latest database backup file. Click on "Generate SAS link" to obtain a randomly generated URL.

Proceed to the VM and paste the SAS link into the web browser. This action will initiate an automatic download Bacpac file.

After downloading, rename the file and store it in a separate folder.

Stop the all Microsoft Dynamics-related services

Open the command prompt as an administrator and navigate to the directory by entering: "cd C:\Program Files\Microsoft SQL Server\160\DAC\bin".

Replace the URL, file name, and new database name in the following script, then execute it in the command prompt:

"SqlPackage.exe /a:import /sf:I:\Bacpac\backupfilename.bacpac /tsn:localhost /tdn:AxDBNew /p:CommandTimeout=50000 /ttsc:True"

Once done all the above steps and successfully imported need to do alter database, below script for alter database.

USE master; 
GO 
ALTER DATABASE AxDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE; 
GO 
ALTER DATABASE AxDBNew MODIFY NAME = AxDB; 
GO 
ALTER DATABASE AxDB SET MULTI_USER; 
GO

Below script used for enabling user


UPDATE USERINFO
SET USERINFO.ENABLE = 1
FROM USERINFO 
WHERE ID = 'username'




Wednesday, 17 April 2019

Creating a new number sequence in D365


Carry out the following steps in order to complete this recipe:



1. Create a new NumberSequenceModuleCustomer_packet class in the D365 Project that
extends the NumberSequenceModuleCustomer class in the Application and add the
following code snippet at the bottom of the loadModule_Extension() method:

class NumberSequenceCustomer_packet extends NumberSeqModuleCustomer
{
public void loadModule_Extension()
{
NumberSeqDatatype datatype = NumberSeqDatatype::construct();

datatype.parmDatatypeId(extendedTypeNum(CustomerGroupId));
datatype.parmReferenceHelp("Customer group Id");
datatype.parmWizardIsContinuous(false);
datatype.parmWizardIsManual(NoYes::No);
datatype.parmWizardIsChngeDownAllowed(NoYes::Yes);
datatype.parmWizardIsChngeUpAllowed(NoYes::Yes);
datatype.parmWizardHihest(999999);
datatype.parmSortField(20);
datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
this.create(datatype);
}
}


2. Create a new runnable class (Job) with the following lines of code, build the solution and run it:


class loadNumSeqCustPackt
{
public static void Main(Args args)
{
NumberSeqModuleCustomer_packt nymberSeqMod = new
NumberSeqModuleCustomer_packt();

nymberSeqMod.loadModule_Extension();
}

}

3.  Run the number sequence wizard by clicking on the Generate button under Number sequence by going to Organization administration | Common | Number sequence and then click on the Next button, as shown in the following screenshot:



4.  Click on Details to view more information. Delete everything apart from the rows where Area is Accounts receivable and Reference is Customer group. Note the number sequence codes and click on the Next button, as shown here:


5.  On the last page, click on the Finish button to complete the setup, as shown in the  following screenshot:

6.    The newly created number sequences now can be found in the Number sequence
form, as shown in the following screenshot:
7.    Navigate to Organization administration | Number sequences | Segment configuration and notice the new Customer group reference under the Accounts receivable area:
8.    Navigate to Accounts receivable | Setup | Accounts receivable parameters and select the Number sequences tab. Here, you should see the new number sequence code:

9.    The last thing to be done is to create a helper method for this number sequence. Create a new extension class CustParameters_Extension for the CustParameters table and add it to the Dynamics 365 Project and then create the following method and build the solution:



[ExtensionOf(tableStr(CustParameters))]
Final class CustParameters_Extension
{
 client server static NumberSequenceReference numRefCustGroupId()
{
NumberSequenceReference NumberSeqReference;
NumberSeqReference = NumberSeqReference::findReference (extendedTypeNum(CustGroupId));
return NumberSeqReference;
}
}



How it works...

We start the recipe by adding a number sequence initialization code into the NumberSeqModuleCustomer_packt class. As understood from its name, the number sequence initialization code holds the initialization of the number sequences that belong to the Accounts receivable module.

The code in the loadModule_Extension() method defines the default number sequence settings to be used in the wizard, such as the data type, description, and highest possible number. Additional options such as the starting sequence number, number format, and others can also be added here. All the mentioned options can be changed while running the wizard. The addParameterType() method is used to define the number sequence scope. In the example, we created a separate sequence for each Legal entity.

Before we start the wizard, we initialize number sequence references. This should be done as a part of the Dynamics 365 for Finance and Operations initialization checklist, but in this example, we execute it manually by calling the loadModule_Extension() method of the NumberSeqApplicationModule_packt class.

Next, we execute the wizard that will create the number sequences for us. We skip the welcome page and in the second step of the wizard, the Details button can be used to display more options. The options can also be changed later in the Number sequences form before or even after the number sequence is actually used. The last page shows an overview of what will be created. Once completed, the wizard creates new records in the Number sequences form for each company.

The newly created number sequence reference appears in the Segment configuration form. Here, we can see that the Data area checkbox is checked, which means that we will have separate number lists for each company. The number sequence setup can be normally located in the module parameter forms.

Friday, 12 April 2019

Getting company address based on the purpose

static void CompanyAddress(Args _args)
{
    CompanyInfo companyInfo;
    LogisticsPostalAddress  postalAddress;
    DirPartyLocation partyLocation;
    LogisticsLocationRole   locationRole;
    DirPartyLocationRole    partyLocationRole;

    LogisticsEntityPostalAddressView postalAddressView;

   while select companyInfo
           where companyInfo.DataArea == curext()
        join partyLocation
            where partyLocation.Party == companyInfo.RecId
        join postalAddress
            where postalAddress.Location == partyLocation.Location
        join partyLocationRole
            where partyLocationRole.PartyLocation == partyLocation.RecId
        join locationRole
           where partyLocationRole.LocationRole == locationRole.RecId
            && locationRole.Name == strFmt("%1",logisticsLocationRoleType::Delivery)
    {
        info(strFmt("Purpose: %1, IsPrimary: %2, Address %3",locationRole.Type, partyLocation.IsPrimary,  postalAddress.Address));
    }

}

Get customer or vendor email address based on the purpose

static void Vend_CustEmailAddressUsingPurpose(Args _args)
{
    VendTable                           vendTable; //if you need customer you can change CustTable.
    DirPartyLocation                    dirPartyLocation;
    LogisticsElectronicAddress          logisticsElectronicAddress;
    LogisticsElectronicAddressRole      logisticsElectronicAddressRole;
    LogisticsLocationRole               logisticsLocationRole;
   
    select firstOnly vendTable
        where vendTable.AccountNum == '‪‪‪US-105';
   
    while select dirPartyLocation
        where dirPartyLocation.party == vendTable.Party
    {
        while select logisticsElectronicAddress
            where logisticsElectronicAddress.Location == dirPartyLocation.Location
                && logisticsElectronicAddress.Type == LogisticsElectronicAddressMethodType::Email
        {
            while select logisticsElectronicAddressRole
                where logisticsElectronicAddressRole.ElectronicAddress == logisticsElectronicAddress.RecId
                join logisticsLocationRole
                where logisticsLocationRole.RecId == logisticsElectronicAddressRole.LocationRole
                && logisticsLocationRole.Name == strFmt("%1",logisticsLocationRoleType::Business)
            {
                info(strFmt("%1 - %2", logisticsElectronicAddress.Locator, logisticsLocationRole.Name));
            }
        }
    }
}

output:

Friday, 22 March 2019

Event handler inD365


Table event handler:

You need to add a new class to write the event handler methods. I would recommend adding one class to one table.

Once create table extension class must be declared above the class mention the attribute for purpose of the class


ExtensionOf(tableStr(TableName))]


ValidateField:



 // Table Dataeventhandler - ValidateField
 [DataEventHandler(tableStr(TableName), DataEventType::ValidatedField)]
 public static void TableName_onValidatedField(Common sender, DataEventArgs e)
 {
      ValidateFieldEventArgs  event   = e as ValidateFieldEventArgs ;
      TableName buffTable             = sender as TableName;
      boolean result                  = event.parmValidateResult();
 }




 // Table-Posteventhandler for validateField
  [PostHandlerFor(tableStr(TableName), tableMethodStr(TableName, validateField))]
  public static void TableName_Post_validateField(XppPrePostArgs args)
  {
      TableName buffTable = args.getThis();
      FieldId fieldId     = args.getArg("_fieldId");
      boolean ret         = args.getReturnValue();

      //pass the return value
      args.setReturnValue(ret);
  }




initValue:

// Table Post eventhandler for table initvalue
 [PostHandlerFor(tableStr(TableName), tableMethodStr(TableName, initValue))]
 public static void TableName_Post_initValue(XppPrePostArgs args)
 {
      TableName buffTable = args.getThis() as TableName;
 }


// Table pre-event handler for initvalue
 [PreHandlerFor(tableStr(TableName), tableMethodStr(TableName, initValue))]
 public static void TableName_Pre_initValue(XppPrePostArgs args)
 {
     TableName buffTable = args.getThis() as TableName;
 }



Insert:

// Table  - insert Dataeventhandler
 [DataEventHandler(tableStr(TableName), DataEventType::Inserted)]
 public static void TableName_onInserted(Common sender, DataEventArgs e)
 {
     ValidateEventArgs   event   = e as ValidateEventArgs;
     TableName buffTable         =sender as TableName;
 }




Update:

// Table-Posteventhandler for update
 [PostHandlerFor(tableStr(TableName), tableMethodStr(TableName, updateBackStatus))]
 public static void TableName_Post_updateBackStatus(XppPrePostArgs args)
 {
     TableName buffTable = args.getThis();
 }




ModifiedField:

// Table- pre-event handler for modified field
 [PreHandlerFor(tableStr(TableName), tableMethodStr(TableName, modifiedField))]
 public static void TableName_Pre_modifiedField(XppPrePostArgs args)
 {
     TableName buffTable = args.getThis() as TableName;

 }

// Table -post-event handler for the modified field
 [PostHandlerFor(tableStr(TableName), tableMethodStr(TableName, modifiedField))]
 public static void TableNamee_Post_modifiedField(XppPrePostArgs args)
 {
      TableName buffTable = args.getThis() as TableName;   
 }





Datasource event handler:

Written:

// Datasource - event handler for written
    [FormDataSourceEventHandler(formDataSourceStr(FormName, DataSourceName), FormDataSourceEventType::Written)]
    public static void DataSourceName_OnWritten(FormDataSource sender, FormDataSourceEventArgs e)
    {
        FormRun         form              = sender.formRun();
        FormDataSource  DatasourceName_ds = form.dataSource(formDataSourceStr(FormName, DataSourceName)) as FormDataSource;
        TableName       buffTable         = DatasourceName_ds.cursor();
    }



initValue:

// Datasource - EventHandler for datasource initvalue
    [FormDataSourceEventHandler(formDataSourceStr(FormName, DataSourceName), FormDataSourceEventType::InitValue)]
    public static void DataSourceNames_OnInitValue(FormDataSource sender, FormDataSourceEventArgs e
    {
        FormRun          formRun             = sender.formRun();
        FormDataSource   DataSourceName_ds   = formRun.dataSource(formDataSourceStr(FormName,DataSourceName)) as FormDataSource;
        TableName        buffTable           = DataSourceName_ds.cursor();
    }


Activated:

//Datasource - Event handler for data source activated method
    [FormDataSourceEventHandler(formDataSourceStr(FormName, DataSourceName), FormDataSourceEventType::Activated)]
    public static void DataSourceName_OnActivated(FormDataSource sender, FormDataSourceEventArgs e)
    {
        DataSourceName buffDataSource = sender.cursor();  
        FormDataSource DataSourceName_ds = sender.formRun().dataSource("DataSourceName");
        FormRun element = sender.formRun();
    }



Init:

  // Datasource - event handler for data source init
    [FormDataSourceEventHandler(formDataSourceStr(FormName, DataSourceName), FormDataSourceEventType::Initialized)]
    public static void DataSourceName_OnInitialized(FormDataSource sender, FormDataSourceEventArgs e)
    {
        FormDataSource datasourceName_ds = sender.forRun().dataSource("DataSourceName");
        FormRun element = sender.formRun();
    }



ValidateWrite:
// DataSource - eventhandler for datasource validatewrite
    [FormDataSourceEventHandler(formDataSourceStr(FormName, DataSourceName), FormDataSourceEventType::ValidatingWrite)]
    public static void DataSourceName_OnValidatingWrite(FormDataSource sender, FormDataSourceEventArgs e)
    {
        var datasource = sender as FormDataSource;
        var args = e as FormDataSourceCancelEventArgs;
        if (args != null && datasource != null)
        {
            // write your own logic
        }
    }



Form event handler: 


OnInitialized:
// Form  - event handler for form OnInitialize
    [FormEventHandler(formStr(FormName), FormEventType::Initialized)]
    public static void FormName_OnInitialized(xFormRun sender, FormEventArgs e)
    {

        FormDataSource DataSourceName_ds = sender.dataSource(formDataSourceStr(FormName, DataSourceName));
            //Or
        FormDataSource DataSourceName_ds = sender.dataSource('DataSourceName');

    }



Closing:
   
// form- event handler for form closing
    [FormEventHandler(formStr(FormName), FormEventType::Closing)]
    public static void FormNamee_OnClosing(xFormRun sender, FormEventArgs e)
    {
        FormDataSource datasource_ds    = sender.dataSource(formDataSourceStr(FormName, DataSourceName));
        TableName      buffTable        = datasource_ds.cursor();
    }



Init:
// Form - event handler for form init.
    [PostHandlerFor(formStr(FormName), formMethodStr(FormName, init))]
    public static void FormName_Post_init(XppPrePostArgs _args)
    {
        FormRun form             = _args.getThis();
        FormDesign design        = form.design();
        FormControl variableName = design.controlName(formControlStr(FormName, controlName));
        FormControl variableName = design.controlName(formControlStr(FormName, controlName));
    }

Step-by-Step Guide to Restore a SQL BACPAC File - Microsoft dynamics D365 Fin & Ops

 Restore steps for bacpac file in to SQL server - Microsoft dynamics D365 Fin & Ops. Log in to LCS and navigate to the asset library. On...