Updating Custom Field (InventdimProjId) in InventDim Table from Sales Line

I am currently working on a customization where I need to update a custom field in the InventDim table. Specifically, upon the creation of a sales line, I intend to transfer the project ID from the sales line to the corresponding InventDim record.

Despite my efforts, I’ve encountered challenges in ensuring that this custom field, named InventdimProjId, is consistently updated in the InventDim table. I have implemented code within the insert method of the sales line and direct updates to the InventDim table. However, despite these efforts, the InventdimProjId field remains null.

Here is the code which i have used

[ExtensionOf(tableStr(SalesLine))]
final class SalesLine_Extension
{
public void insert(
boolean _dropInvent,
boolean _findMarkup,
Common _childBuffer,
boolean _skipCreditLimitCheck,
boolean _skipWHSProcesses,
InventRefTransId _interCompanyInventTransId)
{
next insert(
_dropInvent,
_findMarkup,
_childBuffer,
_skipCreditLimitCheck,
_skipWHSProcesses,
_interCompanyInventTransId);

    InventDim inventDim;
    try
    {
        ttsbegin;

        select forUpdate inventDim
            where inventDim.inventDimId == this.InventDimId;

        if (inventDim && !inventDim.InventdimProjId)
        {
            inventDim.InventdimProjId = this.ProjId;
            inventDim.update();
        }

        ttscommit;
    }
    catch (Exception::Error)
    {
        ttsabort;
        error("Error updating InventdimProjId");
    }

    this.modifyInventDim(this.inventDim(), fieldNum(InventDim, InventdimProjId), false);
}

public boolean modifyInventDim(
    InventDim _inventDim,
    FieldId _dimFieldId,
    boolean _resetPrice)
{
    boolean result = next modifyInventDim(_inventDim, _dimFieldId, _resetPrice);

    try
    {
        ttsbegin;

        select forUpdate _inventDim
            where _inventDim.inventDimId == this.InventDimId;

        if (_inventDim && !_inventDim.InventdimProjId)
        {
            _inventDim.InventdimProjId = this.ProjId;
            _inventDim.update();
            info("After modify: " + _inventDim.InventdimProjId);
        }

        ttscommit;
    }
    catch (Exception::Error)
    {
        ttsabort;
        error("Error updating InventdimProjId: ");
    }

    return result;
}

}

Please note: I can see the project id being displayed in infolog. But its not getting updated in inventdim table.

Best regards,
Vini

Adding a new field to InventDim is far from trivial. Yes, you can easily add a field, but you need to take it into account when finding dimensions, creating InventDimId, calculation the hash, summarizing lines in forms, on-hand calculation and so on… You won’t be able to do it.

Instead of creating a custom field, use one of the pre-defined fields such as InventDimension1.

Also, you have a critical bug in your code. This:

inventDim.InventdimProjId = this.ProjId;
inventDim.update();

would change the meaning of the given InventDimId, which would cause data inconsistency across F&O. Instead, you need to find or create an ID for the new combination of dimensions. For example:

inventDim.InventDimension1 = this.ProjId;
this.InventDimId = InventDim::findOrCreate(inventDim).InventDimId;

Hi Marthi,

I would like to express my gratitude for your insightful feedback on the Dynamics 365 Finance and Operations code implementation.

I have implemented the suggested modification using InventDimension1 and followed the recommended approach of:

[ExtensionOf(tableStr(SalesLine))]
final class SalesLine_Extension
{
public void insert(
boolean _dropInvent,
boolean _findMarkup,
Common _childBuffer,
boolean _skipCreditLimitCheck,
boolean _skipWHSProcesses,
InventRefTransId _interCompanyInventTransId)
{
next insert(
_dropInvent,
_findMarkup,
_childBuffer,
_skipCreditLimitCheck,
_skipWHSProcesses,
_interCompanyInventTransId);

    InventDim inventDim;
    try
    {
        ttsbegin;

        select forUpdate inventDim
            where inventDim.inventDimId == this.InventDimId;

        if (inventDim && !inventDim.InventDimension1)
        {
            inventDim.InventDimension1 = this.ProjId;
            this.InventDimId = InventDim::findOrCreate(inventDim).InventDimId;
        }

        ttscommit;
    }
    catch (Exception::Error)
    {
        ttsabort;
        error("Error updating InventDimension1");
    }

}

However, upon further inspection, I regret to inform you that the value is not being updated in the InventDim table; it remains blank. I am reaching out to seek your expertise on whether there are additional validations or specific code segments that I should examine to ensure the successful update of the InventDim field.

Thank you for your time and support.

Good! It’s correct that InventDim isn’t updated, because that would be a bug, as explained above. findOrCreate checks if there is a record for the given combination of dimensions. If it is, it gives you the ID (nothing changes in InventDim table). If it doesn’t exist, it’ll create a new record (it won’t update any existing one).

By the way, your code sets the new InventDimId to SalesLine but it never saves the record, therefore it doesn’t have any impact on SalesLine. The best solution changing the value before inserting the record, but I think you’ll need to do it somewhere in SalesLineType class. Another approach is updating the record (which is slower).

Throw away ttsabort from the catch block. It’s useless, because when an error is thrown, the transaction is aborted automatically. Therefore your catch block will never be in a transaction.

By the way, using project as an inventory dimension makes no sense to me. I believe it’s a wrong design.

Hi Martin,

There is configID field in InventDim, which is updating the value from salesLine Configuration field, once the salesline is created and saved. But why not projectID in the same way?

I’m sorry, but I don’t understand what you mean. Please tell us more.

public void createProductConfigurationAndVariants()
{
EcoResConfiguration ecoResConfiguration;
InventTable inventTable;
InventSite inventSite;
EcoResConfigurationName configID;

    select firstonly inventSite
        where inventSite.SiteId == this.inventDim().InventSiteId;

    select firstonly inventTable
        where inventTable.ItemId == this.ItemId;

    //Creates configuration Id and variants
    if (inventSite.ManageProjectItems    == NoYes::Yes &&
        inventTable.ProjectItem          == NoYes::Yes)
    {
        if (inventSite.ProjectLinkType   == ProjectLinkType::ProjId   &&
            this.ProjId                     != "")
        {
            configID    = this.ProjId;
        }
        else
        {
            configID    = this.SalesId;
        }            
       
            //update default configuration with newly created configuration ID
            if (ecoResConfiguration.Name)
            {
                InventDim       inventDim;
                SalesLine       salesLineLoc;

                select firstonly forupdate salesLineLoc
                    where salesLineLoc.RecId == this.recId;

                if (salesLineLoc.RecId)
                {
                    inventDim           = this.inventDim();
                    inventDim.configId  = configID;
					inventDim.ProjectId = this.projId;		
                    inventDim           = InventDim::findOrCreate(inventDim);
                    
                    ttsbegin;
                    salesLineLoc.InventDimId        = inventDim.inventDimId;
                    saleslineLoc.RetailVariantId    = InventDimCombination::findByInventDim(this.ItemId, inventDim).RetailVariantId;
                    salesLineLoc.update();
                    ttscommit;
                }
            }
            
        }
    }

}

Here In this method, when conditions are met, it sets up a configID based on certain criteria, and updates the default configuration in the sales line.
The relevant part is where inventDim.configId is assigned the value of configID.
I tried to update the projectID in the same way, yet the field is blank.

It actually does the same thing that I described. It doesn’t update InventDim; it uses InventDim::findOrCreate() to get InventDimId, assigns it to salesLine.InventDimId and saves salesLine.

1 Like