Tuesday, December 14, 2021

How to update record in validTimeState table

        LogisticsPostalAddress  LogisticsPostalAddress;

        select * from HCMWORKER

                where HCMWORKER.PERSONNELNUMBER == '002013'; //68719512003

        TransDate x= today(),y=dateMax();

        select forupdate validtimestate(x) * from LogisticsPostalAddress

                where LogisticsPostalAddress.PRIVATEFORPARTY == HCMWORKER.person;     

        LogisticsPostalAddress.ValidTo = today() -1;

        Info(strFmt("%1",HCMWORKER.Person));

        Info(strFmt("%1",LogisticsPostalAddress.RecId));

        ttsbegin;

        LogisticsPostalAddress.validTimeStateUpdateMode(ValidTimeStateUpdate::Correction);

        LogisticsPostalAddress.update();

        ttscommit;

Saturday, December 11, 2021

Full CIL, Incremental CIL in AX 2012

 Full CIL and Incremental CIL in AX2012


Compile: -The compile is to convert X++ source code into p-code, it is in 2009


Sync:-Checking each and every table defining the value of your EDT


Full CIL:-generate CIL is about to convert the p-code into CIL, referred to as the byte code which, at run time, is used by the CLR to convert into native code for execution on the computer. It is easier to understand that a full CIL generation involves converting all p-code into CIL finally, it converts to the binary Lang


Incremental CIL:-incremental CIL generation involves only the “changed” p-code artifacts that need to be converted into target CIL. Incremental CIL would compile only the objects that were modified since the last incremental compilation.


Some X++ batch jobs can now complete in much less time. All X++ code that runs on the AX32.exe client still runs as interpreted p-code. However, all batch jobs now run as Microsoft .NET Framework CIL, which is often much faster than p-code.


The X++ developer must now complete the extra step of compiling X++ p-code to CIL. To compile p-code to CIL, right-click AOT, and then click Add-ins > Incremental CIL generation from X++.


Next, if the installation uses multiple instances of Application Object Server (AOS), all AOS instances must be stopped and then restarted. This causes the AOS instances to load the updated assembly.


Finally, a service or a batch job must run the X++ code that was compiled to CIL. Services and batch jobs now run only as CIL

Friday, December 10, 2021

Change tracking in SQL

 Open SSMS in administrator mode

Run the following command


ALTER DATABASE DATABASENAME

SET CHANGE_TRACKING = ON

(CHANGE_RETENTION = 5 DAYS, AUTO_CLEENUP = ON)




Enable change tracking on the particular table :

ALTER TABLE custgroup

ENABLE CHANGE_TRACKING

WITH (TRACK_COLUMNS_UPDATED = ON)




To view the change-tracking history of a particular table :

select * from CHANGETABLE(CHANGES custGroup, 0) AS ChTbl


Tada!!

Disable HTTP2 for chrome

Open RUN (Window + R)

Run following command :

chrome.exe -disable-http2

This will open chrome in http2 disabled mode


Change the basic settings of D365 DEV server

Change following settings :

DB - Business Database Name, Default Company, Default Model For New Projects, Offline Authentication Admin Email


Go to the following path

K:\AosService\PackagesLocalDirectory\bin\

Open the below file :

DynamicsDevConfig.xml

and there you may set any setting

Wednesday, December 8, 2021

How to synch DB in AX 2012

Go to 

SQL administration

Click System administration > Periodic > Database > SQL administration.

On the Table actions menu, click Synchronize database, or click Check/Synchronize.

Saturday, December 4, 2021

Debug Issue/Error in D365 FO

 1. Open the event viewer and right click and run as administrator. In the Event viewer go to the Microsoft folder expand it.

2. After expanding the Microsoft folder go to AX-SystemRuntime under Operational. Under Operational you will find the error message in the level column and Task category Column. In the below window you will find two tabs details and general.

In the General tab, you will get the error message.


Click on the Details tab to get the full view of the error message.





Thursday, December 2, 2021

Wednesday, November 10, 2021

Line break code in X++

str desc = 'Description :' + "\r\n" + 'This will be in Next line'

Overloading and overriding

Polymorphism means “Many Forms”. In Polymorphism, poly means “Many” and morph means “Forms.” Polymorphism is one of the main pillars in Object-Oriented Programming. It allows you to create multiple methods with the same name but different signatures in the same class. The same name methods can also be in derived classes.
 
There are two types of Polymorphism :
1. Method Overloading
2. Method Overriding


Method Overloading
Method Overloading is a type of polymorphism. It has several names like “Compile Time Polymorphism” or “Static Polymorphism” and sometimes it is called “Early Binding”. 
Method Overloading means creating multiple methods in a class with the same names but different signatures (Parameters). It permits a class, struct, or interface to declare multiple methods with the same name with unique signatures.
The compiler automatically calls the required method to check the number of parameters and their type which are passed into that method.

Sample Code

   public class Program  
    {  
        public int Add(int num1, int num2)  
        {  
            return (num1 + num2);  
        }  
        public int Add(int num1, int num2, int num3)  
        {  
            return (num1 + num2 + num3);  
        }  
        public float Add(float num1, float num2)  
        {  
            return (num1 + num2);  
        }  
        public string Add(string value1, string value2)  
        {  
            return (value1 + " " + value2);  
        }  
        static void Main(Args _args)  
        {  
            Program objProgram = new Program();  
           Info("Add with two int parameter :" + objProgram.Add(3, 2));  
           Info("Add with three int parameter :" + objProgram.Add(3, 2, 8));  
           Info("Add with two float parameter :" + objProgram.Add(3 f, 22 f));  
           Info("Add with two string parameter :" + objProgram.Add("hello", "world"));  
           
        }  
    }  


In the above example, you can see that there are four methods with the same name but the type of parameters or number of parameters is different. When you call Add(4,5), complier automatically calls the method which has two integer parameters and when you call Add(“hello”,” world”), complier calls the method which has two string parameters. So basically in method overloading complier checks which method should be called at the time of compilation.
Note: Changing the return type of method does not make the method overloaded. You cannot create method overloaded vary only by return type.



Method Overriding
Method Overriding is a type of polymorphism. It has several names like “Run-Time Polymorphism” or “Dynamic Polymorphism” and sometimes it is called “Late Binding”. 
Method Overriding means having two methods with the same name and same signatures [parameters], one should be in the base class and another method should be in a derived class [child class]. You can override the functionality of a base class method to create the same name method with the same signature in a derived class. You can achieve method overriding using inheritance. Virtual and Override keywords are used to achieve method overriding.

class BaseClass  
    {  
        public virtual void Add(int num1, int num2)  
        {  
           // your logic will be here 
        }  
    }  
    class ChildClass: BaseClass  
    {  
        public override void Add(int num1, int num2)  
        {  
          // your logic will be here
            ;  
        }  
    }  
    class Program  
    {  
        static void Main(Args _args)  
        {  
            BaseClass baseClassObj;  
            baseClassObj = new BaseClass();  
            Info("Base class method Add :" + baseClassObj.Add(-3, 8));  
            baseClassObj = new ChildClass();  
            Info("Child class method Add :" + baseClassObj.Add(-2, 2));  
          
        }  
    }  

In the above example, I have created two same name methods in the BaseClass as well as in the child class. When you call the BaseClass Add method with less than zero value as parameters then it adds successfully. But when you call the ChildClass Add method with less than zero value then it checks for a negative value. And the passing values are negative then it asks for a new value.
 
So, here it is clear that we can modify the base class methods in derived classes.
 
Points to be remembered,
The method cannot be private.
The only abstract or virtual method can be overridden.
Which method should be called is decided at run time.

Sunday, November 7, 2021

Define Concept of Extensions

 An extension is a way to add functionality to an object in D365FO without modifying the base code of that object.  

Your extensions are compiled into their own DLLs, which are separate from the D365 base system libraries. It also makes it easier for Microsoft to patch their sys layer code.

Microsoft has added to allow customizations without allowing the base code to be changed because they plan to not allow any overlaying of SYS layer code.

Reference

Difference between Container, List, Map and Set

 Containers:

Containers are dynamic and have no limits. They can contain elements of

almost all data types: boolean, integer, real, date, string, container,

arrays, tables, and extended data types. However, objects may not be stored

in containers.

Containers in AX are used very often. It’s easy to work with them. But…

data in containers are stored sequentially and thus retrieved sequentially.

This means that containers provide slower data access if you are working with

_large numbers_ of records. In case of large numbers of records use temporary

tables.


List:

Lists are structures that may contain any number of elements that are

accessed sequentially. Lists may contain values of any X++ type. All the

values in the list must be of __the same__(this is the main difference

between lists and containers) type, given in the creation of the list. The

implementation of lists is such that the traversal of the list elements is __very

fast.

Take a look for example at the class Dialog addControl() method.

Their controls are stored in ctrls List.


Map:

A map is a data type that associates one (key) value with another value [An

analog – a small table in memory with two fields: Keys, Values]. Both the key

and value values may be of any valid X++ type, including objects. The types

of the key and the value are given in the declaration of the map. The

implementation of maps is such that access to the values is _very fast_.

Don’t confuse map X++ types with Map objects in AOT, which are used for

mapping tables with similar structures of fields


Set:

The functionality of Sets is similar to the list.  A Set is just an unordered list of items, while a list of items held by a Map

are indexed via a key.

Take look at

\Classes\sysLabel\LabelModuleId()

How to get label, name and data type of all fields of any table

 static void JobTableLabel(Args _args)

{


    DictTable       dt=new SysDictTable(tableNum(HcmWorker));

    FieldId       _fieldId=  dt.fieldNext(0);

    DictField     _dictField;

    

while(_fieldId)

    {

      _dictField  =dt.fieldObject(_fieldId);

 info(strFmt("Field Name %1 , Field Lable %2 and Field Type %3", _dictField.name(),_dictField.label(),_dictField.type()));

     _fieldId=  dt.fieldNext(_fieldId);

    }

}

BYOD (Bring your own database) in D365 FO



What is BYOD?

BYOD feature lets administrators configure their own database, and then export one or more data entities that are available in Finance and Operations into it.

The BYOD feature allows you to push data into a database you manage on Azure or on-premises.

This is done with the use of data entities. This means you can use existing entities or build your own entities to structure the data you need for your external database. Currently, more than 1700 Data entities are available.


Objective

You have data in D365 running in the cloud but you still have other applications that you run on-premise or elsewhere. 

So you need to get data from D365 into another environment so other applications can use the data. 

The most common use of BYOD is for data analysis and long-running reporting (Long-running reports are the pain point of AX)


Reference

Link

How-to search system logs for BYOD (and other) errors in D365 F&O : Link

Create DB > Configuration > Publish : Link

How to override form control Lookup using extensions in D365 FO

In D365FO we have a bunch of events to subscribe to on a form control level:

right-click on lookup event of control to subscribe to the event and paste in class.


[FormControlEventHandler(formControlStr(PayrollEmployerTaxRegion, Overview_StateId), FormControlEventType::Lookup)]

    public static void Overview_StateId_OnLookup(FormControl sender, FormControlEventArgs e)

    {

                  // Logic here

    }



Now to cancel parent event, D365FO provide a class FormControlCancelableSuperEventArgs


You can cancel the parent(Original event with below code)


        FormControlCancelableSuperEventArgs ce = e as FormControlCancelableSuperEventArgs;


        //cancel super() to prevent error.

        ce.CancelSuperCall();





//Code

[FormControlEventHandler(formControlStr(PayrollEmployerTaxRegion, Overview_StateId), FormControlEventType::Lookup)]

    public static void Overview_StateId_OnLookup(FormControl sender, FormControlEventArgs e)

    {

        SysTableLookup      sysTableLookup  = SysTableLookup::newParameters(tableNum(LogisticsAddressState), sender);

        Query               query           = new Query();


        // Filter lookup to only show US states

        query.addDataSource(tableNum(LogisticsAddressState)).addRange(fieldNum(LogisticsAddressState, CountryRegionId)).value(LogisticsAddressCountryRegion::findByISOCode(SysCountryRegionCode::countryInfo(curext())).CountryRegionId);


        // Sort the lookup by state Id

        query.dataSourceTable(tableNum(LogisticsAddressState)).addOrderByField(fieldNum(LogisticsAddressState, StateId), SortOrder::Ascending);


        // Add fields

        sysTableLookup.addLookupfield(fieldNum(LogisticsAddressState, StateId));

        sysTableLookup.addLookupfield(fieldNum(LogisticsAddressState, Name));


        // Run lookup

        sysTableLookup.parmQuery(query);

        sysTableLookup.performFormLookup();

        FormControlCancelableSuperEventArgs ce = e as FormControlCancelableSuperEventArgs;


        //cancel super() to prevent error.

        ce.CancelSuperCall();

    } 

Reference

Monday, November 1, 2021

Get Number sequence by code in D365 FO

NumberSeq   num;

        num = NumberSeq::newGetNum(NumberSeqReference::findReference(extendedTypeNum(DAPTransNum)));

info(num.num());

num.used();

Class basic code concept in D365 FO X++

Class GITS_Test_AY

{

    public static GITS_Test_AY construct()

    {

        return new GITS_Test_AY();

    }


    public void PrintName(str _Name)

    {

        info(strFmt("%1",_Name));

    }


    public static void withoutReference()

    {

        info(strFmt("Hello"));

    }


}






----------------Calling class----------------

class GITS_Runnable_AY

{

    public static void main(Args _args)

    {

        GITS_Test_AY    obj = GITS_Test_AY::construct();

        obj.PrintName("Jyoti");

        obj.PrintName("Atul");

        GITS_Test_AY::withoutReference();

    }


}

Difference between Index and Index hint

When you use the index keyword in a select statement the kernel will translate this to the "order by" command and the database optimizer will choose the best index to actually use. When you chose to use the index hint keyword in your select statement, Ax will force the database to use the chosen index.


Index:

When you use the index keyword in a select statement the kernel will translate this to order by command and the database optimizer will choose the best index to actually use. 

Example: select * from InventTable index GroupItemIdx will generate the following SQL statement to the database:

SELECT A.ITEMGROUPID, A.ITEMID, A.ITEMNAME,.... FROM INVENTTABLE A ORDER BY A.ITEMGROUPID, A.ITEMID

The Index ItemGroupIdx of the InventTable exactly contains the two fields ItemGroupID and ItemId (in that order). Using "index", you still give the control of which index to use to the database optimizer. So, if the optimizer finds a better index to use, it will use it.

Index hint:

When you chose to use the index hint keyword in your select statement, Ax will force the database to use the chosen index.

Example: select * from InventTable index hint GroupItemIdx will generate the following SQL statement to the database:

SELECT /*+ INDEX(A I_175GROUPITEMIDX) */ A.ITEMGROUPID, A.ITEMID, A.ITEMNAME,.... FROM INVENTTABLE A

Using "index hint", you take away the control of which index to use from the database optimizer. So, if there may be a better index, the database will not use it.

Sunday, October 31, 2021

How to debug an SSRS report

Sometimes when you place a breakpoint in a data provider class to debug an SSRS report and exercise the report to hit the breakpoint it works and sometimes it doesn't. So the trick to always make the hit is to inherit from the SrsReportDataProviderPreProcess class instead of the SRSReportDataProviderBase class


public class SalesInvoiceDP extends SrsReportDataProviderPreProcess

{

}

Macros in D365 FO

A macro is a variable known to the precompiler. The variable can have a value that is a sequence of characters, but it is not required to have a value.

class GITS_Test
{
    public static void main(Args _args)
    {
        HcmWorker   HcmWorker;
        #localmacro.selectWorker
        select * from HcmWorker
        #endmacro

        #localMacro.whereClause
        where %1.PersonnelNumber == %2
        #endmacro

        #selectWorker
        #whereClause(HcmWorker,'001113');
        Info(strFmt("%1",HcmWorker.name()));
    }
}

Overriding in D365 FO

 class Point

{

    // Instance fields.

    real x;

    real y;


    // Constructor to initialize fields x and y.

    void new(real _x, real _y)

    {

        x = _x;

        y = _y;

    }


    void write()

    {

        info("(" + any2Str(x) + ", " + any2Str(y) + ")");

    }

}


class ThreePoint extends Point

{

    // Additional instance fields z. Fields x and y are inherited.

    real z;


    // Constructor is overridden to initialize z.

    void new(real _x, real _y, real _z)

    {

        // Initialize the fields.

        super(_x, _y);

        z = _z;

    }


    void write()

    {

        info("(" + any2Str(x) + ", " + any2Str(y) + ", " + any2Str(z) + ")");

    }


}


// Code that creates Point objects and calls the write method.

Point point2 = new Point(1.0, 2.0);

Point point3 = new ThreePoint(3.0, 4.0, 5.0);


point2.write();

// Output is "(1.0, 2.0)".


point3.write();

// Output is "(3.0, 4.0, 5.0)".


Reference


Saturday, October 30, 2021

Error while exporting data in excel D365 FO


RESOLUTION:

You can start the Azure storage emulator by following the steps below:


On OneBox VM, run command prompt as administrator.

Navigate to “C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\”

Run “AzureStorageEmulator.exe start”

This should resolve the issue reported above which surfaces while exporting data through data entities in Dynamics 365 for Operations.


List page interaction class and methods

Interaction class of list pages extends SysListPageInteractionBase class. Some handful methods of this class are as follows:

initializing: Called when the form is initializing – Similar to the form init method

intializeQuery: Also called when the form is initializing – Similar to the datasource init method

selectionChanged: Called when the active record changes – Similar to the datasource active method.

setButtonEnabled: Should be overridden to dynamically enable/disable buttons based on the current selection. This is called from the selectionChanged method.

setButtonVisibility: Should be overridden to show/hide buttons when the form first opens. This is used more to do a one-off layout adjustment based on system configuration/parameters, as well as the menu-item used to open the form. eg If you have a menu-item that opens a form based on status, you may want to hide the relevant ‘status’ field to reduce clutter.

Friday, October 29, 2021

Run a class from browser

open browser and just type in


https://usnconeboxax1aos.cloud.onebox.dynamics.com/?cmp=USMF&mi=SysClassRunner&cls=GITS_Test


here class name is "GITS_Test"

Cache lookup property in D365 FO

Types of Cache Lookup :

None

EntireTable

Found

NotInTTS

FoundAndEmpty


For the master table - EntireTable

For static tables(Like unit tables) - Found

For transaction table - NotInTTS

For static tables (record exists or not example discount table) - FoundAndEmpty



 CacheLookup  Property :-


None :-

No data is cached or retrieved from the cache for this table.

This property value should be used for tables that are heavily updated or where it's unacceptable to read outdated data.


NotInTTS :-

All successful caching key selects are cached.

When in a transaction (after ttsBegin), no caches made outside the transaction are used. When inside a transaction, the record is read once from database and subsequently from cache. The record is select-locked when read in a transaction, which ensures that the record cached is not updated while the transaction is active.

A typical example of the NotInTTS property is the CustTable in the Microsoft Dynamics AX standard application. It's acceptable to read outdated data from the cache outside a transaction, but when data is used for validation or creating references, it is ensured that the data is real-time.


Found :-

All successful caching key selects are cached. All caching key selects are returned from the cache if the record exists there. A selectforUpdate in a transaction forces reading from the database and replaces the record in the cache.

This is typically used for static (lookup) tables, such as Unit, where the record usually exists.


FoundAndEmpty :-

All selects on caching keys are cached, including selects that are not returning data.

All caching key selects are returned from caching if the record exists there, or the record is marked as nonexistent in the cache. A selectforUpdate in a transaction forces reading from the database and replaces the record in the cache.

An example of FoundAndEmpty record caching is in the Discount table in the Microsoft Dynamics AX standard application. By default, the Discount table has no records. By using a FoundAndEmpty cache on this table, the keys that are queried for but not found are stored in the cache. Subsequent queries for these same non-existent records can be answered from the cache without a round trip to the database.


EntireTable :-

Creates a set-based cache on the server. The entire table is cached as soon as at least one record is selected from the table.



The Found and FoundAndEmpty caches cross transaction boundaries. The NotInTTS cache is newly created inside a transaction. This example, modified for the purposes of this topic, demonstrates how records are retrieved from the cache when the table's CacheLookup property is set to NotInTTS, and the PrimaryIndex property is set to a unique index on the AccountNum field.

Table level best practices D365 FO

Set Title fields

Create primary index

Create basic methods like find, findRecId, exist.

Add method documentation in every method.

Method name should be camel casing

Add BP deviation comment on every display or edit method.

Create groups containing relevant fields.

Run the BP check on your table (right-click on table -> Add-ins -> Check Best Practices) and it will show the most crucial BP deviations you might have there.

Index and Key in Dynamics 365 FO

Cluster Index

The ClusterIndex value is given to the underlying Microsoft SQL Server database system as a performance tuning choice. This choice generally controls the physical sequence in which the records are stored in the underlying database.[Let's just say we have 100 fields in a table and we need to fetch 3 fields from different locations, then we use cluster index to make it quick]


Primary Index

The drop-down list contains the surrogate key plus every index on the table that has its AlternateKey property set to Yes.


Surrogate key

In AX 2012, a surrogate key is the auto-generated primary key for a table in the database. The surrogate key is linked to the already existing RecId field within any table. This means that the surrogate key is a unique 64-bit integer value that is mandatory for the table and cannot be changed or have duplicates. The fact that it is a 64-bit integer (int64) value means table operations normally perform faster than other types of field such as string fields. This is the main strength of surrogate keys.


Replacement key Index

While a surrogate key is great for lookup and database performance, it is not useful for the end-user because it gives no indication of the table’s purpose, or what related tables it is linked to. For this reason, AX 2012 has added the ‘Replacement Key’ index property for tables. The replacement key index is a dropdown of alternate keys that have been specified for the table. There can be any number of alternate keys for a table but only a single replacement key. More than one field can be specified under a replacement key, and it is these fields that will be displayed to the end-user on a form instead of the surrogate key field.

A replacement key is an alternate key that the system can display on forms instead of a meaningless numeric primary key value. Each table can have a maximum of one replacement key.


Alternate key

A table can have any number of alternate keys. An alternate key may be a natural key or a single field primary key used in foreign or primary key relations with other tables. In either case, to set one, the user must create a new index and then set AllowDuplicates to “No” and AlternateKey to “Yes”. If AllowDuplicates is not set to “No” then AlternateKey should be greyed out and uneditable Reference


CreateRecIdIndex

This property controls whether the system creates a unique index on the RecId field. The default value is Yes. This is the basis of the surrogate key.

No other field is added to this index, not even DataAreaId.


Replacement Key

The drop-down list contains every index that has its AlternateKey property set to Yes.

You might change the default blank value to an index whose field values within each record provide a name or other moniker that is meaningful to people. If a ReplacementKey is chosen, its fields can appear on forms to help identify each record.

The ReplacementKey should be a set of fields that represent the natural key.


Alternate Key

Yes means that other tables can create foreign key relations that reference this key, as an alternative to referencing the primary key.

Indexes with two or more fields cannot have their AlternateKey property value set to Yes.


Configuration key

Configuration keys allow administrators to enable or disable features in the application for all users. Disabling features help to minimize the attack surface against potential attacks.

Configuration keys are applied to:

Tables

Fields

Indexes

Views

Menus

Menu items

Form controls,

Report controls

Extended data types

Enumerations


Security key

Security keys allow administrators to set security on a user group level. Minimizing access on a user group level helps to reduce the attack surface against potential attacks.

The main reasons to apply user-level security are to:

Allow users to do only their designated tasks.

Protect sensitive data in the database.

Prevent users from inadvertently breaking an application by changing code or objects on which the application depends.

You need to apply a security key to:

Tables

Views

Menus

Menu items

Form controls

Report controls


Difference between COC(Chain of commands) and Event Handler in D365

Post Event Handler is static, does not allow you to have access to protected members of a class.

Also, you cannot add new method or class state via event handler, so CoC is way more powerful.

The advantage of chain of command is you can share the same method variables in the pre and post (before/after next() call) or share the same TTS block inside your COC method.

COC also supports return value and parameter modification of the extended method in a much more readable manner.

COC is nearly the same as pre and post-handlers, pre being before the next call and post after it.

Exist method in D365 FO

 static boolean exist(CustGroupId custGroupId)

{

    return custGroupId 

        && (select firstOnly RecId from custGroup

            where custGroup.custGroup == custGroupId).RecId != 0;

}

Wednesday, October 27, 2021

Var in x++

Usually, it's just a shortcut, so you don't have to declare the type if it would make the code less readable. For example, often the type is obvious or not important, and specifying it would make code less readable.


You're welcome to use var where it makes sense, but make sure that you don't make your code less readable by omitting important type information. That the type is obvious to the compiler doesn't mean it's obvious to developers.


In C#, it's also necessary for variables of anonymous types, because there is no way how to declare such a type. For example, you have a LINQ query returning two fields and the framework returns an object with these two fields, but it doesn't have any named type.


Anonymous types are going to be supported in X++ in the future.

Tuesday, October 26, 2021

All methods in D365 FO

 Table Methods

Modified Field : Each time the value of a field is changed ,this method is called.

Init Value : It is used to set a default value for the fields.If we create a new record from the table browser “initvalue” is executed(runs when we create a new record).

Validate Field : It is used for validation only and will return true or false.Each time the value of a field is changed the method ValidateField() is called.

Validate Write : It works like mandatory field(setting) (runs when you save the record).

Validate Delete : while deleting a method if we want to put any validation we can use this method.

 

//Insert update find exist

 

Form Methods

Activate : When a form receives focus.Returns boolean data type that specifies whether a form has focus.

CanClose : When aform is closed.specifies whether you can close the form.The call to the super in the method checks whether closing the form is a valid action.

Closed : The form is closed.use this method to check whether the form has been closed.

Close : The form is closed.the call to the super in this method closes the form window,manages database updates and sets the closed method to true.

CloseCancel : Use this method to check whether the form has been closed by a cancel action.the method is set to true if the form is closed by a cancel action.

CloseOk : The user presses an ok button.specifies whether the form wasa closed by clicking the ok button.the call to the super method sets the boolean flag closedok and calls the close method.

InIt : The form is opened.use the method to initialize a form.the init method I started immediately after the new method and creates the run time image of the form.you must call the super method if you override this methpd and you should add your code before the super call.

Run : The form is opened.Call the run method immediately after the init method.The call to the super method makes the form window appear on the screen and performs a database search for the data to be displayed in the form.


Form Control Methods

Validate : The user exists a control after entering data.

Lookup : The user uses the lookup facility.

Modified : The user exits an edit field after changing it.The user changes a value in a checkbox,combobox,listbox or radio button control.The super call manages the table update.

 

Form Datasource Methods

Active : The user selects a new record.Retrieves data from joined datasource when a user moves to a new record.

Create : The user creates a new record in the datasource.If you use this method to specify field values,the new value are saved to the database when you leave the form.

Delete : the user deletes a record in the datasource.Deletes the current reord from the datasource.

ExecuteQuery : The form is opened for data display.Executes the datasource query and displays the retrieved records.

Filter : The user starts one of the filter commands on the form shortcut menu.Filter records in the datasource.

FindRecord : Activated by the find value method.Finds the specified record in the database and makes it the current one.

InIt : The form is opened.Creates a datasource query based on the datasource properties.

InItValue : A new record is created.The purpose is to fill in initial values in the record.Initializes field values in a new record.If you use this method to specify field values,the new values are not automatically saved to the database when you leave the form.To specify values that you want to save when you leave the form,use the created method.

LinkActive : The user selects a new record in a form that has a datasourcelinked to another datasource.Calls the FormDataSource.executeQuery method on data sources that are linked to the current data source.

Refresh : Not sgtarted by the system.Updates the form by refreshing the view of all records in the datasource.WILL NOT REREAD THE RECORD FROM THE DATASOURCE.IT BASICALLY JUST REFRESHES THE SCREEN WITH WHATEVER IS STORED IN THE FORM FROM THE CACHE.

Reread : Not started by the system.Rereads the current record from the datasource.WILL ONLY REREAD THE CURRENT RECORD FROM THE DATABASE SO YOU SHOULD NOT USE IT TO REFRESH THE FORM DATA IF YOU HAVE ADDED/REMOVED RECORDS.

Research : Not started by the system.Refreshes the database search defined by the query , specified by the FormDataSource.init method.WILL RETURN THE EXISTING FORM QUERY AGAINST THE DATASOURCE,THEREFORE UPDATING THE LIST WITH NEW /REMOVED RECORDS AS WELL AS UPDATING EXISTING ONES.THIS WILL HONOUR ANY EXISTING FILTERS AND SORTING ON THE FORM.

SelectionChanged() : The user selects or unselects one or morerecords in the datasource.Enables youo to change the property values of control when the selected record changes.

ValidateWrite() : A new or updated record is to be written determines whether data is valid and ready to be written.

Write() : The user inserts a new record or updates an existing one.Calls the FormDataSource.validateWrite method and manages the database write operation.

Methods called while modification closing opening deletion saving runbase

 

Field modification

Form closing


Form opening


Record deletion

Record saving

Runbase


Monday, October 25, 2021

Cardinality and RelatedTable Cardinality

Specifically, the Cardinality property corresponds to the notation on the child table (SalesLine in this case). So it should be ZeroMore (0…*).

RelatedTableCardinality property corresponds to the notation on the parent table (SalesTable). So it should be ExactlyOne (1:1).


Semantically, Cardinality specifies how many instances of SalesLine row can be related to a single instance of SalesTable row. ZeroMore means that for every sale order, there can be zero, or more sales lines related to it. If the business requirement dictates that you need to have at least one sales line to be able to create a sales order, the Cardinality would be OneMore (1:*).


RelatedTableCardinality specifies how many instances of SalesTable row can be related to a single instance of SalesLine row. ExactlyOne means that every sales line should belong to one and only one sales order.

Automatically generated batch retryable

Microsoft introduced a BatchRetryable interface to cover unexpected failures on batch jobs.

The problem is that this interface is not implemented automatically, you need manually specify it on all classes. 

To fix this issue, I extended my Runbase class builder tool to automatically generate this property(interface and isRetryable() method)




Saturday, October 23, 2021

Difference between SysOperation Framework and Runbasebatch Framework

Difference between batchprocessing and runbasebatch Framework

The purpose of the SysOperation framework is to provide the same capabilities as the RunBase framework but with base implementations for common overrides. 4 functions are below :


Service: Service class extends from the SysOperationServiceBase class and contains the business logic for the batch operation. Developers often tend to add the business logic in controller classes, which violates the Single responsibility principle[The single-responsibility principle is a computer-programming principle that states that every module, class or function in a computer program should have responsibility over a single part of that program's functionality, and it should encapsulate that part.]

Data Contract: Data contract class is the model class defining attributes needed for batch operations. These attributes are provided by the user, in a dialog. DataContractAttribute attribute is needed for the class and the properties methods requires DataMemberAttribute attribute.

Controller: Controller class extends from the SysOperationServiceController class. It holds information about the batch operation like execution mode, show dialog or progress bar etc. and directs the batch operation.

UI Builder: UI Builder class extends from SysOperationAutomaticUIBuilder class and is used for adding custom behavior to dialog / dialog fields dynamically constructed by the SysOperation framework.


SysOperation framework Classes:

Contract class - SysOperationDataContractBase 

Service - SysOperationServiceBase

UI Builder class - SysOperationAutomaticUIBuilder

Controller - SysOperationServiceController





Here are the main differences between the two:

RunBaseBatch:

Legacy framework: RunBaseBatch is an older framework available in earlier versions of Dynamics AX (before AX 2012). It's still supported in Dynamics 365 F&O, but Microsoft encourages the use of the SysOperation framework for new development.

Object-oriented: RunBaseBatch uses an object-oriented approach, which allows developers to create classes that inherit from the RunBaseBatch class.

Serialization: RunBaseBatch requires manual serialization of class members using the pack and unpack methods. This can lead to errors and inconsistencies if not implemented correctly.

Limited support for user interface (UI) controls: The RunBaseBatch framework has limited support for UI controls, such as dialog boxes, which may require additional customization.

SysOperation Framework:

Modern framework: SysOperation was introduced in Dynamics AX 2012 and is the recommended framework for background processing and batch tasks in Dynamics 365 F&O.

Attribute-based: SysOperation uses attributes to define the class and its methods, making it easier to understand and manage.

Automatic serialization: SysOperation automatically handles serialization, reducing the chances of errors and inconsistencies.

Better UI support: The SysOperation framework provides better support for UI controls, such as dialog boxes, making it easier to create user-friendly interfaces for batch processing tasks.

Integration with Application Object Tree (AOT): SysOperation integrates with AOT, which provides an organized way to access and manage application objects.

In conclusion, while both frameworks can be used for batch processing and background tasks in Dynamics 365 F&O, the SysOperation framework is the recommended choice due to its modern architecture, automatic serialization, better UI support, and integration with AOT. RunBaseBatch is still supported, but it is considered a legacy framework and should only be used for maintaining existing implementations or when specific requirements demand its use.

Monday, October 18, 2021

Interface in X++

Interface:

An interface is an empty shell. There are only the signatures of the methods, which implies that the methods do not have a body. The interface can't do anything. It's just a pattern.

All interfaces are public regardless of whether you explicitly write the keyword public in front of the keyword interface in the class declaration. The methods on an interface are also public, and again the explicit inclusion of the keyword public is optional.


Abstract classes:

Abstract classes, unlike interfaces, are classes. They are more expensive to use because there is a look-up to do when you inherit from them.

Abstract classes look a lot like interfaces, but they have something more: You can define behavior for them. It's more about a person saying, "these classes should look like that, and they have that in common, so fill in the blanks!".

Abstract classes are classes that contain one or more abstract methods.

An abstract method is a method that is declared but contains no implementation.

When we declare a class as abstract, this class cannot initiate in X++ code. To use this class or its method we have to first extend this class than only we are able to use this class or its method.


Interface IDrivable

{

    int getSpeed(){}

   void setSpeed(int newSpeed){}

}

class Automobile implements IDrivable

{

    int speed;

   public int getSpeed()

    {

        return speed;

    }

    public void setSpeed(int newSpeed)

    {

        speed = newSpeed;

    }

}

class UseAnAutomobile

{

    void DriveAutomobile()

    {

        IDrivable drivable;

        Automobile myAutomobile = new Automobile();

        str temp;


        myAutomobile = new Automobile();


        if (myAutomobile is IDrivable)

        {

            drivable = myAutomobile;

            drivable.setSpeed(42);

            temp = int2str(drivable.getSpeed());

        }

        else

        {

            temp = "Instance is not an IDrivable.";

        }

        info(temp);

    }

}




----------------------------------------Abstract class----------------------------------------

To understand the abstract class consider the following example

We have three classes

     1.      absClass  (it’s an abstract class)

     2.      normal class (another class that will use the absClass methods)

     3.      extendAbsClass (this class will extend the absClass)

    1.abstract class absClass

     {

     }

    void printName()

   {

    ;    info("AbsClass... Deepak");

   }

    2. class extendAbsClass extends absClass

       {

        }

    3.class normalClass

      {

      }

  void accessAbsClass()

{

    absClass        absClass;

    extendAbsClass  extendAbsClass;

 //   absClass = new absClass();    // this declaration will throw error “Object could not be created because class absClass is abstract” so first we extend absClass into extendsAbsClass and further use extendsAbsClass to access absClass methods.

    extendAbsClass  = new extendAbsClass();

    extendAbsClass.printName();

}

----------------------------------------Abstract class----------------------------------------







----------------------------------------Abstract method----------------------------------------

When we declare a method as abstract, this method should be overloaded in child class or we can say, this method should be declared/initiated in the child class then only we can use this class or its method.

Note:

a.      Abstract methods may only be declared in abstract classes.

b.      No code or declarations are allowed in abstract methods.

We have three classes

i.                    absMethodClass

ii.                  extendAbsClass

iii.                NormalClass

1.      abstract class absMethodClass

{

}

abstract void absPrintName()

{

                        // we cannot declare any code in the abstract method

}

2.      class extendAbsClass extends absMethodClass

{

}

void absPrintName()

{

    ; // we have to initiate the abstract method here as this class extends the abstract class.

    info("abstract method declaration in derived class");

}

3.      class childClass_1

{

}

void accessAbsClass()

{

    extendAbsClass  extendAbsClass;

    ;

    extendAbsClass  = new extendAbsClass();

    extendAbsClass.absPrintName();

}

Conclusion : 

Abstract classes can't be instantiated

they're explicitly intended to be extended. 

They also usually contain abstract methods, i.e. methods without any implementation that must be implemented by any non-abstract child. 

It allows you to define high-level concepts and provide some common functionality and leave details for concrete implementations. 

----------------------------------------Abstract method----------------------------------------

How to repair a DB using SSMS

Open SSMS and run the following command


GO  

ALTER DATABASE AxDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE

GO

 DBCC CHECKDB('AxDB',REPAIR_REBUILD)

 GO  

ALTER DATABASE AxDB SET MULTI_USER

GO


If this didn't work then try this one


GO  

ALTER DATABASE AxDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE

GO

DBCC CHECKDB ('AxDB', REPAIR_ALLOW_DATA_LOSS)

GO

ALTER DATABASE AxDB SET MULTI_USER

GO

Saturday, October 16, 2021

How to create a Display method in D365 F&O

Create a class extension of the table you want to add display method to and then add the display method


[ExtensionOf(tableStr(CustTable))]

final class CustTable_Extension

{

public static class CustTable_Extension

{

 [SysClientCacheDataMethodAttribute(true)]  

 public static display Name custGroupName(CustTable _this)

 {

 return  CustGroup::find(_this.CustGroup).Name;

 }

}

}


How to make Ledger Dimension lookup in form

Create an int64 field(Dimension Default) EDT in the source table

Put EDT as DimensionDefault


Now drag and drop the field in form and set ControllerClass setting of the field as "LedgerDefaultDimensionEntryController"

How to see open process and kill processes SSMS DB

Open SSMS :


Run the following command :

exec sp_who


i.e this will show all the processes in the SSMS


To kill the process select PID and write the following command

kill 52        [In this case PID is 52]


Set database from SINGLE USER mode to MULTI USER :

ALTER DATABASE BARDABARD

SET MULTI_USER;

GO

How to debug error in D365 F&O

Open event viewer (Run as administrator)


Go to "Application and Services Logs"


Expand "Microsoft"


Go to "AX System Runtime"


Go to "Operational"


Now check the General and Detailed error

Data Source Join Types(Link type) in D365 F&O

Form data source link type is a property of the form data source. We can add more than one table as a data source to the form. Those data sources should have the table level relation, So, then the developer does not need to work on the coding part to find the related records.


Passive Join Type

Passive form data source link type won't update the child data source automatically. For example, if we select the parent table order then order details child data source won't update. If we need to update the child data source we need to call the child data source to execute the query method by the program (code).


Active Join Type

Active link type updates the child data sources without any delay when you select the parent table record. When you deal with more records it will affect application performance.


Delay Join Type

Delay form data source link type is also same as active method the different is delay method won't update immediately when you select the parent record. It will update the child data source when you select the parent table, Ax uses a pause statement before update the child data source. 


Inner join Type

Inner join form data source link type displays the rows that match with parent table and child table. 


Outer join Type

Outer join form data source link type will return all parent records and matched child records. It will return all rows in the parent table. 


Exists Join Type

Exist join form data source link type return matched rows of the parent table. It behaves like an inner join but the difference is once the parent row is matched with child records then stops the process and updates in the grid, Ax won't consider how many records are in the child table for the parent row.


Not Exists Join Type

Not exist join form data source link type is a totally opposite method to exist join. It will return the not-matched parent records with child records.





Inshort:

None: There is no link between the data sources.

Delayed: The linked data source is not queried until it's needed. This can improve form performance by reducing initial load times.

Passive: A relation exists between the data sources, but changes in one do not affect the other.

InnerJoin: Only records that have corresponding records in the joined data source are displayed.

OuterJoin: All records from both data sources are displayed, even if there's no corresponding record in the joined data source.

ExistJoin: Only records from the primary data source for which there are corresponding records in the joined data source are shown.

NotExistJoin: Only records from the primary data source for which there are no corresponding records in the joined data source are shown.

Active: Filters records in a form data source to only show those relevant to the current active record in another linked data source.


How to refresh Data entity list in D365 FO

In order to use the data entities in Dynamics 365 for Finance and Operations, for example through OData or the Data import/export framework, you need to refresh the entity list. The entities need to be refreshed in a new environment, and/or if you have added, deleted, or modified a data entity. In order to refresh the data entities, you click 

Data management workspace > 

Framework parameters > 

Entity settings > 

Refresh entity list in D365FO


Please Note: The refresh usually takes approximately a minute, and it's done in the background. However, the notifications only appear during page refreshes.


Tada !

Saturday, October 9, 2021

Data validation method on table level

 validateField(),

validateWrite(),

validateDelete(),

aosvalidateDelete(), 

aosvalidateInsert(), 

aosvalidateRead(),

aosvalidateUpdate()

Wednesday, October 6, 2021

Different joins in X++ (Inner ,outer ,exist, not exist)

Take 2 tables A & B.

Table A :

Name        Num

Atul             1

Anju            2

Amit            3

Akshay        4

Ritu             5

Table B :

Class        Department        Num

first           accounts            1

second      HR                     2

third          Finance             3

fourth        Technical          4

Fifth          Solution            4


1. Inner join: The common records of both the tables

2. Outer join: All records of table A and common records of Table B

3. Exist join: common records from Table A

4. Not Exist join: The not common record of Table A

Reference

Types of temp tables in D365


InMemory tables :

1. Holds data temporarily in client or server tier

2. These tables can't be stored in Database

3. Can't apply security

4. We cannot use InMemory table buffers

5. InMemory temporary table is used when the data set is small


TempDB tables :

1. Holds data temporarily in database till the scope is valid

2. These tables are stored in the database

3. Can apply security

4. TempDB table buffer can be used in coding

5. TempDB is normally used for larger datasets to improve performance

Tuesday, September 28, 2021

Sequence of methods in form and table

Sequence of methods in form and table in D365 FO


Form:

Sequence of Methods calls while opening the Form

Form — init ()

Form — Datasource — init ()

Form — run ()

Form — Datasource — execute Query ()

Form — Datasource — active ()


Sequence of Methods calls while closing the Form

Form — canClose ()

Form — close ()


Sequence of Methods calls while creating the record in the Form

Form — Datasource — create ()

Form — Datasource — initValue ()

Table — initValue ()

Form — Datasource — active ()


Sequence of Method calls while saving the record in the Form

Form — Datasource — ValidateWrite ()

Table — ValidateWrite ()

Form — Datasource — write ()

Table — insert ()


Sequence of Method calls while deleting the record in the Form

Form — Datasource — validatedelete ()

Table — validatedelete ()

Table — delete ()

Form — Datasource — active ()


Sequence of Methods calls while modifying the fields in the Form

Table — validateField ()

Table — modifiedField ()




Table:

When you press CTR+N

initValue()->


When you change data in a field

validateField() -> validateFieldValue() -> ModifiedField() -> ModifiedFieldValue()


When you close the table after entering some data

validateWrite() – > Insert() -> aosValidateInsert()


When you Save the Record for the first time

validateWrite() ->Insert() – > aosValidateInsert()


When you modify the record and saving

validateWrite() -> update() – > aosValidateUpdate()


When you delete the record

validateDelete() -> delete() -> aosValidateDelete()

Monday, September 27, 2021

SSMS commands

 To see all he processes in ssms

SP_who2


To kill a process by procesId

kill 52

Thursday, September 16, 2021

How to customise standard report in D365 FO

 Find the menu item, in my case I am taking "TaxTrans"

Create extension for same

go to the class on the menu item and create extension of same class, in my case my class was "TaxTransController"

I created a new extension class of controller class


class GITS_TaxTransControllerExt extends SrsReportRunController

{

    public static client void main(Args _args)

    {

        GITS_TaxTransControllerExt Controller;

        Controller = new GITS_TaxTransControllerExt();

        Controller.parmArgs(_args);

        Controller.parmReportName(ssrsReportStr(GITS_TaxTrans,Report));

        Controller.parmShowDialog(true);

        Controller.startOperation();

    }

}



Now dublicate the report in your project area and look for dp class

Now create a new extension class "GITS_TaxTransDP_Extension" for the DP class, in my case dp class was "TaxTransDP"

Also create extension of temp table and add the required fields

Write the following code and update logic accordingly


[ExtensionOf(classstr(TaxTransDP))]

final class GITS_TaxTransDP_Extension

{

    [PostHandlerFor(classStr(TaxTransDP), methodStr(TaxTransDP, processReport))]

    public static void TaxTransDP_Post_processReport(XppPrePostArgs args)

    {

        TaxTrans    lclTaxTrans;       

        TaxTransDP dpInstance = args.getThis() as TaxTransDP;

        TmpTaxTransReport lclTmpTaxTransReport = dpInstance.getTaxTransTmp();

        ttsbegin;

        while select forupdate lclTmpTaxTransReport

        {

            select sum(TaxBaseAmount) from lclTaxTrans

                where lclTaxTrans.Voucher   == lclTmpTaxTransReport.Voucher;

            lclTmpTaxTransReport.TaxBaseAmount  = lclTaxTrans.TaxBaseAmount;

            lclTmpTaxTransReport.update();

        }

        ttscommit;

    }

}



Now Build and deploy

Tada !!!

Sunday, June 20, 2021

Get Display values from Ledger Dimension x++

 class GlobalDisplayFromLedgerDimension

{

    public static str displayValue(RefRecId _LedgerDim,Name _AttribName)

    {

        DimensionAttributeLevelValueAllView dimAttrView;

        DimensionAttribute                  dimAttr;

        

        select DisplayValue from dimAttrView where dimAttrView.ValueCombinationRecId == _LedgerDim

          join dimAttr

            where dimAttr.RecId == dimAttrView.DimensionAttribute

            && dimAttr.Name == _AttribName;

        return dimAttrView.DisplayValue;

    }


}

Get company fiscal year


Ledger::FiscalCalendar()

Friday, June 18, 2021

Difference between Ledger dimension and Financial dimension

 




The Picture above is "Set of ledger" or "Financial dimension"
The Picture below is Ledger Dimension

Object reference not set to an instance of an object D365 F&O

Some of the objects are not compiled and synchronized with DB. we have to build model wise and synchronization and then one full build, it will be resolved.

Some times restart the services and its done

Using SSMS for unit testing

 Search SSMS in start menu

Select SQL Server Management Studio 18

Run it as administrator

Fill in the server name

Click on "Connect"

In the actionpane click on "New Query"

In the availabl databases, select AxDB

No you can write the SQL query for unit testing

EXAMPLE :

select * from BANKACCOUNTTRANS

where BANKACCOUNTTRANS.ACCOUNTID = 'AUB-BHD'

and BANKACCOUNTTRANS.TRANSDATE >= '12/1/2019'

and BANKACCOUNTTRANS.TRANSDATE <= '12/31/2020'


How to restore DB from UAT to Dev D365 FO

Open CMD in administrator mode


Go to :

cd C:\Program Files\Microsoft SQL Server\150\DAC\bin

(i.e sometimes in 130)


Now create a new DB in SSMS (In my case name: AXDBFromUAT)


now run this command 

 SqlPackage.exe /a:import /sf:C:\DBFromUAT\SOLERPUATbackup.bacpac /tsn:localhost /tdn:AXDBFromUAT /p:CommandTimeout=32000

Please Note:

{

    If you are facing below error:

    *** Changes to connection setting default values were incorporated in a recent release.  More information is available at https://aka.ms/dacfx-connection

    *** Error importing database:Could not import package.

    Unable to connect to target server 'localhost'. Please verify the connection information such as the server name, login credentials, and firewall rules for the target server.

    A connection was successfully established with the server, but then an error occurred during the login process. (provider: SSL Provider, error: 0 - The certificate chain was issued by an authority that is not trusted.)

    The certificate chain was issued by an authority that is not trusted.

    *** The settings for connection encryption or server certificate trust may lead to connection failure if the server is not properly configured.


    use below command
    SqlPackage.exe /a:import /sf:C:\DBFromUAT\SOLERPUATbackup.bacpac /tsn:localhost /tdn:AXDBFromUAT /p:CommandTimeout=32000 /ttsc:True

}

(your package is saved in C:\DBFromUAT\SOLERPUATbackup.bacpac)


Now rename the older DB from AXDB to AXDBOld 

and new DB from AXDBFromUAT to AXDB

using the following commands


USE master;  

GO  

ALTER DATABASE AxDBUAT SET SINGLE_USER WITH ROLLBACK IMMEDIATE

GO

ALTER DATABASE AxDBUAT MODIFY NAME = AxDB ;

GO  

ALTER DATABASE AxDB SET MULTI_USER

GO


Link

Renaming issue

{

SELECT * FROM sys.dm_exec_sessions WHERE database_id = DB_ID('AxDB');

then kill that process

}

for process errors during the renaming

run below query


select 

d.name, 

d.dbid, 

spid, 

login_time, 

nt_domain, 

nt_username, 

loginame

from sysprocesses p 

inner join sysdatabases d 

    on p.dbid = d.dbid

where d.name = 'AxDb'

GO


and kill that process 

How to create custom workflow participant assignment provider type in D365 f&O

 Create a class and Write the following code : 


class GITS_DepartmentManagerParticipantProvider implements WorkflowParticipantProvider

{


    public WorkflowParticipantTokenList getParticipantTokens()

    {

        WorkflowParticipantTokenList tokens = WorkflowParticipantTokenList::construct();

        tokens.add('DeptManager','Department Head');

        return tokens;

    }


    public WorkflowUserList resolve(WorkflowContext _context,WorkflowParticipantToken _participantTokenName)

    {

        str             deptName;

        anytype         tempWorker;

        DirPersonUser   personUser;

        HcmWorker       hcmWorker;

        OMOperatingUnit OMOperatingUnit;

        PurchTable      purchTable;

        WorkflowUserList userList = WorkflowUserList::construct();


        if (!_participantTokenName)

        {

            throw Error("@SYS105453");

        }

        

        select WorkerPurchPlacer from PurchTable

            where PurchTable.RecId == _context.parmRecId();


        deptName = HcmWorker::find(purchTable.WorkerPurchPlacer).primaryDepartmentName();

        

        select hcmWorker from OMOperatingUnit

            where OMOperatingUnit.Name == deptName

            &&    OMOperatingUnit.OMOperatingUnitType == OMOperatingUnitType::OMDepartment;

        tempWorker = OMOperatingUnit.hcmWorker;

        

        select User from personUser

            exists join hcmWorker

                where hcmWorker.Person == personUser.PersonParty

                &&    HcmWorker.RecId  == tempWorker;


        userList.add(personUser.User);


        return userList;

    }


    public static GITS_DepartmentManagerParticipantProvider construct()

    {

        return new GITS_DepartmentManagerParticipantProvider();

    }


}





Now create a "Workflow Participant Assignment Providers"

and put the help text and label "Purch Dept manager"

Available for all workflow template : No

Now in the provider class put in the name of the class that you created earlier i.e "GITS_DepartmentManagerParticipantProvider"

Now create a "Workflow type reference" and put in the then name of the workflow type that you want to provide the assignment on.

Moving Deployment package into UAT using LCS

Go to LCS Portal

Sign in with your credentials


Click on the implementation project

Click on the top ham burger icon

A lookup will popup like below, click on Asset library

A new window will open like below

Now go to the Software deployment package in the left panel

Now click on "+" sign

A new form will be opened like below


Fill in the name and description of the package

Click on "Add a file"

Select the "Deployment folder" and select the package that you want to upload "AXDeployment----"

Now click ok

And now click confirm

Now click on Lifecycle Services on the top left to open the Homepage, Now you will see a screen like below


Now click on the Implementation project as shown in the below picture

Now click on "Full details" on the environment(environment here means UAT, Production) you want the package to deploy to

Now you will see a screen like below

Now click on "maintain" in the Action pane and select "Apply updates", as shown in the picture below

Now a new form will open that will show the deployable packages from your asset library

Now select your "deployment package" 

Now click apply

Now click yes

Now you can see "Servicing" and it takes around 1hr - 2hr or more depending on various factors(Package size, environment, Microsoft servers, etc)