Saturday, March 29, 2025

After product receipt from x++ code system is not creating project transactions

Resolving Project Transactions Issue in X++

Resolving Issue: Project Transactions Not Created After Product Receipt in X++

Introduction

When receiving a product receipt in Microsoft Dynamics 365 Finance and Operations via X++ code, you might encounter a scenario where project transactions are not generated, even when a valid project ID is associated with the purchase order. Debugging revealed that the system is not calling the runProjectPostings() method of the PurchFormLetter_PackingSlip class, which prevents the project packing slip from being posted. To resolve this, I created the runRemainProjectUpdates method in the code below.

Code Implementation

Product Receipt Creation


private TestPOReceiptResponseContract createProductReceipt(TestPOReceiptRequestContract _requestContract)
{
    PurchFormLetter purchFormLetter;
    PurchParmTable purchParmTable;
    PurchParmLine purchParmLine;
    PurchFormletterParmData purchFormLetterParmData;
    TestOrderLineRequestContract orderLineContract = _requestContract.parmOrderLineContract();
    PurchTable purchTable = PurchTable::find(orderLineContract.parmPurchaseOrderId());
    PurchLine purchLine = PurchLine::find(purchTable.PurchId, orderLineContract.parmLineNumber());

    purchFormLetterParmData = PurchFormletterParmData::newData(DocumentStatus::PackingSlip, VersioningUpdateType::Initial);
    purchFormLetterParmData.parmOnlyCreateParmUpdate(true);
    purchFormLetterParmData.createData(false);

    PurchParmUpdate purchParmUpdate = purchFormLetterParmData.parmParmUpdate();

    purchParmTable.clear();
    purchParmTable.TransDate = _requestContract.parmProducReceiptDate();
    purchParmTable.Ordering = DocumentStatus::PackingSlip;
    purchParmTable.ParmJobStatus = ParmJobStatus::Waiting;
    purchParmTable.Num = _requestContract.parmCoupaId();
    purchParmTable.PurchId = purchTable.PurchId;
    purchParmTable.insert();
    
    purchParmLine.initFromPurchLine(purchLine);
    purchParmLine.ReceiveNow = _requestContract.parmTotal();
    purchParmLine.ParmId = purchParmTable.ParmId;
    purchParmLine.insert();

    purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
    purchFormLetter.transDate(_requestContract.parmProducReceiptDate());
    purchFormLetter.run();

    // Generate project item transactions
    if (purchTable.ProjId != '')
    {
        this.runRemainProjectUpdates(purchFormLetter, purchParmTable.ParmId);
    }
    
    return this.getResponseContract("@ENG_Labels:ProductReceiptCreated", true);
}
    

Explicitly Calling runRemainProjectUpdates to Create Project Transactions


public void runRemainProjectUpdates(PurchFormLetter _purchFormLetter, ParmId _parmId)
{
    FormletterOutputContract outputContract = _purchFormLetter.getOutputContract();
    VendPackingSlipVersion localVendPackingSlipVersion;
    VendPackingSlipJour localVendPackingSlipJour;
    VendPackingSlipTrans localVendPackingSlipTrans;
    PurchLine localPurchLine;
    SalesLine localSalesLine;
    SalesFormLetter salesFormLetter;

    if (ProjParameters::find().AutomaticItemConsumption == NoYes::Yes)
    {
        select firstonly RecId, AccountingDate from localVendPackingSlipVersion
            where localVendPackingSlipVersion.ParmId == _parmId
            exists join localVendPackingSlipJour
                where localVendPackingSlipVersion.VendPackingSlipJour == localVendPackingSlipJour.RecId
                exists join localVendPackingSlipTrans
                    where localVendPackingSlipTrans.VendPackingSlipJour == localVendPackingSlipJour.RecId
                    exists join localPurchLine
                        where localPurchLine.InventTransId == localVendPackingSlipTrans.InventTransId
                        && localPurchLine.ItemRefType == InventRefType::Sales
                        exists join localSalesLine
                            where localSalesLine.InventTransId == localPurchLine.InventRefTransId
                            && localSalesLine.ProjId;

        if (localVendPackingSlipVersion.RecId)
        {
            salesFormLetter = SalesFormLetter::newFromPurchFormLetter_PackingSlip(
                SysOperationHelper::base64Encode(outputContract.parmJournalLinesPacked()),
                DocumentStatus::ProjectPackingSlip);

            if (localVendPackingSlipVersion.AccountingDate)
            {
                salesFormLetter.transDate(localVendPackingSlipVersion.AccountingDate);
            }

            salesFormLetter.runOperation();
        }
    }
}
    

How to register return sales order lines using X++ code

How to Register Return Sales Order Lines in X++

The TestSalesReturnOrderLineRegister Class in X++

The TestSalesReturnOrderLineRegister class serves as an entry point to the product registration process, specialized for the sales return order process. It handles the return disposition code and manages sales return order specifics, such as creating inventory transactions.

Code Overview



class TestSalesReturnOrderLineRegister extends TradeOrderLineRegister
{
    ReturnDispositionCodeId returnDispositionCodeId;
    DialogField dialogDispositionCodeId;
    SalesLine salesLine;
    boolean reverseInventTrans;
    boolean recreateReservationLine;
    boolean inRegistration;

    public boolean init()
    {
        boolean ret = super();
        salesLine = salesPurchLine;
        return ret;
    }

    public void run()
    {
        this.runPreSuper();
        super();
        this.runPostSuper();
    }

    public void runPostSuper()
    {
        salesLine = SalesLine::findInventTransId(salesLine.InventTransId, true);
        if (inRegistration)
        {
            if (salesLine.ReturnStatus == ReturnStatusLine::Awaiting)
            {
                if (reverseInventTrans && !salesLine.ReturnAllowReservation)
                {
                    SalesLine::changeReturnOrderType(salesLine.InventTransId, null, true);
                    salesLine = SalesLine::findInventTransId(salesLine.InventTransId, true);
                }
                if (salesLine.ReturnDispositionCodeId)
                {
                    salesLine.ReturnDispositionCodeId = '';
                    salesLine.update();
                }
            }
        }
        else 
        {
            if (salesLine.ReturnStatus == ReturnStatusLine::Registered && recreateReservationLine)
            {
                salesLine.createReturnReservationLine();
                salesLine = SalesLine::findInventTransId(salesLine.InventTransId, true);
            }
        }
    }
}
    

Calling the TestSalesReturnOrderLineRegister Class


public void registerReturnSOLine(SalesId _salesId, ReturnDispositionCodeId _dispositionCode)
{
    TradeOrderLineRegister tradeOrderlineRegister;
    TestSalesReturnOrderLineRegister salesReturnOrderLineRegister;
    InventTransWMS_Register inventTransWMS_register;
    TmpInventTransWMS TmpInventTransWMS;
    SalesLine salesLine;
    InventTrans inventTrans;
    InventTransOrigin inventTransOrigin;
    returnDispositionCode returnDispositionCode;

    Args args = new Args();
    while select forUpdate salesLine where salesLine.SalesId == _returnSOTable.SalesId
    {
        args.record(salesLine);
        tradeOrderLineRegister = TestSalesReturnOrderLineRegister::construct();
        tradeOrderLineRegister.parmArgs(args);
        tradeOrderLineRegister.init();
        salesReturnOrderLineRegister = tradeOrderLineRegister;
        salesReturnOrderLineRegister.runPreSuper();
        
        select firstOnly returnDispositionCode
            where returnDispositionCode.DispositionAction == DispositionAction::Credit;
        
        salesLine.ReturnDispositionCodeId = returnDispositionCode.DispositionCodeId;
        salesLine.update();

        select firstOnly crossCompany inventTrans
            join RecId, InventTransId from inventTransOrigin
                where inventTransOrigin.InventTransId == salesLine.InventTransId
                && inventTrans.InventTransOrigin == inventTransOrigin.RecId;

        inventTransWMS_register = inventTransWMS_register::newStandard(tmpInventTransWMS);
        tmpInventTransWMS.clear();
        tmpInventTransWMS.initFromInventTrans(inventTrans);
        tmpInventTransWMS.InventDimId = inventTrans.InventDimId;
        tmpInventTransWMS.insert();

        inventTransWMS_register.writeTmpInventTransWMS(tmpInventTransWMS, inventTrans, inventTrans.inventDim());
        if (!inventTransWMS_register.updateInvent(salesLine))
        {
            throw error("Error during registration of sales line.");
        }
    }
}
    

Wednesday, March 26, 2025

How to create COC for form methods , How to get formRun , How to make control visible false on form in D365FO

How to create COC for form method in D365FO

How to create COC for form method in D365FO

Example Code

[ExtensionOf(formStr(ProjInvoiceListPage))]
final class TestProjInvoiceListPage_Extension
{
    public void init()
    {
        next init();

        FormRun formRun = this as FormRun;

        if(ProjParameters::find().TestPrintPGGDesignForProjectInvoice)
        {
            FormControl         stdViewCopyBtn   = formrun.design(0).controlName('PrintProjInvoiceCopyButton');
            FormControl         stdViewOrigBtn   = formrun.design(0).controlName('PrintProjInvoiceButton');
            stdViewCopyBtn.visible(false);
            stdViewOrigBtn.visible(false);
        }
        else
        {
            FormControl         customViewCopyBtn   = formrun.design(0).controlName('TestPSAProjInvoiceCopy');
            FormControl         customViewOrigBtn   = formrun.design(0).controlName('TestPSAProjInvoiceOriginal');

            customViewCopyBtn.visible(true);
            customViewOrigBtn.visible(true);
        }
    }
}

Thursday, February 6, 2025

Fix Dynamics 365FO Synchronization Error - Transaction Log Full

Fix Dynamics 365FO Synchronization Error - Transaction Log Full

Fix: The transaction log for database is full due to 'log_backup' - Dynamics 365FO

If you're encountering the error "The transaction log for database is full due to 'log_backup'" while working with Dynamics 365 Finance and Operations (D365FO), it means your SQL Server transaction log has reached its maximum capacity.

Solution

Follow these steps to resolve the issue:

Step 1: Check the Database Files

Run the following SQL query to check the database file details:

    SELECT * FROM sys.database_files
    

Note down the log file name from the result and use that same name in the second statement of the step 2 SQL query.

Query result screenshot:

Database files query result

Step 2: Shrink the Transaction Log

Execute the following commands to shrink the transaction log and free up space:

    ALTER DATABASE AxDB SET RECOVERY SIMPLE;
    DBCC SHRINKFILE('AxDb_New_log', 0, TRUNCATEONLY);
    ALTER DATABASE AxDB SET RECOVERY FULL;
    

Replace 'AxDb_New_log' with the actual log file name you noted earlier.

Step 3: Start DB synchronization again...this time it should work

..

Follow "Dynamics World" blog also for some other approach

Tip: Always ensure you have proper database backups before making changes to recovery models.

Wednesday, January 22, 2025

Get Description of financial dimension value from SQL DB of D365FO

Retrieve Financial Dimension Value Description using SQL Query in D365FO

How to Retrieve Financial Dimension Value Description with SQL in D365FO

In this post, we will explore how to retrieve the description of a financial dimension value in an ERP or financial management system using a specific SQL query in D365FO.

The Query


SELECT DIMATTVALUE.DISPLAYVALUE AS 'DIMENSIONVALUE',
       DIMATT.NAME AS 'FINANCIALDIMENSION',
       DIMATTVALUE.ISSUSPENDED,
       HCMWORKER.PERSONNELNUMBER AS 'OWNER',
       DimFinTag.DESCRIPTION
FROM DIMENSIONATTRIBUTEVALUE AS DIMATTVALUE
LEFT JOIN HCMWORKER ON DIMATTVALUE.OWNER = HCMWORKER.RECID
JOIN DIMENSIONATTRIBUTE AS DIMATT ON DIMATT.RECID = DIMATTVALUE.DIMENSIONATTRIBUTE
JOIN DIMENSIONATTRIBUTEDIRCATEGORY dimAttDirCategory 
ON dimAttDirCategory.DIMENSIONATTRIBUTE = DIMATTVALUE.DIMENSIONATTRIBUTE
JOIN DIMENSIONFINANCIALTAG DimFinTag ON DIMATTVALUE.DISPLAYVALUE = DimFinTag.VALUE 
AND DimFinTag.FINANCIALTAGCATEGORY = dimAttDirCategory.DIRCATEGORY
WHERE DIMATTVALUE.ISDELETED = 0
  AND DIMATTVALUE.ISSUSPENDED = 0
        

Feel free to leave a comment below if you have any questions or need further clarification on the query or its results!

Monday, January 13, 2025

Call custom service with JSON body in D365FO

Call Custom Service with JSON Body in D365FO

Call Custom Service with JSON Body in D365FO

        
FileUploadTemporaryStorageResult fileUpload = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
System.IO.Stream stream = fileUpload.openResult();
str responceJson;

using (var reader = new System.IO.StreamReader(stream))
{
    responceJson = reader.ReadToEnd();

    TESTPOReceiptRequestContract contract = FormJsonSerializer::deserializeObject(
        classnum(TESTPOReceiptRequestContract), responceJson);

    new TESTPOReceiptService().processRecord(contract);
}
        
    

After product receipt from x++ code system is not creating project transactions

Resolving Project Transactions Issue in X++ Resolving Issue: Project Transactions Not Created After Product Rec...