Remove a Legal Entity in Microsoft Dynamics 365

Remove a Legal Entity in Microsoft Dynamics 365

Microsoft Dynamics 365 is a platform that offers a wide variety of solutions that help drive each business according to its requirements. One of the procedures is the Remove Legal Entity within the platform.

Even if it is a task that requires a lot of attention, it is not difficult to learn. In this article, we explain how to perform the Remove Legal Entity Process in Dynamics 365.

However, this post is not “a final guide” on how to perform this task. After all, each entity has different requirements.

This guide is just a brief compilation of the type of problems you can encounter while performing this task and how to solve them.

With the incorporation of artificial intelligence, the possibilities of Microsoft Dynamics 365 increase.

The unification of data and the extraction of prospects allows the development of new strategies to meet the established objectives and make proactive decisions.

Each company has its own needs and requirements. In this sense, Microsoft Dynamics 365 offers a scalable implementation and tailored to each business.

What is Microsoft Dynamics 365?

Microsoft Dynamics 365 is a cloud platform that offers a suite of solutions that drive digital transformation.

Dynamics 365 business apps offer different tools and modules that help unify data, with the objective of offering companies a comprehensive vision of the business’ customers, processes, and operations.

Things to Consider Before You Remove a Legal Entity in Dynamics 365

Although you can do many things with Dynamics 365, today we are teaching you how you can remove legal entities using this software.

Before we dive even further into the topic, there are a few things you should consider before removing a legal entity in Dynamics 365. They are the following:

  • You cannot delete business or system entities
  • Conversely, you can delete custom entities. But there are certain conditions associated with them:
    • For example, deleting an entity by pressing the Delete button alone is not possible. If you do that, an error message will pop up. The reason why is that these entities are often associated with other entities or dependencies.

For that reason, you should always eliminate the associated entities or dependencies before you remove the primary legal entity.

With that in mind, here are the steps you should follow to ensure you can delete the entity:

  1. First, delete User role associations with references to the applicable company
  2. Second, delete the transactions within the applicable company
  3. Third, delete the Batch jobs with references to the applicable company
  4. Fourth, delete the Business unit with references to the applicable company.
  5. Fifth, delete the applicable legal entity
  6. For the sixth and final step, delete the item storage, tracking, and supply type relationships for items to be released back into the same company (if recreated with the same company ID).

Now we’re going to see how to do each one of these steps.

Delete Existing Role Associations in Dynamics 365

There may be user references in place against Roles set against the company you’re trying to delete that will need to be removed before the company will allow deletion.

To eliminate these roles, there are two methods:

1. VIA THE AOT

In the AOT, navigate to the table, dbo.OMUSERROLEORGANIZATION and open the table

Remove Legal Entity D365

Then, go to the column “OMINTERNALORGANIZATION”, and filter for the organization ID.
The organization ID is the RECID of the Party Record in the Global Address Book.

Finally, in the AOT, enter the RECID, select all returned records, and Delete.

2. VIA SQL

For a simple lookup of the RECID needed for the role association deletion, the following query in SQL will return the list of unique company party records and their record IDs.

SELECT T1.NAME,T1.RECID
FROM DBO.DIRPARTYTABLE T1
WHERE T1.RECID IN 
(SELECT DISTINCT T2.OMINTERNALORGANIZATION
	 FROM dbo.OMUSERROLEORGANIZATION T2
	)
ORDER BY T1.NAME

In SQL, use the following query to delete the user association specific to the company that is being deleted.

And that’s it, choose the method that you prefer to eliminate this relation, and move on with the next step.

DELETE FROM DBO.OMUSERROLEORGANIZATION
WHERE OMINTERNALORGANIZATION = ### --RECID OF COMPANY TO BE DELETED

Deleting the Transactions in Dynamics 365

If there are transactions in the company you’re trying to delete, they will need to be removed. This is done through the SysDatabaseTransDelete class.

This is a potentially very heavy operation as each record in the SysDatabaseLog is checked which is potentially millions of rows.

Below is an index that was setup to help speed up the transactional delete process.

Create Index on dbo. This is NON-permanent and only required to speed up the deletion process.

USE [DATABASENAMEHERE] –Applicable AX database here
GO
 

CREATE NONCLUSTERED INDEX [INDEXNAMEHERE] ON [dbo].[SYSDATABASELOG]
(
	[RECID] ASC,
	[RECVERSION] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Drop index after deletion of AX company.

Then, in the AOT, navigate to the “SysDatabaseTransDelete” class. Right-click and select “Open”, and Select the option “Yes”.

IMPORTANT INFORMATION

Depending on system capabilities and the number of existing transactions, this process can take anywhere from 30 minutes to 6+ hours. This potentially can affect end users who are in other companies transacting.

Delete Existing Batch References

If there are on-going and or historical batch jobs with references to the company you are trying to delete in AX, they will stop the AX company deletion with an error message.

If this is the case, in the AOT (or SQL if you really know what you’re doing):

  1. First, Navigate to the table, dbo.BATCH and delete all rows containing references to the applicable company in the DATAAREA column.
  2. Next, delete all rows containing reference to the company in the DATAAREA column for dbo.BATCHJOB, dbo.BATCHHISTORY, and dbo.BATCHJOBHISTORY.

Step 4 Remove Legal Entity D365

Deleting the Business Unit

1) VIA THE AOT

The first step is to navigate to the table, dbo.DIMENSIONATTRIBUTEVALUE and open it.Then, in the column ENTITYINSTANCE, filter for the organization ID. This organization ID is the RECID of the Party Record in the Global Address Book. You can look it up in SQL or go to the party record, right-click and click on View Record.
Finally, enter the RECID, select all returned records, and Delete.

2) VIA SQL

To delete this item, you have to run the following select statement provides the line to be deleted.

 SELECT * FROM dbo.DIMENSIONATTRIBUTEVALUE
WHERE ENTITYINSTANCE = Your Record ID

Use the following query to delete the BU association specific to the company that is being deleted.

  DELETE FROM DBO. DIMENSIONATTRIBUTEVALUE
WHERE ENTITYINSTANCE = ### --RECID OF COMPANY TO BE DELETED

Delete Legal Entity

Now, finally deleting the legal entity.

  1. Close the AOT, if open.
  2. Change AX companies to any company that is NOT the one that is being deleted. The deletion process will fail if you are trying to delete the entity, while in it.
  3. Navigate to “Organization administration > Setup > Organization > Legal Entities
  4. Select the applicable company
  5. Select “Delete”
  6. Click “Yes”

Delete Item Relationships

Now, what I would consider an oversight is that deleting the transactions using the previous class does not delete the relationships of the items that had been released to the deleted company.
So if you attempt to release an item into a company that was deleted and then recreated, you will get an error message
And if you attempt to go to “Open product releases” and look at the Infolog on the item you get a reference to the item setup supply type already existing.
The issue is the item still has relationships in place to the previously deleted company in the Storage, Tracking and Supply type tables.
The fix is simple. Either in the AOT or SQL, look/filter in the following tables where the DATAAREAID is equal to the company(s) you are or have deleted.

1) dbo.INVENTITEMSETUPSUPPLYTYPE,

2) dbo.ECORESSTORAGEDIMENSIONGROUPITEM,

3) dbo.ECORESTRACKINGDIMENSIONGROUPITEM

1) VIA THE AOT

In the AOT, navigate to the tables mentioned before and open them.

  • In the column “DATAAREAID”, filter for the COMPANY ID
  • Select all returned records and Delete.

If you have thousands of relationships, deleting via the AOT can take 5 to 10 minutes. Deleting via SQL took about 5 seconds.

2) VIA SQL

The following queries in SQL will return the list of unique item records with company relationships and therefore what needs to be deleted.

 SELECT
FROM dbo.INVENTITEMSETUPSUPPLYTYPE
WHERE ITEMDATAAREAID in ('yourcompany' , 'yourcompany')
SELECT
FROM dbo.ECORESSTORAGEDIMENSIONGROUPITEM
WHERE ITEMDATAAREAID in ('yourcompany' , 'yourcompany')
SELECT
FROM dbo.ECORESTRACKINGDIMENSIONGROUPITEM
WHERE ITEMDATAAREAID in ('yourcompany' , 'yourcompany')

Code For Remove All Transactions in Dynamics 365

To remove all transactions associated with the legal entity, the class SysDatabaseTransDelete was running, the class code is shown below:

// This is a framework class. Customizing this class may cause problems with future upgrades to the software.
[SysObsoleteAttribute('This functionality is deprecated as of AX7.', false)]
public class SysDatabaseTransDelete extends RunBase
{
    Set     tableSet;

    protected boolean canRunInNewSession()
    {
        return false;
    }

    void deleteTable(SysDictTable sysDictTable)
    {
        Common      common;

        this.handleDeleteActions(sysDictTable);
        common = sysDictTable.makeRecord();

        common.skipDatabaseLog(true);
        common.skipDataMethods(true);
        common.skipDeleteActions(true);
        delete_from common;
    }

    void deleteTables()
    {
        Dictionary      dictionary = new Dictionary();
        SysDictTable    sysDictTable;
        tableId         tableId     = dictionary.tableNext(0);

        this.progressInit("@SYS9560", dictionary.tableCnt());

        while (tableId)
        {
            sysDictTable = new SysDictTable(tableId);

            if ( sysDictTable )
            {
                progress.incCount();
                progress.setText(sysDictTable.label());

                if (!sysDictTable.isView() && !sysDictTable.isMap())
                {
                    this.handleTable(sysDictTable);
                }
            }

            tableId = dictionary.tableNext(tableId);
        }
    }

    protected void handleDeleteActions(SysDictTable _sysDictTable)
    {
        SysDictTable        dictTable;
        int                 i;
        int                 deleteActionCnt = _sysDictTable.deleteActionCnt();

        for (i = 1; i <= deleteActionCnt; i++)
        {
            dictTable = new SysDictTable(_sysDictTable.deleteActionTableId(i));
            if (dictTable)
            {
                this.handleTable(dictTable);
            }
            else
            {
                warning(strfmt("@SYS82777", tableid2name(_sysDictTable.id()), _sysDictTable.deleteActionTableId(i)));
            }
        }
    }

    [SysObsoleteAttribute('This functionality is deprecated as of AX7.', false)]
    delegate void handleGlobalTransTableDelegate(SysDictTable sysDictTable, SysDatabaseTransDelete inst)
    {
    }

    void handleGlobalTransTable(SysDictTable sysDictTable)
    {
        this.handleGlobalTransTableDelegate(SysDictTable, this);
    }

    delegate void handleNonTransTableDelegate(SysDictTable sysDictTable, SysDatabaseTransDelete inst)
    {
    }

    void handleNonTransTable(SysDictTable sysDictTable)
    {
        this.handleNonTransTableDelegate(SysDictTable, this);
    }

    void handleTable(SysDictTable sysDictTable)
    {
        TableGroup      tableGroup;

        if (tableSet.in(sysDictTable.id()))
            return;
        tableSet.add(sysDictTable.id());

        if (sysDictTable && !sysDictTable.isTmp() && !sysDictTable.isMap())
        {
            tableGroup = sysDictTable.tableGroup();

            // Handle company specific tables to be deleted
            if (sysDictTable.dataPrCompany())
            {
                switch(tableGroup)
                {
                    case TableGroup::Transaction:
                    case TableGroup::WorksheetHeader:
                    case TableGroup::WorksheetLine:
                        this.handleTransTable(sysDictTable);
                        break;
                    default:
                        this.handleNonTransTable(sysDictTable);
                        break;
                }
            }
            else
            {
                // Handle global tables to be deleted
                switch(tableGroup)
                {
                    case TableGroup::Transaction:
                    case TableGroup::TransactionHeader :
                    case TableGroup::WorksheetHeader:
                    case TableGroup::WorksheetLine:
                        this.handleGlobalTransTable(sysDictTable);
                        break;
                    default:
                        break;
                }
            }
        }
    }

    delegate void handleTransTableDelegate(SysDictTable sysDictTable, SysDatabaseTransDelete inst)
    {
    }

    void handleTransTable(SysDictTable sysDictTable)
    {
        this.handleTransTableDelegate(SysDictTable, this);
    }

    public container pack()
    {
        return connull();
    }

    /// <summary>
    /// Contains the code that does the actual job of the class.
    /// </summary>
    void run()
    {
        ttsbegin;
        tableSet = new Set(Types::Integer);
        this.deleteTables();
        ttscommit;
    }

    public boolean unpack(container packedClass)
    {
        return true;
    }

    public static SysDatabaseTransDelete construct()
    {
        return new SysDatabaseTransDelete();
    }

    client server static ClassDescription description()
    {
        return "@SYS9560";
    }

    static void main(Args args)
    {
        SysDatabaseTransDelete databaseTransDelete = SysDatabaseTransDelete::construct();

        if (Box::yesNo(strfmt("@SYS82778", curext()),DialogButton::No))
        {
            databaseTransDelete.runOperation();
            info("@SYS9265");
        }
    }

}

 

Running the class eliminates all the transactions. Next, eliminate the legal entity in Dynamics 365.

To finalize, verify that the elimination of the legal entity was successful.

In Summary

In conclusion, we know removing legal entities in Dynamics 365 can be a cumbersome and complicated affair. Fortunately, you can power through the process if you have an understanding of the weak points that cause problems.

Remember that Dynamics 365 is a powerful tool that can help improve all of your company’s processes, and we want you to get the most out of it.

Visit our most recent blogs to be aware of other Dynamics 365 processes.

If you want to learn more about Dynamics 365, sign up for our Development Bundle for MB-300T00 And MB-500T00 boot camp and visit Instructor Brandon for more information and news from Microsoft.

Don’t hesitate to contact us if you have any questions, and see you soon!

Videos